@blxzer/pactile 0.5.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 +602 -0
- package/LICENSE +235 -0
- package/README.md +115 -0
- package/README.zh-CN.md +115 -0
- package/bin/compat-warning.js +11 -0
- package/bin/cstl.js +6 -0
- package/bin/pactile.js +3 -0
- package/bin/smart-search.js +38 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +362 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/commands/capability-smoke.d.ts +24 -0
- package/dist/commands/capability-smoke.d.ts.map +1 -0
- package/dist/commands/capability-smoke.js +83 -0
- package/dist/commands/capability-smoke.js.map +1 -0
- package/dist/commands/channel/adapters/claude.d.ts +29 -0
- package/dist/commands/channel/adapters/claude.d.ts.map +1 -0
- package/dist/commands/channel/adapters/claude.js +203 -0
- package/dist/commands/channel/adapters/claude.js.map +1 -0
- package/dist/commands/channel/adapters/codex.d.ts +85 -0
- package/dist/commands/channel/adapters/codex.d.ts.map +1 -0
- package/dist/commands/channel/adapters/codex.js +505 -0
- package/dist/commands/channel/adapters/codex.js.map +1 -0
- package/dist/commands/channel/adapters/index.d.ts +84 -0
- package/dist/commands/channel/adapters/index.d.ts.map +1 -0
- package/dist/commands/channel/adapters/index.js +115 -0
- package/dist/commands/channel/adapters/index.js.map +1 -0
- package/dist/commands/channel/adapters/types.d.ts +33 -0
- package/dist/commands/channel/adapters/types.d.ts.map +1 -0
- package/dist/commands/channel/adapters/types.js +2 -0
- package/dist/commands/channel/adapters/types.js.map +1 -0
- package/dist/commands/channel/agent-loader.d.ts +32 -0
- package/dist/commands/channel/agent-loader.d.ts.map +1 -0
- package/dist/commands/channel/agent-loader.js +154 -0
- package/dist/commands/channel/agent-loader.js.map +1 -0
- package/dist/commands/channel/context-loader.d.ts +26 -0
- package/dist/commands/channel/context-loader.d.ts.map +1 -0
- package/dist/commands/channel/context-loader.js +290 -0
- package/dist/commands/channel/context-loader.js.map +1 -0
- package/dist/commands/channel/context.d.ts +16 -0
- package/dist/commands/channel/context.d.ts.map +1 -0
- package/dist/commands/channel/context.js +83 -0
- package/dist/commands/channel/context.js.map +1 -0
- package/dist/commands/channel/create.d.ts +27 -0
- package/dist/commands/channel/create.d.ts.map +1 -0
- package/dist/commands/channel/create.js +39 -0
- package/dist/commands/channel/create.js.map +1 -0
- package/dist/commands/channel/dev-parse-trace.d.ts +14 -0
- package/dist/commands/channel/dev-parse-trace.d.ts.map +1 -0
- package/dist/commands/channel/dev-parse-trace.js +70 -0
- package/dist/commands/channel/dev-parse-trace.js.map +1 -0
- package/dist/commands/channel/guard.d.ts +150 -0
- package/dist/commands/channel/guard.d.ts.map +1 -0
- package/dist/commands/channel/guard.js +475 -0
- package/dist/commands/channel/guard.js.map +1 -0
- package/dist/commands/channel/index.d.ts +3 -0
- package/dist/commands/channel/index.d.ts.map +1 -0
- package/dist/commands/channel/index.js +531 -0
- package/dist/commands/channel/index.js.map +1 -0
- package/dist/commands/channel/interrupt.d.ts +10 -0
- package/dist/commands/channel/interrupt.d.ts.map +1 -0
- package/dist/commands/channel/interrupt.js +22 -0
- package/dist/commands/channel/interrupt.js.map +1 -0
- package/dist/commands/channel/kill.d.ts +7 -0
- package/dist/commands/channel/kill.d.ts.map +1 -0
- package/dist/commands/channel/kill.js +121 -0
- package/dist/commands/channel/kill.js.map +1 -0
- package/dist/commands/channel/list.d.ts +17 -0
- package/dist/commands/channel/list.d.ts.map +1 -0
- package/dist/commands/channel/list.js +233 -0
- package/dist/commands/channel/list.js.map +1 -0
- package/dist/commands/channel/messages.d.ts +15 -0
- package/dist/commands/channel/messages.d.ts.map +1 -0
- package/dist/commands/channel/messages.js +245 -0
- package/dist/commands/channel/messages.js.map +1 -0
- package/dist/commands/channel/rm.d.ts +27 -0
- package/dist/commands/channel/rm.d.ts.map +1 -0
- package/dist/commands/channel/rm.js +216 -0
- package/dist/commands/channel/rm.js.map +1 -0
- package/dist/commands/channel/run.d.ts +30 -0
- package/dist/commands/channel/run.d.ts.map +1 -0
- package/dist/commands/channel/run.js +130 -0
- package/dist/commands/channel/run.js.map +1 -0
- package/dist/commands/channel/send.d.ts +11 -0
- package/dist/commands/channel/send.d.ts.map +1 -0
- package/dist/commands/channel/send.js +24 -0
- package/dist/commands/channel/send.js.map +1 -0
- package/dist/commands/channel/spawn.d.ts +40 -0
- package/dist/commands/channel/spawn.d.ts.map +1 -0
- package/dist/commands/channel/spawn.js +242 -0
- package/dist/commands/channel/spawn.js.map +1 -0
- package/dist/commands/channel/store/events.d.ts +39 -0
- package/dist/commands/channel/store/events.d.ts.map +1 -0
- package/dist/commands/channel/store/events.js +87 -0
- package/dist/commands/channel/store/events.js.map +1 -0
- package/dist/commands/channel/store/filter.d.ts +3 -0
- package/dist/commands/channel/store/filter.d.ts.map +1 -0
- package/dist/commands/channel/store/filter.js +2 -0
- package/dist/commands/channel/store/filter.js.map +1 -0
- package/dist/commands/channel/store/lock.d.ts +23 -0
- package/dist/commands/channel/store/lock.d.ts.map +1 -0
- package/dist/commands/channel/store/lock.js +99 -0
- package/dist/commands/channel/store/lock.js.map +1 -0
- package/dist/commands/channel/store/paths.d.ts +63 -0
- package/dist/commands/channel/store/paths.d.ts.map +1 -0
- package/dist/commands/channel/store/paths.js +247 -0
- package/dist/commands/channel/store/paths.js.map +1 -0
- package/dist/commands/channel/store/schema.d.ts +27 -0
- package/dist/commands/channel/store/schema.d.ts.map +1 -0
- package/dist/commands/channel/store/schema.js +34 -0
- package/dist/commands/channel/store/schema.js.map +1 -0
- package/dist/commands/channel/store/thread-state.d.ts +5 -0
- package/dist/commands/channel/store/thread-state.d.ts.map +1 -0
- package/dist/commands/channel/store/thread-state.js +16 -0
- package/dist/commands/channel/store/thread-state.js.map +1 -0
- package/dist/commands/channel/store/watch.d.ts +19 -0
- package/dist/commands/channel/store/watch.d.ts.map +1 -0
- package/dist/commands/channel/store/watch.js +146 -0
- package/dist/commands/channel/store/watch.js.map +1 -0
- package/dist/commands/channel/supervisor/idle.d.ts +46 -0
- package/dist/commands/channel/supervisor/idle.d.ts.map +1 -0
- package/dist/commands/channel/supervisor/idle.js +72 -0
- package/dist/commands/channel/supervisor/idle.js.map +1 -0
- package/dist/commands/channel/supervisor/inbox.d.ts +30 -0
- package/dist/commands/channel/supervisor/inbox.d.ts.map +1 -0
- package/dist/commands/channel/supervisor/inbox.js +160 -0
- package/dist/commands/channel/supervisor/inbox.js.map +1 -0
- package/dist/commands/channel/supervisor/shutdown.d.ts +68 -0
- package/dist/commands/channel/supervisor/shutdown.d.ts.map +1 -0
- package/dist/commands/channel/supervisor/shutdown.js +146 -0
- package/dist/commands/channel/supervisor/shutdown.js.map +1 -0
- package/dist/commands/channel/supervisor/stdout.d.ts +51 -0
- package/dist/commands/channel/supervisor/stdout.d.ts.map +1 -0
- package/dist/commands/channel/supervisor/stdout.js +121 -0
- package/dist/commands/channel/supervisor/stdout.js.map +1 -0
- package/dist/commands/channel/supervisor/turns.d.ts +31 -0
- package/dist/commands/channel/supervisor/turns.d.ts.map +1 -0
- package/dist/commands/channel/supervisor/turns.js +45 -0
- package/dist/commands/channel/supervisor/turns.js.map +1 -0
- package/dist/commands/channel/supervisor/warning.d.ts +48 -0
- package/dist/commands/channel/supervisor/warning.d.ts.map +1 -0
- package/dist/commands/channel/supervisor/warning.js +77 -0
- package/dist/commands/channel/supervisor/warning.js.map +1 -0
- package/dist/commands/channel/supervisor.d.ts +59 -0
- package/dist/commands/channel/supervisor.d.ts.map +1 -0
- package/dist/commands/channel/supervisor.js +345 -0
- package/dist/commands/channel/supervisor.js.map +1 -0
- package/dist/commands/channel/text-body.d.ts +13 -0
- package/dist/commands/channel/text-body.d.ts.map +1 -0
- package/dist/commands/channel/text-body.js +47 -0
- package/dist/commands/channel/text-body.js.map +1 -0
- package/dist/commands/channel/threads.d.ts +39 -0
- package/dist/commands/channel/threads.d.ts.map +1 -0
- package/dist/commands/channel/threads.js +106 -0
- package/dist/commands/channel/threads.js.map +1 -0
- package/dist/commands/channel/title.d.ts +12 -0
- package/dist/commands/channel/title.d.ts.map +1 -0
- package/dist/commands/channel/title.js +24 -0
- package/dist/commands/channel/title.js.map +1 -0
- package/dist/commands/channel/wait.d.ts +17 -0
- package/dist/commands/channel/wait.d.ts.map +1 -0
- package/dist/commands/channel/wait.js +75 -0
- package/dist/commands/channel/wait.js.map +1 -0
- package/dist/commands/detach.d.ts +7 -0
- package/dist/commands/detach.d.ts.map +1 -0
- package/dist/commands/detach.js +31 -0
- package/dist/commands/detach.js.map +1 -0
- package/dist/commands/init.d.ts +51 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +1660 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/migrate.d.ts +10 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +38 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/purge.d.ts +9 -0
- package/dist/commands/purge.d.ts.map +1 -0
- package/dist/commands/purge.js +29 -0
- package/dist/commands/purge.js.map +1 -0
- package/dist/commands/rollback.d.ts +7 -0
- package/dist/commands/rollback.d.ts.map +1 -0
- package/dist/commands/rollback.js +27 -0
- package/dist/commands/rollback.js.map +1 -0
- package/dist/commands/rollout.d.ts +34 -0
- package/dist/commands/rollout.d.ts.map +1 -0
- package/dist/commands/rollout.js +102 -0
- package/dist/commands/rollout.js.map +1 -0
- package/dist/commands/uninstall.d.ts +23 -0
- package/dist/commands/uninstall.d.ts.map +1 -0
- package/dist/commands/uninstall.js +68 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/update.d.ts +139 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +2459 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/upgrade.d.ts +28 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +84 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/commands/validate-rules.d.ts +6 -0
- package/dist/commands/validate-rules.d.ts.map +1 -0
- package/dist/commands/validate-rules.js +33 -0
- package/dist/commands/validate-rules.js.map +1 -0
- package/dist/commands/workflow.d.ts +35 -0
- package/dist/commands/workflow.d.ts.map +1 -0
- package/dist/commands/workflow.js +220 -0
- package/dist/commands/workflow.js.map +1 -0
- package/dist/configurators/cursor.d.ts +21 -0
- package/dist/configurators/cursor.d.ts.map +1 -0
- package/dist/configurators/cursor.js +51 -0
- package/dist/configurators/cursor.js.map +1 -0
- package/dist/configurators/index.d.ts +68 -0
- package/dist/configurators/index.d.ts.map +1 -0
- package/dist/configurators/index.js +170 -0
- package/dist/configurators/index.js.map +1 -0
- package/dist/configurators/shared.d.ts +200 -0
- package/dist/configurators/shared.d.ts.map +1 -0
- package/dist/configurators/shared.js +602 -0
- package/dist/configurators/shared.js.map +1 -0
- package/dist/configurators/workflow.d.ts +45 -0
- package/dist/configurators/workflow.d.ts.map +1 -0
- package/dist/configurators/workflow.js +256 -0
- package/dist/configurators/workflow.js.map +1 -0
- package/dist/constants/paths.d.ts +93 -0
- package/dist/constants/paths.d.ts.map +1 -0
- package/dist/constants/paths.js +106 -0
- package/dist/constants/paths.js.map +1 -0
- package/dist/constants/version.d.ts +9 -0
- package/dist/constants/version.d.ts.map +1 -0
- package/dist/constants/version.js +15 -0
- package/dist/constants/version.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/migrations/index.d.ts +62 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +187 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/manifests/0.1.0.json +9 -0
- package/dist/migrations/manifests/0.1.1.json +9 -0
- package/dist/migrations/manifests/0.1.2.json +9 -0
- package/dist/migrations/manifests/0.1.3.json +9 -0
- package/dist/migrations/manifests/0.1.4.json +9 -0
- package/dist/migrations/manifests/0.2.1.json +9 -0
- package/dist/migrations/manifests/0.2.10.json +374 -0
- package/dist/migrations/manifests/0.2.2.json +9 -0
- package/dist/migrations/manifests/0.2.3.json +9 -0
- package/dist/migrations/manifests/0.2.4.json +9 -0
- package/dist/migrations/manifests/0.2.5.json +9 -0
- package/dist/migrations/manifests/0.2.6.json +9 -0
- package/dist/migrations/manifests/0.2.7.json +9 -0
- package/dist/migrations/manifests/0.2.8.json +9 -0
- package/dist/migrations/manifests/0.2.9.json +9 -0
- package/dist/migrations/manifests/0.3.0.json +89 -0
- package/dist/migrations/manifests/0.3.1.json +32 -0
- package/dist/migrations/manifests/0.3.2.json +16 -0
- package/dist/migrations/manifests/0.3.3.json +9 -0
- package/dist/migrations/manifests/0.3.4.json +9 -0
- package/dist/migrations/manifests/0.3.5.json +9 -0
- package/dist/migrations/manifests/0.3.6.json +9 -0
- package/dist/migrations/manifests/0.4.0.json +9 -0
- package/dist/migrations/manifests/0.4.1.json +9 -0
- package/dist/migrations/manifests/0.4.2.json +9 -0
- package/dist/migrations/manifests/0.4.3.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.0.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.1.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.2.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.3.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.4.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.5.json +9 -0
- package/dist/pactile/adapters/codex/index.d.ts +75 -0
- package/dist/pactile/adapters/codex/index.d.ts.map +1 -0
- package/dist/pactile/adapters/codex/index.js +269 -0
- package/dist/pactile/adapters/codex/index.js.map +1 -0
- package/dist/pactile/adapters/cursor/index.d.ts +60 -0
- package/dist/pactile/adapters/cursor/index.d.ts.map +1 -0
- package/dist/pactile/adapters/cursor/index.js +186 -0
- package/dist/pactile/adapters/cursor/index.js.map +1 -0
- package/dist/pactile/adapters/index.d.ts +4 -0
- package/dist/pactile/adapters/index.d.ts.map +1 -0
- package/dist/pactile/adapters/index.js +4 -0
- package/dist/pactile/adapters/index.js.map +1 -0
- package/dist/pactile/adoption/bindings.d.ts +20 -0
- package/dist/pactile/adoption/bindings.d.ts.map +1 -0
- package/dist/pactile/adoption/bindings.js +99 -0
- package/dist/pactile/adoption/bindings.js.map +1 -0
- package/dist/pactile/adoption/discovery.d.ts +8 -0
- package/dist/pactile/adoption/discovery.d.ts.map +1 -0
- package/dist/pactile/adoption/discovery.js +159 -0
- package/dist/pactile/adoption/discovery.js.map +1 -0
- package/dist/pactile/adoption/inventory.d.ts +28 -0
- package/dist/pactile/adoption/inventory.d.ts.map +1 -0
- package/dist/pactile/adoption/inventory.js +261 -0
- package/dist/pactile/adoption/inventory.js.map +1 -0
- package/dist/pactile/adoption/safety.d.ts +19 -0
- package/dist/pactile/adoption/safety.d.ts.map +1 -0
- package/dist/pactile/adoption/safety.js +88 -0
- package/dist/pactile/adoption/safety.js.map +1 -0
- package/dist/pactile/adoption/workflow.d.ts +31 -0
- package/dist/pactile/adoption/workflow.d.ts.map +1 -0
- package/dist/pactile/adoption/workflow.js +259 -0
- package/dist/pactile/adoption/workflow.js.map +1 -0
- package/dist/pactile/compat/cli-options.d.ts +9 -0
- package/dist/pactile/compat/cli-options.d.ts.map +1 -0
- package/dist/pactile/compat/cli-options.js +9 -0
- package/dist/pactile/compat/cli-options.js.map +1 -0
- package/dist/pactile/compat/init-context.d.ts +16 -0
- package/dist/pactile/compat/init-context.d.ts.map +1 -0
- package/dist/pactile/compat/init-context.js +87 -0
- package/dist/pactile/compat/init-context.js.map +1 -0
- package/dist/pactile/compat/legacy-migrations.d.ts +8 -0
- package/dist/pactile/compat/legacy-migrations.d.ts.map +1 -0
- package/dist/pactile/compat/legacy-migrations.js +17 -0
- package/dist/pactile/compat/legacy-migrations.js.map +1 -0
- package/dist/pactile/compat/retired-alternate-client.d.ts +42 -0
- package/dist/pactile/compat/retired-alternate-client.d.ts.map +1 -0
- package/dist/pactile/compat/retired-alternate-client.js +153 -0
- package/dist/pactile/compat/retired-alternate-client.js.map +1 -0
- package/dist/pactile/compat/update-residue.d.ts +4 -0
- package/dist/pactile/compat/update-residue.d.ts.map +1 -0
- package/dist/pactile/compat/update-residue.js +55 -0
- package/dist/pactile/compat/update-residue.js.map +1 -0
- package/dist/pactile/exit/index.d.ts +3 -0
- package/dist/pactile/exit/index.d.ts.map +1 -0
- package/dist/pactile/exit/index.js +3 -0
- package/dist/pactile/exit/index.js.map +1 -0
- package/dist/pactile/exit/receipt.d.ts +23 -0
- package/dist/pactile/exit/receipt.d.ts.map +1 -0
- package/dist/pactile/exit/receipt.js +64 -0
- package/dist/pactile/exit/receipt.js.map +1 -0
- package/dist/pactile/exit/service.d.ts +107 -0
- package/dist/pactile/exit/service.d.ts.map +1 -0
- package/dist/pactile/exit/service.js +774 -0
- package/dist/pactile/exit/service.js.map +1 -0
- package/dist/pactile/index.d.ts +26 -0
- package/dist/pactile/index.d.ts.map +1 -0
- package/dist/pactile/index.js +22 -0
- package/dist/pactile/index.js.map +1 -0
- package/dist/pactile/lifecycle/command-runner.d.ts +26 -0
- package/dist/pactile/lifecycle/command-runner.d.ts.map +1 -0
- package/dist/pactile/lifecycle/command-runner.js +129 -0
- package/dist/pactile/lifecycle/command-runner.js.map +1 -0
- package/dist/pactile/lifecycle/default-adapters.d.ts +5 -0
- package/dist/pactile/lifecycle/default-adapters.d.ts.map +1 -0
- package/dist/pactile/lifecycle/default-adapters.js +136 -0
- package/dist/pactile/lifecycle/default-adapters.js.map +1 -0
- package/dist/pactile/lifecycle/index.d.ts +6 -0
- package/dist/pactile/lifecycle/index.d.ts.map +1 -0
- package/dist/pactile/lifecycle/index.js +6 -0
- package/dist/pactile/lifecycle/index.js.map +1 -0
- package/dist/pactile/lifecycle/legacy-import.d.ts +16 -0
- package/dist/pactile/lifecycle/legacy-import.d.ts.map +1 -0
- package/dist/pactile/lifecycle/legacy-import.js +228 -0
- package/dist/pactile/lifecycle/legacy-import.js.map +1 -0
- package/dist/pactile/lifecycle/orchestrator.d.ts +109 -0
- package/dist/pactile/lifecycle/orchestrator.d.ts.map +1 -0
- package/dist/pactile/lifecycle/orchestrator.js +1030 -0
- package/dist/pactile/lifecycle/orchestrator.js.map +1 -0
- package/dist/pactile/lifecycle/project-files.d.ts +28 -0
- package/dist/pactile/lifecycle/project-files.d.ts.map +1 -0
- package/dist/pactile/lifecycle/project-files.js +297 -0
- package/dist/pactile/lifecycle/project-files.js.map +1 -0
- package/dist/pactile/middleware/index.d.ts +3 -0
- package/dist/pactile/middleware/index.d.ts.map +1 -0
- package/dist/pactile/middleware/index.js +2 -0
- package/dist/pactile/middleware/index.js.map +1 -0
- package/dist/pactile/middleware/manifest-loader.d.ts +22 -0
- package/dist/pactile/middleware/manifest-loader.d.ts.map +1 -0
- package/dist/pactile/middleware/manifest-loader.js +228 -0
- package/dist/pactile/middleware/manifest-loader.js.map +1 -0
- package/dist/pactile/migration/index.d.ts +2 -0
- package/dist/pactile/migration/index.d.ts.map +1 -0
- package/dist/pactile/migration/index.js +2 -0
- package/dist/pactile/migration/index.js.map +1 -0
- package/dist/pactile/migration/transaction.d.ts +54 -0
- package/dist/pactile/migration/transaction.d.ts.map +1 -0
- package/dist/pactile/migration/transaction.js +445 -0
- package/dist/pactile/migration/transaction.js.map +1 -0
- package/dist/pactile/projection/managed-block.d.ts +32 -0
- package/dist/pactile/projection/managed-block.d.ts.map +1 -0
- package/dist/pactile/projection/managed-block.js +78 -0
- package/dist/pactile/projection/managed-block.js.map +1 -0
- package/dist/pactile/projection/planner.d.ts +65 -0
- package/dist/pactile/projection/planner.d.ts.map +1 -0
- package/dist/pactile/projection/planner.js +349 -0
- package/dist/pactile/projection/planner.js.map +1 -0
- package/dist/pactile/projection/shared/index.d.ts +38 -0
- package/dist/pactile/projection/shared/index.d.ts.map +1 -0
- package/dist/pactile/projection/shared/index.js +186 -0
- package/dist/pactile/projection/shared/index.js.map +1 -0
- package/dist/pactile/projection/store.d.ts +72 -0
- package/dist/pactile/projection/store.d.ts.map +1 -0
- package/dist/pactile/projection/store.js +669 -0
- package/dist/pactile/projection/store.js.map +1 -0
- package/dist/pactile/projection/structured-merge.d.ts +11 -0
- package/dist/pactile/projection/structured-merge.d.ts.map +1 -0
- package/dist/pactile/projection/structured-merge.js +347 -0
- package/dist/pactile/projection/structured-merge.js.map +1 -0
- package/dist/pactile/providers/index.d.ts +3 -0
- package/dist/pactile/providers/index.d.ts.map +1 -0
- package/dist/pactile/providers/index.js +3 -0
- package/dist/pactile/providers/index.js.map +1 -0
- package/dist/pactile/providers/probes.d.ts +55 -0
- package/dist/pactile/providers/probes.d.ts.map +1 -0
- package/dist/pactile/providers/probes.js +164 -0
- package/dist/pactile/providers/probes.js.map +1 -0
- package/dist/pactile/registry.d.ts +64 -0
- package/dist/pactile/registry.d.ts.map +1 -0
- package/dist/pactile/registry.js +196 -0
- package/dist/pactile/registry.js.map +1 -0
- package/dist/pactile/retrieval/boundary.d.ts +18 -0
- package/dist/pactile/retrieval/boundary.d.ts.map +1 -0
- package/dist/pactile/retrieval/boundary.js +113 -0
- package/dist/pactile/retrieval/boundary.js.map +1 -0
- package/dist/pactile/retrieval/evidence.d.ts +9 -0
- package/dist/pactile/retrieval/evidence.d.ts.map +1 -0
- package/dist/pactile/retrieval/evidence.js +327 -0
- package/dist/pactile/retrieval/evidence.js.map +1 -0
- package/dist/pactile/retrieval/index.d.ts +4 -0
- package/dist/pactile/retrieval/index.d.ts.map +1 -0
- package/dist/pactile/retrieval/index.js +4 -0
- package/dist/pactile/retrieval/index.js.map +1 -0
- package/dist/pactile/retrieval/planner.d.ts +23 -0
- package/dist/pactile/retrieval/planner.d.ts.map +1 -0
- package/dist/pactile/retrieval/planner.js +702 -0
- package/dist/pactile/retrieval/planner.js.map +1 -0
- package/dist/pactile/retrieval/types.d.ts +108 -0
- package/dist/pactile/retrieval/types.d.ts.map +1 -0
- package/dist/pactile/retrieval/types.js +36 -0
- package/dist/pactile/retrieval/types.js.map +1 -0
- package/dist/pactile/runtime/case-fold.d.ts +2 -0
- package/dist/pactile/runtime/case-fold.d.ts.map +1 -0
- package/dist/pactile/runtime/case-fold.js +31 -0
- package/dist/pactile/runtime/case-fold.js.map +1 -0
- package/dist/pactile/runtime/index.d.ts +8 -0
- package/dist/pactile/runtime/index.d.ts.map +1 -0
- package/dist/pactile/runtime/index.js +5 -0
- package/dist/pactile/runtime/index.js.map +1 -0
- package/dist/pactile/runtime/json-api.d.ts +15 -0
- package/dist/pactile/runtime/json-api.d.ts.map +1 -0
- package/dist/pactile/runtime/json-api.js +68 -0
- package/dist/pactile/runtime/json-api.js.map +1 -0
- package/dist/pactile/runtime/paths.d.ts +59 -0
- package/dist/pactile/runtime/paths.d.ts.map +1 -0
- package/dist/pactile/runtime/paths.js +201 -0
- package/dist/pactile/runtime/paths.js.map +1 -0
- package/dist/pactile/runtime/stores.d.ts +54 -0
- package/dist/pactile/runtime/stores.d.ts.map +1 -0
- package/dist/pactile/runtime/stores.js +375 -0
- package/dist/pactile/runtime/stores.js.map +1 -0
- package/dist/pactile/runtime/unicode-nfc-data.d.ts +12 -0
- package/dist/pactile/runtime/unicode-nfc-data.d.ts.map +1 -0
- package/dist/pactile/runtime/unicode-nfc-data.js +8 -0
- package/dist/pactile/runtime/unicode-nfc-data.js.map +1 -0
- package/dist/pactile/runtime/unicode-nfc.d.ts +3 -0
- package/dist/pactile/runtime/unicode-nfc.d.ts.map +1 -0
- package/dist/pactile/runtime/unicode-nfc.js +77 -0
- package/dist/pactile/runtime/unicode-nfc.js.map +1 -0
- package/dist/pactile/tiles/catalog.d.ts +35 -0
- package/dist/pactile/tiles/catalog.d.ts.map +1 -0
- package/dist/pactile/tiles/catalog.js +235 -0
- package/dist/pactile/tiles/catalog.js.map +1 -0
- package/dist/pactile/tiles/compiler.d.ts +54 -0
- package/dist/pactile/tiles/compiler.d.ts.map +1 -0
- package/dist/pactile/tiles/compiler.js +270 -0
- package/dist/pactile/tiles/compiler.js.map +1 -0
- package/dist/pactile/tiles/content/baseline/index.d.ts +5 -0
- package/dist/pactile/tiles/content/baseline/index.d.ts.map +1 -0
- package/dist/pactile/tiles/content/baseline/index.js +115 -0
- package/dist/pactile/tiles/content/baseline/index.js.map +1 -0
- package/dist/pactile/tiles/content/index.d.ts +4 -0
- package/dist/pactile/tiles/content/index.d.ts.map +1 -0
- package/dist/pactile/tiles/content/index.js +4 -0
- package/dist/pactile/tiles/content/index.js.map +1 -0
- package/dist/pactile/tiles/content/ondemand/index.d.ts +5 -0
- package/dist/pactile/tiles/content/ondemand/index.d.ts.map +1 -0
- package/dist/pactile/tiles/content/ondemand/index.js +184 -0
- package/dist/pactile/tiles/content/ondemand/index.js.map +1 -0
- package/dist/pactile/tiles/content/source.d.ts +29 -0
- package/dist/pactile/tiles/content/source.d.ts.map +1 -0
- package/dist/pactile/tiles/content/source.js +86 -0
- package/dist/pactile/tiles/content/source.js.map +1 -0
- package/dist/pactile/tiles/loader.d.ts +31 -0
- package/dist/pactile/tiles/loader.d.ts.map +1 -0
- package/dist/pactile/tiles/loader.js +139 -0
- package/dist/pactile/tiles/loader.js.map +1 -0
- package/dist/pactile/tiles/safe-yaml.d.ts +11 -0
- package/dist/pactile/tiles/safe-yaml.d.ts.map +1 -0
- package/dist/pactile/tiles/safe-yaml.js +212 -0
- package/dist/pactile/tiles/safe-yaml.js.map +1 -0
- package/dist/templates/common/bundled-skills/pactile-check/SKILL.md +161 -0
- package/dist/templates/common/bundled-skills/pactile-check/references/fowler-12-smells.md +28 -0
- package/dist/templates/common/bundled-skills/pactile-handoff/SKILL.md +117 -0
- package/dist/templates/common/bundled-skills/pactile-meta/SKILL.md +75 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/customize-local/add-project-local-conventions.md +83 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/customize-local/change-agents.md +47 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/customize-local/change-context-loading.md +84 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/customize-local/change-hooks.md +57 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/customize-local/change-skills-or-commands.md +77 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/customize-local/change-spec-structure.md +83 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/customize-local/change-task-lifecycle.md +88 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/customize-local/change-workflow.md +65 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/customize-local/overview.md +55 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/local-architecture/context-injection.md +68 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/local-architecture/generated-files.md +83 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/local-architecture/overview.md +51 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/local-architecture/spec-system.md +102 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/local-architecture/task-system.md +133 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/local-architecture/workflow.md +75 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/local-architecture/workspace-memory.md +71 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/platform-files/agents.md +69 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/platform-files/hooks-and-settings.md +59 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/platform-files/overview.md +45 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/platform-files/platform-map.md +45 -0
- package/dist/templates/common/bundled-skills/pactile-meta/references/platform-files/skills-and-commands.md +108 -0
- package/dist/templates/common/bundled-skills/pactile-micro-grill/SKILL.md +68 -0
- package/dist/templates/common/bundled-skills/pactile-skill-creator/SKILL.md +47 -0
- package/dist/templates/common/bundled-skills/pactile-skill-creator/references/authoring-rules.md +171 -0
- package/dist/templates/common/bundled-skills/pactile-skill-creator/references/general-authoring.md +189 -0
- package/dist/templates/common/bundled-skills/pactile-skill-creator/references/pactile-skill-locations.md +52 -0
- package/dist/templates/common/bundled-skills/pactile-skill-creator/references/review-checklist.md +52 -0
- package/dist/templates/common/bundled-skills/pactile-spec-bootstrap/SKILL.md +41 -0
- package/dist/templates/common/bundled-skills/pactile-spec-bootstrap/references/mcp-setup.md +90 -0
- package/dist/templates/common/bundled-skills/pactile-spec-bootstrap/references/repository-analysis.md +59 -0
- package/dist/templates/common/bundled-skills/pactile-spec-bootstrap/references/spec-task-planning.md +61 -0
- package/dist/templates/common/bundled-skills/pactile-spec-bootstrap/references/spec-writing.md +70 -0
- package/dist/templates/common/bundled-skills/smart-search-cli/SKILL.md +393 -0
- package/dist/templates/common/bundled-skills/smart-search-cli/agents/openai.yaml +3 -0
- package/dist/templates/common/bundled-skills/smart-search-cli/examples/batch-search.md +98 -0
- package/dist/templates/common/bundled-skills/smart-search-cli/examples/evidence-gathering.md +89 -0
- package/dist/templates/common/bundled-skills/smart-search-cli/references/cli-contract.md +323 -0
- package/dist/templates/common/commands/continue.md +62 -0
- package/dist/templates/common/commands/finish-work.md +82 -0
- package/dist/templates/common/commands/start.md +66 -0
- package/dist/templates/common/index.d.ts +68 -0
- package/dist/templates/common/index.d.ts.map +1 -0
- package/dist/templates/common/index.js +123 -0
- package/dist/templates/common/index.js.map +1 -0
- package/dist/templates/common/optional-skills/chrome-cdp/SKILL.md +179 -0
- package/dist/templates/common/optional-skills/chrome-cdp/examples/fetch-hook-api-capture.md +149 -0
- package/dist/templates/common/optional-skills/chrome-cdp/scripts/cdp.mjs +904 -0
- package/dist/templates/common/skills/before-dev.md +35 -0
- package/dist/templates/common/skills/brainstorm.md +204 -0
- package/dist/templates/common/skills/break-loop.md +125 -0
- package/dist/templates/common/skills/update-spec.md +364 -0
- package/dist/templates/cursor/agents/pactile-check.md +58 -0
- package/dist/templates/cursor/agents/pactile-implement.md +56 -0
- package/dist/templates/cursor/agents/pactile-research.md +51 -0
- package/dist/templates/cursor/commands/handoff.md +101 -0
- package/dist/templates/cursor/fixtures/expected-rules.d.ts +14 -0
- package/dist/templates/cursor/fixtures/expected-rules.d.ts.map +1 -0
- package/dist/templates/cursor/fixtures/expected-rules.js +20 -0
- package/dist/templates/cursor/fixtures/expected-rules.js.map +1 -0
- package/dist/templates/cursor/hooks.json +52 -0
- package/dist/templates/cursor/index.d.ts +19 -0
- package/dist/templates/cursor/index.d.ts.map +1 -0
- package/dist/templates/cursor/index.js +19 -0
- package/dist/templates/cursor/index.js.map +1 -0
- package/dist/templates/cursor/rules/pactile-bootstrap.mdc +18 -0
- package/dist/templates/cursor/worktrees.json +11 -0
- package/dist/templates/extract.d.ts +38 -0
- package/dist/templates/extract.d.ts.map +1 -0
- package/dist/templates/extract.js +120 -0
- package/dist/templates/extract.js.map +1 -0
- package/dist/templates/markdown/agents.md +14 -0
- package/dist/templates/markdown/framework/artifact-locale-guide.md.txt +93 -0
- package/dist/templates/markdown/framework/cursor-context-injection-guide.md.txt +85 -0
- package/dist/templates/markdown/framework/cursor-native-modes-guide.md.txt +239 -0
- package/dist/templates/markdown/framework/cursor-semantic-compliance.md.txt +41 -0
- package/dist/templates/markdown/framework/cursor-subagent-policy.md.txt +90 -0
- package/dist/templates/markdown/framework/dogfood-only-surfaces.md.txt +28 -0
- package/dist/templates/markdown/framework/execution-strategy.md.txt +45 -0
- package/dist/templates/markdown/framework/index.md.txt +31 -0
- package/dist/templates/markdown/framework/injection-budget-guide.md.txt +111 -0
- package/dist/templates/markdown/framework/internal-skills-cursor-reachability.md.txt +45 -0
- package/dist/templates/markdown/framework/middleware-protocol.md.txt +238 -0
- package/dist/templates/markdown/framework/parallel-first-execution.md.txt +116 -0
- package/dist/templates/markdown/framework/prd-grill-frontier.md.txt +105 -0
- package/dist/templates/markdown/framework/release-boundary.md.txt +30 -0
- package/dist/templates/markdown/framework/retrieval-daily-guide.md.txt +199 -0
- package/dist/templates/markdown/framework/upgrade.md.txt +15 -0
- package/dist/templates/markdown/framework/verification-strength-guide.md.txt +185 -0
- package/dist/templates/markdown/gitignore.txt +15 -0
- package/dist/templates/markdown/index.d.ts +59 -0
- package/dist/templates/markdown/index.d.ts.map +1 -0
- package/dist/templates/markdown/index.js +144 -0
- package/dist/templates/markdown/index.js.map +1 -0
- package/dist/templates/markdown/prompts/run-semantic-slice-12.md.txt +25 -0
- package/dist/templates/markdown/spec/backend/database-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/backend/directory-structure.md.txt +54 -0
- package/dist/templates/markdown/spec/backend/error-handling.md.txt +51 -0
- package/dist/templates/markdown/spec/backend/index.md.txt +38 -0
- package/dist/templates/markdown/spec/backend/logging-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/backend/quality-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/frontend/component-guidelines.md.txt +59 -0
- package/dist/templates/markdown/spec/frontend/directory-structure.md.txt +54 -0
- package/dist/templates/markdown/spec/frontend/hook-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/frontend/index.md.txt +39 -0
- package/dist/templates/markdown/spec/frontend/quality-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/frontend/state-management.md.txt +51 -0
- package/dist/templates/markdown/spec/frontend/type-safety.md.txt +51 -0
- package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md.txt +174 -0
- package/dist/templates/markdown/spec/guides/cross-layer-thinking-guide.md.txt +162 -0
- package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +634 -0
- package/dist/templates/markdown/spec/guides/debug-loop-guide.md.txt +227 -0
- package/dist/templates/markdown/spec/guides/durable-learning-decision-guide.md.txt +76 -0
- package/dist/templates/markdown/spec/guides/e2e-walkthrough-guide.md.txt +93 -0
- package/dist/templates/markdown/spec/guides/index.md.txt +131 -0
- package/dist/templates/markdown/spec/guides/prototype-guide.md.txt +139 -0
- package/dist/templates/markdown/spec/guides/test-discipline-guide.md.txt +179 -0
- package/dist/templates/markdown/workspace-index.md +125 -0
- package/dist/templates/markdown/worktree.yaml.txt +58 -0
- package/dist/templates/pactile/CONTEXT.md +113 -0
- package/dist/templates/pactile/config/execution-strategy-rules.json +31 -0
- package/dist/templates/pactile/config.yaml +130 -0
- package/dist/templates/pactile/docs/adr/README.md +21 -0
- package/dist/templates/pactile/gitignore.txt +35 -0
- package/dist/templates/pactile/index.d.ts +134 -0
- package/dist/templates/pactile/index.d.ts.map +1 -0
- package/dist/templates/pactile/index.js +316 -0
- package/dist/templates/pactile/index.js.map +1 -0
- package/dist/templates/pactile/modules/approval-personal/contract.md +43 -0
- package/dist/templates/pactile/modules/candidate-pool/contract.md +37 -0
- package/dist/templates/pactile/modules/catalog.d.ts +32 -0
- package/dist/templates/pactile/modules/catalog.d.ts.map +1 -0
- package/dist/templates/pactile/modules/catalog.js +46 -0
- package/dist/templates/pactile/modules/catalog.js.map +1 -0
- package/dist/templates/pactile/modules/close-basic/contract.md +38 -0
- package/dist/templates/pactile/modules/context-progressive/contract.md +44 -0
- package/dist/templates/pactile/modules/debug-recovery/contract.md +44 -0
- package/dist/templates/pactile/modules/define-basic/contract.md +39 -0
- package/dist/templates/pactile/modules/define-extended/contract.md +45 -0
- package/dist/templates/pactile/modules/execute-agent/contract.md +38 -0
- package/dist/templates/pactile/modules/independent-check/contract.md +35 -0
- package/dist/templates/pactile/modules/index.json +133 -0
- package/dist/templates/pactile/modules/intake-basic/contract.md +34 -0
- package/dist/templates/pactile/modules/observability-local/contract.md +31 -0
- package/dist/templates/pactile/modules/parent-child/contract.md +45 -0
- package/dist/templates/pactile/modules/personal-memory/contract.md +56 -0
- package/dist/templates/pactile/modules/retention-storage/contract.md +43 -0
- package/dist/templates/pactile/modules/retrieval-extended/contract.md +77 -0
- package/dist/templates/pactile/modules/session-transfer/contract.md +41 -0
- package/dist/templates/pactile/modules/spec-learning/contract.md +50 -0
- package/dist/templates/pactile/modules/vcs-integration/contract.md +46 -0
- package/dist/templates/pactile/modules/verify-basic/contract.md +38 -0
- package/dist/templates/pactile/modules/worker-orchestration/contract.md +47 -0
- package/dist/templates/pactile/pool/README.md +149 -0
- package/dist/templates/pactile/pool/items/.gitkeep +0 -0
- package/dist/templates/pactile/pool/plan.md +50 -0
- package/dist/templates/pactile/scripts/__init__.py +5 -0
- package/dist/templates/pactile/scripts/add_session.py +547 -0
- package/dist/templates/pactile/scripts/build_context_pack.py +17 -0
- package/dist/templates/pactile/scripts/build_retrieval_pack.py +376 -0
- package/dist/templates/pactile/scripts/codegraph_session_smoke.py +76 -0
- package/dist/templates/pactile/scripts/common/__init__.py +103 -0
- package/dist/templates/pactile/scripts/common/active_task.py +576 -0
- package/dist/templates/pactile/scripts/common/adapter_middleware.py +1373 -0
- package/dist/templates/pactile/scripts/common/artifact_locale.py +303 -0
- package/dist/templates/pactile/scripts/common/artifact_search.py +587 -0
- package/dist/templates/pactile/scripts/common/cli_adapter.py +135 -0
- package/dist/templates/pactile/scripts/common/cli_environment.py +155 -0
- package/dist/templates/pactile/scripts/common/codebase_retrieval_router.py +1339 -0
- package/dist/templates/pactile/scripts/common/config.py +497 -0
- package/dist/templates/pactile/scripts/common/context_pack.py +371 -0
- package/dist/templates/pactile/scripts/common/cursor_retrieval_env.py +31 -0
- package/dist/templates/pactile/scripts/common/developer.py +190 -0
- package/dist/templates/pactile/scripts/common/execution_strategy.py +268 -0
- package/dist/templates/pactile/scripts/common/full_quality.py +237 -0
- package/dist/templates/pactile/scripts/common/git.py +37 -0
- package/dist/templates/pactile/scripts/common/git_context.py +198 -0
- package/dist/templates/pactile/scripts/common/injection_budget.py +317 -0
- package/dist/templates/pactile/scripts/common/io.py +37 -0
- package/dist/templates/pactile/scripts/common/kernel_command.py +369 -0
- package/dist/templates/pactile/scripts/common/lite_context.py +280 -0
- package/dist/templates/pactile/scripts/common/log.py +45 -0
- package/dist/templates/pactile/scripts/common/ondemand_topology.py +419 -0
- package/dist/templates/pactile/scripts/common/packages_context.py +239 -0
- package/dist/templates/pactile/scripts/common/pactile_config.py +131 -0
- package/dist/templates/pactile/scripts/common/parallel_declaration.py +369 -0
- package/dist/templates/pactile/scripts/common/parent_orchestration.py +1198 -0
- package/dist/templates/pactile/scripts/common/paths.py +756 -0
- package/dist/templates/pactile/scripts/common/pool_refs.py +119 -0
- package/dist/templates/pactile/scripts/common/pool_slice.py +269 -0
- package/dist/templates/pactile/scripts/common/pool_store.py +766 -0
- package/dist/templates/pactile/scripts/common/project_file_stats.py +91 -0
- package/dist/templates/pactile/scripts/common/retrieval_adapter_metadata.py +943 -0
- package/dist/templates/pactile/scripts/common/retrieval_agent_instructions.py +123 -0
- package/dist/templates/pactile/scripts/common/retrieval_evidence.py +915 -0
- package/dist/templates/pactile/scripts/common/retrieval_pack.py +422 -0
- package/dist/templates/pactile/scripts/common/retrieval_pack_context.py +122 -0
- package/dist/templates/pactile/scripts/common/retrieval_plan_gate.py +61 -0
- package/dist/templates/pactile/scripts/common/retrieval_result_ranking.py +104 -0
- package/dist/templates/pactile/scripts/common/retrieval_tool_classification.py +166 -0
- package/dist/templates/pactile/scripts/common/safe_commit.py +285 -0
- package/dist/templates/pactile/scripts/common/semantic_plan_gate.py +53 -0
- package/dist/templates/pactile/scripts/common/session_context.py +1213 -0
- package/dist/templates/pactile/scripts/common/session_memory.py +386 -0
- package/dist/templates/pactile/scripts/common/session_pack.py +886 -0
- package/dist/templates/pactile/scripts/common/smart_search_evidence.py +514 -0
- package/dist/templates/pactile/scripts/common/smart_search_resolve.py +150 -0
- package/dist/templates/pactile/scripts/common/subagent_dispatch.py +592 -0
- package/dist/templates/pactile/scripts/common/task_context.py +241 -0
- package/dist/templates/pactile/scripts/common/task_dashboard.py +286 -0
- package/dist/templates/pactile/scripts/common/task_dependencies.py +648 -0
- package/dist/templates/pactile/scripts/common/task_gates.py +2478 -0
- package/dist/templates/pactile/scripts/common/task_map.py +703 -0
- package/dist/templates/pactile/scripts/common/task_queue.py +188 -0
- package/dist/templates/pactile/scripts/common/task_store.py +2252 -0
- package/dist/templates/pactile/scripts/common/task_utils.py +274 -0
- package/dist/templates/pactile/scripts/common/tasks.py +231 -0
- package/dist/templates/pactile/scripts/common/test_adapter_middleware.py +199 -0
- package/dist/templates/pactile/scripts/common/test_depends_mode_block.py +509 -0
- package/dist/templates/pactile/scripts/common/test_full_quality.py +197 -0
- package/dist/templates/pactile/scripts/common/test_kernel_command.py +336 -0
- package/dist/templates/pactile/scripts/common/test_lite_path.py +190 -0
- package/dist/templates/pactile/scripts/common/test_observable_defaults.py +141 -0
- package/dist/templates/pactile/scripts/common/test_ondemand_topology.py +237 -0
- package/dist/templates/pactile/scripts/common/test_parallel_declaration.py +264 -0
- package/dist/templates/pactile/scripts/common/test_pool_slice.py +198 -0
- package/dist/templates/pactile/scripts/common/test_pool_store.py +452 -0
- package/dist/templates/pactile/scripts/common/test_retrieval_arbitration.py +331 -0
- package/dist/templates/pactile/scripts/common/test_task_dashboard.py +155 -0
- package/dist/templates/pactile/scripts/common/test_task_dependencies.py +329 -0
- package/dist/templates/pactile/scripts/common/test_task_store_kernel_patch.py +163 -0
- package/dist/templates/pactile/scripts/common/types.py +110 -0
- package/dist/templates/pactile/scripts/common/workflow_phase.py +194 -0
- package/dist/templates/pactile/scripts/compile_session_pack.py +15 -0
- package/dist/templates/pactile/scripts/cursor_retrieval_probe.py +64 -0
- package/dist/templates/pactile/scripts/cursor_retrieval_probe_prompt.md +33 -0
- package/dist/templates/pactile/scripts/generate_dispatch_prompt.py +182 -0
- package/dist/templates/pactile/scripts/get_context.py +19 -0
- package/dist/templates/pactile/scripts/get_developer.py +26 -0
- package/dist/templates/pactile/scripts/hooks/linear_sync.py +243 -0
- package/dist/templates/pactile/scripts/init_developer.py +51 -0
- package/dist/templates/pactile/scripts/injection_budget_probe.py +69 -0
- package/dist/templates/pactile/scripts/pool.py +237 -0
- package/dist/templates/pactile/scripts/rank_retrieval_candidates.py +98 -0
- package/dist/templates/pactile/scripts/retrieval_probe_matrix_template.json +43 -0
- package/dist/templates/pactile/scripts/route_codebase_retrieval.py +72 -0
- package/dist/templates/pactile/scripts/run_smart_search.py +12 -0
- package/dist/templates/pactile/scripts/score_evidence.py +131 -0
- package/dist/templates/pactile/scripts/search_artifacts.py +13 -0
- package/dist/templates/pactile/scripts/search_memory.py +12 -0
- package/dist/templates/pactile/scripts/spec_health_outcomes.py +160 -0
- package/dist/templates/pactile/scripts/task.py +1118 -0
- package/dist/templates/pactile/scripts/verify_evidence_probe.py +138 -0
- package/dist/templates/pactile/tasks/.gitkeep +0 -0
- package/dist/templates/pactile/tasks/locale/en/default-prd.md +27 -0
- package/dist/templates/pactile/tasks/locale/zh/default-prd.md +27 -0
- package/dist/templates/pactile/tasks/templates/release-execution/design.md +61 -0
- package/dist/templates/pactile/tasks/templates/release-execution/handoff-template.md +29 -0
- package/dist/templates/pactile/tasks/templates/release-execution/implement.md +29 -0
- package/dist/templates/pactile/tasks/templates/release-execution/prd.md +31 -0
- package/dist/templates/pactile/tasks/templates/release-readiness/design.md +50 -0
- package/dist/templates/pactile/tasks/templates/release-readiness/handoff-template.md +39 -0
- package/dist/templates/pactile/tasks/templates/release-readiness/implement.md +29 -0
- package/dist/templates/pactile/tasks/templates/release-readiness/prd.md +31 -0
- package/dist/templates/pactile/workflow.md +64 -0
- package/dist/templates/shared-hooks/event-bridge.py +121 -0
- package/dist/templates/shared-hooks/index.d.ts +50 -0
- package/dist/templates/shared-hooks/index.d.ts.map +1 -0
- package/dist/templates/shared-hooks/index.js +96 -0
- package/dist/templates/shared-hooks/index.js.map +1 -0
- package/dist/templates/shared-hooks/inject-retrieval-plan.py +217 -0
- package/dist/templates/shared-hooks/inject-shell-session-context.py +183 -0
- package/dist/templates/shared-hooks/inject-subagent-context.py +267 -0
- package/dist/templates/shared-hooks/inject-workflow-state.py +106 -0
- package/dist/templates/shared-hooks/rename-session-for-task.py +231 -0
- package/dist/templates/shared-hooks/research-end-retrieval-pack.py +345 -0
- package/dist/templates/shared-hooks/session-start.py +355 -0
- package/dist/templates/shared-hooks/spec-write-audit.py +173 -0
- package/dist/templates/template-utils.d.ts +28 -0
- package/dist/templates/template-utils.d.ts.map +1 -0
- package/dist/templates/template-utils.js +83 -0
- package/dist/templates/template-utils.js.map +1 -0
- package/dist/types/ai-tools.d.ts +102 -0
- package/dist/types/ai-tools.d.ts.map +1 -0
- package/dist/types/ai-tools.js +60 -0
- package/dist/types/ai-tools.js.map +1 -0
- package/dist/types/migration.d.ts +125 -0
- package/dist/types/migration.d.ts.map +1 -0
- package/dist/types/migration.js +8 -0
- package/dist/types/migration.js.map +1 -0
- package/dist/utils/agents-md.d.ts +27 -0
- package/dist/utils/agents-md.d.ts.map +1 -0
- package/dist/utils/agents-md.js +70 -0
- package/dist/utils/agents-md.js.map +1 -0
- package/dist/utils/codebase-retrieval-router.d.ts +31 -0
- package/dist/utils/codebase-retrieval-router.d.ts.map +1 -0
- package/dist/utils/codebase-retrieval-router.js +88 -0
- package/dist/utils/codebase-retrieval-router.js.map +1 -0
- package/dist/utils/compare-versions.d.ts +12 -0
- package/dist/utils/compare-versions.d.ts.map +1 -0
- package/dist/utils/compare-versions.js +86 -0
- package/dist/utils/compare-versions.js.map +1 -0
- package/dist/utils/cursor-retrieval-env.d.ts +17 -0
- package/dist/utils/cursor-retrieval-env.d.ts.map +1 -0
- package/dist/utils/cursor-retrieval-env.js +19 -0
- package/dist/utils/cursor-retrieval-env.js.map +1 -0
- package/dist/utils/cwd-guard.d.ts +38 -0
- package/dist/utils/cwd-guard.d.ts.map +1 -0
- package/dist/utils/cwd-guard.js +63 -0
- package/dist/utils/cwd-guard.js.map +1 -0
- package/dist/utils/file-writer.d.ts +36 -0
- package/dist/utils/file-writer.d.ts.map +1 -0
- package/dist/utils/file-writer.js +203 -0
- package/dist/utils/file-writer.js.map +1 -0
- package/dist/utils/manifest-prune.d.ts +59 -0
- package/dist/utils/manifest-prune.d.ts.map +1 -0
- package/dist/utils/manifest-prune.js +176 -0
- package/dist/utils/manifest-prune.js.map +1 -0
- package/dist/utils/mirror-check.d.ts +22 -0
- package/dist/utils/mirror-check.d.ts.map +1 -0
- package/dist/utils/mirror-check.js +90 -0
- package/dist/utils/mirror-check.js.map +1 -0
- package/dist/utils/normalize-text.d.ts +7 -0
- package/dist/utils/normalize-text.d.ts.map +1 -0
- package/dist/utils/normalize-text.js +16 -0
- package/dist/utils/normalize-text.js.map +1 -0
- package/dist/utils/p36-upgrade.d.ts +62 -0
- package/dist/utils/p36-upgrade.d.ts.map +1 -0
- package/dist/utils/p36-upgrade.js +165 -0
- package/dist/utils/p36-upgrade.js.map +1 -0
- package/dist/utils/posix.d.ts +13 -0
- package/dist/utils/posix.d.ts.map +1 -0
- package/dist/utils/posix.js +15 -0
- package/dist/utils/posix.js.map +1 -0
- package/dist/utils/post-update-smoke.d.ts +7 -0
- package/dist/utils/post-update-smoke.d.ts.map +1 -0
- package/dist/utils/post-update-smoke.js +40 -0
- package/dist/utils/post-update-smoke.js.map +1 -0
- package/dist/utils/project-capabilities.d.ts +82 -0
- package/dist/utils/project-capabilities.d.ts.map +1 -0
- package/dist/utils/project-capabilities.js +691 -0
- package/dist/utils/project-capabilities.js.map +1 -0
- package/dist/utils/project-detector.d.ts +46 -0
- package/dist/utils/project-detector.d.ts.map +1 -0
- package/dist/utils/project-detector.js +666 -0
- package/dist/utils/project-detector.js.map +1 -0
- package/dist/utils/proxy.d.ts +25 -0
- package/dist/utils/proxy.d.ts.map +1 -0
- package/dist/utils/proxy.js +60 -0
- package/dist/utils/proxy.js.map +1 -0
- package/dist/utils/readiness.d.ts +40 -0
- package/dist/utils/readiness.d.ts.map +1 -0
- package/dist/utils/readiness.js +491 -0
- package/dist/utils/readiness.js.map +1 -0
- package/dist/utils/retrieval-agent-instructions.d.ts +10 -0
- package/dist/utils/retrieval-agent-instructions.d.ts.map +1 -0
- package/dist/utils/retrieval-agent-instructions.js +97 -0
- package/dist/utils/retrieval-agent-instructions.js.map +1 -0
- package/dist/utils/retrieval-execution-telemetry.d.ts +53 -0
- package/dist/utils/retrieval-execution-telemetry.d.ts.map +1 -0
- package/dist/utils/retrieval-execution-telemetry.js +116 -0
- package/dist/utils/retrieval-execution-telemetry.js.map +1 -0
- package/dist/utils/retrieval-result-ranking.d.ts +34 -0
- package/dist/utils/retrieval-result-ranking.d.ts.map +1 -0
- package/dist/utils/retrieval-result-ranking.js +71 -0
- package/dist/utils/retrieval-result-ranking.js.map +1 -0
- package/dist/utils/retrieval-tool-classification.d.ts +18 -0
- package/dist/utils/retrieval-tool-classification.d.ts.map +1 -0
- package/dist/utils/retrieval-tool-classification.js +118 -0
- package/dist/utils/retrieval-tool-classification.js.map +1 -0
- package/dist/utils/semantic-plan-gate.d.ts +8 -0
- package/dist/utils/semantic-plan-gate.d.ts.map +1 -0
- package/dist/utils/semantic-plan-gate.js +24 -0
- package/dist/utils/semantic-plan-gate.js.map +1 -0
- package/dist/utils/task-json.d.ts +13 -0
- package/dist/utils/task-json.d.ts.map +1 -0
- package/dist/utils/task-json.js +12 -0
- package/dist/utils/task-json.js.map +1 -0
- package/dist/utils/template-fetcher.d.ts +150 -0
- package/dist/utils/template-fetcher.d.ts.map +1 -0
- package/dist/utils/template-fetcher.js +907 -0
- package/dist/utils/template-fetcher.js.map +1 -0
- package/dist/utils/template-hash.d.ts +123 -0
- package/dist/utils/template-hash.d.ts.map +1 -0
- package/dist/utils/template-hash.js +375 -0
- package/dist/utils/template-hash.js.map +1 -0
- package/dist/utils/uninstall-scrubbers.d.ts +30 -0
- package/dist/utils/uninstall-scrubbers.d.ts.map +1 -0
- package/dist/utils/uninstall-scrubbers.js +196 -0
- package/dist/utils/uninstall-scrubbers.js.map +1 -0
- package/dist/utils/update-rollout-report.d.ts +171 -0
- package/dist/utils/update-rollout-report.d.ts.map +1 -0
- package/dist/utils/update-rollout-report.js +126 -0
- package/dist/utils/update-rollout-report.js.map +1 -0
- package/dist/utils/validate-rules.d.ts +21 -0
- package/dist/utils/validate-rules.d.ts.map +1 -0
- package/dist/utils/validate-rules.js +88 -0
- package/dist/utils/validate-rules.js.map +1 -0
- package/dist/utils/workflow-dir.d.ts +15 -0
- package/dist/utils/workflow-dir.d.ts.map +1 -0
- package/dist/utils/workflow-dir.js +33 -0
- package/dist/utils/workflow-dir.js.map +1 -0
- package/dist/utils/workflow-resolver.d.ts +86 -0
- package/dist/utils/workflow-resolver.d.ts.map +1 -0
- package/dist/utils/workflow-resolver.js +265 -0
- package/dist/utils/workflow-resolver.js.map +1 -0
- package/package.json +117 -0
- package/scripts/postinstall.js +6 -0
|
@@ -0,0 +1,1660 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import readline from "node:readline";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import figlet from "figlet";
|
|
8
|
+
import inquirer from "inquirer";
|
|
9
|
+
import { createWorkflowStructure } from "../configurators/workflow.js";
|
|
10
|
+
import { getInitToolChoices } from "../configurators/index.js";
|
|
11
|
+
import { getPythonCommandForPlatform, setResolvedPythonCommand, } from "../configurators/shared.js";
|
|
12
|
+
import { DIR_NAMES, FILE_NAMES, PATHS } from "../constants/paths.js";
|
|
13
|
+
import { VERSION } from "../constants/version.js";
|
|
14
|
+
import { setWriteMode, startRecordingWrites, stopRecordingWrites, } from "../utils/file-writer.js";
|
|
15
|
+
import { applyKernelCreate, applyKernelStart, writeWaveCConfirmed, } from "@blxzer/pactile-core/task";
|
|
16
|
+
import { PACTILE_ENVIRONMENT_KEYS, readPactileEnvironment, } from "@blxzer/pactile-core";
|
|
17
|
+
import { emptyTaskJson } from "../utils/task-json.js";
|
|
18
|
+
import { detectProjectType, detectMonorepo, sanitizePkgName, } from "../utils/project-detector.js";
|
|
19
|
+
import { initializeHashes, removeHash } from "../utils/template-hash.js";
|
|
20
|
+
import { NATIVE_WORKFLOW_ID, resolveWorkflowTemplate, } from "../utils/workflow-resolver.js";
|
|
21
|
+
import { isCwdHomedir, homedirGuardMessage, homedirBypassEnabled, } from "../utils/cwd-guard.js";
|
|
22
|
+
import { fetchTemplateIndex, probeRegistryIndex, downloadTemplateById, downloadRegistryDirect, parseRegistrySource, TIMEOUTS, TEMPLATE_INDEX_URL, } from "../utils/template-fetcher.js";
|
|
23
|
+
import { setupProxy, maskProxyUrl } from "../utils/proxy.js";
|
|
24
|
+
import { reportInitReadiness, snapshotReadinessForRollout, } from "../utils/readiness.js";
|
|
25
|
+
import { getProjectCapability, getProjectCapabilityChoices, loadProjectCapabilities, parseProjectCapabilities, writeProjectCapabilityFiles, } from "../utils/project-capabilities.js";
|
|
26
|
+
import { collectCanonicalGenerationFiles, collectLegacyCstlLifecycleFiles, discoverCanonicalGenerationPaths, installedPactilePlatforms, materializeCanonicalGeneration, materializePreparedLegacyUserState, prepareLegacyCstlImport, readLegacyCstlVersion, runLifecycleCommand, seedCanonicalBuildRoot, } from "../pactile/lifecycle/index.js";
|
|
27
|
+
import { InstallStateStore } from "../pactile/runtime/stores.js";
|
|
28
|
+
import { inspectLegacyInitContext, legacyImportPreparedMessage, } from "../pactile/compat/init-context.js";
|
|
29
|
+
const MIN_PYTHON_MAJOR = 3;
|
|
30
|
+
const MIN_PYTHON_MINOR = 9;
|
|
31
|
+
const PYTHON_VERSION_RE = /Python (\d+)\.(\d+)/;
|
|
32
|
+
export function isSupportedPythonVersion(versionOutput) {
|
|
33
|
+
const match = versionOutput.match(PYTHON_VERSION_RE);
|
|
34
|
+
if (!match)
|
|
35
|
+
return false;
|
|
36
|
+
const major = Number(match[1]);
|
|
37
|
+
const minor = Number(match[2]);
|
|
38
|
+
return (major > MIN_PYTHON_MAJOR ||
|
|
39
|
+
(major === MIN_PYTHON_MAJOR && minor >= MIN_PYTHON_MINOR));
|
|
40
|
+
}
|
|
41
|
+
function detectPythonVersion(command) {
|
|
42
|
+
try {
|
|
43
|
+
return execSync(`${command} --version`, {
|
|
44
|
+
encoding: "utf-8",
|
|
45
|
+
stdio: "pipe",
|
|
46
|
+
}).trim();
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
const code = err?.code;
|
|
50
|
+
if (code === "EPERM" || code === "EACCES") {
|
|
51
|
+
return "sandbox-restricted";
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export function requireSupportedPython(command) {
|
|
57
|
+
// Final escape hatch — set when the user knows python3 is on PATH but
|
|
58
|
+
// the probe keeps failing for environment-specific reasons.
|
|
59
|
+
if (readPactileEnvironment(PACTILE_ENVIRONMENT_KEYS.skipPythonCheck) === "1") {
|
|
60
|
+
return `version check skipped (PACTILE_SKIP_PYTHON_CHECK=1)`;
|
|
61
|
+
}
|
|
62
|
+
const versionOutput = detectPythonVersion(command);
|
|
63
|
+
if (versionOutput === "sandbox-restricted") {
|
|
64
|
+
console.warn(chalk.yellow(`⚠ Python version check skipped — sandboxed environment blocked ` +
|
|
65
|
+
`child_process spawn (EPERM/EACCES). Assuming "${command}" is on ` +
|
|
66
|
+
`PATH. If init fails later, re-run on the host or set ` +
|
|
67
|
+
`PACTILE_SKIP_PYTHON_CHECK=1.`));
|
|
68
|
+
return `version unknown (sandbox-restricted)`;
|
|
69
|
+
}
|
|
70
|
+
if (!versionOutput) {
|
|
71
|
+
throw new Error(`Python command "${command}" not found. Pactile init requires Python ≥ 3.9.`);
|
|
72
|
+
}
|
|
73
|
+
if (!isSupportedPythonVersion(versionOutput)) {
|
|
74
|
+
throw new Error(`${versionOutput} detected via "${command}", but Pactile init requires Python ≥ 3.9.`);
|
|
75
|
+
}
|
|
76
|
+
return versionOutput;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Candidate Python command list per platform.
|
|
80
|
+
*
|
|
81
|
+
* Windows: `python` is the usual python.org installer choice, but Microsoft
|
|
82
|
+
* Store ships `python3`, and the `py` launcher is `py -3`. We try all three
|
|
83
|
+
* before giving up — fixes #236 where users with only `python3` (not
|
|
84
|
+
* `python`) had `pactile init` fail outright.
|
|
85
|
+
*
|
|
86
|
+
* Non-Windows: `python3` is canonical; `python` is a fallback for systems
|
|
87
|
+
* where Python 3 is the only Python and is named `python` (some Arch
|
|
88
|
+
* configs, conda envs).
|
|
89
|
+
*/
|
|
90
|
+
const PYTHON_CANDIDATES = {
|
|
91
|
+
win32: ["python", "python3", "py -3"],
|
|
92
|
+
other: ["python3", "python"],
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Detect a working Python ≥ 3.9 command on the host platform.
|
|
96
|
+
*
|
|
97
|
+
* Honors `PACTILE_PYTHON_CMD` (explicit override, no probe) and
|
|
98
|
+
* `PACTILE_SKIP_PYTHON_CHECK=1` (skip probe, trust platform default).
|
|
99
|
+
*
|
|
100
|
+
* Otherwise tries each candidate in `PYTHON_CANDIDATES` in order and returns
|
|
101
|
+
* the first whose `--version` matches `Python ≥ 3.9`. Caches the result via
|
|
102
|
+
* `setResolvedPythonCommand` so all downstream template / configurator
|
|
103
|
+
* writes pick up the resolved value.
|
|
104
|
+
*
|
|
105
|
+
* Throws a helpful, Windows-aware error if no candidate works.
|
|
106
|
+
*/
|
|
107
|
+
export function resolveSupportedPython() {
|
|
108
|
+
// Explicit override — user knows their environment.
|
|
109
|
+
const override = readPactileEnvironment(PACTILE_ENVIRONMENT_KEYS.pythonCommand)?.trim();
|
|
110
|
+
if (override) {
|
|
111
|
+
setResolvedPythonCommand(override);
|
|
112
|
+
return { command: override, version: "set via PACTILE_PYTHON_CMD" };
|
|
113
|
+
}
|
|
114
|
+
// Skip probe entirely.
|
|
115
|
+
if (readPactileEnvironment(PACTILE_ENVIRONMENT_KEYS.skipPythonCheck) === "1") {
|
|
116
|
+
const fallback = getPythonCommandForPlatform();
|
|
117
|
+
setResolvedPythonCommand(fallback);
|
|
118
|
+
return {
|
|
119
|
+
command: fallback,
|
|
120
|
+
version: "version check skipped (PACTILE_SKIP_PYTHON_CHECK=1)",
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const candidates = process.platform === "win32"
|
|
124
|
+
? PYTHON_CANDIDATES.win32
|
|
125
|
+
: PYTHON_CANDIDATES.other;
|
|
126
|
+
const probeFailures = [];
|
|
127
|
+
for (const candidate of candidates) {
|
|
128
|
+
const probe = detectPythonVersion(candidate);
|
|
129
|
+
if (probe === "sandbox-restricted") {
|
|
130
|
+
console.warn(chalk.yellow(`⚠ Python version check skipped — sandboxed environment blocked ` +
|
|
131
|
+
`child_process spawn (EPERM/EACCES). Assuming "${candidate}" is ` +
|
|
132
|
+
`on PATH. If init fails later, re-run on the host or set ` +
|
|
133
|
+
`PACTILE_SKIP_PYTHON_CHECK=1.`));
|
|
134
|
+
setResolvedPythonCommand(candidate);
|
|
135
|
+
return {
|
|
136
|
+
command: candidate,
|
|
137
|
+
version: "version unknown (sandbox-restricted)",
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
if (!probe) {
|
|
141
|
+
probeFailures.push(`${candidate}: not found`);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (!isSupportedPythonVersion(probe)) {
|
|
145
|
+
probeFailures.push(`${candidate}: ${probe} (< 3.9)`);
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
setResolvedPythonCommand(candidate);
|
|
149
|
+
return { command: candidate, version: probe };
|
|
150
|
+
}
|
|
151
|
+
const isWindows = process.platform === "win32";
|
|
152
|
+
const installHint = isWindows
|
|
153
|
+
? `Install Python ≥ 3.9 from https://www.python.org/downloads/windows/ — make sure ` +
|
|
154
|
+
`"Add Python to PATH" is checked in the installer. Or, if Python is ` +
|
|
155
|
+
`installed under a different name, set PACTILE_PYTHON_CMD=<your-cmd> ` +
|
|
156
|
+
`before re-running init (e.g. \`set PACTILE_PYTHON_CMD=py -3\`).`
|
|
157
|
+
: `Install Python ≥ 3.9 from https://www.python.org/downloads/ or via your ` +
|
|
158
|
+
`package manager. Or set PACTILE_PYTHON_CMD=<your-cmd> before re-running.`;
|
|
159
|
+
throw new Error(`No supported Python command found. Tried: ${candidates.join(", ")}.\n` +
|
|
160
|
+
`Probe results:\n ${probeFailures.join("\n ")}\n\n` +
|
|
161
|
+
`Pactile init requires Python ≥ 3.9. ${installHint}\n` +
|
|
162
|
+
`Last-resort escape hatch: set PACTILE_SKIP_PYTHON_CHECK=1 to skip the probe entirely.`);
|
|
163
|
+
}
|
|
164
|
+
// =============================================================================
|
|
165
|
+
// Bootstrap Task Creation
|
|
166
|
+
// =============================================================================
|
|
167
|
+
const BOOTSTRAP_TASK_NAME = "00-bootstrap-guidelines";
|
|
168
|
+
/**
|
|
169
|
+
* Slugify a developer name for safe use in task directory names.
|
|
170
|
+
*
|
|
171
|
+
* Unlike `sanitizePkgName` (which only strips npm @scope/ prefixes), this
|
|
172
|
+
* handles arbitrary developer input: spaces, Unicode letters, punctuation,
|
|
173
|
+
* path separators. Returns "user" fallback when input slugifies to empty.
|
|
174
|
+
*
|
|
175
|
+
* Exported for unit testing; not part of the public API.
|
|
176
|
+
*/
|
|
177
|
+
export function slugifyDeveloperName(name) {
|
|
178
|
+
const slug = name
|
|
179
|
+
.toLowerCase()
|
|
180
|
+
.normalize("NFKD")
|
|
181
|
+
.replace(/[^\p{Letter}\p{Number}]+/gu, "-")
|
|
182
|
+
.replace(/^-+|-+$/g, "");
|
|
183
|
+
return slug || "user";
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Write a task skeleton (task.json + prd.md).
|
|
187
|
+
*
|
|
188
|
+
* Idempotent: if the task dir already exists, returns true without touching
|
|
189
|
+
* anything. Shared by both creator bootstrap and joiner onboarding flows.
|
|
190
|
+
*/
|
|
191
|
+
function writeTaskSkeleton(cwd, taskName, taskJson, prdContent) {
|
|
192
|
+
const taskDir = path.join(cwd, PATHS.TASKS, taskName);
|
|
193
|
+
if (fs.existsSync(taskDir))
|
|
194
|
+
return true; // idempotent
|
|
195
|
+
try {
|
|
196
|
+
fs.mkdirSync(taskDir, { recursive: true });
|
|
197
|
+
const created = applyKernelCreate({
|
|
198
|
+
taskDir,
|
|
199
|
+
actor: "pactile init",
|
|
200
|
+
idempotencyKey: `init:${taskName}`,
|
|
201
|
+
record: { ...taskJson, status: "planning" },
|
|
202
|
+
evidence: "pactile init skeleton",
|
|
203
|
+
});
|
|
204
|
+
if (taskJson.status === "in_progress") {
|
|
205
|
+
applyKernelStart({
|
|
206
|
+
taskDir,
|
|
207
|
+
expectedRevision: created.kernel.revision,
|
|
208
|
+
actor: "pactile init",
|
|
209
|
+
idempotencyKey: `init-start:${taskName}`,
|
|
210
|
+
record: { ...taskJson, status: "in_progress" },
|
|
211
|
+
evidence: "pactile init skeleton start",
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
fs.writeFileSync(path.join(taskDir, FILE_NAMES.PRD), prdContent, "utf-8");
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Compute the bootstrap checklist items (previously stored as structured
|
|
223
|
+
* `subtasks: [{name, status}]` in task.json). Per task 04-21-task-schema-unify
|
|
224
|
+
* (D1), these live as markdown `- [ ]` items in prd.md instead, so task.json
|
|
225
|
+
* stays canonical with `subtasks: string[]` (child task dir names, same as
|
|
226
|
+
* task_store.py).
|
|
227
|
+
*/
|
|
228
|
+
function getBootstrapChecklistItems(projectType, packages) {
|
|
229
|
+
if (packages && packages.length > 0) {
|
|
230
|
+
const items = packages.map((pkg) => `Fill guidelines for ${pkg.name}`);
|
|
231
|
+
items.push("Add code examples");
|
|
232
|
+
return items;
|
|
233
|
+
}
|
|
234
|
+
if (projectType === "frontend") {
|
|
235
|
+
return ["Fill frontend guidelines", "Add code examples"];
|
|
236
|
+
}
|
|
237
|
+
if (projectType === "backend") {
|
|
238
|
+
return ["Fill backend guidelines", "Add code examples"];
|
|
239
|
+
}
|
|
240
|
+
return [
|
|
241
|
+
"Fill backend guidelines",
|
|
242
|
+
"Fill frontend guidelines",
|
|
243
|
+
"Add code examples",
|
|
244
|
+
];
|
|
245
|
+
}
|
|
246
|
+
function renderCapabilityReadinessSection(selectedCapabilities) {
|
|
247
|
+
if (selectedCapabilities.length === 0) {
|
|
248
|
+
return "";
|
|
249
|
+
}
|
|
250
|
+
const checklist = selectedCapabilities
|
|
251
|
+
.map((id) => {
|
|
252
|
+
const capability = getProjectCapability(id);
|
|
253
|
+
return `- [ ] \`${capability.id}\` — ${capability.title}. Verify the generated MCP/config path is usable before claiming it in task evidence.`;
|
|
254
|
+
})
|
|
255
|
+
.join("\n");
|
|
256
|
+
return `
|
|
257
|
+
## Capability readiness (required before archive)
|
|
258
|
+
|
|
259
|
+
Init selected optional project capabilities for this repo. Treat them as
|
|
260
|
+
\`pending\` until you verify they work in this checkout.
|
|
261
|
+
|
|
262
|
+
${checklist}
|
|
263
|
+
|
|
264
|
+
- Read \`.pactile/capabilities.json\` / \`.pactile/capabilities.md\` and keep the
|
|
265
|
+
readiness state honest: \`pending\`, \`ready\`, or \`failed\`.
|
|
266
|
+
- For \`codebase-retrieval\`, verify \`.codegraph/\` exists (or initialize it)
|
|
267
|
+
and confirm the MCP path is usable. After the first index, CodeGraph's file
|
|
268
|
+
watcher auto-syncs later edits; you do not need to re-run full indexing for
|
|
269
|
+
every code change.
|
|
270
|
+
- If a capability cannot be made ready, record the failure and fallback path in
|
|
271
|
+
\`verify.md\` before archiving bootstrap.
|
|
272
|
+
- Validation entrypoint: \`pactile capability-smoke --write-status\`
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
`;
|
|
276
|
+
}
|
|
277
|
+
function getBootstrapRelatedFiles(projectType, packages) {
|
|
278
|
+
if (packages && packages.length > 0) {
|
|
279
|
+
return packages.map((pkg) => `.pactile/spec/${sanitizePkgName(pkg.name)}/`);
|
|
280
|
+
}
|
|
281
|
+
if (projectType === "frontend") {
|
|
282
|
+
return [".pactile/spec/frontend/"];
|
|
283
|
+
}
|
|
284
|
+
if (projectType === "backend") {
|
|
285
|
+
return [".pactile/spec/backend/"];
|
|
286
|
+
}
|
|
287
|
+
return [".pactile/spec/backend/", ".pactile/spec/frontend/"];
|
|
288
|
+
}
|
|
289
|
+
function getBootstrapPrdContent(projectType, pythonCmd, selectedCapabilities, packages) {
|
|
290
|
+
const checklistItems = getBootstrapChecklistItems(projectType, packages);
|
|
291
|
+
const checklistMarkdown = checklistItems
|
|
292
|
+
.map((item) => `- [ ] ${item}`)
|
|
293
|
+
.join("\n");
|
|
294
|
+
const header = `# Bootstrap Task: Fill Project Development Guidelines
|
|
295
|
+
|
|
296
|
+
**You (the AI) are running this task. The developer does not read this file.**
|
|
297
|
+
|
|
298
|
+
The developer just ran \`pactile init\` on this project for the first time.
|
|
299
|
+
\`.pactile/\` now exists with empty spec scaffolding, and this bootstrap task
|
|
300
|
+
exists under \`.pactile/tasks/\`. When they want to work on it, they should start
|
|
301
|
+
this task from a session that provides Pactile session identity.
|
|
302
|
+
|
|
303
|
+
**Your job**: help them populate \`.pactile/spec/\` with the team's real
|
|
304
|
+
coding conventions. Every future AI session — this project's
|
|
305
|
+
\`pactile-implement\` and \`pactile-check\` sub-agents — auto-loads spec files
|
|
306
|
+
listed in per-task jsonl manifests. Empty spec = sub-agents write generic
|
|
307
|
+
code. Real spec = sub-agents match the team's actual patterns.
|
|
308
|
+
|
|
309
|
+
Don't dump instructions. Open with a short greeting, figure out if the repo
|
|
310
|
+
has any existing convention docs (AGENTS.md, .cursorrules, CONTRIBUTING.md, etc.), and drive
|
|
311
|
+
the rest conversationally.
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Status (update the checkboxes as you complete each item)
|
|
316
|
+
|
|
317
|
+
${checklistMarkdown}
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
${renderCapabilityReadinessSection(selectedCapabilities)}
|
|
322
|
+
|
|
323
|
+
## Spec files to populate
|
|
324
|
+
`;
|
|
325
|
+
const backendSection = `
|
|
326
|
+
|
|
327
|
+
### Backend guidelines
|
|
328
|
+
|
|
329
|
+
| File | What to document |
|
|
330
|
+
|------|------------------|
|
|
331
|
+
| \`.pactile/spec/backend/directory-structure.md\` | Where different file types go (routes, services, utils) |
|
|
332
|
+
| \`.pactile/spec/backend/database-guidelines.md\` | ORM, migrations, query patterns, naming conventions |
|
|
333
|
+
| \`.pactile/spec/backend/error-handling.md\` | How errors are caught, logged, and returned |
|
|
334
|
+
| \`.pactile/spec/backend/logging-guidelines.md\` | Log levels, format, what to log |
|
|
335
|
+
| \`.pactile/spec/backend/quality-guidelines.md\` | Code review standards, testing requirements |
|
|
336
|
+
`;
|
|
337
|
+
const frontendSection = `
|
|
338
|
+
|
|
339
|
+
### Frontend guidelines
|
|
340
|
+
|
|
341
|
+
| File | What to document |
|
|
342
|
+
|------|------------------|
|
|
343
|
+
| \`.pactile/spec/frontend/directory-structure.md\` | Component/page/hook organization |
|
|
344
|
+
| \`.pactile/spec/frontend/component-guidelines.md\` | Component patterns, props conventions |
|
|
345
|
+
| \`.pactile/spec/frontend/hook-guidelines.md\` | Custom hook naming, patterns |
|
|
346
|
+
| \`.pactile/spec/frontend/state-management.md\` | State library, patterns, what goes where |
|
|
347
|
+
| \`.pactile/spec/frontend/type-safety.md\` | TypeScript conventions, type organization |
|
|
348
|
+
| \`.pactile/spec/frontend/quality-guidelines.md\` | Linting, testing, accessibility |
|
|
349
|
+
`;
|
|
350
|
+
const footer = `
|
|
351
|
+
|
|
352
|
+
### Thinking guides (already populated)
|
|
353
|
+
|
|
354
|
+
\`.pactile/spec/guides/\` contains general thinking guides pre-filled with
|
|
355
|
+
best practices. Customize only if something clearly doesn't fit this project.
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## How to fill the spec
|
|
360
|
+
|
|
361
|
+
### Step 1: Import from existing convention files first (preferred)
|
|
362
|
+
|
|
363
|
+
Search the repo for existing convention docs. If any exist, read them and
|
|
364
|
+
extract the relevant rules into the matching \`.pactile/spec/\` files —
|
|
365
|
+
usually much faster than documenting from scratch.
|
|
366
|
+
|
|
367
|
+
| File / Directory | Notes |
|
|
368
|
+
|------|------|
|
|
369
|
+
| \`AGENTS.md\` | Agent entry / managed instructions |
|
|
370
|
+
| \`.cursorrules\` | Legacy Cursor rules file |
|
|
371
|
+
| \`.cursor/rules/*.mdc\` | Cursor rules directory |
|
|
372
|
+
| \`CONTRIBUTING.md\` | General project conventions |
|
|
373
|
+
| \`.editorconfig\` | Editor formatting rules |
|
|
374
|
+
|
|
375
|
+
### Step 2: Analyze the codebase for anything not covered by existing docs
|
|
376
|
+
|
|
377
|
+
Scan real code to discover patterns. Before writing each spec file:
|
|
378
|
+
- Find 2-3 real examples of each pattern in the codebase.
|
|
379
|
+
- Reference real file paths (not hypothetical ones).
|
|
380
|
+
- Document anti-patterns the team clearly avoids.
|
|
381
|
+
|
|
382
|
+
### Step 3: Document reality, not ideals
|
|
383
|
+
|
|
384
|
+
**Critical**: write what the code *actually does*, not what it should do.
|
|
385
|
+
Sub-agents match the spec, so aspirational patterns that don't exist in the
|
|
386
|
+
codebase will cause sub-agents to write code that looks out of place.
|
|
387
|
+
|
|
388
|
+
If the team has known tech debt, document the current state — improvement
|
|
389
|
+
is a separate conversation, not a bootstrap concern.
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## Quick explainer of the runtime (share when they ask "why do we need spec at all")
|
|
394
|
+
|
|
395
|
+
- Every AI coding task spawns two sub-agents: \`pactile-implement\` (writes
|
|
396
|
+
code) and \`pactile-check\` (verifies quality).
|
|
397
|
+
- Each task has \`implement.jsonl\` / \`check.jsonl\` manifests listing which
|
|
398
|
+
spec files to load.
|
|
399
|
+
- The platform hook auto-injects those spec files + the task's \`prd.md\`
|
|
400
|
+
into every sub-agent prompt, so the sub-agent codes/reviews per team
|
|
401
|
+
conventions without anyone pasting them manually.
|
|
402
|
+
- Source of truth: \`.pactile/spec/\`. That's why filling it well now pays
|
|
403
|
+
off forever.
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
## Completion
|
|
408
|
+
|
|
409
|
+
When the developer confirms the checklist items above are done with real
|
|
410
|
+
examples (not placeholders), guide them to run:
|
|
411
|
+
|
|
412
|
+
\`\`\`bash
|
|
413
|
+
${pythonCmd} ./.pactile/scripts/task.py archive 00-bootstrap-guidelines
|
|
414
|
+
\`\`\`
|
|
415
|
+
|
|
416
|
+
After archive, every new developer who joins this project will get a
|
|
417
|
+
\`00-join-<slug>\` onboarding task instead of this bootstrap task.
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
## Suggested opening line
|
|
422
|
+
|
|
423
|
+
"Welcome to Pactile! Your init just set me up to help you fill the project
|
|
424
|
+
spec — a one-time setup so every future AI session follows the team's
|
|
425
|
+
conventions instead of writing generic code. Before we start, do you have
|
|
426
|
+
any existing convention docs (AGENTS.md, .cursorrules, CONTRIBUTING.md,
|
|
427
|
+
etc.) I can pull from, or should I scan the codebase from scratch?"
|
|
428
|
+
`;
|
|
429
|
+
let content = header;
|
|
430
|
+
if (packages && packages.length > 0) {
|
|
431
|
+
// Monorepo: generate per-package sections
|
|
432
|
+
for (const pkg of packages) {
|
|
433
|
+
const pkgType = pkg.type === "unknown" ? "fullstack" : pkg.type;
|
|
434
|
+
const specName = sanitizePkgName(pkg.name);
|
|
435
|
+
content += `\n### Package: ${pkg.name} (\`spec/${specName}/\`)\n`;
|
|
436
|
+
if (pkgType !== "frontend") {
|
|
437
|
+
content += `\n- Backend guidelines: \`.pactile/spec/${specName}/backend/\`\n`;
|
|
438
|
+
}
|
|
439
|
+
if (pkgType !== "backend") {
|
|
440
|
+
content += `\n- Frontend guidelines: \`.pactile/spec/${specName}/frontend/\`\n`;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
else if (projectType === "frontend") {
|
|
445
|
+
content += frontendSection;
|
|
446
|
+
}
|
|
447
|
+
else if (projectType === "backend") {
|
|
448
|
+
content += backendSection;
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
// fullstack
|
|
452
|
+
content += backendSection;
|
|
453
|
+
content += frontendSection;
|
|
454
|
+
}
|
|
455
|
+
content += footer;
|
|
456
|
+
return content;
|
|
457
|
+
}
|
|
458
|
+
function getBootstrapTaskJson(developer, projectType, packages) {
|
|
459
|
+
const today = new Date().toISOString().split("T")[0];
|
|
460
|
+
const relatedFiles = getBootstrapRelatedFiles(projectType, packages);
|
|
461
|
+
// Canonical 24-field shape via emptyTaskJson factory.
|
|
462
|
+
// Checklist items (previously stored as structured `subtasks`) are now
|
|
463
|
+
// rendered as `- [ ]` items in prd.md; task.json.subtasks is always
|
|
464
|
+
// string[] (child task dir names) per the canonical schema.
|
|
465
|
+
return emptyTaskJson({
|
|
466
|
+
id: BOOTSTRAP_TASK_NAME,
|
|
467
|
+
name: BOOTSTRAP_TASK_NAME,
|
|
468
|
+
title: "Bootstrap Guidelines",
|
|
469
|
+
description: "Fill in project development guidelines for AI agents",
|
|
470
|
+
status: "in_progress",
|
|
471
|
+
dev_type: "docs",
|
|
472
|
+
priority: "P1",
|
|
473
|
+
creator: developer,
|
|
474
|
+
assignee: developer,
|
|
475
|
+
createdAt: today,
|
|
476
|
+
relatedFiles,
|
|
477
|
+
notes: `First-time setup task created by pactile init (${projectType} project)`,
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Create bootstrap task for first-time setup
|
|
482
|
+
*/
|
|
483
|
+
function createBootstrapTask(cwd, developer, pythonCmd, projectType, selectedCapabilities, packages) {
|
|
484
|
+
const taskJson = getBootstrapTaskJson(developer, projectType, packages);
|
|
485
|
+
const prdContent = getBootstrapPrdContent(projectType, pythonCmd, selectedCapabilities, packages);
|
|
486
|
+
return writeTaskSkeleton(cwd, BOOTSTRAP_TASK_NAME, taskJson, prdContent);
|
|
487
|
+
}
|
|
488
|
+
// =============================================================================
|
|
489
|
+
// Joiner Onboarding Task Creation
|
|
490
|
+
// =============================================================================
|
|
491
|
+
/**
|
|
492
|
+
* task.json factory for joiner onboarding. Mirrors the bootstrap factory but
|
|
493
|
+
* uses dev_type "docs", higher priority "P1", and the developer-specific task
|
|
494
|
+
* name (so multiple joiners in the same checkout don't collide).
|
|
495
|
+
*/
|
|
496
|
+
function getJoinerTaskJson(developer, taskName) {
|
|
497
|
+
const today = new Date().toISOString().split("T")[0];
|
|
498
|
+
return emptyTaskJson({
|
|
499
|
+
id: taskName,
|
|
500
|
+
name: taskName,
|
|
501
|
+
title: `Joining: Onboard to this Pactile project (${developer})`,
|
|
502
|
+
description: "Onboard a new developer to an existing Pactile project: learn the workflow, conventions, and find assigned work",
|
|
503
|
+
status: "in_progress",
|
|
504
|
+
dev_type: "docs",
|
|
505
|
+
priority: "P1",
|
|
506
|
+
creator: developer,
|
|
507
|
+
assignee: developer,
|
|
508
|
+
createdAt: today,
|
|
509
|
+
notes: "Generated by pactile init for a new developer joining an existing Pactile project",
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* PRD content for joiner onboarding. Kept concise (~80 lines) — deeper
|
|
514
|
+
* guidance lives in skills and docs.
|
|
515
|
+
*/
|
|
516
|
+
function getJoinerPrdContent(developer, pythonCmd, selectedCapabilities) {
|
|
517
|
+
const slug = slugifyDeveloperName(developer);
|
|
518
|
+
const selectedCapabilityChecklist = selectedCapabilities
|
|
519
|
+
.map((id) => {
|
|
520
|
+
const capability = getProjectCapability(id);
|
|
521
|
+
return `- \`${capability.id}\` — re-check readiness in this clone before claiming it is available.`;
|
|
522
|
+
})
|
|
523
|
+
.join("\n");
|
|
524
|
+
let capabilitySection = "";
|
|
525
|
+
if (selectedCapabilities.length > 0) {
|
|
526
|
+
capabilitySection = `
|
|
527
|
+
### 5. Re-verify selected project capabilities
|
|
528
|
+
|
|
529
|
+
This repo has capability selections recorded in \`.pactile/capabilities.json\`.
|
|
530
|
+
Before they rely on MCP-backed behavior, remind them to check the selected set:
|
|
531
|
+
|
|
532
|
+
${selectedCapabilityChecklist}
|
|
533
|
+
|
|
534
|
+
- If a capability is not \`ready\`, have them re-run the local verification path
|
|
535
|
+
instead of assuming the previous machine's setup carries over.
|
|
536
|
+
|
|
537
|
+
---
|
|
538
|
+
`;
|
|
539
|
+
}
|
|
540
|
+
return `# Joiner Onboarding Task
|
|
541
|
+
|
|
542
|
+
**You (the AI) are running this task. The developer does not read this file.**
|
|
543
|
+
|
|
544
|
+
\`${developer}\` just ran \`pactile init\` on a fresh clone, saw "Developer
|
|
545
|
+
initialized", and will now start asking you questions in chat. This joiner task
|
|
546
|
+
exists under \`.pactile/tasks/\`; when they want to work on it, they should
|
|
547
|
+
select it from a session that provides Pactile session identity.
|
|
548
|
+
|
|
549
|
+
Your job is to orient them to Pactile. Don't dump all of this at them — open
|
|
550
|
+
with a short greeting, ask where they want to start, and fill in the rest as
|
|
551
|
+
they engage.
|
|
552
|
+
|
|
553
|
+
---
|
|
554
|
+
|
|
555
|
+
## Topics to cover (adapt order to their questions)
|
|
556
|
+
|
|
557
|
+
### 1. What Pactile is + the workflow
|
|
558
|
+
|
|
559
|
+
Pactile is a governed capability workspace for Cursor and Codex that keeps AI
|
|
560
|
+
agents consistent with project-specific conventions instead of writing generic
|
|
561
|
+
code every session.
|
|
562
|
+
|
|
563
|
+
- **Human lifecycle**: Open → Define → Approve → Execute → Verify →
|
|
564
|
+
(Integrate? when parent-child) → Close. Kernel writes that state.
|
|
565
|
+
\`.pactile/workflow.md\` is a human overview, **not runtime SSOT**.
|
|
566
|
+
- **Task files** live under \`.pactile/tasks/\`. \`status\` is a projection, not
|
|
567
|
+
the only truth.
|
|
568
|
+
- **User slash (Native Cursor)**:
|
|
569
|
+
- \`/pactile-continue\` — resume only when this live session already has a
|
|
570
|
+
selected task
|
|
571
|
+
- \`/pactile-finish-work\` — wrap up a finished task
|
|
572
|
+
- \`/pactile-handoff\` — session handoff to a temp path (not the task's
|
|
573
|
+
\`handoff.md\`)
|
|
574
|
+
SessionStart covers entry. \`/pactile-start\` is not installed as a slash on
|
|
575
|
+
agent-capable Cursor. Official \`/goal\` is not a Pactile Task.
|
|
576
|
+
|
|
577
|
+
### 2. Runtime mechanics (explain when they ask "how does it know what to do")
|
|
578
|
+
|
|
579
|
+
- **SessionStart hook** injects identity, git status, selected task, Task
|
|
580
|
+
Dashboard, and a compiled session pack when Event Bridge subscribers
|
|
581
|
+
produce one. It must not dump \`workflow.md\` Phase Index as the runtime
|
|
582
|
+
program.
|
|
583
|
+
- **\`/pactile-continue\`** loads Kernel / Dashboard (or the compiled pack if
|
|
584
|
+
already in context), reads \`prd.md\` + recent activity, and routes by
|
|
585
|
+
Kernel human phase. Do **not** treat \`get_context.py --mode phase\` (Phase
|
|
586
|
+
Index) as runtime SSOT. Internal skills (brainstorm, check, …) are not
|
|
587
|
+
user slash commands.
|
|
588
|
+
- **Workers**: if this Cursor Task API has no \`pactile-implement\` /
|
|
589
|
+
\`pactile-check\` enum, dispatch as \`generalPurpose\`. Never label that run
|
|
590
|
+
\`true-independent\`. When a check worker is available, it follows
|
|
591
|
+
\`check.jsonl\` — reviews against specs, auto-fixes issues, runs
|
|
592
|
+
lint/typecheck.
|
|
593
|
+
|
|
594
|
+
File layout (mention when they ask "where does what live"):
|
|
595
|
+
- \`.pactile/.runtime/sessions/<session>.json\` — live-session selected-task state, gitignored
|
|
596
|
+
- \`.pactile/tasks/<task>/{implement,check}.jsonl\` — per-task context manifests
|
|
597
|
+
- \`.pactile/spec/\` — project-wide conventions (source of truth)
|
|
598
|
+
- \`.pactile/workspace/${developer}/journal-*.md\` — their session log,
|
|
599
|
+
rotated at ~2000 lines
|
|
600
|
+
|
|
601
|
+
### 3. This project's actual conventions
|
|
602
|
+
|
|
603
|
+
- Summarize \`.pactile/spec/\` for them — what coding conventions this
|
|
604
|
+
specific team enforces.
|
|
605
|
+
- Point at the last 5 entries in \`.pactile/tasks/archive/\` as a rhythm
|
|
606
|
+
example of how people actually work here. **If archive is empty** (the
|
|
607
|
+
project just started), skip this — don't invent examples.
|
|
608
|
+
- Not your job in this onboarding to teach them the business code itself —
|
|
609
|
+
the README and their teammates handle that.
|
|
610
|
+
|
|
611
|
+
### 4. Their assigned work
|
|
612
|
+
|
|
613
|
+
- Check if \`.pactile/workspace/${developer}/\` already exists — if yes, it's
|
|
614
|
+
their journal from another machine and worth mentioning.
|
|
615
|
+
- Run \`${pythonCmd} ./.pactile/scripts/task.py list --assignee ${developer}\` to
|
|
616
|
+
show tasks assigned to them. (Quote the name if it contains spaces.)
|
|
617
|
+
- Remind them that the "My Tasks" section appears in the SessionStart context
|
|
618
|
+
on every new session.
|
|
619
|
+
|
|
620
|
+
---
|
|
621
|
+
|
|
622
|
+
${capabilitySection}
|
|
623
|
+
|
|
624
|
+
## Optional: walk through a small task end-to-end
|
|
625
|
+
|
|
626
|
+
If they want to practice before touching real work, offer to pick a tiny
|
|
627
|
+
P3 task or a typo fix and run the full cycle together: \`/pactile-continue\`
|
|
628
|
+
→ implement in Agent → \`/pactile-finish-work\`.
|
|
629
|
+
|
|
630
|
+
---
|
|
631
|
+
|
|
632
|
+
## Completion
|
|
633
|
+
|
|
634
|
+
When they feel oriented (or after you've covered the four topics with
|
|
635
|
+
reasonable back-and-forth), guide them to run:
|
|
636
|
+
|
|
637
|
+
\`\`\`bash
|
|
638
|
+
${pythonCmd} ./.pactile/scripts/task.py archive 00-join-${slug}
|
|
639
|
+
\`\`\`
|
|
640
|
+
|
|
641
|
+
---
|
|
642
|
+
|
|
643
|
+
## Suggested opening line
|
|
644
|
+
|
|
645
|
+
"Welcome! Your \`pactile init\` set me up to onboard you to this project. I
|
|
646
|
+
can walk you through the workflow, show you the runtime mechanics under the
|
|
647
|
+
hood, summarize the team's spec, or jump to what you're already curious about
|
|
648
|
+
— which would you prefer?"
|
|
649
|
+
`;
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Create joiner onboarding task for a new developer on an existing Pactile
|
|
653
|
+
* project. Task name is slugified to be filesystem-safe for arbitrary
|
|
654
|
+
* developer names (spaces, Unicode, punctuation).
|
|
655
|
+
*/
|
|
656
|
+
function createJoinerOnboardingTask(cwd, developer, pythonCmd) {
|
|
657
|
+
const slug = slugifyDeveloperName(developer);
|
|
658
|
+
const taskName = `00-join-${slug}`;
|
|
659
|
+
const taskJson = getJoinerTaskJson(developer, taskName);
|
|
660
|
+
const prdContent = getJoinerPrdContent(developer, pythonCmd, loadProjectCapabilities(cwd));
|
|
661
|
+
return writeTaskSkeleton(cwd, taskName, taskJson, prdContent);
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Handle re-init when .pactile/ already exists.
|
|
665
|
+
* Returns true if handled (caller should return), false if user chose full re-init.
|
|
666
|
+
*/
|
|
667
|
+
async function handleReinit(cwd, options, developerName, pythonCmd) {
|
|
668
|
+
const TOOLS = getPactileInitToolChoices();
|
|
669
|
+
const installState = new InstallStateStore(cwd).read();
|
|
670
|
+
const configuredPlatforms = new Set((installState?.state.installedAdapters ?? [])
|
|
671
|
+
.filter((adapter) => adapter.status === "active")
|
|
672
|
+
.map((adapter) => adapter.id.replace(/^adapter\./, ""))
|
|
673
|
+
.filter((platform) => platform === "cursor" || platform === "codex"));
|
|
674
|
+
const configuredNames = [...configuredPlatforms]
|
|
675
|
+
.map((id) => TOOLS.find((choice) => choice.platformId === id)?.name ?? id)
|
|
676
|
+
.join(", ");
|
|
677
|
+
// Determine explicit platform flags
|
|
678
|
+
const explicitTools = TOOLS.filter((t) => options[t.key]).map((t) => t.key);
|
|
679
|
+
let doAddPlatforms = explicitTools.length > 0;
|
|
680
|
+
let doAddDeveloper = !!options.user;
|
|
681
|
+
let platformsToAdd = explicitTools;
|
|
682
|
+
// No explicit flags → show menu
|
|
683
|
+
if (!doAddPlatforms && !doAddDeveloper) {
|
|
684
|
+
if (options.yes) {
|
|
685
|
+
console.log(chalk.gray(`Already initialized with: ${configuredNames}`));
|
|
686
|
+
console.log(chalk.gray("Use platform flags (e.g., --cursor) or -u <name> to add platforms/developer."));
|
|
687
|
+
return true;
|
|
688
|
+
}
|
|
689
|
+
console.log(chalk.gray(`\n Already initialized with: ${configuredNames}\n`));
|
|
690
|
+
const { action } = await inquirer.prompt([
|
|
691
|
+
{
|
|
692
|
+
type: "list",
|
|
693
|
+
name: "action",
|
|
694
|
+
message: "Pactile is already initialized. What would you like to do?",
|
|
695
|
+
choices: [
|
|
696
|
+
{ name: "Add AI platform(s)", value: "add-platform" },
|
|
697
|
+
{
|
|
698
|
+
name: "Set up developer identity on this device",
|
|
699
|
+
value: "add-developer",
|
|
700
|
+
},
|
|
701
|
+
{ name: "Full re-initialize", value: "full" },
|
|
702
|
+
],
|
|
703
|
+
},
|
|
704
|
+
]);
|
|
705
|
+
if (action === "full") {
|
|
706
|
+
return false; // Fall through to full init
|
|
707
|
+
}
|
|
708
|
+
if (action === "add-platform")
|
|
709
|
+
doAddPlatforms = true;
|
|
710
|
+
if (action === "add-developer")
|
|
711
|
+
doAddDeveloper = true;
|
|
712
|
+
}
|
|
713
|
+
// --- Add platforms ---
|
|
714
|
+
if (doAddPlatforms) {
|
|
715
|
+
if (platformsToAdd.length === 0) {
|
|
716
|
+
// Interactive: show only unconfigured platforms
|
|
717
|
+
const unconfigured = TOOLS.filter((t) => {
|
|
718
|
+
return !configuredPlatforms.has(t.platformId);
|
|
719
|
+
});
|
|
720
|
+
if (unconfigured.length === 0) {
|
|
721
|
+
console.log(chalk.green("✓ All available platforms are already configured."));
|
|
722
|
+
}
|
|
723
|
+
else {
|
|
724
|
+
const answers = await inquirer.prompt([
|
|
725
|
+
{
|
|
726
|
+
type: "checkbox",
|
|
727
|
+
name: "tools",
|
|
728
|
+
message: "Select platforms to add:",
|
|
729
|
+
choices: unconfigured.map((t) => ({
|
|
730
|
+
name: t.name,
|
|
731
|
+
value: t.key,
|
|
732
|
+
})),
|
|
733
|
+
},
|
|
734
|
+
]);
|
|
735
|
+
platformsToAdd = answers.tools;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
const requested = platformsToAdd
|
|
739
|
+
.map((tool) => TOOLS.find((choice) => choice.key === tool)?.platformId)
|
|
740
|
+
.filter((platform) => platform !== undefined);
|
|
741
|
+
const toReconcile = requested.filter((platform) => !configuredPlatforms.has(platform));
|
|
742
|
+
for (const platform of requested.filter((item) => configuredPlatforms.has(item))) {
|
|
743
|
+
console.log(chalk.gray(` ○ ${TOOLS.find((choice) => choice.platformId === platform)?.name ?? platform} already configured, skipping`));
|
|
744
|
+
}
|
|
745
|
+
if (toReconcile.length > 0) {
|
|
746
|
+
const composedPlatforms = [
|
|
747
|
+
...installedPactilePlatforms(installState?.state ?? null),
|
|
748
|
+
...toReconcile,
|
|
749
|
+
];
|
|
750
|
+
const files = collectCanonicalGenerationFiles(cwd, discoverCanonicalGenerationPaths(cwd), composedPlatforms, VERSION);
|
|
751
|
+
const result = await runLifecycleCommand({
|
|
752
|
+
projectRoot: cwd,
|
|
753
|
+
operation: "reconcile",
|
|
754
|
+
runtimeVersion: VERSION,
|
|
755
|
+
files,
|
|
756
|
+
platforms: composedPlatforms,
|
|
757
|
+
});
|
|
758
|
+
reportLifecycleResult(result, "Adapter reconcile");
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
// --- Add developer ---
|
|
762
|
+
if (doAddDeveloper) {
|
|
763
|
+
let devName = developerName;
|
|
764
|
+
if (!devName) {
|
|
765
|
+
devName = await askInput("Your name: ");
|
|
766
|
+
while (!devName) {
|
|
767
|
+
console.log(chalk.yellow("Name is required"));
|
|
768
|
+
devName = await askInput("Your name: ");
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
// Capture pre-init state: if .developer did not exist before we ran
|
|
772
|
+
// init_developer.py, this checkout had no identity → treat as a new
|
|
773
|
+
// joiner onboarding onto an existing Pactile project.
|
|
774
|
+
const hadDeveloperFileBefore = fs.existsSync(path.join(cwd, DIR_NAMES.WORKFLOW, FILE_NAMES.DEVELOPER));
|
|
775
|
+
try {
|
|
776
|
+
const scriptPath = path.join(cwd, PATHS.SCRIPTS, "init_developer.py");
|
|
777
|
+
execSync(`${pythonCmd} "${scriptPath}" "${devName}"`, {
|
|
778
|
+
cwd,
|
|
779
|
+
stdio: "pipe",
|
|
780
|
+
});
|
|
781
|
+
console.log(chalk.green(`✓ Developer "${devName}" initialized`));
|
|
782
|
+
}
|
|
783
|
+
catch {
|
|
784
|
+
console.log(chalk.yellow("⚠ Could not initialize developer. Run manually:"));
|
|
785
|
+
console.log(chalk.gray(` ${pythonCmd} .pactile/scripts/init_developer.py ${devName}`));
|
|
786
|
+
}
|
|
787
|
+
// Create joiner onboarding task for fresh checkouts (no prior .developer).
|
|
788
|
+
// Runs outside the init_developer try/catch so failures surface as warnings.
|
|
789
|
+
if (!hadDeveloperFileBefore) {
|
|
790
|
+
try {
|
|
791
|
+
if (!createJoinerOnboardingTask(cwd, devName, pythonCmd)) {
|
|
792
|
+
console.warn(chalk.yellow("⚠ Failed to create joiner onboarding task"));
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
catch (err) {
|
|
796
|
+
console.warn(chalk.yellow(`⚠ Joiner onboarding setup failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
return true;
|
|
801
|
+
}
|
|
802
|
+
function getPactileInitToolChoices() {
|
|
803
|
+
return [
|
|
804
|
+
...getInitToolChoices().map((choice) => ({
|
|
805
|
+
...choice,
|
|
806
|
+
key: choice.key,
|
|
807
|
+
platformId: choice.platformId,
|
|
808
|
+
})),
|
|
809
|
+
{
|
|
810
|
+
key: "codex",
|
|
811
|
+
name: "Codex (ChatGPT desktop app)",
|
|
812
|
+
defaultChecked: true,
|
|
813
|
+
platformId: "codex",
|
|
814
|
+
},
|
|
815
|
+
];
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Write monorepo package configuration to config.yaml (non-destructive patch).
|
|
819
|
+
* Appends packages: and default_package: without disturbing existing config.
|
|
820
|
+
*/
|
|
821
|
+
function writeMonorepoConfig(cwd, packages) {
|
|
822
|
+
const configPath = path.join(cwd, DIR_NAMES.WORKFLOW, "config.yaml");
|
|
823
|
+
let content = "";
|
|
824
|
+
try {
|
|
825
|
+
content = fs.readFileSync(configPath, "utf-8");
|
|
826
|
+
}
|
|
827
|
+
catch {
|
|
828
|
+
// Config not created yet; will be created by createWorkflowStructure
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
831
|
+
// Don't overwrite if packages: already exists (re-init case)
|
|
832
|
+
if (/^packages\s*:/m.test(content)) {
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
const lines = ["\n# Auto-detected monorepo packages", "packages:"];
|
|
836
|
+
for (const pkg of packages) {
|
|
837
|
+
lines.push(` ${sanitizePkgName(pkg.name)}:`);
|
|
838
|
+
lines.push(` path: ${pkg.path}`);
|
|
839
|
+
if (pkg.isSubmodule) {
|
|
840
|
+
lines.push(" type: submodule");
|
|
841
|
+
}
|
|
842
|
+
else if (pkg.isGitRepo) {
|
|
843
|
+
lines.push(" git: true");
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
// Use first non-submodule package as default, fallback to first package
|
|
847
|
+
const defaultPkg = packages.find((p) => !p.isSubmodule)?.name ?? packages[0]?.name;
|
|
848
|
+
if (defaultPkg) {
|
|
849
|
+
lines.push(`default_package: ${defaultPkg}`);
|
|
850
|
+
}
|
|
851
|
+
fs.writeFileSync(configPath, content.trimEnd() + "\n" + lines.join("\n") + "\n", "utf-8");
|
|
852
|
+
}
|
|
853
|
+
function reportLifecycleResult(result, action) {
|
|
854
|
+
if (result.status === "review" || result.status === "interrupted") {
|
|
855
|
+
throw new Error(`${action} stopped: ${result.reason}`);
|
|
856
|
+
}
|
|
857
|
+
if (result.status === "degraded") {
|
|
858
|
+
const failures = result.adapters
|
|
859
|
+
.filter((adapter) => adapter.status !== "succeeded")
|
|
860
|
+
.map((adapter) => `${adapter.adapterId}: ${adapter.reason ?? "pending"}${adapter.retryable ? " (retryable)" : ""}`);
|
|
861
|
+
console.warn(chalk.yellow(`${action} committed canonical state but is degraded: ${failures.join(", ")}`));
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
console.log(chalk.green(`✓ ${action} completed`));
|
|
865
|
+
}
|
|
866
|
+
export async function init(options) {
|
|
867
|
+
// Refuse to run in $HOME — running here would scoop platform runtime data
|
|
868
|
+
// (Claude/Codex/OpenCode session histories etc.) into the Pactile hash
|
|
869
|
+
// manifest, and a subsequent cleanup could damage it.
|
|
870
|
+
if (isCwdHomedir() && !homedirBypassEnabled()) {
|
|
871
|
+
console.error(chalk.red(homedirGuardMessage("init")));
|
|
872
|
+
process.exit(1);
|
|
873
|
+
}
|
|
874
|
+
const cwd = process.cwd();
|
|
875
|
+
const isFirstInit = !fs.existsSync(path.join(cwd, DIR_NAMES.WORKFLOW));
|
|
876
|
+
const importingCstl = options.importCstl === true;
|
|
877
|
+
const legacyContext = inspectLegacyInitContext({
|
|
878
|
+
cwd,
|
|
879
|
+
canonicalRootAbsent: isFirstInit,
|
|
880
|
+
importRequested: importingCstl,
|
|
881
|
+
developerFileName: FILE_NAMES.DEVELOPER,
|
|
882
|
+
});
|
|
883
|
+
if ((options.withOptional?.length ?? 0) > 0) {
|
|
884
|
+
throw new Error("--with-optional no longer writes host skill directories during init; select a declared Pactile capability instead");
|
|
885
|
+
}
|
|
886
|
+
// Captured here (before createWorkflowStructure + init_developer run) so
|
|
887
|
+
// the three-branch dispatch at the bottom can tell "fresh clone joiner"
|
|
888
|
+
// (canonical root exists, .developer missing) apart from creator first init.
|
|
889
|
+
const hadDeveloperFileAtStart = fs.existsSync(path.join(cwd, DIR_NAMES.WORKFLOW, FILE_NAMES.DEVELOPER)) ||
|
|
890
|
+
legacyContext.importedDeveloperFilePresent;
|
|
891
|
+
if (legacyContext.coexistenceNotice.length > 0) {
|
|
892
|
+
console.log(chalk.cyan(legacyContext.coexistenceNotice[0]));
|
|
893
|
+
for (const line of legacyContext.coexistenceNotice.slice(1)) {
|
|
894
|
+
console.log(chalk.gray(line));
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
// Generate ASCII art banner dynamically using FIGlet "Rebel" font
|
|
898
|
+
const banner = figlet.textSync("Pactile", { font: "Rebel" });
|
|
899
|
+
console.log(chalk.cyan(`\n${banner.trimEnd()}`));
|
|
900
|
+
console.log(chalk.gray("\n Cross-platform AI workflow framework for Cursor & Codex\n"));
|
|
901
|
+
// Set up proxy before any network calls
|
|
902
|
+
const proxyUrl = setupProxy();
|
|
903
|
+
if (proxyUrl) {
|
|
904
|
+
console.log(chalk.gray(` Using proxy: ${maskProxyUrl(proxyUrl)}\n`));
|
|
905
|
+
}
|
|
906
|
+
// Set write mode based on options
|
|
907
|
+
let writeMode = "ask";
|
|
908
|
+
if (options.force) {
|
|
909
|
+
writeMode = "force";
|
|
910
|
+
console.log(chalk.gray("Mode: Force overwrite existing files\n"));
|
|
911
|
+
}
|
|
912
|
+
else if (options.skipExisting) {
|
|
913
|
+
writeMode = "skip";
|
|
914
|
+
console.log(chalk.gray("Mode: Skip existing files\n"));
|
|
915
|
+
}
|
|
916
|
+
else if (options.yes) {
|
|
917
|
+
// -y implies non-interactive: never prompt on conflicts. Default to skip
|
|
918
|
+
// (preserve user files) — explicit --force is required to overwrite.
|
|
919
|
+
writeMode = "skip";
|
|
920
|
+
console.log(chalk.gray("Mode: Non-interactive (skip existing files)\n"));
|
|
921
|
+
}
|
|
922
|
+
setWriteMode(writeMode);
|
|
923
|
+
// Detect developer name from git config or options
|
|
924
|
+
let developerName = options.user;
|
|
925
|
+
if (!developerName) {
|
|
926
|
+
// Only detect from git if current directory is a git repo
|
|
927
|
+
const isGitRepo = fs.existsSync(path.join(cwd, ".git"));
|
|
928
|
+
if (isGitRepo) {
|
|
929
|
+
try {
|
|
930
|
+
developerName = execSync("git config user.name", {
|
|
931
|
+
cwd,
|
|
932
|
+
encoding: "utf-8",
|
|
933
|
+
}).trim();
|
|
934
|
+
}
|
|
935
|
+
catch {
|
|
936
|
+
// Git not available or no user.name configured
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
if (developerName) {
|
|
941
|
+
console.log(chalk.blue("👤 Developer:"), chalk.gray(developerName));
|
|
942
|
+
}
|
|
943
|
+
const { command: pythonCmd } = resolveSupportedPython();
|
|
944
|
+
// ==========================================================================
|
|
945
|
+
// Re-init fast path: skip full flow when .pactile/ already exists.
|
|
946
|
+
// ==========================================================================
|
|
947
|
+
// Aborted-init recovery (issue #204): if .pactile/ exists but tasks/ is
|
|
948
|
+
// empty, the previous init never reached bootstrap creation. Fall through
|
|
949
|
+
// to the full flow so the main-dispatch tasksEmpty fallback fires —
|
|
950
|
+
// handleReinit's joiner branch would otherwise mis-route the recovery.
|
|
951
|
+
const tasksDirEarly = path.join(cwd, PATHS.TASKS);
|
|
952
|
+
const tasksEmptyEarly = !fs.existsSync(tasksDirEarly) || fs.readdirSync(tasksDirEarly).length === 0;
|
|
953
|
+
if (!isFirstInit &&
|
|
954
|
+
!importingCstl &&
|
|
955
|
+
!options.force &&
|
|
956
|
+
!options.skipExisting &&
|
|
957
|
+
!tasksEmptyEarly) {
|
|
958
|
+
const reinitDone = await handleReinit(cwd, options, developerName, pythonCmd);
|
|
959
|
+
if (reinitDone)
|
|
960
|
+
return;
|
|
961
|
+
// reinitDone === false means user chose "full re-initialize" → fall through
|
|
962
|
+
}
|
|
963
|
+
if (!developerName && !options.yes) {
|
|
964
|
+
// Ask for developer name if not detected and not in yes mode
|
|
965
|
+
console.log(chalk.gray("\nPactile supports team collaboration - each developer has their own\n" +
|
|
966
|
+
`workspace directory (${PATHS.WORKSPACE}/{name}/) to track AI sessions.\n` +
|
|
967
|
+
"Tip: Usually this is your git username (git config user.name).\n"));
|
|
968
|
+
developerName = await askInput("Your name: ");
|
|
969
|
+
while (!developerName) {
|
|
970
|
+
console.log(chalk.yellow("Name is required"));
|
|
971
|
+
developerName = await askInput("Your name: ");
|
|
972
|
+
}
|
|
973
|
+
console.log(chalk.blue("👤 Developer:"), chalk.gray(developerName));
|
|
974
|
+
}
|
|
975
|
+
// Detect project type (silent - no output)
|
|
976
|
+
const detectedType = detectProjectType(cwd);
|
|
977
|
+
// Parse custom registry source early (needed by both monorepo + single-repo flows)
|
|
978
|
+
let registry;
|
|
979
|
+
if (options.registry) {
|
|
980
|
+
try {
|
|
981
|
+
registry = parseRegistrySource(options.registry);
|
|
982
|
+
}
|
|
983
|
+
catch (error) {
|
|
984
|
+
console.log(chalk.red(error instanceof Error ? error.message : "Invalid registry source"));
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
// Determine template strategy from flags (needed before monorepo template downloads)
|
|
989
|
+
let templateStrategy = "skip";
|
|
990
|
+
if (options.overwrite) {
|
|
991
|
+
templateStrategy = "overwrite";
|
|
992
|
+
}
|
|
993
|
+
else if (options.append) {
|
|
994
|
+
templateStrategy = "append";
|
|
995
|
+
}
|
|
996
|
+
// ==========================================================================
|
|
997
|
+
// Monorepo Detection
|
|
998
|
+
// ==========================================================================
|
|
999
|
+
let monorepoPackages;
|
|
1000
|
+
let remoteSpecPackages;
|
|
1001
|
+
if (options.monorepo !== false) {
|
|
1002
|
+
// options.monorepo: true = --monorepo, false = --no-monorepo, undefined = auto
|
|
1003
|
+
const detected = detectMonorepo(cwd);
|
|
1004
|
+
if (options.monorepo === true && !detected) {
|
|
1005
|
+
console.log(chalk.red("Error: --monorepo specified but no multi-package layout detected."));
|
|
1006
|
+
console.log("");
|
|
1007
|
+
console.log(chalk.gray("Checked:"));
|
|
1008
|
+
console.log(chalk.gray(" ✗ pnpm-workspace.yaml"));
|
|
1009
|
+
console.log(chalk.gray(" ✗ package.json workspaces"));
|
|
1010
|
+
console.log(chalk.gray(" ✗ Cargo.toml [workspace]"));
|
|
1011
|
+
console.log(chalk.gray(" ✗ go.work"));
|
|
1012
|
+
console.log(chalk.gray(" ✗ pyproject.toml [tool.uv.workspace]"));
|
|
1013
|
+
console.log(chalk.gray(" ✗ .gitmodules"));
|
|
1014
|
+
console.log(chalk.gray(" ✗ sibling .git directories (need ≥ 2)"));
|
|
1015
|
+
console.log("");
|
|
1016
|
+
console.log("To configure manually, add to .pactile/config.yaml:");
|
|
1017
|
+
console.log("");
|
|
1018
|
+
console.log(chalk.cyan(" packages:"));
|
|
1019
|
+
console.log(chalk.cyan(" frontend:"));
|
|
1020
|
+
console.log(chalk.cyan(" path: ./frontend"));
|
|
1021
|
+
console.log(chalk.cyan(" git: true # if it has its own .git"));
|
|
1022
|
+
console.log(chalk.cyan(" backend:"));
|
|
1023
|
+
console.log(chalk.cyan(" path: ./backend"));
|
|
1024
|
+
console.log(chalk.cyan(" git: true"));
|
|
1025
|
+
return;
|
|
1026
|
+
}
|
|
1027
|
+
if (detected && detected.length > 0) {
|
|
1028
|
+
let enableMonorepo = false;
|
|
1029
|
+
if (options.monorepo === true || options.yes) {
|
|
1030
|
+
enableMonorepo = true;
|
|
1031
|
+
}
|
|
1032
|
+
else {
|
|
1033
|
+
// Show detected packages and ask
|
|
1034
|
+
console.log(chalk.blue("\n🔍 Detected monorepo packages:"));
|
|
1035
|
+
for (const pkg of detected) {
|
|
1036
|
+
const tag = pkg.isSubmodule
|
|
1037
|
+
? chalk.gray(" (submodule)")
|
|
1038
|
+
: pkg.isGitRepo
|
|
1039
|
+
? chalk.gray(" (git repo)")
|
|
1040
|
+
: "";
|
|
1041
|
+
console.log(chalk.gray(` - ${pkg.name}`) +
|
|
1042
|
+
chalk.gray(` (${pkg.path})`) +
|
|
1043
|
+
chalk.gray(` [${pkg.type}]`) +
|
|
1044
|
+
tag);
|
|
1045
|
+
}
|
|
1046
|
+
console.log("");
|
|
1047
|
+
const { useMonorepo } = await inquirer.prompt([
|
|
1048
|
+
{
|
|
1049
|
+
type: "confirm",
|
|
1050
|
+
name: "useMonorepo",
|
|
1051
|
+
message: "Enable monorepo mode?",
|
|
1052
|
+
default: true,
|
|
1053
|
+
},
|
|
1054
|
+
]);
|
|
1055
|
+
enableMonorepo = useMonorepo;
|
|
1056
|
+
}
|
|
1057
|
+
if (enableMonorepo) {
|
|
1058
|
+
monorepoPackages = detected;
|
|
1059
|
+
remoteSpecPackages = new Set();
|
|
1060
|
+
// Per-package template selection (unless -y mode: all use blank spec)
|
|
1061
|
+
if (!options.yes && !options.template) {
|
|
1062
|
+
for (const pkg of detected) {
|
|
1063
|
+
const { specSource } = await inquirer.prompt([
|
|
1064
|
+
{
|
|
1065
|
+
type: "list",
|
|
1066
|
+
name: "specSource",
|
|
1067
|
+
message: `Spec source for ${pkg.name} (${pkg.path}):`,
|
|
1068
|
+
choices: [
|
|
1069
|
+
{ name: "From scratch (Pactile default)", value: "blank" },
|
|
1070
|
+
{ name: "Download remote template", value: "remote" },
|
|
1071
|
+
],
|
|
1072
|
+
default: "blank",
|
|
1073
|
+
},
|
|
1074
|
+
]);
|
|
1075
|
+
if (specSource === "remote") {
|
|
1076
|
+
// Use existing template download flow, targeting spec/<name>/
|
|
1077
|
+
const destDir = path.join(cwd, PATHS.SPEC, sanitizePkgName(pkg.name));
|
|
1078
|
+
console.log(chalk.blue(`📦 Select template for ${pkg.name}...`));
|
|
1079
|
+
// Fetch templates if not already done
|
|
1080
|
+
const templates = await fetchTemplateIndex();
|
|
1081
|
+
const specTemplates = templates
|
|
1082
|
+
.filter((t) => t.type === "spec")
|
|
1083
|
+
.map((t) => ({
|
|
1084
|
+
name: `${t.id} (${t.name})`,
|
|
1085
|
+
value: t.id,
|
|
1086
|
+
}));
|
|
1087
|
+
if (specTemplates.length > 0) {
|
|
1088
|
+
const { templateId } = await inquirer.prompt([
|
|
1089
|
+
{
|
|
1090
|
+
type: "list",
|
|
1091
|
+
name: "templateId",
|
|
1092
|
+
message: `Select template for ${pkg.name}:`,
|
|
1093
|
+
choices: specTemplates,
|
|
1094
|
+
},
|
|
1095
|
+
]);
|
|
1096
|
+
const result = await downloadTemplateById(cwd, templateId, templateStrategy, templates.find((t) => t.id === templateId), undefined, destDir);
|
|
1097
|
+
if (result.success) {
|
|
1098
|
+
console.log(chalk.green(` ${result.message}`));
|
|
1099
|
+
remoteSpecPackages.add(sanitizePkgName(pkg.name));
|
|
1100
|
+
}
|
|
1101
|
+
else {
|
|
1102
|
+
console.log(chalk.yellow(` ${result.message}`));
|
|
1103
|
+
console.log(chalk.gray(" Falling back to blank spec..."));
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
else {
|
|
1107
|
+
console.log(chalk.gray(" No templates available. Using blank spec."));
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
else if (options.template) {
|
|
1113
|
+
// --template as default for all packages
|
|
1114
|
+
for (const pkg of detected) {
|
|
1115
|
+
const destDir = path.join(cwd, PATHS.SPEC, sanitizePkgName(pkg.name));
|
|
1116
|
+
const result = await downloadTemplateById(cwd, options.template, templateStrategy, undefined, registry, destDir);
|
|
1117
|
+
if (result.success && !result.skipped) {
|
|
1118
|
+
remoteSpecPackages.add(sanitizePkgName(pkg.name));
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
// Tool definitions derived from the canonical host registry.
|
|
1126
|
+
const TOOLS = getPactileInitToolChoices();
|
|
1127
|
+
// Build tools from explicit flags
|
|
1128
|
+
const explicitTools = TOOLS.filter((t) => options[t.key]).map((t) => t.key);
|
|
1129
|
+
let tools;
|
|
1130
|
+
if (explicitTools.length > 0) {
|
|
1131
|
+
// Explicit flags take precedence (works with or without -y)
|
|
1132
|
+
tools = explicitTools;
|
|
1133
|
+
}
|
|
1134
|
+
else if (options.yes) {
|
|
1135
|
+
// No explicit tools + -y: default to Cursor and Codex
|
|
1136
|
+
tools = TOOLS.filter((t) => t.defaultChecked).map((t) => t.key);
|
|
1137
|
+
}
|
|
1138
|
+
else {
|
|
1139
|
+
// Interactive mode
|
|
1140
|
+
const answers = await inquirer.prompt([
|
|
1141
|
+
{
|
|
1142
|
+
type: "checkbox",
|
|
1143
|
+
name: "tools",
|
|
1144
|
+
message: "Select AI tools to configure:",
|
|
1145
|
+
choices: TOOLS.map((t) => ({
|
|
1146
|
+
name: t.name,
|
|
1147
|
+
value: t.key,
|
|
1148
|
+
checked: t.defaultChecked,
|
|
1149
|
+
})),
|
|
1150
|
+
},
|
|
1151
|
+
]);
|
|
1152
|
+
tools = answers.tools;
|
|
1153
|
+
}
|
|
1154
|
+
// Treat unknown project type as fullstack
|
|
1155
|
+
const projectType = detectedType === "unknown" ? "fullstack" : detectedType;
|
|
1156
|
+
if (tools.length === 0) {
|
|
1157
|
+
console.log(chalk.yellow("No tools selected. At least one tool is required."));
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
const explicitCapabilities = parseProjectCapabilities(options.capability);
|
|
1161
|
+
let selectedCapabilities = explicitCapabilities;
|
|
1162
|
+
if (!options.yes && !options.capability?.length) {
|
|
1163
|
+
const capabilityAnswers = await inquirer.prompt([
|
|
1164
|
+
{
|
|
1165
|
+
type: "checkbox",
|
|
1166
|
+
name: "capabilities",
|
|
1167
|
+
message: "Select optional project capabilities:",
|
|
1168
|
+
choices: getProjectCapabilityChoices().map((choice) => ({
|
|
1169
|
+
name: choice.name,
|
|
1170
|
+
value: choice.id,
|
|
1171
|
+
checked: false,
|
|
1172
|
+
})),
|
|
1173
|
+
},
|
|
1174
|
+
]);
|
|
1175
|
+
selectedCapabilities = capabilityAnswers.capabilities ?? [];
|
|
1176
|
+
}
|
|
1177
|
+
reportInitReadiness(snapshotReadinessForRollout({
|
|
1178
|
+
cwd,
|
|
1179
|
+
selected: selectedCapabilities,
|
|
1180
|
+
skipReadiness: options.skipReadiness,
|
|
1181
|
+
}));
|
|
1182
|
+
// ==========================================================================
|
|
1183
|
+
// Template Selection (single-repo only; monorepo handles templates above)
|
|
1184
|
+
// ==========================================================================
|
|
1185
|
+
let selectedTemplate = null;
|
|
1186
|
+
// Pre-fetched templates list (used to pass selected SpecTemplate to downloadTemplateById)
|
|
1187
|
+
let fetchedTemplates = [];
|
|
1188
|
+
let registryBackend;
|
|
1189
|
+
// Determine the index URL based on registry
|
|
1190
|
+
const indexUrl = registry
|
|
1191
|
+
? `${registry.rawBaseUrl}/index.json`
|
|
1192
|
+
: TEMPLATE_INDEX_URL;
|
|
1193
|
+
if (monorepoPackages) {
|
|
1194
|
+
// Monorepo: template selection already handled above
|
|
1195
|
+
}
|
|
1196
|
+
else if (options.template) {
|
|
1197
|
+
// Template specified via --template flag
|
|
1198
|
+
selectedTemplate = options.template;
|
|
1199
|
+
}
|
|
1200
|
+
else if (!options.yes) {
|
|
1201
|
+
// Interactive mode: show template selection
|
|
1202
|
+
const timeoutSec = TIMEOUTS.INDEX_FETCH_MS / 1000;
|
|
1203
|
+
const sourceLabel = registry ? registry.gigetSource : TEMPLATE_INDEX_URL;
|
|
1204
|
+
console.log(chalk.gray(` Fetching available templates from ${sourceLabel}`));
|
|
1205
|
+
let elapsed = 0;
|
|
1206
|
+
const ticker = setInterval(() => {
|
|
1207
|
+
elapsed++;
|
|
1208
|
+
process.stdout.write(`\r${chalk.gray(` Loading... ${elapsed}s/${timeoutSec}s`)}`);
|
|
1209
|
+
}, 1000);
|
|
1210
|
+
process.stdout.write(chalk.gray(` Loading... 0s/${timeoutSec}s`));
|
|
1211
|
+
let templates;
|
|
1212
|
+
let registryProbeNotFound = false;
|
|
1213
|
+
let registryProbeError;
|
|
1214
|
+
if (registry) {
|
|
1215
|
+
const probeResult = await probeRegistryIndex(indexUrl, registry);
|
|
1216
|
+
templates = probeResult.templates;
|
|
1217
|
+
registryProbeNotFound = probeResult.isNotFound;
|
|
1218
|
+
registryProbeError = probeResult.error;
|
|
1219
|
+
registryBackend = probeResult.backend;
|
|
1220
|
+
}
|
|
1221
|
+
else {
|
|
1222
|
+
templates = await fetchTemplateIndex(indexUrl);
|
|
1223
|
+
}
|
|
1224
|
+
clearInterval(ticker);
|
|
1225
|
+
// Clear the loading line
|
|
1226
|
+
process.stdout.write("\r\x1b[2K");
|
|
1227
|
+
fetchedTemplates = templates;
|
|
1228
|
+
if (templates.length === 0 && registry && registryProbeNotFound) {
|
|
1229
|
+
// Custom registry: confirmed no index.json — will try direct download later
|
|
1230
|
+
console.log(chalk.gray(" No index.json found at registry. Will download as direct spec template."));
|
|
1231
|
+
}
|
|
1232
|
+
else if (templates.length === 0 && registry) {
|
|
1233
|
+
// Custom registry: transient error (not a 404) — abort, don't misclassify
|
|
1234
|
+
console.log(chalk.red(` ${registryProbeError?.message ?? "Could not reach registry. Check your connection and try again."}`));
|
|
1235
|
+
return;
|
|
1236
|
+
}
|
|
1237
|
+
else if (templates.length === 0) {
|
|
1238
|
+
console.log(chalk.gray(" Could not fetch templates (offline or server unavailable)."));
|
|
1239
|
+
console.log(chalk.gray(" Using blank templates.\n"));
|
|
1240
|
+
}
|
|
1241
|
+
if (templates.length > 0) {
|
|
1242
|
+
// Build template choices
|
|
1243
|
+
const specTemplates = templates
|
|
1244
|
+
.filter((t) => t.type === "spec")
|
|
1245
|
+
.map((t) => ({
|
|
1246
|
+
name: `${t.id} (${t.name})`,
|
|
1247
|
+
value: t.id,
|
|
1248
|
+
}));
|
|
1249
|
+
const templateChoices = registry
|
|
1250
|
+
? specTemplates
|
|
1251
|
+
: [
|
|
1252
|
+
{
|
|
1253
|
+
name: "from scratch (default)",
|
|
1254
|
+
value: "blank",
|
|
1255
|
+
},
|
|
1256
|
+
...specTemplates,
|
|
1257
|
+
{
|
|
1258
|
+
name: "custom (enter a registry source)",
|
|
1259
|
+
value: "__custom__",
|
|
1260
|
+
},
|
|
1261
|
+
];
|
|
1262
|
+
// Loop to allow returning from custom source input back to the picker
|
|
1263
|
+
let templatePicked = false;
|
|
1264
|
+
while (templateChoices.length > 0 && !templatePicked) {
|
|
1265
|
+
const templateAnswer = await inquirer.prompt([
|
|
1266
|
+
{
|
|
1267
|
+
type: "list",
|
|
1268
|
+
name: "template",
|
|
1269
|
+
message: "Select a spec template:",
|
|
1270
|
+
choices: templateChoices,
|
|
1271
|
+
default: registry ? undefined : "blank",
|
|
1272
|
+
},
|
|
1273
|
+
]);
|
|
1274
|
+
if (templateAnswer.template === "__custom__") {
|
|
1275
|
+
// Prompt for custom registry source (empty → back to picker)
|
|
1276
|
+
const customSource = await askInput("Enter registry source (e.g., gh:myorg/myrepo/specs), or press Enter to go back: ");
|
|
1277
|
+
if (!customSource) {
|
|
1278
|
+
continue; // Back to picker
|
|
1279
|
+
}
|
|
1280
|
+
try {
|
|
1281
|
+
registry = parseRegistrySource(customSource);
|
|
1282
|
+
fetchedTemplates = []; // Reset so direct-download guard works correctly
|
|
1283
|
+
// Probe index.json to detect marketplace vs direct download
|
|
1284
|
+
const customIndexUrl = `${registry.rawBaseUrl}/index.json`;
|
|
1285
|
+
console.log(chalk.gray(` Checking for templates at ${registry.gigetSource}...`));
|
|
1286
|
+
const customProbe = await probeRegistryIndex(customIndexUrl, registry);
|
|
1287
|
+
const customTemplates = customProbe.templates;
|
|
1288
|
+
registryBackend = customProbe.backend;
|
|
1289
|
+
if (customTemplates.length > 0) {
|
|
1290
|
+
// Marketplace mode: show picker with custom templates
|
|
1291
|
+
fetchedTemplates = customTemplates;
|
|
1292
|
+
const customChoices = customTemplates
|
|
1293
|
+
.filter((t) => t.type === "spec")
|
|
1294
|
+
.map((t) => ({
|
|
1295
|
+
name: `${t.id} (${t.name})`,
|
|
1296
|
+
value: t.id,
|
|
1297
|
+
}));
|
|
1298
|
+
if (customChoices.length > 0) {
|
|
1299
|
+
const customAnswer = await inquirer.prompt([
|
|
1300
|
+
{
|
|
1301
|
+
type: "list",
|
|
1302
|
+
name: "template",
|
|
1303
|
+
message: "Select a spec template:",
|
|
1304
|
+
choices: customChoices,
|
|
1305
|
+
},
|
|
1306
|
+
]);
|
|
1307
|
+
selectedTemplate = customAnswer.template;
|
|
1308
|
+
// Check if spec directory already exists and ask what to do
|
|
1309
|
+
const specDir = path.join(cwd, PATHS.SPEC);
|
|
1310
|
+
if (fs.existsSync(specDir) &&
|
|
1311
|
+
!options.overwrite &&
|
|
1312
|
+
!options.append) {
|
|
1313
|
+
const actionAnswer = await inquirer.prompt([
|
|
1314
|
+
{
|
|
1315
|
+
type: "list",
|
|
1316
|
+
name: "action",
|
|
1317
|
+
message: `Directory ${PATHS.SPEC} already exists. What do you want to do?`,
|
|
1318
|
+
choices: [
|
|
1319
|
+
{ name: "Skip (keep existing)", value: "skip" },
|
|
1320
|
+
{
|
|
1321
|
+
name: "Overwrite (replace all)",
|
|
1322
|
+
value: "overwrite",
|
|
1323
|
+
},
|
|
1324
|
+
{
|
|
1325
|
+
name: "Append (add missing files only)",
|
|
1326
|
+
value: "append",
|
|
1327
|
+
},
|
|
1328
|
+
],
|
|
1329
|
+
default: "skip",
|
|
1330
|
+
},
|
|
1331
|
+
]);
|
|
1332
|
+
templateStrategy = actionAnswer.action;
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
templatePicked = true;
|
|
1336
|
+
}
|
|
1337
|
+
else if (customProbe.isNotFound) {
|
|
1338
|
+
// No index.json → direct download mode
|
|
1339
|
+
templatePicked = true;
|
|
1340
|
+
}
|
|
1341
|
+
else {
|
|
1342
|
+
// Transient error (not 404) — loop back, don't misclassify
|
|
1343
|
+
console.log(chalk.yellow(` ${customProbe.error?.message ?? "Could not reach registry. Try again or enter a different source."}`));
|
|
1344
|
+
registry = undefined; // Reset so we don't fall through to direct download
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
catch (error) {
|
|
1348
|
+
console.log(chalk.red(error instanceof Error
|
|
1349
|
+
? error.message
|
|
1350
|
+
: "Invalid registry source"));
|
|
1351
|
+
// Loop back to picker
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
else {
|
|
1355
|
+
templatePicked = true;
|
|
1356
|
+
if (templateAnswer.template !== "blank") {
|
|
1357
|
+
selectedTemplate = templateAnswer.template;
|
|
1358
|
+
// Check if spec directory already exists and ask what to do
|
|
1359
|
+
const specDir = path.join(cwd, PATHS.SPEC);
|
|
1360
|
+
if (fs.existsSync(specDir) &&
|
|
1361
|
+
!options.overwrite &&
|
|
1362
|
+
!options.append) {
|
|
1363
|
+
const actionAnswer = await inquirer.prompt([
|
|
1364
|
+
{
|
|
1365
|
+
type: "list",
|
|
1366
|
+
name: "action",
|
|
1367
|
+
message: `Directory ${PATHS.SPEC} already exists. What do you want to do?`,
|
|
1368
|
+
choices: [
|
|
1369
|
+
{ name: "Skip (keep existing)", value: "skip" },
|
|
1370
|
+
{ name: "Overwrite (replace all)", value: "overwrite" },
|
|
1371
|
+
{
|
|
1372
|
+
name: "Append (add missing files only)",
|
|
1373
|
+
value: "append",
|
|
1374
|
+
},
|
|
1375
|
+
],
|
|
1376
|
+
default: "skip",
|
|
1377
|
+
},
|
|
1378
|
+
]);
|
|
1379
|
+
templateStrategy = actionAnswer.action;
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
// -y mode with --registry (no --template): probe index.json to detect mode
|
|
1387
|
+
// Skip when monorepo mode already handled templates above
|
|
1388
|
+
if (options.yes && registry && !selectedTemplate && !monorepoPackages) {
|
|
1389
|
+
const probeResult = await probeRegistryIndex(`${registry.rawBaseUrl}/index.json`, registry);
|
|
1390
|
+
registryBackend = probeResult.backend;
|
|
1391
|
+
if (probeResult.templates.length > 0) {
|
|
1392
|
+
// Marketplace mode requires interactive selection — can't auto-select
|
|
1393
|
+
console.log(chalk.red("Error: Registry is a marketplace with multiple templates. " +
|
|
1394
|
+
"Use --template <id> to specify which one, or remove -y for interactive selection."));
|
|
1395
|
+
return;
|
|
1396
|
+
}
|
|
1397
|
+
if (!probeResult.isNotFound) {
|
|
1398
|
+
// Transient error (not 404) — abort, don't misclassify as direct-download
|
|
1399
|
+
console.log(chalk.red(`Error: ${probeResult.error?.message ?? "Could not reach registry. Check your connection and try again."}`));
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1402
|
+
// isNotFound=true → no index.json, proceed with direct download (fetchedTemplates stays empty)
|
|
1403
|
+
}
|
|
1404
|
+
// ==========================================================================
|
|
1405
|
+
// Download Remote Template (if selected or direct registry download)
|
|
1406
|
+
// ==========================================================================
|
|
1407
|
+
let useRemoteTemplate = false;
|
|
1408
|
+
if (selectedTemplate) {
|
|
1409
|
+
// Marketplace mode: download specific template by ID
|
|
1410
|
+
console.log(chalk.blue(`📦 Downloading template "${selectedTemplate}"...`));
|
|
1411
|
+
console.log(chalk.gray(" This may take a moment on slow connections."));
|
|
1412
|
+
// Find pre-fetched SpecTemplate to avoid double-fetch
|
|
1413
|
+
const prefetched = fetchedTemplates.find((t) => t.id === selectedTemplate);
|
|
1414
|
+
const result = await downloadTemplateById(cwd, selectedTemplate, templateStrategy, prefetched, registry, undefined, registryBackend);
|
|
1415
|
+
if (result.success) {
|
|
1416
|
+
if (result.skipped) {
|
|
1417
|
+
console.log(chalk.gray(` ${result.message}`));
|
|
1418
|
+
}
|
|
1419
|
+
else {
|
|
1420
|
+
console.log(chalk.green(` ${result.message}`));
|
|
1421
|
+
useRemoteTemplate = true;
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
else {
|
|
1425
|
+
console.log(chalk.yellow(` ${result.message}`));
|
|
1426
|
+
console.log(chalk.gray(" Falling back to blank templates..."));
|
|
1427
|
+
const retryCmd = registry
|
|
1428
|
+
? `pactile init --registry ${registry.gigetSource} --template ${selectedTemplate}`
|
|
1429
|
+
: `pactile init --template ${selectedTemplate}`;
|
|
1430
|
+
console.log(chalk.gray(` You can retry later: ${retryCmd}`));
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
else if (registry && fetchedTemplates.length === 0) {
|
|
1434
|
+
// Direct download mode: registry has no index.json, download directory directly
|
|
1435
|
+
console.log(chalk.blue(`📦 Downloading spec from ${registry.gigetSource}...`));
|
|
1436
|
+
console.log(chalk.gray(" This may take a moment on slow connections."));
|
|
1437
|
+
// Ask about existing spec dir in interactive mode
|
|
1438
|
+
if (!options.yes && !options.overwrite && !options.append) {
|
|
1439
|
+
const specDir = path.join(cwd, PATHS.SPEC);
|
|
1440
|
+
if (fs.existsSync(specDir)) {
|
|
1441
|
+
const actionAnswer = await inquirer.prompt([
|
|
1442
|
+
{
|
|
1443
|
+
type: "list",
|
|
1444
|
+
name: "action",
|
|
1445
|
+
message: `Directory ${PATHS.SPEC} already exists. What do you want to do?`,
|
|
1446
|
+
choices: [
|
|
1447
|
+
{ name: "Skip (keep existing)", value: "skip" },
|
|
1448
|
+
{ name: "Overwrite (replace all)", value: "overwrite" },
|
|
1449
|
+
{ name: "Append (add missing files only)", value: "append" },
|
|
1450
|
+
],
|
|
1451
|
+
default: "skip",
|
|
1452
|
+
},
|
|
1453
|
+
]);
|
|
1454
|
+
templateStrategy = actionAnswer.action;
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
const result = await downloadRegistryDirect(cwd, registry, templateStrategy, undefined, registryBackend);
|
|
1458
|
+
if (result.success) {
|
|
1459
|
+
if (result.skipped) {
|
|
1460
|
+
console.log(chalk.gray(` ${result.message}`));
|
|
1461
|
+
}
|
|
1462
|
+
else {
|
|
1463
|
+
console.log(chalk.green(` ${result.message}`));
|
|
1464
|
+
useRemoteTemplate = true;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
else {
|
|
1468
|
+
console.log(chalk.yellow(` ${result.message}`));
|
|
1469
|
+
console.log(chalk.gray(" Falling back to blank templates..."));
|
|
1470
|
+
console.log(chalk.gray(` You can retry later: pactile init --registry ${registry.gigetSource}`));
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
// ==========================================================================
|
|
1474
|
+
// Resolve workflow template (default: native bundled)
|
|
1475
|
+
// ==========================================================================
|
|
1476
|
+
const workflowIdInput = options.workflow?.trim();
|
|
1477
|
+
const workflowId = workflowIdInput && workflowIdInput.length > 0
|
|
1478
|
+
? workflowIdInput
|
|
1479
|
+
: NATIVE_WORKFLOW_ID;
|
|
1480
|
+
let workflowMdOverride;
|
|
1481
|
+
if (workflowId !== NATIVE_WORKFLOW_ID || options.workflowSource) {
|
|
1482
|
+
const resolved = await resolveWorkflowTemplate(workflowId, {
|
|
1483
|
+
source: options.workflowSource,
|
|
1484
|
+
});
|
|
1485
|
+
if (resolved.id !== NATIVE_WORKFLOW_ID) {
|
|
1486
|
+
workflowMdOverride = resolved.content;
|
|
1487
|
+
console.log(chalk.blue(`🧭 Using workflow template: ${chalk.cyan(resolved.id)}`));
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
// ==========================================================================
|
|
1491
|
+
// Create Workflow Structure
|
|
1492
|
+
// ==========================================================================
|
|
1493
|
+
// Build the complete canonical candidate away from the live project. The
|
|
1494
|
+
// lifecycle seals and commits these bytes before the callback publishes the
|
|
1495
|
+
// live `.pactile` view; failed planning/staging/validation leaves live
|
|
1496
|
+
// canonical files untouched and the legacy source remains read-only.
|
|
1497
|
+
const buildRoot = fs.mkdtempSync(path.join(os.tmpdir(), "pactile-init-"));
|
|
1498
|
+
try {
|
|
1499
|
+
let importedFileCount = 0;
|
|
1500
|
+
if (importingCstl) {
|
|
1501
|
+
importedFileCount = prepareLegacyCstlImport(cwd, buildRoot).length;
|
|
1502
|
+
}
|
|
1503
|
+
else if (!isFirstInit) {
|
|
1504
|
+
seedCanonicalBuildRoot(cwd, buildRoot);
|
|
1505
|
+
}
|
|
1506
|
+
// Record every successful canonical/root write from this section. The
|
|
1507
|
+
// captured set is the source of truth for `.template-hashes.json`'s
|
|
1508
|
+
// platform/root entries — replacing the previous "walk every managed dir"
|
|
1509
|
+
// approach that swept user-owned runtime files into the manifest.
|
|
1510
|
+
const writtenPaths = startRecordingWrites(buildRoot);
|
|
1511
|
+
try {
|
|
1512
|
+
console.log(chalk.blue("📁 Creating workflow structure..."));
|
|
1513
|
+
await createWorkflowStructure(buildRoot, {
|
|
1514
|
+
projectType,
|
|
1515
|
+
skipSpecTemplates: useRemoteTemplate,
|
|
1516
|
+
packages: monorepoPackages,
|
|
1517
|
+
remoteSpecPackages,
|
|
1518
|
+
workflowMdOverride,
|
|
1519
|
+
});
|
|
1520
|
+
if (monorepoPackages) {
|
|
1521
|
+
writeMonorepoConfig(buildRoot, monorepoPackages);
|
|
1522
|
+
console.log(chalk.blue("📦 Monorepo packages written to config.yaml"));
|
|
1523
|
+
}
|
|
1524
|
+
fs.writeFileSync(path.join(buildRoot, DIR_NAMES.WORKFLOW, ".version"), VERSION);
|
|
1525
|
+
await writeProjectCapabilityFiles(buildRoot, selectedCapabilities, []);
|
|
1526
|
+
}
|
|
1527
|
+
finally {
|
|
1528
|
+
stopRecordingWrites();
|
|
1529
|
+
}
|
|
1530
|
+
const hashedCount = initializeHashes(buildRoot, {
|
|
1531
|
+
trackedPaths: writtenPaths,
|
|
1532
|
+
merge: !isFirstInit,
|
|
1533
|
+
});
|
|
1534
|
+
if (hashedCount > 0) {
|
|
1535
|
+
console.log(chalk.gray(`📋 Tracking ${hashedCount} template files for updates`));
|
|
1536
|
+
}
|
|
1537
|
+
if (workflowMdOverride !== undefined && workflowId !== NATIVE_WORKFLOW_ID) {
|
|
1538
|
+
removeHash(buildRoot, PATHS.WORKFLOW_GUIDE_FILE);
|
|
1539
|
+
}
|
|
1540
|
+
const selectedPlatformIds = tools
|
|
1541
|
+
.map((tool) => TOOLS.find((choice) => choice.key === tool)?.platformId)
|
|
1542
|
+
.filter((platform) => platform !== undefined);
|
|
1543
|
+
const candidateFiles = collectCanonicalGenerationFiles(buildRoot, discoverCanonicalGenerationPaths(buildRoot), selectedPlatformIds, VERSION);
|
|
1544
|
+
const legacyLifecycleFiles = importingCstl
|
|
1545
|
+
? collectLegacyCstlLifecycleFiles(cwd, buildRoot, candidateFiles)
|
|
1546
|
+
: null;
|
|
1547
|
+
const canonicalLifecycleOperation = new InstallStateStore(cwd).read()
|
|
1548
|
+
? "update"
|
|
1549
|
+
: "init";
|
|
1550
|
+
const lifecycleResult = await runLifecycleCommand({
|
|
1551
|
+
projectRoot: cwd,
|
|
1552
|
+
operation: importingCstl ? "import" : canonicalLifecycleOperation,
|
|
1553
|
+
runtimeVersion: VERSION,
|
|
1554
|
+
files: importingCstl ? (legacyLifecycleFiles ?? []) : candidateFiles,
|
|
1555
|
+
platforms: selectedPlatformIds,
|
|
1556
|
+
materializeCanonical: (context) => materializeCanonicalGeneration(cwd, context),
|
|
1557
|
+
...(importingCstl
|
|
1558
|
+
? {
|
|
1559
|
+
legacy: {
|
|
1560
|
+
runtimeVersion: readLegacyCstlVersion(cwd),
|
|
1561
|
+
schemaVersion: null,
|
|
1562
|
+
files: legacyLifecycleFiles ?? [],
|
|
1563
|
+
},
|
|
1564
|
+
}
|
|
1565
|
+
: {}),
|
|
1566
|
+
});
|
|
1567
|
+
reportLifecycleResult(lifecycleResult, importingCstl
|
|
1568
|
+
? "Legacy import and Adapter reconcile"
|
|
1569
|
+
: canonicalLifecycleOperation === "update"
|
|
1570
|
+
? "Pactile re-initialize"
|
|
1571
|
+
: "Pactile init");
|
|
1572
|
+
if (importingCstl || isFirstInit) {
|
|
1573
|
+
// User-owned namespaces are intentionally excluded from the immutable
|
|
1574
|
+
// generation. Publish the freshly prepared workspace/spec skeleton (and
|
|
1575
|
+
// any imported state) only after canonical activation succeeds.
|
|
1576
|
+
materializePreparedLegacyUserState(buildRoot, cwd);
|
|
1577
|
+
if (isFirstInit && !importingCstl) {
|
|
1578
|
+
// A fresh init may have no developer name yet, so its empty tasks/
|
|
1579
|
+
// directory has no file for the state publisher to copy.
|
|
1580
|
+
for (const relativePath of [PATHS.WORKSPACE, PATHS.TASKS, PATHS.SPEC]) {
|
|
1581
|
+
fs.mkdirSync(path.join(cwd, relativePath), { recursive: true });
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
if (importingCstl) {
|
|
1586
|
+
console.log(chalk.cyan(legacyImportPreparedMessage(importedFileCount)));
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
finally {
|
|
1590
|
+
fs.rmSync(buildRoot, { recursive: true, force: true });
|
|
1591
|
+
}
|
|
1592
|
+
if (isFirstInit && !importingCstl) {
|
|
1593
|
+
// A fresh canonical install cannot contain the retired task shape. Mark
|
|
1594
|
+
// that fact once so the first `pactile update` does not manufacture a
|
|
1595
|
+
// migration backup or prompt for a legacy transition that never existed.
|
|
1596
|
+
writeWaveCConfirmed(cwd);
|
|
1597
|
+
}
|
|
1598
|
+
// Initialize developer identity (silent - no output)
|
|
1599
|
+
if (developerName) {
|
|
1600
|
+
try {
|
|
1601
|
+
const scriptPath = path.join(cwd, PATHS.SCRIPTS, "init_developer.py");
|
|
1602
|
+
execSync(`${pythonCmd} "${scriptPath}" "${developerName}"`, {
|
|
1603
|
+
cwd,
|
|
1604
|
+
stdio: "pipe", // Silent
|
|
1605
|
+
});
|
|
1606
|
+
}
|
|
1607
|
+
catch {
|
|
1608
|
+
// Silent failure - user can run init_developer.py manually
|
|
1609
|
+
}
|
|
1610
|
+
// Three-branch dispatch using flags captured at init() start (before
|
|
1611
|
+
// createWorkflowStructure/init_developer ran, so they reflect the disk
|
|
1612
|
+
// state of the user's checkout, not the state this init just produced):
|
|
1613
|
+
// isFirstInit=true → creator bootstrap (new project)
|
|
1614
|
+
// isFirstInit=false + no .developer file → joiner onboarding (fresh clone)
|
|
1615
|
+
// isFirstInit=false + .developer exists → same-dev re-init, no task
|
|
1616
|
+
//
|
|
1617
|
+
// Tasks-empty fallback (issue #204): if .pactile/ exists but tasks dir is
|
|
1618
|
+
// empty, the previous init aborted before creating the bootstrap task. Run
|
|
1619
|
+
// bootstrap creation regardless of isFirstInit. writeTaskSkeleton is
|
|
1620
|
+
// idempotent so repeated triggers are safe.
|
|
1621
|
+
//
|
|
1622
|
+
// Runs OUTSIDE the init_developer try/catch (which uses stdio: "pipe")
|
|
1623
|
+
// so joiner failures surface as warnings instead of being silently
|
|
1624
|
+
// swallowed.
|
|
1625
|
+
const tasksDir = path.join(cwd, PATHS.TASKS);
|
|
1626
|
+
const tasksEmpty = !fs.existsSync(tasksDir) || fs.readdirSync(tasksDir).length === 0;
|
|
1627
|
+
if ((isFirstInit && !importingCstl) || tasksEmpty) {
|
|
1628
|
+
const bootstrapCreated = createBootstrapTask(cwd, developerName, pythonCmd, projectType, selectedCapabilities, monorepoPackages);
|
|
1629
|
+
if (bootstrapCreated) {
|
|
1630
|
+
console.log(chalk.gray(`Next: complete ${BOOTSTRAP_TASK_NAME} to verify selected capabilities and fill the project spec.`));
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
else if (!hadDeveloperFileAtStart) {
|
|
1634
|
+
try {
|
|
1635
|
+
if (!createJoinerOnboardingTask(cwd, developerName, pythonCmd)) {
|
|
1636
|
+
console.warn(chalk.yellow("⚠ Failed to create joiner onboarding task"));
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
catch (err) {
|
|
1640
|
+
console.warn(chalk.yellow(`⚠ Joiner onboarding setup failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
/**
|
|
1646
|
+
* Simple readline-based input (no flickering like inquirer)
|
|
1647
|
+
*/
|
|
1648
|
+
function askInput(prompt) {
|
|
1649
|
+
const rl = readline.createInterface({
|
|
1650
|
+
input: process.stdin,
|
|
1651
|
+
output: process.stdout,
|
|
1652
|
+
});
|
|
1653
|
+
return new Promise((resolve) => {
|
|
1654
|
+
rl.question(prompt, (answer) => {
|
|
1655
|
+
rl.close();
|
|
1656
|
+
resolve(answer.trim());
|
|
1657
|
+
});
|
|
1658
|
+
});
|
|
1659
|
+
}
|
|
1660
|
+
//# sourceMappingURL=init.js.map
|