@kynetic-ai/spec 0.1.2 → 0.3.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 +116 -0
- package/dist/cli/batch-exec.d.ts.map +1 -0
- package/dist/cli/batch-exec.js +694 -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 +140 -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 +57 -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 +533 -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 +516 -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 +1097 -169
- 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 +811 -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 +1233 -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 +53 -0
- package/dist/cli/commands/skill-install.d.ts.map +1 -0
- package/dist/cli/commands/skill-install.js +452 -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 +569 -346
- 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 +227 -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 +569 -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 +235 -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 +468 -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 +351 -0
- package/dist/parser/config.d.ts.map +1 -0
- package/dist/parser/config.js +326 -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 +189 -0
- package/dist/parser/plan-document.d.ts.map +1 -0
- package/dist/parser/plan-document.js +340 -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 +277 -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 +83 -0
- package/dist/ralph/subagent.d.ts.map +1 -0
- package/dist/ralph/subagent.js +174 -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 +95 -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 +2 -2
- package/dist/schema/common.d.ts.map +1 -1
- package/dist/schema/common.js +34 -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 +233 -1
- package/dist/sessions/store.d.ts.map +1 -1
- package/dist/sessions/store.js +628 -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 +51 -0
- package/dist/strings/errors.d.ts.map +1 -1
- package/dist/strings/errors.js +136 -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/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/help/SKILL.md +42 -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/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/help/SKILL.md +37 -0
- package/templates/skills/manifest.yaml +15 -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
|
@@ -7,54 +7,63 @@
|
|
|
7
7
|
* AC-agent-1: kspec meta agents outputs table
|
|
8
8
|
* AC-agent-2: kspec meta agents --json outputs JSON
|
|
9
9
|
*/
|
|
10
|
-
import chalk from
|
|
11
|
-
import Table from
|
|
12
|
-
import { ulid } from
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
10
|
+
import chalk from "chalk";
|
|
11
|
+
import Table from "cli-table3";
|
|
12
|
+
import { ulid } from "ulid";
|
|
13
|
+
import { markMutating } from "../command-annotations.js";
|
|
14
|
+
import { createObservation, createTask, deleteInboxItem, deleteMetaItem, findInboxItemByRef, getMetaStats, initContext, loadAllItems, loadAllTasks, loadInboxItems, loadMetaContext, loadSessionContext, ReferenceIndex, resolveMetaRef, saveMetaItem, saveObservation, saveSessionContext, saveTask, } from "../../parser/index.js";
|
|
15
|
+
import { commitIfShadow } from "../../parser/shadow.js";
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
import { WorkflowStepSchema, } from "../../schema/index.js";
|
|
18
|
+
import { errors } from "../../strings/errors.js";
|
|
19
|
+
import { executeBatchOperation, formatBatchOutput } from "../batch.js";
|
|
20
|
+
import { EXIT_CODES } from "../exit-codes.js";
|
|
21
|
+
import { error, isJsonMode, output, success } from "../output.js";
|
|
22
|
+
import { parseTagsArray } from "../parse-utils.js";
|
|
23
|
+
import { parseIntOption } from "../validators.js";
|
|
18
24
|
/**
|
|
19
|
-
* Resolve a meta reference to its ULID
|
|
20
|
-
*
|
|
25
|
+
* Resolve a meta reference to its ULID and type.
|
|
26
|
+
* Wrapper around resolveMetaRef for backward compatibility with existing call sites.
|
|
27
|
+
* AC: @skill-meta-integration ac-4 - skills included in resolution
|
|
21
28
|
*/
|
|
22
29
|
function resolveMetaRefToUlid(ref, metaCtx) {
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return null;
|
|
30
|
+
const result = resolveMetaRef(metaCtx, ref);
|
|
31
|
+
if (!result)
|
|
32
|
+
return null;
|
|
33
|
+
return { ulid: result.ulid, type: result.type };
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Batch-compatible resolver for observations.
|
|
37
|
+
* Returns null instead of calling process.exit() to allow partial failure handling.
|
|
38
|
+
* AC: @trait-multi-ref-batch ac-2, ac-8 - Partial failure handling and ref resolution
|
|
39
|
+
*/
|
|
40
|
+
function resolveObservationRefForBatch(ref, observations) {
|
|
41
|
+
const normalizedRef = ref.startsWith("@") ? ref.substring(1) : ref;
|
|
42
|
+
const observation = observations.find((o) => o._ulid.startsWith(normalizedRef));
|
|
43
|
+
if (!observation) {
|
|
44
|
+
return { item: null, error: `Observation not found: ${ref}` };
|
|
45
|
+
}
|
|
46
|
+
return { item: observation };
|
|
41
47
|
}
|
|
42
48
|
/**
|
|
43
49
|
* Format meta show output
|
|
50
|
+
* AC: @skill-meta-integration ac-3 - skill count included in summary
|
|
44
51
|
*/
|
|
45
52
|
function formatMetaShow(meta) {
|
|
46
53
|
const stats = getMetaStats(meta);
|
|
47
54
|
if (!meta.manifest) {
|
|
48
|
-
console.log(chalk.yellow(
|
|
49
|
-
console.log(chalk.gray(
|
|
55
|
+
console.log(chalk.yellow("No meta manifest found (kynetic.meta.yaml)"));
|
|
56
|
+
console.log(chalk.gray("Create one to define agents, workflows, conventions, observations, and skills"));
|
|
50
57
|
return;
|
|
51
58
|
}
|
|
52
|
-
console.log(chalk.bold(
|
|
53
|
-
console.log(chalk.gray(
|
|
59
|
+
console.log(chalk.bold("Meta-Spec Summary"));
|
|
60
|
+
console.log(chalk.gray("─".repeat(40)));
|
|
54
61
|
console.log(`Agents: ${stats.agents}`);
|
|
55
62
|
console.log(`Workflows: ${stats.workflows}`);
|
|
56
63
|
console.log(`Conventions: ${stats.conventions}`);
|
|
57
64
|
console.log(`Observations: ${stats.observations} (${stats.unresolvedObservations} unresolved)`);
|
|
65
|
+
// AC: @skill-meta-integration ac-3 - include skill count
|
|
66
|
+
console.log(`Skills: ${stats.skills}`);
|
|
58
67
|
}
|
|
59
68
|
/**
|
|
60
69
|
* Format agents table output
|
|
@@ -62,36 +71,37 @@ function formatMetaShow(meta) {
|
|
|
62
71
|
*/
|
|
63
72
|
function formatAgents(agents) {
|
|
64
73
|
if (agents.length === 0) {
|
|
65
|
-
console.log(chalk.yellow(
|
|
74
|
+
console.log(chalk.yellow("No agents defined"));
|
|
66
75
|
return;
|
|
67
76
|
}
|
|
68
77
|
const table = new Table({
|
|
69
|
-
head: [chalk.bold(
|
|
78
|
+
head: [chalk.bold("ID"), chalk.bold("Name"), chalk.bold("Capabilities")],
|
|
70
79
|
style: {
|
|
71
80
|
head: [],
|
|
72
81
|
border: [],
|
|
73
82
|
},
|
|
74
83
|
});
|
|
75
84
|
for (const agent of agents) {
|
|
76
|
-
table.push([
|
|
77
|
-
agent.id,
|
|
78
|
-
agent.name,
|
|
79
|
-
agent.capabilities.join(', '),
|
|
80
|
-
]);
|
|
85
|
+
table.push([agent.id, agent.name, agent.capabilities.join(", ")]);
|
|
81
86
|
}
|
|
82
87
|
console.log(table.toString());
|
|
83
88
|
}
|
|
84
89
|
/**
|
|
85
90
|
* Format workflows table output
|
|
86
|
-
* AC-workflow-1: outputs table with columns: ID, Trigger, Steps (count)
|
|
91
|
+
* AC-workflow-1: outputs table with columns: ID, Trigger, Steps (count), Mode
|
|
87
92
|
*/
|
|
88
93
|
function formatWorkflows(workflows) {
|
|
89
94
|
if (workflows.length === 0) {
|
|
90
|
-
console.log(chalk.yellow(
|
|
95
|
+
console.log(chalk.yellow("No workflows defined"));
|
|
91
96
|
return;
|
|
92
97
|
}
|
|
93
98
|
const table = new Table({
|
|
94
|
-
head: [
|
|
99
|
+
head: [
|
|
100
|
+
chalk.bold("ID"),
|
|
101
|
+
chalk.bold("Trigger"),
|
|
102
|
+
chalk.bold("Steps"),
|
|
103
|
+
chalk.bold("Mode"),
|
|
104
|
+
],
|
|
95
105
|
style: {
|
|
96
106
|
head: [],
|
|
97
107
|
border: [],
|
|
@@ -102,6 +112,7 @@ function formatWorkflows(workflows) {
|
|
|
102
112
|
workflow.id,
|
|
103
113
|
workflow.trigger,
|
|
104
114
|
workflow.steps.length.toString(),
|
|
115
|
+
workflow.mode || "interactive",
|
|
105
116
|
]);
|
|
106
117
|
}
|
|
107
118
|
console.log(table.toString());
|
|
@@ -109,23 +120,32 @@ function formatWorkflows(workflows) {
|
|
|
109
120
|
/**
|
|
110
121
|
* Format workflows verbose output
|
|
111
122
|
* AC-workflow-2: outputs each workflow with full step list
|
|
123
|
+
* AC: @loop-mode-workflows ac-3 (shows based_on field)
|
|
112
124
|
*/
|
|
113
125
|
function formatWorkflowsVerbose(workflows) {
|
|
114
126
|
if (workflows.length === 0) {
|
|
115
|
-
console.log(chalk.yellow(
|
|
127
|
+
console.log(chalk.yellow("No workflows defined"));
|
|
116
128
|
return;
|
|
117
129
|
}
|
|
118
130
|
for (const workflow of workflows) {
|
|
119
131
|
console.log(chalk.bold(`${workflow.id} - ${workflow.trigger}`));
|
|
132
|
+
// Show mode if it's loop (skip for interactive as it's default)
|
|
133
|
+
if (workflow.mode === "loop") {
|
|
134
|
+
console.log(chalk.cyan(`Mode: ${workflow.mode}`));
|
|
135
|
+
}
|
|
136
|
+
// AC: @loop-mode-workflows ac-3 - Show based_on reference
|
|
137
|
+
if (workflow.based_on) {
|
|
138
|
+
console.log(chalk.cyan(`Based on: ${workflow.based_on}`));
|
|
139
|
+
}
|
|
120
140
|
if (workflow.description) {
|
|
121
141
|
console.log(chalk.gray(workflow.description));
|
|
122
142
|
}
|
|
123
|
-
console.log(chalk.gray(
|
|
143
|
+
console.log(chalk.gray("─".repeat(60)));
|
|
124
144
|
for (const step of workflow.steps) {
|
|
125
145
|
const prefix = {
|
|
126
|
-
check: chalk.yellow(
|
|
127
|
-
action: chalk.blue(
|
|
128
|
-
decision: chalk.magenta(
|
|
146
|
+
check: chalk.yellow("[check]"),
|
|
147
|
+
action: chalk.blue("[action]"),
|
|
148
|
+
decision: chalk.magenta("[decision]"),
|
|
129
149
|
}[step.type];
|
|
130
150
|
console.log(`${prefix} ${step.content}`);
|
|
131
151
|
if (step.on_fail) {
|
|
@@ -137,7 +157,7 @@ function formatWorkflowsVerbose(workflows) {
|
|
|
137
157
|
}
|
|
138
158
|
}
|
|
139
159
|
}
|
|
140
|
-
console.log(
|
|
160
|
+
console.log("");
|
|
141
161
|
}
|
|
142
162
|
}
|
|
143
163
|
/**
|
|
@@ -146,11 +166,11 @@ function formatWorkflowsVerbose(workflows) {
|
|
|
146
166
|
*/
|
|
147
167
|
function formatConventions(conventions) {
|
|
148
168
|
if (conventions.length === 0) {
|
|
149
|
-
console.log(chalk.yellow(
|
|
169
|
+
console.log(chalk.yellow("No conventions defined"));
|
|
150
170
|
return;
|
|
151
171
|
}
|
|
152
172
|
const table = new Table({
|
|
153
|
-
head: [chalk.bold(
|
|
173
|
+
head: [chalk.bold("Domain"), chalk.bold("Rules"), chalk.bold("Validation")],
|
|
154
174
|
style: {
|
|
155
175
|
head: [],
|
|
156
176
|
border: [],
|
|
@@ -160,7 +180,7 @@ function formatConventions(conventions) {
|
|
|
160
180
|
table.push([
|
|
161
181
|
convention.domain,
|
|
162
182
|
convention.rules.length.toString(),
|
|
163
|
-
convention.validation ?
|
|
183
|
+
convention.validation ? "yes" : "no",
|
|
164
184
|
]);
|
|
165
185
|
}
|
|
166
186
|
console.log(table.toString());
|
|
@@ -171,20 +191,20 @@ function formatConventions(conventions) {
|
|
|
171
191
|
*/
|
|
172
192
|
function formatConventionDetail(convention) {
|
|
173
193
|
console.log(chalk.bold(`${convention.domain} Convention`));
|
|
174
|
-
console.log(chalk.gray(
|
|
175
|
-
console.log(chalk.bold(
|
|
194
|
+
console.log(chalk.gray("─".repeat(60)));
|
|
195
|
+
console.log(chalk.bold("\nRules:"));
|
|
176
196
|
for (const rule of convention.rules) {
|
|
177
197
|
console.log(` • ${rule}`);
|
|
178
198
|
}
|
|
179
199
|
if (convention.examples && convention.examples.length > 0) {
|
|
180
|
-
console.log(chalk.bold(
|
|
200
|
+
console.log(chalk.bold("\nExamples:"));
|
|
181
201
|
for (const example of convention.examples) {
|
|
182
202
|
console.log(chalk.green(` ✓ ${example.good}`));
|
|
183
203
|
console.log(chalk.red(` ✗ ${example.bad}`));
|
|
184
204
|
}
|
|
185
205
|
}
|
|
186
206
|
if (convention.validation) {
|
|
187
|
-
console.log(chalk.bold(
|
|
207
|
+
console.log(chalk.bold("\nValidation:"));
|
|
188
208
|
console.log(` Type: ${convention.validation.type}`);
|
|
189
209
|
if (convention.validation.pattern) {
|
|
190
210
|
console.log(` Pattern: ${convention.validation.pattern}`);
|
|
@@ -193,39 +213,69 @@ function formatConventionDetail(convention) {
|
|
|
193
213
|
console.log(` Message: ${convention.validation.message}`);
|
|
194
214
|
}
|
|
195
215
|
}
|
|
196
|
-
console.log(
|
|
216
|
+
console.log("");
|
|
197
217
|
}
|
|
198
218
|
/**
|
|
199
219
|
* Format observations table output
|
|
200
220
|
* AC-obs-2: outputs table with columns: ID, Type, Workflow, Created, Content (truncated)
|
|
221
|
+
* AC: @obs-list-display ac-1 - When --all flag used, show Resolved column with ✓/✗
|
|
201
222
|
*/
|
|
202
223
|
function formatObservations(observations, showResolved) {
|
|
203
|
-
const filtered = showResolved
|
|
224
|
+
const filtered = showResolved
|
|
225
|
+
? observations
|
|
226
|
+
: observations.filter((o) => !o.resolved);
|
|
204
227
|
if (filtered.length === 0) {
|
|
205
|
-
console.log(chalk.yellow(showResolved ?
|
|
228
|
+
console.log(chalk.yellow(showResolved ? "No observations found" : "No unresolved observations"));
|
|
206
229
|
return;
|
|
207
230
|
}
|
|
231
|
+
// AC: @obs-list-display ac-1 - Include Resolved column when showing all observations
|
|
232
|
+
const headers = showResolved
|
|
233
|
+
? [
|
|
234
|
+
chalk.bold("ID"),
|
|
235
|
+
chalk.bold("Type"),
|
|
236
|
+
chalk.bold("Resolved"),
|
|
237
|
+
chalk.bold("Workflow"),
|
|
238
|
+
chalk.bold("Created"),
|
|
239
|
+
chalk.bold("Content"),
|
|
240
|
+
]
|
|
241
|
+
: [
|
|
242
|
+
chalk.bold("ID"),
|
|
243
|
+
chalk.bold("Type"),
|
|
244
|
+
chalk.bold("Workflow"),
|
|
245
|
+
chalk.bold("Created"),
|
|
246
|
+
chalk.bold("Content"),
|
|
247
|
+
];
|
|
248
|
+
const colWidths = showResolved
|
|
249
|
+
? [10, 10, 10, 20, 12, 40]
|
|
250
|
+
: [10, 10, 20, 12, 50];
|
|
208
251
|
const table = new Table({
|
|
209
|
-
head:
|
|
210
|
-
chalk.bold('ID'),
|
|
211
|
-
chalk.bold('Type'),
|
|
212
|
-
chalk.bold('Workflow'),
|
|
213
|
-
chalk.bold('Created'),
|
|
214
|
-
chalk.bold('Content'),
|
|
215
|
-
],
|
|
252
|
+
head: headers,
|
|
216
253
|
style: {
|
|
217
254
|
head: [],
|
|
218
255
|
border: [],
|
|
219
256
|
},
|
|
220
|
-
colWidths
|
|
257
|
+
colWidths,
|
|
221
258
|
wordWrap: true,
|
|
222
259
|
});
|
|
223
260
|
for (const obs of filtered) {
|
|
224
261
|
const id = obs._ulid.substring(0, 8);
|
|
225
|
-
const workflow = obs.workflow_ref ||
|
|
226
|
-
const created = new Date(obs.created_at).toISOString().split(
|
|
227
|
-
|
|
228
|
-
|
|
262
|
+
const workflow = obs.workflow_ref || "-";
|
|
263
|
+
const created = new Date(obs.created_at).toISOString().split("T")[0];
|
|
264
|
+
// Adjust content truncation based on available column width
|
|
265
|
+
const maxContentLen = showResolved ? 37 : 47;
|
|
266
|
+
const content = obs.content.length > maxContentLen
|
|
267
|
+
? `${obs.content.substring(0, maxContentLen)}...`
|
|
268
|
+
: obs.content;
|
|
269
|
+
// AC: @obs-list-display ac-1 - Show ✓ for resolved, ✗ for unresolved
|
|
270
|
+
if (showResolved) {
|
|
271
|
+
const resolvedIndicator = obs.resolved
|
|
272
|
+
? chalk.green("✓")
|
|
273
|
+
: chalk.red("✗");
|
|
274
|
+
table.push([id, obs.type, resolvedIndicator, workflow, created, content]);
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
table.push([id, obs.type, workflow, created, content]);
|
|
278
|
+
}
|
|
229
279
|
}
|
|
230
280
|
console.log(table.toString());
|
|
231
281
|
}
|
|
@@ -234,12 +284,12 @@ function formatObservations(observations, showResolved) {
|
|
|
234
284
|
*/
|
|
235
285
|
export function registerMetaCommands(program) {
|
|
236
286
|
const meta = program
|
|
237
|
-
.command(
|
|
238
|
-
.description(
|
|
287
|
+
.command("meta")
|
|
288
|
+
.description("Meta-spec commands (agents, workflows, conventions, observations)");
|
|
239
289
|
// AC-meta-manifest-1: kspec meta show outputs summary with counts
|
|
240
290
|
meta
|
|
241
|
-
.command(
|
|
242
|
-
.description(
|
|
291
|
+
.command("show")
|
|
292
|
+
.description("Display meta-spec summary")
|
|
243
293
|
.action(async () => {
|
|
244
294
|
try {
|
|
245
295
|
const ctx = await initContext();
|
|
@@ -261,8 +311,8 @@ export function registerMetaCommands(program) {
|
|
|
261
311
|
});
|
|
262
312
|
// AC-agent-1, AC-agent-2: kspec meta agents
|
|
263
313
|
meta
|
|
264
|
-
.command(
|
|
265
|
-
.description(
|
|
314
|
+
.command("agents")
|
|
315
|
+
.description("List agents defined in meta-spec")
|
|
266
316
|
.action(async () => {
|
|
267
317
|
try {
|
|
268
318
|
const ctx = await initContext();
|
|
@@ -291,10 +341,12 @@ export function registerMetaCommands(program) {
|
|
|
291
341
|
}
|
|
292
342
|
});
|
|
293
343
|
// AC-workflow-1, AC-workflow-2, AC-workflow-4: kspec meta workflows
|
|
344
|
+
// AC: @loop-mode-workflows ac-1 (--tag loop filtering)
|
|
294
345
|
meta
|
|
295
|
-
.command(
|
|
296
|
-
.description(
|
|
297
|
-
.option(
|
|
346
|
+
.command("workflows")
|
|
347
|
+
.description("List workflows defined in meta-spec")
|
|
348
|
+
.option("--verbose", "Show full workflow details with all steps")
|
|
349
|
+
.option("--tag <tag>", "Filter workflows by tag (e.g., --tag loop)")
|
|
298
350
|
.action(async (options) => {
|
|
299
351
|
try {
|
|
300
352
|
const ctx = await initContext();
|
|
@@ -303,13 +355,29 @@ export function registerMetaCommands(program) {
|
|
|
303
355
|
process.exit(EXIT_CODES.ERROR);
|
|
304
356
|
}
|
|
305
357
|
const metaCtx = await loadMetaContext(ctx);
|
|
306
|
-
|
|
358
|
+
let workflows = metaCtx.workflows || [];
|
|
359
|
+
// AC: @loop-mode-workflows ac-1 - Filter by tag
|
|
360
|
+
if (options.tag) {
|
|
361
|
+
workflows = workflows.filter((w) => {
|
|
362
|
+
// Match by explicit tags array or by mode field (for "loop" tag)
|
|
363
|
+
const tags = w.tags || [];
|
|
364
|
+
if (tags.includes(options.tag))
|
|
365
|
+
return true;
|
|
366
|
+
// Special case: --tag loop also matches mode: loop
|
|
367
|
+
if (options.tag === "loop" && w.mode === "loop")
|
|
368
|
+
return true;
|
|
369
|
+
return false;
|
|
370
|
+
});
|
|
371
|
+
}
|
|
307
372
|
// AC-workflow-4: JSON output includes full workflow details
|
|
308
373
|
output(workflows.map((workflow) => ({
|
|
309
374
|
id: workflow.id,
|
|
310
375
|
trigger: workflow.trigger,
|
|
311
376
|
description: workflow.description,
|
|
312
377
|
steps: workflow.steps,
|
|
378
|
+
mode: workflow.mode || "interactive",
|
|
379
|
+
based_on: workflow.based_on,
|
|
380
|
+
tags: workflow.tags || [],
|
|
313
381
|
})),
|
|
314
382
|
// AC-workflow-1 (table) or AC-workflow-2 (verbose)
|
|
315
383
|
() => {
|
|
@@ -328,9 +396,9 @@ export function registerMetaCommands(program) {
|
|
|
328
396
|
});
|
|
329
397
|
// AC-conv-1, AC-conv-2, AC-conv-5: kspec meta conventions
|
|
330
398
|
meta
|
|
331
|
-
.command(
|
|
332
|
-
.description(
|
|
333
|
-
.option(
|
|
399
|
+
.command("conventions")
|
|
400
|
+
.description("List conventions defined in meta-spec")
|
|
401
|
+
.option("--domain <domain>", "Filter by specific domain")
|
|
334
402
|
.action(async (options) => {
|
|
335
403
|
try {
|
|
336
404
|
const ctx = await initContext();
|
|
@@ -367,9 +435,10 @@ export function registerMetaCommands(program) {
|
|
|
367
435
|
}
|
|
368
436
|
});
|
|
369
437
|
// meta-get-cmd: kspec meta get <ref>
|
|
438
|
+
// AC: @skill-meta-integration ac-1 - skills can be retrieved by id
|
|
370
439
|
meta
|
|
371
|
-
.command(
|
|
372
|
-
.description(
|
|
440
|
+
.command("get <ref>")
|
|
441
|
+
.description("Get a meta item by reference (agent, workflow, convention, observation, or skill)")
|
|
373
442
|
.action(async (ref) => {
|
|
374
443
|
try {
|
|
375
444
|
const ctx = await initContext();
|
|
@@ -378,54 +447,17 @@ export function registerMetaCommands(program) {
|
|
|
378
447
|
process.exit(EXIT_CODES.ERROR);
|
|
379
448
|
}
|
|
380
449
|
const metaCtx = await loadMetaContext(ctx);
|
|
381
|
-
//
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
const agents = metaCtx.agents || [];
|
|
385
|
-
const workflows = metaCtx.workflows || [];
|
|
386
|
-
const conventions = metaCtx.conventions || [];
|
|
387
|
-
const observations = metaCtx.observations || [];
|
|
388
|
-
// Try to find by ID or ULID prefix
|
|
389
|
-
let found = null;
|
|
390
|
-
let itemType = '';
|
|
391
|
-
// Check agents (by id or ULID)
|
|
392
|
-
const agent = agents.find((a) => a.id === normalizedRef || a._ulid.startsWith(normalizedRef));
|
|
393
|
-
if (agent) {
|
|
394
|
-
found = agent;
|
|
395
|
-
itemType = 'agent';
|
|
396
|
-
}
|
|
397
|
-
// Check workflows (by id or ULID)
|
|
398
|
-
if (!found) {
|
|
399
|
-
const workflow = workflows.find((w) => w.id === normalizedRef || w._ulid.startsWith(normalizedRef));
|
|
400
|
-
if (workflow) {
|
|
401
|
-
found = workflow;
|
|
402
|
-
itemType = 'workflow';
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
// Check conventions (by domain or ULID)
|
|
406
|
-
if (!found) {
|
|
407
|
-
const convention = conventions.find((c) => c.domain === normalizedRef || c._ulid.startsWith(normalizedRef));
|
|
408
|
-
if (convention) {
|
|
409
|
-
found = convention;
|
|
410
|
-
itemType = 'convention';
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
// Check observations (by ULID)
|
|
414
|
-
if (!found) {
|
|
415
|
-
const observation = observations.find((o) => o._ulid.startsWith(normalizedRef));
|
|
416
|
-
if (observation) {
|
|
417
|
-
found = observation;
|
|
418
|
-
itemType = 'observation';
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
if (!found) {
|
|
450
|
+
// AC: @skill-meta-integration ac-1 - Use unified resolver
|
|
451
|
+
const resolved = resolveMetaRef(metaCtx, ref);
|
|
452
|
+
if (!resolved) {
|
|
422
453
|
error(errors.reference.metaNotFound(ref));
|
|
423
454
|
process.exit(EXIT_CODES.ERROR);
|
|
424
455
|
}
|
|
456
|
+
const { item: found, type: itemType } = resolved;
|
|
425
457
|
// Output the item
|
|
426
458
|
output(found, () => {
|
|
427
459
|
console.log(chalk.bold(`${itemType.charAt(0).toUpperCase() + itemType.slice(1)}: ${ref}`));
|
|
428
|
-
console.log(chalk.gray(
|
|
460
|
+
console.log(chalk.gray("─".repeat(60)));
|
|
429
461
|
console.log(JSON.stringify(found, null, 2));
|
|
430
462
|
});
|
|
431
463
|
}
|
|
@@ -435,10 +467,11 @@ export function registerMetaCommands(program) {
|
|
|
435
467
|
}
|
|
436
468
|
});
|
|
437
469
|
// meta-list-cmd: kspec meta list
|
|
470
|
+
// AC: @skill-meta-integration ac-2 - skills can be filtered with --type skill
|
|
438
471
|
meta
|
|
439
|
-
.command(
|
|
440
|
-
.description(
|
|
441
|
-
.option(
|
|
472
|
+
.command("list")
|
|
473
|
+
.description("List all meta items")
|
|
474
|
+
.option("--type <type>", "Filter by type (agent, workflow, convention, observation, skill)")
|
|
442
475
|
.action(async (options) => {
|
|
443
476
|
try {
|
|
444
477
|
const ctx = await initContext();
|
|
@@ -449,58 +482,69 @@ export function registerMetaCommands(program) {
|
|
|
449
482
|
const metaCtx = await loadMetaContext(ctx);
|
|
450
483
|
const items = [];
|
|
451
484
|
// Add agents
|
|
452
|
-
if (!options.type || options.type ===
|
|
485
|
+
if (!options.type || options.type === "agent") {
|
|
453
486
|
for (const agent of metaCtx.agents || []) {
|
|
454
487
|
items.push({
|
|
455
488
|
id: agent.id,
|
|
456
|
-
type:
|
|
489
|
+
type: "agent",
|
|
457
490
|
context: agent.name,
|
|
458
491
|
ulid: agent._ulid,
|
|
459
492
|
});
|
|
460
493
|
}
|
|
461
494
|
}
|
|
462
495
|
// Add workflows
|
|
463
|
-
if (!options.type || options.type ===
|
|
496
|
+
if (!options.type || options.type === "workflow") {
|
|
464
497
|
for (const workflow of metaCtx.workflows || []) {
|
|
465
498
|
items.push({
|
|
466
499
|
id: workflow.id,
|
|
467
|
-
type:
|
|
500
|
+
type: "workflow",
|
|
468
501
|
context: workflow.trigger,
|
|
469
502
|
ulid: workflow._ulid,
|
|
470
503
|
});
|
|
471
504
|
}
|
|
472
505
|
}
|
|
473
506
|
// Add conventions
|
|
474
|
-
if (!options.type || options.type ===
|
|
507
|
+
if (!options.type || options.type === "convention") {
|
|
475
508
|
for (const convention of metaCtx.conventions || []) {
|
|
476
509
|
items.push({
|
|
477
510
|
id: convention.domain,
|
|
478
|
-
type:
|
|
511
|
+
type: "convention",
|
|
479
512
|
context: `${convention.rules.length} rules`,
|
|
480
513
|
ulid: convention._ulid,
|
|
481
514
|
});
|
|
482
515
|
}
|
|
483
516
|
}
|
|
484
517
|
// Add observations
|
|
485
|
-
if (!options.type || options.type ===
|
|
518
|
+
if (!options.type || options.type === "observation") {
|
|
486
519
|
for (const observation of metaCtx.observations || []) {
|
|
487
520
|
const ulidPrefix = observation._ulid.substring(0, 8);
|
|
488
521
|
items.push({
|
|
489
522
|
id: ulidPrefix,
|
|
490
|
-
type:
|
|
491
|
-
context: `${observation.type} ${observation.resolved ?
|
|
523
|
+
type: "observation",
|
|
524
|
+
context: `${observation.type} ${observation.resolved ? "(resolved)" : ""}`,
|
|
492
525
|
ulid: observation._ulid,
|
|
493
526
|
});
|
|
494
527
|
}
|
|
495
528
|
}
|
|
529
|
+
// AC: @skill-meta-integration ac-2 - Add skills
|
|
530
|
+
if (!options.type || options.type === "skill") {
|
|
531
|
+
for (const skill of metaCtx.skills || []) {
|
|
532
|
+
items.push({
|
|
533
|
+
id: skill.id,
|
|
534
|
+
type: "skill",
|
|
535
|
+
context: skill.name || skill.description || skill.origin,
|
|
536
|
+
ulid: skill._ulid,
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
}
|
|
496
540
|
// Output
|
|
497
541
|
output(items, () => {
|
|
498
542
|
if (items.length === 0) {
|
|
499
|
-
console.log(chalk.yellow(
|
|
543
|
+
console.log(chalk.yellow("No meta items found"));
|
|
500
544
|
return;
|
|
501
545
|
}
|
|
502
546
|
const table = new Table({
|
|
503
|
-
head: [chalk.bold(
|
|
547
|
+
head: [chalk.bold("ID"), chalk.bold("Type"), chalk.bold("Context")],
|
|
504
548
|
style: {
|
|
505
549
|
head: [],
|
|
506
550
|
border: [],
|
|
@@ -519,13 +563,12 @@ export function registerMetaCommands(program) {
|
|
|
519
563
|
});
|
|
520
564
|
// AC-obs-1: kspec meta observe <type> <content>
|
|
521
565
|
// AC: @meta-observe-cmd from-inbox-conversion
|
|
522
|
-
meta
|
|
523
|
-
.
|
|
524
|
-
.
|
|
525
|
-
.option(
|
|
526
|
-
.option(
|
|
527
|
-
.option(
|
|
528
|
-
.option('--type <type>', 'Override type when using --from-inbox (defaults to idea)')
|
|
566
|
+
markMutating(meta.command("observe [type] [content]"))
|
|
567
|
+
.description("Create an observation (friction, success, question, idea)")
|
|
568
|
+
.option("--workflow <ref>", "Reference to workflow this observation relates to")
|
|
569
|
+
.option("--author <author>", "Author of the observation")
|
|
570
|
+
.option("--from-inbox <ref>", "Convert inbox item to observation")
|
|
571
|
+
.option("--type <type>", "Override type when using --from-inbox (defaults to idea)")
|
|
529
572
|
.action(async (type, content, options) => {
|
|
530
573
|
try {
|
|
531
574
|
const ctx = await initContext();
|
|
@@ -546,51 +589,65 @@ export function registerMetaCommands(program) {
|
|
|
546
589
|
// Use inbox item content
|
|
547
590
|
const observationContent = item.text;
|
|
548
591
|
// Type defaults to 'idea' but can be overridden with --type flag
|
|
549
|
-
const observationType = (options.type ||
|
|
592
|
+
const observationType = (options.type || "idea");
|
|
550
593
|
// Validate observation type
|
|
551
|
-
const validTypes = [
|
|
594
|
+
const validTypes = [
|
|
595
|
+
"friction",
|
|
596
|
+
"success",
|
|
597
|
+
"question",
|
|
598
|
+
"idea",
|
|
599
|
+
];
|
|
552
600
|
if (!validTypes.includes(observationType)) {
|
|
553
601
|
error(errors.validation.invalidObservationType(observationType));
|
|
554
|
-
console.log(`Valid types: ${validTypes.join(
|
|
602
|
+
console.log(`Valid types: ${validTypes.join(", ")}`);
|
|
555
603
|
process.exit(EXIT_CODES.ERROR);
|
|
556
604
|
}
|
|
557
605
|
// Create observation
|
|
558
606
|
const observation = createObservation(observationType, observationContent, {
|
|
559
607
|
workflow_ref: options.workflow,
|
|
560
608
|
author: options.author,
|
|
609
|
+
configAuthor: ctx.config?.identity?.author,
|
|
561
610
|
});
|
|
562
611
|
// Save observation
|
|
563
612
|
await saveObservation(ctx, observation);
|
|
564
613
|
// Delete inbox item
|
|
565
614
|
const deleted = await deleteInboxItem(ctx, item._ulid);
|
|
566
615
|
if (!deleted) {
|
|
567
|
-
error(
|
|
616
|
+
error("Failed to delete inbox item after creating observation");
|
|
568
617
|
process.exit(EXIT_CODES.ERROR);
|
|
569
618
|
}
|
|
570
|
-
await commitIfShadow(ctx.shadow,
|
|
619
|
+
await commitIfShadow(ctx.shadow, "meta-observe-from-inbox", observation._ulid.substring(0, 8), `Convert inbox item to ${observationType} observation`);
|
|
571
620
|
// Return observation ref
|
|
572
621
|
output(observation, () => success(`Created observation: ${observation._ulid.substring(0, 8)}`));
|
|
573
622
|
return;
|
|
574
623
|
}
|
|
575
624
|
// Standard observe flow (without --from-inbox)
|
|
576
625
|
if (!type || !content) {
|
|
577
|
-
error(
|
|
626
|
+
error("Type and content are required when not using --from-inbox");
|
|
578
627
|
process.exit(EXIT_CODES.ERROR);
|
|
579
628
|
}
|
|
580
629
|
// Validate observation type
|
|
581
|
-
const validTypes = [
|
|
630
|
+
const validTypes = [
|
|
631
|
+
"friction",
|
|
632
|
+
"success",
|
|
633
|
+
"question",
|
|
634
|
+
"idea",
|
|
635
|
+
];
|
|
582
636
|
if (!validTypes.includes(type)) {
|
|
583
637
|
error(errors.validation.invalidObservationType(type));
|
|
584
|
-
console.log(`Valid types: ${validTypes.join(
|
|
638
|
+
console.log(`Valid types: ${validTypes.join(", ")}`);
|
|
585
639
|
process.exit(EXIT_CODES.ERROR);
|
|
586
640
|
}
|
|
587
641
|
// Create observation
|
|
588
642
|
const observation = createObservation(type, content, {
|
|
589
643
|
workflow_ref: options.workflow,
|
|
590
644
|
author: options.author,
|
|
645
|
+
configAuthor: ctx.config?.identity?.author,
|
|
591
646
|
});
|
|
592
647
|
// Save to manifest
|
|
593
648
|
await saveObservation(ctx, observation);
|
|
649
|
+
// AC: @trait-shadow-commit ac-1
|
|
650
|
+
await commitIfShadow(ctx.shadow, "meta-observe", observation._ulid.substring(0, 8), type);
|
|
594
651
|
// AC-obs-1: outputs "OK Created observation: <ULID-prefix>"
|
|
595
652
|
// In JSON mode, return the created observation object
|
|
596
653
|
output(observation, () => success(`Created observation: ${observation._ulid.substring(0, 8)}`));
|
|
@@ -601,14 +658,16 @@ export function registerMetaCommands(program) {
|
|
|
601
658
|
}
|
|
602
659
|
});
|
|
603
660
|
// AC-obs-2, AC-obs-5: kspec meta observations
|
|
661
|
+
// AC: @observation-content-search ac-search-flag, ac-regex-support, ac-combined-filters
|
|
604
662
|
meta
|
|
605
|
-
.command(
|
|
606
|
-
.description(
|
|
607
|
-
.option(
|
|
608
|
-
.option(
|
|
609
|
-
.option(
|
|
610
|
-
.option(
|
|
611
|
-
.option(
|
|
663
|
+
.command("observations")
|
|
664
|
+
.description("List observations (shows unresolved by default)")
|
|
665
|
+
.option("--type <type>", "Filter by observation type (friction/success/question/idea)")
|
|
666
|
+
.option("--workflow <ref>", "Filter by workflow reference")
|
|
667
|
+
.option("--all", "Include resolved observations")
|
|
668
|
+
.option("--promoted", "Show only observations promoted to tasks")
|
|
669
|
+
.option("--pending-resolution", "Show observations with completed tasks awaiting resolution")
|
|
670
|
+
.option("--search <pattern>", "Search observations by regex pattern (matches content)")
|
|
612
671
|
.action(async (options) => {
|
|
613
672
|
try {
|
|
614
673
|
const ctx = await initContext();
|
|
@@ -641,7 +700,18 @@ export function registerMetaCommands(program) {
|
|
|
641
700
|
return false;
|
|
642
701
|
const item = taskResult.item;
|
|
643
702
|
// Type guard: check if item is a task (has status and depends_on properties)
|
|
644
|
-
return
|
|
703
|
+
return ("status" in item &&
|
|
704
|
+
"depends_on" in item &&
|
|
705
|
+
item.status === "completed");
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
// AC: @observation-content-search ac-search-flag, ac-regex-support, ac-combined-filters, ac-search-all-fields
|
|
709
|
+
// Apply --search filter using regex pattern (consistent with kspec search behavior)
|
|
710
|
+
if (options.search) {
|
|
711
|
+
const { grepItem } = await import("../../utils/grep.js");
|
|
712
|
+
observations = observations.filter((obs) => {
|
|
713
|
+
const match = grepItem(obs, options.search);
|
|
714
|
+
return match !== null;
|
|
645
715
|
});
|
|
646
716
|
}
|
|
647
717
|
// AC-obs-5: JSON output includes full observation objects
|
|
@@ -667,12 +737,11 @@ export function registerMetaCommands(program) {
|
|
|
667
737
|
}
|
|
668
738
|
});
|
|
669
739
|
// AC-obs-3, AC-obs-6, AC-obs-8: kspec meta promote
|
|
670
|
-
meta
|
|
671
|
-
.
|
|
672
|
-
.
|
|
673
|
-
.
|
|
674
|
-
.option(
|
|
675
|
-
.option('--force', 'Force promotion even if observation is resolved')
|
|
740
|
+
markMutating(meta.command("promote <ref>"))
|
|
741
|
+
.description("Promote observation to a task")
|
|
742
|
+
.requiredOption("--title <title>", "Task title")
|
|
743
|
+
.option("--priority <priority>", "Task priority (1-5)", "2")
|
|
744
|
+
.option("--force", "Force promotion even if observation is resolved")
|
|
676
745
|
.action(async (ref, options) => {
|
|
677
746
|
try {
|
|
678
747
|
const ctx = await initContext();
|
|
@@ -681,14 +750,17 @@ export function registerMetaCommands(program) {
|
|
|
681
750
|
process.exit(EXIT_CODES.ERROR);
|
|
682
751
|
}
|
|
683
752
|
const metaCtx = await loadMetaContext(ctx);
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
const observation = observations.find((o) => o._ulid.startsWith(normalizedRef));
|
|
688
|
-
if (!observation) {
|
|
753
|
+
// Use unified resolver - promotes only observations
|
|
754
|
+
const resolved = resolveMetaRef(metaCtx, ref);
|
|
755
|
+
if (!resolved) {
|
|
689
756
|
error(errors.reference.observationNotFound(ref));
|
|
690
757
|
process.exit(EXIT_CODES.ERROR);
|
|
691
758
|
}
|
|
759
|
+
if (resolved.type !== "observation") {
|
|
760
|
+
error(`Cannot promote ${resolved.type}. Only observations can be promoted to tasks.`);
|
|
761
|
+
process.exit(EXIT_CODES.ERROR);
|
|
762
|
+
}
|
|
763
|
+
const observation = resolved.item;
|
|
692
764
|
// AC-obs-6: Check if already promoted
|
|
693
765
|
if (observation.promoted_to) {
|
|
694
766
|
error(errors.conflict.observationAlreadyPromoted(observation.promoted_to));
|
|
@@ -699,21 +771,33 @@ export function registerMetaCommands(program) {
|
|
|
699
771
|
error(errors.operation.cannotPromoteResolved);
|
|
700
772
|
process.exit(EXIT_CODES.ERROR);
|
|
701
773
|
}
|
|
774
|
+
// Validate priority
|
|
775
|
+
const priorityResult = parseIntOption(options.priority, {
|
|
776
|
+
min: 1,
|
|
777
|
+
max: 5,
|
|
778
|
+
name: "Priority",
|
|
779
|
+
});
|
|
780
|
+
if (!priorityResult.ok) {
|
|
781
|
+
error(priorityResult.error);
|
|
782
|
+
process.exit(EXIT_CODES.VALIDATION_FAILED);
|
|
783
|
+
}
|
|
702
784
|
// AC-obs-3: Create task with title, description from observation, meta_ref, and origin
|
|
703
785
|
const task = createTask({
|
|
704
786
|
title: options.title,
|
|
705
787
|
description: observation.content,
|
|
706
|
-
priority:
|
|
788
|
+
priority: priorityResult.value,
|
|
707
789
|
meta_ref: observation.workflow_ref,
|
|
708
|
-
origin:
|
|
790
|
+
origin: "observation_promotion",
|
|
709
791
|
});
|
|
710
792
|
// Save task
|
|
711
793
|
await saveTask(ctx, task);
|
|
712
|
-
await commitIfShadow(ctx.shadow,
|
|
794
|
+
await commitIfShadow(ctx.shadow, "task-add", task.slugs[0] || task._ulid.slice(0, 8), task.title);
|
|
713
795
|
const taskRef = `@${task._ulid.substring(0, 8)}`;
|
|
714
796
|
// Update observation with promoted_to field
|
|
715
797
|
observation.promoted_to = taskRef;
|
|
716
798
|
await saveObservation(ctx, observation);
|
|
799
|
+
// AC: @trait-shadow-commit ac-1
|
|
800
|
+
await commitIfShadow(ctx.shadow, "observation-promote", observation._ulid.substring(0, 8));
|
|
717
801
|
// AC-obs-3: outputs "OK Created task: <ULID-prefix>"
|
|
718
802
|
// In JSON mode, return the created task object
|
|
719
803
|
output(task, () => success(`Created task: ${taskRef.substring(0, 9)}`));
|
|
@@ -724,10 +808,16 @@ export function registerMetaCommands(program) {
|
|
|
724
808
|
}
|
|
725
809
|
});
|
|
726
810
|
// AC-obs-4, AC-obs-7, AC-obs-9: kspec meta resolve
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
.description(
|
|
730
|
-
.
|
|
811
|
+
// AC: @trait-multi-ref-batch - Batch support with --refs flag
|
|
812
|
+
markMutating(meta.command("resolve [ref] [resolution]"))
|
|
813
|
+
.description("Resolve an observation (or multiple with --refs)")
|
|
814
|
+
.option("--refs <refs...>", "Resolve multiple observations by ref")
|
|
815
|
+
.option("--resolution <text>", "Resolution text (required for batch mode unless observations have promoted tasks)")
|
|
816
|
+
.addHelpText("after", `
|
|
817
|
+
Examples:
|
|
818
|
+
$ kspec meta resolve @obs-ref "Fixed in PR #123"
|
|
819
|
+
$ kspec meta resolve --refs @obs1 @obs2 --resolution "Resolved in batch"`)
|
|
820
|
+
.action(async (ref, resolutionArg, options) => {
|
|
731
821
|
try {
|
|
732
822
|
const ctx = await initContext();
|
|
733
823
|
if (!ctx.manifestPath) {
|
|
@@ -736,69 +826,100 @@ export function registerMetaCommands(program) {
|
|
|
736
826
|
}
|
|
737
827
|
const metaCtx = await loadMetaContext(ctx);
|
|
738
828
|
const observations = metaCtx.observations || [];
|
|
739
|
-
//
|
|
740
|
-
const
|
|
741
|
-
const
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
829
|
+
// Load tasks/items for auto-resolution from promoted tasks
|
|
830
|
+
const tasks = await loadAllTasks(ctx);
|
|
831
|
+
const items = await loadAllItems(ctx);
|
|
832
|
+
const index = new ReferenceIndex(tasks, items);
|
|
833
|
+
// Resolution can come from positional arg or --resolution flag
|
|
834
|
+
const resolution = resolutionArg || options.resolution;
|
|
835
|
+
// AC: @trait-multi-ref-batch ac-8 - Deduplicate refs
|
|
836
|
+
const refsFlag = options.refs
|
|
837
|
+
? [...new Set(options.refs)]
|
|
838
|
+
: undefined;
|
|
839
|
+
// AC: @trait-multi-ref-batch ac-1, ac-2, ac-3, ac-4, ac-5
|
|
840
|
+
const result = await executeBatchOperation({
|
|
841
|
+
positionalRef: ref,
|
|
842
|
+
refsFlag,
|
|
843
|
+
context: { ctx, observations, tasks, items, index, resolution },
|
|
844
|
+
items: observations,
|
|
845
|
+
index: index,
|
|
846
|
+
resolveRef: (refStr, obsList) => {
|
|
847
|
+
return resolveObservationRefForBatch(refStr, obsList);
|
|
848
|
+
},
|
|
849
|
+
executeOperation: async (observation, { ctx, tasks, items, index, resolution }) => {
|
|
850
|
+
// AC-obs-7: Check if already resolved
|
|
851
|
+
if (observation.resolved) {
|
|
852
|
+
const resolvedDate = new Date(observation.resolved_at)
|
|
853
|
+
.toISOString()
|
|
854
|
+
.split("T")[0];
|
|
855
|
+
const resolutionText = observation.resolution || "";
|
|
856
|
+
const truncated = resolutionText.length > 50
|
|
857
|
+
? `${resolutionText.substring(0, 50)}...`
|
|
858
|
+
: resolutionText;
|
|
859
|
+
return {
|
|
860
|
+
success: false,
|
|
861
|
+
error: `Already resolved on ${resolvedDate}: ${truncated}`,
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
// AC-obs-9: Auto-populate resolution from task completion if promoted
|
|
865
|
+
let finalResolution = resolution;
|
|
866
|
+
if (!finalResolution && observation.promoted_to) {
|
|
867
|
+
const taskResult = index.resolve(observation.promoted_to);
|
|
868
|
+
if (taskResult.ok) {
|
|
869
|
+
const item = taskResult.item;
|
|
870
|
+
// Type guard: ensure this is a task
|
|
871
|
+
if ("status" in item && "depends_on" in item) {
|
|
872
|
+
const task = item;
|
|
873
|
+
if (task.status === "completed" && task.closed_reason) {
|
|
874
|
+
finalResolution = `Resolved via task ${observation.promoted_to}: ${task.closed_reason}`;
|
|
875
|
+
}
|
|
876
|
+
else if (task.status === "completed") {
|
|
877
|
+
finalResolution = `Resolved via task ${observation.promoted_to}`;
|
|
878
|
+
}
|
|
879
|
+
else {
|
|
880
|
+
return {
|
|
881
|
+
success: false,
|
|
882
|
+
error: `Task ${observation.promoted_to} is not completed yet`,
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
else {
|
|
887
|
+
return {
|
|
888
|
+
success: false,
|
|
889
|
+
error: `Reference ${observation.promoted_to} is not a task`,
|
|
890
|
+
};
|
|
891
|
+
}
|
|
774
892
|
}
|
|
775
893
|
else {
|
|
776
|
-
|
|
777
|
-
|
|
894
|
+
return {
|
|
895
|
+
success: false,
|
|
896
|
+
error: `Task ${observation.promoted_to} not found`,
|
|
897
|
+
};
|
|
778
898
|
}
|
|
779
899
|
}
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
900
|
+
if (!finalResolution) {
|
|
901
|
+
return {
|
|
902
|
+
success: false,
|
|
903
|
+
error: "Resolution text required",
|
|
904
|
+
};
|
|
783
905
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
success(`Resolved: ${observation._ulid.substring(0, 8)}`);
|
|
906
|
+
// AC-obs-4: Update observation
|
|
907
|
+
observation.resolved = true;
|
|
908
|
+
observation.resolution = finalResolution;
|
|
909
|
+
observation.resolved_at = new Date().toISOString();
|
|
910
|
+
observation.resolved_by = observation.author;
|
|
911
|
+
await saveObservation(ctx, observation);
|
|
912
|
+
// AC: @trait-shadow-commit ac-1
|
|
913
|
+
await commitIfShadow(ctx.shadow, "observation-resolve", observation._ulid.substring(0, 8));
|
|
914
|
+
return {
|
|
915
|
+
success: true,
|
|
916
|
+
message: `Resolved: ${observation._ulid.substring(0, 8)}`,
|
|
917
|
+
};
|
|
918
|
+
},
|
|
919
|
+
getUlid: (obs) => obs._ulid,
|
|
920
|
+
});
|
|
921
|
+
// AC: @trait-multi-ref-batch ac-5, ac-7 - Output formatting
|
|
922
|
+
formatBatchOutput(result, "Resolve");
|
|
802
923
|
}
|
|
803
924
|
catch (err) {
|
|
804
925
|
error(errors.failures.resolveObservation, err);
|
|
@@ -806,23 +927,31 @@ export function registerMetaCommands(program) {
|
|
|
806
927
|
}
|
|
807
928
|
});
|
|
808
929
|
// Meta add command - create new meta items
|
|
809
|
-
meta
|
|
810
|
-
.
|
|
811
|
-
.
|
|
812
|
-
.option(
|
|
813
|
-
.option(
|
|
814
|
-
.option(
|
|
815
|
-
.option(
|
|
816
|
-
.option(
|
|
817
|
-
.option(
|
|
818
|
-
.option(
|
|
819
|
-
.option(
|
|
820
|
-
.option(
|
|
930
|
+
markMutating(meta.command("add <type>"))
|
|
931
|
+
.description("Create a new meta item (agent, workflow, or convention)")
|
|
932
|
+
.option("--id <id>", "Semantic ID (required for agents and workflows)")
|
|
933
|
+
.option("--domain <domain>", "Domain (required for conventions)")
|
|
934
|
+
.option("--name <name>", "Name (for agents)")
|
|
935
|
+
.option("--trigger <trigger>", "Trigger (for workflows)")
|
|
936
|
+
.option("--description <desc>", "Description")
|
|
937
|
+
.option("--capability <cap...>", "Capabilities (for agents)")
|
|
938
|
+
.option("--tool <tool...>", "Tools (for agents)")
|
|
939
|
+
.option("--convention <conv...>", "Convention references (for agents)")
|
|
940
|
+
.option("--rule <rule...>", "Rules (for conventions)")
|
|
941
|
+
.option("--steps <json>", "Workflow steps as JSON array (for workflows)")
|
|
942
|
+
.option("--mode <mode>", "Workflow mode: interactive (default) or loop (for workflows)")
|
|
943
|
+
.option("--based-on <ref>", "Base workflow reference (for loop workflows)")
|
|
944
|
+
.option("--tag <tag...>", "Tags for the workflow (for workflows)")
|
|
945
|
+
.addHelpText("after", `
|
|
946
|
+
Examples:
|
|
947
|
+
$ kspec meta add agent --id my-agent --name "My Agent" --capability search code
|
|
948
|
+
$ kspec meta add convention --domain testing --rule "Always test" --rule "Use mocks"
|
|
949
|
+
$ kspec meta add workflow --id my-flow --trigger manual --tag automation ci`)
|
|
821
950
|
.action(async (type, options) => {
|
|
822
951
|
try {
|
|
823
952
|
const ctx = await initContext();
|
|
824
953
|
// Validate type
|
|
825
|
-
const validTypes = [
|
|
954
|
+
const validTypes = ["agent", "workflow", "convention"];
|
|
826
955
|
if (!validTypes.includes(type)) {
|
|
827
956
|
error(errors.validation.invalidType(type, validTypes));
|
|
828
957
|
process.exit(EXIT_CODES.ERROR);
|
|
@@ -831,7 +960,7 @@ export function registerMetaCommands(program) {
|
|
|
831
960
|
const itemUlid = ulid();
|
|
832
961
|
// Create the item based on type
|
|
833
962
|
let item;
|
|
834
|
-
if (type ===
|
|
963
|
+
if (type === "agent") {
|
|
835
964
|
// Validate required fields
|
|
836
965
|
if (!options.id) {
|
|
837
966
|
error(errors.validation.agentRequiresId);
|
|
@@ -845,13 +974,13 @@ export function registerMetaCommands(program) {
|
|
|
845
974
|
_ulid: itemUlid,
|
|
846
975
|
id: options.id,
|
|
847
976
|
name: options.name,
|
|
848
|
-
description: options.description ||
|
|
977
|
+
description: options.description || "",
|
|
849
978
|
capabilities: options.capability || [],
|
|
850
979
|
tools: options.tool || [],
|
|
851
980
|
conventions: options.convention || [],
|
|
852
981
|
};
|
|
853
982
|
}
|
|
854
|
-
else if (type ===
|
|
983
|
+
else if (type === "workflow") {
|
|
855
984
|
// Validate required fields
|
|
856
985
|
if (!options.id) {
|
|
857
986
|
error(errors.validation.workflowRequiresId);
|
|
@@ -861,12 +990,50 @@ export function registerMetaCommands(program) {
|
|
|
861
990
|
error(errors.validation.workflowRequiresTrigger);
|
|
862
991
|
process.exit(EXIT_CODES.ERROR);
|
|
863
992
|
}
|
|
993
|
+
// Parse and validate --steps if provided
|
|
994
|
+
let steps = [];
|
|
995
|
+
if (options.steps) {
|
|
996
|
+
// AC: @meta-add-cmd ac-2 - Parse JSON
|
|
997
|
+
let parsedSteps;
|
|
998
|
+
try {
|
|
999
|
+
parsedSteps = JSON.parse(options.steps);
|
|
1000
|
+
}
|
|
1001
|
+
catch (err) {
|
|
1002
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1003
|
+
error(errors.validation.invalidStepsJson(message));
|
|
1004
|
+
process.exit(EXIT_CODES.ERROR);
|
|
1005
|
+
}
|
|
1006
|
+
// AC: @meta-add-cmd ac-3 - Verify it's an array
|
|
1007
|
+
if (!Array.isArray(parsedSteps)) {
|
|
1008
|
+
error(errors.validation.stepsNotArray);
|
|
1009
|
+
process.exit(EXIT_CODES.ERROR);
|
|
1010
|
+
}
|
|
1011
|
+
// AC: @meta-add-cmd ac-4 - Validate with schema
|
|
1012
|
+
const result = z.array(WorkflowStepSchema).safeParse(parsedSteps);
|
|
1013
|
+
if (!result.success) {
|
|
1014
|
+
const issues = result.error.issues
|
|
1015
|
+
.map((i) => `${i.path.join(".")}: ${i.message}`)
|
|
1016
|
+
.join("; ");
|
|
1017
|
+
error(errors.validation.invalidStepsSchema(issues));
|
|
1018
|
+
process.exit(EXIT_CODES.ERROR);
|
|
1019
|
+
}
|
|
1020
|
+
steps = result.data;
|
|
1021
|
+
}
|
|
1022
|
+
// Validate mode if provided
|
|
1023
|
+
const validModes = ["interactive", "loop"];
|
|
1024
|
+
if (options.mode && !validModes.includes(options.mode)) {
|
|
1025
|
+
error(`Invalid mode: ${options.mode}. Valid modes: ${validModes.join(", ")}`);
|
|
1026
|
+
process.exit(EXIT_CODES.ERROR);
|
|
1027
|
+
}
|
|
864
1028
|
item = {
|
|
865
1029
|
_ulid: itemUlid,
|
|
866
1030
|
id: options.id,
|
|
867
1031
|
trigger: options.trigger,
|
|
868
|
-
description: options.description ||
|
|
869
|
-
steps
|
|
1032
|
+
description: options.description || "",
|
|
1033
|
+
steps,
|
|
1034
|
+
...(options.mode && { mode: options.mode }),
|
|
1035
|
+
...(options.basedOn && { based_on: options.basedOn }),
|
|
1036
|
+
...(options.tag && options.tag.length > 0 && { tags: parseTagsArray(options.tag) }),
|
|
870
1037
|
};
|
|
871
1038
|
}
|
|
872
1039
|
else {
|
|
@@ -884,12 +1051,14 @@ export function registerMetaCommands(program) {
|
|
|
884
1051
|
}
|
|
885
1052
|
// Save the item
|
|
886
1053
|
await saveMetaItem(ctx, item, type);
|
|
1054
|
+
// AC: @trait-shadow-commit ac-1
|
|
1055
|
+
await commitIfShadow(ctx.shadow, `meta-add-${type}`, itemUlid.substring(0, 8), "id" in item ? item.id : "domain" in item ? item.domain : undefined);
|
|
887
1056
|
if (isJsonMode()) {
|
|
888
1057
|
// In JSON mode, output the item data directly
|
|
889
1058
|
console.log(JSON.stringify(item, null, 2));
|
|
890
1059
|
}
|
|
891
1060
|
else {
|
|
892
|
-
const idOrDomain =
|
|
1061
|
+
const idOrDomain = "id" in item ? item.id : "domain" in item ? item.domain : itemUlid;
|
|
893
1062
|
success(`Created ${type}: ${idOrDomain} (@${itemUlid.substring(0, 8)})`);
|
|
894
1063
|
}
|
|
895
1064
|
}
|
|
@@ -899,55 +1068,35 @@ export function registerMetaCommands(program) {
|
|
|
899
1068
|
}
|
|
900
1069
|
});
|
|
901
1070
|
// Meta set command - update existing meta items
|
|
902
|
-
meta
|
|
903
|
-
.
|
|
904
|
-
.
|
|
905
|
-
.option(
|
|
906
|
-
.option(
|
|
907
|
-
.option(
|
|
908
|
-
.option(
|
|
909
|
-
.option(
|
|
910
|
-
.option(
|
|
911
|
-
.option('--add-rule <rule>', 'Add rule (for conventions)')
|
|
1071
|
+
markMutating(meta.command("set <ref>"))
|
|
1072
|
+
.description("Update an existing meta item")
|
|
1073
|
+
.option("--name <name>", "Update name (for agents)")
|
|
1074
|
+
.option("--description <desc>", "Update description")
|
|
1075
|
+
.option("--trigger <trigger>", "Update trigger (for workflows)")
|
|
1076
|
+
.option("--add-capability <cap>", "Add capability (for agents)")
|
|
1077
|
+
.option("--add-tool <tool>", "Add tool (for agents)")
|
|
1078
|
+
.option("--add-convention <conv>", "Add convention reference (for agents)")
|
|
1079
|
+
.option("--add-rule <rule>", "Add rule (for conventions)")
|
|
912
1080
|
.action(async (ref, options) => {
|
|
913
1081
|
try {
|
|
914
1082
|
const ctx = await initContext();
|
|
915
1083
|
const metaCtx = await loadMetaContext(ctx);
|
|
916
|
-
//
|
|
917
|
-
const
|
|
918
|
-
|
|
919
|
-
let itemType = null;
|
|
920
|
-
// Search in agents
|
|
921
|
-
const agents = metaCtx.manifest?.agents || [];
|
|
922
|
-
const agent = agents.find((a) => a.id === normalizedRef || a._ulid.startsWith(normalizedRef));
|
|
923
|
-
if (agent) {
|
|
924
|
-
found = agent;
|
|
925
|
-
itemType = 'agent';
|
|
926
|
-
}
|
|
927
|
-
// Search in workflows
|
|
928
|
-
if (!found) {
|
|
929
|
-
const workflows = metaCtx.manifest?.workflows || [];
|
|
930
|
-
const workflow = workflows.find((w) => w.id === normalizedRef || w._ulid.startsWith(normalizedRef));
|
|
931
|
-
if (workflow) {
|
|
932
|
-
found = workflow;
|
|
933
|
-
itemType = 'workflow';
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
// Search in conventions
|
|
937
|
-
if (!found) {
|
|
938
|
-
const conventions = metaCtx.manifest?.conventions || [];
|
|
939
|
-
const convention = conventions.find((c) => c.domain === normalizedRef || c._ulid.startsWith(normalizedRef));
|
|
940
|
-
if (convention) {
|
|
941
|
-
found = convention;
|
|
942
|
-
itemType = 'convention';
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
if (!found || !itemType) {
|
|
1084
|
+
// Use unified resolver
|
|
1085
|
+
const resolved = resolveMetaRef(metaCtx, ref);
|
|
1086
|
+
if (!resolved) {
|
|
946
1087
|
error(errors.reference.metaNotFound(ref));
|
|
947
1088
|
process.exit(EXIT_CODES.ERROR);
|
|
948
1089
|
}
|
|
1090
|
+
// meta set only supports agent, workflow, convention
|
|
1091
|
+
// Skills have their own `kspec skill set` command
|
|
1092
|
+
const { item, type: itemType } = resolved;
|
|
1093
|
+
if (itemType !== "agent" && itemType !== "workflow" && itemType !== "convention") {
|
|
1094
|
+
error(`Cannot use 'meta set' with ${itemType}. Use 'kspec ${itemType === "skill" ? "skill" : "meta"} ${itemType === "observation" ? "resolve" : "set"} ${ref}' instead.`);
|
|
1095
|
+
process.exit(EXIT_CODES.ERROR);
|
|
1096
|
+
}
|
|
1097
|
+
const found = item;
|
|
949
1098
|
// Update fields based on type
|
|
950
|
-
if (itemType ===
|
|
1099
|
+
if (itemType === "agent") {
|
|
951
1100
|
const item = found;
|
|
952
1101
|
if (options.name)
|
|
953
1102
|
item.name = options.name;
|
|
@@ -969,7 +1118,7 @@ export function registerMetaCommands(program) {
|
|
|
969
1118
|
}
|
|
970
1119
|
}
|
|
971
1120
|
}
|
|
972
|
-
else if (itemType ===
|
|
1121
|
+
else if (itemType === "workflow") {
|
|
973
1122
|
const item = found;
|
|
974
1123
|
if (options.trigger)
|
|
975
1124
|
item.trigger = options.trigger;
|
|
@@ -987,14 +1136,16 @@ export function registerMetaCommands(program) {
|
|
|
987
1136
|
}
|
|
988
1137
|
// Save the updated item
|
|
989
1138
|
await saveMetaItem(ctx, found, itemType);
|
|
1139
|
+
// AC: @trait-shadow-commit ac-1
|
|
1140
|
+
await commitIfShadow(ctx.shadow, `meta-set-${itemType}`, found._ulid.substring(0, 8));
|
|
990
1141
|
if (isJsonMode()) {
|
|
991
1142
|
// In JSON mode, output the item data directly
|
|
992
1143
|
console.log(JSON.stringify(found, null, 2));
|
|
993
1144
|
}
|
|
994
1145
|
else {
|
|
995
|
-
const idOrDomain = itemType ===
|
|
1146
|
+
const idOrDomain = itemType === "agent"
|
|
996
1147
|
? found.id
|
|
997
|
-
: itemType ===
|
|
1148
|
+
: itemType === "workflow"
|
|
998
1149
|
? found.id
|
|
999
1150
|
: found.domain;
|
|
1000
1151
|
success(`Updated ${itemType}: ${idOrDomain}`);
|
|
@@ -1006,60 +1157,40 @@ export function registerMetaCommands(program) {
|
|
|
1006
1157
|
}
|
|
1007
1158
|
});
|
|
1008
1159
|
// Meta delete command - delete meta items
|
|
1009
|
-
meta
|
|
1010
|
-
.
|
|
1011
|
-
.
|
|
1012
|
-
.option('--confirm', 'Skip confirmation prompt')
|
|
1160
|
+
markMutating(meta.command("delete <ref>"))
|
|
1161
|
+
.description("Delete a meta item")
|
|
1162
|
+
.option("--confirm", "Skip confirmation prompt")
|
|
1013
1163
|
.action(async (ref, options) => {
|
|
1014
1164
|
try {
|
|
1015
1165
|
const ctx = await initContext();
|
|
1016
1166
|
const metaCtx = await loadMetaContext(ctx);
|
|
1017
|
-
//
|
|
1018
|
-
const
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
// Search in agents
|
|
1023
|
-
const agents = metaCtx.manifest?.agents || [];
|
|
1024
|
-
const agent = agents.find((a) => a.id === normalizedRef || a._ulid.startsWith(normalizedRef));
|
|
1025
|
-
if (agent) {
|
|
1026
|
-
itemType = 'agent';
|
|
1027
|
-
itemUlid = agent._ulid;
|
|
1028
|
-
itemLabel = `agent ${agent.id}`;
|
|
1029
|
-
}
|
|
1030
|
-
// Search in workflows
|
|
1031
|
-
if (!itemType) {
|
|
1032
|
-
const workflows = metaCtx.manifest?.workflows || [];
|
|
1033
|
-
const workflow = workflows.find((w) => w.id === normalizedRef || w._ulid.startsWith(normalizedRef));
|
|
1034
|
-
if (workflow) {
|
|
1035
|
-
itemType = 'workflow';
|
|
1036
|
-
itemUlid = workflow._ulid;
|
|
1037
|
-
itemLabel = `workflow ${workflow.id}`;
|
|
1038
|
-
}
|
|
1167
|
+
// Use unified resolver
|
|
1168
|
+
const resolved = resolveMetaRef(metaCtx, ref);
|
|
1169
|
+
if (!resolved) {
|
|
1170
|
+
error(errors.reference.metaNotFound(ref));
|
|
1171
|
+
process.exit(EXIT_CODES.ERROR);
|
|
1039
1172
|
}
|
|
1040
|
-
//
|
|
1041
|
-
if (
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
if (convention) {
|
|
1045
|
-
itemType = 'convention';
|
|
1046
|
-
itemUlid = convention._ulid;
|
|
1047
|
-
itemLabel = `convention ${convention.domain}`;
|
|
1048
|
-
}
|
|
1173
|
+
// meta delete does not support skills - they use `kspec skill delete`
|
|
1174
|
+
if (resolved.type === "skill") {
|
|
1175
|
+
error(`Cannot use 'meta delete' with skills. Use 'kspec skill delete ${ref}' instead.`);
|
|
1176
|
+
process.exit(EXIT_CODES.ERROR);
|
|
1049
1177
|
}
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
itemLabel = `observation ${observation._ulid.substring(0, 8)}`;
|
|
1058
|
-
}
|
|
1178
|
+
const itemType = resolved.type;
|
|
1179
|
+
const itemUlid = resolved.ulid;
|
|
1180
|
+
// Build human-readable label for the item
|
|
1181
|
+
let itemLabel;
|
|
1182
|
+
const item = resolved.item;
|
|
1183
|
+
if (itemType === "agent" && "id" in item) {
|
|
1184
|
+
itemLabel = `agent ${item.id}`;
|
|
1059
1185
|
}
|
|
1060
|
-
if (
|
|
1061
|
-
|
|
1062
|
-
|
|
1186
|
+
else if (itemType === "workflow" && "id" in item) {
|
|
1187
|
+
itemLabel = `workflow ${item.id}`;
|
|
1188
|
+
}
|
|
1189
|
+
else if (itemType === "convention" && "domain" in item) {
|
|
1190
|
+
itemLabel = `convention ${item.domain}`;
|
|
1191
|
+
}
|
|
1192
|
+
else {
|
|
1193
|
+
itemLabel = `observation ${itemUlid.substring(0, 8)}`;
|
|
1063
1194
|
}
|
|
1064
1195
|
// Check for dangling references (unless --confirm is used to override)
|
|
1065
1196
|
if (!options.confirm) {
|
|
@@ -1076,12 +1207,12 @@ export function registerMetaCommands(program) {
|
|
|
1076
1207
|
if (referencingTasks.length > 0) {
|
|
1077
1208
|
const taskRefs = referencingTasks
|
|
1078
1209
|
.map((t) => `@${t.slugs?.[0] || t._ulid.substring(0, 8)}`)
|
|
1079
|
-
.join(
|
|
1210
|
+
.join(", ");
|
|
1080
1211
|
error(errors.operation.cannotDeleteReferencedByTasks(itemLabel, referencingTasks.length, taskRefs));
|
|
1081
1212
|
process.exit(EXIT_CODES.ERROR);
|
|
1082
1213
|
}
|
|
1083
1214
|
// Check observations with workflow_ref (only for workflows)
|
|
1084
|
-
if (itemType ===
|
|
1215
|
+
if (itemType === "workflow") {
|
|
1085
1216
|
const observations = metaCtx.observations || [];
|
|
1086
1217
|
const referencingObservations = observations.filter((o) => {
|
|
1087
1218
|
if (!o.workflow_ref)
|
|
@@ -1094,7 +1225,7 @@ export function registerMetaCommands(program) {
|
|
|
1094
1225
|
if (referencingObservations.length > 0) {
|
|
1095
1226
|
const obsRefs = referencingObservations
|
|
1096
1227
|
.map((o) => `@${o._ulid.substring(0, 8)}`)
|
|
1097
|
-
.join(
|
|
1228
|
+
.join(", ");
|
|
1098
1229
|
error(errors.operation.cannotDeleteReferencedByObservations(itemLabel, referencingObservations.length, obsRefs));
|
|
1099
1230
|
process.exit(EXIT_CODES.ERROR);
|
|
1100
1231
|
}
|
|
@@ -1109,6 +1240,8 @@ export function registerMetaCommands(program) {
|
|
|
1109
1240
|
error(errors.operation.deleteItemFailed(itemLabel));
|
|
1110
1241
|
process.exit(EXIT_CODES.ERROR);
|
|
1111
1242
|
}
|
|
1243
|
+
// AC: @trait-shadow-commit ac-1
|
|
1244
|
+
await commitIfShadow(ctx.shadow, `meta-delete-${itemType}`, itemUlid.substring(0, 8));
|
|
1112
1245
|
success(`Deleted ${itemLabel}`);
|
|
1113
1246
|
}
|
|
1114
1247
|
catch (err) {
|
|
@@ -1117,10 +1250,9 @@ export function registerMetaCommands(program) {
|
|
|
1117
1250
|
}
|
|
1118
1251
|
});
|
|
1119
1252
|
// meta-focus-cmd: kspec meta focus [ref]
|
|
1120
|
-
meta
|
|
1121
|
-
.
|
|
1122
|
-
.
|
|
1123
|
-
.option('--clear', 'Clear current focus')
|
|
1253
|
+
markMutating(meta.command("focus [ref]"))
|
|
1254
|
+
.description("Get or set session focus")
|
|
1255
|
+
.option("--clear", "Clear current focus")
|
|
1124
1256
|
.action(async (ref, options) => {
|
|
1125
1257
|
try {
|
|
1126
1258
|
const ctx = await initContext();
|
|
@@ -1133,7 +1265,7 @@ export function registerMetaCommands(program) {
|
|
|
1133
1265
|
if (options.clear) {
|
|
1134
1266
|
sessionCtx.focus = null;
|
|
1135
1267
|
await saveSessionContext(ctx, sessionCtx);
|
|
1136
|
-
output({ focus: null }, () => success(
|
|
1268
|
+
output({ focus: null }, () => success("Cleared session focus"));
|
|
1137
1269
|
return;
|
|
1138
1270
|
}
|
|
1139
1271
|
// Show current focus
|
|
@@ -1143,13 +1275,13 @@ export function registerMetaCommands(program) {
|
|
|
1143
1275
|
console.log(`Current focus: ${sessionCtx.focus}`);
|
|
1144
1276
|
}
|
|
1145
1277
|
else {
|
|
1146
|
-
console.log(chalk.yellow(
|
|
1278
|
+
console.log(chalk.yellow("No focus set"));
|
|
1147
1279
|
}
|
|
1148
1280
|
});
|
|
1149
1281
|
return;
|
|
1150
1282
|
}
|
|
1151
1283
|
// Set focus to ref
|
|
1152
|
-
sessionCtx.focus = ref.startsWith(
|
|
1284
|
+
sessionCtx.focus = ref.startsWith("@") ? ref : `@${ref}`;
|
|
1153
1285
|
await saveSessionContext(ctx, sessionCtx);
|
|
1154
1286
|
output({ focus: sessionCtx.focus }, () => success(`Set focus to: ${sessionCtx.focus}`));
|
|
1155
1287
|
}
|
|
@@ -1159,9 +1291,8 @@ export function registerMetaCommands(program) {
|
|
|
1159
1291
|
}
|
|
1160
1292
|
});
|
|
1161
1293
|
// meta-thread-cmd: kspec meta thread <action> [text]
|
|
1162
|
-
meta
|
|
1163
|
-
.
|
|
1164
|
-
.description('Manage active threads')
|
|
1294
|
+
markMutating(meta.command("thread <action> [text]"))
|
|
1295
|
+
.description("Manage active threads")
|
|
1165
1296
|
.action(async (action, text) => {
|
|
1166
1297
|
try {
|
|
1167
1298
|
const ctx = await initContext();
|
|
@@ -1171,13 +1302,13 @@ export function registerMetaCommands(program) {
|
|
|
1171
1302
|
}
|
|
1172
1303
|
const sessionCtx = await loadSessionContext(ctx);
|
|
1173
1304
|
// List threads
|
|
1174
|
-
if (action ===
|
|
1305
|
+
if (action === "list") {
|
|
1175
1306
|
output({ threads: sessionCtx.threads }, () => {
|
|
1176
1307
|
if (sessionCtx.threads.length === 0) {
|
|
1177
|
-
console.log(chalk.yellow(
|
|
1308
|
+
console.log(chalk.yellow("No active threads"));
|
|
1178
1309
|
}
|
|
1179
1310
|
else {
|
|
1180
|
-
console.log(
|
|
1311
|
+
console.log("Active threads:");
|
|
1181
1312
|
sessionCtx.threads.forEach((thread, idx) => {
|
|
1182
1313
|
console.log(` ${idx + 1}. ${thread}`);
|
|
1183
1314
|
});
|
|
@@ -1186,16 +1317,16 @@ export function registerMetaCommands(program) {
|
|
|
1186
1317
|
return;
|
|
1187
1318
|
}
|
|
1188
1319
|
// Clear all threads
|
|
1189
|
-
if (action ===
|
|
1320
|
+
if (action === "clear") {
|
|
1190
1321
|
sessionCtx.threads = [];
|
|
1191
1322
|
await saveSessionContext(ctx, sessionCtx);
|
|
1192
|
-
output({ threads: [] }, () => success(
|
|
1323
|
+
output({ threads: [] }, () => success("Cleared all threads"));
|
|
1193
1324
|
return;
|
|
1194
1325
|
}
|
|
1195
1326
|
// Add thread
|
|
1196
|
-
if (action ===
|
|
1327
|
+
if (action === "add") {
|
|
1197
1328
|
if (!text) {
|
|
1198
|
-
error(
|
|
1329
|
+
error("Thread text is required for add action");
|
|
1199
1330
|
process.exit(EXIT_CODES.ERROR);
|
|
1200
1331
|
}
|
|
1201
1332
|
sessionCtx.threads.push(text);
|
|
@@ -1204,13 +1335,15 @@ export function registerMetaCommands(program) {
|
|
|
1204
1335
|
return;
|
|
1205
1336
|
}
|
|
1206
1337
|
// Remove thread by index (1-based)
|
|
1207
|
-
if (action ===
|
|
1338
|
+
if (action === "remove") {
|
|
1208
1339
|
if (!text) {
|
|
1209
|
-
error(
|
|
1340
|
+
error("Index is required for remove action");
|
|
1210
1341
|
process.exit(EXIT_CODES.ERROR);
|
|
1211
1342
|
}
|
|
1212
1343
|
const index = parseInt(text, 10);
|
|
1213
|
-
if (isNaN(index) ||
|
|
1344
|
+
if (Number.isNaN(index) ||
|
|
1345
|
+
index < 1 ||
|
|
1346
|
+
index > sessionCtx.threads.length) {
|
|
1214
1347
|
error(`Invalid index: ${text}. Must be between 1 and ${sessionCtx.threads.length}`);
|
|
1215
1348
|
process.exit(EXIT_CODES.ERROR);
|
|
1216
1349
|
}
|
|
@@ -1229,9 +1362,8 @@ export function registerMetaCommands(program) {
|
|
|
1229
1362
|
}
|
|
1230
1363
|
});
|
|
1231
1364
|
// meta-question-cmd: kspec meta question <action> [text]
|
|
1232
|
-
meta
|
|
1233
|
-
.
|
|
1234
|
-
.description('Manage open questions')
|
|
1365
|
+
markMutating(meta.command("question <action> [text]"))
|
|
1366
|
+
.description("Manage open questions")
|
|
1235
1367
|
.action(async (action, text) => {
|
|
1236
1368
|
try {
|
|
1237
1369
|
const ctx = await initContext();
|
|
@@ -1241,13 +1373,13 @@ export function registerMetaCommands(program) {
|
|
|
1241
1373
|
}
|
|
1242
1374
|
const sessionCtx = await loadSessionContext(ctx);
|
|
1243
1375
|
// List questions
|
|
1244
|
-
if (action ===
|
|
1376
|
+
if (action === "list") {
|
|
1245
1377
|
output({ questions: sessionCtx.open_questions }, () => {
|
|
1246
1378
|
if (sessionCtx.open_questions.length === 0) {
|
|
1247
|
-
console.log(chalk.yellow(
|
|
1379
|
+
console.log(chalk.yellow("No open questions"));
|
|
1248
1380
|
}
|
|
1249
1381
|
else {
|
|
1250
|
-
console.log(
|
|
1382
|
+
console.log("Open questions:");
|
|
1251
1383
|
sessionCtx.open_questions.forEach((question, idx) => {
|
|
1252
1384
|
console.log(` ${idx + 1}. ${question}`);
|
|
1253
1385
|
});
|
|
@@ -1256,16 +1388,16 @@ export function registerMetaCommands(program) {
|
|
|
1256
1388
|
return;
|
|
1257
1389
|
}
|
|
1258
1390
|
// Clear all questions
|
|
1259
|
-
if (action ===
|
|
1391
|
+
if (action === "clear") {
|
|
1260
1392
|
sessionCtx.open_questions = [];
|
|
1261
1393
|
await saveSessionContext(ctx, sessionCtx);
|
|
1262
|
-
output({ questions: [] }, () => success(
|
|
1394
|
+
output({ questions: [] }, () => success("Cleared all questions"));
|
|
1263
1395
|
return;
|
|
1264
1396
|
}
|
|
1265
1397
|
// Add question
|
|
1266
|
-
if (action ===
|
|
1398
|
+
if (action === "add") {
|
|
1267
1399
|
if (!text) {
|
|
1268
|
-
error(
|
|
1400
|
+
error("Question text is required for add action");
|
|
1269
1401
|
process.exit(EXIT_CODES.ERROR);
|
|
1270
1402
|
}
|
|
1271
1403
|
sessionCtx.open_questions.push(text);
|
|
@@ -1274,13 +1406,15 @@ export function registerMetaCommands(program) {
|
|
|
1274
1406
|
return;
|
|
1275
1407
|
}
|
|
1276
1408
|
// Remove question by index (1-based)
|
|
1277
|
-
if (action ===
|
|
1409
|
+
if (action === "remove") {
|
|
1278
1410
|
if (!text) {
|
|
1279
|
-
error(
|
|
1411
|
+
error("Index is required for remove action");
|
|
1280
1412
|
process.exit(EXIT_CODES.ERROR);
|
|
1281
1413
|
}
|
|
1282
1414
|
const index = parseInt(text, 10);
|
|
1283
|
-
if (isNaN(index) ||
|
|
1415
|
+
if (Number.isNaN(index) ||
|
|
1416
|
+
index < 1 ||
|
|
1417
|
+
index > sessionCtx.open_questions.length) {
|
|
1284
1418
|
error(`Invalid index: ${text}. Must be between 1 and ${sessionCtx.open_questions.length}`);
|
|
1285
1419
|
process.exit(EXIT_CODES.ERROR);
|
|
1286
1420
|
}
|
|
@@ -1300,9 +1434,9 @@ export function registerMetaCommands(program) {
|
|
|
1300
1434
|
});
|
|
1301
1435
|
// meta-context-cmd: kspec meta context
|
|
1302
1436
|
meta
|
|
1303
|
-
.command(
|
|
1304
|
-
.description(
|
|
1305
|
-
.option(
|
|
1437
|
+
.command("context")
|
|
1438
|
+
.description("Show full session context")
|
|
1439
|
+
.option("--clear", "Clear all session context")
|
|
1306
1440
|
.action(async (options) => {
|
|
1307
1441
|
try {
|
|
1308
1442
|
const ctx = await initContext();
|
|
@@ -1322,7 +1456,7 @@ export function registerMetaCommands(program) {
|
|
|
1322
1456
|
threads: [],
|
|
1323
1457
|
open_questions: [],
|
|
1324
1458
|
updated_at: sessionCtx.updated_at,
|
|
1325
|
-
}, () => success(
|
|
1459
|
+
}, () => success("Cleared all session context"));
|
|
1326
1460
|
return;
|
|
1327
1461
|
}
|
|
1328
1462
|
// Show full session context
|
|
@@ -1332,38 +1466,38 @@ export function registerMetaCommands(program) {
|
|
|
1332
1466
|
open_questions: sessionCtx.open_questions,
|
|
1333
1467
|
updated_at: sessionCtx.updated_at,
|
|
1334
1468
|
}, () => {
|
|
1335
|
-
console.log(chalk.bold(
|
|
1336
|
-
console.log(chalk.gray(
|
|
1469
|
+
console.log(chalk.bold("Session Context"));
|
|
1470
|
+
console.log(chalk.gray("─".repeat(60)));
|
|
1337
1471
|
// Focus
|
|
1338
|
-
console.log(chalk.bold(
|
|
1472
|
+
console.log(chalk.bold("\nFocus:"));
|
|
1339
1473
|
if (sessionCtx.focus) {
|
|
1340
1474
|
console.log(` ${sessionCtx.focus}`);
|
|
1341
1475
|
}
|
|
1342
1476
|
else {
|
|
1343
|
-
console.log(chalk.gray(
|
|
1477
|
+
console.log(chalk.gray(" (none)"));
|
|
1344
1478
|
}
|
|
1345
1479
|
// Active threads
|
|
1346
|
-
console.log(chalk.bold(
|
|
1480
|
+
console.log(chalk.bold("\nActive Threads:"));
|
|
1347
1481
|
if (sessionCtx.threads.length > 0) {
|
|
1348
1482
|
sessionCtx.threads.forEach((thread, idx) => {
|
|
1349
1483
|
console.log(` ${idx + 1}. ${thread}`);
|
|
1350
1484
|
});
|
|
1351
1485
|
}
|
|
1352
1486
|
else {
|
|
1353
|
-
console.log(chalk.gray(
|
|
1487
|
+
console.log(chalk.gray(" (none)"));
|
|
1354
1488
|
}
|
|
1355
1489
|
// Open questions
|
|
1356
|
-
console.log(chalk.bold(
|
|
1490
|
+
console.log(chalk.bold("\nOpen Questions:"));
|
|
1357
1491
|
if (sessionCtx.open_questions.length > 0) {
|
|
1358
1492
|
sessionCtx.open_questions.forEach((question, idx) => {
|
|
1359
1493
|
console.log(` ${idx + 1}. ${question}`);
|
|
1360
1494
|
});
|
|
1361
1495
|
}
|
|
1362
1496
|
else {
|
|
1363
|
-
console.log(chalk.gray(
|
|
1497
|
+
console.log(chalk.gray(" (none)"));
|
|
1364
1498
|
}
|
|
1365
1499
|
// Last updated
|
|
1366
|
-
console.log(chalk.bold(
|
|
1500
|
+
console.log(chalk.bold("\nLast Updated:"));
|
|
1367
1501
|
const updatedDate = new Date(sessionCtx.updated_at);
|
|
1368
1502
|
console.log(` ${updatedDate.toISOString()}`);
|
|
1369
1503
|
console.log(chalk.gray(` (${updatedDate.toLocaleString()})`));
|