@kynetic-ai/spec 0.1.2 → 0.4.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/README.md +250 -17
- package/dist/acp/client.d.ts +18 -4
- package/dist/acp/client.d.ts.map +1 -1
- package/dist/acp/client.js +44 -26
- package/dist/acp/client.js.map +1 -1
- package/dist/acp/framing.d.ts +2 -2
- package/dist/acp/framing.d.ts.map +1 -1
- package/dist/acp/framing.js +37 -29
- package/dist/acp/framing.js.map +1 -1
- package/dist/acp/index.d.ts +6 -7
- package/dist/acp/index.d.ts.map +1 -1
- package/dist/acp/index.js +3 -3
- package/dist/acp/index.js.map +1 -1
- package/dist/acp/types.d.ts +5 -5
- package/dist/acp/types.d.ts.map +1 -1
- package/dist/acp/types.js +18 -18
- package/dist/acp/types.js.map +1 -1
- package/dist/agents/adapters.d.ts.map +1 -1
- package/dist/agents/adapters.js +24 -13
- package/dist/agents/adapters.js.map +1 -1
- package/dist/agents/index.d.ts +2 -2
- package/dist/agents/index.js +2 -2
- package/dist/agents/spawner.d.ts +4 -4
- package/dist/agents/spawner.d.ts.map +1 -1
- package/dist/agents/spawner.js +6 -6
- package/dist/agents/spawner.js.map +1 -1
- package/dist/cli/batch-context.d.ts +43 -0
- package/dist/cli/batch-context.d.ts.map +1 -0
- package/dist/cli/batch-context.js +93 -0
- package/dist/cli/batch-context.js.map +1 -0
- package/dist/cli/batch-exec.d.ts +107 -0
- package/dist/cli/batch-exec.d.ts.map +1 -0
- package/dist/cli/batch-exec.js +706 -0
- package/dist/cli/batch-exec.js.map +1 -0
- package/dist/cli/batch.d.ts +4 -2
- package/dist/cli/batch.d.ts.map +1 -1
- package/dist/cli/batch.js +15 -14
- package/dist/cli/batch.js.map +1 -1
- package/dist/cli/command-annotations.d.ts +23 -0
- package/dist/cli/command-annotations.d.ts.map +1 -0
- package/dist/cli/command-annotations.js +27 -0
- package/dist/cli/command-annotations.js.map +1 -0
- package/dist/cli/commands/agents.d.ts +46 -0
- package/dist/cli/commands/agents.d.ts.map +1 -0
- package/dist/cli/commands/agents.js +377 -0
- package/dist/cli/commands/agents.js.map +1 -0
- package/dist/cli/commands/batch.d.ts +20 -0
- package/dist/cli/commands/batch.d.ts.map +1 -0
- package/dist/cli/commands/batch.js +214 -0
- package/dist/cli/commands/batch.js.map +1 -0
- package/dist/cli/commands/clone-for-testing.d.ts +1 -1
- package/dist/cli/commands/clone-for-testing.d.ts.map +1 -1
- package/dist/cli/commands/clone-for-testing.js +37 -47
- package/dist/cli/commands/clone-for-testing.js.map +1 -1
- package/dist/cli/commands/derive.d.ts +1 -1
- package/dist/cli/commands/derive.d.ts.map +1 -1
- package/dist/cli/commands/derive.js +141 -88
- package/dist/cli/commands/derive.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts +11 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +152 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/export.d.ts +12 -0
- package/dist/cli/commands/export.d.ts.map +1 -0
- package/dist/cli/commands/export.js +134 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/commands/help.d.ts +1 -1
- package/dist/cli/commands/help.d.ts.map +1 -1
- package/dist/cli/commands/help.js +163 -37
- package/dist/cli/commands/help.js.map +1 -1
- package/dist/cli/commands/inbox.d.ts +1 -1
- package/dist/cli/commands/inbox.d.ts.map +1 -1
- package/dist/cli/commands/inbox.js +178 -56
- package/dist/cli/commands/inbox.js.map +1 -1
- package/dist/cli/commands/index.d.ts +31 -19
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +31 -19
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/init.d.ts +5 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +108 -57
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/item.d.ts +1 -1
- package/dist/cli/commands/item.d.ts.map +1 -1
- package/dist/cli/commands/item.js +557 -274
- package/dist/cli/commands/item.js.map +1 -1
- package/dist/cli/commands/link.d.ts +1 -1
- package/dist/cli/commands/link.d.ts.map +1 -1
- package/dist/cli/commands/link.js +55 -46
- package/dist/cli/commands/link.js.map +1 -1
- package/dist/cli/commands/log.d.ts +1 -1
- package/dist/cli/commands/log.d.ts.map +1 -1
- package/dist/cli/commands/log.js +58 -51
- package/dist/cli/commands/log.js.map +1 -1
- package/dist/cli/commands/merge-driver.d.ts +19 -0
- package/dist/cli/commands/merge-driver.d.ts.map +1 -0
- package/dist/cli/commands/merge-driver.js +398 -0
- package/dist/cli/commands/merge-driver.js.map +1 -0
- package/dist/cli/commands/meta.d.ts +1 -1
- package/dist/cli/commands/meta.d.ts.map +1 -1
- package/dist/cli/commands/meta.js +534 -399
- package/dist/cli/commands/meta.js.map +1 -1
- package/dist/cli/commands/module.d.ts +1 -1
- package/dist/cli/commands/module.d.ts.map +1 -1
- package/dist/cli/commands/module.js +30 -25
- package/dist/cli/commands/module.js.map +1 -1
- package/dist/cli/commands/plan-import.d.ts +11 -0
- package/dist/cli/commands/plan-import.d.ts.map +1 -0
- package/dist/cli/commands/plan-import.js +547 -0
- package/dist/cli/commands/plan-import.js.map +1 -0
- package/dist/cli/commands/plan.d.ts +10 -0
- package/dist/cli/commands/plan.d.ts.map +1 -0
- package/dist/cli/commands/plan.js +421 -0
- package/dist/cli/commands/plan.js.map +1 -0
- package/dist/cli/commands/ralph.d.ts +1 -1
- package/dist/cli/commands/ralph.d.ts.map +1 -1
- package/dist/cli/commands/ralph.js +1109 -170
- package/dist/cli/commands/ralph.js.map +1 -1
- package/dist/cli/commands/refs.d.ts +13 -0
- package/dist/cli/commands/refs.d.ts.map +1 -0
- package/dist/cli/commands/refs.js +283 -0
- package/dist/cli/commands/refs.js.map +1 -0
- package/dist/cli/commands/search.d.ts +1 -1
- package/dist/cli/commands/search.d.ts.map +1 -1
- package/dist/cli/commands/search.js +199 -37
- package/dist/cli/commands/search.js.map +1 -1
- package/dist/cli/commands/serve.d.ts +10 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +491 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/session.d.ts +25 -6
- package/dist/cli/commands/session.d.ts.map +1 -1
- package/dist/cli/commands/session.js +810 -127
- package/dist/cli/commands/session.js.map +1 -1
- package/dist/cli/commands/setup-seeding.d.ts +81 -0
- package/dist/cli/commands/setup-seeding.d.ts.map +1 -0
- package/dist/cli/commands/setup-seeding.js +292 -0
- package/dist/cli/commands/setup-seeding.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +77 -3
- package/dist/cli/commands/setup.d.ts.map +1 -1
- package/dist/cli/commands/setup.js +1267 -274
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/cli/commands/shadow.d.ts +1 -1
- package/dist/cli/commands/shadow.d.ts.map +1 -1
- package/dist/cli/commands/shadow.js +70 -50
- package/dist/cli/commands/shadow.js.map +1 -1
- package/dist/cli/commands/skill-crud.d.ts +58 -0
- package/dist/cli/commands/skill-crud.d.ts.map +1 -0
- package/dist/cli/commands/skill-crud.js +753 -0
- package/dist/cli/commands/skill-crud.js.map +1 -0
- package/dist/cli/commands/skill-diff.d.ts +27 -0
- package/dist/cli/commands/skill-diff.d.ts.map +1 -0
- package/dist/cli/commands/skill-diff.js +840 -0
- package/dist/cli/commands/skill-diff.js.map +1 -0
- package/dist/cli/commands/skill-install.d.ts +56 -0
- package/dist/cli/commands/skill-install.d.ts.map +1 -0
- package/dist/cli/commands/skill-install.js +509 -0
- package/dist/cli/commands/skill-install.js.map +1 -0
- package/dist/cli/commands/skill.d.ts +20 -0
- package/dist/cli/commands/skill.d.ts.map +1 -0
- package/dist/cli/commands/skill.js +36 -0
- package/dist/cli/commands/skill.js.map +1 -0
- package/dist/cli/commands/task.d.ts +1 -1
- package/dist/cli/commands/task.d.ts.map +1 -1
- package/dist/cli/commands/task.js +584 -350
- package/dist/cli/commands/task.js.map +1 -1
- package/dist/cli/commands/tasks.d.ts +26 -1
- package/dist/cli/commands/tasks.d.ts.map +1 -1
- package/dist/cli/commands/tasks.js +225 -122
- package/dist/cli/commands/tasks.js.map +1 -1
- package/dist/cli/commands/trait.d.ts +1 -1
- package/dist/cli/commands/trait.d.ts.map +1 -1
- package/dist/cli/commands/trait.js +166 -101
- package/dist/cli/commands/trait.js.map +1 -1
- package/dist/cli/commands/triage.d.ts +7 -0
- package/dist/cli/commands/triage.d.ts.map +1 -0
- package/dist/cli/commands/triage.js +483 -0
- package/dist/cli/commands/triage.js.map +1 -0
- package/dist/cli/commands/util.d.ts +7 -0
- package/dist/cli/commands/util.d.ts.map +1 -0
- package/dist/cli/commands/util.js +30 -0
- package/dist/cli/commands/util.js.map +1 -0
- package/dist/cli/commands/validate.d.ts +1 -1
- package/dist/cli/commands/validate.d.ts.map +1 -1
- package/dist/cli/commands/validate.js +264 -83
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/commands/workflow.d.ts +16 -0
- package/dist/cli/commands/workflow.d.ts.map +1 -0
- package/dist/cli/commands/workflow.js +851 -0
- package/dist/cli/commands/workflow.js.map +1 -0
- package/dist/cli/exit-codes.d.ts +7 -0
- package/dist/cli/exit-codes.d.ts.map +1 -1
- package/dist/cli/exit-codes.js +26 -18
- package/dist/cli/exit-codes.js.map +1 -1
- package/dist/cli/help/content.d.ts.map +1 -1
- package/dist/cli/help/content.js +86 -71
- package/dist/cli/help/content.js.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +131 -19
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/introspection.d.ts +6 -2
- package/dist/cli/introspection.d.ts.map +1 -1
- package/dist/cli/introspection.js +11 -8
- package/dist/cli/introspection.js.map +1 -1
- package/dist/cli/output.d.ts +64 -4
- package/dist/cli/output.d.ts.map +1 -1
- package/dist/cli/output.js +237 -85
- package/dist/cli/output.js.map +1 -1
- package/dist/cli/parse-utils.d.ts +21 -0
- package/dist/cli/parse-utils.d.ts.map +1 -0
- package/dist/cli/parse-utils.js +32 -0
- package/dist/cli/parse-utils.js.map +1 -0
- package/dist/cli/pid-utils.d.ts +72 -0
- package/dist/cli/pid-utils.d.ts.map +1 -0
- package/dist/cli/pid-utils.js +174 -0
- package/dist/cli/pid-utils.js.map +1 -0
- package/dist/cli/suggest.d.ts.map +1 -1
- package/dist/cli/suggest.js +1 -2
- package/dist/cli/suggest.js.map +1 -1
- package/dist/cli/validators.d.ts +43 -0
- package/dist/cli/validators.d.ts.map +1 -0
- package/dist/cli/validators.js +84 -0
- package/dist/cli/validators.js.map +1 -0
- package/dist/daemon/index.ts +52 -0
- package/dist/daemon/middleware/project-context.ts +126 -0
- package/dist/daemon/pid.ts +179 -0
- package/dist/daemon/project-context.ts +343 -0
- package/dist/daemon/routes/inbox.ts +164 -0
- package/dist/daemon/routes/items.ts +322 -0
- package/dist/daemon/routes/meta.ts +118 -0
- package/dist/daemon/routes/projects.ts +162 -0
- package/dist/daemon/routes/tasks.ts +327 -0
- package/dist/daemon/routes/triage.ts +402 -0
- package/dist/daemon/routes/validation.ts +248 -0
- package/dist/daemon/server.ts +408 -0
- package/dist/daemon/watcher.ts +195 -0
- package/dist/daemon/websocket/handler.ts +138 -0
- package/dist/daemon/websocket/heartbeat.ts +71 -0
- package/dist/daemon/websocket/pubsub.ts +125 -0
- package/dist/daemon/websocket/types.ts +66 -0
- package/dist/export/html.d.ts +19 -0
- package/dist/export/html.d.ts.map +1 -0
- package/dist/export/html.js +239 -0
- package/dist/export/html.js.map +1 -0
- package/dist/export/index.d.ts +10 -0
- package/dist/export/index.d.ts.map +1 -0
- package/dist/export/index.js +10 -0
- package/dist/export/index.js.map +1 -0
- package/dist/export/json.d.ts +24 -0
- package/dist/export/json.d.ts.map +1 -0
- package/dist/export/json.js +198 -0
- package/dist/export/json.js.map +1 -0
- package/dist/export/triage.d.ts +51 -0
- package/dist/export/triage.d.ts.map +1 -0
- package/dist/export/triage.js +83 -0
- package/dist/export/triage.js.map +1 -0
- package/dist/export/types.d.ts +122 -0
- package/dist/export/types.d.ts.map +1 -0
- package/dist/export/types.js +9 -0
- package/dist/export/types.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/lib/claude-plugin-registry.d.ts +66 -0
- package/dist/lib/claude-plugin-registry.d.ts.map +1 -0
- package/dist/lib/claude-plugin-registry.js +318 -0
- package/dist/lib/claude-plugin-registry.js.map +1 -0
- package/dist/merge/arrays.d.ts +87 -0
- package/dist/merge/arrays.d.ts.map +1 -0
- package/dist/merge/arrays.js +164 -0
- package/dist/merge/arrays.js.map +1 -0
- package/dist/merge/file-type.d.ts +32 -0
- package/dist/merge/file-type.d.ts.map +1 -0
- package/dist/merge/file-type.js +70 -0
- package/dist/merge/file-type.js.map +1 -0
- package/dist/merge/index.d.ts +14 -0
- package/dist/merge/index.d.ts.map +1 -0
- package/dist/merge/index.js +11 -0
- package/dist/merge/index.js.map +1 -0
- package/dist/merge/objects.d.ts +46 -0
- package/dist/merge/objects.d.ts.map +1 -0
- package/dist/merge/objects.js +193 -0
- package/dist/merge/objects.js.map +1 -0
- package/dist/merge/parse.d.ts +23 -0
- package/dist/merge/parse.d.ts.map +1 -0
- package/dist/merge/parse.js +78 -0
- package/dist/merge/parse.js.map +1 -0
- package/dist/merge/resolve.d.ts +66 -0
- package/dist/merge/resolve.d.ts.map +1 -0
- package/dist/merge/resolve.js +189 -0
- package/dist/merge/resolve.js.map +1 -0
- package/dist/merge/types.d.ts +82 -0
- package/dist/merge/types.d.ts.map +1 -0
- package/dist/merge/types.js +8 -0
- package/dist/merge/types.js.map +1 -0
- package/dist/parser/agent-data-sections.d.ts +53 -0
- package/dist/parser/agent-data-sections.d.ts.map +1 -0
- package/dist/parser/agent-data-sections.js +118 -0
- package/dist/parser/agent-data-sections.js.map +1 -0
- package/dist/parser/alignment.d.ts +4 -4
- package/dist/parser/alignment.d.ts.map +1 -1
- package/dist/parser/alignment.js +27 -22
- package/dist/parser/alignment.js.map +1 -1
- package/dist/parser/assess.d.ts +5 -5
- package/dist/parser/assess.d.ts.map +1 -1
- package/dist/parser/assess.js +36 -32
- package/dist/parser/assess.js.map +1 -1
- package/dist/parser/config.d.ts +457 -0
- package/dist/parser/config.d.ts.map +1 -0
- package/dist/parser/config.js +373 -0
- package/dist/parser/config.js.map +1 -0
- package/dist/parser/convention-validation.d.ts +1 -1
- package/dist/parser/convention-validation.d.ts.map +1 -1
- package/dist/parser/convention-validation.js +21 -16
- package/dist/parser/convention-validation.js.map +1 -1
- package/dist/parser/coverage-cache.d.ts +49 -0
- package/dist/parser/coverage-cache.d.ts.map +1 -0
- package/dist/parser/coverage-cache.js +123 -0
- package/dist/parser/coverage-cache.js.map +1 -0
- package/dist/parser/daemon-status.d.ts +37 -0
- package/dist/parser/daemon-status.d.ts.map +1 -0
- package/dist/parser/daemon-status.js +67 -0
- package/dist/parser/daemon-status.js.map +1 -0
- package/dist/parser/doctor.d.ts +107 -0
- package/dist/parser/doctor.d.ts.map +1 -0
- package/dist/parser/doctor.js +366 -0
- package/dist/parser/doctor.js.map +1 -0
- package/dist/parser/fix.d.ts +1 -1
- package/dist/parser/fix.d.ts.map +1 -1
- package/dist/parser/fix.js +31 -27
- package/dist/parser/fix.js.map +1 -1
- package/dist/parser/index.d.ts +16 -11
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/parser/index.js +16 -11
- package/dist/parser/index.js.map +1 -1
- package/dist/parser/items.d.ts +8 -2
- package/dist/parser/items.d.ts.map +1 -1
- package/dist/parser/items.js +71 -35
- package/dist/parser/items.js.map +1 -1
- package/dist/parser/meta.d.ts +167 -9
- package/dist/parser/meta.d.ts.map +1 -1
- package/dist/parser/meta.js +379 -46
- package/dist/parser/meta.js.map +1 -1
- package/dist/parser/plan-document.d.ts +197 -0
- package/dist/parser/plan-document.d.ts.map +1 -0
- package/dist/parser/plan-document.js +341 -0
- package/dist/parser/plan-document.js.map +1 -0
- package/dist/parser/plans.d.ts +59 -0
- package/dist/parser/plans.d.ts.map +1 -0
- package/dist/parser/plans.js +239 -0
- package/dist/parser/plans.js.map +1 -0
- package/dist/parser/refs.d.ts +22 -9
- package/dist/parser/refs.d.ts.map +1 -1
- package/dist/parser/refs.js +102 -50
- package/dist/parser/refs.js.map +1 -1
- package/dist/parser/setup-status.d.ts +71 -0
- package/dist/parser/setup-status.d.ts.map +1 -0
- package/dist/parser/setup-status.js +269 -0
- package/dist/parser/setup-status.js.map +1 -0
- package/dist/parser/shadow.d.ts +150 -19
- package/dist/parser/shadow.d.ts.map +1 -1
- package/dist/parser/shadow.js +548 -187
- package/dist/parser/shadow.js.map +1 -1
- package/dist/parser/skill-render.d.ts +317 -0
- package/dist/parser/skill-render.d.ts.map +1 -0
- package/dist/parser/skill-render.js +943 -0
- package/dist/parser/skill-render.js.map +1 -0
- package/dist/parser/traits.d.ts +3 -3
- package/dist/parser/traits.d.ts.map +1 -1
- package/dist/parser/traits.js +2 -2
- package/dist/parser/traits.js.map +1 -1
- package/dist/parser/validate-skills.d.ts +32 -0
- package/dist/parser/validate-skills.d.ts.map +1 -0
- package/dist/parser/validate-skills.js +202 -0
- package/dist/parser/validate-skills.js.map +1 -0
- package/dist/parser/validate.d.ts +45 -3
- package/dist/parser/validate.d.ts.map +1 -1
- package/dist/parser/validate.js +622 -105
- package/dist/parser/validate.js.map +1 -1
- package/dist/parser/yaml.d.ts +83 -19
- package/dist/parser/yaml.d.ts.map +1 -1
- package/dist/parser/yaml.js +478 -173
- package/dist/parser/yaml.js.map +1 -1
- package/dist/ralph/cli-renderer.d.ts +8 -1
- package/dist/ralph/cli-renderer.d.ts.map +1 -1
- package/dist/ralph/cli-renderer.js +105 -34
- package/dist/ralph/cli-renderer.js.map +1 -1
- package/dist/ralph/events.d.ts +10 -10
- package/dist/ralph/events.d.ts.map +1 -1
- package/dist/ralph/events.js +301 -98
- package/dist/ralph/events.js.map +1 -1
- package/dist/ralph/index.d.ts +5 -2
- package/dist/ralph/index.d.ts.map +1 -1
- package/dist/ralph/index.js +9 -3
- package/dist/ralph/index.js.map +1 -1
- package/dist/ralph/loop-errors.d.ts +83 -0
- package/dist/ralph/loop-errors.d.ts.map +1 -0
- package/dist/ralph/loop-errors.js +150 -0
- package/dist/ralph/loop-errors.js.map +1 -0
- package/dist/ralph/subagent.d.ts +94 -0
- package/dist/ralph/subagent.d.ts.map +1 -0
- package/dist/ralph/subagent.js +193 -0
- package/dist/ralph/subagent.js.map +1 -0
- package/dist/ralph/wrap-up.d.ts +125 -0
- package/dist/ralph/wrap-up.d.ts.map +1 -0
- package/dist/ralph/wrap-up.js +270 -0
- package/dist/ralph/wrap-up.js.map +1 -0
- package/dist/schema/batch.d.ts +97 -0
- package/dist/schema/batch.d.ts.map +1 -0
- package/dist/schema/batch.js +24 -0
- package/dist/schema/batch.js.map +1 -0
- package/dist/schema/common.d.ts +8 -2
- package/dist/schema/common.d.ts.map +1 -1
- package/dist/schema/common.js +42 -31
- package/dist/schema/common.js.map +1 -1
- package/dist/schema/inbox.d.ts +12 -12
- package/dist/schema/inbox.js +4 -4
- package/dist/schema/inbox.js.map +1 -1
- package/dist/schema/index.d.ts +8 -5
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +8 -5
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/meta.d.ts +1454 -27
- package/dist/schema/meta.d.ts.map +1 -1
- package/dist/schema/meta.js +198 -21
- package/dist/schema/meta.js.map +1 -1
- package/dist/schema/plan.d.ts +285 -0
- package/dist/schema/plan.d.ts.map +1 -0
- package/dist/schema/plan.js +81 -0
- package/dist/schema/plan.js.map +1 -0
- package/dist/schema/spec.d.ts +72 -33
- package/dist/schema/spec.d.ts.map +1 -1
- package/dist/schema/spec.js +22 -9
- package/dist/schema/spec.js.map +1 -1
- package/dist/schema/task.d.ts +172 -161
- package/dist/schema/task.d.ts.map +1 -1
- package/dist/schema/task.js +21 -12
- package/dist/schema/task.js.map +1 -1
- package/dist/schema/triage.d.ts +266 -0
- package/dist/schema/triage.d.ts.map +1 -0
- package/dist/schema/triage.js +134 -0
- package/dist/schema/triage.js.map +1 -0
- package/dist/sessions/index.d.ts +2 -2
- package/dist/sessions/index.d.ts.map +1 -1
- package/dist/sessions/index.js +3 -3
- package/dist/sessions/index.js.map +1 -1
- package/dist/sessions/store.d.ts +241 -1
- package/dist/sessions/store.d.ts.map +1 -1
- package/dist/sessions/store.js +810 -31
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/types.d.ts +10 -10
- package/dist/sessions/types.d.ts.map +1 -1
- package/dist/sessions/types.js +10 -9
- package/dist/sessions/types.js.map +1 -1
- package/dist/strings/errors.d.ts +55 -0
- package/dist/strings/errors.d.ts.map +1 -1
- package/dist/strings/errors.js +138 -106
- package/dist/strings/errors.js.map +1 -1
- package/dist/strings/guidance.d.ts.map +1 -1
- package/dist/strings/guidance.js +16 -16
- package/dist/strings/guidance.js.map +1 -1
- package/dist/strings/index.d.ts +4 -4
- package/dist/strings/index.d.ts.map +1 -1
- package/dist/strings/index.js +4 -4
- package/dist/strings/index.js.map +1 -1
- package/dist/strings/labels.d.ts +4 -0
- package/dist/strings/labels.d.ts.map +1 -1
- package/dist/strings/labels.js +45 -41
- package/dist/strings/labels.js.map +1 -1
- package/dist/strings/validation.d.ts.map +1 -1
- package/dist/strings/validation.js +71 -71
- package/dist/strings/validation.js.map +1 -1
- package/dist/triage/actions.d.ts +27 -0
- package/dist/triage/actions.d.ts.map +1 -0
- package/dist/triage/actions.js +95 -0
- package/dist/triage/actions.js.map +1 -0
- package/dist/triage/constants.d.ts +6 -0
- package/dist/triage/constants.d.ts.map +1 -0
- package/dist/triage/constants.js +7 -0
- package/dist/triage/constants.js.map +1 -0
- package/dist/triage/index.d.ts +3 -0
- package/dist/triage/index.d.ts.map +1 -0
- package/dist/triage/index.js +3 -0
- package/dist/triage/index.js.map +1 -0
- package/dist/utils/commit.d.ts +1 -1
- package/dist/utils/commit.d.ts.map +1 -1
- package/dist/utils/commit.js +28 -26
- package/dist/utils/commit.js.map +1 -1
- package/dist/utils/git.d.ts +1 -1
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +40 -38
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/grep.js +11 -11
- package/dist/utils/grep.js.map +1 -1
- package/dist/utils/index.d.ts +7 -7
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +4 -4
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/time.d.ts.map +1 -1
- package/dist/utils/time.js +10 -10
- package/dist/utils/time.js.map +1 -1
- package/package.json +28 -5
- package/plugin/.claude-plugin/marketplace.json +17 -0
- package/plugin/.claude-plugin/plugin.json +5 -0
- package/plugin/plugins/kspec/skills/create-workflow/SKILL.md +235 -0
- package/plugin/plugins/kspec/skills/help/SKILL.md +42 -0
- package/plugin/plugins/kspec/skills/observations/SKILL.md +143 -0
- package/plugin/plugins/kspec/skills/plan/SKILL.md +343 -0
- package/plugin/plugins/kspec/skills/reflect/SKILL.md +161 -0
- package/plugin/plugins/kspec/skills/review/SKILL.md +193 -0
- package/plugin/plugins/kspec/skills/task-work/SKILL.md +303 -0
- package/plugin/plugins/kspec/skills/triage/SKILL.md +206 -0
- package/plugin/plugins/kspec/skills/triage/docs/automation.md +120 -0
- package/plugin/plugins/kspec/skills/triage/docs/inbox.md +144 -0
- package/plugin/plugins/kspec/skills/triage/docs/observations.md +85 -0
- package/plugin/plugins/kspec/skills/triage-automation/SKILL.md +140 -0
- package/plugin/plugins/kspec/skills/triage-inbox/SKILL.md +232 -0
- package/plugin/plugins/kspec/skills/writing-specs/SKILL.md +340 -0
- package/templates/agents-sections/01-quick-start.md +22 -0
- package/templates/agents-sections/02-shadow-branch.md +34 -0
- package/templates/agents-sections/03-task-lifecycle.md +48 -0
- package/templates/agents-sections/04-pr-workflow.md +17 -0
- package/templates/agents-sections/05-commit-convention.md +27 -0
- package/templates/agents-sections/06-ralph-loop.md +45 -0
- package/templates/hooks/pre-commit +34 -0
- package/templates/skills/create-workflow/SKILL.md +228 -0
- package/templates/skills/help/SKILL.md +37 -0
- package/templates/skills/manifest.yaml +60 -0
- package/templates/skills/observations/SKILL.md +137 -0
- package/templates/skills/plan/SKILL.md +336 -0
- package/templates/skills/reflect/SKILL.md +155 -0
- package/templates/skills/review/SKILL.md +186 -0
- package/templates/skills/task-work/SKILL.md +296 -0
- package/templates/skills/triage/SKILL.md +199 -0
- package/templates/skills/triage/docs/automation.md +120 -0
- package/templates/skills/triage/docs/inbox.md +144 -0
- package/templates/skills/triage/docs/observations.md +85 -0
- package/templates/skills/triage-automation/SKILL.md +134 -0
- package/templates/skills/triage-inbox/SKILL.md +225 -0
- package/templates/skills/writing-specs/SKILL.md +333 -0
|
@@ -0,0 +1,706 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch command parsing, validation, execution, and error reporting.
|
|
3
|
+
*
|
|
4
|
+
* Parses JSON batch input from stdin/file/inline, validates command paths
|
|
5
|
+
* against the CLI's introspection tree, executes in atomic or immediate
|
|
6
|
+
* mode, and produces helpful error messages.
|
|
7
|
+
*/
|
|
8
|
+
import * as fs from "node:fs/promises";
|
|
9
|
+
import * as path from "node:path";
|
|
10
|
+
import * as os from "node:os";
|
|
11
|
+
import chalk from "chalk";
|
|
12
|
+
import { ZodError } from "zod";
|
|
13
|
+
import { BatchInputSchema, } from "../schema/batch.js";
|
|
14
|
+
import { initContext } from "../parser/yaml.js";
|
|
15
|
+
import { shadowAutoCommit, shadowPushAsync } from "../parser/shadow.js";
|
|
16
|
+
import { extractCommandTree, findCommand, flattenCommandTree } from "./introspection.js";
|
|
17
|
+
import { findClosestCommand } from "./suggest.js";
|
|
18
|
+
import { createBatchCommandFilter } from "./command-annotations.js";
|
|
19
|
+
import { setJsonMode, setVerboseMode } from "./output.js";
|
|
20
|
+
import { BatchExitError, OutputCapture, installExitInterceptor, uninstallExitInterceptor, setBatchMode, } from "./batch-context.js";
|
|
21
|
+
// ── Error Types ─────────────────────────────────────────────────────
|
|
22
|
+
export class BatchParseError extends Error {
|
|
23
|
+
constructor(message) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = "BatchParseError";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// ── Parsing ─────────────────────────────────────────────────────────
|
|
29
|
+
/**
|
|
30
|
+
* Read raw text from a batch input source.
|
|
31
|
+
*/
|
|
32
|
+
async function readSource(source) {
|
|
33
|
+
switch (source.type) {
|
|
34
|
+
case "inline":
|
|
35
|
+
return source.json;
|
|
36
|
+
case "file":
|
|
37
|
+
try {
|
|
38
|
+
return await fs.readFile(source.path, "utf-8");
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
throw new BatchParseError(`Failed to read batch file: ${err.message}`);
|
|
42
|
+
}
|
|
43
|
+
case "stdin": {
|
|
44
|
+
const chunks = [];
|
|
45
|
+
for await (const chunk of process.stdin) {
|
|
46
|
+
chunks.push(chunk);
|
|
47
|
+
}
|
|
48
|
+
const text = Buffer.concat(chunks).toString("utf-8");
|
|
49
|
+
if (!text.trim()) {
|
|
50
|
+
throw new BatchParseError("No input received on stdin");
|
|
51
|
+
}
|
|
52
|
+
return text;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Parse batch input from a source, returning validated commands.
|
|
58
|
+
*
|
|
59
|
+
* @throws {BatchParseError} on invalid JSON, empty array, or schema violations
|
|
60
|
+
*/
|
|
61
|
+
export async function parseBatchInput(source) {
|
|
62
|
+
const raw = await readSource(source);
|
|
63
|
+
// Parse JSON — preserve the native error message which includes position
|
|
64
|
+
let parsed;
|
|
65
|
+
try {
|
|
66
|
+
parsed = JSON.parse(raw);
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
throw new BatchParseError(`Invalid JSON: ${err.message}`);
|
|
70
|
+
}
|
|
71
|
+
// Validate against schema
|
|
72
|
+
try {
|
|
73
|
+
return BatchInputSchema.parse(parsed);
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
if (err instanceof ZodError) {
|
|
77
|
+
const messages = err.errors.map((e) => {
|
|
78
|
+
const path = e.path.length > 0 ? ` at ${e.path.join(".")}` : "";
|
|
79
|
+
return `${e.message}${path}`;
|
|
80
|
+
});
|
|
81
|
+
throw new BatchParseError(`Batch validation failed: ${messages.join("; ")}`);
|
|
82
|
+
}
|
|
83
|
+
throw err;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// ── Validation ──────────────────────────────────────────────────────
|
|
87
|
+
/**
|
|
88
|
+
* Extract the option name from Commander flag syntax.
|
|
89
|
+
* e.g. "-f, --force" → "force", "--spec-ref <value>" → "spec-ref"
|
|
90
|
+
*/
|
|
91
|
+
function extractOptionName(flags) {
|
|
92
|
+
const match = flags.match(/--([a-zA-Z0-9-]+)/);
|
|
93
|
+
return match ? match[1] : null;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Convert a kebab-case string to camelCase.
|
|
97
|
+
* e.g. "spec-ref" → "specRef"
|
|
98
|
+
*/
|
|
99
|
+
function kebabToCamel(s) {
|
|
100
|
+
return s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Get all known argument and option names for a command, returning both
|
|
104
|
+
* kebab-case and camelCase variants.
|
|
105
|
+
*/
|
|
106
|
+
function getKnownArgNames(cmd) {
|
|
107
|
+
const names = new Set();
|
|
108
|
+
const required = [];
|
|
109
|
+
// Positional arguments
|
|
110
|
+
for (const arg of cmd.arguments) {
|
|
111
|
+
names.add(arg.name);
|
|
112
|
+
names.add(kebabToCamel(arg.name));
|
|
113
|
+
if (arg.required) {
|
|
114
|
+
required.push(arg.name);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Options
|
|
118
|
+
for (const opt of cmd.options) {
|
|
119
|
+
const optName = extractOptionName(opt.flags);
|
|
120
|
+
if (optName) {
|
|
121
|
+
names.add(optName);
|
|
122
|
+
names.add(kebabToCamel(optName));
|
|
123
|
+
if (opt.mandatory) {
|
|
124
|
+
required.push(optName);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return { names, required };
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Collect all leaf command paths from a command tree as space-joined strings.
|
|
132
|
+
*/
|
|
133
|
+
function collectLeafCommandPaths(tree) {
|
|
134
|
+
const flat = flattenCommandTree(tree);
|
|
135
|
+
return flat
|
|
136
|
+
.filter((cmd) => cmd.subcommands.length === 0)
|
|
137
|
+
.map((cmd) => cmd.fullPath.slice(1).join(" ")) // skip root name
|
|
138
|
+
.filter((path) => path.length > 0);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Validate batch commands against the CLI's command tree.
|
|
142
|
+
*
|
|
143
|
+
* AC: @batch-command-schema ac-command-field — validates command paths
|
|
144
|
+
* AC: @batch-command-schema ac-args-mapping — validates arg names
|
|
145
|
+
* AC: @batch-command-schema ac-unknown-command — suggests similar commands
|
|
146
|
+
* AC: @batch-command-schema ac-missing-required — identifies missing args
|
|
147
|
+
* AC: @batch-command-schema ac-id-field — preserves id in errors
|
|
148
|
+
*/
|
|
149
|
+
export function validateBatchCommands(commands, program, options) {
|
|
150
|
+
const errors = [];
|
|
151
|
+
const validLeafPaths = collectLeafCommandPaths(program);
|
|
152
|
+
for (let i = 0; i < commands.length; i++) {
|
|
153
|
+
const cmd = commands[i];
|
|
154
|
+
const parts = cmd.command.trim().split(/\s+/);
|
|
155
|
+
// 1. Resolve command path
|
|
156
|
+
const found = findCommand(program, parts);
|
|
157
|
+
if (!found) {
|
|
158
|
+
// Unknown command — suggest closest
|
|
159
|
+
const suggestion = findClosestCommand(cmd.command, validLeafPaths);
|
|
160
|
+
errors.push({
|
|
161
|
+
index: i,
|
|
162
|
+
id: cmd.id,
|
|
163
|
+
command: cmd.command,
|
|
164
|
+
type: "unknown_command",
|
|
165
|
+
message: `Unknown command: "${cmd.command}"`,
|
|
166
|
+
suggestion: suggestion ?? undefined,
|
|
167
|
+
});
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
// Reject command groups (non-leaf nodes)
|
|
171
|
+
if (found.subcommands.length > 0) {
|
|
172
|
+
const suggestion = findClosestCommand(cmd.command, validLeafPaths);
|
|
173
|
+
errors.push({
|
|
174
|
+
index: i,
|
|
175
|
+
id: cmd.id,
|
|
176
|
+
command: cmd.command,
|
|
177
|
+
type: "unknown_command",
|
|
178
|
+
message: `"${cmd.command}" is a command group, not an executable command`,
|
|
179
|
+
suggestion: suggestion ?? undefined,
|
|
180
|
+
});
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
// 2. Reject nested batch commands (batch or any subcommands like batch commands)
|
|
184
|
+
// AC: @batch-allowed-commands ac-batch-itself
|
|
185
|
+
if (found.fullPath[1] === "batch") {
|
|
186
|
+
errors.push({
|
|
187
|
+
index: i,
|
|
188
|
+
id: cmd.id,
|
|
189
|
+
command: cmd.command,
|
|
190
|
+
type: "rejected_command",
|
|
191
|
+
message: "Nested batch commands are not allowed",
|
|
192
|
+
});
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
// 3. Apply command filter if provided
|
|
196
|
+
// AC: @batch-allowed-commands ac-denylist
|
|
197
|
+
if (options?.commandFilter && !options.commandFilter(found)) {
|
|
198
|
+
errors.push({
|
|
199
|
+
index: i,
|
|
200
|
+
id: cmd.id,
|
|
201
|
+
command: cmd.command,
|
|
202
|
+
type: "rejected_command",
|
|
203
|
+
message: `Command "${cmd.command}" is not allowed in batch mode. Only mutating commands can be used in batch.`,
|
|
204
|
+
});
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
// 4. Check for unknown args
|
|
208
|
+
const { names: knownNames, required: requiredNames } = getKnownArgNames(found);
|
|
209
|
+
// Collect all known names as flat array for suggestion matching
|
|
210
|
+
const knownNamesArray = Array.from(knownNames);
|
|
211
|
+
for (const argKey of Object.keys(cmd.args)) {
|
|
212
|
+
// Accept both kebab-case and camelCase
|
|
213
|
+
if (!knownNames.has(argKey)) {
|
|
214
|
+
const suggestion = findClosestCommand(argKey, knownNamesArray);
|
|
215
|
+
errors.push({
|
|
216
|
+
index: i,
|
|
217
|
+
id: cmd.id,
|
|
218
|
+
command: cmd.command,
|
|
219
|
+
type: "unknown_arg",
|
|
220
|
+
message: `Unknown argument "${argKey}" for command "${cmd.command}"`,
|
|
221
|
+
suggestion: suggestion ?? undefined,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// 5. Check for missing required args
|
|
226
|
+
for (const reqName of requiredNames) {
|
|
227
|
+
const camelName = kebabToCamel(reqName);
|
|
228
|
+
if (!(reqName in cmd.args) &&
|
|
229
|
+
!(camelName in cmd.args) &&
|
|
230
|
+
// Skip if provided via positional alias
|
|
231
|
+
!Object.keys(cmd.args).some((k) => kebabToCamel(k) === camelName)) {
|
|
232
|
+
errors.push({
|
|
233
|
+
index: i,
|
|
234
|
+
id: cmd.id,
|
|
235
|
+
command: cmd.command,
|
|
236
|
+
type: "missing_required",
|
|
237
|
+
message: `Missing required argument "${reqName}" for command "${cmd.command}"`,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return {
|
|
243
|
+
valid: errors.length === 0,
|
|
244
|
+
commands,
|
|
245
|
+
errors,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
// ── Error Reporting ─────────────────────────────────────────────────
|
|
249
|
+
/**
|
|
250
|
+
* Format validation errors for human or JSON output.
|
|
251
|
+
*
|
|
252
|
+
* @param result - Validation result containing errors
|
|
253
|
+
* @param json - If true, return JSON string; otherwise human-readable lines
|
|
254
|
+
* @returns Formatted error string
|
|
255
|
+
*/
|
|
256
|
+
export function reportBatchValidationErrors(result, json = false) {
|
|
257
|
+
if (result.valid) {
|
|
258
|
+
return json ? JSON.stringify({ valid: true, errors: [] }) : "";
|
|
259
|
+
}
|
|
260
|
+
if (json) {
|
|
261
|
+
return JSON.stringify({
|
|
262
|
+
valid: false,
|
|
263
|
+
errors: result.errors,
|
|
264
|
+
}, null, 2);
|
|
265
|
+
}
|
|
266
|
+
// Human-readable format
|
|
267
|
+
const lines = [];
|
|
268
|
+
for (const err of result.errors) {
|
|
269
|
+
const label = err.id ?? `#${err.index}`;
|
|
270
|
+
lines.push(`[${label}] ${err.message}`);
|
|
271
|
+
if (err.suggestion) {
|
|
272
|
+
lines.push(` Did you mean: ${err.suggestion}?`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
// Add helpful hint for discoverability
|
|
276
|
+
lines.push("");
|
|
277
|
+
lines.push("Run 'kspec batch commands' for a list of available commands.");
|
|
278
|
+
return lines.join("\n");
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Build Commander argv from a BatchCommand and its CommandMeta.
|
|
282
|
+
*
|
|
283
|
+
* Translates { command: "inbox add", args: { content: "hello", tag: ["a","b"] } }
|
|
284
|
+
* into ["inbox", "add", "hello", "--tag", "a", "--tag", "b"]
|
|
285
|
+
*
|
|
286
|
+
* Positional args are emitted in Commander definition order (not JSON key order)
|
|
287
|
+
* to ensure correct argument mapping regardless of how the JSON was serialized.
|
|
288
|
+
*/
|
|
289
|
+
/**
|
|
290
|
+
* Serialize a value for CLI argv. Plain objects are JSON-stringified
|
|
291
|
+
* so that flags like --data receive valid JSON instead of "[object Object]".
|
|
292
|
+
*/
|
|
293
|
+
function toArgString(value) {
|
|
294
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
295
|
+
return JSON.stringify(value);
|
|
296
|
+
}
|
|
297
|
+
return String(value);
|
|
298
|
+
}
|
|
299
|
+
export function buildCommandArgv(cmd, cmdMeta) {
|
|
300
|
+
const argv = [...cmd.command.trim().split(/\s+/)];
|
|
301
|
+
// Build sets for classification
|
|
302
|
+
const positionalDefs = cmdMeta.arguments; // ordered by Commander definition
|
|
303
|
+
const positionalNameSet = new Set();
|
|
304
|
+
for (const arg of positionalDefs) {
|
|
305
|
+
positionalNameSet.add(arg.name);
|
|
306
|
+
positionalNameSet.add(kebabToCamel(arg.name));
|
|
307
|
+
}
|
|
308
|
+
const optionMap = new Map();
|
|
309
|
+
for (const opt of cmdMeta.options) {
|
|
310
|
+
const name = extractOptionName(opt.flags);
|
|
311
|
+
if (name) {
|
|
312
|
+
optionMap.set(name, { flags: opt.flags, variadic: opt.variadic });
|
|
313
|
+
optionMap.set(kebabToCamel(name), { flags: opt.flags, variadic: opt.variadic });
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
// Phase 1: Emit positional args in Commander definition order
|
|
317
|
+
for (const argDef of positionalDefs) {
|
|
318
|
+
const name = argDef.name;
|
|
319
|
+
const camelName = kebabToCamel(name);
|
|
320
|
+
const value = cmd.args[name] ?? cmd.args[camelName];
|
|
321
|
+
if (value === undefined)
|
|
322
|
+
continue;
|
|
323
|
+
if (Array.isArray(value)) {
|
|
324
|
+
for (const v of value)
|
|
325
|
+
argv.push(toArgString(v));
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
argv.push(toArgString(value));
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
// Phase 2: Emit options from remaining keys
|
|
332
|
+
for (const [key, value] of Object.entries(cmd.args)) {
|
|
333
|
+
const camelKey = kebabToCamel(key);
|
|
334
|
+
// Skip positional args (already emitted)
|
|
335
|
+
if (positionalNameSet.has(key) || positionalNameSet.has(camelKey)) {
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
// Convert camelCase key back to kebab-case for CLI
|
|
339
|
+
const kebabKey = key.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
340
|
+
const flagName = `--${kebabKey}`;
|
|
341
|
+
if (typeof value === "boolean") {
|
|
342
|
+
if (value) {
|
|
343
|
+
argv.push(flagName);
|
|
344
|
+
}
|
|
345
|
+
// false booleans: omit (Commander treats absence as false)
|
|
346
|
+
}
|
|
347
|
+
else if (Array.isArray(value)) {
|
|
348
|
+
// Variadic or repeated options
|
|
349
|
+
for (const v of value) {
|
|
350
|
+
argv.push(flagName, toArgString(v));
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
else if (value !== null && value !== undefined) {
|
|
354
|
+
argv.push(flagName, toArgString(value));
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return argv;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Reset Commander command tree state between dispatches.
|
|
361
|
+
* Commander retains _optionValues between parseAsync calls.
|
|
362
|
+
*/
|
|
363
|
+
export function resetCommandTree(cmd) {
|
|
364
|
+
cmd._optionValues = {};
|
|
365
|
+
cmd._optionValueSources = {};
|
|
366
|
+
cmd.processedArgs = [];
|
|
367
|
+
for (const sub of cmd.commands) {
|
|
368
|
+
resetCommandTree(sub);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Check if a CommandMeta supports the --force option.
|
|
373
|
+
*/
|
|
374
|
+
function commandHasForce(cmdMeta) {
|
|
375
|
+
return cmdMeta.options.some((opt) => {
|
|
376
|
+
const name = extractOptionName(opt.flags);
|
|
377
|
+
return name === "force";
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Execute a batch of commands.
|
|
382
|
+
*
|
|
383
|
+
* AC: @batch-exec ac-default-atomic — atomic mode by default
|
|
384
|
+
* AC: @batch-exec ac-no-atomic-flag — immediate mode with --no-atomic
|
|
385
|
+
* AC: @batch-exec ac-stop-on-error — stop on first failure (default)
|
|
386
|
+
* AC: @batch-exec ac-continue — continue on error with --continue
|
|
387
|
+
* AC: @batch-exec ac-dry-run — validate without executing
|
|
388
|
+
* AC: @batch-exec ac-prevalidate — validation before any execution
|
|
389
|
+
* AC: @batch-exec ac-confirmation-suppressed — auto-append --force
|
|
390
|
+
*/
|
|
391
|
+
export async function executeBatch(commands, program, options) {
|
|
392
|
+
const mode = options.atomic ? "atomic" : "immediate";
|
|
393
|
+
// Build command tree for validation
|
|
394
|
+
const tree = extractCommandTree(program);
|
|
395
|
+
const commandFilter = createBatchCommandFilter();
|
|
396
|
+
// AC: ac-prevalidate — validate all commands before executing any
|
|
397
|
+
const validation = validateBatchCommands(commands, tree, { commandFilter });
|
|
398
|
+
if (!validation.valid) {
|
|
399
|
+
return {
|
|
400
|
+
success: false,
|
|
401
|
+
mode,
|
|
402
|
+
summary: {
|
|
403
|
+
total: commands.length,
|
|
404
|
+
succeeded: 0,
|
|
405
|
+
failed: validation.errors.length,
|
|
406
|
+
},
|
|
407
|
+
results: validation.errors.map((err) => ({
|
|
408
|
+
index: err.index,
|
|
409
|
+
id: err.id,
|
|
410
|
+
command: err.command,
|
|
411
|
+
success: false,
|
|
412
|
+
error: err.message,
|
|
413
|
+
suggestion: err.suggestion,
|
|
414
|
+
})),
|
|
415
|
+
validationFailed: true,
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
// AC: ac-dry-run — validate without executing
|
|
419
|
+
// AC: @trait-dry-run ac-6 — include dry_run boolean in JSON output
|
|
420
|
+
if (options.dryRun) {
|
|
421
|
+
return {
|
|
422
|
+
success: true,
|
|
423
|
+
dry_run: true,
|
|
424
|
+
mode,
|
|
425
|
+
summary: { total: commands.length, succeeded: commands.length, failed: 0 },
|
|
426
|
+
results: commands.map((cmd, i) => ({
|
|
427
|
+
index: i,
|
|
428
|
+
id: cmd.id,
|
|
429
|
+
command: cmd.command,
|
|
430
|
+
success: true,
|
|
431
|
+
output: "dry-run: would execute",
|
|
432
|
+
})),
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
if (options.atomic) {
|
|
436
|
+
return executeAtomic(commands, program, tree, options);
|
|
437
|
+
}
|
|
438
|
+
else {
|
|
439
|
+
return executeImmediate(commands, program, tree, options);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Atomic execution: copy specDir to temp, run all, copy back on success.
|
|
444
|
+
*
|
|
445
|
+
* AC: @batch-exec ac-default-atomic
|
|
446
|
+
* AC: @batch-exec ac-atomic-rollback
|
|
447
|
+
* AC: @batch-exec ac-atomic-isolation
|
|
448
|
+
* AC: @batch-exec ac-single-commit
|
|
449
|
+
*/
|
|
450
|
+
async function executeAtomic(commands, program, tree, options) {
|
|
451
|
+
// Get the real context for copy-back
|
|
452
|
+
const ctx = await initContext();
|
|
453
|
+
const realSpecDir = ctx.specDir;
|
|
454
|
+
// Create temp copy using mkdtemp for safe, collision-free naming
|
|
455
|
+
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "kspec-batch-"));
|
|
456
|
+
await fs.cp(realSpecDir, tempDir, { recursive: true });
|
|
457
|
+
// Remove .git from temp copy to prevent worktree pointer leaks
|
|
458
|
+
await fs.rm(path.join(tempDir, ".git"), { force: true, recursive: true });
|
|
459
|
+
// Set up atomic context
|
|
460
|
+
const savedChalkLevel = chalk.level;
|
|
461
|
+
const savedSpecDir = process.env.KSPEC_SPEC_DIR;
|
|
462
|
+
const savedBatchProjectRoot = process.env.KSPEC_BATCH_PROJECT_ROOT;
|
|
463
|
+
// AC: @project-config ac-7 — set real project root before redirecting spec dir
|
|
464
|
+
process.env.KSPEC_BATCH_PROJECT_ROOT = ctx.rootDir;
|
|
465
|
+
process.env.KSPEC_SPEC_DIR = tempDir;
|
|
466
|
+
setBatchMode(true);
|
|
467
|
+
chalk.level = 0;
|
|
468
|
+
const results = [];
|
|
469
|
+
let allSucceeded = true;
|
|
470
|
+
let copyBackFailed = false;
|
|
471
|
+
try {
|
|
472
|
+
for (let i = 0; i < commands.length; i++) {
|
|
473
|
+
const cmd = commands[i];
|
|
474
|
+
const result = await dispatchCommand(cmd, i, program, tree);
|
|
475
|
+
results.push(result);
|
|
476
|
+
if (!result.success) {
|
|
477
|
+
allSucceeded = false;
|
|
478
|
+
// Atomic mode: stop on first failure, discard everything
|
|
479
|
+
// Fill remaining as not-executed
|
|
480
|
+
for (let j = i + 1; j < commands.length; j++) {
|
|
481
|
+
results.push({
|
|
482
|
+
index: j,
|
|
483
|
+
id: commands[j].id,
|
|
484
|
+
command: commands[j].command,
|
|
485
|
+
success: false,
|
|
486
|
+
error: "Not executed (prior command failed in atomic mode)",
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
break;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
// Copy back on success
|
|
493
|
+
if (allSucceeded) {
|
|
494
|
+
try {
|
|
495
|
+
// Clear real specDir contents (except .git and .gitattributes) before copy-back
|
|
496
|
+
const entries = await fs.readdir(realSpecDir);
|
|
497
|
+
for (const entry of entries) {
|
|
498
|
+
if (entry === ".git" || entry === ".gitattributes")
|
|
499
|
+
continue;
|
|
500
|
+
await fs.rm(path.join(realSpecDir, entry), { recursive: true, force: true });
|
|
501
|
+
}
|
|
502
|
+
// Copy temp contents back
|
|
503
|
+
const tempEntries = await fs.readdir(tempDir);
|
|
504
|
+
for (const entry of tempEntries) {
|
|
505
|
+
await fs.cp(path.join(tempDir, entry), path.join(realSpecDir, entry), { recursive: true });
|
|
506
|
+
}
|
|
507
|
+
// Single shadow commit for all changes
|
|
508
|
+
if (ctx.shadow?.enabled) {
|
|
509
|
+
const successCount = results.filter((r) => r.success).length;
|
|
510
|
+
await shadowAutoCommit(ctx.shadow.worktreeDir, `batch: ${successCount} command${successCount !== 1 ? "s" : ""}`);
|
|
511
|
+
shadowPushAsync(ctx.shadow.worktreeDir);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
catch (copyErr) {
|
|
515
|
+
// Copy-back failed — preserve tempDir for manual recovery
|
|
516
|
+
copyBackFailed = true;
|
|
517
|
+
allSucceeded = false;
|
|
518
|
+
console.error(`Batch copy-back failed: ${copyErr instanceof Error ? copyErr.message : copyErr}`);
|
|
519
|
+
console.error(`Temp dir preserved for recovery: ${tempDir}`);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
finally {
|
|
524
|
+
// Clean up
|
|
525
|
+
setBatchMode(false);
|
|
526
|
+
chalk.level = savedChalkLevel;
|
|
527
|
+
if (savedSpecDir !== undefined) {
|
|
528
|
+
process.env.KSPEC_SPEC_DIR = savedSpecDir;
|
|
529
|
+
}
|
|
530
|
+
else {
|
|
531
|
+
delete process.env.KSPEC_SPEC_DIR;
|
|
532
|
+
}
|
|
533
|
+
// AC: @project-config ac-7 — restore batch project root env var
|
|
534
|
+
if (savedBatchProjectRoot !== undefined) {
|
|
535
|
+
process.env.KSPEC_BATCH_PROJECT_ROOT = savedBatchProjectRoot;
|
|
536
|
+
}
|
|
537
|
+
else {
|
|
538
|
+
delete process.env.KSPEC_BATCH_PROJECT_ROOT;
|
|
539
|
+
}
|
|
540
|
+
// Only remove temp dir if copy-back succeeded (or commands failed)
|
|
541
|
+
if (!copyBackFailed) {
|
|
542
|
+
await fs.rm(tempDir, { recursive: true, force: true }).catch(() => { });
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
const succeeded = results.filter((r) => r.success).length;
|
|
546
|
+
const failed = results.filter((r) => !r.success).length;
|
|
547
|
+
return {
|
|
548
|
+
success: allSucceeded,
|
|
549
|
+
mode: "atomic",
|
|
550
|
+
summary: { total: commands.length, succeeded, failed },
|
|
551
|
+
results,
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Immediate execution: execute against real state, per-command commits.
|
|
556
|
+
*
|
|
557
|
+
* AC: @batch-exec ac-no-atomic-flag
|
|
558
|
+
* AC: @batch-exec ac-immediate-per-commit
|
|
559
|
+
* AC: @batch-exec ac-immediate-no-rollback
|
|
560
|
+
*/
|
|
561
|
+
async function executeImmediate(commands, program, tree, options) {
|
|
562
|
+
const savedChalkLevel = chalk.level;
|
|
563
|
+
chalk.level = 0;
|
|
564
|
+
const results = [];
|
|
565
|
+
try {
|
|
566
|
+
for (let i = 0; i < commands.length; i++) {
|
|
567
|
+
const cmd = commands[i];
|
|
568
|
+
const result = await dispatchCommand(cmd, i, program, tree);
|
|
569
|
+
results.push(result);
|
|
570
|
+
if (!result.success && !options.continueOnError) {
|
|
571
|
+
// Stop on first failure, remaining not executed
|
|
572
|
+
for (let j = i + 1; j < commands.length; j++) {
|
|
573
|
+
results.push({
|
|
574
|
+
index: j,
|
|
575
|
+
id: commands[j].id,
|
|
576
|
+
command: commands[j].command,
|
|
577
|
+
success: false,
|
|
578
|
+
error: "Not executed (prior command failed)",
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
break;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
finally {
|
|
586
|
+
chalk.level = savedChalkLevel;
|
|
587
|
+
}
|
|
588
|
+
const succeeded = results.filter((r) => r.success).length;
|
|
589
|
+
const failed = results.filter((r) => !r.success).length;
|
|
590
|
+
return {
|
|
591
|
+
success: failed === 0,
|
|
592
|
+
mode: "immediate",
|
|
593
|
+
summary: { total: commands.length, succeeded, failed },
|
|
594
|
+
results,
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Dispatch a single command through Commander's parseAsync.
|
|
599
|
+
*/
|
|
600
|
+
async function dispatchCommand(cmd, index, program, tree) {
|
|
601
|
+
const parts = cmd.command.trim().split(/\s+/);
|
|
602
|
+
const cmdMeta = findCommand(tree, parts);
|
|
603
|
+
if (!cmdMeta) {
|
|
604
|
+
return {
|
|
605
|
+
index,
|
|
606
|
+
id: cmd.id,
|
|
607
|
+
command: cmd.command,
|
|
608
|
+
success: false,
|
|
609
|
+
error: `Command not found: ${cmd.command}`,
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
// Build argv, auto-appending --force if supported
|
|
613
|
+
// AC: ac-confirmation-suppressed
|
|
614
|
+
const enrichedCmd = { ...cmd, args: { ...cmd.args } };
|
|
615
|
+
if (commandHasForce(cmdMeta) && !("force" in enrichedCmd.args)) {
|
|
616
|
+
enrichedCmd.args.force = true;
|
|
617
|
+
}
|
|
618
|
+
const argv = buildCommandArgv(enrichedCmd, cmdMeta);
|
|
619
|
+
// Reset Commander state
|
|
620
|
+
resetCommandTree(program);
|
|
621
|
+
setJsonMode(false);
|
|
622
|
+
setVerboseMode(false);
|
|
623
|
+
const capture = new OutputCapture();
|
|
624
|
+
capture.start();
|
|
625
|
+
installExitInterceptor();
|
|
626
|
+
let caughtError = undefined;
|
|
627
|
+
let succeeded = false;
|
|
628
|
+
try {
|
|
629
|
+
await program.parseAsync(argv, { from: "user" });
|
|
630
|
+
succeeded = true;
|
|
631
|
+
}
|
|
632
|
+
catch (err) {
|
|
633
|
+
caughtError = err;
|
|
634
|
+
}
|
|
635
|
+
finally {
|
|
636
|
+
capture.stop();
|
|
637
|
+
uninstallExitInterceptor();
|
|
638
|
+
}
|
|
639
|
+
if (succeeded) {
|
|
640
|
+
const output = capture.getOutput();
|
|
641
|
+
// Try to parse output as JSON for structured results
|
|
642
|
+
let parsedOutput = output;
|
|
643
|
+
try {
|
|
644
|
+
parsedOutput = JSON.parse(output);
|
|
645
|
+
}
|
|
646
|
+
catch {
|
|
647
|
+
// Not JSON, keep as string
|
|
648
|
+
}
|
|
649
|
+
return {
|
|
650
|
+
index,
|
|
651
|
+
id: cmd.id,
|
|
652
|
+
command: cmd.command,
|
|
653
|
+
success: true,
|
|
654
|
+
output: parsedOutput,
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
// Handle errors
|
|
658
|
+
const err = caughtError;
|
|
659
|
+
if (err instanceof BatchExitError) {
|
|
660
|
+
// Filter out BatchExitError noise from captured output (handlers may
|
|
661
|
+
// catch and re-log the error before calling process.exit again)
|
|
662
|
+
const capturedOutput = capture
|
|
663
|
+
.getOutput()
|
|
664
|
+
.split("\n")
|
|
665
|
+
.filter((line) => !line.includes("BatchExitError"))
|
|
666
|
+
.join("\n")
|
|
667
|
+
.trim();
|
|
668
|
+
if (err.code === 0) {
|
|
669
|
+
return {
|
|
670
|
+
index,
|
|
671
|
+
id: cmd.id,
|
|
672
|
+
command: cmd.command,
|
|
673
|
+
success: true,
|
|
674
|
+
output: capturedOutput,
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
return {
|
|
678
|
+
index,
|
|
679
|
+
id: cmd.id,
|
|
680
|
+
command: cmd.command,
|
|
681
|
+
success: false,
|
|
682
|
+
error: capturedOutput || `Command exited with code ${err.code}`,
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
// Commander errors (e.g., missing required arg at runtime)
|
|
686
|
+
const isCommanderError = err && typeof err === "object" && "code" in err && "exitCode" in err;
|
|
687
|
+
if (isCommanderError) {
|
|
688
|
+
const cmdErr = err;
|
|
689
|
+
return {
|
|
690
|
+
index,
|
|
691
|
+
id: cmd.id,
|
|
692
|
+
command: cmd.command,
|
|
693
|
+
success: false,
|
|
694
|
+
error: cmdErr.message || capture.getOutput(),
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
// Generic errors
|
|
698
|
+
return {
|
|
699
|
+
index,
|
|
700
|
+
id: cmd.id,
|
|
701
|
+
command: cmd.command,
|
|
702
|
+
success: false,
|
|
703
|
+
error: err instanceof Error ? err.message : String(err),
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
//# sourceMappingURL=batch-exec.js.map
|