@entelligentsia/forgecli 0.7.10 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +127 -0
- package/dist/CHANGELOG-forge-plugin.md +70 -0
- package/dist/CHANGELOG-pi.md +63 -0
- package/dist/bin/argv.d.ts +2 -2
- package/dist/bin/argv.js +27 -0
- package/dist/bin/argv.js.map +1 -1
- package/dist/bin/config.d.ts +69 -0
- package/dist/bin/config.js +315 -0
- package/dist/bin/config.js.map +1 -0
- package/dist/bin/doctor.d.ts +1 -0
- package/dist/bin/doctor.js +12 -0
- package/dist/bin/doctor.js.map +1 -1
- package/dist/bin/env-defaults.d.ts +1 -0
- package/dist/bin/env-defaults.js +13 -0
- package/dist/bin/env-defaults.js.map +1 -0
- package/dist/bin/forge.js +16 -0
- package/dist/bin/forge.js.map +1 -1
- package/dist/bin/update-cli.d.ts +9 -0
- package/dist/bin/update-cli.js +120 -0
- package/dist/bin/update-cli.js.map +1 -0
- package/dist/extensions/forgecli/config-command.d.ts +8 -0
- package/dist/extensions/forgecli/config-command.js +66 -0
- package/dist/extensions/forgecli/config-command.js.map +1 -0
- package/dist/extensions/forgecli/config-layer.d.ts +38 -0
- package/dist/extensions/forgecli/config-layer.js +68 -0
- package/dist/extensions/forgecli/config-layer.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/component.d.ts +35 -0
- package/dist/extensions/forgecli/config-tui/component.js +236 -0
- package/dist/extensions/forgecli/config-tui/component.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/handler.d.ts +40 -0
- package/dist/extensions/forgecli/config-tui/handler.js +240 -0
- package/dist/extensions/forgecli/config-tui/handler.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/index.d.ts +5 -0
- package/dist/extensions/forgecli/config-tui/index.js +5 -0
- package/dist/extensions/forgecli/config-tui/index.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/keys.d.ts +26 -0
- package/dist/extensions/forgecli/config-tui/keys.js +33 -0
- package/dist/extensions/forgecli/config-tui/keys.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/plugin-config-reader.d.ts +23 -0
- package/dist/extensions/forgecli/config-tui/plugin-config-reader.js +58 -0
- package/dist/extensions/forgecli/config-tui/plugin-config-reader.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/advanced-menu.d.ts +7 -0
- package/dist/extensions/forgecli/config-tui/screens/advanced-menu.js +83 -0
- package/dist/extensions/forgecli/config-tui/screens/advanced-menu.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/confirm-quit.d.ts +11 -0
- package/dist/extensions/forgecli/config-tui/screens/confirm-quit.js +54 -0
- package/dist/extensions/forgecli/config-tui/screens/confirm-quit.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/override-editor.d.ts +11 -0
- package/dist/extensions/forgecli/config-tui/screens/override-editor.js +233 -0
- package/dist/extensions/forgecli/config-tui/screens/override-editor.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/overrides-list-phases.d.ts +7 -0
- package/dist/extensions/forgecli/config-tui/screens/overrides-list-phases.js +91 -0
- package/dist/extensions/forgecli/config-tui/screens/overrides-list-phases.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/overrides-list.d.ts +7 -0
- package/dist/extensions/forgecli/config-tui/screens/overrides-list.js +71 -0
- package/dist/extensions/forgecli/config-tui/screens/overrides-list.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/persona-editor.d.ts +10 -0
- package/dist/extensions/forgecli/config-tui/screens/persona-editor.js +182 -0
- package/dist/extensions/forgecli/config-tui/screens/persona-editor.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/persona-picker.d.ts +7 -0
- package/dist/extensions/forgecli/config-tui/screens/persona-picker.js +76 -0
- package/dist/extensions/forgecli/config-tui/screens/persona-picker.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/personas-list.d.ts +7 -0
- package/dist/extensions/forgecli/config-tui/screens/personas-list.js +98 -0
- package/dist/extensions/forgecli/config-tui/screens/personas-list.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/shared.d.ts +29 -0
- package/dist/extensions/forgecli/config-tui/screens/shared.js +100 -0
- package/dist/extensions/forgecli/config-tui/screens/shared.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/show-resolved.d.ts +23 -0
- package/dist/extensions/forgecli/config-tui/screens/show-resolved.js +128 -0
- package/dist/extensions/forgecli/config-tui/screens/show-resolved.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/tier-menu.d.ts +7 -0
- package/dist/extensions/forgecli/config-tui/screens/tier-menu.js +135 -0
- package/dist/extensions/forgecli/config-tui/screens/tier-menu.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/tier-picker.d.ts +9 -0
- package/dist/extensions/forgecli/config-tui/screens/tier-picker.js +122 -0
- package/dist/extensions/forgecli/config-tui/screens/tier-picker.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/types.d.ts +24 -0
- package/dist/extensions/forgecli/config-tui/screens/types.js +5 -0
- package/dist/extensions/forgecli/config-tui/screens/types.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens.d.ts +24 -0
- package/dist/extensions/forgecli/config-tui/screens.js +78 -0
- package/dist/extensions/forgecli/config-tui/screens.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/state/buffer.d.ts +11 -0
- package/dist/extensions/forgecli/config-tui/state/buffer.js +91 -0
- package/dist/extensions/forgecli/config-tui/state/buffer.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/state/constants.d.ts +4 -0
- package/dist/extensions/forgecli/config-tui/state/constants.js +14 -0
- package/dist/extensions/forgecli/config-tui/state/constants.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/state/index.d.ts +6 -0
- package/dist/extensions/forgecli/config-tui/state/index.js +9 -0
- package/dist/extensions/forgecli/config-tui/state/index.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/state/init.d.ts +2 -0
- package/dist/extensions/forgecli/config-tui/state/init.js +30 -0
- package/dist/extensions/forgecli/config-tui/state/init.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/state/model.d.ts +192 -0
- package/dist/extensions/forgecli/config-tui/state/model.js +4 -0
- package/dist/extensions/forgecli/config-tui/state/model.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/state/reducer.d.ts +2 -0
- package/dist/extensions/forgecli/config-tui/state/reducer.js +212 -0
- package/dist/extensions/forgecli/config-tui/state/reducer.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/state/selectors.d.ts +91 -0
- package/dist/extensions/forgecli/config-tui/state/selectors.js +231 -0
- package/dist/extensions/forgecli/config-tui/state/selectors.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/state.d.ts +6 -0
- package/dist/extensions/forgecli/config-tui/state.js +11 -0
- package/dist/extensions/forgecli/config-tui/state.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/theme.d.ts +37 -0
- package/dist/extensions/forgecli/config-tui/theme.js +88 -0
- package/dist/extensions/forgecli/config-tui/theme.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/tier-meta.d.ts +28 -0
- package/dist/extensions/forgecli/config-tui/tier-meta.js +69 -0
- package/dist/extensions/forgecli/config-tui/tier-meta.js.map +1 -0
- package/dist/extensions/forgecli/config-writer.d.ts +16 -0
- package/dist/extensions/forgecli/config-writer.js +63 -0
- package/dist/extensions/forgecli/config-writer.js.map +1 -0
- package/dist/extensions/forgecli/fix-bug.js +85 -1
- package/dist/extensions/forgecli/fix-bug.js.map +1 -1
- package/dist/extensions/forgecli/forge-cli-schema.json +54 -0
- package/dist/extensions/forgecli/forge-commands.js +3 -8
- package/dist/extensions/forgecli/forge-commands.js.map +1 -1
- package/dist/extensions/forgecli/forge-subagent.d.ts +13 -0
- package/dist/extensions/forgecli/forge-subagent.js +19 -0
- package/dist/extensions/forgecli/forge-subagent.js.map +1 -1
- package/dist/extensions/forgecli/index.js +19 -3
- package/dist/extensions/forgecli/index.js.map +1 -1
- package/dist/extensions/forgecli/input-router.d.ts +33 -0
- package/dist/extensions/forgecli/input-router.js +133 -0
- package/dist/extensions/forgecli/input-router.js.map +1 -0
- package/dist/extensions/forgecli/model-resolver.d.ts +32 -0
- package/dist/extensions/forgecli/model-resolver.js +65 -0
- package/dist/extensions/forgecli/model-resolver.js.map +1 -0
- package/dist/extensions/forgecli/model-validator.d.ts +29 -0
- package/dist/extensions/forgecli/model-validator.js +107 -0
- package/dist/extensions/forgecli/model-validator.js.map +1 -0
- package/dist/extensions/forgecli/run-sprint.js +59 -0
- package/dist/extensions/forgecli/run-sprint.js.map +1 -1
- package/dist/extensions/forgecli/run-task.js +93 -1
- package/dist/extensions/forgecli/run-task.js.map +1 -1
- package/dist/extensions/forgecli/thread-switcher.js +5 -2
- package/dist/extensions/forgecli/thread-switcher.js.map +1 -1
- package/dist/extensions/forgecli/update-check.js +1 -1
- package/dist/extensions/forgecli/update-check.js.map +1 -1
- package/dist/extensions/forgecli/whats-new-widget.d.ts +5 -5
- package/dist/extensions/forgecli/whats-new-widget.js +16 -13
- package/dist/extensions/forgecli/whats-new-widget.js.map +1 -1
- package/dist/extensions/forgecli/whats-new.js +6 -5
- package/dist/extensions/forgecli/whats-new.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +27 -98
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +62 -132
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +25 -15
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +17 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +8 -2
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +17 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js +8 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-coding-agent/CHANGELOG.md +63 -0
- package/node_modules/@earendil-works/pi-coding-agent/README.md +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/config-selector.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/config-selector.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/config-selector.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli.js +6 -10
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/config.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +12 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/config.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +30 -15
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.d.ts +3 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js +23 -13
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.d.ts +4 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.js +58 -38
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/slash-commands.js +0 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js +3 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.d.ts +2 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.js +7 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +6 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.js +3 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/changelog.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/changelog.js +2 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/changelog.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/child-process.d.ts +7 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/child-process.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/child-process.js +60 -7
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/child-process.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/docs/packages.md +2 -2
- package/node_modules/@earendil-works/pi-coding-agent/docs/settings.md +1 -3
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/sandbox/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/with-deps/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/package.json +6 -6
- package/node_modules/@earendil-works/pi-tui/package.json +2 -2
- package/node_modules/@protobufjs/fetch/CHANGELOG.md +8 -0
- package/node_modules/@protobufjs/fetch/index.d.ts +7 -7
- package/node_modules/@protobufjs/fetch/index.js +4 -7
- package/node_modules/@protobufjs/fetch/package.json +7 -5
- package/node_modules/@protobufjs/fetch/tests/data/file.txt +1 -0
- package/node_modules/@protobufjs/fetch/tests/index.js +150 -8
- package/node_modules/@protobufjs/fetch/util/fs.js +11 -0
- package/node_modules/@protobufjs/inquire/CHANGELOG.md +8 -0
- package/node_modules/@protobufjs/inquire/index.d.ts +1 -0
- package/node_modules/@protobufjs/inquire/index.js +1 -0
- package/node_modules/@protobufjs/inquire/package.json +1 -1
- package/node_modules/protobufjs/dist/light/protobuf.js +187 -153
- package/node_modules/protobufjs/dist/light/protobuf.js.map +1 -1
- package/node_modules/protobufjs/dist/light/protobuf.min.js +3 -3
- package/node_modules/protobufjs/dist/light/protobuf.min.js.map +1 -1
- package/node_modules/protobufjs/dist/minimal/protobuf.js +14 -5
- package/node_modules/protobufjs/dist/minimal/protobuf.js.map +1 -1
- package/node_modules/protobufjs/dist/minimal/protobuf.min.js +3 -3
- package/node_modules/protobufjs/dist/minimal/protobuf.min.js.map +1 -1
- package/node_modules/protobufjs/dist/protobuf.js +207 -173
- package/node_modules/protobufjs/dist/protobuf.js.map +1 -1
- package/node_modules/protobufjs/dist/protobuf.min.js +3 -3
- package/node_modules/protobufjs/dist/protobuf.min.js.map +1 -1
- package/node_modules/protobufjs/package.json +6 -3
- package/node_modules/protobufjs/src/util/fs.js +11 -0
- package/node_modules/protobufjs/src/util/minimal.js +10 -2
- package/node_modules/protobufjs/src/util.js +1 -1
- package/node_modules/undici/README.md +14 -5
- package/node_modules/undici/docs/docs/api/Client.md +4 -2
- package/node_modules/undici/docs/docs/api/Dispatcher.md +62 -27
- package/node_modules/undici/docs/docs/api/GlobalInstallation.md +7 -5
- package/node_modules/undici/docs/docs/api/H2CClient.md +1 -1
- package/node_modules/undici/docs/docs/api/RedirectHandler.md +14 -9
- package/node_modules/undici/docs/docs/api/RetryAgent.md +0 -1
- package/node_modules/undici/docs/docs/api/RetryHandler.md +12 -14
- package/node_modules/undici/docs/docs/api/SnapshotAgent.md +23 -0
- package/node_modules/undici/docs/docs/best-practices/migrating-from-v7-to-v8.md +231 -0
- package/node_modules/undici/index.js +4 -2
- package/node_modules/undici/lib/api/api-connect.js +13 -11
- package/node_modules/undici/lib/api/api-pipeline.js +26 -13
- package/node_modules/undici/lib/api/api-request.js +45 -21
- package/node_modules/undici/lib/api/api-stream.js +81 -20
- package/node_modules/undici/lib/api/api-upgrade.js +21 -11
- package/node_modules/undici/lib/api/readable.js +3 -2
- package/node_modules/undici/lib/cache/memory-cache-store.js +1 -1
- package/node_modules/undici/lib/cache/sqlite-cache-store.js +6 -4
- package/node_modules/undici/lib/core/connect.js +17 -1
- package/node_modules/undici/lib/core/constants.js +1 -24
- package/node_modules/undici/lib/core/errors.js +2 -2
- package/node_modules/undici/lib/core/request.js +115 -18
- package/node_modules/undici/lib/core/socks5-client.js +24 -9
- package/node_modules/undici/lib/core/socks5-utils.js +32 -23
- package/node_modules/undici/lib/core/symbols.js +1 -0
- package/node_modules/undici/lib/core/util.js +70 -43
- package/node_modules/undici/lib/dispatcher/agent.js +47 -33
- package/node_modules/undici/lib/dispatcher/balanced-pool.js +21 -26
- package/node_modules/undici/lib/dispatcher/client-h1.js +98 -39
- package/node_modules/undici/lib/dispatcher/client-h2.js +603 -272
- package/node_modules/undici/lib/dispatcher/client.js +12 -5
- package/node_modules/undici/lib/dispatcher/dispatcher-base.js +24 -5
- package/node_modules/undici/lib/dispatcher/dispatcher.js +0 -4
- package/node_modules/undici/lib/dispatcher/dispatcher1-wrapper.js +107 -0
- package/node_modules/undici/lib/dispatcher/h2c-client.js +5 -5
- package/node_modules/undici/lib/dispatcher/pool-base.js +28 -10
- package/node_modules/undici/lib/dispatcher/pool.js +31 -6
- package/node_modules/undici/lib/dispatcher/proxy-agent.js +38 -13
- package/node_modules/undici/lib/dispatcher/round-robin-pool.js +31 -9
- package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +95 -80
- package/node_modules/undici/lib/global.js +13 -1
- package/node_modules/undici/lib/handler/cache-handler.js +16 -8
- package/node_modules/undici/lib/handler/decorator-handler.js +1 -2
- package/node_modules/undici/lib/handler/redirect-handler.js +5 -51
- package/node_modules/undici/lib/handler/retry-handler.js +15 -2
- package/node_modules/undici/lib/interceptor/cache.js +30 -17
- package/node_modules/undici/lib/interceptor/decompress.js +28 -2
- package/node_modules/undici/lib/interceptor/dns.js +1 -1
- package/node_modules/undici/lib/interceptor/redirect.js +3 -3
- package/node_modules/undici/lib/llhttp/llhttp-wasm.js +1 -1
- package/node_modules/undici/lib/llhttp/llhttp_simd-wasm.js +1 -1
- package/node_modules/undici/lib/mock/mock-agent.js +8 -8
- package/node_modules/undici/lib/mock/mock-call-history.js +15 -15
- package/node_modules/undici/lib/mock/mock-utils.js +37 -22
- package/node_modules/undici/lib/mock/snapshot-agent.js +16 -6
- package/node_modules/undici/lib/mock/snapshot-recorder.js +38 -3
- package/node_modules/undici/lib/util/cache.js +8 -7
- package/node_modules/undici/lib/util/runtime-features.js +3 -34
- package/node_modules/undici/lib/web/cache/cache.js +6 -8
- package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +245 -150
- package/node_modules/undici/lib/web/fetch/body.js +3 -9
- package/node_modules/undici/lib/web/fetch/formdata-parser.js +17 -6
- package/node_modules/undici/lib/web/fetch/formdata.js +21 -2
- package/node_modules/undici/lib/web/fetch/index.js +214 -221
- package/node_modules/undici/lib/web/webidl/index.js +7 -9
- package/node_modules/undici/lib/web/websocket/frame.js +1 -7
- package/node_modules/undici/lib/web/websocket/permessage-deflate.js +13 -31
- package/node_modules/undici/lib/web/websocket/receiver.js +62 -22
- package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +11 -17
- package/node_modules/undici/lib/web/websocket/websocket.js +6 -1
- package/node_modules/undici/package.json +9 -9
- package/node_modules/undici/types/agent.d.ts +0 -2
- package/node_modules/undici/types/client.d.ts +25 -19
- package/node_modules/undici/types/dispatcher.d.ts +7 -27
- package/node_modules/undici/types/dispatcher1-wrapper.d.ts +7 -0
- package/node_modules/undici/types/formdata.d.ts +0 -6
- package/node_modules/undici/types/h2c-client.d.ts +6 -6
- package/node_modules/undici/types/header.d.ts +5 -0
- package/node_modules/undici/types/index.d.ts +3 -1
- package/node_modules/undici/types/interceptors.d.ts +1 -1
- package/node_modules/undici/types/pool.d.ts +0 -2
- package/node_modules/undici/types/proxy-agent.d.ts +2 -2
- package/node_modules/undici/types/round-robin-pool.d.ts +0 -2
- package/node_modules/undici/types/snapshot-agent.d.ts +4 -0
- package/node_modules/undici/types/socks5-proxy-agent.d.ts +2 -2
- package/node_modules/undici/types/webidl.d.ts +0 -1
- package/package.json +16 -9
- package/dist/extensions/forgecli/review-command.d.ts +0 -2
- package/dist/extensions/forgecli/review-command.js +0 -184
- package/dist/extensions/forgecli/review-command.js.map +0 -1
- package/dist/forge-payload/.tools/banners.cjs +0 -435
- package/dist/forge-payload/.tools/build-context-pack.cjs +0 -290
- package/dist/forge-payload/.tools/build-init-context.cjs +0 -322
- package/dist/forge-payload/.tools/build-overlay.cjs +0 -326
- package/dist/forge-payload/.tools/build-persona-pack.cjs +0 -226
- package/dist/forge-payload/.tools/collate.cjs +0 -1041
- package/dist/forge-payload/.tools/generation-manifest.cjs +0 -311
- package/dist/forge-payload/.tools/lib/forge-root.cjs +0 -59
- package/dist/forge-payload/.tools/lib/paths.cjs +0 -29
- package/dist/forge-payload/.tools/lib/pricing.cjs +0 -165
- package/dist/forge-payload/.tools/lib/project-root.cjs +0 -32
- package/dist/forge-payload/.tools/lib/result.js +0 -40
- package/dist/forge-payload/.tools/lib/store-facade.cjs +0 -162
- package/dist/forge-payload/.tools/lib/store-nlp.cjs +0 -250
- package/dist/forge-payload/.tools/lib/store-query-exec.cjs +0 -272
- package/dist/forge-payload/.tools/lib/validate.js +0 -141
- package/dist/forge-payload/.tools/manage-config.cjs +0 -340
- package/dist/forge-payload/.tools/manage-versions.cjs +0 -365
- package/dist/forge-payload/.tools/package.json +0 -3
- package/dist/forge-payload/.tools/parse-gates.cjs +0 -151
- package/dist/forge-payload/.tools/parse-verdict.cjs +0 -67
- package/dist/forge-payload/.tools/preflight-gate.cjs +0 -350
- package/dist/forge-payload/.tools/prompts/sprint-plan-prompt.md +0 -70
- package/dist/forge-payload/.tools/schemas/task-list.schema.json +0 -53
- package/dist/forge-payload/.tools/seed-store.cjs +0 -237
- package/dist/forge-payload/.tools/store-cli.cjs +0 -1226
- package/dist/forge-payload/.tools/store-query.cjs +0 -319
- package/dist/forge-payload/.tools/store.cjs +0 -315
- package/dist/forge-payload/.tools/substitute-placeholders.cjs +0 -625
- package/dist/forge-payload/.tools/validate-store.cjs +0 -593
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-anthropic/package-lock.json +0 -24
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/sandbox/package-lock.json +0 -92
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/with-deps/package-lock.json +0 -31
- package/node_modules/undici/lib/handler/unwrap-handler.js +0 -100
- package/node_modules/undici/lib/handler/wrap-handler.js +0 -105
- package/node_modules/undici/lib/llhttp/.gitkeep +0 -0
- package/node_modules/undici/lib/util/promise.js +0 -28
- package/skills/refresh-kb-links/SKILL.md +0 -217
- package/skills/store-custodian/SKILL.md +0 -163
- package/skills/store-query-grammar/SKILL.md +0 -145
- package/skills/store-query-nlp/SKILL.md +0 -110
|
@@ -1,625 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* substitute-placeholders.cjs — Phase 3 (Materialize) engine for FR-002.
|
|
6
|
-
*
|
|
7
|
-
* Reads config.json and project-context.json, walks every file under
|
|
8
|
-
* a base-pack directory, replaces {{KEY}} placeholders, and writes materialised
|
|
9
|
-
* output to the appropriate output directories.
|
|
10
|
-
*
|
|
11
|
-
* Output path mapping (--target claude-code, default):
|
|
12
|
-
* base-pack/commands/ → <outRoot>/.claude/commands/forge/
|
|
13
|
-
* base-pack/personas/ → <outRoot>/.forge/personas/
|
|
14
|
-
* base-pack/skills/ → <outRoot>/.forge/skills/
|
|
15
|
-
* base-pack/workflows/ → <outRoot>/.forge/workflows/
|
|
16
|
-
* base-pack/templates/ → <outRoot>/.forge/templates/
|
|
17
|
-
*
|
|
18
|
-
* Output path mapping (--target pi):
|
|
19
|
-
* base-pack/personas/ → <outRoot>/personas/
|
|
20
|
-
* base-pack/skills/ → <outRoot>/skills/
|
|
21
|
-
* base-pack/workflows/ → <outRoot>/workflows/ (including _fragments/)
|
|
22
|
-
* base-pack/templates/ → <outRoot>/templates/
|
|
23
|
-
* base-pack/commands/ → SKIPPED (pi commands are registered programmatically)
|
|
24
|
-
*
|
|
25
|
-
* CLI:
|
|
26
|
-
* node substitute-placeholders.cjs
|
|
27
|
-
* [--target <claude-code|pi>] (default: claude-code)
|
|
28
|
-
* [--src <path>] (base-pack source dir for --target pi)
|
|
29
|
-
* [--forge-root <path>]
|
|
30
|
-
* [--base-pack <path>]
|
|
31
|
-
* [--config <path>]
|
|
32
|
-
* [--context <path>]
|
|
33
|
-
* [--rules <path>]
|
|
34
|
-
* [--out <projectRoot>]
|
|
35
|
-
* [--dry-run]
|
|
36
|
-
*
|
|
37
|
-
* Exported API (for unit testing):
|
|
38
|
-
* buildSubstitutionMap(config, context, rules?)
|
|
39
|
-
* applySubstitutions(text, map)
|
|
40
|
-
* extractFrontmatter(content)
|
|
41
|
-
* substituteFile(content, map)
|
|
42
|
-
* walkBasePackPi(src, outRoot, dryRun, io)
|
|
43
|
-
* PI_TARGET_SUBDIRS
|
|
44
|
-
* REQUIRED_KEYS
|
|
45
|
-
* RUNTIME_PASSTHROUGH_KEYS
|
|
46
|
-
*/
|
|
47
|
-
|
|
48
|
-
const fs = require('node:fs');
|
|
49
|
-
const path = require('node:path');
|
|
50
|
-
const { getCommandsSubdir } = require('./lib/paths.cjs');
|
|
51
|
-
|
|
52
|
-
// ── Constants ────────────────────────────────────────────────────────────────
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Keys that must be present in the substitution map. Their absence causes
|
|
56
|
-
* process.exit(1) (or a throw in library mode).
|
|
57
|
-
*/
|
|
58
|
-
const REQUIRED_KEYS = new Set(['PROJECT_NAME', 'PREFIX']);
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Runtime passthrough keys: placeholders filled at runtime by tools such as
|
|
62
|
-
* collate.cjs. These MUST NOT be replaced by this tool. Any {{KEY}} whose key
|
|
63
|
-
* is in this set is left untouched in the output.
|
|
64
|
-
*/
|
|
65
|
-
const RUNTIME_PASSTHROUGH_KEYS = new Set([
|
|
66
|
-
'DATE',
|
|
67
|
-
'SPRINT_ID',
|
|
68
|
-
'TASK_ID',
|
|
69
|
-
'ROLE',
|
|
70
|
-
'MODEL',
|
|
71
|
-
'PHASES',
|
|
72
|
-
'INPUT',
|
|
73
|
-
'OUTPUT',
|
|
74
|
-
'COST',
|
|
75
|
-
'INPUT_TOKENS',
|
|
76
|
-
'OUTPUT_TOKENS',
|
|
77
|
-
'CACHE_READ',
|
|
78
|
-
'CACHE_WRITE',
|
|
79
|
-
'TOTAL_INPUT_TOKENS',
|
|
80
|
-
'TOTAL_OUTPUT_TOKENS',
|
|
81
|
-
'TOTAL_CACHE_READ_TOKENS',
|
|
82
|
-
'TOTAL_CACHE_WRITE_TOKENS',
|
|
83
|
-
'TOTAL_COST_USD',
|
|
84
|
-
'placeholder',
|
|
85
|
-
]);
|
|
86
|
-
|
|
87
|
-
// ── Output path mapping ──────────────────────────────────────────────────────
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Maps a base-pack subdirectory name to an output directory path relative to
|
|
91
|
-
* the project root. The 'commands' entry is computed dynamically from the
|
|
92
|
-
* project prefix via getCommandsSubdir() — see walkBasePack.
|
|
93
|
-
*/
|
|
94
|
-
const SUBDIR_OUTPUT_MAP = {
|
|
95
|
-
personas: path.join('.forge', 'personas'),
|
|
96
|
-
skills: path.join('.forge', 'skills'),
|
|
97
|
-
workflows: path.join('.forge', 'workflows'),
|
|
98
|
-
templates: path.join('.forge', 'templates'),
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Subdirectories included when --target pi is used.
|
|
103
|
-
* 'commands' is explicitly excluded — pi commands are registered
|
|
104
|
-
* programmatically in TypeScript, not via .md files.
|
|
105
|
-
*
|
|
106
|
-
* Exported for unit tests (Test Group 15).
|
|
107
|
-
*/
|
|
108
|
-
const PI_TARGET_SUBDIRS = new Set(['workflows', 'personas', 'skills', 'templates']);
|
|
109
|
-
|
|
110
|
-
// ── Frontmatter extraction ───────────────────────────────────────────────────
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Extract YAML frontmatter from a file's content.
|
|
114
|
-
*
|
|
115
|
-
* The opening `---` must be at line 1, column 0 (no leading whitespace) to
|
|
116
|
-
* avoid false positives from `---` horizontal rules in Markdown body content.
|
|
117
|
-
*
|
|
118
|
-
* @param {string} content
|
|
119
|
-
* @returns {{ frontmatter: string|null, body: string }}
|
|
120
|
-
*/
|
|
121
|
-
function extractFrontmatter(content) {
|
|
122
|
-
// Opening --- must be at the very start of the file, at column 0.
|
|
123
|
-
if (!content.startsWith('---\n') && !content.startsWith('---\r\n')) {
|
|
124
|
-
return { frontmatter: null, body: content };
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Find the closing ---
|
|
128
|
-
const lines = content.split('\n');
|
|
129
|
-
for (let i = 1; i < lines.length; i++) {
|
|
130
|
-
if (lines[i] === '---' || lines[i] === '---\r') {
|
|
131
|
-
// Closing delimiter found at line i (0-indexed)
|
|
132
|
-
// Reconstruct frontmatter (lines 0..i inclusive) and body (lines i+1..)
|
|
133
|
-
const frontmatterLines = lines.slice(0, i + 1);
|
|
134
|
-
const bodyLines = lines.slice(i + 1);
|
|
135
|
-
|
|
136
|
-
// Re-attach trailing newline to closing --- so frontmatter ends with \n
|
|
137
|
-
const frontmatter = frontmatterLines.join('\n') + '\n';
|
|
138
|
-
const body = bodyLines.join('\n');
|
|
139
|
-
|
|
140
|
-
return { frontmatter, body };
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// No closing --- found — treat entire content as body (malformed frontmatter)
|
|
145
|
-
return { frontmatter: null, body: content };
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// ── Substitution ─────────────────────────────────────────────────────────────
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Apply substitution map to a string. Keys in RUNTIME_PASSTHROUGH_KEYS are
|
|
152
|
-
* left intact. Unknown keys are also left intact (missing optional keys).
|
|
153
|
-
*
|
|
154
|
-
* @param {string} text
|
|
155
|
-
* @param {Map<string, string>} map
|
|
156
|
-
* @returns {string}
|
|
157
|
-
*/
|
|
158
|
-
function applySubstitutions(text, map) {
|
|
159
|
-
// Only match placeholders whose keys are ALL_CAPS_WITH_UNDERSCORES or
|
|
160
|
-
// lowercase-with-hyphens (for skill names). Dot-notation is intentionally
|
|
161
|
-
// NOT matched — T03 uses flat keys only.
|
|
162
|
-
return text.replace(/\{\{([A-Za-z][A-Za-z0-9_-]*)\}\}/g, (full, key) => {
|
|
163
|
-
if (RUNTIME_PASSTHROUGH_KEYS.has(key)) return full;
|
|
164
|
-
if (map.has(key)) return map.get(key);
|
|
165
|
-
// Unknown key — leave intact (missing optional)
|
|
166
|
-
return full;
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Apply substitutions to a file's content, preserving frontmatter byte-for-byte.
|
|
172
|
-
*
|
|
173
|
-
* @param {string} content
|
|
174
|
-
* @param {Map<string, string>} map
|
|
175
|
-
* @returns {string}
|
|
176
|
-
*/
|
|
177
|
-
function substituteFile(content, map) {
|
|
178
|
-
const { frontmatter, body } = extractFrontmatter(content);
|
|
179
|
-
if (frontmatter === null) {
|
|
180
|
-
return applySubstitutions(content, map);
|
|
181
|
-
}
|
|
182
|
-
// Frontmatter is preserved byte-for-byte; only the body gets substitution
|
|
183
|
-
return frontmatter + applySubstitutions(body, map);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// ── Substitution map builder ──────────────────────────────────────────────────
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Build the flat substitution map from config.json and project-context.json.
|
|
190
|
-
*
|
|
191
|
-
* @param {object} config — parsed .forge/config.json
|
|
192
|
-
* @param {object|null} context — parsed project-context.json (may be null)
|
|
193
|
-
* @param {object|null} rules — parsed build-base-pack-rules.json (optional;
|
|
194
|
-
* loaded from forge root if omitted in CLI mode)
|
|
195
|
-
* @returns {Map<string, string>}
|
|
196
|
-
* @throws {Error} if PROJECT_NAME or PREFIX is missing
|
|
197
|
-
*/
|
|
198
|
-
function buildSubstitutionMap(config, context, rules) {
|
|
199
|
-
const project = (config && config.project) || {};
|
|
200
|
-
const commands = (config && config.commands) || {};
|
|
201
|
-
const paths = (config && config.paths) || {};
|
|
202
|
-
const engRoot = paths.engineering || 'engineering';
|
|
203
|
-
|
|
204
|
-
// ── Validate required keys ─────────────────────────────────────────────────
|
|
205
|
-
// PROJECT_NAME is sourced from config.project.name OR context.project.name
|
|
206
|
-
const projectName = (project.name) || (context && context.project && context.project.name) || '';
|
|
207
|
-
const prefix = (project.prefix) || (context && context.project && context.project.prefix) || '';
|
|
208
|
-
|
|
209
|
-
if (!projectName) {
|
|
210
|
-
throw new Error('substitute-placeholders: missing required key PROJECT_NAME (config.project.name)');
|
|
211
|
-
}
|
|
212
|
-
if (!prefix) {
|
|
213
|
-
throw new Error('substitute-placeholders: missing required key PREFIX (config.project.prefix)');
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
const map = new Map();
|
|
217
|
-
|
|
218
|
-
// ── Config-sourced keys ────────────────────────────────────────────────────
|
|
219
|
-
map.set('PROJECT_NAME', projectName);
|
|
220
|
-
map.set('PREFIX', prefix);
|
|
221
|
-
map.set('TEST_COMMAND', commands.test || '');
|
|
222
|
-
map.set('LINT_COMMAND', commands.lint || '');
|
|
223
|
-
map.set('KB_PATH', engRoot + '/architecture');
|
|
224
|
-
|
|
225
|
-
// ── project-context.json sourced keys ─────────────────────────────────────
|
|
226
|
-
if (context) {
|
|
227
|
-
const arch = context.architecture || {};
|
|
228
|
-
const frameworks = arch.frameworks || {};
|
|
229
|
-
const deployment = context.deployment || {};
|
|
230
|
-
const conventions = context.conventions || {};
|
|
231
|
-
const verification = context.verification || {};
|
|
232
|
-
|
|
233
|
-
// ENTITY_MODEL — entities array joined with ', '
|
|
234
|
-
const entities = Array.isArray(context.entities) ? context.entities : [];
|
|
235
|
-
map.set('ENTITY_MODEL', entities.join(', '));
|
|
236
|
-
|
|
237
|
-
// DATA_ACCESS — direct string
|
|
238
|
-
map.set('DATA_ACCESS', arch.dataAccess || '');
|
|
239
|
-
|
|
240
|
-
// KEY_DIRECTORIES — array joined with ', '
|
|
241
|
-
const keyDirs = Array.isArray(arch.keyDirectories) ? arch.keyDirectories : [];
|
|
242
|
-
map.set('KEY_DIRECTORIES', keyDirs.join(', '));
|
|
243
|
-
|
|
244
|
-
// TECHNICAL_DEBT — array joined with ', '
|
|
245
|
-
const techDebt = Array.isArray(context.technicalDebt) ? context.technicalDebt : [];
|
|
246
|
-
map.set('TECHNICAL_DEBT', techDebt.join(', '));
|
|
247
|
-
|
|
248
|
-
// IMPACT_CATEGORIES — array joined with ', '
|
|
249
|
-
const impact = Array.isArray(context.impactCategories) ? context.impactCategories : [];
|
|
250
|
-
map.set('IMPACT_CATEGORIES', impact.join(', '));
|
|
251
|
-
|
|
252
|
-
// DEPLOYMENT_ENVIRONMENTS — markdown table
|
|
253
|
-
const envs = Array.isArray(deployment.environments) ? deployment.environments : [];
|
|
254
|
-
map.set('DEPLOYMENT_ENVIRONMENTS', renderDeploymentTable(envs));
|
|
255
|
-
|
|
256
|
-
// BRANCHING_CONVENTION — direct string
|
|
257
|
-
map.set('BRANCHING_CONVENTION', conventions.branching || '');
|
|
258
|
-
|
|
259
|
-
// STACK_SUMMARY — backend + frontend + database, empty parts omitted
|
|
260
|
-
const stackParts = [frameworks.backend, frameworks.frontend, frameworks.database]
|
|
261
|
-
.filter(Boolean);
|
|
262
|
-
map.set('STACK_SUMMARY', stackParts.join(' + '));
|
|
263
|
-
|
|
264
|
-
// VERIFICATION_COMMANDS — comma-separated non-empty command values
|
|
265
|
-
const verificationValues = Object.values(verification).filter(Boolean);
|
|
266
|
-
map.set('VERIFICATION_COMMANDS', verificationValues.join(', '));
|
|
267
|
-
|
|
268
|
-
// SKILL_DIRECTIVES — 'skill → persona1, persona2' per entry
|
|
269
|
-
const skillWiring = Array.isArray(context.skillWiring) ? context.skillWiring : [];
|
|
270
|
-
const skillLines = skillWiring.map(entry => {
|
|
271
|
-
const personas = Array.isArray(entry.personas) ? entry.personas : [];
|
|
272
|
-
return `${entry.skill} → ${personas.join(', ')}`;
|
|
273
|
-
});
|
|
274
|
-
map.set('SKILL_DIRECTIVES', skillLines.join('\n'));
|
|
275
|
-
} else {
|
|
276
|
-
// No context — set defaults for all context-sourced keys
|
|
277
|
-
for (const key of [
|
|
278
|
-
'ENTITY_MODEL', 'DATA_ACCESS', 'KEY_DIRECTORIES', 'TECHNICAL_DEBT',
|
|
279
|
-
'IMPACT_CATEGORIES', 'DEPLOYMENT_ENVIRONMENTS', 'BRANCHING_CONVENTION',
|
|
280
|
-
'STACK_SUMMARY', 'VERIFICATION_COMMANDS', 'SKILL_DIRECTIVES',
|
|
281
|
-
]) {
|
|
282
|
-
map.set(key, '');
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// ── Skill-context blocks ───────────────────────────────────────────────────
|
|
287
|
-
// These are rendered by joining the pre-substituted lines with \n and then
|
|
288
|
-
// performing normal placeholder substitution on the joined block.
|
|
289
|
-
//
|
|
290
|
-
// Advisory Note 1: GENERIC_SKILL_PROJECT_CONTEXT uses empty array if the
|
|
291
|
-
// 'generic' key is absent from personaProjectContext (treat as empty, not throw).
|
|
292
|
-
|
|
293
|
-
const personaContextMap = (rules && rules.personaProjectContext) || {};
|
|
294
|
-
|
|
295
|
-
const PERSONA_CONTEXT_KEYS = {
|
|
296
|
-
ARCHITECT_SKILL_PROJECT_CONTEXT: 'architect',
|
|
297
|
-
ENGINEER_SKILL_PROJECT_CONTEXT: 'engineer',
|
|
298
|
-
SUPERVISOR_SKILL_PROJECT_CONTEXT: 'supervisor',
|
|
299
|
-
COLLATOR_SKILL_PROJECT_CONTEXT: 'collator',
|
|
300
|
-
BUG_FIXER_SKILL_PROJECT_CONTEXT: 'bug-fixer',
|
|
301
|
-
QA_ENGINEER_SKILL_PROJECT_CONTEXT: 'qa-engineer',
|
|
302
|
-
GENERIC_SKILL_PROJECT_CONTEXT: 'generic',
|
|
303
|
-
};
|
|
304
|
-
|
|
305
|
-
for (const [placeholder, personaKey] of Object.entries(PERSONA_CONTEXT_KEYS)) {
|
|
306
|
-
const lines = Array.isArray(personaContextMap[personaKey]) ? personaContextMap[personaKey] : [];
|
|
307
|
-
if (lines.length === 0) {
|
|
308
|
-
map.set(placeholder, '');
|
|
309
|
-
continue;
|
|
310
|
-
}
|
|
311
|
-
// Join lines, then apply substitutions from the map built so far
|
|
312
|
-
const raw = lines.join('\n');
|
|
313
|
-
const substituted = applySubstitutions(raw, map);
|
|
314
|
-
map.set(placeholder, substituted);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
return map;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// ── Rendering helpers ─────────────────────────────────────────────────────────
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* Render a deployment environments array as a Markdown table.
|
|
324
|
-
*
|
|
325
|
-
* @param {Array<{name:string, frontend:string, backend:string, region:string}>} envs
|
|
326
|
-
* @returns {string}
|
|
327
|
-
*/
|
|
328
|
-
function renderDeploymentTable(envs) {
|
|
329
|
-
if (!Array.isArray(envs) || envs.length === 0) return '';
|
|
330
|
-
const header = '| Environment | Frontend | Backend | Region |';
|
|
331
|
-
const sep = '|---|---|---|---|';
|
|
332
|
-
const rows = envs.map(e =>
|
|
333
|
-
`| ${e.name || ''} | ${e.frontend || ''} | ${e.backend || ''} | ${e.region || ''} |`
|
|
334
|
-
);
|
|
335
|
-
return [header, sep, ...rows].join('\n');
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// ── Walker ────────────────────────────────────────────────────────────────────
|
|
339
|
-
|
|
340
|
-
/**
|
|
341
|
-
* Walk the base-pack directory and write substituted files to outRoot.
|
|
342
|
-
*
|
|
343
|
-
* Advisory Note 3: every output path is resolved and checked to be under outRoot
|
|
344
|
-
* to prevent path traversal via symlinks or '..' segments.
|
|
345
|
-
*
|
|
346
|
-
* @param {string} basePack — absolute path to the base-pack directory
|
|
347
|
-
* @param {Map<string, string>} map
|
|
348
|
-
* @param {string} outRoot — absolute project root (e.g. '/home/user/myproject')
|
|
349
|
-
* @param {boolean} dryRun — if true, perform no writes
|
|
350
|
-
* @param {{ warn: function }} io — pluggable stderr for warnings
|
|
351
|
-
*/
|
|
352
|
-
function walkBasePack(basePack, map, outRoot, dryRun, io) {
|
|
353
|
-
const warn = (io && io.warn) || ((msg) => process.stderr.write(msg + '\n'));
|
|
354
|
-
|
|
355
|
-
// Extract prefix from substitution map for commands path computation
|
|
356
|
-
const prefix = map.get('PREFIX') || '';
|
|
357
|
-
const commandsSubdir = prefix ? getCommandsSubdir(prefix) : 'forge';
|
|
358
|
-
|
|
359
|
-
// Sorted readdir for deterministic idempotent output (Advisory Note 7)
|
|
360
|
-
const topEntries = fs.readdirSync(basePack).sort();
|
|
361
|
-
for (const subdir of topEntries) {
|
|
362
|
-
const subdirPath = path.join(basePack, subdir);
|
|
363
|
-
const stat = fs.statSync(subdirPath);
|
|
364
|
-
if (!stat.isDirectory()) continue;
|
|
365
|
-
|
|
366
|
-
let relOutputDir;
|
|
367
|
-
if (subdir === 'commands') {
|
|
368
|
-
relOutputDir = path.join('.claude', 'commands', commandsSubdir);
|
|
369
|
-
} else {
|
|
370
|
-
relOutputDir = SUBDIR_OUTPUT_MAP[subdir];
|
|
371
|
-
}
|
|
372
|
-
if (!relOutputDir) {
|
|
373
|
-
warn(`substitute-placeholders: unknown base-pack subdir "${subdir}" — skipping`);
|
|
374
|
-
continue;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
walkDir(subdirPath, relOutputDir, outRoot, map, dryRun, warn);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* Recursively walk a directory, substituting and writing each file.
|
|
383
|
-
*
|
|
384
|
-
* FR-004 fix: uses `entry` (bare filename from readdirSync) instead of
|
|
385
|
-
* `path.relative(baseDir, srcPath)` which caused double-nesting when
|
|
386
|
-
* recursing into subdirectories like _fragments/. The output directory
|
|
387
|
-
* is already tracked via `relOutputDir` (updated on each recursive
|
|
388
|
-
* descent), so using just the filename is sufficient.
|
|
389
|
-
*/
|
|
390
|
-
function walkDir(currentDir, relOutputDir, outRoot, map, dryRun, warn) {
|
|
391
|
-
const entries = fs.readdirSync(currentDir).sort();
|
|
392
|
-
for (const entry of entries) {
|
|
393
|
-
const srcPath = path.join(currentDir, entry);
|
|
394
|
-
const stat = fs.statSync(srcPath);
|
|
395
|
-
|
|
396
|
-
if (stat.isDirectory()) {
|
|
397
|
-
const childRelOutputDir = path.join(relOutputDir, entry);
|
|
398
|
-
walkDir(srcPath, childRelOutputDir, outRoot, map, dryRun, warn);
|
|
399
|
-
continue;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
if (!stat.isFile()) continue;
|
|
403
|
-
|
|
404
|
-
const relFile = entry;
|
|
405
|
-
const outPath = path.resolve(outRoot, relOutputDir, relFile);
|
|
406
|
-
|
|
407
|
-
// Path traversal defence: outPath must be inside outRoot
|
|
408
|
-
const safeOutRoot = path.resolve(outRoot);
|
|
409
|
-
if (!outPath.startsWith(safeOutRoot + path.sep) && outPath !== safeOutRoot) {
|
|
410
|
-
warn(`substitute-placeholders: skipping file outside outRoot: ${outPath}`);
|
|
411
|
-
continue;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
const content = fs.readFileSync(srcPath, 'utf8');
|
|
415
|
-
const substituted = substituteFile(content, map);
|
|
416
|
-
|
|
417
|
-
if (!dryRun) {
|
|
418
|
-
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
419
|
-
fs.writeFileSync(outPath, substituted, 'utf8');
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// ── Pi target walker ─────────────────────────────────────────────────────────
|
|
425
|
-
|
|
426
|
-
/**
|
|
427
|
-
* Walk the base-pack directory and write files to outRoot for --target pi.
|
|
428
|
-
*
|
|
429
|
-
* Shares ~80% of walkBasePack logic; differs only in output-path mapping:
|
|
430
|
-
* - Output is flat (e.g., `workflows/` not `.forge/workflows/`)
|
|
431
|
-
* - Only PI_TARGET_SUBDIRS are included; all others are silently skipped
|
|
432
|
-
* - Substitution map is always new Map() — all {{KEY}} tokens preserved
|
|
433
|
-
* - Path-traversal defence (same outPath.startsWith(safeOutRoot) check as walkBasePack)
|
|
434
|
-
*
|
|
435
|
-
* @param {string} src — absolute path to base-pack source directory
|
|
436
|
-
* @param {string} outRoot — absolute output root
|
|
437
|
-
* @param {boolean} dryRun — if true, perform no writes
|
|
438
|
-
* @param {{ warn: function }} io — pluggable stderr for warnings
|
|
439
|
-
*/
|
|
440
|
-
function walkBasePackPi(src, outRoot, dryRun, io) {
|
|
441
|
-
const warn = (io && io.warn) || ((msg) => process.stderr.write(msg + '\n'));
|
|
442
|
-
|
|
443
|
-
// Empty substitution map — all {{KEY}} tokens preserved (pass-through)
|
|
444
|
-
const emptyMap = new Map();
|
|
445
|
-
|
|
446
|
-
const topEntries = fs.readdirSync(src).sort();
|
|
447
|
-
for (const subdir of topEntries) {
|
|
448
|
-
const subdirPath = path.join(src, subdir);
|
|
449
|
-
const stat = fs.statSync(subdirPath);
|
|
450
|
-
if (!stat.isDirectory()) continue;
|
|
451
|
-
|
|
452
|
-
if (!PI_TARGET_SUBDIRS.has(subdir)) {
|
|
453
|
-
// Expected skips (e.g., commands/) are debug-level; no user-facing warning
|
|
454
|
-
continue;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// Flat layout: output directly to outRoot/<subdir>/... (no .forge/ wrapper)
|
|
458
|
-
walkDir(subdirPath, subdir, outRoot, emptyMap, dryRun, warn);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
// ── CLI entry point ───────────────────────────────────────────────────────────
|
|
463
|
-
|
|
464
|
-
if (require.main === module) {
|
|
465
|
-
try {
|
|
466
|
-
const argv = process.argv.slice(2);
|
|
467
|
-
const args = parseCliArgs(argv);
|
|
468
|
-
|
|
469
|
-
const dryRun = args.dryRun || false;
|
|
470
|
-
const target = args.target || 'claude-code';
|
|
471
|
-
|
|
472
|
-
// Validate target
|
|
473
|
-
const VALID_TARGETS = new Set(['claude-code', 'pi']);
|
|
474
|
-
if (!VALID_TARGETS.has(target)) {
|
|
475
|
-
process.stderr.write(
|
|
476
|
-
`substitute-placeholders: unknown --target "${target}". Valid targets: claude-code, pi\n`
|
|
477
|
-
);
|
|
478
|
-
process.exit(1);
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
// Resolve output root
|
|
482
|
-
const outRoot = args.out || process.cwd();
|
|
483
|
-
|
|
484
|
-
if (target === 'pi') {
|
|
485
|
-
// ── --target pi dispatch ──────────────────────────────────────────────
|
|
486
|
-
|
|
487
|
-
// Warn if --config, --context, or --rules were passed (they are ignored)
|
|
488
|
-
if (args.config || args.context || args.rules) {
|
|
489
|
-
process.stderr.write(
|
|
490
|
-
'Warning: --config and --context are ignored when --target pi\n'
|
|
491
|
-
);
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
// Resolve --src (default: <forgeRoot>/init/base-pack)
|
|
495
|
-
const forgeRoot = args.forgeRoot || resolveForgeRoot();
|
|
496
|
-
const src = args.src || path.join(forgeRoot, 'init', 'base-pack');
|
|
497
|
-
if (!fs.existsSync(src)) {
|
|
498
|
-
process.stderr.write(`substitute-placeholders: --src path not found at ${src}\n`);
|
|
499
|
-
process.exit(1);
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
// Walk pi base-pack (pass-through, no substitution)
|
|
503
|
-
walkBasePackPi(src, outRoot, dryRun, null);
|
|
504
|
-
|
|
505
|
-
if (dryRun) {
|
|
506
|
-
process.stdout.write('substitute-placeholders: dry run complete (no files written)\n');
|
|
507
|
-
} else {
|
|
508
|
-
process.stdout.write('substitute-placeholders: pi layout complete\n');
|
|
509
|
-
}
|
|
510
|
-
process.exit(0);
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
// ── --target claude-code dispatch (default) ───────────────────────────────
|
|
514
|
-
|
|
515
|
-
// Resolve forge root
|
|
516
|
-
const forgeRoot = args.forgeRoot || resolveForgeRoot();
|
|
517
|
-
|
|
518
|
-
// Resolve base-pack
|
|
519
|
-
const basePack = args.basePack || path.join(forgeRoot, 'init', 'base-pack');
|
|
520
|
-
if (!fs.existsSync(basePack)) {
|
|
521
|
-
process.stderr.write(`substitute-placeholders: base-pack not found at ${basePack}\n`);
|
|
522
|
-
process.exit(1);
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
// Resolve config
|
|
526
|
-
const configPath = args.config || path.resolve(process.cwd(), '.forge', 'config.json');
|
|
527
|
-
if (!fs.existsSync(configPath)) {
|
|
528
|
-
process.stderr.write(`substitute-placeholders: config not found at ${configPath}\n`);
|
|
529
|
-
process.exit(1);
|
|
530
|
-
}
|
|
531
|
-
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
532
|
-
|
|
533
|
-
// Resolve project-context (optional)
|
|
534
|
-
let context = null;
|
|
535
|
-
const contextPath = args.context;
|
|
536
|
-
if (contextPath) {
|
|
537
|
-
if (!fs.existsSync(contextPath)) {
|
|
538
|
-
process.stderr.write(`substitute-placeholders: context not found at ${contextPath}\n`);
|
|
539
|
-
process.exit(1);
|
|
540
|
-
}
|
|
541
|
-
context = JSON.parse(fs.readFileSync(contextPath, 'utf8'));
|
|
542
|
-
} else {
|
|
543
|
-
// Try default location
|
|
544
|
-
const defaultContext = path.resolve(process.cwd(), '.forge', 'project-context.json');
|
|
545
|
-
if (fs.existsSync(defaultContext)) {
|
|
546
|
-
context = JSON.parse(fs.readFileSync(defaultContext, 'utf8'));
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
// Resolve build-base-pack-rules.json (optional)
|
|
551
|
-
let rules = null;
|
|
552
|
-
const rulesPath = args.rules || path.join(forgeRoot, 'tools', 'build-base-pack-rules.json');
|
|
553
|
-
if (fs.existsSync(rulesPath)) {
|
|
554
|
-
rules = JSON.parse(fs.readFileSync(rulesPath, 'utf8'));
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
// Build substitution map — exits 1 if required keys are missing
|
|
558
|
-
let map;
|
|
559
|
-
try {
|
|
560
|
-
map = buildSubstitutionMap(config, context, rules);
|
|
561
|
-
} catch (err) {
|
|
562
|
-
process.stderr.write(err.message + '\n');
|
|
563
|
-
process.exit(1);
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
// Walk and materialise
|
|
567
|
-
walkBasePack(basePack, map, outRoot, dryRun, null);
|
|
568
|
-
|
|
569
|
-
if (dryRun) {
|
|
570
|
-
process.stdout.write('substitute-placeholders: dry run complete (no files written)\n');
|
|
571
|
-
} else {
|
|
572
|
-
process.stdout.write('substitute-placeholders: materialisation complete\n');
|
|
573
|
-
}
|
|
574
|
-
process.exit(0);
|
|
575
|
-
} catch (err) {
|
|
576
|
-
process.stderr.write(`substitute-placeholders: fatal error: ${err.message}\n`);
|
|
577
|
-
process.exit(1);
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
// ── CLI argument parser ───────────────────────────────────────────────────────
|
|
582
|
-
|
|
583
|
-
function parseCliArgs(argv) {
|
|
584
|
-
const args = {};
|
|
585
|
-
for (let i = 0; i < argv.length; i++) {
|
|
586
|
-
const a = argv[i];
|
|
587
|
-
if (a === '--dry-run') { args.dryRun = true; continue; }
|
|
588
|
-
if (a === '--target' && argv[i + 1]) { args.target = argv[++i]; continue; }
|
|
589
|
-
if (a === '--src' && argv[i + 1]) { args.src = argv[++i]; continue; }
|
|
590
|
-
if (a === '--forge-root' && argv[i + 1]) { args.forgeRoot = argv[++i]; continue; }
|
|
591
|
-
if (a === '--base-pack' && argv[i + 1]) { args.basePack = argv[++i]; continue; }
|
|
592
|
-
if (a === '--config' && argv[i + 1]) { args.config = argv[++i]; continue; }
|
|
593
|
-
if (a === '--context' && argv[i + 1]) { args.context = argv[++i]; continue; }
|
|
594
|
-
if (a === '--rules' && argv[i + 1]) { args.rules = argv[++i]; continue; }
|
|
595
|
-
if (a === '--out' && argv[i + 1]) { args.out = argv[++i]; continue; }
|
|
596
|
-
}
|
|
597
|
-
return args;
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
// ── Forge root resolver ───────────────────────────────────────────────────────
|
|
601
|
-
|
|
602
|
-
function resolveForgeRoot() {
|
|
603
|
-
const configPath = path.resolve(process.cwd(), '.forge', 'config.json');
|
|
604
|
-
if (fs.existsSync(configPath)) {
|
|
605
|
-
try {
|
|
606
|
-
const cfg = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
607
|
-
if (cfg.paths && cfg.paths.forgeRoot) return cfg.paths.forgeRoot;
|
|
608
|
-
} catch (_) { /* fall through */ }
|
|
609
|
-
}
|
|
610
|
-
// Default: assume we're running from within forge/forge/tools/
|
|
611
|
-
return path.resolve(__dirname, '..');
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
// ── Exports (for unit testing) ────────────────────────────────────────────────
|
|
615
|
-
|
|
616
|
-
module.exports = {
|
|
617
|
-
buildSubstitutionMap,
|
|
618
|
-
applySubstitutions,
|
|
619
|
-
extractFrontmatter,
|
|
620
|
-
substituteFile,
|
|
621
|
-
walkBasePackPi, // NEW — layout-reshape walker for --target pi
|
|
622
|
-
PI_TARGET_SUBDIRS, // NEW — exported constant for tests
|
|
623
|
-
REQUIRED_KEYS,
|
|
624
|
-
RUNTIME_PASSTHROUGH_KEYS,
|
|
625
|
-
};
|