brainclaw 0.28.0 → 1.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +193 -170
- package/dist/brainclaw-vscode.vsix +0 -0
- package/dist/cli.js +683 -23
- package/dist/commands/accept.js +3 -0
- package/dist/commands/add-step.js +11 -26
- package/dist/commands/agent-board.js +70 -3
- package/dist/commands/audit.js +19 -0
- package/dist/commands/check-policy.js +54 -0
- package/dist/commands/check-security-mcp.js +145 -0
- package/dist/commands/check-security.js +106 -0
- package/dist/commands/claim-resource.js +1 -0
- package/dist/commands/codev.js +672 -0
- package/dist/commands/compact.js +74 -0
- package/dist/commands/complete-step.js +16 -26
- package/dist/commands/constraint.js +8 -20
- package/dist/commands/decision.js +9 -20
- package/dist/commands/delete-plan.js +10 -12
- package/dist/commands/delete-step.js +16 -0
- package/dist/commands/dispatch.js +163 -0
- package/dist/commands/doctor.js +1122 -49
- package/dist/commands/enable-agent.js +1 -0
- package/dist/commands/export.js +280 -22
- package/dist/commands/handoff.js +33 -0
- package/dist/commands/harvest.js +189 -0
- package/dist/commands/hooks.js +82 -25
- package/dist/commands/inbox.js +169 -0
- package/dist/commands/init.js +38 -31
- package/dist/commands/install-hooks.js +71 -44
- package/dist/commands/link.js +89 -0
- package/dist/commands/list-claims.js +48 -3
- package/dist/commands/list-plans.js +129 -25
- package/dist/commands/loops-handlers.js +409 -0
- package/dist/commands/mcp-read-handlers.js +1628 -0
- package/dist/commands/mcp-schemas.generated.js +74 -0
- package/dist/commands/mcp.js +4244 -1475
- package/dist/commands/plan-resource.js +64 -0
- package/dist/commands/plan.js +12 -26
- package/dist/commands/prune.js +37 -2
- package/dist/commands/reflect.js +20 -7
- package/dist/commands/release-claim.js +11 -6
- package/dist/commands/release-notes.js +170 -0
- package/dist/commands/repair.js +210 -0
- package/dist/commands/run-profile.js +57 -0
- package/dist/commands/sequence.js +113 -0
- package/dist/commands/session-end.js +423 -14
- package/dist/commands/session-start.js +214 -41
- package/dist/commands/setup-security.js +103 -0
- package/dist/commands/setup.js +42 -4
- package/dist/commands/stale.js +109 -0
- package/dist/commands/switch.js +131 -10
- package/dist/commands/trap.js +14 -31
- package/dist/commands/update-handoff.js +63 -4
- package/dist/commands/update-plan.js +21 -28
- package/dist/commands/update-step.js +37 -0
- package/dist/commands/upgrade.js +313 -6
- package/dist/commands/usage.js +102 -0
- package/dist/commands/version.js +20 -0
- package/dist/commands/who.js +124 -0
- package/dist/commands/worktree.js +105 -0
- package/dist/core/actions.js +315 -0
- package/dist/core/agent-capability.js +610 -17
- package/dist/core/agent-context.js +7 -1
- package/dist/core/agent-files.js +1169 -85
- package/dist/core/agent-integrations.js +160 -5
- package/dist/core/agent-inventory.js +2 -0
- package/dist/core/agent-profiles.js +93 -0
- package/dist/core/agent-registry.js +162 -30
- package/dist/core/agentrun-reconciler.js +345 -0
- package/dist/core/agentruns.js +424 -0
- package/dist/core/ai-agent-detection.js +31 -10
- package/dist/core/archival.js +77 -0
- package/dist/core/assignment-sweeper.js +82 -0
- package/dist/core/assignments.js +367 -0
- package/dist/core/audit.js +30 -0
- package/dist/core/bootstrap.js +61 -10
- package/dist/core/brainclaw-version.js +94 -2
- package/dist/core/candidates.js +93 -2
- package/dist/core/claims.js +419 -0
- package/dist/core/codev-metrics.js +77 -0
- package/dist/core/codev-personas.js +31 -0
- package/dist/core/codev-plan-gen.js +35 -0
- package/dist/core/codev-prompts.js +74 -0
- package/dist/core/codev-responses.js +62 -0
- package/dist/core/codev-rounds.js +218 -0
- package/dist/core/config.js +4 -0
- package/dist/core/context.js +454 -34
- package/dist/core/coordination.js +201 -6
- package/dist/core/cross-project.js +230 -16
- package/dist/core/default-profiles/doctor.yaml +11 -0
- package/dist/core/default-profiles/janitor.yaml +11 -0
- package/dist/core/default-profiles/onboarder.yaml +11 -0
- package/dist/core/default-profiles/reviewer.yaml +13 -0
- package/dist/core/dispatcher.js +1189 -0
- package/dist/core/duplicates.js +2 -2
- package/dist/core/entity-operations.js +450 -0
- package/dist/core/entity-registry.js +344 -0
- package/dist/core/event-log.js +1 -0
- package/dist/core/events.js +106 -2
- package/dist/core/execution-adapters.js +154 -0
- package/dist/core/execution-context.js +63 -0
- package/dist/core/execution-profile.js +270 -0
- package/dist/core/execution.js +255 -0
- package/dist/core/facade-schema.js +81 -0
- package/dist/core/federation-cloud.js +99 -0
- package/dist/core/federation-message.js +52 -0
- package/dist/core/federation-transport.js +65 -0
- package/dist/core/gc-semantic.js +482 -0
- package/dist/core/governance.js +247 -0
- package/dist/core/guards.js +19 -0
- package/dist/core/ideation.js +72 -0
- package/dist/core/identity.js +252 -28
- package/dist/core/ids.js +6 -0
- package/dist/core/input-validation.js +2 -2
- package/dist/core/instruction-templates.js +344 -136
- package/dist/core/io.js +90 -11
- package/dist/core/lock.js +6 -2
- package/dist/core/loops/brief-assembly.js +213 -0
- package/dist/core/loops/facade-schema.js +148 -0
- package/dist/core/loops/index.js +7 -0
- package/dist/core/loops/iteration-engine.js +139 -0
- package/dist/core/loops/lock.js +385 -0
- package/dist/core/loops/store.js +201 -0
- package/dist/core/loops/types.js +403 -0
- package/dist/core/loops/verbs.js +534 -0
- package/dist/core/markdown.js +15 -3
- package/dist/core/memory-compactor.js +432 -0
- package/dist/core/memory-git.js +152 -8
- package/dist/core/messaging.js +278 -0
- package/dist/core/migration.js +32 -1
- package/dist/core/mutation-pipeline.js +4 -2
- package/dist/core/operations/memory-mutation.js +129 -0
- package/dist/core/operations/memory-write.js +78 -0
- package/dist/core/operations/plan.js +190 -0
- package/dist/core/policy.js +169 -0
- package/dist/core/repo-analysis.js +67 -0
- package/dist/core/reputation.js +9 -3
- package/dist/core/schema.js +546 -21
- package/dist/core/search.js +21 -2
- package/dist/core/security-cache.js +71 -0
- package/dist/core/security-guard.js +152 -0
- package/dist/core/security-scoring.js +86 -0
- package/dist/core/sequence.js +130 -0
- package/dist/core/socket-client.js +113 -0
- package/dist/core/staleness.js +246 -0
- package/dist/core/state.js +98 -22
- package/dist/core/store-resolution.js +54 -12
- package/dist/core/toml-writer.js +76 -0
- package/dist/core/upgrades/backup.js +232 -0
- package/dist/core/upgrades/health-check.js +169 -0
- package/dist/core/upgrades/patches/candidate-archive.js +145 -0
- package/dist/core/upgrades/patches/handoff-review-strip.js +128 -0
- package/dist/core/upgrades/patches/provenance-rollout.js +136 -0
- package/dist/core/upgrades/schema-version.js +97 -0
- package/dist/core/worktree.js +606 -0
- package/dist/facts.js +114 -0
- package/dist/facts.json +111 -0
- package/docs/architecture/project-refs.md +5 -1
- package/docs/cli.md +690 -43
- package/docs/concepts/ideation-loop.md +317 -0
- package/docs/concepts/loop-engine.md +456 -0
- package/docs/concepts/mcp-governance.md +268 -0
- package/docs/concepts/memory-staleness.md +122 -0
- package/docs/concepts/multi-agent-workflows.md +166 -0
- package/docs/concepts/plans-and-claims.md +31 -6
- package/docs/concepts/project-md-convention.md +35 -0
- package/docs/concepts/troubleshooting.md +220 -0
- package/docs/concepts/upgrade-cli.md +202 -0
- package/docs/concepts/upgrade-dogfood-procedure.md +114 -0
- package/docs/context-format-changelog.md +2 -2
- package/docs/context-format.md +2 -2
- package/docs/index.md +68 -0
- package/docs/integrations/agents.md +15 -16
- package/docs/integrations/cline.md +88 -0
- package/docs/integrations/codex.md +75 -23
- package/docs/integrations/continue.md +60 -0
- package/docs/integrations/copilot.md +67 -9
- package/docs/integrations/kilocode.md +72 -0
- package/docs/integrations/mcp.md +304 -21
- package/docs/integrations/mistral-vibe.md +122 -0
- package/docs/integrations/opencode.md +84 -0
- package/docs/integrations/overview.md +23 -8
- package/docs/integrations/roo.md +74 -0
- package/docs/integrations/windsurf.md +83 -0
- package/docs/mcp-schema-changelog.md +191 -1
- package/docs/playbooks/integration/index.md +121 -0
- package/docs/playbooks/productivity/index.md +102 -0
- package/docs/playbooks/team/index.md +122 -0
- package/docs/product/agent-first-model.md +184 -0
- package/docs/product/entity-model-audit.md +462 -0
- package/docs/quickstart-existing-project.md +135 -0
- package/docs/quickstart.md +124 -37
- package/docs/release-maintenance.md +79 -0
- package/docs/review.md +2 -0
- package/docs/server-operations.md +118 -0
- package/package.json +20 -12
- package/dist/commands/claude-desktop-extension.js +0 -18
- package/dist/commands/diff.js +0 -99
- package/dist/core/claude-desktop-extension.js +0 -224
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `brainclaw repair` — safe, non-destructive repair flow built on doctor's
|
|
3
|
+
* structured repair candidates (pln#397 stp_b31fbe23 + stp_7ad66f68).
|
|
4
|
+
*
|
|
5
|
+
* Design:
|
|
6
|
+
* 1. Run the doctor JSON output and capture `repair_candidates[]`.
|
|
7
|
+
* 2. Split into `safe` and `unsafe`.
|
|
8
|
+
* 3. Execute safe candidates by default; unsafe stay deferred unless the
|
|
9
|
+
* caller passes `includeUnsafe`.
|
|
10
|
+
*
|
|
11
|
+
* Preservation guarantees (stp_7ad66f68):
|
|
12
|
+
* - NO action in this module deletes files. Lossy-looking actions
|
|
13
|
+
* (quarantine, archive) always rename into a clearly-labelled parking
|
|
14
|
+
* directory so operators can recover. Enforced by a source-level
|
|
15
|
+
* invariant test in tests/unit/repair-preservation.test.ts.
|
|
16
|
+
* - Before executing any unsafe candidate, a highlighted warning prints
|
|
17
|
+
* exactly what will be moved and where it will land — operators get
|
|
18
|
+
* full visibility before data relocates.
|
|
19
|
+
* - Memory entities (plans, decisions, constraints, traps, claims,
|
|
20
|
+
* handoffs) are never touched by any current action. Only inbox
|
|
21
|
+
* hygiene and filesystem-shape candidates are wired.
|
|
22
|
+
*
|
|
23
|
+
* Exposed via CLI (`brainclaw repair`) and MCP (`bclaw_repair`). Always
|
|
24
|
+
* returns a structured summary so agents can inspect what changed.
|
|
25
|
+
*/
|
|
26
|
+
import fs from 'node:fs';
|
|
27
|
+
import path from 'node:path';
|
|
28
|
+
import { memoryExists, memoryDir } from '../core/io.js';
|
|
29
|
+
import { runDoctor } from './doctor.js';
|
|
30
|
+
/**
|
|
31
|
+
* Execute a single repair candidate. Returns the outcome; never throws.
|
|
32
|
+
* Safe actions are pure creation / rename operations — see the switch cases.
|
|
33
|
+
*/
|
|
34
|
+
function executeCandidate(candidate, cwd) {
|
|
35
|
+
try {
|
|
36
|
+
switch (candidate.action) {
|
|
37
|
+
case 'mkdir': {
|
|
38
|
+
const target = path.resolve(cwd, candidate.target);
|
|
39
|
+
if (!fs.existsSync(target)) {
|
|
40
|
+
fs.mkdirSync(target, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
return { action: candidate.action, target: candidate.target, status: 'applied' };
|
|
43
|
+
}
|
|
44
|
+
case 'move_inbox_message': {
|
|
45
|
+
// Orphaned messages stored under the wrong agent directory. Read the
|
|
46
|
+
// message, resolve the correct destination from message.to, and
|
|
47
|
+
// rename. Source file already exists; target dir is auto-created.
|
|
48
|
+
const sourceAbs = path.resolve(cwd, candidate.target);
|
|
49
|
+
if (!fs.existsSync(sourceAbs)) {
|
|
50
|
+
return { action: candidate.action, target: candidate.target, status: 'skipped', reason: 'source file no longer exists' };
|
|
51
|
+
}
|
|
52
|
+
const parsed = JSON.parse(fs.readFileSync(sourceAbs, 'utf-8'));
|
|
53
|
+
const recipient = parsed.document?.to ?? parsed.to;
|
|
54
|
+
if (!recipient) {
|
|
55
|
+
return { action: candidate.action, target: candidate.target, status: 'skipped', reason: 'message has no recipient (to) field' };
|
|
56
|
+
}
|
|
57
|
+
const normalizedAgent = recipient.toLowerCase().replace(/[^a-z0-9_-]/g, '_');
|
|
58
|
+
const inboxRoot = path.join(memoryDir(cwd), 'coordination', 'inbox', normalizedAgent);
|
|
59
|
+
if (!fs.existsSync(inboxRoot)) {
|
|
60
|
+
fs.mkdirSync(inboxRoot, { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
const destAbs = path.join(inboxRoot, path.basename(sourceAbs));
|
|
63
|
+
if (fs.existsSync(destAbs) && path.resolve(destAbs) !== path.resolve(sourceAbs)) {
|
|
64
|
+
return { action: candidate.action, target: candidate.target, status: 'skipped', reason: `destination already exists: ${destAbs}` };
|
|
65
|
+
}
|
|
66
|
+
fs.renameSync(sourceAbs, destAbs);
|
|
67
|
+
return { action: candidate.action, target: candidate.target, status: 'applied' };
|
|
68
|
+
}
|
|
69
|
+
case 'quarantine_inbox_message': {
|
|
70
|
+
// Unsafe: move malformed message to a quarantine directory so a human
|
|
71
|
+
// can inspect it. Never deletes. Requires includeUnsafe.
|
|
72
|
+
const sourceAbs = path.resolve(cwd, candidate.target);
|
|
73
|
+
if (!fs.existsSync(sourceAbs)) {
|
|
74
|
+
return { action: candidate.action, target: candidate.target, status: 'skipped', reason: 'source file no longer exists' };
|
|
75
|
+
}
|
|
76
|
+
const quarantineDir = path.join(memoryDir(cwd), 'coordination', 'inbox', '.quarantine');
|
|
77
|
+
if (!fs.existsSync(quarantineDir)) {
|
|
78
|
+
fs.mkdirSync(quarantineDir, { recursive: true });
|
|
79
|
+
}
|
|
80
|
+
const destAbs = path.join(quarantineDir, `${Date.now()}-${path.basename(sourceAbs)}`);
|
|
81
|
+
fs.renameSync(sourceAbs, destAbs);
|
|
82
|
+
return { action: candidate.action, target: candidate.target, status: 'applied' };
|
|
83
|
+
}
|
|
84
|
+
default:
|
|
85
|
+
return {
|
|
86
|
+
action: candidate.action,
|
|
87
|
+
target: candidate.target,
|
|
88
|
+
status: 'skipped',
|
|
89
|
+
reason: `unknown action: ${candidate.action}`,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
return {
|
|
95
|
+
action: candidate.action,
|
|
96
|
+
target: candidate.target,
|
|
97
|
+
status: 'failed',
|
|
98
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Collect repair candidates by running doctor with JSON output captured.
|
|
104
|
+
* We re-run doctor instead of accepting them via an argument so the caller
|
|
105
|
+
* always sees the current state of the store.
|
|
106
|
+
*/
|
|
107
|
+
function collectCandidates(cwd) {
|
|
108
|
+
const originalLog = console.log;
|
|
109
|
+
let captured = '';
|
|
110
|
+
console.log = (...args) => { captured += args.map(String).join(' '); };
|
|
111
|
+
try {
|
|
112
|
+
runDoctor({ cwd, json: true });
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
console.log = originalLog;
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
const parsed = JSON.parse(captured);
|
|
119
|
+
return Array.isArray(parsed.repair_candidates) ? parsed.repair_candidates : [];
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
export function runRepair(options = {}) {
|
|
126
|
+
const cwd = options.cwd ?? process.cwd();
|
|
127
|
+
if (!memoryExists(cwd)) {
|
|
128
|
+
console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
const candidates = collectCandidates(cwd);
|
|
132
|
+
const safe = candidates.filter((c) => c.safe);
|
|
133
|
+
const unsafe = candidates.filter((c) => !c.safe);
|
|
134
|
+
const applied = [];
|
|
135
|
+
const skipped = [];
|
|
136
|
+
const failed = [];
|
|
137
|
+
const toRun = [...safe, ...(options.includeUnsafe ? unsafe : [])];
|
|
138
|
+
const deferred = options.includeUnsafe ? [] : unsafe;
|
|
139
|
+
// pln#397 stp_7ad66f68: explicit warning banner whenever we're about to
|
|
140
|
+
// touch existing files. Operators see exactly what moves and where
|
|
141
|
+
// before any rename executes. No JSON noise.
|
|
142
|
+
if (!options.json && !options.dryRun && options.includeUnsafe && unsafe.length > 0) {
|
|
143
|
+
console.warn('');
|
|
144
|
+
console.warn('⚠ Preservation notice — the following unsafe actions will RELOCATE files (never delete):');
|
|
145
|
+
for (const candidate of unsafe) {
|
|
146
|
+
console.warn(` • ${candidate.action} → ${candidate.target}`);
|
|
147
|
+
console.warn(` ${candidate.description}`);
|
|
148
|
+
}
|
|
149
|
+
console.warn('Files are moved to labelled parking directories (e.g. inbox/.quarantine/) so you can recover them manually.');
|
|
150
|
+
console.warn('');
|
|
151
|
+
}
|
|
152
|
+
for (const candidate of toRun) {
|
|
153
|
+
if (options.dryRun) {
|
|
154
|
+
skipped.push({
|
|
155
|
+
action: candidate.action,
|
|
156
|
+
target: candidate.target,
|
|
157
|
+
status: 'skipped',
|
|
158
|
+
reason: 'dry-run',
|
|
159
|
+
});
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
const outcome = executeCandidate(candidate, cwd);
|
|
163
|
+
if (outcome.status === 'applied')
|
|
164
|
+
applied.push(outcome);
|
|
165
|
+
else if (outcome.status === 'failed')
|
|
166
|
+
failed.push(outcome);
|
|
167
|
+
else
|
|
168
|
+
skipped.push(outcome);
|
|
169
|
+
}
|
|
170
|
+
for (const candidate of deferred) {
|
|
171
|
+
skipped.push({
|
|
172
|
+
action: candidate.action,
|
|
173
|
+
target: candidate.target,
|
|
174
|
+
status: 'skipped',
|
|
175
|
+
reason: 'unsafe — pass --include-unsafe to execute (preserves data, but requires confirmation)',
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
const result = {
|
|
179
|
+
ok: failed.length === 0,
|
|
180
|
+
dry_run: Boolean(options.dryRun),
|
|
181
|
+
candidates_total: candidates.length,
|
|
182
|
+
candidates_safe: safe.length,
|
|
183
|
+
candidates_unsafe: unsafe.length,
|
|
184
|
+
applied,
|
|
185
|
+
skipped,
|
|
186
|
+
failed,
|
|
187
|
+
};
|
|
188
|
+
if (options.json) {
|
|
189
|
+
console.log(JSON.stringify(result, null, 2));
|
|
190
|
+
return result;
|
|
191
|
+
}
|
|
192
|
+
if (candidates.length === 0) {
|
|
193
|
+
console.log('Nothing to repair — doctor surfaced no candidates.');
|
|
194
|
+
return result;
|
|
195
|
+
}
|
|
196
|
+
if (options.dryRun) {
|
|
197
|
+
console.log(`Dry-run: ${candidates.length} candidate(s) (${safe.length} safe, ${unsafe.length} unsafe)`);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
console.log(`Repair complete: ${applied.length} applied, ${skipped.length} skipped, ${failed.length} failed`);
|
|
201
|
+
}
|
|
202
|
+
for (const o of applied)
|
|
203
|
+
console.log(` ✔ ${o.action} → ${o.target}`);
|
|
204
|
+
for (const o of skipped)
|
|
205
|
+
console.log(` ○ ${o.action} → ${o.target}${o.reason ? ` (${o.reason})` : ''}`);
|
|
206
|
+
for (const o of failed)
|
|
207
|
+
console.log(` ✗ ${o.action} → ${o.target}${o.reason ? ` (${o.reason})` : ''}`);
|
|
208
|
+
return result;
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=repair.js.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command: brainclaw run <profile-name>
|
|
3
|
+
*
|
|
4
|
+
* Loads an agent profile, resolves the invoke template, and spawns the agent.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { execSync } from 'node:child_process';
|
|
9
|
+
import { loadProfile, listProfiles } from '../core/agent-profiles.js';
|
|
10
|
+
import { getDefaultInvokeTemplate } from '../core/agent-capability.js';
|
|
11
|
+
import { requireInitialized } from '../core/guards.js';
|
|
12
|
+
export function runRunProfile(profileName, options = {}) {
|
|
13
|
+
const cwd = options.cwd ?? process.cwd();
|
|
14
|
+
requireInitialized(cwd);
|
|
15
|
+
// List mode: no profile name
|
|
16
|
+
if (!profileName) {
|
|
17
|
+
const profiles = listProfiles(cwd);
|
|
18
|
+
if (profiles.length === 0) {
|
|
19
|
+
console.log('No agent profiles found. Add .yaml files to .brainclaw/agents/profiles/');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
console.log('Available profiles:');
|
|
23
|
+
for (const p of profiles) {
|
|
24
|
+
console.log(` ${p.name} — ${p.description} [${p.trigger}]`);
|
|
25
|
+
}
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const profile = loadProfile(profileName, cwd);
|
|
29
|
+
// Resolve invoke template: --agent override replaces the profile's invoke
|
|
30
|
+
let invoke = profile.invoke;
|
|
31
|
+
if (options.agent) {
|
|
32
|
+
const template = getDefaultInvokeTemplate(options.agent);
|
|
33
|
+
if (template) {
|
|
34
|
+
invoke = template.command;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
console.error(`Unknown agent: ${options.agent}. Using profile invoke template.`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Replace {prompt} placeholder with the profile prompt
|
|
41
|
+
const command = invoke.replace(/\{prompt\}/g, profile.prompt.replace(/"/g, '\\"'));
|
|
42
|
+
if (options.dry) {
|
|
43
|
+
console.log(`[dry-run] Profile: ${profile.name}`);
|
|
44
|
+
console.log(`[dry-run] Command: ${command}`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
console.log(`Running profile: ${profile.name}`);
|
|
48
|
+
console.log(`Command: ${command}`);
|
|
49
|
+
try {
|
|
50
|
+
execSync(command, { cwd, stdio: 'inherit' });
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
const code = err.status ?? 1;
|
|
54
|
+
process.exit(code);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=run-profile.js.map
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { resolveCurrentAgentName } from '../core/agent-registry.js';
|
|
2
|
+
import { requireInitialized } from '../core/guards.js';
|
|
3
|
+
import { validateCliInput } from '../core/input-validation.js';
|
|
4
|
+
import { createSequence, listSequences, loadSequence, updateSequence } from '../core/sequence.js';
|
|
5
|
+
const KNOWN_SUBCOMMANDS = new Set(['create', 'list', 'ls', 'show', 'update']);
|
|
6
|
+
function parseItems(raw) {
|
|
7
|
+
if (!raw)
|
|
8
|
+
return undefined;
|
|
9
|
+
let parsed;
|
|
10
|
+
try {
|
|
11
|
+
parsed = JSON.parse(raw);
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
throw new Error(`Invalid --items JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
15
|
+
}
|
|
16
|
+
if (!Array.isArray(parsed)) {
|
|
17
|
+
throw new Error('Invalid --items JSON: expected an array');
|
|
18
|
+
}
|
|
19
|
+
return parsed;
|
|
20
|
+
}
|
|
21
|
+
export function runSequenceResource(subcommand, args, options = {}) {
|
|
22
|
+
const cwd = options.cwd ?? process.cwd();
|
|
23
|
+
requireInitialized(cwd);
|
|
24
|
+
const normalized = subcommand.trim().toLowerCase();
|
|
25
|
+
if (!KNOWN_SUBCOMMANDS.has(normalized)) {
|
|
26
|
+
console.error(`Error: unknown sequence subcommand "${subcommand}".`);
|
|
27
|
+
console.error(' Available: create, list, show, update');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
if (normalized === 'create') {
|
|
31
|
+
const name = args.join(' ').trim();
|
|
32
|
+
if (!name) {
|
|
33
|
+
console.error('Error: sequence create requires <name>');
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
validateCliInput(name, options.tag);
|
|
37
|
+
const items = parseItems(options.items);
|
|
38
|
+
const result = createSequence({
|
|
39
|
+
name,
|
|
40
|
+
description: options.description,
|
|
41
|
+
status: options.status,
|
|
42
|
+
owner: options.owner,
|
|
43
|
+
items,
|
|
44
|
+
author: options.author ?? resolveCurrentAgentName(cwd),
|
|
45
|
+
tags: options.tag,
|
|
46
|
+
}, cwd);
|
|
47
|
+
console.log(`✔ Sequence added: [${result.id}] ${name}`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (normalized === 'list' || normalized === 'ls') {
|
|
51
|
+
const sequences = listSequences(cwd).filter((sequence) => !options.status || sequence.status === options.status);
|
|
52
|
+
if (options.json) {
|
|
53
|
+
console.log(JSON.stringify(sequences, null, 2));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (sequences.length === 0) {
|
|
57
|
+
console.log('No sequences found.');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
console.log(`${sequences.length} sequence(s):`);
|
|
61
|
+
for (const sequence of sequences) {
|
|
62
|
+
console.log(`[${sequence.id}] ${sequence.name} (${sequence.status}, items=${sequence.items.length})`);
|
|
63
|
+
}
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (normalized === 'show') {
|
|
67
|
+
const id = args[0];
|
|
68
|
+
if (!id) {
|
|
69
|
+
console.error('Error: sequence show requires <id>.');
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
const sequence = loadSequence(id, cwd);
|
|
73
|
+
if (options.json) {
|
|
74
|
+
console.log(JSON.stringify(sequence, null, 2));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
console.log(`Sequence: ${sequence.id}`);
|
|
78
|
+
console.log(` Name: ${sequence.name}`);
|
|
79
|
+
console.log(` Status: ${sequence.status}`);
|
|
80
|
+
if (sequence.owner)
|
|
81
|
+
console.log(` Owner: ${sequence.owner}`);
|
|
82
|
+
if (sequence.description)
|
|
83
|
+
console.log(` Description: ${sequence.description}`);
|
|
84
|
+
console.log(` Updated: ${sequence.updated_at}`);
|
|
85
|
+
if (sequence.items.length > 0) {
|
|
86
|
+
console.log(' Items:');
|
|
87
|
+
for (const item of sequence.items) {
|
|
88
|
+
const lane = item.lane ? ` lane=${item.lane}` : '';
|
|
89
|
+
const hardAfter = item.hard_after.length ? ` hard_after=${item.hard_after.join(',')}` : '';
|
|
90
|
+
const softAfter = item.soft_after.length ? ` soft_after=${item.soft_after.join(',')}` : '';
|
|
91
|
+
console.log(` #${item.rank} ${item.planId}${lane}${hardAfter}${softAfter}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const id = args[0];
|
|
97
|
+
if (!id) {
|
|
98
|
+
console.error('Error: sequence update requires <id>.');
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
const items = options.items ? parseItems(options.items) : undefined;
|
|
102
|
+
const sequence = updateSequence({
|
|
103
|
+
id,
|
|
104
|
+
name: options.name,
|
|
105
|
+
description: options.description,
|
|
106
|
+
status: options.status,
|
|
107
|
+
owner: options.owner,
|
|
108
|
+
items,
|
|
109
|
+
tags: options.tag,
|
|
110
|
+
}, cwd);
|
|
111
|
+
console.log(`✔ Sequence updated: [${sequence.id}] ${sequence.name}`);
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=sequence.js.map
|