@agimon-ai/doompi-build

Folder-convention scanner and build presets for DoomPi extensions.

Packages

Package details

package

Install @agimon-ai/doompi-build from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@agimon-ai/doompi-build
Package
@agimon-ai/doompi-build
Version
0.0.1-alpha.6
Published
Sep 19, 2026
Downloads
421/mo · 421/wk
Author
agiflow-ai
License
MIT
Types
package
Size
397.2 KB
Dependencies
0 dependencies · 0 peers

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

@agimon-ai/doompi-build

Folder-convention scanner and build presets for DoomPi extensions.

An extension declares what it contributes by where its files sit. This package reads that tree and hands the result to the generators and bundler presets, so a package keeps no parallel registry of its own contents.

See Extension layout for the convention and Extension lifecycles for what happens to a contribution once mounted.

Scanning

import { scanExtensions } from '@agimon-ai/doompi-build';

const graph = scanExtensions({ packageDir: process.cwd() });
for (const entry of graph.entries) console.log(entry.scope, entry.side, entry.surface, entry.name);
for (const notice of graph.notices) console.warn(notice.path, notice.message);

The scan is filesystem in, data out. It walks directories rather than globbing, which is what keeps parenthesised group folders safe: tsdown's globber reads a bare (name) as an extglob group, and a walk never sees a pattern at all.

Nothing throws. A folder the convention does not recognise becomes a notice and its subtree is skipped, so one bad directory never costs a package its other contributions.

What a path declares

src/extensions/<scope>/(side)/<surface>/<name>[.<target>][.<platform>].<ext>
Axis Read from
scope workspaces/ and sessions/ nesting below the root
side the (backend) or (frontend) group folder
gate a mode/<id>/ or domain/<id>/ container folder
surface the folder directly holding the file, such as tool/
route folders below a routed surface, with [param] and [...catchAll]
name the first filename segment
target filename segments between the name and the platform
platform a trailing filename segment naming a platform for that side

_private folders are never scanned. *.test.*, *.spec.* and *.stories.* are excluded everywhere.

Options

Every name in the convention is configurable, and the defaults are the documented ones.

scanExtensions({
  packageDir,
  root: 'src/extensions',
  sides: { backend: 'backend', frontend: 'frontend' },
  platforms: { backend: ['cli', 'server'], frontend: ['cli', 'web', 'ios', 'android', 'desktop'] },
  generatedEntries: ['pi', 'server', 'web'],
});

Generating

generateExtension scans the authored tree, renders an entry for each host it contributes to, and writes build inputs beneath ignored generated/. A target with no contributions produces no entry, and removing a target deletes its obsolete generated entry.

import { generateExtension } from '@agimon-ai/doompi-build';

const { targets, changed, notices } = generateExtension({ packageDir });

Normal builds generate missing or stale entries, including in CI. Pass check: true only for an explicit write-free freshness check. Generated files are disposable build output and are not committed.

The tsdown preset

// tsdown.config.ts, the whole file
import { doompiExtension } from '@agimon-ai/doompi-build/tsdown';
import { defineConfig } from 'tsdown';

export default defineConfig(doompiExtension());

The preset generates entries while the config loads because tsdown needs its entry map before building. It builds Node host entries and public src/exports modules, then bundles routed frontend contributions separately to dist/extensions/web.mjs. The browser bundle keeps bare package imports external so the cockpit supplies shared React and store singletons. It also emits local ?url assets and ?worker&url worker chunks.

The build synchronizes pi, doompiServer, doompiWeb, and generated host exports in package.json. Keep package-specific public entries with the preset entry option, use exportsDir for a nonstandard public-export root, and set pluginId when the historical cockpit id differs from the package-derived default.

Packages with a frontend target typecheck it through a root tsconfig.web.json. Include generated in the Node project, exclude routed (frontend) files from it, and include those files plus generated/web.ts in the browser project.