@jaimevalasek/aioson 1.17.3 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/README.md +85 -51
- package/docs/en/3-recipes/full-feature-with-sheldon.md +1 -1
- package/docs/en/5-reference/cli-reference.md +4 -4
- package/docs/en/5-reference/qa-browser.md +2 -2
- package/docs/en/README.md +1 -1
- package/docs/en/deyvin-subtask-scout/how-to-use.md +2 -2
- package/docs/en/deyvin-subtask-scout/sub-task-scout.md +3 -3
- package/docs/en/deyvin-subtask-scout/troubleshooting.md +1 -1
- package/docs/pt/3-receitas/publicar-no-aioson-com.md +17 -0
- package/docs/pt/5-referencia/comandos-cli.md +2 -2
- package/docs/pt/5-referencia/inteligencia-adaptativa.md +3 -3
- package/docs/pt/5-referencia/skills.md +1 -1
- package/docs/pt/5-referencia/web3.md +3 -3
- package/docs/pt/README.md +1 -1
- package/docs/pt/_arquivo/README.md +1 -1
- package/docs/pt/_arquivo/cenarios.md +31 -31
- package/docs/pt/_arquivo/design-hybrid-forge.md +5 -5
- package/docs/pt/_arquivo/guia-engineer.md +1 -1
- package/docs/pt/_arquivo/profiler-system.md +1 -1
- package/docs/pt/_arquivo/site-forge.md +16 -16
- package/docs/pt/_arquivo/squad-genome.md +2 -2
- package/docs/pt/agentes.md +37 -37
- package/docs/pt/deyvin-subtask-scout/como-usar.md +2 -2
- package/docs/pt/deyvin-subtask-scout/sub-task-scout.md +1 -1
- package/docs/pt/deyvin-subtask-scout/troubleshooting.md +1 -1
- package/docs/pt/living-memory/README.md +1 -1
- package/docs/pt/living-memory/memoria-viva.md +2 -2
- package/docs/pt/living-memory/reflexao-in-harness.md +1 -1
- package/docs/pt/living-memory/troubleshooting.md +6 -6
- package/package.json +1 -1
- package/src/cli.js +111 -7
- package/src/commands/gate-approve.js +56 -1
- package/src/commands/live.js +81 -54
- package/src/commands/op-capture.js +27 -2
- package/src/commands/op-list.js +33 -1
- package/src/commands/store-system.js +4 -0
- package/src/commands/tool-capabilities.js +14 -10
- package/src/commands/workflow-heal.js +47 -1
- package/src/constants.js +73 -0
- package/src/i18n/messages/en.js +20 -2
- package/src/i18n/messages/es.js +18 -1
- package/src/i18n/messages/fr.js +18 -1
- package/src/i18n/messages/pt-BR.js +20 -2
- package/src/lib/dev-resume.js +6 -1
- package/src/lib/tool-capabilities.js +64 -37
- package/src/operator-memory/decision.js +11 -4
- package/src/operator-memory/proposal.js +11 -7
- package/src/session-handoff.js +52 -1
- package/template/.aioson/agents/analyst.md +33 -1
- package/template/.aioson/agents/architect.md +33 -1
- package/template/.aioson/agents/briefing.md +23 -0
- package/template/.aioson/agents/orchestrator.md +26 -0
- package/template/.aioson/agents/pentester.md +66 -14
- package/template/.aioson/agents/pm.md +18 -1
- package/template/.aioson/agents/product.md +11 -0
- package/template/.aioson/agents/sheldon.md +21 -1
- package/template/.aioson/agents/tester.md +114 -1
- package/template/.aioson/docs/pentester/browser-dast-playbook.md +398 -0
- package/template/.aioson/rules/agent-structural-contract.md +139 -0
- package/template/.aioson/skills/process/decision-presentation/SKILL.md +2 -2
- package/template/.claude/commands/aioson/agent/analyst.md +16 -5
- package/template/.claude/commands/aioson/agent/architect.md +17 -5
- package/template/.claude/commands/aioson/agent/briefing.md +16 -5
- package/template/.claude/commands/aioson/agent/committer.md +16 -5
- package/template/.claude/commands/aioson/agent/copywriter.md +16 -5
- package/template/.claude/commands/aioson/agent/design-hybrid-forge.md +16 -5
- package/template/.claude/commands/aioson/agent/dev.md +18 -5
- package/template/.claude/commands/aioson/agent/deyvin.md +16 -5
- package/template/.claude/commands/aioson/agent/discover.md +16 -5
- package/template/.claude/commands/aioson/agent/discovery-design-doc.md +16 -5
- package/template/.claude/commands/aioson/agent/genome.md +16 -5
- package/template/.claude/commands/aioson/agent/neo.md +16 -5
- package/template/.claude/commands/aioson/agent/orache.md +16 -5
- package/template/.claude/commands/aioson/agent/orchestrator.md +21 -5
- package/template/.claude/commands/aioson/agent/pair.md +16 -5
- package/template/.claude/commands/aioson/agent/pentester.md +22 -5
- package/template/.claude/commands/aioson/agent/pm.md +20 -5
- package/template/.claude/commands/aioson/agent/product.md +16 -5
- package/template/.claude/commands/aioson/agent/profiler-enricher.md +16 -5
- package/template/.claude/commands/aioson/agent/profiler-forge.md +16 -5
- package/template/.claude/commands/aioson/agent/profiler-researcher.md +16 -5
- package/template/.claude/commands/aioson/agent/qa.md +16 -5
- package/template/.claude/commands/aioson/agent/setup.md +16 -5
- package/template/.claude/commands/aioson/agent/sheldon.md +16 -5
- package/template/.claude/commands/aioson/agent/site-forge.md +16 -5
- package/template/.claude/commands/aioson/agent/squad.md +16 -5
- package/template/.claude/commands/aioson/agent/tester.md +16 -5
- package/template/.claude/commands/aioson/agent/ux-ui.md +19 -5
- package/template/.claude/commands/aioson/agent/validator.md +17 -5
package/src/commands/live.js
CHANGED
|
@@ -19,7 +19,7 @@ const {
|
|
|
19
19
|
const { ensureDir, exists } = require('../utils');
|
|
20
20
|
const { SUPPORTED_PROMPT_TOOLS } = require('../prompt-tool');
|
|
21
21
|
const { isTmuxAvailable, launchTmuxSession, buildSessionName, hasSession, attachSession } = require('../lib/tmux-launcher');
|
|
22
|
-
const { resolveResumeArgs } = require('../lib/tool-capabilities');
|
|
22
|
+
const { resolvePermissionModeArgs, resolveResumeArgs } = require('../lib/tool-capabilities');
|
|
23
23
|
|
|
24
24
|
const LIVE_EVENTS_LIMIT = 10;
|
|
25
25
|
const LIVE_MESSAGE_LIMIT = 500;
|
|
@@ -116,14 +116,16 @@ function parseJsonOption(value) {
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
// Combine `--resume` (mapped per-tool via TOOL_CAPS) with user-provided `--tool-args`.
|
|
120
|
-
// Resume args go FIRST so that codex `resume --last` (subcommand) lands at argv[1].
|
|
121
|
-
function buildLaunchArgs(options, tool) {
|
|
122
|
-
const resumeOpt = options.resume !== undefined ? options.resume : options.Resume;
|
|
123
|
-
const resumeArgs = resolveResumeArgs(tool, resumeOpt);
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
119
|
+
// Combine `--resume` (mapped per-tool via TOOL_CAPS) with user-provided `--tool-args`.
|
|
120
|
+
// Resume args go FIRST so that codex `resume --last` (subcommand) lands at argv[1].
|
|
121
|
+
function buildLaunchArgs(options, tool) {
|
|
122
|
+
const resumeOpt = options.resume !== undefined ? options.resume : options.Resume;
|
|
123
|
+
const resumeArgs = resolveResumeArgs(tool, resumeOpt);
|
|
124
|
+
const permissionMode = options['permission-mode'] || options.permissionMode;
|
|
125
|
+
const permissionArgs = resolvePermissionModeArgs(tool, permissionMode);
|
|
126
|
+
const userArgs = parseToolArgs(options['tool-args'] || options.toolArgs);
|
|
127
|
+
return [...resumeArgs, ...permissionArgs, ...userArgs];
|
|
128
|
+
}
|
|
127
129
|
|
|
128
130
|
function parseToolArgs(value) {
|
|
129
131
|
if (value === undefined || value === null || value === '') return [];
|
|
@@ -234,7 +236,7 @@ async function resolveExecutablePath(command) {
|
|
|
234
236
|
.filter(Boolean);
|
|
235
237
|
|
|
236
238
|
const extensions = process.platform === 'win32'
|
|
237
|
-
? Array.from(new Set([
|
|
239
|
+
? Array.from(new Set([...String(process.env.PATHEXT || '.EXE;.CMD;.BAT;.COM').split(';').map((entry) => entry.toLowerCase())]))
|
|
238
240
|
: [''];
|
|
239
241
|
|
|
240
242
|
for (const dir of pathEntries) {
|
|
@@ -1235,57 +1237,80 @@ async function runLiveStart({ args, options = {}, logger, t }) {
|
|
|
1235
1237
|
};
|
|
1236
1238
|
}
|
|
1237
1239
|
} else {
|
|
1238
|
-
// Non-tmux reuse logic
|
|
1240
|
+
// Non-tmux reuse logic
|
|
1239
1241
|
const existingTool = state.tool_session || null;
|
|
1240
1242
|
if (existingTool && existingTool !== tool) {
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
attachChild = spawn(binaryPath, buildLaunchArgs(options, tool), {
|
|
1250
|
-
cwd: targetDir,
|
|
1251
|
-
env: process.env,
|
|
1252
|
-
stdio: 'inherit'
|
|
1243
|
+
// Auto-close stale session when tool changed (same pattern as tmux recovery above)
|
|
1244
|
+
updateRun(db, {
|
|
1245
|
+
runKey: existing.run.run_key,
|
|
1246
|
+
status: 'completed',
|
|
1247
|
+
summary: `Auto-closed: tool changed from ${existingTool} to ${tool}`,
|
|
1248
|
+
eventType: 'session_closed',
|
|
1249
|
+
phase: 'live',
|
|
1250
|
+
message: `Tool mismatch — auto-closed previous ${existingTool} session`
|
|
1253
1251
|
});
|
|
1254
|
-
state.child_pid = attachChild.pid || null;
|
|
1255
1252
|
if (existing.task?.task_key) {
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1253
|
+
updateTask(db, {
|
|
1254
|
+
taskKey: existing.task.task_key,
|
|
1255
|
+
status: 'completed',
|
|
1256
|
+
goal: `Auto-closed after tool change to ${tool}`
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
await clearAgentSession(runtimeDir, agentName);
|
|
1260
|
+
if (!options.json) {
|
|
1261
|
+
logger.log(t('live.tool_mismatch_auto_closed', { existing: existingTool, requested: tool }) ||
|
|
1262
|
+
`Previous session (${existingTool}) auto-closed — starting new with ${tool}`);
|
|
1263
|
+
}
|
|
1264
|
+
// Fall through to create a new session below
|
|
1265
|
+
} else {
|
|
1266
|
+
// Tools match (or no previous tool) — reuse existing session
|
|
1267
|
+
const attach = Boolean(options.attach);
|
|
1268
|
+
let attachChild = null;
|
|
1269
|
+
let attachResult = null;
|
|
1270
|
+
|
|
1271
|
+
if (attach && !noLaunch) {
|
|
1272
|
+
attachChild = spawn(binaryPath, buildLaunchArgs(options, tool), {
|
|
1273
|
+
cwd: targetDir,
|
|
1274
|
+
env: process.env,
|
|
1275
|
+
stdio: 'inherit',
|
|
1276
|
+
shell: process.platform === 'win32'
|
|
1277
|
+
});
|
|
1278
|
+
state.child_pid = attachChild.pid || null;
|
|
1279
|
+
if (existing.task?.task_key) {
|
|
1280
|
+
const taskMeta = parseTaskMeta(existing.task);
|
|
1281
|
+
taskMeta.child_pid = state.child_pid;
|
|
1282
|
+
updateTask(db, { taskKey: existing.task.task_key, metaJson: taskMeta });
|
|
1283
|
+
}
|
|
1259
1284
|
}
|
|
1260
|
-
}
|
|
1261
1285
|
|
|
1262
|
-
|
|
1286
|
+
await writeLiveState(runtimeDir, existing.sessionKey, state);
|
|
1263
1287
|
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1288
|
+
if (!options.json) {
|
|
1289
|
+
logger.log(t('live.session_already_active', { agent: agentName, session: existing.sessionKey, runKey: existing.run.run_key, dbPath }));
|
|
1290
|
+
}
|
|
1267
1291
|
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1292
|
+
if (attachChild) {
|
|
1293
|
+
attachResult = await waitForChild(attachChild);
|
|
1294
|
+
}
|
|
1271
1295
|
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1296
|
+
return {
|
|
1297
|
+
ok: true,
|
|
1298
|
+
targetDir,
|
|
1299
|
+
dbPath,
|
|
1300
|
+
agent: existing.agentName,
|
|
1301
|
+
tool: state.tool_session || tool,
|
|
1302
|
+
taskKey: existing.task?.task_key || existing.sessionRef?.taskKey || null,
|
|
1303
|
+
runKey: existing.run.run_key,
|
|
1304
|
+
sessionKey: existing.sessionKey,
|
|
1305
|
+
pid: state.child_pid || null,
|
|
1306
|
+
processState: detectProcessState(state.child_pid),
|
|
1307
|
+
reused: true,
|
|
1308
|
+
open: true,
|
|
1309
|
+
attached: attach,
|
|
1310
|
+
childExitCode: attachResult?.code ?? null,
|
|
1311
|
+
childSignal: attachResult?.signal ?? null
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1289
1314
|
}
|
|
1290
1315
|
}
|
|
1291
1316
|
|
|
@@ -1356,7 +1381,8 @@ async function runLiveStart({ args, options = {}, logger, t }) {
|
|
|
1356
1381
|
child = spawn(binaryPath, buildLaunchArgs(options, tool), {
|
|
1357
1382
|
cwd: targetDir,
|
|
1358
1383
|
env: process.env,
|
|
1359
|
-
stdio: 'inherit'
|
|
1384
|
+
stdio: 'inherit',
|
|
1385
|
+
shell: process.platform === 'win32'
|
|
1360
1386
|
});
|
|
1361
1387
|
taskMeta.child_pid = child.pid || null;
|
|
1362
1388
|
updateTask(db, {
|
|
@@ -1368,7 +1394,8 @@ async function runLiveStart({ args, options = {}, logger, t }) {
|
|
|
1368
1394
|
child = spawn(binaryPath, buildLaunchArgs(options, tool), {
|
|
1369
1395
|
cwd: targetDir,
|
|
1370
1396
|
env: process.env,
|
|
1371
|
-
stdio: 'inherit'
|
|
1397
|
+
stdio: 'inherit',
|
|
1398
|
+
shell: process.platform === 'win32'
|
|
1372
1399
|
});
|
|
1373
1400
|
taskMeta.child_pid = child.pid || null;
|
|
1374
1401
|
updateTask(db, {
|
|
@@ -27,6 +27,8 @@ const { captureSignal, readProposal, VALID_SIGNAL_TYPES } = require('../operator
|
|
|
27
27
|
const { promoteProposal } = require('../operator-memory/decision');
|
|
28
28
|
const { emitDossierEvent } = require('../lib/dossier-telemetry');
|
|
29
29
|
|
|
30
|
+
const CONFIRMATIONS_JSONL = '.aioson/runtime/session-confirmations.jsonl';
|
|
31
|
+
|
|
30
32
|
const PROMOTION_THRESHOLD = 2;
|
|
31
33
|
|
|
32
34
|
function existsCheckFactory(identity) {
|
|
@@ -55,6 +57,8 @@ First detection writes to proposals/{slug}.md. Second detection promotes to deci
|
|
|
55
57
|
const quote = options.quote;
|
|
56
58
|
const proposal = options.proposal;
|
|
57
59
|
const sourceAgent = options['source-agent'] || options.sourceAgent || 'unknown';
|
|
60
|
+
const featureSlug = options.feature ? String(options.feature) : null;
|
|
61
|
+
const sessionId = options['session-id'] || options.sessionId || null;
|
|
58
62
|
|
|
59
63
|
if (!signal || !proposal) {
|
|
60
64
|
const err = `op:capture — required: --signal=<type> --proposal=<paraphrase>. Got signal=${signal}, proposal=${proposal ? 'present' : 'missing'}.`;
|
|
@@ -95,7 +99,9 @@ First detection writes to proposals/{slug}.md. Second detection promotes to deci
|
|
|
95
99
|
signal_type: signal,
|
|
96
100
|
quote,
|
|
97
101
|
proposal,
|
|
98
|
-
source_agent: sourceAgent
|
|
102
|
+
source_agent: sourceAgent,
|
|
103
|
+
feature_slug: featureSlug,
|
|
104
|
+
session_id: sessionId
|
|
99
105
|
});
|
|
100
106
|
} catch (err) {
|
|
101
107
|
const errMsg = `op:capture failed: ${err.message}`;
|
|
@@ -104,6 +110,24 @@ First detection writes to proposals/{slug}.md. Second detection promotes to deci
|
|
|
104
110
|
return { ok: false, exitCode: 1, error: errMsg };
|
|
105
111
|
}
|
|
106
112
|
|
|
113
|
+
// M2: append confirmation signals to session accumulator for decision_rationale
|
|
114
|
+
if (signal === 'confirmation') {
|
|
115
|
+
try {
|
|
116
|
+
const accPath = path.join(targetDir, CONFIRMATIONS_JSONL);
|
|
117
|
+
const accDir = path.dirname(accPath);
|
|
118
|
+
fs.mkdirSync(accDir, { recursive: true });
|
|
119
|
+
const entry = JSON.stringify({
|
|
120
|
+
agent: sourceAgent,
|
|
121
|
+
decision: proposal,
|
|
122
|
+
quote: quote || null,
|
|
123
|
+
timestamp: new Date().toISOString()
|
|
124
|
+
});
|
|
125
|
+
fs.appendFileSync(accPath, entry + '\n', 'utf8');
|
|
126
|
+
} catch {
|
|
127
|
+
// best-effort — never block op:capture
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
107
131
|
const count = result.proposal.detected_count;
|
|
108
132
|
|
|
109
133
|
if (count >= PROMOTION_THRESHOLD) {
|
|
@@ -142,5 +166,6 @@ First detection writes to proposals/{slug}.md. Second detection promotes to deci
|
|
|
142
166
|
|
|
143
167
|
module.exports = {
|
|
144
168
|
runOpCapture,
|
|
145
|
-
PROMOTION_THRESHOLD
|
|
169
|
+
PROMOTION_THRESHOLD,
|
|
170
|
+
CONFIRMATIONS_JSONL
|
|
146
171
|
};
|
package/src/commands/op-list.js
CHANGED
|
@@ -21,13 +21,15 @@ const { readDecision } = require('../operator-memory/decision');
|
|
|
21
21
|
|
|
22
22
|
async function runOpList({ args = [], options = {}, logger }) {
|
|
23
23
|
if (options.help === true || args.includes('--help') || args.includes('-h')) {
|
|
24
|
-
if (logger) logger.log('op:list [--proposals] [--include-archived] [--format=table|json] — list active decisions.');
|
|
24
|
+
if (logger) logger.log('op:list [--proposals] [--include-archived] [--feature=<slug>] [--agent=<name>] [--format=table|json] — list active decisions.');
|
|
25
25
|
return { ok: true };
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const format = options.format || 'table';
|
|
29
29
|
const showProposals = Boolean(options.proposals);
|
|
30
30
|
const includeArchived = Boolean(options['include-archived']);
|
|
31
|
+
const filterFeature = options.feature ? String(options.feature) : null;
|
|
32
|
+
const filterAgent = options.agent ? String(options.agent) : null;
|
|
31
33
|
|
|
32
34
|
const resolved = resolveIdentity();
|
|
33
35
|
ensureStorageTree(resolved.identity);
|
|
@@ -65,9 +67,39 @@ async function runOpList({ args = [], options = {}, logger }) {
|
|
|
65
67
|
}
|
|
66
68
|
}
|
|
67
69
|
|
|
70
|
+
// M3: apply --feature and --agent filters (BR-AO-07: AND-composable)
|
|
71
|
+
if (filterFeature) {
|
|
72
|
+
items = items.filter((item) => item.feature_slug === filterFeature);
|
|
73
|
+
}
|
|
74
|
+
if (filterAgent) {
|
|
75
|
+
items = items.filter((item) => item.source_agent === filterAgent);
|
|
76
|
+
}
|
|
77
|
+
|
|
68
78
|
if (format === 'json' || options.json) {
|
|
79
|
+
// BR-AO-09: structured JSON output when --feature is used
|
|
80
|
+
if (filterFeature) {
|
|
81
|
+
const decisions = items.map((item) => ({
|
|
82
|
+
agent: item.source_agent || 'unknown',
|
|
83
|
+
signal: item.signal_type || null,
|
|
84
|
+
quote: Array.isArray(item.quotes) ? (item.quotes[item.quotes.length - 1] || null) : null,
|
|
85
|
+
proposal: item.proposal || item.body || item.title || null,
|
|
86
|
+
timestamp: item.last_reinforced || item.last_detected || null,
|
|
87
|
+
session_id: item.session_id || null
|
|
88
|
+
}));
|
|
89
|
+
const result = {
|
|
90
|
+
ok: true,
|
|
91
|
+
feature: filterFeature,
|
|
92
|
+
decisions,
|
|
93
|
+
total: decisions.length
|
|
94
|
+
};
|
|
95
|
+
if (options.json) return result;
|
|
96
|
+
if (logger) logger.log(JSON.stringify(result, null, 2));
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
|
|
69
100
|
const result = {
|
|
70
101
|
ok: true,
|
|
102
|
+
feature: null,
|
|
71
103
|
identity: resolved.identity,
|
|
72
104
|
identity_source: resolved.source,
|
|
73
105
|
tier: showProposals ? 'proposals' : (includeArchived ? 'active+archive' : 'active'),
|
|
@@ -351,6 +351,10 @@ async function runSystemPublish({ args, options, logger, t }) {
|
|
|
351
351
|
|
|
352
352
|
logger.log('Creating ZIP package...');
|
|
353
353
|
const zipBuffer = await createZipBuffer(files);
|
|
354
|
+
const MAX_ZIP_BYTES = 2 * 1024 * 1024;
|
|
355
|
+
if (zipBuffer.length > MAX_ZIP_BYTES) {
|
|
356
|
+
throw new Error(`ZIP exceeds 2 MB limit (${(zipBuffer.length / 1024 / 1024).toFixed(2)} MB). Reduce the number of files or bundle size.`);
|
|
357
|
+
}
|
|
354
358
|
const zipBase64 = zipBuffer.toString('base64');
|
|
355
359
|
const zipKb = (zipBuffer.length / 1024).toFixed(1);
|
|
356
360
|
logger.log(`ZIP: ${zipKb} KB (${fileCount} files)`);
|
|
@@ -6,9 +6,9 @@ const { TOOL_CAPS, getToolCapabilities, listSupportedTools } = require('../lib/t
|
|
|
6
6
|
// so external clients (AIOSON Play, IDE extensions) can drive UI without
|
|
7
7
|
// hard-coding their own copy of this lookup.
|
|
8
8
|
//
|
|
9
|
-
// Usage:
|
|
10
|
-
// aioson tool:capabilities --json
|
|
11
|
-
// aioson tool:capabilities --tool=claude --json
|
|
9
|
+
// Usage:
|
|
10
|
+
// aioson tool:capabilities --json
|
|
11
|
+
// aioson tool:capabilities --tool=claude --json
|
|
12
12
|
async function runToolCapabilities({ args: _args, options = {}, logger, t: _t }) {
|
|
13
13
|
const tool = options.tool ? String(options.tool).trim() : null;
|
|
14
14
|
|
|
@@ -22,8 +22,8 @@ async function runToolCapabilities({ args: _args, options = {}, logger, t: _t })
|
|
|
22
22
|
payload = { tool: tool.toLowerCase(), capabilities: caps };
|
|
23
23
|
} else {
|
|
24
24
|
payload = {
|
|
25
|
-
tools: TOOL_CAPS,
|
|
26
|
-
schema_version:
|
|
25
|
+
tools: TOOL_CAPS,
|
|
26
|
+
schema_version: 2,
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -37,8 +37,8 @@ async function runToolCapabilities({ args: _args, options = {}, logger, t: _t })
|
|
|
37
37
|
const caps = payload.capabilities;
|
|
38
38
|
logger.log(`Tool: ${payload.tool}`);
|
|
39
39
|
logger.log(` binary: ${caps.binary}`);
|
|
40
|
-
logger.log(` install_command: ${caps.install_command}`);
|
|
41
|
-
logger.log(` supports_resume: ${caps.supports_resume}`);
|
|
40
|
+
logger.log(` install_command: ${caps.install_command}`);
|
|
41
|
+
logger.log(` supports_resume: ${caps.supports_resume}`);
|
|
42
42
|
if (caps.supports_resume) {
|
|
43
43
|
logger.log(` resume_last: ${(caps.resume_last || []).join(' ')}`);
|
|
44
44
|
logger.log(` supports_session_id: ${caps.supports_session_id}`);
|
|
@@ -48,9 +48,13 @@ async function runToolCapabilities({ args: _args, options = {}, logger, t: _t })
|
|
|
48
48
|
logger.log(` supports_session_picker: ${caps.supports_session_picker}`);
|
|
49
49
|
if (caps.supports_session_picker) {
|
|
50
50
|
logger.log(` session_picker: ${(caps.session_picker || []).join(' ')}`);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
logger.log(` supports_yolo: ${caps.supports_yolo}`);
|
|
54
|
+
if (caps.supports_yolo) {
|
|
55
|
+
logger.log(` yolo_args: ${(caps.yolo_args || []).join(' ')}`);
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
54
58
|
logger.log(`Supported tools: ${listSupportedTools().join(', ')}`);
|
|
55
59
|
logger.log(`Run with --tool=<name> for details, or --json for the full map.`);
|
|
56
60
|
}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
const path = require('node:path');
|
|
15
|
+
const fs = require('node:fs/promises');
|
|
15
16
|
const {
|
|
16
17
|
loadOrCreateState,
|
|
17
18
|
activateStage,
|
|
@@ -26,6 +27,28 @@ const {
|
|
|
26
27
|
incrementRetryCount,
|
|
27
28
|
buildHealingActivation
|
|
28
29
|
} = require('../self-healing');
|
|
30
|
+
const { CHECKPOINTS_DIR } = require('./gate-approve');
|
|
31
|
+
|
|
32
|
+
const GATE_ORDER = ['D', 'C', 'B', 'A'];
|
|
33
|
+
|
|
34
|
+
async function readLatestCheckpoint(targetDir, slug) {
|
|
35
|
+
const dir = path.join(targetDir, CHECKPOINTS_DIR);
|
|
36
|
+
try {
|
|
37
|
+
const files = await fs.readdir(dir);
|
|
38
|
+
const matching = files
|
|
39
|
+
.filter((f) => f.endsWith(`-${slug}.json`))
|
|
40
|
+
.sort((a, b) => {
|
|
41
|
+
const gateA = a.replace('gate-', '').charAt(0);
|
|
42
|
+
const gateB = b.replace('gate-', '').charAt(0);
|
|
43
|
+
return GATE_ORDER.indexOf(gateA) - GATE_ORDER.indexOf(gateB);
|
|
44
|
+
});
|
|
45
|
+
if (matching.length === 0) return null;
|
|
46
|
+
const raw = await fs.readFile(path.join(dir, matching[0]), 'utf8');
|
|
47
|
+
return JSON.parse(raw);
|
|
48
|
+
} catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
29
52
|
|
|
30
53
|
async function runWorkflowHeal({ args, options, logger, t }) {
|
|
31
54
|
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
@@ -58,6 +81,10 @@ async function runWorkflowHeal({ args, options, logger, t }) {
|
|
|
58
81
|
return { ok: false, reason: 'stage_not_in_sequence' };
|
|
59
82
|
}
|
|
60
83
|
|
|
84
|
+
// M1 checkpoint-at-gate: read latest checkpoint for recovery context (EC-AO-02: graceful fallback)
|
|
85
|
+
const featureSlug = state.featureSlug || null;
|
|
86
|
+
const checkpoint = featureSlug ? await readLatestCheckpoint(targetDir, featureSlug) : null;
|
|
87
|
+
|
|
61
88
|
// Build healing activation
|
|
62
89
|
let activation;
|
|
63
90
|
try {
|
|
@@ -74,6 +101,24 @@ async function runWorkflowHeal({ args, options, logger, t }) {
|
|
|
74
101
|
return { ok: false, reason: 'activation_failed', error: err.message };
|
|
75
102
|
}
|
|
76
103
|
|
|
104
|
+
if (checkpoint) {
|
|
105
|
+
const sanitize = (s) => String(s || '').replace(/[\r\n]+/g, ' ').slice(0, 200);
|
|
106
|
+
const files = Array.isArray(checkpoint.prerequisites_snapshot)
|
|
107
|
+
? checkpoint.prerequisites_snapshot.map((s) => sanitize(s && s.file)).join(', ') || 'none'
|
|
108
|
+
: 'none';
|
|
109
|
+
const cpBlock = [
|
|
110
|
+
'',
|
|
111
|
+
'## Checkpoint Recovery Context (auto-injected by AIOSON motor)',
|
|
112
|
+
'',
|
|
113
|
+
`> Last approved gate: **${sanitize(checkpoint.gate)}** (${sanitize(checkpoint.timestamp)})`,
|
|
114
|
+
`> Approved by: ${sanitize(checkpoint.agent)}`,
|
|
115
|
+
`> Artifacts at gate time: ${files}`,
|
|
116
|
+
''
|
|
117
|
+
].join('\n');
|
|
118
|
+
activation.prompt = activation.prompt + cpBlock;
|
|
119
|
+
activation.checkpoint = checkpoint;
|
|
120
|
+
}
|
|
121
|
+
|
|
77
122
|
// Increment retry counter
|
|
78
123
|
const newCount = await incrementRetryCount(targetDir, stage, activation.prompt.substring(0, 200));
|
|
79
124
|
|
|
@@ -127,10 +172,11 @@ async function runWorkflowHeal({ args, options, logger, t }) {
|
|
|
127
172
|
retryCount: newCount,
|
|
128
173
|
maxRetries: 3,
|
|
129
174
|
runtime,
|
|
175
|
+
checkpoint: checkpoint || null,
|
|
130
176
|
agent: activation.agent,
|
|
131
177
|
instructionPath: activation.instructionPath,
|
|
132
178
|
prompt: activation.prompt
|
|
133
179
|
};
|
|
134
180
|
}
|
|
135
181
|
|
|
136
|
-
module.exports = { runWorkflowHeal };
|
|
182
|
+
module.exports = { runWorkflowHeal, readLatestCheckpoint };
|
package/src/constants.js
CHANGED
|
@@ -190,6 +190,7 @@ const AGENT_DEFINITIONS = [
|
|
|
190
190
|
{
|
|
191
191
|
id: 'setup',
|
|
192
192
|
displayName: 'Setup',
|
|
193
|
+
description: 'Project onboarding and context setup',
|
|
193
194
|
command: '@setup',
|
|
194
195
|
path: '.aioson/agents/setup.md',
|
|
195
196
|
dependsOn: [],
|
|
@@ -198,6 +199,7 @@ const AGENT_DEFINITIONS = [
|
|
|
198
199
|
{
|
|
199
200
|
id: 'discovery-design-doc',
|
|
200
201
|
displayName: 'Discovery/Design Doc',
|
|
202
|
+
description: 'Discovery and design doc generation',
|
|
201
203
|
command: '@discovery-design-doc',
|
|
202
204
|
path: '.aioson/agents/discovery-design-doc.md',
|
|
203
205
|
dependsOn: ['.aioson/context/project.context.md'],
|
|
@@ -206,6 +208,7 @@ const AGENT_DEFINITIONS = [
|
|
|
206
208
|
{
|
|
207
209
|
id: 'discover',
|
|
208
210
|
displayName: 'Discover',
|
|
211
|
+
description: 'Semantic knowledge discovery and bootstrap cache generation',
|
|
209
212
|
command: '@discover',
|
|
210
213
|
path: '.aioson/agents/discover.md',
|
|
211
214
|
dependsOn: ['.aioson/context/project.context.md'],
|
|
@@ -214,6 +217,7 @@ const AGENT_DEFINITIONS = [
|
|
|
214
217
|
{
|
|
215
218
|
id: 'product',
|
|
216
219
|
displayName: 'Product',
|
|
220
|
+
description: 'Product vision, PRD and feature scoping',
|
|
217
221
|
command: '@product',
|
|
218
222
|
path: '.aioson/agents/product.md',
|
|
219
223
|
dependsOn: ['.aioson/context/project.context.md'],
|
|
@@ -222,6 +226,7 @@ const AGENT_DEFINITIONS = [
|
|
|
222
226
|
{
|
|
223
227
|
id: 'deyvin',
|
|
224
228
|
displayName: 'Deyvin',
|
|
229
|
+
description: 'Pair programming partner for continuity sessions',
|
|
225
230
|
command: '@deyvin',
|
|
226
231
|
path: '.aioson/agents/deyvin.md',
|
|
227
232
|
aliases: ['pair'],
|
|
@@ -231,6 +236,7 @@ const AGENT_DEFINITIONS = [
|
|
|
231
236
|
{
|
|
232
237
|
id: 'analyst',
|
|
233
238
|
displayName: 'Analyst',
|
|
239
|
+
description: 'Domain discovery and entity mapping (SMALL/MEDIUM)',
|
|
234
240
|
command: '@analyst',
|
|
235
241
|
path: '.aioson/agents/analyst.md',
|
|
236
242
|
dependsOn: ['.aioson/context/project.context.md'],
|
|
@@ -239,6 +245,7 @@ const AGENT_DEFINITIONS = [
|
|
|
239
245
|
{
|
|
240
246
|
id: 'architect',
|
|
241
247
|
displayName: 'Architect',
|
|
248
|
+
description: 'Project structure and technical decisions (SMALL/MEDIUM)',
|
|
242
249
|
command: '@architect',
|
|
243
250
|
path: '.aioson/agents/architect.md',
|
|
244
251
|
dependsOn: [
|
|
@@ -250,6 +257,7 @@ const AGENT_DEFINITIONS = [
|
|
|
250
257
|
{
|
|
251
258
|
id: 'ux-ui',
|
|
252
259
|
displayName: 'UI/UX',
|
|
260
|
+
description: 'UI/UX design system and component spec (SMALL/MEDIUM)',
|
|
253
261
|
command: '@ux-ui',
|
|
254
262
|
path: '.aioson/agents/ux-ui.md',
|
|
255
263
|
dependsOn: [
|
|
@@ -263,6 +271,7 @@ const AGENT_DEFINITIONS = [
|
|
|
263
271
|
{
|
|
264
272
|
id: 'pm',
|
|
265
273
|
displayName: 'PM',
|
|
274
|
+
description: 'Backlog and user stories (MEDIUM only)',
|
|
266
275
|
command: '@pm',
|
|
267
276
|
path: '.aioson/agents/pm.md',
|
|
268
277
|
dependsOn: [
|
|
@@ -277,6 +286,7 @@ const AGENT_DEFINITIONS = [
|
|
|
277
286
|
{
|
|
278
287
|
id: 'dev',
|
|
279
288
|
displayName: 'Dev',
|
|
289
|
+
description: 'Feature implementation (any stack)',
|
|
280
290
|
command: '@dev',
|
|
281
291
|
path: '.aioson/agents/dev.md',
|
|
282
292
|
dependsOn: [
|
|
@@ -289,8 +299,14 @@ const AGENT_DEFINITIONS = [
|
|
|
289
299
|
{
|
|
290
300
|
id: 'pentester',
|
|
291
301
|
displayName: 'Pentester',
|
|
302
|
+
description: 'Adversarial security review and threat-surface mapping',
|
|
292
303
|
command: '@pentester',
|
|
293
304
|
path: '.aioson/agents/pentester.md',
|
|
305
|
+
flags: [
|
|
306
|
+
{ name: 'mode', value: 'framework_target|app_target', description: 'Target mode for security review' },
|
|
307
|
+
{ name: 'feature', value: '<slug>', description: 'Feature slug (required for app_target)' },
|
|
308
|
+
{ name: 'scope', value: '<scope>', description: 'Target scope (required for app_target)' }
|
|
309
|
+
],
|
|
294
310
|
dependsOn: [
|
|
295
311
|
'.aioson/context/project.context.md',
|
|
296
312
|
'.aioson/context/spec-{slug}.md (active feature)'
|
|
@@ -300,6 +316,7 @@ const AGENT_DEFINITIONS = [
|
|
|
300
316
|
{
|
|
301
317
|
id: 'qa',
|
|
302
318
|
displayName: 'QA',
|
|
319
|
+
description: 'Risk-first review and test generation (SMALL/MEDIUM)',
|
|
303
320
|
command: '@qa',
|
|
304
321
|
path: '.aioson/agents/qa.md',
|
|
305
322
|
dependsOn: ['.aioson/context/discovery.md'],
|
|
@@ -308,6 +325,7 @@ const AGENT_DEFINITIONS = [
|
|
|
308
325
|
{
|
|
309
326
|
id: 'validator',
|
|
310
327
|
displayName: 'Validator',
|
|
328
|
+
description: 'Technical validation against success contract',
|
|
311
329
|
command: '@validator',
|
|
312
330
|
path: '.aioson/agents/validator.md',
|
|
313
331
|
dependsOn: [
|
|
@@ -319,6 +337,7 @@ const AGENT_DEFINITIONS = [
|
|
|
319
337
|
{
|
|
320
338
|
id: 'tester',
|
|
321
339
|
displayName: 'Tester',
|
|
340
|
+
description: 'Systematic test engineering for implemented apps (all sizes)',
|
|
322
341
|
command: '@tester',
|
|
323
342
|
path: '.aioson/agents/tester.md',
|
|
324
343
|
dependsOn: ['.aioson/context/project.context.md'],
|
|
@@ -327,6 +346,7 @@ const AGENT_DEFINITIONS = [
|
|
|
327
346
|
{
|
|
328
347
|
id: 'orchestrator',
|
|
329
348
|
displayName: 'Orchestrator',
|
|
349
|
+
description: 'Session protocol and parallel execution (MEDIUM)',
|
|
330
350
|
command: '@orchestrator',
|
|
331
351
|
path: '.aioson/agents/orchestrator.md',
|
|
332
352
|
dependsOn: [
|
|
@@ -342,6 +362,7 @@ const AGENT_DEFINITIONS = [
|
|
|
342
362
|
{
|
|
343
363
|
id: 'squad',
|
|
344
364
|
displayName: 'Squad',
|
|
365
|
+
description: 'Squad assembly and management',
|
|
345
366
|
command: '@squad',
|
|
346
367
|
path: '.aioson/agents/squad.md',
|
|
347
368
|
dependsOn: [],
|
|
@@ -351,6 +372,7 @@ const AGENT_DEFINITIONS = [
|
|
|
351
372
|
{
|
|
352
373
|
id: 'orache',
|
|
353
374
|
displayName: 'Orache',
|
|
375
|
+
description: 'Domain investigation and strategic research',
|
|
354
376
|
command: '@orache',
|
|
355
377
|
path: '.aioson/agents/orache.md',
|
|
356
378
|
dependsOn: [],
|
|
@@ -359,6 +381,7 @@ const AGENT_DEFINITIONS = [
|
|
|
359
381
|
{
|
|
360
382
|
id: 'genome',
|
|
361
383
|
displayName: 'Genome',
|
|
384
|
+
description: 'Domain genome creation and application',
|
|
362
385
|
command: '@genome',
|
|
363
386
|
path: '.aioson/agents/genome.md',
|
|
364
387
|
dependsOn: [],
|
|
@@ -367,6 +390,7 @@ const AGENT_DEFINITIONS = [
|
|
|
367
390
|
{
|
|
368
391
|
id: 'design-hybrid-forge',
|
|
369
392
|
displayName: 'Design Hybrid Forge',
|
|
393
|
+
description: 'Generate hybrid design skill from two visual parents',
|
|
370
394
|
command: '@design-hybrid-forge',
|
|
371
395
|
path: '.aioson/agents/design-hybrid-forge.md',
|
|
372
396
|
dependsOn: ['.aioson/context/project.context.md'],
|
|
@@ -375,14 +399,61 @@ const AGENT_DEFINITIONS = [
|
|
|
375
399
|
{
|
|
376
400
|
id: 'site-forge',
|
|
377
401
|
displayName: 'Site Forge',
|
|
402
|
+
description: 'Clone, extract, and forge sites and design skills from any URL',
|
|
378
403
|
command: '@site-forge',
|
|
379
404
|
path: '.aioson/agents/site-forge.md',
|
|
380
405
|
dependsOn: ['.aioson/context/project.context.md'],
|
|
381
406
|
output: 'src/components/*.tsx + src/app/page.tsx + docs/research/{hostname}/ + public/images/{hostname}/'
|
|
382
407
|
},
|
|
408
|
+
{
|
|
409
|
+
id: 'neo',
|
|
410
|
+
displayName: 'Neo',
|
|
411
|
+
description: 'System router: see the full picture, get guided to the right agent',
|
|
412
|
+
command: '@neo',
|
|
413
|
+
path: '.aioson/agents/neo.md',
|
|
414
|
+
dependsOn: ['.aioson/context/project.context.md'],
|
|
415
|
+
output: 'routing decision + agent handoff'
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
id: 'sheldon',
|
|
419
|
+
displayName: 'Sheldon',
|
|
420
|
+
description: 'Deep technical analysis and architecture review',
|
|
421
|
+
command: '@sheldon',
|
|
422
|
+
path: '.aioson/agents/sheldon.md',
|
|
423
|
+
dependsOn: ['.aioson/context/project.context.md'],
|
|
424
|
+
output: 'enriched PRD or architecture review'
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
id: 'committer',
|
|
428
|
+
displayName: 'Committer',
|
|
429
|
+
description: 'Professional Git commit generation from changes and context',
|
|
430
|
+
command: '@committer',
|
|
431
|
+
path: '.aioson/agents/committer.md',
|
|
432
|
+
dependsOn: [],
|
|
433
|
+
output: 'git commit(s)'
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
id: 'copywriter',
|
|
437
|
+
displayName: 'Copywriter',
|
|
438
|
+
description: 'Conversion-focused marketing copy',
|
|
439
|
+
command: '@copywriter',
|
|
440
|
+
path: '.aioson/agents/copywriter.md',
|
|
441
|
+
dependsOn: [],
|
|
442
|
+
output: 'marketing copy + content assets'
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
id: 'briefing',
|
|
446
|
+
displayName: 'Briefing',
|
|
447
|
+
description: 'Pre-production briefings and planning',
|
|
448
|
+
command: '@briefing',
|
|
449
|
+
path: '.aioson/agents/briefing.md',
|
|
450
|
+
dependsOn: ['.aioson/context/project.context.md'],
|
|
451
|
+
output: '.aioson/briefings/{slug}/'
|
|
452
|
+
},
|
|
383
453
|
{
|
|
384
454
|
id: 'profiler-researcher',
|
|
385
455
|
displayName: 'Profiler Researcher',
|
|
456
|
+
description: 'Clone profiler: research phase',
|
|
386
457
|
command: '@profiler-researcher',
|
|
387
458
|
path: '.aioson/agents/profiler-researcher.md',
|
|
388
459
|
dependsOn: [],
|
|
@@ -391,6 +462,7 @@ const AGENT_DEFINITIONS = [
|
|
|
391
462
|
{
|
|
392
463
|
id: 'profiler-enricher',
|
|
393
464
|
displayName: 'Profiler Enricher',
|
|
465
|
+
description: 'Clone profiler: enrichment phase',
|
|
394
466
|
command: '@profiler-enricher',
|
|
395
467
|
path: '.aioson/agents/profiler-enricher.md',
|
|
396
468
|
dependsOn: ['.aioson/profiler-reports/{person-slug}/research-report.md'],
|
|
@@ -399,6 +471,7 @@ const AGENT_DEFINITIONS = [
|
|
|
399
471
|
{
|
|
400
472
|
id: 'profiler-forge',
|
|
401
473
|
displayName: 'Profiler Forge',
|
|
474
|
+
description: 'Clone profiler: forge and validate',
|
|
402
475
|
command: '@profiler-forge',
|
|
403
476
|
path: '.aioson/agents/profiler-forge.md',
|
|
404
477
|
dependsOn: ['.aioson/profiler-reports/{person-slug}/enriched-profile.md'],
|