@cleocode/cleo 2026.4.59 → 2026.4.62
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/dist/cli/index.js +1917 -314
- package/dist/cli/index.js.map +4 -4
- package/package.json +8 -8
- package/dist/cli/commander-shim.d.ts +0 -112
- package/dist/cli/commander-shim.d.ts.map +0 -1
- package/dist/cli/commander-shim.js +0 -233
- package/dist/cli/commander-shim.js.map +0 -1
- package/dist/cli/commands/adapter.d.ts +0 -21
- package/dist/cli/commands/adapter.d.ts.map +0 -1
- package/dist/cli/commands/adapter.js +0 -73
- package/dist/cli/commands/adapter.js.map +0 -1
- package/dist/cli/commands/add-batch.d.ts +0 -16
- package/dist/cli/commands/add-batch.d.ts.map +0 -1
- package/dist/cli/commands/add-batch.js +0 -133
- package/dist/cli/commands/add-batch.js.map +0 -1
- package/dist/cli/commands/add.d.ts +0 -12
- package/dist/cli/commands/add.d.ts.map +0 -1
- package/dist/cli/commands/add.js +0 -238
- package/dist/cli/commands/add.js.map +0 -1
- package/dist/cli/commands/admin.d.ts +0 -15
- package/dist/cli/commands/admin.d.ts.map +0 -1
- package/dist/cli/commands/admin.js +0 -143
- package/dist/cli/commands/admin.js.map +0 -1
- package/dist/cli/commands/adr.d.ts +0 -27
- package/dist/cli/commands/adr.d.ts.map +0 -1
- package/dist/cli/commands/adr.js +0 -79
- package/dist/cli/commands/adr.js.map +0 -1
- package/dist/cli/commands/agent-profile-status.d.ts +0 -98
- package/dist/cli/commands/agent-profile-status.d.ts.map +0 -1
- package/dist/cli/commands/agent-profile-status.js +0 -71
- package/dist/cli/commands/agent-profile-status.js.map +0 -1
- package/dist/cli/commands/agent.d.ts +0 -41
- package/dist/cli/commands/agent.d.ts.map +0 -1
- package/dist/cli/commands/agent.js +0 -2270
- package/dist/cli/commands/agent.js.map +0 -1
- package/dist/cli/commands/agents.d.ts +0 -17
- package/dist/cli/commands/agents.d.ts.map +0 -1
- package/dist/cli/commands/agents.js +0 -20
- package/dist/cli/commands/agents.js.map +0 -1
- package/dist/cli/commands/analyze.d.ts +0 -12
- package/dist/cli/commands/analyze.d.ts.map +0 -1
- package/dist/cli/commands/analyze.js +0 -20
- package/dist/cli/commands/analyze.js.map +0 -1
- package/dist/cli/commands/archive-stats.d.ts +0 -18
- package/dist/cli/commands/archive-stats.d.ts.map +0 -1
- package/dist/cli/commands/archive-stats.js +0 -49
- package/dist/cli/commands/archive-stats.js.map +0 -1
- package/dist/cli/commands/archive.d.ts +0 -12
- package/dist/cli/commands/archive.d.ts.map +0 -1
- package/dist/cli/commands/archive.js +0 -32
- package/dist/cli/commands/archive.js.map +0 -1
- package/dist/cli/commands/backfill.d.ts +0 -38
- package/dist/cli/commands/backfill.d.ts.map +0 -1
- package/dist/cli/commands/backfill.js +0 -144
- package/dist/cli/commands/backfill.js.map +0 -1
- package/dist/cli/commands/backup-inspect.d.ts +0 -24
- package/dist/cli/commands/backup-inspect.d.ts.map +0 -1
- package/dist/cli/commands/backup-inspect.js +0 -417
- package/dist/cli/commands/backup-inspect.js.map +0 -1
- package/dist/cli/commands/backup.d.ts +0 -13
- package/dist/cli/commands/backup.d.ts.map +0 -1
- package/dist/cli/commands/backup.js +0 -479
- package/dist/cli/commands/backup.js.map +0 -1
- package/dist/cli/commands/blockers.d.ts +0 -7
- package/dist/cli/commands/blockers.d.ts.map +0 -1
- package/dist/cli/commands/blockers.js +0 -16
- package/dist/cli/commands/blockers.js.map +0 -1
- package/dist/cli/commands/brain.d.ts +0 -29
- package/dist/cli/commands/brain.d.ts.map +0 -1
- package/dist/cli/commands/brain.js +0 -358
- package/dist/cli/commands/brain.js.map +0 -1
- package/dist/cli/commands/briefing.d.ts +0 -22
- package/dist/cli/commands/briefing.d.ts.map +0 -1
- package/dist/cli/commands/briefing.js +0 -45
- package/dist/cli/commands/briefing.js.map +0 -1
- package/dist/cli/commands/bug.d.ts +0 -12
- package/dist/cli/commands/bug.d.ts.map +0 -1
- package/dist/cli/commands/bug.js +0 -81
- package/dist/cli/commands/bug.js.map +0 -1
- package/dist/cli/commands/cancel.d.ts +0 -17
- package/dist/cli/commands/cancel.d.ts.map +0 -1
- package/dist/cli/commands/cancel.js +0 -28
- package/dist/cli/commands/cancel.js.map +0 -1
- package/dist/cli/commands/cant.d.ts +0 -32
- package/dist/cli/commands/cant.d.ts.map +0 -1
- package/dist/cli/commands/cant.js +0 -264
- package/dist/cli/commands/cant.js.map +0 -1
- package/dist/cli/commands/chain.d.ts +0 -16
- package/dist/cli/commands/chain.d.ts.map +0 -1
- package/dist/cli/commands/chain.js +0 -52
- package/dist/cli/commands/chain.js.map +0 -1
- package/dist/cli/commands/check.d.ts +0 -25
- package/dist/cli/commands/check.d.ts.map +0 -1
- package/dist/cli/commands/check.js +0 -193
- package/dist/cli/commands/check.js.map +0 -1
- package/dist/cli/commands/checkpoint.d.ts +0 -15
- package/dist/cli/commands/checkpoint.d.ts.map +0 -1
- package/dist/cli/commands/checkpoint.js +0 -91
- package/dist/cli/commands/checkpoint.js.map +0 -1
- package/dist/cli/commands/claim.d.ts +0 -27
- package/dist/cli/commands/claim.d.ts.map +0 -1
- package/dist/cli/commands/claim.js +0 -45
- package/dist/cli/commands/claim.js.map +0 -1
- package/dist/cli/commands/code.d.ts +0 -11
- package/dist/cli/commands/code.d.ts.map +0 -1
- package/dist/cli/commands/code.js +0 -114
- package/dist/cli/commands/code.js.map +0 -1
- package/dist/cli/commands/commands.d.ts +0 -13
- package/dist/cli/commands/commands.d.ts.map +0 -1
- package/dist/cli/commands/commands.js +0 -29
- package/dist/cli/commands/commands.js.map +0 -1
- package/dist/cli/commands/complete.d.ts +0 -12
- package/dist/cli/commands/complete.d.ts.map +0 -1
- package/dist/cli/commands/complete.js +0 -92
- package/dist/cli/commands/complete.js.map +0 -1
- package/dist/cli/commands/complexity.d.ts +0 -17
- package/dist/cli/commands/complexity.d.ts.map +0 -1
- package/dist/cli/commands/complexity.js +0 -25
- package/dist/cli/commands/complexity.js.map +0 -1
- package/dist/cli/commands/compliance.d.ts +0 -9
- package/dist/cli/commands/compliance.d.ts.map +0 -1
- package/dist/cli/commands/compliance.js +0 -110
- package/dist/cli/commands/compliance.js.map +0 -1
- package/dist/cli/commands/config.d.ts +0 -10
- package/dist/cli/commands/config.d.ts.map +0 -1
- package/dist/cli/commands/config.js +0 -69
- package/dist/cli/commands/config.js.map +0 -1
- package/dist/cli/commands/consensus.d.ts +0 -13
- package/dist/cli/commands/consensus.d.ts.map +0 -1
- package/dist/cli/commands/consensus.js +0 -45
- package/dist/cli/commands/consensus.js.map +0 -1
- package/dist/cli/commands/context.d.ts +0 -15
- package/dist/cli/commands/context.d.ts.map +0 -1
- package/dist/cli/commands/context.js +0 -76
- package/dist/cli/commands/context.js.map +0 -1
- package/dist/cli/commands/contribution.d.ts +0 -13
- package/dist/cli/commands/contribution.d.ts.map +0 -1
- package/dist/cli/commands/contribution.js +0 -41
- package/dist/cli/commands/contribution.js.map +0 -1
- package/dist/cli/commands/current.d.ts +0 -13
- package/dist/cli/commands/current.d.ts.map +0 -1
- package/dist/cli/commands/current.js +0 -20
- package/dist/cli/commands/current.js.map +0 -1
- package/dist/cli/commands/dash.d.ts +0 -12
- package/dist/cli/commands/dash.d.ts.map +0 -1
- package/dist/cli/commands/dash.js +0 -20
- package/dist/cli/commands/dash.js.map +0 -1
- package/dist/cli/commands/decomposition.d.ts +0 -13
- package/dist/cli/commands/decomposition.d.ts.map +0 -1
- package/dist/cli/commands/decomposition.js +0 -45
- package/dist/cli/commands/decomposition.js.map +0 -1
- package/dist/cli/commands/delete.d.ts +0 -12
- package/dist/cli/commands/delete.d.ts.map +0 -1
- package/dist/cli/commands/delete.js +0 -37
- package/dist/cli/commands/delete.js.map +0 -1
- package/dist/cli/commands/deps.d.ts +0 -24
- package/dist/cli/commands/deps.d.ts.map +0 -1
- package/dist/cli/commands/deps.js +0 -98
- package/dist/cli/commands/deps.js.map +0 -1
- package/dist/cli/commands/detect-drift.d.ts +0 -15
- package/dist/cli/commands/detect-drift.d.ts.map +0 -1
- package/dist/cli/commands/detect-drift.js +0 -428
- package/dist/cli/commands/detect-drift.js.map +0 -1
- package/dist/cli/commands/detect.d.ts +0 -13
- package/dist/cli/commands/detect.d.ts.map +0 -1
- package/dist/cli/commands/detect.js +0 -20
- package/dist/cli/commands/detect.js.map +0 -1
- package/dist/cli/commands/diagnostics.d.ts +0 -16
- package/dist/cli/commands/diagnostics.d.ts.map +0 -1
- package/dist/cli/commands/diagnostics.js +0 -58
- package/dist/cli/commands/diagnostics.js.map +0 -1
- package/dist/cli/commands/docs.d.ts +0 -13
- package/dist/cli/commands/docs.d.ts.map +0 -1
- package/dist/cli/commands/docs.js +0 -169
- package/dist/cli/commands/docs.js.map +0 -1
- package/dist/cli/commands/doctor.d.ts +0 -15
- package/dist/cli/commands/doctor.d.ts.map +0 -1
- package/dist/cli/commands/doctor.js +0 -133
- package/dist/cli/commands/doctor.js.map +0 -1
- package/dist/cli/commands/dynamic.d.ts +0 -24
- package/dist/cli/commands/dynamic.d.ts.map +0 -1
- package/dist/cli/commands/dynamic.js +0 -27
- package/dist/cli/commands/dynamic.js.map +0 -1
- package/dist/cli/commands/env.d.ts +0 -12
- package/dist/cli/commands/env.d.ts.map +0 -1
- package/dist/cli/commands/env.js +0 -44
- package/dist/cli/commands/env.js.map +0 -1
- package/dist/cli/commands/exists.d.ts +0 -24
- package/dist/cli/commands/exists.d.ts.map +0 -1
- package/dist/cli/commands/exists.js +0 -53
- package/dist/cli/commands/exists.js.map +0 -1
- package/dist/cli/commands/export-tasks.d.ts +0 -10
- package/dist/cli/commands/export-tasks.d.ts.map +0 -1
- package/dist/cli/commands/export-tasks.js +0 -47
- package/dist/cli/commands/export-tasks.js.map +0 -1
- package/dist/cli/commands/export.d.ts +0 -9
- package/dist/cli/commands/export.d.ts.map +0 -1
- package/dist/cli/commands/export.js +0 -46
- package/dist/cli/commands/export.js.map +0 -1
- package/dist/cli/commands/find.d.ts +0 -14
- package/dist/cli/commands/find.d.ts.map +0 -1
- package/dist/cli/commands/find.js +0 -152
- package/dist/cli/commands/find.js.map +0 -1
- package/dist/cli/commands/generate-changelog.d.ts +0 -14
- package/dist/cli/commands/generate-changelog.d.ts.map +0 -1
- package/dist/cli/commands/generate-changelog.js +0 -252
- package/dist/cli/commands/generate-changelog.js.map +0 -1
- package/dist/cli/commands/grade.d.ts +0 -13
- package/dist/cli/commands/grade.d.ts.map +0 -1
- package/dist/cli/commands/grade.js +0 -26
- package/dist/cli/commands/grade.js.map +0 -1
- package/dist/cli/commands/history.d.ts +0 -9
- package/dist/cli/commands/history.d.ts.map +0 -1
- package/dist/cli/commands/history.js +0 -33
- package/dist/cli/commands/history.js.map +0 -1
- package/dist/cli/commands/implementation.d.ts +0 -13
- package/dist/cli/commands/implementation.d.ts.map +0 -1
- package/dist/cli/commands/implementation.js +0 -41
- package/dist/cli/commands/implementation.js.map +0 -1
- package/dist/cli/commands/import-tasks.d.ts +0 -10
- package/dist/cli/commands/import-tasks.d.ts.map +0 -1
- package/dist/cli/commands/import-tasks.js +0 -38
- package/dist/cli/commands/import-tasks.js.map +0 -1
- package/dist/cli/commands/import.d.ts +0 -9
- package/dist/cli/commands/import.d.ts.map +0 -1
- package/dist/cli/commands/import.js +0 -28
- package/dist/cli/commands/import.js.map +0 -1
- package/dist/cli/commands/init.d.ts +0 -34
- package/dist/cli/commands/init.d.ts.map +0 -1
- package/dist/cli/commands/init.js +0 -96
- package/dist/cli/commands/init.js.map +0 -1
- package/dist/cli/commands/inject.d.ts +0 -8
- package/dist/cli/commands/inject.d.ts.map +0 -1
- package/dist/cli/commands/inject.js +0 -28
- package/dist/cli/commands/inject.js.map +0 -1
- package/dist/cli/commands/intelligence.d.ts +0 -22
- package/dist/cli/commands/intelligence.d.ts.map +0 -1
- package/dist/cli/commands/intelligence.js +0 -72
- package/dist/cli/commands/intelligence.js.map +0 -1
- package/dist/cli/commands/issue.d.ts +0 -17
- package/dist/cli/commands/issue.d.ts.map +0 -1
- package/dist/cli/commands/issue.js +0 -107
- package/dist/cli/commands/issue.js.map +0 -1
- package/dist/cli/commands/labels.d.ts +0 -17
- package/dist/cli/commands/labels.d.ts.map +0 -1
- package/dist/cli/commands/labels.js +0 -48
- package/dist/cli/commands/labels.js.map +0 -1
- package/dist/cli/commands/lifecycle.d.ts +0 -8
- package/dist/cli/commands/lifecycle.d.ts.map +0 -1
- package/dist/cli/commands/lifecycle.js +0 -128
- package/dist/cli/commands/lifecycle.js.map +0 -1
- package/dist/cli/commands/list.d.ts +0 -14
- package/dist/cli/commands/list.d.ts.map +0 -1
- package/dist/cli/commands/list.js +0 -143
- package/dist/cli/commands/list.js.map +0 -1
- package/dist/cli/commands/log.d.ts +0 -12
- package/dist/cli/commands/log.d.ts.map +0 -1
- package/dist/cli/commands/log.js +0 -30
- package/dist/cli/commands/log.js.map +0 -1
- package/dist/cli/commands/map.d.ts +0 -10
- package/dist/cli/commands/map.d.ts.map +0 -1
- package/dist/cli/commands/map.js +0 -23
- package/dist/cli/commands/map.js.map +0 -1
- package/dist/cli/commands/memory-brain.d.ts +0 -15
- package/dist/cli/commands/memory-brain.d.ts.map +0 -1
- package/dist/cli/commands/memory-brain.js +0 -436
- package/dist/cli/commands/memory-brain.js.map +0 -1
- package/dist/cli/commands/migrate-claude-mem.d.ts +0 -23
- package/dist/cli/commands/migrate-claude-mem.d.ts.map +0 -1
- package/dist/cli/commands/migrate-claude-mem.js +0 -79
- package/dist/cli/commands/migrate-claude-mem.js.map +0 -1
- package/dist/cli/commands/next.d.ts +0 -9
- package/dist/cli/commands/next.d.ts.map +0 -1
- package/dist/cli/commands/next.js +0 -20
- package/dist/cli/commands/next.js.map +0 -1
- package/dist/cli/commands/nexus.d.ts +0 -20
- package/dist/cli/commands/nexus.d.ts.map +0 -1
- package/dist/cli/commands/nexus.js +0 -2290
- package/dist/cli/commands/nexus.js.map +0 -1
- package/dist/cli/commands/observe.d.ts +0 -13
- package/dist/cli/commands/observe.d.ts.map +0 -1
- package/dist/cli/commands/observe.js +0 -30
- package/dist/cli/commands/observe.js.map +0 -1
- package/dist/cli/commands/ops.d.ts +0 -10
- package/dist/cli/commands/ops.d.ts.map +0 -1
- package/dist/cli/commands/ops.js +0 -19
- package/dist/cli/commands/ops.js.map +0 -1
- package/dist/cli/commands/orchestrate.d.ts +0 -24
- package/dist/cli/commands/orchestrate.d.ts.map +0 -1
- package/dist/cli/commands/orchestrate.js +0 -254
- package/dist/cli/commands/orchestrate.js.map +0 -1
- package/dist/cli/commands/otel.d.ts +0 -12
- package/dist/cli/commands/otel.d.ts.map +0 -1
- package/dist/cli/commands/otel.js +0 -128
- package/dist/cli/commands/otel.js.map +0 -1
- package/dist/cli/commands/phase.d.ts +0 -12
- package/dist/cli/commands/phase.d.ts.map +0 -1
- package/dist/cli/commands/phase.js +0 -91
- package/dist/cli/commands/phase.js.map +0 -1
- package/dist/cli/commands/phases.d.ts +0 -14
- package/dist/cli/commands/phases.d.ts.map +0 -1
- package/dist/cli/commands/phases.js +0 -42
- package/dist/cli/commands/phases.js.map +0 -1
- package/dist/cli/commands/plan.d.ts +0 -8
- package/dist/cli/commands/plan.d.ts.map +0 -1
- package/dist/cli/commands/plan.js +0 -15
- package/dist/cli/commands/plan.js.map +0 -1
- package/dist/cli/commands/promote.d.ts +0 -11
- package/dist/cli/commands/promote.d.ts.map +0 -1
- package/dist/cli/commands/promote.js +0 -18
- package/dist/cli/commands/promote.js.map +0 -1
- package/dist/cli/commands/provider.d.ts +0 -21
- package/dist/cli/commands/provider.d.ts.map +0 -1
- package/dist/cli/commands/provider.js +0 -88
- package/dist/cli/commands/provider.js.map +0 -1
- package/dist/cli/commands/reason.d.ts +0 -36
- package/dist/cli/commands/reason.d.ts.map +0 -1
- package/dist/cli/commands/reason.js +0 -85
- package/dist/cli/commands/reason.js.map +0 -1
- package/dist/cli/commands/refresh-memory.d.ts +0 -9
- package/dist/cli/commands/refresh-memory.d.ts.map +0 -1
- package/dist/cli/commands/refresh-memory.js +0 -24
- package/dist/cli/commands/refresh-memory.js.map +0 -1
- package/dist/cli/commands/relates.d.ts +0 -12
- package/dist/cli/commands/relates.d.ts.map +0 -1
- package/dist/cli/commands/relates.js +0 -53
- package/dist/cli/commands/relates.js.map +0 -1
- package/dist/cli/commands/release.d.ts +0 -8
- package/dist/cli/commands/release.d.ts.map +0 -1
- package/dist/cli/commands/release.js +0 -82
- package/dist/cli/commands/release.js.map +0 -1
- package/dist/cli/commands/remote.d.ts +0 -12
- package/dist/cli/commands/remote.d.ts.map +0 -1
- package/dist/cli/commands/remote.js +0 -207
- package/dist/cli/commands/remote.js.map +0 -1
- package/dist/cli/commands/reorder.d.ts +0 -17
- package/dist/cli/commands/reorder.d.ts.map +0 -1
- package/dist/cli/commands/reorder.js +0 -41
- package/dist/cli/commands/reorder.js.map +0 -1
- package/dist/cli/commands/reparent.d.ts +0 -10
- package/dist/cli/commands/reparent.d.ts.map +0 -1
- package/dist/cli/commands/reparent.js +0 -19
- package/dist/cli/commands/reparent.js.map +0 -1
- package/dist/cli/commands/research.d.ts +0 -8
- package/dist/cli/commands/research.d.ts.map +0 -1
- package/dist/cli/commands/research.js +0 -164
- package/dist/cli/commands/research.js.map +0 -1
- package/dist/cli/commands/restore.d.ts +0 -54
- package/dist/cli/commands/restore.d.ts.map +0 -1
- package/dist/cli/commands/restore.js +0 -470
- package/dist/cli/commands/restore.js.map +0 -1
- package/dist/cli/commands/roadmap.d.ts +0 -14
- package/dist/cli/commands/roadmap.d.ts.map +0 -1
- package/dist/cli/commands/roadmap.js +0 -26
- package/dist/cli/commands/roadmap.js.map +0 -1
- package/dist/cli/commands/safestop.d.ts +0 -14
- package/dist/cli/commands/safestop.d.ts.map +0 -1
- package/dist/cli/commands/safestop.js +0 -32
- package/dist/cli/commands/safestop.js.map +0 -1
- package/dist/cli/commands/schema.d.ts +0 -27
- package/dist/cli/commands/schema.d.ts.map +0 -1
- package/dist/cli/commands/schema.js +0 -160
- package/dist/cli/commands/schema.js.map +0 -1
- package/dist/cli/commands/self-update.d.ts +0 -15
- package/dist/cli/commands/self-update.d.ts.map +0 -1
- package/dist/cli/commands/self-update.js +0 -363
- package/dist/cli/commands/self-update.js.map +0 -1
- package/dist/cli/commands/sequence.d.ts +0 -11
- package/dist/cli/commands/sequence.d.ts.map +0 -1
- package/dist/cli/commands/sequence.js +0 -40
- package/dist/cli/commands/sequence.js.map +0 -1
- package/dist/cli/commands/session.d.ts +0 -12
- package/dist/cli/commands/session.d.ts.map +0 -1
- package/dist/cli/commands/session.js +0 -219
- package/dist/cli/commands/session.js.map +0 -1
- package/dist/cli/commands/show.d.ts +0 -13
- package/dist/cli/commands/show.d.ts.map +0 -1
- package/dist/cli/commands/show.js +0 -40
- package/dist/cli/commands/show.js.map +0 -1
- package/dist/cli/commands/skills.d.ts +0 -13
- package/dist/cli/commands/skills.d.ts.map +0 -1
- package/dist/cli/commands/skills.js +0 -161
- package/dist/cli/commands/skills.js.map +0 -1
- package/dist/cli/commands/snapshot.d.ts +0 -9
- package/dist/cli/commands/snapshot.d.ts.map +0 -1
- package/dist/cli/commands/snapshot.js +0 -50
- package/dist/cli/commands/snapshot.js.map +0 -1
- package/dist/cli/commands/specification.d.ts +0 -13
- package/dist/cli/commands/specification.d.ts.map +0 -1
- package/dist/cli/commands/specification.js +0 -45
- package/dist/cli/commands/specification.js.map +0 -1
- package/dist/cli/commands/start.d.ts +0 -13
- package/dist/cli/commands/start.d.ts.map +0 -1
- package/dist/cli/commands/start.js +0 -20
- package/dist/cli/commands/start.js.map +0 -1
- package/dist/cli/commands/stats.d.ts +0 -12
- package/dist/cli/commands/stats.d.ts.map +0 -1
- package/dist/cli/commands/stats.js +0 -35
- package/dist/cli/commands/stats.js.map +0 -1
- package/dist/cli/commands/sticky.d.ts +0 -16
- package/dist/cli/commands/sticky.d.ts.map +0 -1
- package/dist/cli/commands/sticky.js +0 -218
- package/dist/cli/commands/sticky.js.map +0 -1
- package/dist/cli/commands/stop.d.ts +0 -13
- package/dist/cli/commands/stop.d.ts.map +0 -1
- package/dist/cli/commands/stop.js +0 -20
- package/dist/cli/commands/stop.js.map +0 -1
- package/dist/cli/commands/sync.d.ts +0 -26
- package/dist/cli/commands/sync.d.ts.map +0 -1
- package/dist/cli/commands/sync.js +0 -82
- package/dist/cli/commands/sync.js.map +0 -1
- package/dist/cli/commands/testing.d.ts +0 -13
- package/dist/cli/commands/testing.d.ts.map +0 -1
- package/dist/cli/commands/testing.js +0 -65
- package/dist/cli/commands/testing.js.map +0 -1
- package/dist/cli/commands/token.d.ts +0 -10
- package/dist/cli/commands/token.d.ts.map +0 -1
- package/dist/cli/commands/token.js +0 -135
- package/dist/cli/commands/token.js.map +0 -1
- package/dist/cli/commands/update.d.ts +0 -12
- package/dist/cli/commands/update.d.ts.map +0 -1
- package/dist/cli/commands/update.js +0 -83
- package/dist/cli/commands/update.js.map +0 -1
- package/dist/cli/commands/upgrade.d.ts +0 -18
- package/dist/cli/commands/upgrade.d.ts.map +0 -1
- package/dist/cli/commands/upgrade.js +0 -103
- package/dist/cli/commands/upgrade.js.map +0 -1
- package/dist/cli/commands/validate.d.ts +0 -12
- package/dist/cli/commands/validate.d.ts.map +0 -1
- package/dist/cli/commands/validate.js +0 -24
- package/dist/cli/commands/validate.js.map +0 -1
- package/dist/cli/commands/verify.d.ts +0 -8
- package/dist/cli/commands/verify.d.ts.map +0 -1
- package/dist/cli/commands/verify.js +0 -28
- package/dist/cli/commands/verify.js.map +0 -1
- package/dist/cli/commands/web.d.ts +0 -19
- package/dist/cli/commands/web.d.ts.map +0 -1
- package/dist/cli/commands/web.js +0 -371
- package/dist/cli/commands/web.js.map +0 -1
- package/dist/cli/field-context.d.ts +0 -32
- package/dist/cli/field-context.d.ts.map +0 -1
- package/dist/cli/field-context.js +0 -47
- package/dist/cli/field-context.js.map +0 -1
- package/dist/cli/format-context.d.ts +0 -32
- package/dist/cli/format-context.d.ts.map +0 -1
- package/dist/cli/format-context.js +0 -50
- package/dist/cli/format-context.js.map +0 -1
- package/dist/cli/help-generator.d.ts +0 -74
- package/dist/cli/help-generator.d.ts.map +0 -1
- package/dist/cli/help-generator.js +0 -229
- package/dist/cli/help-generator.js.map +0 -1
- package/dist/cli/help-renderer.d.ts +0 -28
- package/dist/cli/help-renderer.d.ts.map +0 -1
- package/dist/cli/help-renderer.js +0 -301
- package/dist/cli/help-renderer.js.map +0 -1
- package/dist/cli/index.d.ts +0 -9
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/logger-bootstrap.d.ts +0 -6
- package/dist/cli/logger-bootstrap.d.ts.map +0 -1
- package/dist/cli/logger-bootstrap.js +0 -10
- package/dist/cli/logger-bootstrap.js.map +0 -1
- package/dist/cli/middleware/output-format.d.ts +0 -30
- package/dist/cli/middleware/output-format.d.ts.map +0 -1
- package/dist/cli/middleware/output-format.js +0 -35
- package/dist/cli/middleware/output-format.js.map +0 -1
- package/dist/cli/progress.d.ts +0 -84
- package/dist/cli/progress.d.ts.map +0 -1
- package/dist/cli/progress.js +0 -169
- package/dist/cli/progress.js.map +0 -1
- package/dist/cli/renderers/colors.d.ts +0 -32
- package/dist/cli/renderers/colors.d.ts.map +0 -1
- package/dist/cli/renderers/colors.js +0 -141
- package/dist/cli/renderers/colors.js.map +0 -1
- package/dist/cli/renderers/error.d.ts +0 -13
- package/dist/cli/renderers/error.d.ts.map +0 -1
- package/dist/cli/renderers/error.js +0 -42
- package/dist/cli/renderers/error.js.map +0 -1
- package/dist/cli/renderers/index.d.ts +0 -87
- package/dist/cli/renderers/index.d.ts.map +0 -1
- package/dist/cli/renderers/index.js +0 -262
- package/dist/cli/renderers/index.js.map +0 -1
- package/dist/cli/renderers/lafs-validator.d.ts +0 -91
- package/dist/cli/renderers/lafs-validator.d.ts.map +0 -1
- package/dist/cli/renderers/lafs-validator.js +0 -176
- package/dist/cli/renderers/lafs-validator.js.map +0 -1
- package/dist/cli/renderers/normalizer.d.ts +0 -21
- package/dist/cli/renderers/normalizer.d.ts.map +0 -1
- package/dist/cli/renderers/normalizer.js +0 -106
- package/dist/cli/renderers/normalizer.js.map +0 -1
- package/dist/cli/renderers/system.d.ts +0 -25
- package/dist/cli/renderers/system.d.ts.map +0 -1
- package/dist/cli/renderers/system.js +0 -416
- package/dist/cli/renderers/system.js.map +0 -1
- package/dist/cli/renderers/tasks.d.ts +0 -28
- package/dist/cli/renderers/tasks.d.ts.map +0 -1
- package/dist/cli/renderers/tasks.js +0 -306
- package/dist/cli/renderers/tasks.js.map +0 -1
- package/dist/dispatch/adapters/cli.d.ts +0 -67
- package/dist/dispatch/adapters/cli.d.ts.map +0 -1
- package/dist/dispatch/adapters/cli.js +0 -331
- package/dist/dispatch/adapters/cli.js.map +0 -1
- package/dist/dispatch/context/session-context.d.ts +0 -54
- package/dist/dispatch/context/session-context.d.ts.map +0 -1
- package/dist/dispatch/context/session-context.js +0 -61
- package/dist/dispatch/context/session-context.js.map +0 -1
- package/dist/dispatch/dispatcher.d.ts +0 -23
- package/dist/dispatch/dispatcher.d.ts.map +0 -1
- package/dist/dispatch/dispatcher.js +0 -84
- package/dist/dispatch/dispatcher.js.map +0 -1
- package/dist/dispatch/domains/_base.d.ts +0 -59
- package/dist/dispatch/domains/_base.d.ts.map +0 -1
- package/dist/dispatch/domains/_base.js +0 -77
- package/dist/dispatch/domains/_base.js.map +0 -1
- package/dist/dispatch/domains/_meta.d.ts +0 -23
- package/dist/dispatch/domains/_meta.d.ts.map +0 -1
- package/dist/dispatch/domains/_meta.js +0 -25
- package/dist/dispatch/domains/_meta.js.map +0 -1
- package/dist/dispatch/domains/_routing.d.ts +0 -8
- package/dist/dispatch/domains/_routing.d.ts.map +0 -1
- package/dist/dispatch/domains/_routing.js +0 -20
- package/dist/dispatch/domains/_routing.js.map +0 -1
- package/dist/dispatch/domains/admin.d.ts +0 -25
- package/dist/dispatch/domains/admin.d.ts.map +0 -1
- package/dist/dispatch/domains/admin.js +0 -791
- package/dist/dispatch/domains/admin.js.map +0 -1
- package/dist/dispatch/domains/check.d.ts +0 -22
- package/dist/dispatch/domains/check.d.ts.map +0 -1
- package/dist/dispatch/domains/check.js +0 -381
- package/dist/dispatch/domains/check.js.map +0 -1
- package/dist/dispatch/domains/conduit.d.ts +0 -38
- package/dist/dispatch/domains/conduit.d.ts.map +0 -1
- package/dist/dispatch/domains/conduit.js +0 -360
- package/dist/dispatch/domains/conduit.js.map +0 -1
- package/dist/dispatch/domains/diagnostics.d.ts +0 -20
- package/dist/dispatch/domains/diagnostics.d.ts.map +0 -1
- package/dist/dispatch/domains/diagnostics.js +0 -77
- package/dist/dispatch/domains/diagnostics.js.map +0 -1
- package/dist/dispatch/domains/index.d.ts +0 -29
- package/dist/dispatch/domains/index.d.ts.map +0 -1
- package/dist/dispatch/domains/index.js +0 -45
- package/dist/dispatch/domains/index.js.map +0 -1
- package/dist/dispatch/domains/intelligence.d.ts +0 -26
- package/dist/dispatch/domains/intelligence.d.ts.map +0 -1
- package/dist/dispatch/domains/intelligence.js +0 -154
- package/dist/dispatch/domains/intelligence.js.map +0 -1
- package/dist/dispatch/domains/memory.d.ts +0 -22
- package/dist/dispatch/domains/memory.d.ts.map +0 -1
- package/dist/dispatch/domains/memory.js +0 -387
- package/dist/dispatch/domains/memory.js.map +0 -1
- package/dist/dispatch/domains/nexus.d.ts +0 -22
- package/dist/dispatch/domains/nexus.d.ts.map +0 -1
- package/dist/dispatch/domains/nexus.js +0 -286
- package/dist/dispatch/domains/nexus.js.map +0 -1
- package/dist/dispatch/domains/orchestrate.d.ts +0 -26
- package/dist/dispatch/domains/orchestrate.d.ts.map +0 -1
- package/dist/dispatch/domains/orchestrate.js +0 -691
- package/dist/dispatch/domains/orchestrate.js.map +0 -1
- package/dist/dispatch/domains/pipeline.d.ts +0 -35
- package/dist/dispatch/domains/pipeline.d.ts.map +0 -1
- package/dist/dispatch/domains/pipeline.js +0 -593
- package/dist/dispatch/domains/pipeline.js.map +0 -1
- package/dist/dispatch/domains/session.d.ts +0 -22
- package/dist/dispatch/domains/session.d.ts.map +0 -1
- package/dist/dispatch/domains/session.js +0 -267
- package/dist/dispatch/domains/session.js.map +0 -1
- package/dist/dispatch/domains/sticky.d.ts +0 -20
- package/dist/dispatch/domains/sticky.d.ts.map +0 -1
- package/dist/dispatch/domains/sticky.js +0 -167
- package/dist/dispatch/domains/sticky.js.map +0 -1
- package/dist/dispatch/domains/tasks.d.ts +0 -25
- package/dist/dispatch/domains/tasks.d.ts.map +0 -1
- package/dist/dispatch/domains/tasks.js +0 -368
- package/dist/dispatch/domains/tasks.js.map +0 -1
- package/dist/dispatch/domains/tools.d.ts +0 -37
- package/dist/dispatch/domains/tools.d.ts.map +0 -1
- package/dist/dispatch/domains/tools.js +0 -481
- package/dist/dispatch/domains/tools.js.map +0 -1
- package/dist/dispatch/engines/_error.d.ts +0 -119
- package/dist/dispatch/engines/_error.d.ts.map +0 -1
- package/dist/dispatch/engines/_error.js +0 -298
- package/dist/dispatch/engines/_error.js.map +0 -1
- package/dist/dispatch/engines/code-engine.d.ts +0 -18
- package/dist/dispatch/engines/code-engine.d.ts.map +0 -1
- package/dist/dispatch/engines/code-engine.js +0 -71
- package/dist/dispatch/engines/code-engine.js.map +0 -1
- package/dist/dispatch/engines/codebase-map-engine.d.ts +0 -31
- package/dist/dispatch/engines/codebase-map-engine.d.ts.map +0 -1
- package/dist/dispatch/engines/codebase-map-engine.js +0 -43
- package/dist/dispatch/engines/codebase-map-engine.js.map +0 -1
- package/dist/dispatch/engines/config-engine.d.ts +0 -32
- package/dist/dispatch/engines/config-engine.d.ts.map +0 -1
- package/dist/dispatch/engines/config-engine.js +0 -70
- package/dist/dispatch/engines/config-engine.js.map +0 -1
- package/dist/dispatch/engines/diagnostics-engine.d.ts +0 -57
- package/dist/dispatch/engines/diagnostics-engine.d.ts.map +0 -1
- package/dist/dispatch/engines/diagnostics-engine.js +0 -163
- package/dist/dispatch/engines/diagnostics-engine.js.map +0 -1
- package/dist/dispatch/engines/hooks-engine.d.ts +0 -96
- package/dist/dispatch/engines/hooks-engine.d.ts.map +0 -1
- package/dist/dispatch/engines/hooks-engine.js +0 -144
- package/dist/dispatch/engines/hooks-engine.js.map +0 -1
- package/dist/dispatch/engines/init-engine.d.ts +0 -56
- package/dist/dispatch/engines/init-engine.d.ts.map +0 -1
- package/dist/dispatch/engines/init-engine.js +0 -78
- package/dist/dispatch/engines/init-engine.js.map +0 -1
- package/dist/dispatch/engines/lifecycle-engine.d.ts +0 -66
- package/dist/dispatch/engines/lifecycle-engine.d.ts.map +0 -1
- package/dist/dispatch/engines/lifecycle-engine.js +0 -224
- package/dist/dispatch/engines/lifecycle-engine.js.map +0 -1
- package/dist/dispatch/engines/memory-engine.d.ts +0 -10
- package/dist/dispatch/engines/memory-engine.d.ts.map +0 -1
- package/dist/dispatch/engines/memory-engine.js +0 -10
- package/dist/dispatch/engines/memory-engine.js.map +0 -1
- package/dist/dispatch/engines/nexus-engine.d.ts +0 -167
- package/dist/dispatch/engines/nexus-engine.d.ts.map +0 -1
- package/dist/dispatch/engines/nexus-engine.js +0 -356
- package/dist/dispatch/engines/nexus-engine.js.map +0 -1
- package/dist/dispatch/engines/orchestrate-engine.d.ts +0 -141
- package/dist/dispatch/engines/orchestrate-engine.d.ts.map +0 -1
- package/dist/dispatch/engines/orchestrate-engine.js +0 -892
- package/dist/dispatch/engines/orchestrate-engine.js.map +0 -1
- package/dist/dispatch/engines/pipeline-engine.d.ts +0 -51
- package/dist/dispatch/engines/pipeline-engine.d.ts.map +0 -1
- package/dist/dispatch/engines/pipeline-engine.js +0 -191
- package/dist/dispatch/engines/pipeline-engine.js.map +0 -1
- package/dist/dispatch/engines/release-engine.d.ts +0 -94
- package/dist/dispatch/engines/release-engine.d.ts.map +0 -1
- package/dist/dispatch/engines/release-engine.js +0 -763
- package/dist/dispatch/engines/release-engine.js.map +0 -1
- package/dist/dispatch/engines/session-engine.d.ts +0 -387
- package/dist/dispatch/engines/session-engine.d.ts.map +0 -1
- package/dist/dispatch/engines/session-engine.js +0 -924
- package/dist/dispatch/engines/session-engine.js.map +0 -1
- package/dist/dispatch/engines/sticky-engine.d.ts +0 -100
- package/dist/dispatch/engines/sticky-engine.d.ts.map +0 -1
- package/dist/dispatch/engines/sticky-engine.js +0 -181
- package/dist/dispatch/engines/sticky-engine.js.map +0 -1
- package/dist/dispatch/engines/system-engine.d.ts +0 -543
- package/dist/dispatch/engines/system-engine.d.ts.map +0 -1
- package/dist/dispatch/engines/system-engine.js +0 -1273
- package/dist/dispatch/engines/system-engine.js.map +0 -1
- package/dist/dispatch/engines/task-engine.d.ts +0 -971
- package/dist/dispatch/engines/task-engine.d.ts.map +0 -1
- package/dist/dispatch/engines/task-engine.js +0 -1255
- package/dist/dispatch/engines/task-engine.js.map +0 -1
- package/dist/dispatch/engines/template-parser.d.ts +0 -85
- package/dist/dispatch/engines/template-parser.d.ts.map +0 -1
- package/dist/dispatch/engines/template-parser.js +0 -108
- package/dist/dispatch/engines/template-parser.js.map +0 -1
- package/dist/dispatch/engines/tools-engine.d.ts +0 -270
- package/dist/dispatch/engines/tools-engine.d.ts.map +0 -1
- package/dist/dispatch/engines/tools-engine.js +0 -663
- package/dist/dispatch/engines/tools-engine.js.map +0 -1
- package/dist/dispatch/engines/validate-engine.d.ts +0 -218
- package/dist/dispatch/engines/validate-engine.d.ts.map +0 -1
- package/dist/dispatch/engines/validate-engine.js +0 -737
- package/dist/dispatch/engines/validate-engine.js.map +0 -1
- package/dist/dispatch/index.d.ts +0 -20
- package/dist/dispatch/index.d.ts.map +0 -1
- package/dist/dispatch/index.js +0 -19
- package/dist/dispatch/index.js.map +0 -1
- package/dist/dispatch/lib/background-jobs.d.ts +0 -86
- package/dist/dispatch/lib/background-jobs.d.ts.map +0 -1
- package/dist/dispatch/lib/background-jobs.js +0 -183
- package/dist/dispatch/lib/background-jobs.js.map +0 -1
- package/dist/dispatch/lib/budget.d.ts +0 -36
- package/dist/dispatch/lib/budget.d.ts.map +0 -1
- package/dist/dispatch/lib/budget.js +0 -109
- package/dist/dispatch/lib/budget.js.map +0 -1
- package/dist/dispatch/lib/capability-matrix.d.ts +0 -11
- package/dist/dispatch/lib/capability-matrix.d.ts.map +0 -1
- package/dist/dispatch/lib/capability-matrix.js +0 -10
- package/dist/dispatch/lib/capability-matrix.js.map +0 -1
- package/dist/dispatch/lib/config-loader.d.ts +0 -42
- package/dist/dispatch/lib/config-loader.d.ts.map +0 -1
- package/dist/dispatch/lib/config-loader.js +0 -217
- package/dist/dispatch/lib/config-loader.js.map +0 -1
- package/dist/dispatch/lib/config.d.ts +0 -11
- package/dist/dispatch/lib/config.d.ts.map +0 -1
- package/dist/dispatch/lib/config.js +0 -10
- package/dist/dispatch/lib/config.js.map +0 -1
- package/dist/dispatch/lib/defaults.d.ts +0 -115
- package/dist/dispatch/lib/defaults.d.ts.map +0 -1
- package/dist/dispatch/lib/defaults.js +0 -61
- package/dist/dispatch/lib/defaults.js.map +0 -1
- package/dist/dispatch/lib/engine.d.ts +0 -26
- package/dist/dispatch/lib/engine.d.ts.map +0 -1
- package/dist/dispatch/lib/engine.js +0 -46
- package/dist/dispatch/lib/engine.js.map +0 -1
- package/dist/dispatch/lib/exit-codes.d.ts +0 -35
- package/dist/dispatch/lib/exit-codes.d.ts.map +0 -1
- package/dist/dispatch/lib/exit-codes.js +0 -60
- package/dist/dispatch/lib/exit-codes.js.map +0 -1
- package/dist/dispatch/lib/gateway-meta.d.ts +0 -37
- package/dist/dispatch/lib/gateway-meta.d.ts.map +0 -1
- package/dist/dispatch/lib/gateway-meta.js +0 -50
- package/dist/dispatch/lib/gateway-meta.js.map +0 -1
- package/dist/dispatch/lib/job-manager-accessor.d.ts +0 -9
- package/dist/dispatch/lib/job-manager-accessor.d.ts.map +0 -1
- package/dist/dispatch/lib/job-manager-accessor.js +0 -13
- package/dist/dispatch/lib/job-manager-accessor.js.map +0 -1
- package/dist/dispatch/lib/meta.d.ts +0 -26
- package/dist/dispatch/lib/meta.d.ts.map +0 -1
- package/dist/dispatch/lib/meta.js +0 -37
- package/dist/dispatch/lib/meta.js.map +0 -1
- package/dist/dispatch/lib/param-utils.d.ts +0 -11
- package/dist/dispatch/lib/param-utils.d.ts.map +0 -1
- package/dist/dispatch/lib/param-utils.js +0 -10
- package/dist/dispatch/lib/param-utils.js.map +0 -1
- package/dist/dispatch/lib/projections.d.ts +0 -56
- package/dist/dispatch/lib/projections.d.ts.map +0 -1
- package/dist/dispatch/lib/projections.js +0 -65
- package/dist/dispatch/lib/projections.js.map +0 -1
- package/dist/dispatch/lib/proto-envelope.d.ts +0 -56
- package/dist/dispatch/lib/proto-envelope.d.ts.map +0 -1
- package/dist/dispatch/lib/proto-envelope.js +0 -17
- package/dist/dispatch/lib/proto-envelope.js.map +0 -1
- package/dist/dispatch/lib/schema-utils.d.ts +0 -39
- package/dist/dispatch/lib/schema-utils.d.ts.map +0 -1
- package/dist/dispatch/lib/schema-utils.js +0 -88
- package/dist/dispatch/lib/schema-utils.js.map +0 -1
- package/dist/dispatch/lib/security.d.ts +0 -11
- package/dist/dispatch/lib/security.d.ts.map +0 -1
- package/dist/dispatch/lib/security.js +0 -10
- package/dist/dispatch/lib/security.js.map +0 -1
- package/dist/dispatch/middleware/audit.d.ts +0 -23
- package/dist/dispatch/middleware/audit.d.ts.map +0 -1
- package/dist/dispatch/middleware/audit.js +0 -169
- package/dist/dispatch/middleware/audit.js.map +0 -1
- package/dist/dispatch/middleware/field-filter.d.ts +0 -25
- package/dist/dispatch/middleware/field-filter.d.ts.map +0 -1
- package/dist/dispatch/middleware/field-filter.js +0 -70
- package/dist/dispatch/middleware/field-filter.js.map +0 -1
- package/dist/dispatch/middleware/pipeline.d.ts +0 -33
- package/dist/dispatch/middleware/pipeline.d.ts.map +0 -1
- package/dist/dispatch/middleware/pipeline.js +0 -60
- package/dist/dispatch/middleware/pipeline.js.map +0 -1
- package/dist/dispatch/middleware/projection.d.ts +0 -35
- package/dist/dispatch/middleware/projection.d.ts.map +0 -1
- package/dist/dispatch/middleware/projection.js +0 -146
- package/dist/dispatch/middleware/projection.js.map +0 -1
- package/dist/dispatch/middleware/protocol-enforcement.d.ts +0 -30
- package/dist/dispatch/middleware/protocol-enforcement.d.ts.map +0 -1
- package/dist/dispatch/middleware/protocol-enforcement.js +0 -56
- package/dist/dispatch/middleware/protocol-enforcement.js.map +0 -1
- package/dist/dispatch/middleware/rate-limiter.d.ts +0 -72
- package/dist/dispatch/middleware/rate-limiter.d.ts.map +0 -1
- package/dist/dispatch/middleware/rate-limiter.js +0 -127
- package/dist/dispatch/middleware/rate-limiter.js.map +0 -1
- package/dist/dispatch/middleware/sanitizer.d.ts +0 -24
- package/dist/dispatch/middleware/sanitizer.d.ts.map +0 -1
- package/dist/dispatch/middleware/sanitizer.js +0 -56
- package/dist/dispatch/middleware/sanitizer.js.map +0 -1
- package/dist/dispatch/middleware/session-resolver.d.ts +0 -26
- package/dist/dispatch/middleware/session-resolver.d.ts.map +0 -1
- package/dist/dispatch/middleware/session-resolver.js +0 -65
- package/dist/dispatch/middleware/session-resolver.js.map +0 -1
- package/dist/dispatch/middleware/telemetry.d.ts +0 -21
- package/dist/dispatch/middleware/telemetry.d.ts.map +0 -1
- package/dist/dispatch/middleware/telemetry.js +0 -50
- package/dist/dispatch/middleware/telemetry.js.map +0 -1
- package/dist/dispatch/middleware/verification-gates.d.ts +0 -22
- package/dist/dispatch/middleware/verification-gates.d.ts.map +0 -1
- package/dist/dispatch/middleware/verification-gates.js +0 -59
- package/dist/dispatch/middleware/verification-gates.js.map +0 -1
- package/dist/dispatch/registry.d.ts +0 -91
- package/dist/dispatch/registry.d.ts.map +0 -1
- package/dist/dispatch/registry.js +0 -3535
- package/dist/dispatch/registry.js.map +0 -1
- package/dist/dispatch/types.d.ts +0 -206
- package/dist/dispatch/types.d.ts.map +0 -1
- package/dist/dispatch/types.js +0 -27
- package/dist/dispatch/types.js.map +0 -1
|
@@ -1,2270 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CLI agent command group — agent credential management (unified registry).
|
|
3
|
-
*
|
|
4
|
-
* Provides:
|
|
5
|
-
* cleo agent register — register a new agent credential
|
|
6
|
-
* cleo agent list — list all registered agent credentials
|
|
7
|
-
* cleo agent get <id> — get a specific agent credential
|
|
8
|
-
* cleo agent remove <id> — remove an agent credential
|
|
9
|
-
* cleo agent rotate-key <id> — rotate an agent's API key
|
|
10
|
-
* cleo agent poll — one-shot message check
|
|
11
|
-
* cleo agent send — send a message to an agent or conversation
|
|
12
|
-
* cleo agent start — start the daemon poller for an agent
|
|
13
|
-
* cleo agent install — install an agent from .cantz archive or directory
|
|
14
|
-
* cleo agent pack — package an agent directory as .cantz archive
|
|
15
|
-
* cleo agent create — scaffold a new agent package with persona.cant and manifest.json
|
|
16
|
-
*
|
|
17
|
-
* **Daemon vs. Pi session — important distinction.** The daemon spawned
|
|
18
|
-
* by `cleo agent start` ONLY polls SignalDock for inbound messages and
|
|
19
|
-
* keeps the cloud status indicator green. It does NOT execute CANT
|
|
20
|
-
* workflow profiles inside the daemon process. CANT workflow execution
|
|
21
|
-
* (sessions, parallel arms, conditionals, approval gates, discretion
|
|
22
|
-
* evaluation, etc.) lives entirely inside the
|
|
23
|
-
* `cant-bridge.ts` Pi extension at
|
|
24
|
-
* `packages/cleo/templates/cleoos-hub/pi-extensions/cant-bridge.ts`,
|
|
25
|
-
* which interprets `.cant` files via shell-out to the `cleo cant`
|
|
26
|
-
* command family. Operators who want profile-driven behaviour should
|
|
27
|
-
* start a Pi session and use `/cant:load <file>` followed by
|
|
28
|
-
* `/cant:run <file> <workflowName>`. The daemon and the Pi session are
|
|
29
|
-
* distinct runtimes with distinct purposes, by design (see ADR-035 §D5
|
|
30
|
-
* "Option Y" addendum).
|
|
31
|
-
*
|
|
32
|
-
* @see docs/specs/SIGNALDOCK-UNIFIED-AGENT-REGISTRY.md Section 3.4
|
|
33
|
-
* @see .cleo/adrs/ADR-035-pi-v2-v3-harness.md §D5 + Addendum
|
|
34
|
-
* @task T178
|
|
35
|
-
*/
|
|
36
|
-
import { checkAgentHealth, detectCrashedAgents, detectStaleAgents, getHealthReport, STALE_THRESHOLD_MS, } from '@cleocode/core/internal';
|
|
37
|
-
import { cliOutput } from '../renderers/index.js';
|
|
38
|
-
import { computeProfileStatus } from './agent-profile-status.js';
|
|
39
|
-
/**
|
|
40
|
-
* Register the `cleo agent` command group.
|
|
41
|
-
*/
|
|
42
|
-
export function registerAgentCommand(program) {
|
|
43
|
-
const agent = program.command('agent').description('Agent lifecycle, credentials, and messaging');
|
|
44
|
-
// --- cleo agent register ---
|
|
45
|
-
agent
|
|
46
|
-
.command('register')
|
|
47
|
-
.description('Register a new agent credential in the local registry')
|
|
48
|
-
.requiredOption('--id <agentId>', 'Unique agent identifier')
|
|
49
|
-
.requiredOption('--name <displayName>', 'Human-readable display name')
|
|
50
|
-
.requiredOption('--api-key <apiKey>', 'API key (sk_live_...)')
|
|
51
|
-
.option('--api-url <url>', 'API base URL', 'https://api.signaldock.io')
|
|
52
|
-
.option('--classification <class>', 'Agent classification (e.g. code_dev, orchestrator)')
|
|
53
|
-
.option('--privacy <tier>', 'Privacy tier: public, discoverable, private', 'public')
|
|
54
|
-
.action(async (opts) => {
|
|
55
|
-
try {
|
|
56
|
-
const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
|
|
57
|
-
await getDb();
|
|
58
|
-
const registry = new AgentRegistryAccessor(process.cwd());
|
|
59
|
-
const agentId = opts['id'];
|
|
60
|
-
const displayName = opts['name'];
|
|
61
|
-
const classification = opts['classification'];
|
|
62
|
-
const credential = await registry.register({
|
|
63
|
-
agentId,
|
|
64
|
-
displayName,
|
|
65
|
-
apiKey: opts['apiKey'],
|
|
66
|
-
apiBaseUrl: opts['apiUrl'] ?? 'https://api.signaldock.io',
|
|
67
|
-
classification,
|
|
68
|
-
privacyTier: opts['privacy'] ?? 'public',
|
|
69
|
-
capabilities: [],
|
|
70
|
-
skills: [],
|
|
71
|
-
transportType: 'http',
|
|
72
|
-
transportConfig: {},
|
|
73
|
-
isActive: true,
|
|
74
|
-
});
|
|
75
|
-
// Scaffold .cant persona file if it doesn't exist
|
|
76
|
-
const { existsSync, mkdirSync, writeFileSync } = await import('node:fs');
|
|
77
|
-
const { join } = await import('node:path');
|
|
78
|
-
const cantDir = join('.cleo', 'agents');
|
|
79
|
-
const cantPath = join(cantDir, `${agentId}.cant`);
|
|
80
|
-
let cantScaffolded = false;
|
|
81
|
-
if (!existsSync(cantPath)) {
|
|
82
|
-
mkdirSync(cantDir, { recursive: true });
|
|
83
|
-
const role = classification ?? 'specialist';
|
|
84
|
-
const cantContent = `---
|
|
85
|
-
kind: agent
|
|
86
|
-
version: 2
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
agent ${agentId}:
|
|
90
|
-
house: none
|
|
91
|
-
allegiance: canon
|
|
92
|
-
role: ${role}
|
|
93
|
-
parent: cleoos-opus-orchestrator
|
|
94
|
-
description: "${displayName}"
|
|
95
|
-
|
|
96
|
-
tone:
|
|
97
|
-
|
|
|
98
|
-
TODO: Describe how this agent communicates.
|
|
99
|
-
|
|
100
|
-
prompt:
|
|
101
|
-
|
|
|
102
|
-
TODO: Write the core behavioral instruction.
|
|
103
|
-
|
|
104
|
-
skills: [ct-cleo]
|
|
105
|
-
|
|
106
|
-
permissions:
|
|
107
|
-
tasks: read
|
|
108
|
-
session: read
|
|
109
|
-
memory: read
|
|
110
|
-
|
|
111
|
-
transport:
|
|
112
|
-
primary: local
|
|
113
|
-
fallback: sse
|
|
114
|
-
cloud: http
|
|
115
|
-
apiBaseUrl: https://api.signaldock.io
|
|
116
|
-
|
|
117
|
-
lifecycle:
|
|
118
|
-
start: cleo agent start ${agentId}
|
|
119
|
-
stop: cleo agent stop ${agentId}
|
|
120
|
-
status: cleo agent status ${agentId}
|
|
121
|
-
|
|
122
|
-
context:
|
|
123
|
-
active-tasks
|
|
124
|
-
memory-bridge
|
|
125
|
-
|
|
126
|
-
on SessionStart:
|
|
127
|
-
/checkin @all #online
|
|
128
|
-
|
|
129
|
-
enforcement:
|
|
130
|
-
1: TODO — what does this agent push back on?
|
|
131
|
-
`;
|
|
132
|
-
writeFileSync(cantPath, cantContent, 'utf-8');
|
|
133
|
-
cantScaffolded = true;
|
|
134
|
-
}
|
|
135
|
-
cliOutput({
|
|
136
|
-
success: true,
|
|
137
|
-
data: {
|
|
138
|
-
agentId: credential.agentId,
|
|
139
|
-
displayName: credential.displayName,
|
|
140
|
-
cantFile: cantScaffolded ? cantPath : existsSync(cantPath) ? cantPath : null,
|
|
141
|
-
cantScaffolded,
|
|
142
|
-
},
|
|
143
|
-
}, { command: 'agent register' });
|
|
144
|
-
}
|
|
145
|
-
catch (err) {
|
|
146
|
-
cliOutput({ success: false, error: { code: 'E_REGISTER', message: String(err) } }, { command: 'agent register' });
|
|
147
|
-
process.exitCode = 1;
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
// --- cleo agent signin ---
|
|
151
|
-
agent
|
|
152
|
-
.command('signin <agentId>')
|
|
153
|
-
.description('Sign in as an agent — marks active, caches credentials for session')
|
|
154
|
-
.option('--api-url <url>', 'Override API base URL for cloud status update')
|
|
155
|
-
.action(async (agentId, opts) => {
|
|
156
|
-
try {
|
|
157
|
-
const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
|
|
158
|
-
await getDb();
|
|
159
|
-
const registry = new AgentRegistryAccessor(process.cwd());
|
|
160
|
-
// Look up the credential
|
|
161
|
-
const credential = await registry.get(agentId);
|
|
162
|
-
if (!credential) {
|
|
163
|
-
cliOutput({
|
|
164
|
-
success: false,
|
|
165
|
-
error: {
|
|
166
|
-
code: 'E_NOT_FOUND',
|
|
167
|
-
message: `Agent '${agentId}' not registered. Run: cleo agent register --id ${agentId} --name "..." --api-key sk_live_...`,
|
|
168
|
-
},
|
|
169
|
-
}, { command: 'agent signin' });
|
|
170
|
-
process.exitCode = 1;
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
// Mark as active + update lastUsedAt
|
|
174
|
-
await registry.update(agentId, { isActive: true });
|
|
175
|
-
await registry.markUsed(agentId);
|
|
176
|
-
// Attempt to set online status on cloud (best-effort, don't fail if offline)
|
|
177
|
-
const apiUrl = opts['apiUrl'] ?? credential.apiBaseUrl;
|
|
178
|
-
try {
|
|
179
|
-
await fetch(`${apiUrl}/agents/${agentId}/status`, {
|
|
180
|
-
method: 'PUT',
|
|
181
|
-
headers: {
|
|
182
|
-
'Content-Type': 'application/json',
|
|
183
|
-
Authorization: `Bearer ${credential.apiKey}`,
|
|
184
|
-
'X-Agent-Id': agentId,
|
|
185
|
-
},
|
|
186
|
-
body: JSON.stringify({ status: 'online' }),
|
|
187
|
-
signal: AbortSignal.timeout(5000),
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
catch {
|
|
191
|
-
// Offline is fine — LocalTransport works without cloud
|
|
192
|
-
}
|
|
193
|
-
cliOutput({
|
|
194
|
-
success: true,
|
|
195
|
-
data: {
|
|
196
|
-
agentId: credential.agentId,
|
|
197
|
-
displayName: credential.displayName,
|
|
198
|
-
apiBaseUrl: apiUrl,
|
|
199
|
-
status: 'online',
|
|
200
|
-
transport: 'local',
|
|
201
|
-
},
|
|
202
|
-
}, { command: 'agent signin' });
|
|
203
|
-
}
|
|
204
|
-
catch (err) {
|
|
205
|
-
cliOutput({ success: false, error: { code: 'E_SIGNIN', message: String(err) } }, { command: 'agent signin' });
|
|
206
|
-
process.exitCode = 1;
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
// --- cleo agent start ---
|
|
210
|
-
// Boot the SignalDock-poller daemon for an agent.
|
|
211
|
-
//
|
|
212
|
-
// Profile handling:
|
|
213
|
-
// The `--cant <file>` option (or the default
|
|
214
|
-
// `.cleo/agents/<agentId>.cant` lookup) is read for two reasons:
|
|
215
|
-
//
|
|
216
|
-
// 1. **Fail-fast validation**: if the file exists and the optional
|
|
217
|
-
// `@cleocode/cant` validator is available in this build, the
|
|
218
|
-
// file is parsed so malformed profiles surface as a status
|
|
219
|
-
// string rather than blowing up later.
|
|
220
|
-
// 2. **Status surface**: the resulting status (`validated`,
|
|
221
|
-
// `invalid (N errors)`, `loaded (unvalidated)`, or `none`) is
|
|
222
|
-
// reported in the LAFS envelope so operators know the daemon
|
|
223
|
-
// saw the file they expected.
|
|
224
|
-
//
|
|
225
|
-
// The profile string is then DROPPED. The daemon does NOT execute
|
|
226
|
-
// workflow profiles. Profile-driven behaviour (sessions, parallel
|
|
227
|
-
// arms, conditionals, approval gates, discretion evaluation) runs
|
|
228
|
-
// inside Pi sessions through the `cant-bridge.ts` Pi extension at
|
|
229
|
-
// `packages/cleo/templates/cleoos-hub/pi-extensions/cant-bridge.ts`.
|
|
230
|
-
// Operators who want profile execution should start a Pi session
|
|
231
|
-
// and run `/cant:load <file>` followed by
|
|
232
|
-
// `/cant:run <file> <workflowName>`.
|
|
233
|
-
//
|
|
234
|
-
// See ADR-035 §D5 (Option Y addendum) for the architectural
|
|
235
|
-
// rationale: there is exactly ONE workflow execution engine in
|
|
236
|
-
// CleoOS — `cant-bridge.ts` — and it lives inside Pi by design.
|
|
237
|
-
agent
|
|
238
|
-
.command('start <agentId>')
|
|
239
|
-
.description('Start an agent daemon — polls SignalDock for messages. Profile is validated for fail-fast feedback only; CANT execution lives in Pi via cant-bridge.ts.')
|
|
240
|
-
.option('--cant <file>', 'Path to .cant persona file (validated only, NOT executed by the daemon)')
|
|
241
|
-
.option('--poll-interval <ms>', 'Poll interval in milliseconds', '5000')
|
|
242
|
-
.option('--no-heartbeat', 'Disable heartbeat service')
|
|
243
|
-
.action(async (agentId, opts) => {
|
|
244
|
-
try {
|
|
245
|
-
const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
|
|
246
|
-
const { createRuntime } = await import('@cleocode/runtime');
|
|
247
|
-
const { existsSync, readFileSync } = await import('node:fs');
|
|
248
|
-
const { join } = await import('node:path');
|
|
249
|
-
await getDb();
|
|
250
|
-
const registry = new AgentRegistryAccessor(process.cwd());
|
|
251
|
-
// 1. Look up credential
|
|
252
|
-
const credential = await registry.get(agentId);
|
|
253
|
-
if (!credential) {
|
|
254
|
-
cliOutput({
|
|
255
|
-
success: false,
|
|
256
|
-
error: {
|
|
257
|
-
code: 'E_NOT_FOUND',
|
|
258
|
-
message: `Agent '${agentId}' not registered. Run: cleo agent register --id ${agentId} --name "..." --api-key sk_live_...`,
|
|
259
|
-
},
|
|
260
|
-
}, { command: 'agent start' });
|
|
261
|
-
process.exitCode = 1;
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
// 2. Read and (best-effort) validate the .cant profile.
|
|
265
|
-
// This is FAIL-FAST GUARDING ONLY. The profile string is
|
|
266
|
-
// used to compute a status field below, then dropped. The
|
|
267
|
-
// daemon does not interpret the workflow body — see the
|
|
268
|
-
// block comment above this command for why.
|
|
269
|
-
let profile = null;
|
|
270
|
-
let cantValidation = null;
|
|
271
|
-
const cantPath = opts['cant'] ?? join('.cleo', 'agents', `${agentId}.cant`);
|
|
272
|
-
if (existsSync(cantPath)) {
|
|
273
|
-
profile = readFileSync(cantPath, 'utf-8');
|
|
274
|
-
try {
|
|
275
|
-
const cantModule = await import('@cleocode/cant');
|
|
276
|
-
// validate() may not be available in all builds of @cleocode/cant
|
|
277
|
-
const validate = 'validate' in cantModule
|
|
278
|
-
? cantModule.validate
|
|
279
|
-
: null;
|
|
280
|
-
if (validate) {
|
|
281
|
-
const result = validate(profile);
|
|
282
|
-
cantValidation = {
|
|
283
|
-
valid: result.valid,
|
|
284
|
-
errors: result.diagnostics?.map((d) => d.message) ?? [],
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
catch {
|
|
289
|
-
// cant-napi not available — profile loaded but unvalidated
|
|
290
|
-
cantValidation = null;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
// 3. Mark active + update lastUsedAt
|
|
294
|
-
await registry.update(agentId, { isActive: true });
|
|
295
|
-
await registry.markUsed(agentId);
|
|
296
|
-
// 4. Set cloud status (best-effort)
|
|
297
|
-
try {
|
|
298
|
-
await fetch(`${credential.apiBaseUrl}/agents/${agentId}/status`, {
|
|
299
|
-
method: 'PUT',
|
|
300
|
-
headers: {
|
|
301
|
-
'Content-Type': 'application/json',
|
|
302
|
-
Authorization: `Bearer ${credential.apiKey}`,
|
|
303
|
-
'X-Agent-Id': agentId,
|
|
304
|
-
},
|
|
305
|
-
body: JSON.stringify({ status: 'online' }),
|
|
306
|
-
signal: AbortSignal.timeout(5000),
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
catch {
|
|
310
|
-
// Offline is fine — LocalTransport works without cloud
|
|
311
|
-
}
|
|
312
|
-
// 5. Start runtime services (transport auto-resolved: Local > SSE > HTTP).
|
|
313
|
-
// Note: createRuntime() does NOT receive the profile. The
|
|
314
|
-
// daemon's job is purely SignalDock polling + cloud status.
|
|
315
|
-
const pollInterval = Number(opts['pollInterval'] ?? 5000);
|
|
316
|
-
const runtime = await createRuntime(registry, {
|
|
317
|
-
agentId,
|
|
318
|
-
pollIntervalMs: pollInterval,
|
|
319
|
-
heartbeatIntervalMs: opts['heartbeat'] === false ? 0 : 30000,
|
|
320
|
-
groupConversationIds: [],
|
|
321
|
-
});
|
|
322
|
-
runtime.poller.start();
|
|
323
|
-
cliOutput({
|
|
324
|
-
success: true,
|
|
325
|
-
data: {
|
|
326
|
-
agentId,
|
|
327
|
-
displayName: credential.displayName,
|
|
328
|
-
status: 'online',
|
|
329
|
-
transport: runtime.transport.name,
|
|
330
|
-
// Surfaced for operator visibility only — see
|
|
331
|
-
// computeProfileStatus tsdoc for the four possible values.
|
|
332
|
-
profile: computeProfileStatus(profile, cantValidation),
|
|
333
|
-
services: {
|
|
334
|
-
poller: 'running',
|
|
335
|
-
heartbeat: runtime.heartbeat ? 'running' : 'disabled',
|
|
336
|
-
keyRotation: runtime.keyRotation ? 'running' : 'disabled',
|
|
337
|
-
},
|
|
338
|
-
},
|
|
339
|
-
}, { command: 'agent start' });
|
|
340
|
-
// 6. Keep process alive until shutdown signal (cross-platform)
|
|
341
|
-
const shutdown = () => {
|
|
342
|
-
runtime.stop();
|
|
343
|
-
void registry.update(agentId, { isActive: false }).catch(() => { });
|
|
344
|
-
process.exit(0);
|
|
345
|
-
};
|
|
346
|
-
process.on('SIGINT', shutdown);
|
|
347
|
-
process.on('SIGTERM', shutdown);
|
|
348
|
-
// Windows: listen for 'message' from parent process managers (PM2, etc.)
|
|
349
|
-
if (process.platform === 'win32') {
|
|
350
|
-
process.on('message', (msg) => {
|
|
351
|
-
if (msg === 'shutdown')
|
|
352
|
-
shutdown();
|
|
353
|
-
});
|
|
354
|
-
}
|
|
355
|
-
// Keep alive
|
|
356
|
-
await new Promise(() => { });
|
|
357
|
-
}
|
|
358
|
-
catch (err) {
|
|
359
|
-
cliOutput({ success: false, error: { code: 'E_START', message: String(err) } }, { command: 'agent start' });
|
|
360
|
-
process.exitCode = 1;
|
|
361
|
-
}
|
|
362
|
-
});
|
|
363
|
-
// --- cleo agent stop ---
|
|
364
|
-
agent
|
|
365
|
-
.command('stop <agentId>')
|
|
366
|
-
.description('Stop an agent — mark offline and deactivate')
|
|
367
|
-
.action(async (agentId) => {
|
|
368
|
-
try {
|
|
369
|
-
const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
|
|
370
|
-
await getDb();
|
|
371
|
-
const registry = new AgentRegistryAccessor(process.cwd());
|
|
372
|
-
const credential = await registry.get(agentId);
|
|
373
|
-
if (!credential) {
|
|
374
|
-
cliOutput({
|
|
375
|
-
success: false,
|
|
376
|
-
error: { code: 'E_NOT_FOUND', message: `Agent '${agentId}' not registered.` },
|
|
377
|
-
}, { command: 'agent stop' });
|
|
378
|
-
process.exitCode = 1;
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
// Mark inactive
|
|
382
|
-
await registry.update(agentId, { isActive: false });
|
|
383
|
-
// Set cloud status offline (best-effort)
|
|
384
|
-
try {
|
|
385
|
-
await fetch(`${credential.apiBaseUrl}/agents/${agentId}/status`, {
|
|
386
|
-
method: 'PUT',
|
|
387
|
-
headers: {
|
|
388
|
-
'Content-Type': 'application/json',
|
|
389
|
-
Authorization: `Bearer ${credential.apiKey}`,
|
|
390
|
-
'X-Agent-Id': agentId,
|
|
391
|
-
},
|
|
392
|
-
body: JSON.stringify({ status: 'offline' }),
|
|
393
|
-
signal: AbortSignal.timeout(5000),
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
catch {
|
|
397
|
-
// Offline is fine
|
|
398
|
-
}
|
|
399
|
-
cliOutput({ success: true, data: { agentId, status: 'offline' } }, { command: 'agent stop' });
|
|
400
|
-
}
|
|
401
|
-
catch (err) {
|
|
402
|
-
cliOutput({ success: false, error: { code: 'E_STOP', message: String(err) } }, { command: 'agent stop' });
|
|
403
|
-
process.exitCode = 1;
|
|
404
|
-
}
|
|
405
|
-
});
|
|
406
|
-
// --- cleo agent status ---
|
|
407
|
-
agent
|
|
408
|
-
.command('status [agentId]')
|
|
409
|
-
.description('Show agent status — all agents or specific agent')
|
|
410
|
-
.action(async (agentId) => {
|
|
411
|
-
try {
|
|
412
|
-
const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
|
|
413
|
-
await getDb();
|
|
414
|
-
const registry = new AgentRegistryAccessor(process.cwd());
|
|
415
|
-
if (agentId) {
|
|
416
|
-
const credential = await registry.get(agentId);
|
|
417
|
-
if (!credential) {
|
|
418
|
-
cliOutput({
|
|
419
|
-
success: false,
|
|
420
|
-
error: { code: 'E_NOT_FOUND', message: `Agent '${agentId}' not registered.` },
|
|
421
|
-
}, { command: 'agent status' });
|
|
422
|
-
process.exitCode = 1;
|
|
423
|
-
return;
|
|
424
|
-
}
|
|
425
|
-
cliOutput({
|
|
426
|
-
success: true,
|
|
427
|
-
data: {
|
|
428
|
-
agentId: credential.agentId,
|
|
429
|
-
displayName: credential.displayName,
|
|
430
|
-
active: credential.isActive,
|
|
431
|
-
lastUsedAt: credential.lastUsedAt,
|
|
432
|
-
transport: credential.transportType,
|
|
433
|
-
},
|
|
434
|
-
}, { command: 'agent status' });
|
|
435
|
-
}
|
|
436
|
-
else {
|
|
437
|
-
const agents = await registry.list();
|
|
438
|
-
cliOutput({
|
|
439
|
-
success: true,
|
|
440
|
-
data: {
|
|
441
|
-
agents: agents.map((a) => ({
|
|
442
|
-
agentId: a.agentId,
|
|
443
|
-
displayName: a.displayName,
|
|
444
|
-
active: a.isActive,
|
|
445
|
-
lastUsedAt: a.lastUsedAt,
|
|
446
|
-
})),
|
|
447
|
-
total: agents.length,
|
|
448
|
-
},
|
|
449
|
-
}, { command: 'agent status' });
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
catch (err) {
|
|
453
|
-
cliOutput({ success: false, error: { code: 'E_STATUS', message: String(err) } }, { command: 'agent status' });
|
|
454
|
-
process.exitCode = 1;
|
|
455
|
-
}
|
|
456
|
-
});
|
|
457
|
-
// --- cleo agent assign ---
|
|
458
|
-
agent
|
|
459
|
-
.command('assign <agentId> <taskId>')
|
|
460
|
-
.description('Assign a task to an agent via messaging')
|
|
461
|
-
.action(async (agentId, taskId) => {
|
|
462
|
-
try {
|
|
463
|
-
const { AgentRegistryAccessor, getDb, createConduit } = await import('@cleocode/core/internal');
|
|
464
|
-
await getDb();
|
|
465
|
-
const registry = new AgentRegistryAccessor(process.cwd());
|
|
466
|
-
const active = await registry.getActive();
|
|
467
|
-
if (!active) {
|
|
468
|
-
cliOutput({
|
|
469
|
-
success: false,
|
|
470
|
-
error: {
|
|
471
|
-
code: 'E_NO_ACTIVE',
|
|
472
|
-
message: 'No active agent. Run: cleo agent signin <id>',
|
|
473
|
-
},
|
|
474
|
-
}, { command: 'agent assign' });
|
|
475
|
-
process.exitCode = 1;
|
|
476
|
-
return;
|
|
477
|
-
}
|
|
478
|
-
const conduit = await createConduit(registry);
|
|
479
|
-
await conduit.send(agentId, `/action @${agentId} #task-assignment\n\nAssigned task ${taskId}. Run: cleo show ${taskId} && cleo start ${taskId}`);
|
|
480
|
-
await conduit.disconnect();
|
|
481
|
-
cliOutput({
|
|
482
|
-
success: true,
|
|
483
|
-
data: { agentId, taskId, assignedBy: active.agentId },
|
|
484
|
-
}, { command: 'agent assign' });
|
|
485
|
-
}
|
|
486
|
-
catch (err) {
|
|
487
|
-
cliOutput({ success: false, error: { code: 'E_ASSIGN', message: String(err) } }, { command: 'agent assign' });
|
|
488
|
-
process.exitCode = 1;
|
|
489
|
-
}
|
|
490
|
-
});
|
|
491
|
-
// --- cleo agent wake ---
|
|
492
|
-
agent
|
|
493
|
-
.command('wake <agentId>')
|
|
494
|
-
.description('Wake an idle agent — send a prod message')
|
|
495
|
-
.action(async (agentId) => {
|
|
496
|
-
try {
|
|
497
|
-
const { AgentRegistryAccessor, getDb, createConduit } = await import('@cleocode/core/internal');
|
|
498
|
-
await getDb();
|
|
499
|
-
const registry = new AgentRegistryAccessor(process.cwd());
|
|
500
|
-
const active = await registry.getActive();
|
|
501
|
-
if (!active) {
|
|
502
|
-
cliOutput({
|
|
503
|
-
success: false,
|
|
504
|
-
error: {
|
|
505
|
-
code: 'E_NO_ACTIVE',
|
|
506
|
-
message: 'No active agent. Run: cleo agent signin <id>',
|
|
507
|
-
},
|
|
508
|
-
}, { command: 'agent wake' });
|
|
509
|
-
process.exitCode = 1;
|
|
510
|
-
return;
|
|
511
|
-
}
|
|
512
|
-
const conduit = await createConduit(registry);
|
|
513
|
-
await conduit.send(agentId, `/action @${agentId} #wake #prod\n\nYou are idle. Check your queue: cleo current || cleo next. Report status immediately.`);
|
|
514
|
-
await conduit.disconnect();
|
|
515
|
-
cliOutput({ success: true, data: { agentId, prodBy: active.agentId } }, { command: 'agent wake' });
|
|
516
|
-
}
|
|
517
|
-
catch (err) {
|
|
518
|
-
cliOutput({ success: false, error: { code: 'E_WAKE', message: String(err) } }, { command: 'agent wake' });
|
|
519
|
-
process.exitCode = 1;
|
|
520
|
-
}
|
|
521
|
-
});
|
|
522
|
-
// --- cleo agent spawn ---
|
|
523
|
-
agent
|
|
524
|
-
.command('spawn')
|
|
525
|
-
.description('Spawn a new ephemeral agent for a specific task')
|
|
526
|
-
.requiredOption('--role <role>', 'Agent role (e.g. code_dev, research, security)')
|
|
527
|
-
.option('--task <taskId>', 'Task to assign to the spawned agent')
|
|
528
|
-
.option('--model <model>', 'Model to use (e.g. opus, sonnet)')
|
|
529
|
-
.option('--name <name>', 'Display name for the agent')
|
|
530
|
-
.action(async (opts) => {
|
|
531
|
-
try {
|
|
532
|
-
const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
|
|
533
|
-
await getDb();
|
|
534
|
-
const registry = new AgentRegistryAccessor(process.cwd());
|
|
535
|
-
const role = opts['role'];
|
|
536
|
-
const taskId = opts['task'];
|
|
537
|
-
const model = opts['model'] ?? 'sonnet';
|
|
538
|
-
const displayName = opts['name'] ?? `ephemeral-${role}-${Date.now().toString(36)}`;
|
|
539
|
-
const agentId = displayName;
|
|
540
|
-
// Register the ephemeral agent locally (no cloud registration)
|
|
541
|
-
await registry.register({
|
|
542
|
-
agentId,
|
|
543
|
-
displayName,
|
|
544
|
-
apiKey: 'ephemeral-local-only',
|
|
545
|
-
apiBaseUrl: 'local',
|
|
546
|
-
classification: role,
|
|
547
|
-
privacyTier: 'private',
|
|
548
|
-
capabilities: ['chat', 'tools'],
|
|
549
|
-
skills: [role],
|
|
550
|
-
transportType: 'http',
|
|
551
|
-
transportConfig: {},
|
|
552
|
-
isActive: true,
|
|
553
|
-
});
|
|
554
|
-
cliOutput({
|
|
555
|
-
success: true,
|
|
556
|
-
data: {
|
|
557
|
-
agentId,
|
|
558
|
-
displayName,
|
|
559
|
-
role,
|
|
560
|
-
model,
|
|
561
|
-
taskId: taskId ?? null,
|
|
562
|
-
transport: 'local',
|
|
563
|
-
lifecycle: 'ephemeral',
|
|
564
|
-
},
|
|
565
|
-
}, { command: 'agent spawn' });
|
|
566
|
-
}
|
|
567
|
-
catch (err) {
|
|
568
|
-
cliOutput({ success: false, error: { code: 'E_SPAWN', message: String(err) } }, { command: 'agent spawn' });
|
|
569
|
-
process.exitCode = 1;
|
|
570
|
-
}
|
|
571
|
-
});
|
|
572
|
-
// --- cleo agent reassign ---
|
|
573
|
-
agent
|
|
574
|
-
.command('reassign <taskId> <agentId>')
|
|
575
|
-
.description('Reassign a task to another agent via conduit message')
|
|
576
|
-
.action(async (taskId, agentId) => {
|
|
577
|
-
try {
|
|
578
|
-
const { AgentRegistryAccessor, getDb, createConduit } = await import('@cleocode/core/internal');
|
|
579
|
-
await getDb();
|
|
580
|
-
const registry = new AgentRegistryAccessor(process.cwd());
|
|
581
|
-
const active = await registry.getActive();
|
|
582
|
-
if (!active) {
|
|
583
|
-
cliOutput({ success: false, error: { code: 'E_NO_ACTIVE', message: 'No active agent.' } }, { command: 'agent reassign' });
|
|
584
|
-
process.exitCode = 1;
|
|
585
|
-
return;
|
|
586
|
-
}
|
|
587
|
-
const conduit = await createConduit(registry);
|
|
588
|
-
await conduit.send(agentId, `/action @${agentId} #task-reassignment\n\nTask ${taskId} reassigned to you by ${active.agentId}. Run: cleo show ${taskId} && cleo start ${taskId}`);
|
|
589
|
-
await conduit.disconnect();
|
|
590
|
-
cliOutput({ success: true, data: { taskId, newOwner: agentId, reassignedBy: active.agentId } }, { command: 'agent reassign' });
|
|
591
|
-
}
|
|
592
|
-
catch (err) {
|
|
593
|
-
cliOutput({ success: false, error: { code: 'E_REASSIGN', message: String(err) } }, { command: 'agent reassign' });
|
|
594
|
-
process.exitCode = 1;
|
|
595
|
-
}
|
|
596
|
-
});
|
|
597
|
-
// --- cleo agent stop-all ---
|
|
598
|
-
agent
|
|
599
|
-
.command('stop-all')
|
|
600
|
-
.description('Stop all active agents — mark all offline')
|
|
601
|
-
.action(async () => {
|
|
602
|
-
try {
|
|
603
|
-
const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
|
|
604
|
-
await getDb();
|
|
605
|
-
const registry = new AgentRegistryAccessor(process.cwd());
|
|
606
|
-
const agents = await registry.list({ active: true });
|
|
607
|
-
let stopped = 0;
|
|
608
|
-
for (const a of agents) {
|
|
609
|
-
await registry.update(a.agentId, { isActive: false });
|
|
610
|
-
try {
|
|
611
|
-
await fetch(`${a.apiBaseUrl}/agents/${a.agentId}/status`, {
|
|
612
|
-
method: 'PUT',
|
|
613
|
-
headers: {
|
|
614
|
-
'Content-Type': 'application/json',
|
|
615
|
-
Authorization: `Bearer ${a.apiKey}`,
|
|
616
|
-
'X-Agent-Id': a.agentId,
|
|
617
|
-
},
|
|
618
|
-
body: JSON.stringify({ status: 'offline' }),
|
|
619
|
-
signal: AbortSignal.timeout(3000),
|
|
620
|
-
});
|
|
621
|
-
}
|
|
622
|
-
catch {
|
|
623
|
-
/* best-effort */
|
|
624
|
-
}
|
|
625
|
-
stopped++;
|
|
626
|
-
}
|
|
627
|
-
cliOutput({ success: true, data: { stopped, total: agents.length } }, { command: 'agent stop-all' });
|
|
628
|
-
}
|
|
629
|
-
catch (err) {
|
|
630
|
-
cliOutput({ success: false, error: { code: 'E_STOP_ALL', message: String(err) } }, { command: 'agent stop-all' });
|
|
631
|
-
process.exitCode = 1;
|
|
632
|
-
}
|
|
633
|
-
});
|
|
634
|
-
// --- cleo agent work ---
|
|
635
|
-
agent
|
|
636
|
-
.command('work <agentId>')
|
|
637
|
-
.description('Enter autonomous work loop — poll tasks, report, optionally execute. Phase 3: --execute enables the Conductor Loop.')
|
|
638
|
-
.option('--poll-interval <ms>', 'Task check interval in milliseconds', '30000')
|
|
639
|
-
.option('--execute', 'Autonomously execute ready tasks via orchestrate.spawn.execute (Phase 3 Conductor Loop)')
|
|
640
|
-
.option('--adapter <id>', 'Adapter id to route spawns through (default: auto-detect from capabilities)')
|
|
641
|
-
.option('--epic <id>', 'Restrict autonomous execution to a specific epic (default: any ready task)')
|
|
642
|
-
.action(async (agentId, opts) => {
|
|
643
|
-
try {
|
|
644
|
-
const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
|
|
645
|
-
const { createRuntime } = await import('@cleocode/runtime');
|
|
646
|
-
const { existsSync } = await import('node:fs');
|
|
647
|
-
const { join } = await import('node:path');
|
|
648
|
-
const { execFile } = await import('node:child_process');
|
|
649
|
-
const { promisify } = await import('node:util');
|
|
650
|
-
const execFileAsync = promisify(execFile);
|
|
651
|
-
await getDb();
|
|
652
|
-
const registry = new AgentRegistryAccessor(process.cwd());
|
|
653
|
-
const credential = await registry.get(agentId);
|
|
654
|
-
if (!credential) {
|
|
655
|
-
cliOutput({
|
|
656
|
-
success: false,
|
|
657
|
-
error: { code: 'E_NOT_FOUND', message: `Agent '${agentId}' not registered.` },
|
|
658
|
-
}, { command: 'agent work' });
|
|
659
|
-
process.exitCode = 1;
|
|
660
|
-
return;
|
|
661
|
-
}
|
|
662
|
-
await registry.update(agentId, { isActive: true });
|
|
663
|
-
await registry.markUsed(agentId);
|
|
664
|
-
const cantPath = join('.cleo', 'agents', `${agentId}.cant`);
|
|
665
|
-
const hasProfile = existsSync(cantPath);
|
|
666
|
-
const runtime = await createRuntime(registry, {
|
|
667
|
-
agentId,
|
|
668
|
-
pollIntervalMs: 5000,
|
|
669
|
-
heartbeatIntervalMs: 30000,
|
|
670
|
-
});
|
|
671
|
-
runtime.poller.start();
|
|
672
|
-
const executeMode = opts['execute'] === true;
|
|
673
|
-
const epicRestrict = typeof opts['epic'] === 'string' ? opts['epic'] : undefined;
|
|
674
|
-
const adapterRestrict = typeof opts['adapter'] === 'string' ? opts['adapter'] : undefined;
|
|
675
|
-
cliOutput({
|
|
676
|
-
success: true,
|
|
677
|
-
data: {
|
|
678
|
-
agentId,
|
|
679
|
-
mode: executeMode ? 'conductor-loop' : 'watch-only',
|
|
680
|
-
profile: hasProfile ? 'loaded' : 'none',
|
|
681
|
-
status: 'running',
|
|
682
|
-
epic: epicRestrict ?? 'any',
|
|
683
|
-
adapter: adapterRestrict ?? 'auto',
|
|
684
|
-
},
|
|
685
|
-
}, { command: 'agent work' });
|
|
686
|
-
// Parse LAFS envelope from CLI stdout (handles both minimal and full shapes)
|
|
687
|
-
const parseLafs = (raw) => {
|
|
688
|
-
const lines = raw.trim().split('\n');
|
|
689
|
-
const envLine = [...lines].reverse().find((l) => l.startsWith('{'));
|
|
690
|
-
if (!envLine)
|
|
691
|
-
return undefined;
|
|
692
|
-
try {
|
|
693
|
-
const env = JSON.parse(envLine);
|
|
694
|
-
if (env.ok === true)
|
|
695
|
-
return env.r;
|
|
696
|
-
if (env.success === true)
|
|
697
|
-
return (env.result ?? env.data);
|
|
698
|
-
return undefined;
|
|
699
|
-
}
|
|
700
|
-
catch {
|
|
701
|
-
return undefined;
|
|
702
|
-
}
|
|
703
|
-
};
|
|
704
|
-
const runCleo = async (args, timeoutMs = 15000) => {
|
|
705
|
-
const { stdout } = await execFileAsync('cleo', args, {
|
|
706
|
-
encoding: 'utf-8',
|
|
707
|
-
timeout: timeoutMs,
|
|
708
|
-
});
|
|
709
|
-
return stdout;
|
|
710
|
-
};
|
|
711
|
-
const taskInterval = Number(opts['pollInterval'] ?? 30000);
|
|
712
|
-
let inFlight = false;
|
|
713
|
-
let iterations = 0;
|
|
714
|
-
const workLoop = setInterval(async () => {
|
|
715
|
-
if (inFlight)
|
|
716
|
-
return;
|
|
717
|
-
inFlight = true;
|
|
718
|
-
iterations += 1;
|
|
719
|
-
try {
|
|
720
|
-
const currentRaw = await runCleo(['current']).catch(() => '');
|
|
721
|
-
if (currentRaw.trim()) {
|
|
722
|
-
// A task is already in progress — skip
|
|
723
|
-
return;
|
|
724
|
-
}
|
|
725
|
-
// Resolve next ready task (respect epic restriction when set)
|
|
726
|
-
const nextArgs = epicRestrict ? ['orchestrate', 'next', epicRestrict] : ['next'];
|
|
727
|
-
const nextRaw = await runCleo(nextArgs).catch(() => '');
|
|
728
|
-
if (!nextRaw.trim())
|
|
729
|
-
return;
|
|
730
|
-
const nextData = parseLafs(nextRaw);
|
|
731
|
-
const taskId = nextData?.nextTask?.id ??
|
|
732
|
-
(typeof nextData?.id === 'string' ? nextData.id : undefined);
|
|
733
|
-
if (!taskId)
|
|
734
|
-
return;
|
|
735
|
-
if (!executeMode) {
|
|
736
|
-
// Watch-only legacy behaviour: advertise availability
|
|
737
|
-
console.log(`[${agentId}] Task available: ${taskId}. Pass --execute to run autonomously.`);
|
|
738
|
-
return;
|
|
739
|
-
}
|
|
740
|
-
// Phase 3 Conductor Loop: actually execute via orchestrate.spawn.execute
|
|
741
|
-
const spawnArgs = ['orchestrate', 'spawn', taskId];
|
|
742
|
-
if (adapterRestrict) {
|
|
743
|
-
spawnArgs.push('--adapter', adapterRestrict);
|
|
744
|
-
}
|
|
745
|
-
const spawnRaw = await runCleo(spawnArgs, 60000).catch((e) => {
|
|
746
|
-
console.error(`[${agentId}] conductor-loop: spawn failed for ${taskId}: ${String(e)}`);
|
|
747
|
-
return '';
|
|
748
|
-
});
|
|
749
|
-
const spawnData = parseLafs(spawnRaw);
|
|
750
|
-
if (spawnData?.instanceId) {
|
|
751
|
-
console.log(`[${agentId}] conductor-loop spawned task=${taskId} instance=${spawnData.instanceId} status=${spawnData.status ?? 'unknown'}`);
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
catch {
|
|
755
|
-
/* non-fatal — loop continues */
|
|
756
|
-
}
|
|
757
|
-
finally {
|
|
758
|
-
inFlight = false;
|
|
759
|
-
}
|
|
760
|
-
}, taskInterval);
|
|
761
|
-
const shutdown = () => {
|
|
762
|
-
clearInterval(workLoop);
|
|
763
|
-
runtime.stop();
|
|
764
|
-
void registry.update(agentId, { isActive: false }).catch(() => { });
|
|
765
|
-
if (executeMode) {
|
|
766
|
-
console.log(`[${agentId}] conductor-loop shutdown after ${iterations} iterations.`);
|
|
767
|
-
}
|
|
768
|
-
process.exit(0);
|
|
769
|
-
};
|
|
770
|
-
process.on('SIGINT', shutdown);
|
|
771
|
-
process.on('SIGTERM', shutdown);
|
|
772
|
-
if (process.platform === 'win32') {
|
|
773
|
-
process.on('message', (msg) => {
|
|
774
|
-
if (msg === 'shutdown')
|
|
775
|
-
shutdown();
|
|
776
|
-
});
|
|
777
|
-
}
|
|
778
|
-
await new Promise(() => { });
|
|
779
|
-
}
|
|
780
|
-
catch (err) {
|
|
781
|
-
cliOutput({ success: false, error: { code: 'E_WORK', message: String(err) } }, { command: 'agent work' });
|
|
782
|
-
process.exitCode = 1;
|
|
783
|
-
}
|
|
784
|
-
});
|
|
785
|
-
// --- cleo agent list ---
|
|
786
|
-
/**
|
|
787
|
-
* Lists agents visible in the current project (default: INNER JOIN project-scoped),
|
|
788
|
-
* or all global agents when `--global` is supplied (full scan, no project filter).
|
|
789
|
-
*
|
|
790
|
-
* Output columns: agentId, name, classification, transportType, isActive,
|
|
791
|
-
* lastUsedAt, attachment (derived from projectRef).
|
|
792
|
-
*
|
|
793
|
-
* @task T362 @epic T310
|
|
794
|
-
*/
|
|
795
|
-
agent
|
|
796
|
-
.command('list')
|
|
797
|
-
.description('List registered agent credentials')
|
|
798
|
-
.option('--active', 'Show only active agents (project-scoped mode only)')
|
|
799
|
-
.option('--global', 'Show all global agents regardless of project attachment (ADR-037 §4 Q1=B)')
|
|
800
|
-
.option('--include-disabled', 'Include detached/disabled agents (enabled=0)')
|
|
801
|
-
.action(async (opts) => {
|
|
802
|
-
try {
|
|
803
|
-
const { listAgentsForProject, getDb } = await import('@cleocode/core/internal');
|
|
804
|
-
await getDb();
|
|
805
|
-
const includeGlobal = opts['global'] === true;
|
|
806
|
-
const includeDisabled = opts['includeDisabled'] === true;
|
|
807
|
-
const agents = listAgentsForProject(process.cwd(), {
|
|
808
|
-
includeGlobal,
|
|
809
|
-
includeDisabled,
|
|
810
|
-
});
|
|
811
|
-
// Apply legacy --active filter only when NOT in global mode
|
|
812
|
-
const filtered = !includeGlobal && opts['active'] ? agents.filter((a) => a.isActive) : agents;
|
|
813
|
-
cliOutput({
|
|
814
|
-
success: true,
|
|
815
|
-
data: filtered.map((a) => ({
|
|
816
|
-
agentId: a.agentId,
|
|
817
|
-
name: a.displayName,
|
|
818
|
-
classification: a.classification ?? null,
|
|
819
|
-
transportType: a.transportType,
|
|
820
|
-
isActive: a.isActive,
|
|
821
|
-
lastUsedAt: a.lastUsedAt ?? null,
|
|
822
|
-
attachment: a.projectRef
|
|
823
|
-
? a.projectRef.enabled === 1
|
|
824
|
-
? '[attached]'
|
|
825
|
-
: '[disabled]'
|
|
826
|
-
: '[global]',
|
|
827
|
-
})),
|
|
828
|
-
}, { command: 'agent list' });
|
|
829
|
-
}
|
|
830
|
-
catch (err) {
|
|
831
|
-
cliOutput({ success: false, error: { code: 'E_LIST', message: String(err) } }, { command: 'agent list' });
|
|
832
|
-
process.exitCode = 1;
|
|
833
|
-
}
|
|
834
|
-
});
|
|
835
|
-
// --- cleo agent get <id> ---
|
|
836
|
-
/**
|
|
837
|
-
* Returns details for a specific agent credential.
|
|
838
|
-
*
|
|
839
|
-
* Default: project-scoped lookup via `lookupAgent(includeGlobal=false)` — agent
|
|
840
|
-
* must have a project_agent_refs row with enabled=1 in the current project.
|
|
841
|
-
*
|
|
842
|
-
* With `--global`: cross-project identity lookup via `lookupAgent(includeGlobal=true)`.
|
|
843
|
-
* Returns the global identity even if the agent is not attached to this project;
|
|
844
|
-
* projectRef block will be null when not attached.
|
|
845
|
-
*
|
|
846
|
-
* @task T362 @epic T310
|
|
847
|
-
*/
|
|
848
|
-
agent
|
|
849
|
-
.command('get <agentId>')
|
|
850
|
-
.description('Get details for a specific agent credential')
|
|
851
|
-
.option('--global', 'Perform global identity lookup — returns agent even if not attached to current project')
|
|
852
|
-
.action(async (agentId, opts) => {
|
|
853
|
-
try {
|
|
854
|
-
const { lookupAgent, getDb } = await import('@cleocode/core/internal');
|
|
855
|
-
await getDb();
|
|
856
|
-
const includeGlobal = opts['global'] === true;
|
|
857
|
-
const agent = lookupAgent(process.cwd(), agentId, { includeGlobal });
|
|
858
|
-
if (!agent) {
|
|
859
|
-
cliOutput({
|
|
860
|
-
success: false,
|
|
861
|
-
error: { code: 'E_NOT_FOUND', message: `Agent not found: ${agentId}` },
|
|
862
|
-
}, { command: 'agent get' });
|
|
863
|
-
process.exitCode = 4;
|
|
864
|
-
return;
|
|
865
|
-
}
|
|
866
|
-
// Redact API key in output
|
|
867
|
-
const redactedKey = agent.apiKey.length > 16
|
|
868
|
-
? `${agent.apiKey.substring(0, 12)}...${agent.apiKey.substring(agent.apiKey.length - 4)}`
|
|
869
|
-
: '***redacted***';
|
|
870
|
-
cliOutput({
|
|
871
|
-
success: true,
|
|
872
|
-
data: {
|
|
873
|
-
agentId: agent.agentId,
|
|
874
|
-
displayName: agent.displayName,
|
|
875
|
-
apiKey: redactedKey,
|
|
876
|
-
apiBaseUrl: agent.apiBaseUrl,
|
|
877
|
-
classification: agent.classification ?? null,
|
|
878
|
-
transportType: agent.transportType,
|
|
879
|
-
isActive: agent.isActive,
|
|
880
|
-
lastUsedAt: agent.lastUsedAt ?? null,
|
|
881
|
-
createdAt: agent.createdAt,
|
|
882
|
-
updatedAt: agent.updatedAt,
|
|
883
|
-
projectRef: agent.projectRef ?? 'not attached to current project',
|
|
884
|
-
},
|
|
885
|
-
}, { command: 'agent get' });
|
|
886
|
-
}
|
|
887
|
-
catch (err) {
|
|
888
|
-
cliOutput({ success: false, error: { code: 'E_GET', message: String(err) } }, { command: 'agent get' });
|
|
889
|
-
process.exitCode = 1;
|
|
890
|
-
}
|
|
891
|
-
});
|
|
892
|
-
// --- cleo agent attach <id> ---
|
|
893
|
-
/**
|
|
894
|
-
* @task T364
|
|
895
|
-
* @epic T310
|
|
896
|
-
* @why ADR-037 §3 — project_agent_refs override table allows per-project
|
|
897
|
-
* agents to be attached/detached without touching global identity.
|
|
898
|
-
*/
|
|
899
|
-
agent
|
|
900
|
-
.command('attach <agentId>')
|
|
901
|
-
.description('Attach a global agent to the current project')
|
|
902
|
-
.option('--role <role>', 'Per-project role override')
|
|
903
|
-
.option('--capabilities-override <json>', 'JSON blob of capability overrides')
|
|
904
|
-
.action(async (agentId, opts) => {
|
|
905
|
-
try {
|
|
906
|
-
const { AgentRegistryAccessor, attachAgentToProject, lookupAgent, getDb } = await import('@cleocode/core/internal');
|
|
907
|
-
await getDb();
|
|
908
|
-
const projectRoot = process.cwd();
|
|
909
|
-
// Ensure both DBs initialised before any cross-DB operation
|
|
910
|
-
const _registry = new AgentRegistryAccessor(projectRoot);
|
|
911
|
-
void _registry;
|
|
912
|
-
// Verify agent exists globally
|
|
913
|
-
const global = lookupAgent(projectRoot, agentId, { includeGlobal: true });
|
|
914
|
-
if (!global) {
|
|
915
|
-
cliOutput({
|
|
916
|
-
success: false,
|
|
917
|
-
error: { code: 'E_NOT_FOUND', message: `Agent not found: ${agentId}` },
|
|
918
|
-
}, { command: 'agent attach' });
|
|
919
|
-
process.exitCode = 4;
|
|
920
|
-
return;
|
|
921
|
-
}
|
|
922
|
-
attachAgentToProject(projectRoot, agentId, {
|
|
923
|
-
role: typeof opts['role'] === 'string' ? opts['role'] : null,
|
|
924
|
-
capabilitiesOverride: typeof opts['capabilitiesOverride'] === 'string' ? opts['capabilitiesOverride'] : null,
|
|
925
|
-
});
|
|
926
|
-
cliOutput({
|
|
927
|
-
success: true,
|
|
928
|
-
data: {
|
|
929
|
-
attached: agentId,
|
|
930
|
-
projectRoot,
|
|
931
|
-
role: typeof opts['role'] === 'string' ? opts['role'] : null,
|
|
932
|
-
},
|
|
933
|
-
}, { command: 'agent attach' });
|
|
934
|
-
}
|
|
935
|
-
catch (err) {
|
|
936
|
-
cliOutput({ success: false, error: { code: 'E_ATTACH', message: String(err) } }, { command: 'agent attach' });
|
|
937
|
-
process.exitCode = 1;
|
|
938
|
-
}
|
|
939
|
-
});
|
|
940
|
-
// --- cleo agent detach <id> ---
|
|
941
|
-
/**
|
|
942
|
-
* @task T364
|
|
943
|
-
* @epic T310
|
|
944
|
-
* @why ADR-037 §3 — soft-delete via project_agent_refs.enabled=0 preserves
|
|
945
|
-
* global agent identity while removing it from the project view.
|
|
946
|
-
*/
|
|
947
|
-
agent
|
|
948
|
-
.command('detach <agentId>')
|
|
949
|
-
.description('Detach an agent from the current project (preserves global identity)')
|
|
950
|
-
.action(async (agentId) => {
|
|
951
|
-
try {
|
|
952
|
-
const { AgentRegistryAccessor, detachAgentFromProject, getProjectAgentRef, getDb } = await import('@cleocode/core/internal');
|
|
953
|
-
await getDb();
|
|
954
|
-
const projectRoot = process.cwd();
|
|
955
|
-
// Ensure both DBs initialised
|
|
956
|
-
const _registry = new AgentRegistryAccessor(projectRoot);
|
|
957
|
-
void _registry;
|
|
958
|
-
const ref = getProjectAgentRef(projectRoot, agentId);
|
|
959
|
-
if (!ref) {
|
|
960
|
-
cliOutput({
|
|
961
|
-
success: false,
|
|
962
|
-
error: {
|
|
963
|
-
code: 'E_NOT_FOUND',
|
|
964
|
-
message: `Agent ${agentId} not attached to current project`,
|
|
965
|
-
},
|
|
966
|
-
}, { command: 'agent detach' });
|
|
967
|
-
process.exitCode = 4;
|
|
968
|
-
return;
|
|
969
|
-
}
|
|
970
|
-
detachAgentFromProject(projectRoot, agentId);
|
|
971
|
-
cliOutput({ success: true, data: { detached: agentId, projectRoot } }, { command: 'agent detach' });
|
|
972
|
-
}
|
|
973
|
-
catch (err) {
|
|
974
|
-
cliOutput({ success: false, error: { code: 'E_DETACH', message: String(err) } }, { command: 'agent detach' });
|
|
975
|
-
process.exitCode = 1;
|
|
976
|
-
}
|
|
977
|
-
});
|
|
978
|
-
// --- cleo agent remove <id> ---
|
|
979
|
-
/**
|
|
980
|
-
* Detach agent from current project (default) or remove from global registry
|
|
981
|
-
* with the --global flag.
|
|
982
|
-
*
|
|
983
|
-
* Default (no --global): sets enabled=0 in conduit.db:project_agent_refs only.
|
|
984
|
-
* This is identical to `cleo agent detach` and is the post-T310 default.
|
|
985
|
-
*
|
|
986
|
-
* --global: calls AgentRegistryAccessor.removeGlobal() (destructive). Pre-check
|
|
987
|
-
* scans the current project's conduit.db for an active reference. If one exists
|
|
988
|
-
* and --force-global is not supplied, aborts with E_VALIDATION (exit 6). The
|
|
989
|
-
* scan is limited to the current project — see ADR-037 §6 known limitations.
|
|
990
|
-
*
|
|
991
|
-
* @task T366
|
|
992
|
-
* @epic T310
|
|
993
|
-
* @why ADR-037 §6 — never-auto-delete semantics; --global flag required for
|
|
994
|
-
* destructive removal; best-effort cross-project scan with documented
|
|
995
|
-
* limitation (current project only for v1).
|
|
996
|
-
*/
|
|
997
|
-
agent
|
|
998
|
-
.command('remove <agentId>')
|
|
999
|
-
.description('Detach agent from current project (default) or remove global identity with --global')
|
|
1000
|
-
.option('--global', 'Remove from global signaldock.db (destructive, irreversible)')
|
|
1001
|
-
.option('--force-global', 'Force global removal even when the current project still has an active reference')
|
|
1002
|
-
.action(async (agentId, opts) => {
|
|
1003
|
-
try {
|
|
1004
|
-
const { AgentRegistryAccessor, detachAgentFromProject, getProjectAgentRef, getDb } = await import('@cleocode/core/internal');
|
|
1005
|
-
await getDb();
|
|
1006
|
-
const projectRoot = process.cwd();
|
|
1007
|
-
if (!opts['global']) {
|
|
1008
|
-
// Project-scoped detach (default post-T310) — mirrors `cleo agent detach`
|
|
1009
|
-
// Ensure both DBs initialised
|
|
1010
|
-
const _registry = new AgentRegistryAccessor(projectRoot);
|
|
1011
|
-
void _registry;
|
|
1012
|
-
const ref = getProjectAgentRef(projectRoot, agentId);
|
|
1013
|
-
if (!ref) {
|
|
1014
|
-
cliOutput({
|
|
1015
|
-
success: false,
|
|
1016
|
-
error: {
|
|
1017
|
-
code: 'E_NOT_FOUND',
|
|
1018
|
-
message: `Agent ${agentId} not attached to current project`,
|
|
1019
|
-
},
|
|
1020
|
-
}, { command: 'agent remove' });
|
|
1021
|
-
process.exitCode = 4;
|
|
1022
|
-
return;
|
|
1023
|
-
}
|
|
1024
|
-
detachAgentFromProject(projectRoot, agentId);
|
|
1025
|
-
cliOutput({ success: true, data: { removed: agentId, scope: 'project', projectRoot } }, { command: 'agent remove' });
|
|
1026
|
-
return;
|
|
1027
|
-
}
|
|
1028
|
-
// --global: destructive removal from signaldock.db
|
|
1029
|
-
// Safety scan — limited to current project (ADR-037 §6 known limitation).
|
|
1030
|
-
const _registry2 = new AgentRegistryAccessor(projectRoot);
|
|
1031
|
-
void _registry2;
|
|
1032
|
-
const activeRef = getProjectAgentRef(projectRoot, agentId);
|
|
1033
|
-
if (activeRef && !opts['forceGlobal']) {
|
|
1034
|
-
console.warn(`NOTE: Safety scan is limited to the current project. Other projects may have ` +
|
|
1035
|
-
`dangling references after global removal.`);
|
|
1036
|
-
cliOutput({
|
|
1037
|
-
success: false,
|
|
1038
|
-
error: {
|
|
1039
|
-
code: 'E_VALIDATION',
|
|
1040
|
-
message: `Agent "${agentId}" is still attached to current project. ` +
|
|
1041
|
-
`Detach first or pass --force-global to proceed anyway.`,
|
|
1042
|
-
fix: `cleo agent detach ${agentId} # detach first, then retry` +
|
|
1043
|
-
` OR cleo agent remove ${agentId} --global --force-global`,
|
|
1044
|
-
},
|
|
1045
|
-
}, { command: 'agent remove' });
|
|
1046
|
-
process.exitCode = 6;
|
|
1047
|
-
return;
|
|
1048
|
-
}
|
|
1049
|
-
console.warn(`NOTE: Safety scan is limited to the current project. Other projects may have ` +
|
|
1050
|
-
`dangling references after global removal.`);
|
|
1051
|
-
const registry = new AgentRegistryAccessor(projectRoot);
|
|
1052
|
-
await registry.removeGlobal(agentId, { force: opts['forceGlobal'] === true });
|
|
1053
|
-
cliOutput({ success: true, data: { removed: agentId, scope: 'global' } }, { command: 'agent remove' });
|
|
1054
|
-
}
|
|
1055
|
-
catch (err) {
|
|
1056
|
-
cliOutput({ success: false, error: { code: 'E_REMOVE', message: String(err) } }, { command: 'agent remove' });
|
|
1057
|
-
process.exitCode = 1;
|
|
1058
|
-
}
|
|
1059
|
-
});
|
|
1060
|
-
// --- cleo agent rotate-key <id> ---
|
|
1061
|
-
agent
|
|
1062
|
-
.command('rotate-key <agentId>')
|
|
1063
|
-
.description('Rotate an agent API key (generates new key on cloud, re-encrypts locally)')
|
|
1064
|
-
.action(async (agentId) => {
|
|
1065
|
-
try {
|
|
1066
|
-
const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
|
|
1067
|
-
await getDb();
|
|
1068
|
-
const registry = new AgentRegistryAccessor(process.cwd());
|
|
1069
|
-
const result = await registry.rotateKey(agentId);
|
|
1070
|
-
cliOutput({
|
|
1071
|
-
success: true,
|
|
1072
|
-
data: {
|
|
1073
|
-
agentId: result.agentId,
|
|
1074
|
-
newApiKey: `${result.newApiKey.substring(0, 12)}...`,
|
|
1075
|
-
message: 'API key rotated. Old key is invalidated.',
|
|
1076
|
-
},
|
|
1077
|
-
}, { command: 'agent rotate-key' });
|
|
1078
|
-
}
|
|
1079
|
-
catch (err) {
|
|
1080
|
-
cliOutput({ success: false, error: { code: 'E_ROTATE', message: String(err) } }, { command: 'agent rotate-key' });
|
|
1081
|
-
process.exitCode = 1;
|
|
1082
|
-
}
|
|
1083
|
-
});
|
|
1084
|
-
// --- cleo agent claim-code <id> ---
|
|
1085
|
-
agent
|
|
1086
|
-
.command('claim-code <agentId>')
|
|
1087
|
-
.description('Generate a claim code for human ownership of an agent')
|
|
1088
|
-
.action(async (agentId) => {
|
|
1089
|
-
try {
|
|
1090
|
-
const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
|
|
1091
|
-
await getDb();
|
|
1092
|
-
const registry = new AgentRegistryAccessor(process.cwd());
|
|
1093
|
-
const credential = await registry.get(agentId);
|
|
1094
|
-
if (!credential) {
|
|
1095
|
-
cliOutput({
|
|
1096
|
-
success: false,
|
|
1097
|
-
error: { code: 'E_NOT_FOUND', message: `Agent not found: ${agentId}` },
|
|
1098
|
-
}, { command: 'agent claim-code' });
|
|
1099
|
-
process.exitCode = 4;
|
|
1100
|
-
return;
|
|
1101
|
-
}
|
|
1102
|
-
const response = await fetch(`${credential.apiBaseUrl}/agents/${agentId}/claim-code`, {
|
|
1103
|
-
method: 'POST',
|
|
1104
|
-
headers: {
|
|
1105
|
-
'Content-Type': 'application/json',
|
|
1106
|
-
Authorization: `Bearer ${credential.apiKey}`,
|
|
1107
|
-
'X-Agent-Id': agentId,
|
|
1108
|
-
},
|
|
1109
|
-
});
|
|
1110
|
-
if (!response.ok) {
|
|
1111
|
-
const text = await response.text().catch(() => '');
|
|
1112
|
-
throw new Error(`Failed to generate claim code: ${response.status} ${text}`);
|
|
1113
|
-
}
|
|
1114
|
-
const data = (await response.json());
|
|
1115
|
-
cliOutput({
|
|
1116
|
-
success: true,
|
|
1117
|
-
data: {
|
|
1118
|
-
agentId,
|
|
1119
|
-
claimCode: data.data?.claimCode,
|
|
1120
|
-
claimUrl: data.data?.claimUrl ?? `https://signaldock.io/claim/${data.data?.claimCode}`,
|
|
1121
|
-
expiresAt: data.data?.expiresAt,
|
|
1122
|
-
message: 'Share this claim code with the human owner to verify agent ownership.',
|
|
1123
|
-
},
|
|
1124
|
-
}, { command: 'agent claim-code' });
|
|
1125
|
-
}
|
|
1126
|
-
catch (err) {
|
|
1127
|
-
cliOutput({ success: false, error: { code: 'E_CLAIM', message: String(err) } }, { command: 'agent claim-code' });
|
|
1128
|
-
process.exitCode = 1;
|
|
1129
|
-
}
|
|
1130
|
-
});
|
|
1131
|
-
// --- cleo agent watch ---
|
|
1132
|
-
agent
|
|
1133
|
-
.command('watch')
|
|
1134
|
-
.description('Start continuous message polling for the active agent (long-running)')
|
|
1135
|
-
.option('--agent <id>', 'Agent ID to watch as (defaults to most recently used)')
|
|
1136
|
-
.option('--interval <ms>', 'Poll interval in milliseconds', '5000')
|
|
1137
|
-
.option('--group <ids>', 'Comma-separated group conversation IDs to monitor')
|
|
1138
|
-
.action(async (opts) => {
|
|
1139
|
-
try {
|
|
1140
|
-
const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
|
|
1141
|
-
const { createRuntime } = await import('@cleocode/runtime');
|
|
1142
|
-
await getDb();
|
|
1143
|
-
const registry = new AgentRegistryAccessor(process.cwd());
|
|
1144
|
-
const groupIds = opts['group']
|
|
1145
|
-
? opts['group'].split(',').map((s) => s.trim())
|
|
1146
|
-
: undefined;
|
|
1147
|
-
const handle = await createRuntime(registry, {
|
|
1148
|
-
agentId: opts['agent'],
|
|
1149
|
-
pollIntervalMs: Number(opts['interval']) || 5000,
|
|
1150
|
-
groupConversationIds: groupIds,
|
|
1151
|
-
});
|
|
1152
|
-
handle.poller.onMessage((msg) => {
|
|
1153
|
-
cliOutput({
|
|
1154
|
-
success: true,
|
|
1155
|
-
data: {
|
|
1156
|
-
event: 'message',
|
|
1157
|
-
id: msg.id,
|
|
1158
|
-
from: msg.from,
|
|
1159
|
-
content: msg.content,
|
|
1160
|
-
threadId: msg.threadId,
|
|
1161
|
-
timestamp: msg.timestamp,
|
|
1162
|
-
},
|
|
1163
|
-
}, { command: 'agent watch' });
|
|
1164
|
-
});
|
|
1165
|
-
handle.poller.start();
|
|
1166
|
-
cliOutput({
|
|
1167
|
-
success: true,
|
|
1168
|
-
data: {
|
|
1169
|
-
event: 'started',
|
|
1170
|
-
agentId: handle.agentId,
|
|
1171
|
-
pollIntervalMs: Number(opts['interval']) || 5000,
|
|
1172
|
-
groupConversationIds: groupIds ?? [],
|
|
1173
|
-
message: 'Watching for messages. Press Ctrl+C to stop.',
|
|
1174
|
-
},
|
|
1175
|
-
}, { command: 'agent watch' });
|
|
1176
|
-
// Keep alive until SIGINT/SIGTERM
|
|
1177
|
-
const shutdown = () => {
|
|
1178
|
-
handle.stop();
|
|
1179
|
-
cliOutput({ success: true, data: { event: 'stopped', agentId: handle.agentId } }, { command: 'agent watch' });
|
|
1180
|
-
process.exit(0);
|
|
1181
|
-
};
|
|
1182
|
-
process.on('SIGINT', shutdown);
|
|
1183
|
-
process.on('SIGTERM', shutdown);
|
|
1184
|
-
if (process.platform === 'win32') {
|
|
1185
|
-
process.on('message', (msg) => {
|
|
1186
|
-
if (msg === 'shutdown')
|
|
1187
|
-
shutdown();
|
|
1188
|
-
});
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1191
|
-
catch (err) {
|
|
1192
|
-
cliOutput({ success: false, error: { code: 'E_WATCH', message: String(err) } }, { command: 'agent watch' });
|
|
1193
|
-
process.exitCode = 1;
|
|
1194
|
-
}
|
|
1195
|
-
});
|
|
1196
|
-
// --- cleo agent poll ---
|
|
1197
|
-
agent
|
|
1198
|
-
.command('poll')
|
|
1199
|
-
.description('One-shot message check for the active agent')
|
|
1200
|
-
.option('--agent <id>', 'Agent ID to poll as (defaults to most recently used)')
|
|
1201
|
-
.option('--limit <n>', 'Max messages to fetch', '20')
|
|
1202
|
-
.action(async (opts) => {
|
|
1203
|
-
try {
|
|
1204
|
-
const { AgentRegistryAccessor, createConduit, getDb } = await import('@cleocode/core/internal');
|
|
1205
|
-
await getDb();
|
|
1206
|
-
const registry = new AgentRegistryAccessor(process.cwd());
|
|
1207
|
-
const agentId = opts['agent'];
|
|
1208
|
-
const conduit = await createConduit(registry, agentId);
|
|
1209
|
-
const limit = Number(opts['limit']) || 20;
|
|
1210
|
-
const messages = await conduit.poll({ limit });
|
|
1211
|
-
cliOutput({
|
|
1212
|
-
success: true,
|
|
1213
|
-
data: { agentId: conduit.agentId, messages, count: messages.length, limit },
|
|
1214
|
-
}, { command: 'agent poll' });
|
|
1215
|
-
await conduit.disconnect();
|
|
1216
|
-
}
|
|
1217
|
-
catch (err) {
|
|
1218
|
-
cliOutput({ success: false, error: { code: 'E_POLL', message: String(err) } }, { command: 'agent poll' });
|
|
1219
|
-
process.exitCode = 1;
|
|
1220
|
-
}
|
|
1221
|
-
});
|
|
1222
|
-
// --- cleo agent send ---
|
|
1223
|
-
agent
|
|
1224
|
-
.command('send <message>')
|
|
1225
|
-
.description('Send a message to an agent or conversation')
|
|
1226
|
-
.option('--to <agentId>', 'Target agent ID')
|
|
1227
|
-
.option('--conv <conversationId>', 'Target conversation ID')
|
|
1228
|
-
.option('--agent <id>', 'Send as this agent (defaults to most recently used)')
|
|
1229
|
-
.action(async (message, opts) => {
|
|
1230
|
-
try {
|
|
1231
|
-
const { AgentRegistryAccessor, createConduit, getDb } = await import('@cleocode/core/internal');
|
|
1232
|
-
await getDb();
|
|
1233
|
-
const registry = new AgentRegistryAccessor(process.cwd());
|
|
1234
|
-
const agentId = opts['agent'];
|
|
1235
|
-
const to = opts['to'];
|
|
1236
|
-
const conv = opts['conv'];
|
|
1237
|
-
if (!to && !conv) {
|
|
1238
|
-
cliOutput({ success: false, error: { code: 'E_ARGS', message: 'Must specify --to or --conv' } }, { command: 'agent send' });
|
|
1239
|
-
process.exitCode = 1;
|
|
1240
|
-
return;
|
|
1241
|
-
}
|
|
1242
|
-
const conduit = await createConduit(registry, agentId);
|
|
1243
|
-
const result = await conduit.send(to ?? conv ?? '', message, {
|
|
1244
|
-
threadId: conv,
|
|
1245
|
-
});
|
|
1246
|
-
cliOutput({ success: true, data: { messageId: result.messageId, deliveredAt: result.deliveredAt } }, { command: 'agent send' });
|
|
1247
|
-
await conduit.disconnect();
|
|
1248
|
-
}
|
|
1249
|
-
catch (err) {
|
|
1250
|
-
cliOutput({ success: false, error: { code: 'E_SEND', message: String(err) } }, { command: 'agent send' });
|
|
1251
|
-
process.exitCode = 1;
|
|
1252
|
-
}
|
|
1253
|
-
});
|
|
1254
|
-
// --- cleo agent health ---
|
|
1255
|
-
agent
|
|
1256
|
-
.command('health')
|
|
1257
|
-
.description('Check agent health and detect stale or crashed agents')
|
|
1258
|
-
.option('--id <agentId>', 'Check health for a specific agent ID')
|
|
1259
|
-
.option('--threshold <ms>', 'Staleness threshold in milliseconds (default: 180000 = 3 minutes)', String(STALE_THRESHOLD_MS))
|
|
1260
|
-
.option('--detect-crashed', 'Detect and mark crashed agents (write operation)')
|
|
1261
|
-
.action(async (opts) => {
|
|
1262
|
-
const thresholdMs = typeof opts['threshold'] === 'string' ? Number(opts['threshold']) : STALE_THRESHOLD_MS;
|
|
1263
|
-
const agentId = opts['id'];
|
|
1264
|
-
const detectCrashed = Boolean(opts['detectCrashed']);
|
|
1265
|
-
if (agentId) {
|
|
1266
|
-
const health = await checkAgentHealth(agentId, thresholdMs);
|
|
1267
|
-
if (!health) {
|
|
1268
|
-
cliOutput({
|
|
1269
|
-
success: false,
|
|
1270
|
-
error: { code: 'E_NOT_FOUND', message: `Agent not found: ${agentId}` },
|
|
1271
|
-
}, { command: 'agent health' });
|
|
1272
|
-
process.exitCode = 4;
|
|
1273
|
-
return;
|
|
1274
|
-
}
|
|
1275
|
-
cliOutput({ success: true, data: health }, { command: 'agent health' });
|
|
1276
|
-
return;
|
|
1277
|
-
}
|
|
1278
|
-
if (detectCrashed) {
|
|
1279
|
-
const crashed = await detectCrashedAgents(thresholdMs);
|
|
1280
|
-
cliOutput({
|
|
1281
|
-
success: true,
|
|
1282
|
-
data: {
|
|
1283
|
-
detectedCrashed: crashed.length,
|
|
1284
|
-
agents: crashed.map((a) => ({
|
|
1285
|
-
id: a.id,
|
|
1286
|
-
agentType: a.agentType,
|
|
1287
|
-
lastHeartbeat: a.lastHeartbeat,
|
|
1288
|
-
status: a.status,
|
|
1289
|
-
})),
|
|
1290
|
-
},
|
|
1291
|
-
}, { command: 'agent health' });
|
|
1292
|
-
return;
|
|
1293
|
-
}
|
|
1294
|
-
const [report, stale] = await Promise.all([
|
|
1295
|
-
getHealthReport(thresholdMs),
|
|
1296
|
-
detectStaleAgents(thresholdMs),
|
|
1297
|
-
]);
|
|
1298
|
-
cliOutput({
|
|
1299
|
-
success: true,
|
|
1300
|
-
data: {
|
|
1301
|
-
summary: {
|
|
1302
|
-
total: report.total,
|
|
1303
|
-
active: report.active,
|
|
1304
|
-
idle: report.idle,
|
|
1305
|
-
starting: report.starting,
|
|
1306
|
-
error: report.error,
|
|
1307
|
-
crashed: report.crashed,
|
|
1308
|
-
stopped: report.stopped,
|
|
1309
|
-
totalErrors: report.totalErrors,
|
|
1310
|
-
},
|
|
1311
|
-
staleAgents: stale.map((s) => ({
|
|
1312
|
-
id: s.agentId,
|
|
1313
|
-
status: s.status,
|
|
1314
|
-
heartbeatAgeMs: s.heartbeatAgeMs,
|
|
1315
|
-
lastHeartbeat: s.lastHeartbeat,
|
|
1316
|
-
thresholdMs: s.thresholdMs,
|
|
1317
|
-
})),
|
|
1318
|
-
thresholdMs,
|
|
1319
|
-
},
|
|
1320
|
-
}, { command: 'agent health' });
|
|
1321
|
-
});
|
|
1322
|
-
// --- cleo agent install <path> ---
|
|
1323
|
-
/**
|
|
1324
|
-
* Install an agent from a `.cantz` archive or a directory containing `persona.cant`.
|
|
1325
|
-
*
|
|
1326
|
-
* - If the path is a `.cantz` file, extracts the ZIP to a temp directory first.
|
|
1327
|
-
* - Validates that `persona.cant` exists in the source.
|
|
1328
|
-
* - Copies the agent directory to the target tier.
|
|
1329
|
-
* - Default: project tier (`.cleo/cant/agents/<name>/`).
|
|
1330
|
-
* - `--global`: global tier (`~/.local/share/cleo/cant/agents/`).
|
|
1331
|
-
* - Best-effort agent registration in signaldock.db.
|
|
1332
|
-
*
|
|
1333
|
-
* @task T438
|
|
1334
|
-
* @epic T250
|
|
1335
|
-
* @see docs/specs/CANTZ-PACKAGE-STANDARD.md
|
|
1336
|
-
*/
|
|
1337
|
-
agent
|
|
1338
|
-
.command('install <path>')
|
|
1339
|
-
.description('Install an agent from a .cantz archive or agent directory')
|
|
1340
|
-
.option('--global', 'Install to global tier (~/.local/share/cleo/cant/agents/)')
|
|
1341
|
-
.action(async (sourcePath, opts) => {
|
|
1342
|
-
try {
|
|
1343
|
-
const { existsSync, mkdirSync, cpSync, readFileSync, rmSync, statSync } = await import('node:fs');
|
|
1344
|
-
const { join, basename, resolve } = await import('node:path');
|
|
1345
|
-
const { homedir } = await import('node:os');
|
|
1346
|
-
const { tmpdir } = await import('node:os');
|
|
1347
|
-
const resolvedPath = resolve(sourcePath);
|
|
1348
|
-
if (!existsSync(resolvedPath)) {
|
|
1349
|
-
cliOutput({
|
|
1350
|
-
success: false,
|
|
1351
|
-
error: {
|
|
1352
|
-
code: 'E_NOT_FOUND',
|
|
1353
|
-
message: `Path does not exist: ${resolvedPath}`,
|
|
1354
|
-
},
|
|
1355
|
-
}, { command: 'agent install' });
|
|
1356
|
-
process.exitCode = 4;
|
|
1357
|
-
return;
|
|
1358
|
-
}
|
|
1359
|
-
let agentDir;
|
|
1360
|
-
let agentName;
|
|
1361
|
-
let tempDir = null;
|
|
1362
|
-
const isCantzArchive = resolvedPath.endsWith('.cantz') && statSync(resolvedPath).isFile();
|
|
1363
|
-
if (isCantzArchive) {
|
|
1364
|
-
// Extract ZIP to temp directory
|
|
1365
|
-
const { execFileSync } = await import('node:child_process');
|
|
1366
|
-
tempDir = join(tmpdir(), `cleo-agent-install-${Date.now()}`);
|
|
1367
|
-
mkdirSync(tempDir, { recursive: true });
|
|
1368
|
-
try {
|
|
1369
|
-
execFileSync('unzip', ['-o', '-q', resolvedPath, '-d', tempDir], {
|
|
1370
|
-
encoding: 'utf-8',
|
|
1371
|
-
timeout: 30000,
|
|
1372
|
-
});
|
|
1373
|
-
}
|
|
1374
|
-
catch (unzipErr) {
|
|
1375
|
-
if (tempDir)
|
|
1376
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
1377
|
-
cliOutput({
|
|
1378
|
-
success: false,
|
|
1379
|
-
error: {
|
|
1380
|
-
code: 'E_VALIDATION',
|
|
1381
|
-
message: `Failed to extract .cantz archive: ${String(unzipErr)}`,
|
|
1382
|
-
},
|
|
1383
|
-
}, { command: 'agent install' });
|
|
1384
|
-
process.exitCode = 6;
|
|
1385
|
-
return;
|
|
1386
|
-
}
|
|
1387
|
-
// Find the top-level directory inside the extracted archive
|
|
1388
|
-
const { readdirSync } = await import('node:fs');
|
|
1389
|
-
const topLevel = readdirSync(tempDir).filter((entry) => {
|
|
1390
|
-
const entryPath = join(tempDir, entry);
|
|
1391
|
-
return statSync(entryPath).isDirectory();
|
|
1392
|
-
});
|
|
1393
|
-
if (topLevel.length !== 1) {
|
|
1394
|
-
if (tempDir)
|
|
1395
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
1396
|
-
cliOutput({
|
|
1397
|
-
success: false,
|
|
1398
|
-
error: {
|
|
1399
|
-
code: 'E_VALIDATION',
|
|
1400
|
-
message: `Archive must contain exactly one top-level directory, found ${topLevel.length}`,
|
|
1401
|
-
},
|
|
1402
|
-
}, { command: 'agent install' });
|
|
1403
|
-
process.exitCode = 6;
|
|
1404
|
-
return;
|
|
1405
|
-
}
|
|
1406
|
-
agentName = topLevel[0];
|
|
1407
|
-
agentDir = join(tempDir, agentName);
|
|
1408
|
-
}
|
|
1409
|
-
else if (statSync(resolvedPath).isDirectory()) {
|
|
1410
|
-
agentDir = resolvedPath;
|
|
1411
|
-
agentName = basename(resolvedPath);
|
|
1412
|
-
}
|
|
1413
|
-
else {
|
|
1414
|
-
cliOutput({
|
|
1415
|
-
success: false,
|
|
1416
|
-
error: {
|
|
1417
|
-
code: 'E_VALIDATION',
|
|
1418
|
-
message: `Path must be a .cantz file or a directory: ${resolvedPath}`,
|
|
1419
|
-
},
|
|
1420
|
-
}, { command: 'agent install' });
|
|
1421
|
-
process.exitCode = 6;
|
|
1422
|
-
return;
|
|
1423
|
-
}
|
|
1424
|
-
// Validate persona.cant exists
|
|
1425
|
-
const personaPath = join(agentDir, 'persona.cant');
|
|
1426
|
-
if (!existsSync(personaPath)) {
|
|
1427
|
-
if (tempDir)
|
|
1428
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
1429
|
-
cliOutput({
|
|
1430
|
-
success: false,
|
|
1431
|
-
error: {
|
|
1432
|
-
code: 'E_VALIDATION',
|
|
1433
|
-
message: `Agent directory must contain persona.cant: ${personaPath}`,
|
|
1434
|
-
},
|
|
1435
|
-
}, { command: 'agent install' });
|
|
1436
|
-
process.exitCode = 6;
|
|
1437
|
-
return;
|
|
1438
|
-
}
|
|
1439
|
-
// Determine target tier directory
|
|
1440
|
-
const isGlobal = opts['global'] === true;
|
|
1441
|
-
let targetRoot;
|
|
1442
|
-
if (isGlobal) {
|
|
1443
|
-
const home = homedir();
|
|
1444
|
-
const xdgData = process.env['XDG_DATA_HOME'] ?? join(home, '.local', 'share');
|
|
1445
|
-
targetRoot = join(xdgData, 'cleo', 'cant', 'agents');
|
|
1446
|
-
}
|
|
1447
|
-
else {
|
|
1448
|
-
targetRoot = join(process.cwd(), '.cleo', 'cant', 'agents');
|
|
1449
|
-
}
|
|
1450
|
-
const targetDir = join(targetRoot, agentName);
|
|
1451
|
-
// Copy agent directory to target
|
|
1452
|
-
mkdirSync(targetRoot, { recursive: true });
|
|
1453
|
-
cpSync(agentDir, targetDir, { recursive: true, force: true });
|
|
1454
|
-
// Cleanup temp directory if we extracted from .cantz
|
|
1455
|
-
if (tempDir) {
|
|
1456
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
1457
|
-
}
|
|
1458
|
-
// Best-effort agent registration in signaldock.db
|
|
1459
|
-
let registered = false;
|
|
1460
|
-
try {
|
|
1461
|
-
const persona = readFileSync(join(targetDir, 'persona.cant'), 'utf-8');
|
|
1462
|
-
// Extract display name from persona.cant (best-effort parse)
|
|
1463
|
-
const descMatch = persona.match(/description:\s*"([^"]+)"/);
|
|
1464
|
-
const displayName = descMatch?.[1] ?? agentName;
|
|
1465
|
-
const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
|
|
1466
|
-
await getDb();
|
|
1467
|
-
const registry = new AgentRegistryAccessor(process.cwd());
|
|
1468
|
-
const existing = await registry.get(agentName);
|
|
1469
|
-
if (!existing) {
|
|
1470
|
-
await registry.register({
|
|
1471
|
-
agentId: agentName,
|
|
1472
|
-
displayName,
|
|
1473
|
-
apiKey: 'local-installed',
|
|
1474
|
-
apiBaseUrl: 'local',
|
|
1475
|
-
classification: 'specialist',
|
|
1476
|
-
privacyTier: 'private',
|
|
1477
|
-
capabilities: [],
|
|
1478
|
-
skills: [],
|
|
1479
|
-
transportType: 'http',
|
|
1480
|
-
transportConfig: {},
|
|
1481
|
-
isActive: false,
|
|
1482
|
-
});
|
|
1483
|
-
registered = true;
|
|
1484
|
-
}
|
|
1485
|
-
}
|
|
1486
|
-
catch {
|
|
1487
|
-
// Registration is best-effort — do not fail the install
|
|
1488
|
-
}
|
|
1489
|
-
cliOutput({
|
|
1490
|
-
success: true,
|
|
1491
|
-
data: {
|
|
1492
|
-
agent: agentName,
|
|
1493
|
-
tier: isGlobal ? 'global' : 'project',
|
|
1494
|
-
path: targetDir,
|
|
1495
|
-
registered,
|
|
1496
|
-
},
|
|
1497
|
-
}, { command: 'agent install' });
|
|
1498
|
-
}
|
|
1499
|
-
catch (err) {
|
|
1500
|
-
cliOutput({ success: false, error: { code: 'E_INSTALL', message: String(err) } }, { command: 'agent install' });
|
|
1501
|
-
process.exitCode = 1;
|
|
1502
|
-
}
|
|
1503
|
-
});
|
|
1504
|
-
// --- cleo agent pack <dir> ---
|
|
1505
|
-
/**
|
|
1506
|
-
* Package an agent directory into a `.cantz` ZIP archive.
|
|
1507
|
-
*
|
|
1508
|
-
* Validates that the source directory contains `persona.cant`, then
|
|
1509
|
-
* creates a ZIP archive named `<dirname>.cantz` in the current working
|
|
1510
|
-
* directory.
|
|
1511
|
-
*
|
|
1512
|
-
* @task T438
|
|
1513
|
-
* @epic T250
|
|
1514
|
-
* @see docs/specs/CANTZ-PACKAGE-STANDARD.md
|
|
1515
|
-
*/
|
|
1516
|
-
agent
|
|
1517
|
-
.command('pack <dir>')
|
|
1518
|
-
.description('Package an agent directory as a .cantz archive')
|
|
1519
|
-
.action(async (dir) => {
|
|
1520
|
-
try {
|
|
1521
|
-
const { existsSync, statSync } = await import('node:fs');
|
|
1522
|
-
const { resolve, basename, dirname } = await import('node:path');
|
|
1523
|
-
const { execFileSync } = await import('node:child_process');
|
|
1524
|
-
const resolvedDir = resolve(dir);
|
|
1525
|
-
if (!existsSync(resolvedDir) || !statSync(resolvedDir).isDirectory()) {
|
|
1526
|
-
cliOutput({
|
|
1527
|
-
success: false,
|
|
1528
|
-
error: {
|
|
1529
|
-
code: 'E_NOT_FOUND',
|
|
1530
|
-
message: `Directory does not exist: ${resolvedDir}`,
|
|
1531
|
-
},
|
|
1532
|
-
}, { command: 'agent pack' });
|
|
1533
|
-
process.exitCode = 4;
|
|
1534
|
-
return;
|
|
1535
|
-
}
|
|
1536
|
-
// Validate persona.cant exists
|
|
1537
|
-
const { join } = await import('node:path');
|
|
1538
|
-
const personaPath = join(resolvedDir, 'persona.cant');
|
|
1539
|
-
if (!existsSync(personaPath)) {
|
|
1540
|
-
cliOutput({
|
|
1541
|
-
success: false,
|
|
1542
|
-
error: {
|
|
1543
|
-
code: 'E_VALIDATION',
|
|
1544
|
-
message: `Agent directory must contain persona.cant: ${personaPath}`,
|
|
1545
|
-
},
|
|
1546
|
-
}, { command: 'agent pack' });
|
|
1547
|
-
process.exitCode = 6;
|
|
1548
|
-
return;
|
|
1549
|
-
}
|
|
1550
|
-
const agentName = basename(resolvedDir);
|
|
1551
|
-
const archiveName = `${agentName}.cantz`;
|
|
1552
|
-
const archivePath = resolve(archiveName);
|
|
1553
|
-
const parentDir = dirname(resolvedDir);
|
|
1554
|
-
// Create ZIP archive — run zip from parent directory so the
|
|
1555
|
-
// archive contains agentName/ as the top-level directory
|
|
1556
|
-
try {
|
|
1557
|
-
execFileSync('zip', ['-r', archivePath, agentName], {
|
|
1558
|
-
cwd: parentDir,
|
|
1559
|
-
encoding: 'utf-8',
|
|
1560
|
-
timeout: 30000,
|
|
1561
|
-
});
|
|
1562
|
-
}
|
|
1563
|
-
catch (zipErr) {
|
|
1564
|
-
cliOutput({
|
|
1565
|
-
success: false,
|
|
1566
|
-
error: {
|
|
1567
|
-
code: 'E_PACK',
|
|
1568
|
-
message: `Failed to create archive: ${String(zipErr)}`,
|
|
1569
|
-
},
|
|
1570
|
-
}, { command: 'agent pack' });
|
|
1571
|
-
process.exitCode = 1;
|
|
1572
|
-
return;
|
|
1573
|
-
}
|
|
1574
|
-
// Get file count and archive size
|
|
1575
|
-
const archiveStats = statSync(archivePath);
|
|
1576
|
-
const { readdirSync } = await import('node:fs');
|
|
1577
|
-
let fileCount = 0;
|
|
1578
|
-
const countFiles = (dirPath) => {
|
|
1579
|
-
const entries = readdirSync(dirPath, { withFileTypes: true });
|
|
1580
|
-
for (const entry of entries) {
|
|
1581
|
-
if (entry.isFile()) {
|
|
1582
|
-
fileCount++;
|
|
1583
|
-
}
|
|
1584
|
-
else if (entry.isDirectory()) {
|
|
1585
|
-
countFiles(join(dirPath, entry.name));
|
|
1586
|
-
}
|
|
1587
|
-
}
|
|
1588
|
-
};
|
|
1589
|
-
countFiles(resolvedDir);
|
|
1590
|
-
cliOutput({
|
|
1591
|
-
success: true,
|
|
1592
|
-
data: {
|
|
1593
|
-
archive: archivePath,
|
|
1594
|
-
agent: agentName,
|
|
1595
|
-
files: fileCount,
|
|
1596
|
-
size: archiveStats.size,
|
|
1597
|
-
},
|
|
1598
|
-
}, { command: 'agent pack' });
|
|
1599
|
-
}
|
|
1600
|
-
catch (err) {
|
|
1601
|
-
cliOutput({ success: false, error: { code: 'E_PACK', message: String(err) } }, { command: 'agent pack' });
|
|
1602
|
-
process.exitCode = 1;
|
|
1603
|
-
}
|
|
1604
|
-
});
|
|
1605
|
-
// --- cleo agent create ---
|
|
1606
|
-
/**
|
|
1607
|
-
* Scaffold a complete agent package with persona.cant, manifest.json,
|
|
1608
|
-
* and optional expertise seed files.
|
|
1609
|
-
*
|
|
1610
|
-
* Creates a directory structure conforming to the CANTZ package standard
|
|
1611
|
-
* (docs/specs/CANTZ-PACKAGE-STANDARD.md) with role-based persona templates
|
|
1612
|
-
* derived from the starter-bundle canonical agents.
|
|
1613
|
-
*
|
|
1614
|
-
* Template roles:
|
|
1615
|
-
* - **orchestrator**: read-only tools, high tier, dispatch-focused
|
|
1616
|
-
* - **lead**: read-only tools, mid tier, task decomposition
|
|
1617
|
-
* - **worker**: full tool access, mid tier, code execution
|
|
1618
|
-
* - **docs-worker**: documentation-focused worker variant
|
|
1619
|
-
*
|
|
1620
|
-
* @task T439
|
|
1621
|
-
* @epic T250
|
|
1622
|
-
* @see docs/specs/CANTZ-PACKAGE-STANDARD.md
|
|
1623
|
-
* @see packages/cleo-os/starter-bundle/agents/ — canonical format reference
|
|
1624
|
-
*/
|
|
1625
|
-
agent
|
|
1626
|
-
.command('create')
|
|
1627
|
-
.description('Scaffold a new agent package with persona.cant and manifest.json')
|
|
1628
|
-
.requiredOption('--name <name>', 'Agent name (kebab-case)')
|
|
1629
|
-
.requiredOption('--role <role>', 'Agent role: orchestrator, lead, worker, or docs-worker')
|
|
1630
|
-
.option('--tier <tier>', 'Agent tier: low, mid, or high (defaults based on role)')
|
|
1631
|
-
.option('--team <teamName>', 'Team this agent belongs to')
|
|
1632
|
-
.option('--domain <description>', 'Domain description for file permissions and context')
|
|
1633
|
-
.option('--global', 'Create in global tier (~/.local/share/cleo/cant/agents/)')
|
|
1634
|
-
.option('--seed-brain', 'Create expertise/mental-model-seed.md and seed a BRAIN observation')
|
|
1635
|
-
.option('--parent <parentAgent>', 'Parent agent name in the hierarchy')
|
|
1636
|
-
.action(async (opts) => {
|
|
1637
|
-
try {
|
|
1638
|
-
const { existsSync, mkdirSync, writeFileSync } = await import('node:fs');
|
|
1639
|
-
const { join } = await import('node:path');
|
|
1640
|
-
const { homedir } = await import('node:os');
|
|
1641
|
-
const name = opts['name'];
|
|
1642
|
-
const role = opts['role'];
|
|
1643
|
-
const tier = opts['tier'] ?? inferTierFromRole(role);
|
|
1644
|
-
const team = opts['team'];
|
|
1645
|
-
const domain = opts['domain'];
|
|
1646
|
-
const isGlobal = opts['global'] === true;
|
|
1647
|
-
const seedBrain = opts['seedBrain'] === true;
|
|
1648
|
-
const parent = opts['parent'];
|
|
1649
|
-
// Validate role
|
|
1650
|
-
const validRoles = ['orchestrator', 'lead', 'worker', 'docs-worker'];
|
|
1651
|
-
if (!validRoles.includes(role)) {
|
|
1652
|
-
cliOutput({
|
|
1653
|
-
success: false,
|
|
1654
|
-
error: {
|
|
1655
|
-
code: 'E_VALIDATION',
|
|
1656
|
-
message: `Invalid role "${role}". Must be one of: ${validRoles.join(', ')}`,
|
|
1657
|
-
fix: `cleo agent create --name ${name} --role worker`,
|
|
1658
|
-
},
|
|
1659
|
-
}, { command: 'agent create' });
|
|
1660
|
-
process.exitCode = 6;
|
|
1661
|
-
return;
|
|
1662
|
-
}
|
|
1663
|
-
// Validate tier
|
|
1664
|
-
const validTiers = ['low', 'mid', 'high'];
|
|
1665
|
-
if (!validTiers.includes(tier)) {
|
|
1666
|
-
cliOutput({
|
|
1667
|
-
success: false,
|
|
1668
|
-
error: {
|
|
1669
|
-
code: 'E_VALIDATION',
|
|
1670
|
-
message: `Invalid tier "${tier}". Must be one of: ${validTiers.join(', ')}`,
|
|
1671
|
-
fix: `cleo agent create --name ${name} --role ${role} --tier mid`,
|
|
1672
|
-
},
|
|
1673
|
-
}, { command: 'agent create' });
|
|
1674
|
-
process.exitCode = 6;
|
|
1675
|
-
return;
|
|
1676
|
-
}
|
|
1677
|
-
// Validate name is kebab-case
|
|
1678
|
-
if (!/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(name)) {
|
|
1679
|
-
cliOutput({
|
|
1680
|
-
success: false,
|
|
1681
|
-
error: {
|
|
1682
|
-
code: 'E_VALIDATION',
|
|
1683
|
-
message: `Agent name must be kebab-case: "${name}"`,
|
|
1684
|
-
fix: 'Use lowercase letters, numbers, and hyphens. Must start with a letter.',
|
|
1685
|
-
},
|
|
1686
|
-
}, { command: 'agent create' });
|
|
1687
|
-
process.exitCode = 6;
|
|
1688
|
-
return;
|
|
1689
|
-
}
|
|
1690
|
-
// Determine target directory
|
|
1691
|
-
let targetRoot;
|
|
1692
|
-
if (isGlobal) {
|
|
1693
|
-
const home = homedir();
|
|
1694
|
-
const xdgData = process.env['XDG_DATA_HOME'] ?? join(home, '.local', 'share');
|
|
1695
|
-
targetRoot = join(xdgData, 'cleo', 'cant', 'agents');
|
|
1696
|
-
}
|
|
1697
|
-
else {
|
|
1698
|
-
targetRoot = join(process.cwd(), '.cleo', 'cant', 'agents');
|
|
1699
|
-
}
|
|
1700
|
-
const agentDir = join(targetRoot, name);
|
|
1701
|
-
// Check if agent directory already exists
|
|
1702
|
-
if (existsSync(agentDir)) {
|
|
1703
|
-
cliOutput({
|
|
1704
|
-
success: false,
|
|
1705
|
-
error: {
|
|
1706
|
-
code: 'E_VALIDATION',
|
|
1707
|
-
message: `Agent directory already exists: ${agentDir}`,
|
|
1708
|
-
fix: 'Remove the existing directory or choose a different name.',
|
|
1709
|
-
},
|
|
1710
|
-
}, { command: 'agent create' });
|
|
1711
|
-
process.exitCode = 6;
|
|
1712
|
-
return;
|
|
1713
|
-
}
|
|
1714
|
-
// Create directory structure
|
|
1715
|
-
mkdirSync(agentDir, { recursive: true });
|
|
1716
|
-
// Generate persona.cant from role template
|
|
1717
|
-
const personaContent = generatePersonaCant({
|
|
1718
|
-
name,
|
|
1719
|
-
role,
|
|
1720
|
-
tier,
|
|
1721
|
-
team,
|
|
1722
|
-
domain,
|
|
1723
|
-
parent,
|
|
1724
|
-
});
|
|
1725
|
-
writeFileSync(join(agentDir, 'persona.cant'), personaContent, 'utf-8');
|
|
1726
|
-
// Generate manifest.json
|
|
1727
|
-
const manifest = generateManifest({ name, role, tier, domain });
|
|
1728
|
-
writeFileSync(join(agentDir, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`, 'utf-8');
|
|
1729
|
-
// Track created files for summary
|
|
1730
|
-
const createdFiles = [
|
|
1731
|
-
join(agentDir, 'persona.cant'),
|
|
1732
|
-
join(agentDir, 'manifest.json'),
|
|
1733
|
-
];
|
|
1734
|
-
// Generate team config if team specified
|
|
1735
|
-
if (team) {
|
|
1736
|
-
const teamConfigContent = generateTeamConfig(name, role, team);
|
|
1737
|
-
writeFileSync(join(agentDir, 'team-config.cant'), teamConfigContent, 'utf-8');
|
|
1738
|
-
createdFiles.push(join(agentDir, 'team-config.cant'));
|
|
1739
|
-
}
|
|
1740
|
-
// Seed brain expertise if requested
|
|
1741
|
-
if (seedBrain) {
|
|
1742
|
-
const expertiseDir = join(agentDir, 'expertise');
|
|
1743
|
-
mkdirSync(expertiseDir, { recursive: true });
|
|
1744
|
-
const seedContent = generateMentalModelSeed(name, role, domain);
|
|
1745
|
-
writeFileSync(join(expertiseDir, 'mental-model-seed.md'), seedContent, 'utf-8');
|
|
1746
|
-
createdFiles.push(join(expertiseDir, 'mental-model-seed.md'));
|
|
1747
|
-
// Best-effort BRAIN observation via CLI
|
|
1748
|
-
try {
|
|
1749
|
-
const { execFile } = await import('node:child_process');
|
|
1750
|
-
const { promisify } = await import('node:util');
|
|
1751
|
-
const execFileAsync = promisify(execFile);
|
|
1752
|
-
await execFileAsync('cleo', [
|
|
1753
|
-
'observe',
|
|
1754
|
-
`Agent ${name} created with role ${role}`,
|
|
1755
|
-
'--title',
|
|
1756
|
-
`Agent creation: ${name}`,
|
|
1757
|
-
], { encoding: 'utf-8', timeout: 10000 }).catch(() => {
|
|
1758
|
-
// Best-effort — do not fail create if observe fails
|
|
1759
|
-
});
|
|
1760
|
-
}
|
|
1761
|
-
catch {
|
|
1762
|
-
// Best-effort — do not fail create if observe fails
|
|
1763
|
-
}
|
|
1764
|
-
}
|
|
1765
|
-
// Best-effort agent registration in signaldock.db
|
|
1766
|
-
let registered = false;
|
|
1767
|
-
try {
|
|
1768
|
-
const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
|
|
1769
|
-
await getDb();
|
|
1770
|
-
const registry = new AgentRegistryAccessor(process.cwd());
|
|
1771
|
-
const existing = await registry.get(name);
|
|
1772
|
-
if (!existing) {
|
|
1773
|
-
const descMatch = personaContent.match(/description:\s*"([^"]+)"/);
|
|
1774
|
-
const displayName = descMatch?.[1] ?? name;
|
|
1775
|
-
await registry.register({
|
|
1776
|
-
agentId: name,
|
|
1777
|
-
displayName,
|
|
1778
|
-
apiKey: 'local-created',
|
|
1779
|
-
apiBaseUrl: 'local',
|
|
1780
|
-
classification: role,
|
|
1781
|
-
privacyTier: 'private',
|
|
1782
|
-
capabilities: [],
|
|
1783
|
-
skills: [],
|
|
1784
|
-
transportType: 'http',
|
|
1785
|
-
transportConfig: {},
|
|
1786
|
-
isActive: false,
|
|
1787
|
-
});
|
|
1788
|
-
registered = true;
|
|
1789
|
-
}
|
|
1790
|
-
}
|
|
1791
|
-
catch {
|
|
1792
|
-
// Registration is best-effort — do not fail the create
|
|
1793
|
-
}
|
|
1794
|
-
cliOutput({
|
|
1795
|
-
success: true,
|
|
1796
|
-
data: {
|
|
1797
|
-
agent: name,
|
|
1798
|
-
role,
|
|
1799
|
-
tier,
|
|
1800
|
-
directory: agentDir,
|
|
1801
|
-
scope: isGlobal ? 'global' : 'project',
|
|
1802
|
-
files: createdFiles,
|
|
1803
|
-
registered,
|
|
1804
|
-
brainSeeded: seedBrain,
|
|
1805
|
-
},
|
|
1806
|
-
}, { command: 'agent create' });
|
|
1807
|
-
}
|
|
1808
|
-
catch (err) {
|
|
1809
|
-
cliOutput({ success: false, error: { code: 'E_CREATE', message: String(err) } }, { command: 'agent create' });
|
|
1810
|
-
process.exitCode = 1;
|
|
1811
|
-
}
|
|
1812
|
-
});
|
|
1813
|
-
}
|
|
1814
|
-
/**
|
|
1815
|
-
* Infer the default tier from the agent role.
|
|
1816
|
-
*
|
|
1817
|
-
* - orchestrator -> high
|
|
1818
|
-
* - lead -> mid
|
|
1819
|
-
* - worker -> mid
|
|
1820
|
-
* - docs-worker -> mid
|
|
1821
|
-
*
|
|
1822
|
-
* @param role - The agent role string.
|
|
1823
|
-
* @returns The inferred tier string.
|
|
1824
|
-
*/
|
|
1825
|
-
function inferTierFromRole(role) {
|
|
1826
|
-
if (role === 'orchestrator')
|
|
1827
|
-
return 'high';
|
|
1828
|
-
return 'mid';
|
|
1829
|
-
}
|
|
1830
|
-
/**
|
|
1831
|
-
* Generate a `persona.cant` file from role-based templates.
|
|
1832
|
-
*
|
|
1833
|
-
* Templates are derived from the canonical starter-bundle agents at
|
|
1834
|
-
* `packages/cleo-os/starter-bundle/agents/`. Each role maps to a
|
|
1835
|
-
* specific set of tools, permissions, context sources, and behavioral
|
|
1836
|
-
* hooks.
|
|
1837
|
-
*
|
|
1838
|
-
* @param params - Agent persona parameters.
|
|
1839
|
-
* @returns The complete persona.cant file content.
|
|
1840
|
-
*
|
|
1841
|
-
* @see packages/cleo-os/starter-bundle/agents/cleo-orchestrator.cant
|
|
1842
|
-
* @see packages/cleo-os/starter-bundle/agents/dev-lead.cant
|
|
1843
|
-
* @see packages/cleo-os/starter-bundle/agents/code-worker.cant
|
|
1844
|
-
* @see packages/cleo-os/starter-bundle/agents/docs-worker.cant
|
|
1845
|
-
*/
|
|
1846
|
-
function generatePersonaCant(params) {
|
|
1847
|
-
const { name, role, tier, team, domain, parent } = params;
|
|
1848
|
-
switch (role) {
|
|
1849
|
-
case 'orchestrator':
|
|
1850
|
-
return generateOrchestratorPersona(name, tier, team, parent);
|
|
1851
|
-
case 'lead':
|
|
1852
|
-
return generateLeadPersona(name, tier, team, domain, parent);
|
|
1853
|
-
case 'worker':
|
|
1854
|
-
return generateWorkerPersona(name, tier, team, domain, parent);
|
|
1855
|
-
case 'docs-worker':
|
|
1856
|
-
return generateDocsWorkerPersona(name, tier, team, domain, parent);
|
|
1857
|
-
default:
|
|
1858
|
-
return generateWorkerPersona(name, tier, team, domain, parent);
|
|
1859
|
-
}
|
|
1860
|
-
}
|
|
1861
|
-
/**
|
|
1862
|
-
* Generate an orchestrator persona.cant.
|
|
1863
|
-
*
|
|
1864
|
-
* Orchestrators coordinate work but do not execute code. They hold
|
|
1865
|
-
* read-only core tools (Read, Grep, Glob) plus dispatch tools for
|
|
1866
|
-
* routing work to leads and workers.
|
|
1867
|
-
*
|
|
1868
|
-
* @param name - Agent name (kebab-case).
|
|
1869
|
-
* @param tier - Agent tier.
|
|
1870
|
-
* @param team - Optional team name.
|
|
1871
|
-
* @param parent - Optional parent agent.
|
|
1872
|
-
* @returns The persona.cant content string.
|
|
1873
|
-
*/
|
|
1874
|
-
function generateOrchestratorPersona(name, tier, team, parent) {
|
|
1875
|
-
const parentLine = parent ? `\n parent: ${parent}` : '';
|
|
1876
|
-
const teamComment = team ? `\n# Team: ${team}` : '';
|
|
1877
|
-
return `---
|
|
1878
|
-
kind: agent
|
|
1879
|
-
version: "1"
|
|
1880
|
-
---
|
|
1881
|
-
|
|
1882
|
-
# ${name} — orchestrator agent.${teamComment}
|
|
1883
|
-
# Coordinates the team, classifies work, dispatches to leads/workers.
|
|
1884
|
-
|
|
1885
|
-
agent ${name}:
|
|
1886
|
-
role: orchestrator${parentLine}
|
|
1887
|
-
tier: ${tier}
|
|
1888
|
-
description: "Orchestrator agent. Reads task context, classifies work, dispatches to leads, and synthesizes results. Does not execute code — coordinates."
|
|
1889
|
-
consult-when: "Cross-team decisions, scope changes, human-in-the-loop escalation, or when a lead reports a blocking ambiguity"
|
|
1890
|
-
|
|
1891
|
-
context_sources:
|
|
1892
|
-
- source: decisions
|
|
1893
|
-
query: "recent architectural and project decisions"
|
|
1894
|
-
max_entries: 5
|
|
1895
|
-
- source: patterns
|
|
1896
|
-
query: "project conventions and established patterns"
|
|
1897
|
-
max_entries: 3
|
|
1898
|
-
on_overflow: escalate_tier
|
|
1899
|
-
|
|
1900
|
-
mental_model:
|
|
1901
|
-
scope: project
|
|
1902
|
-
max_tokens: 2000
|
|
1903
|
-
on_load:
|
|
1904
|
-
validate: true
|
|
1905
|
-
|
|
1906
|
-
permissions:
|
|
1907
|
-
tasks: read, write
|
|
1908
|
-
session: read, write
|
|
1909
|
-
memory: read, write
|
|
1910
|
-
|
|
1911
|
-
skills:
|
|
1912
|
-
- ct-cleo
|
|
1913
|
-
- ct-task-executor
|
|
1914
|
-
|
|
1915
|
-
tools:
|
|
1916
|
-
core: [Read, Grep, Glob]
|
|
1917
|
-
dispatch: [dispatch_worker, report_to_user]
|
|
1918
|
-
|
|
1919
|
-
on SessionStart:
|
|
1920
|
-
session "Read active tasks and recent decisions to build situational awareness"
|
|
1921
|
-
context: [active-tasks, memory-bridge, recent-decisions]
|
|
1922
|
-
|
|
1923
|
-
on TaskCompleted:
|
|
1924
|
-
if **the completed task unblocks downstream work**:
|
|
1925
|
-
session "Reassess task queue and dispatch next work"
|
|
1926
|
-
`;
|
|
1927
|
-
}
|
|
1928
|
-
/**
|
|
1929
|
-
* Generate a lead persona.cant.
|
|
1930
|
-
*
|
|
1931
|
-
* Leads decide HOW to build and dispatch work to workers. They hold
|
|
1932
|
-
* read-only tools per TEAM-002 / ULTRAPLAN 10.3 — no Edit, Write, or
|
|
1933
|
-
* Bash access.
|
|
1934
|
-
*
|
|
1935
|
-
* @param name - Agent name (kebab-case).
|
|
1936
|
-
* @param tier - Agent tier.
|
|
1937
|
-
* @param team - Optional team name.
|
|
1938
|
-
* @param domain - Optional domain description.
|
|
1939
|
-
* @param parent - Optional parent agent.
|
|
1940
|
-
* @returns The persona.cant content string.
|
|
1941
|
-
*/
|
|
1942
|
-
function generateLeadPersona(name, tier, team, domain, parent) {
|
|
1943
|
-
const parentLine = parent ? `\n parent: ${parent}` : '\n parent: cleo-orchestrator';
|
|
1944
|
-
const teamComment = team ? `\n# Team: ${team}` : '';
|
|
1945
|
-
const domainDesc = domain ? ` Specializes in ${domain}.` : '';
|
|
1946
|
-
return `---
|
|
1947
|
-
kind: agent
|
|
1948
|
-
version: "1"
|
|
1949
|
-
---
|
|
1950
|
-
|
|
1951
|
-
# ${name} — lead agent.${teamComment}
|
|
1952
|
-
# Decomposes tasks, reviews worker output, decides technical approach.
|
|
1953
|
-
# MUST NOT hold Edit/Write/Bash tools (TEAM-002 / ULTRAPLAN 10.3).
|
|
1954
|
-
|
|
1955
|
-
agent ${name}:
|
|
1956
|
-
role: lead${parentLine}
|
|
1957
|
-
tier: ${tier}
|
|
1958
|
-
description: "Development lead.${domainDesc} Decomposes tasks into concrete implementation steps, reviews worker output, and decides technical approach. Does not write code directly."
|
|
1959
|
-
consult-when: "Implementation strategy, code architecture, refactoring direction, task decomposition, or when workers need clarification"
|
|
1960
|
-
|
|
1961
|
-
context_sources:
|
|
1962
|
-
- source: patterns
|
|
1963
|
-
query: "codebase conventions and architecture patterns"
|
|
1964
|
-
max_entries: 5
|
|
1965
|
-
- source: decisions
|
|
1966
|
-
query: "technical decisions affecting implementation"
|
|
1967
|
-
max_entries: 3
|
|
1968
|
-
on_overflow: escalate_tier
|
|
1969
|
-
|
|
1970
|
-
mental_model:
|
|
1971
|
-
scope: project
|
|
1972
|
-
max_tokens: 1000
|
|
1973
|
-
on_load:
|
|
1974
|
-
validate: true
|
|
1975
|
-
|
|
1976
|
-
permissions:
|
|
1977
|
-
files:
|
|
1978
|
-
read: ["**/*"]
|
|
1979
|
-
|
|
1980
|
-
skills:
|
|
1981
|
-
- ct-cleo
|
|
1982
|
-
- ct-dev-workflow
|
|
1983
|
-
- ct-task-executor
|
|
1984
|
-
|
|
1985
|
-
tools:
|
|
1986
|
-
core: [Read, Grep, Glob]
|
|
1987
|
-
dispatch: [dispatch_worker, report_to_orchestrator]
|
|
1988
|
-
|
|
1989
|
-
on SessionStart:
|
|
1990
|
-
session "Review current task assignments and worker availability"
|
|
1991
|
-
context: [active-tasks, memory-bridge]
|
|
1992
|
-
|
|
1993
|
-
on TaskCompleted:
|
|
1994
|
-
if **the completed task introduced new code**:
|
|
1995
|
-
session "Review worker output for quality and completeness before reporting to orchestrator"
|
|
1996
|
-
`;
|
|
1997
|
-
}
|
|
1998
|
-
/**
|
|
1999
|
-
* Generate a worker persona.cant.
|
|
2000
|
-
*
|
|
2001
|
-
* Workers execute code changes within declared file globs. They hold
|
|
2002
|
-
* the full tool set (Read, Edit, Write, Bash, Glob, Grep) and operate
|
|
2003
|
-
* within file permission boundaries derived from the `--domain` flag.
|
|
2004
|
-
*
|
|
2005
|
-
* @param name - Agent name (kebab-case).
|
|
2006
|
-
* @param tier - Agent tier.
|
|
2007
|
-
* @param team - Optional team name.
|
|
2008
|
-
* @param domain - Optional domain description for file permissions.
|
|
2009
|
-
* @param parent - Optional parent agent.
|
|
2010
|
-
* @returns The persona.cant content string.
|
|
2011
|
-
*/
|
|
2012
|
-
function generateWorkerPersona(name, tier, team, domain, parent) {
|
|
2013
|
-
const parentLine = parent ? `\n parent: ${parent}` : '\n parent: dev-lead';
|
|
2014
|
-
const teamComment = team ? `\n# Team: ${team}` : '';
|
|
2015
|
-
const domainDesc = domain ? ` Specializes in ${domain}.` : '';
|
|
2016
|
-
const writeGlobs = deriveWriteGlobs(domain);
|
|
2017
|
-
return `---
|
|
2018
|
-
kind: agent
|
|
2019
|
-
version: "1"
|
|
2020
|
-
---
|
|
2021
|
-
|
|
2022
|
-
# ${name} — worker agent.${teamComment}
|
|
2023
|
-
# Executes code changes within declared file globs.
|
|
2024
|
-
|
|
2025
|
-
agent ${name}:
|
|
2026
|
-
role: worker${parentLine}
|
|
2027
|
-
tier: ${tier}
|
|
2028
|
-
description: "Code worker.${domainDesc} Reads requirements, writes code, runs tests, and validates changes. Operates within declared file permission globs."
|
|
2029
|
-
consult-when: "Writing code, fixing bugs, running tests, formatting, or any file modification task"
|
|
2030
|
-
|
|
2031
|
-
context_sources:
|
|
2032
|
-
- source: patterns
|
|
2033
|
-
query: "coding conventions and testing patterns"
|
|
2034
|
-
max_entries: 5
|
|
2035
|
-
- source: learnings
|
|
2036
|
-
query: "past implementation mistakes and fixes"
|
|
2037
|
-
max_entries: 3
|
|
2038
|
-
on_overflow: escalate_tier
|
|
2039
|
-
|
|
2040
|
-
mental_model:
|
|
2041
|
-
scope: project
|
|
2042
|
-
max_tokens: 1000
|
|
2043
|
-
on_load:
|
|
2044
|
-
validate: true
|
|
2045
|
-
|
|
2046
|
-
permissions:
|
|
2047
|
-
files:
|
|
2048
|
-
write: ${JSON.stringify(writeGlobs)}
|
|
2049
|
-
read: ["**/*"]
|
|
2050
|
-
delete: ${JSON.stringify(writeGlobs)}
|
|
2051
|
-
|
|
2052
|
-
skills:
|
|
2053
|
-
- ct-cleo
|
|
2054
|
-
- ct-dev-workflow
|
|
2055
|
-
- ct-task-executor
|
|
2056
|
-
|
|
2057
|
-
tools:
|
|
2058
|
-
core: [Read, Edit, Write, Bash, Glob, Grep]
|
|
2059
|
-
|
|
2060
|
-
on SessionStart:
|
|
2061
|
-
session "Check assigned task and read relevant source files before starting work"
|
|
2062
|
-
context: [active-tasks, memory-bridge]
|
|
2063
|
-
|
|
2064
|
-
on PostToolUse:
|
|
2065
|
-
if tool.name == "Write" or tool.name == "Edit":
|
|
2066
|
-
session "Verify the change compiles and passes lint before proceeding"
|
|
2067
|
-
`;
|
|
2068
|
-
}
|
|
2069
|
-
/**
|
|
2070
|
-
* Generate a docs-worker persona.cant.
|
|
2071
|
-
*
|
|
2072
|
-
* Documentation workers write and maintain documentation within declared
|
|
2073
|
-
* documentation file globs. They carry documentation-specific skills and
|
|
2074
|
-
* context sources.
|
|
2075
|
-
*
|
|
2076
|
-
* @param name - Agent name (kebab-case).
|
|
2077
|
-
* @param tier - Agent tier.
|
|
2078
|
-
* @param team - Optional team name.
|
|
2079
|
-
* @param domain - Optional domain description.
|
|
2080
|
-
* @param parent - Optional parent agent.
|
|
2081
|
-
* @returns The persona.cant content string.
|
|
2082
|
-
*/
|
|
2083
|
-
function generateDocsWorkerPersona(name, tier, team, domain, parent) {
|
|
2084
|
-
const parentLine = parent ? `\n parent: ${parent}` : '\n parent: dev-lead';
|
|
2085
|
-
const teamComment = team ? `\n# Team: ${team}` : '';
|
|
2086
|
-
const domainDesc = domain ? ` Specializes in ${domain} documentation.` : '';
|
|
2087
|
-
return `---
|
|
2088
|
-
kind: agent
|
|
2089
|
-
version: "1"
|
|
2090
|
-
---
|
|
2091
|
-
|
|
2092
|
-
# ${name} — documentation worker agent.${teamComment}
|
|
2093
|
-
# Writes and maintains documentation within declared globs.
|
|
2094
|
-
|
|
2095
|
-
agent ${name}:
|
|
2096
|
-
role: worker${parentLine}
|
|
2097
|
-
tier: ${tier}
|
|
2098
|
-
description: "Documentation worker.${domainDesc} Writes READMEs, updates guides, adds TSDoc comments, and maintains project documentation. Operates within declared documentation file globs."
|
|
2099
|
-
consult-when: "Writing documentation, updating READMEs, adding TSDoc comments, or improving existing docs"
|
|
2100
|
-
|
|
2101
|
-
context_sources:
|
|
2102
|
-
- source: patterns
|
|
2103
|
-
query: "documentation conventions and style patterns"
|
|
2104
|
-
max_entries: 3
|
|
2105
|
-
- source: decisions
|
|
2106
|
-
query: "architectural decisions needing documentation"
|
|
2107
|
-
max_entries: 3
|
|
2108
|
-
on_overflow: escalate_tier
|
|
2109
|
-
|
|
2110
|
-
mental_model:
|
|
2111
|
-
scope: project
|
|
2112
|
-
max_tokens: 1000
|
|
2113
|
-
on_load:
|
|
2114
|
-
validate: true
|
|
2115
|
-
|
|
2116
|
-
permissions:
|
|
2117
|
-
files:
|
|
2118
|
-
write: ["docs/**", "**/*.md", "**/*.mdx"]
|
|
2119
|
-
read: ["**/*"]
|
|
2120
|
-
delete: ["docs/**"]
|
|
2121
|
-
|
|
2122
|
-
skills:
|
|
2123
|
-
- ct-cleo
|
|
2124
|
-
- ct-documentor
|
|
2125
|
-
- ct-docs-write
|
|
2126
|
-
|
|
2127
|
-
tools:
|
|
2128
|
-
core: [Read, Edit, Write, Bash, Glob, Grep]
|
|
2129
|
-
|
|
2130
|
-
on SessionStart:
|
|
2131
|
-
session "Check assigned documentation task and review existing docs for context"
|
|
2132
|
-
context: [active-tasks, memory-bridge]
|
|
2133
|
-
|
|
2134
|
-
on PostToolUse:
|
|
2135
|
-
if tool.name == "Write" or tool.name == "Edit":
|
|
2136
|
-
session "Verify markdown renders correctly and follows project style conventions"
|
|
2137
|
-
`;
|
|
2138
|
-
}
|
|
2139
|
-
/**
|
|
2140
|
-
* Derive file write globs from a domain description string.
|
|
2141
|
-
*
|
|
2142
|
-
* Maps common domain keywords to appropriate file glob patterns.
|
|
2143
|
-
* Falls back to the default `["src/**", "packages/**"]` when no
|
|
2144
|
-
* domain is specified or no keywords match.
|
|
2145
|
-
*
|
|
2146
|
-
* @param domain - Optional domain description string.
|
|
2147
|
-
* @returns Array of glob pattern strings for file write permissions.
|
|
2148
|
-
*/
|
|
2149
|
-
function deriveWriteGlobs(domain) {
|
|
2150
|
-
const defaults = ['src/**', 'packages/**', 'lib/**', 'test/**', 'tests/**'];
|
|
2151
|
-
if (!domain)
|
|
2152
|
-
return defaults;
|
|
2153
|
-
const lower = domain.toLowerCase();
|
|
2154
|
-
// Domain-specific glob mappings
|
|
2155
|
-
if (lower.includes('frontend') || lower.includes('ui') || lower.includes('component')) {
|
|
2156
|
-
return ['src/**', 'packages/**', 'components/**', 'styles/**', 'public/**', 'test/**'];
|
|
2157
|
-
}
|
|
2158
|
-
if (lower.includes('backend') || lower.includes('api') || lower.includes('server')) {
|
|
2159
|
-
return ['src/**', 'packages/**', 'lib/**', 'api/**', 'test/**', 'tests/**'];
|
|
2160
|
-
}
|
|
2161
|
-
if (lower.includes('infra') || lower.includes('deploy') || lower.includes('ci')) {
|
|
2162
|
-
return ['.github/**', 'infra/**', 'deploy/**', 'scripts/**', 'Dockerfile*'];
|
|
2163
|
-
}
|
|
2164
|
-
if (lower.includes('test') || lower.includes('qa') || lower.includes('quality')) {
|
|
2165
|
-
return ['test/**', 'tests/**', 'src/**/*.test.*', 'src/**/*.spec.*', 'packages/**/*.test.*'];
|
|
2166
|
-
}
|
|
2167
|
-
if (lower.includes('rust') || lower.includes('crate')) {
|
|
2168
|
-
return ['crates/**', 'src/**', 'Cargo.toml', 'test/**'];
|
|
2169
|
-
}
|
|
2170
|
-
if (lower.includes('doc')) {
|
|
2171
|
-
return ['docs/**', '**/*.md', '**/*.mdx'];
|
|
2172
|
-
}
|
|
2173
|
-
return defaults;
|
|
2174
|
-
}
|
|
2175
|
-
/**
|
|
2176
|
-
* Generate a `manifest.json` object for the agent package.
|
|
2177
|
-
*
|
|
2178
|
-
* Conforms to the CANTZ-PACKAGE-STANDARD.md Section 2.3 schema.
|
|
2179
|
-
*
|
|
2180
|
-
* @param params - Manifest generation parameters.
|
|
2181
|
-
* @returns A plain object ready for JSON serialization.
|
|
2182
|
-
*/
|
|
2183
|
-
function generateManifest(params) {
|
|
2184
|
-
return {
|
|
2185
|
-
name: params.name,
|
|
2186
|
-
version: '1.0.0',
|
|
2187
|
-
description: `${capitalizeFirst(params.role)} agent${params.domain ? ` for ${params.domain}` : ''}`,
|
|
2188
|
-
cant: {
|
|
2189
|
-
minVersion: '1',
|
|
2190
|
-
tier: params.tier,
|
|
2191
|
-
role: params.role === 'docs-worker' ? 'worker' : params.role,
|
|
2192
|
-
},
|
|
2193
|
-
createdAt: new Date().toISOString(),
|
|
2194
|
-
};
|
|
2195
|
-
}
|
|
2196
|
-
/**
|
|
2197
|
-
* Generate a team configuration CANT file fragment.
|
|
2198
|
-
*
|
|
2199
|
-
* Creates a minimal team-config.cant that declares the agent's
|
|
2200
|
-
* membership in a named team.
|
|
2201
|
-
*
|
|
2202
|
-
* @param name - Agent name.
|
|
2203
|
-
* @param role - Agent role.
|
|
2204
|
-
* @param team - Team name.
|
|
2205
|
-
* @returns The team-config.cant content string.
|
|
2206
|
-
*/
|
|
2207
|
-
function generateTeamConfig(name, role, team) {
|
|
2208
|
-
return `---
|
|
2209
|
-
kind: team-config
|
|
2210
|
-
version: "1"
|
|
2211
|
-
---
|
|
2212
|
-
|
|
2213
|
-
# Team membership for ${name}
|
|
2214
|
-
|
|
2215
|
-
team ${team}:
|
|
2216
|
-
member ${name}:
|
|
2217
|
-
role: ${role}
|
|
2218
|
-
status: active
|
|
2219
|
-
`;
|
|
2220
|
-
}
|
|
2221
|
-
/**
|
|
2222
|
-
* Generate a mental model seed markdown file.
|
|
2223
|
-
*
|
|
2224
|
-
* Creates an initial expertise document with placeholder sections
|
|
2225
|
-
* for the agent to populate as it learns about the project domain.
|
|
2226
|
-
*
|
|
2227
|
-
* @param name - Agent name.
|
|
2228
|
-
* @param role - Agent role.
|
|
2229
|
-
* @param domain - Optional domain description.
|
|
2230
|
-
* @returns The mental-model-seed.md content string.
|
|
2231
|
-
*/
|
|
2232
|
-
function generateMentalModelSeed(name, role, domain) {
|
|
2233
|
-
const domainSection = domain
|
|
2234
|
-
? `## Domain\n\n${domain}\n`
|
|
2235
|
-
: `## Domain\n\nTODO: Describe the domain this agent specializes in.\n`;
|
|
2236
|
-
return `# Mental Model Seed: ${name}
|
|
2237
|
-
|
|
2238
|
-
> Auto-generated at ${new Date().toISOString()}
|
|
2239
|
-
> Role: ${role}
|
|
2240
|
-
|
|
2241
|
-
${domainSection}
|
|
2242
|
-
## Key Patterns
|
|
2243
|
-
|
|
2244
|
-
TODO: Document recurring patterns this agent should recognize.
|
|
2245
|
-
|
|
2246
|
-
## Known Pitfalls
|
|
2247
|
-
|
|
2248
|
-
TODO: Document common mistakes or anti-patterns in this domain.
|
|
2249
|
-
|
|
2250
|
-
## Decision History
|
|
2251
|
-
|
|
2252
|
-
TODO: Track important decisions and their rationale.
|
|
2253
|
-
|
|
2254
|
-
## Learning Log
|
|
2255
|
-
|
|
2256
|
-
TODO: Record discoveries and insights as the agent operates.
|
|
2257
|
-
`;
|
|
2258
|
-
}
|
|
2259
|
-
/**
|
|
2260
|
-
* Capitalize the first letter of a string.
|
|
2261
|
-
*
|
|
2262
|
-
* @param str - Input string.
|
|
2263
|
-
* @returns String with the first character uppercased.
|
|
2264
|
-
*/
|
|
2265
|
-
function capitalizeFirst(str) {
|
|
2266
|
-
if (str.length === 0)
|
|
2267
|
-
return str;
|
|
2268
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
2269
|
-
}
|
|
2270
|
-
//# sourceMappingURL=agent.js.map
|