@jaimevalasek/aioson 1.28.1 → 1.30.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 +42 -0
- package/README.md +7 -5
- package/docs/en/5-reference/cli-reference.md +40 -10
- package/docs/pt/4-agentes/briefing.md +2 -0
- package/docs/pt/4-agentes/copywriter.md +2 -0
- package/docs/pt/4-agentes/genome.md +1 -0
- package/docs/pt/4-agentes/pm.md +1 -1
- package/docs/pt/4-agentes/profiler-enricher.md +2 -0
- package/docs/pt/4-agentes/profiler-forge.md +2 -0
- package/docs/pt/4-agentes/sheldon.md +2 -0
- package/docs/pt/4-agentes/squad.md +12 -10
- package/docs/pt/5-referencia/autopilot-handoff.md +4 -4
- package/docs/pt/5-referencia/comandos-cli.md +7 -3
- package/docs/pt/5-referencia/fluxo-artefatos.md +1 -1
- package/docs/pt/5-referencia/memoria-e-contexto.md +62 -2
- package/docs/pt/_arquivo/monitor-de-contexto.md +2 -2
- package/package.json +4 -2
- package/src/cli.js +72 -24
- package/src/commands/ac-test-audit.js +45 -0
- package/src/commands/artifact-validate.js +62 -50
- package/src/commands/classify.js +73 -2
- package/src/commands/context-brief.js +59 -0
- package/src/commands/context-guard.js +88 -0
- package/src/commands/context-monitor.js +1 -1
- package/src/commands/context-search.js +101 -52
- package/src/commands/context-select.js +11 -2
- package/src/commands/feature-archive.js +21 -12
- package/src/commands/feature-current.js +82 -0
- package/src/commands/gate-check.js +32 -15
- package/src/commands/harness-check.js +17 -1
- package/src/commands/hooks-install.js +169 -26
- package/src/commands/hygiene-scan.js +423 -0
- package/src/commands/rules-lint.js +124 -0
- package/src/commands/sdd-benchmark.js +134 -0
- package/src/commands/spec-analyze.js +6 -4
- package/src/commands/store-system.js +329 -49
- package/src/constants.js +8 -3
- package/src/context-brief.js +585 -0
- package/src/context-guard.js +209 -0
- package/src/context-search.js +796 -96
- package/src/context-selector.js +802 -420
- package/src/handoff-contract.js +14 -6
- package/src/harness/contract-schema.js +1 -1
- package/src/i18n/messages/en.js +12 -5
- package/src/i18n/messages/es.js +11 -4
- package/src/i18n/messages/fr.js +11 -4
- package/src/i18n/messages/pt-BR.js +12 -5
- package/src/lib/ac-test-audit.js +194 -0
- package/src/preflight-engine.js +10 -6
- package/src/squad/state-manager.js +1 -1
- package/template/.aioson/agents/analyst.md +93 -53
- package/template/.aioson/agents/architect.md +41 -32
- package/template/.aioson/agents/briefing-refiner.md +15 -2
- package/template/.aioson/agents/briefing.md +105 -86
- package/template/.aioson/agents/committer.md +1 -1
- package/template/.aioson/agents/copywriter.md +53 -10
- package/template/.aioson/agents/design-hybrid-forge.md +9 -5
- package/template/.aioson/agents/dev.md +22 -25
- package/template/.aioson/agents/deyvin.md +126 -124
- package/template/.aioson/agents/discover.md +8 -9
- package/template/.aioson/agents/discovery-design-doc.md +52 -36
- package/template/.aioson/agents/forge-run.md +3 -0
- package/template/.aioson/agents/genome.md +12 -6
- package/template/.aioson/agents/neo.md +30 -24
- package/template/.aioson/agents/orache.md +16 -21
- package/template/.aioson/agents/orchestrator.md +40 -31
- package/template/.aioson/agents/pentester.md +22 -12
- package/template/.aioson/agents/pm.md +11 -2
- package/template/.aioson/agents/product.md +162 -183
- package/template/.aioson/agents/profiler-enricher.md +29 -6
- package/template/.aioson/agents/profiler-forge.md +16 -6
- package/template/.aioson/agents/profiler-researcher.md +10 -6
- package/template/.aioson/agents/qa.md +29 -19
- package/template/.aioson/agents/scope-check.md +14 -2
- package/template/.aioson/agents/sheldon.md +51 -21
- package/template/.aioson/agents/site-forge.md +4 -6
- package/template/.aioson/agents/squad.md +7 -12
- package/template/.aioson/agents/tester.md +40 -30
- package/template/.aioson/agents/ux-ui.md +56 -41
- package/template/.aioson/agents/validator.md +2 -2
- package/template/.aioson/config.md +4 -3
- package/template/.aioson/design-docs/agent-loading-contract.md +3 -3
- package/template/.aioson/docs/LAYERS.md +2 -0
- package/template/.aioson/docs/autonomy-protocol.md +7 -5
- package/template/.aioson/docs/autopilot-handoff.md +5 -3
- package/template/.aioson/docs/dev/execution-discipline.md +3 -0
- package/template/.aioson/docs/dev/simple-plan-lane.md +126 -77
- package/template/.aioson/docs/dev/stack-conventions.md +4 -1
- package/template/.aioson/docs/deyvin/continuity-recovery.md +21 -18
- package/template/.aioson/docs/deyvin/debugging-escalation.md +3 -0
- package/template/.aioson/docs/deyvin/pair-execution.md +3 -0
- package/template/.aioson/docs/deyvin/runtime-handoffs.md +6 -3
- package/template/.aioson/docs/dossier/agent-templates.md +3 -0
- package/template/.aioson/docs/dossier/schema.md +3 -0
- package/template/.aioson/docs/example-external-api-context.md +2 -0
- package/template/.aioson/docs/feature-expansion-taxonomy.md +53 -0
- package/template/.aioson/docs/handoff-persistence.md +95 -91
- package/template/.aioson/docs/pentester/app-playbooks.md +3 -0
- package/template/.aioson/docs/pentester/browser-dast-playbook.md +401 -398
- package/template/.aioson/docs/pentester/llm-supplychain.md +3 -0
- package/template/.aioson/docs/product/conversation-playbook.md +1 -1
- package/template/.aioson/docs/quality/code-health-analysis.md +2 -0
- package/template/.aioson/docs/sheldon/enrichment-paths.md +47 -1
- package/template/.aioson/docs/sheldon/harness-contract.md +26 -21
- package/template/.aioson/docs/sheldon/quality-lens.md +3 -0
- package/template/.aioson/docs/sheldon/research-loop.md +3 -0
- package/template/.aioson/docs/sheldon/web-intelligence.md +3 -0
- package/template/.aioson/docs/site-forge-build.md +4 -2
- package/template/.aioson/docs/site-forge-extraction.md +2 -0
- package/template/.aioson/docs/site-forge-qa.md +2 -0
- package/template/.aioson/docs/site-forge-recon.md +7 -5
- package/template/.aioson/docs/site-forge-transform.md +2 -0
- package/template/.aioson/docs/squad/content-output.md +3 -0
- package/template/.aioson/docs/squad/creation-flow.md +22 -1
- package/template/.aioson/docs/squad/domain-breadth.md +3 -0
- package/template/.aioson/docs/squad/domain-classification.md +3 -0
- package/template/.aioson/docs/squad/eval-gate.md +3 -0
- package/template/.aioson/docs/squad/genome-bindings.md +14 -0
- package/template/.aioson/docs/squad/package-contract.md +5 -0
- package/template/.aioson/docs/squad/persona-grounding.md +65 -62
- package/template/.aioson/docs/squad/quality-lens.md +3 -0
- package/template/.aioson/docs/squad/research-loop.md +3 -0
- package/template/.aioson/docs/squad/session-operations.md +3 -0
- package/template/.aioson/docs/squad/workflow-quality.md +3 -0
- package/template/.aioson/docs/tester/coverage-quality.md +4 -1
- package/template/.aioson/docs/ux-ui/design-execution.md +9 -7
- package/template/.aioson/rules/README.md +48 -2
- package/template/.aioson/rules/agent-language-policy.md +26 -21
- package/template/.aioson/rules/agent-structural-contract.md +168 -158
- package/template/.aioson/rules/aioson-context-boundary.md +7 -1
- package/template/.aioson/rules/canonical-path-contract.md +16 -10
- package/template/.aioson/rules/data-format-convention.md +17 -11
- package/template/.aioson/rules/disk-first-artifacts.md +12 -8
- package/template/.aioson/rules/example-monetary-values.md +4 -0
- package/template/.aioson/rules/implementation-structure-and-data-access.md +50 -0
- package/template/.aioson/rules/output-brevity.md +2 -0
- package/template/.aioson/rules/prd-section-ownership.md +17 -12
- package/template/.aioson/rules/security-baseline.md +8 -3
- package/template/.aioson/rules/simple-plan-lane.md +22 -5
- package/template/.aioson/rules/source-code-language-convention.md +34 -0
- package/template/.aioson/rules/spec-level-ownership.md +10 -5
- package/template/.aioson/rules/squad-driver-pattern.md +5 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/artifact-map.md +24 -23
- package/template/.aioson/skills/process/aioson-spec-driven/references/classification-map.md +4 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/dev.md +2 -2
- package/template/.aioson/skills/process/aioson-spec-driven/references/qa.md +1 -1
- package/template/.aioson/skills/process/briefing-expansion-scout/SKILL.md +72 -0
- package/template/.aioson/skills/process/product-scope-expansion/SKILL.md +74 -0
- package/template/.aioson/skills/process/sheldon-expansion-audit/SKILL.md +67 -0
- package/template/.aioson/skills/static/context-budget-guide.md +1 -1
- package/template/.aioson/skills/static/multi-agent-patterns.md +5 -4
- package/template/.aioson/tasks/squad-create.md +11 -0
- package/template/.aioson/tasks/squad-design.md +3 -3
- package/template/AGENTS.md +36 -19
- package/template/CLAUDE.md +9 -5
|
@@ -17,8 +17,10 @@
|
|
|
17
17
|
const path = require('node:path');
|
|
18
18
|
const fs = require('node:fs/promises');
|
|
19
19
|
const os = require('node:os');
|
|
20
|
+
const { getAgentDefinition, normalizeAgentName } = require('../agents');
|
|
20
21
|
|
|
21
22
|
const HOME = os.homedir();
|
|
23
|
+
const HOOK_AGENT_NAME_RE = /^[a-z][a-z0-9-]*$/;
|
|
22
24
|
|
|
23
25
|
// ─── Config file paths ────────────────────────────────────────────────────────
|
|
24
26
|
|
|
@@ -30,22 +32,63 @@ const CONFIG_PATHS = {
|
|
|
30
32
|
|
|
31
33
|
// ─── Hook command templates ───────────────────────────────────────────────────
|
|
32
34
|
|
|
35
|
+
function normalizeHookAgentName(input = 'dev') {
|
|
36
|
+
const raw = normalizeAgentName(input || 'dev').replace(/^\//, '');
|
|
37
|
+
const definition = getAgentDefinition(raw);
|
|
38
|
+
const agentName = definition ? definition.id : raw;
|
|
39
|
+
|
|
40
|
+
if (!HOOK_AGENT_NAME_RE.test(agentName)) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
`invalid agent name "${String(input)}"; use a known agent id or kebab-case identifier`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return agentName;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function shellQuote(value) {
|
|
50
|
+
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
|
51
|
+
}
|
|
52
|
+
|
|
33
53
|
function makeEmitCommand(agentName, source) {
|
|
34
54
|
// $PWD is the project directory at hook execution time
|
|
35
|
-
return `aioson hooks:emit "$PWD" --agent=${agentName} --source=${source} 2>/dev/null || true`;
|
|
55
|
+
return `aioson hooks:emit "$PWD" --agent=${shellQuote(agentName)} --source=${shellQuote(source)} 2>/dev/null || true`;
|
|
36
56
|
}
|
|
37
57
|
|
|
38
58
|
function makeDoneCommand(agentName) {
|
|
39
|
-
return `aioson agent:done "$PWD" --agent=${agentName} --summary
|
|
59
|
+
return `aioson agent:done "$PWD" --agent=${shellQuote(agentName)} --summary=${shellQuote(`Session ended via ${agentName} hook`)} 2>/dev/null || true`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function makeGuardCommand(agentName) {
|
|
63
|
+
// PreToolUse: the harness pipes the pending edit event (JSON on stdin); the
|
|
64
|
+
// guard derives a query from the artifact itself, runs context:brief, and
|
|
65
|
+
// injects salient project-rule constraints before the write lands. Advisory —
|
|
66
|
+
// always exits 0, never blocks the tool.
|
|
67
|
+
return `aioson context:guard "$PWD" --tool=claude --agent=${shellQuote(agentName)} --json 2>/dev/null || true`;
|
|
40
68
|
}
|
|
41
69
|
|
|
42
70
|
// ─── Claude Code ─────────────────────────────────────────────────────────────
|
|
43
71
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
72
|
+
// True for any hook entry AIOSON owns, so reinstall/uninstall can scrub them
|
|
73
|
+
// without disturbing user-authored hooks.
|
|
74
|
+
const AIOSON_HOOK_SIGNATURES = [
|
|
75
|
+
'aioson hooks:emit',
|
|
76
|
+
'aioson agent:done',
|
|
77
|
+
'aioson context:guard',
|
|
78
|
+
'aioson live:start'
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
function isAiosonHookEntry(entry) {
|
|
82
|
+
const cmd = entry?.hooks?.[0]?.command || entry?.command || '';
|
|
83
|
+
return AIOSON_HOOK_SIGNATURES.some((sig) => cmd.includes(sig));
|
|
84
|
+
}
|
|
47
85
|
|
|
48
|
-
|
|
86
|
+
function buildClaudeHooks(agentName, includeGuard = true) {
|
|
87
|
+
const safeAgentName = normalizeHookAgentName(agentName);
|
|
88
|
+
const emitCmd = makeEmitCommand(safeAgentName, 'claude');
|
|
89
|
+
const doneCmd = makeDoneCommand(safeAgentName);
|
|
90
|
+
|
|
91
|
+
const hooks = {
|
|
49
92
|
PostToolUse: [
|
|
50
93
|
{
|
|
51
94
|
matcher: 'Write|Edit|MultiEdit',
|
|
@@ -66,9 +109,20 @@ function buildClaudeHooks(agentName) {
|
|
|
66
109
|
}
|
|
67
110
|
]
|
|
68
111
|
};
|
|
112
|
+
|
|
113
|
+
if (includeGuard) {
|
|
114
|
+
hooks.PreToolUse = [
|
|
115
|
+
{
|
|
116
|
+
matcher: 'Write|Edit|MultiEdit|NotebookEdit',
|
|
117
|
+
hooks: [{ type: 'command', command: makeGuardCommand(safeAgentName) }]
|
|
118
|
+
}
|
|
119
|
+
];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return hooks;
|
|
69
123
|
}
|
|
70
124
|
|
|
71
|
-
async function installClaudeHooks(agentName, dryRun, logger) {
|
|
125
|
+
async function installClaudeHooks(agentName, dryRun, logger, includeGuard = true) {
|
|
72
126
|
const configPath = CONFIG_PATHS.claude;
|
|
73
127
|
await fs.mkdir(path.dirname(configPath), { recursive: true });
|
|
74
128
|
|
|
@@ -77,21 +131,26 @@ async function installClaudeHooks(agentName, dryRun, logger) {
|
|
|
77
131
|
existing = JSON.parse(await fs.readFile(configPath, 'utf8'));
|
|
78
132
|
} catch { /* file doesn't exist yet */ }
|
|
79
133
|
|
|
80
|
-
const newHooks = buildClaudeHooks(agentName);
|
|
134
|
+
const newHooks = buildClaudeHooks(agentName, includeGuard);
|
|
81
135
|
|
|
82
136
|
// Merge: add AIOSON hooks without removing existing ones
|
|
83
137
|
const merged = { ...existing };
|
|
84
138
|
if (!merged.hooks) merged.hooks = {};
|
|
85
139
|
|
|
140
|
+
// When the guard is opted out, still scrub any previously-installed guard hook
|
|
141
|
+
// so a reinstall with --no-guard actually removes it.
|
|
142
|
+
for (const event of Object.keys(merged.hooks)) {
|
|
143
|
+
if (newHooks[event]) continue;
|
|
144
|
+
merged.hooks[event] = (merged.hooks[event] || []).filter((entry) => !isAiosonHookEntry(entry));
|
|
145
|
+
if (merged.hooks[event].length === 0) delete merged.hooks[event];
|
|
146
|
+
}
|
|
147
|
+
|
|
86
148
|
for (const [event, hookList] of Object.entries(newHooks)) {
|
|
87
149
|
if (!merged.hooks[event]) {
|
|
88
150
|
merged.hooks[event] = hookList;
|
|
89
151
|
} else {
|
|
90
152
|
// Remove any existing AIOSON hooks (to avoid duplicates on reinstall)
|
|
91
|
-
const filtered = merged.hooks[event].filter((entry) =>
|
|
92
|
-
const cmd = entry.hooks?.[0]?.command || '';
|
|
93
|
-
return !cmd.includes('aioson hooks:emit') && !cmd.includes('aioson agent:done');
|
|
94
|
-
});
|
|
153
|
+
const filtered = merged.hooks[event].filter((entry) => !isAiosonHookEntry(entry));
|
|
95
154
|
merged.hooks[event] = [...filtered, ...hookList];
|
|
96
155
|
}
|
|
97
156
|
}
|
|
@@ -102,6 +161,9 @@ async function installClaudeHooks(agentName, dryRun, logger) {
|
|
|
102
161
|
} else {
|
|
103
162
|
logger.log(` [dry-run] Would write: ${configPath}`);
|
|
104
163
|
logger.log(` Hooks to add:`);
|
|
164
|
+
if (includeGuard) {
|
|
165
|
+
logger.log(` PreToolUse (Write|Edit|MultiEdit|NotebookEdit) → context:guard`);
|
|
166
|
+
}
|
|
105
167
|
logger.log(` PostToolUse (Write|Edit|MultiEdit|Bash|Task|TodoWrite) → hooks:emit`);
|
|
106
168
|
logger.log(` Stop → agent:done`);
|
|
107
169
|
}
|
|
@@ -112,9 +174,10 @@ async function installClaudeHooks(agentName, dryRun, logger) {
|
|
|
112
174
|
// ─── Antigravity ─────────────────────────────────────────────────────────────
|
|
113
175
|
|
|
114
176
|
function buildAntigravityHooks(agentName) {
|
|
115
|
-
const
|
|
116
|
-
const
|
|
117
|
-
const
|
|
177
|
+
const safeAgentName = normalizeHookAgentName(agentName);
|
|
178
|
+
const emitCmd = makeEmitCommand(safeAgentName, 'antigravity');
|
|
179
|
+
const doneCmd = makeDoneCommand(safeAgentName);
|
|
180
|
+
const startCmd = `aioson live:start "$PWD" --agent=${shellQuote(safeAgentName)} --tool=antigravity --no-launch 2>/dev/null || true`;
|
|
118
181
|
|
|
119
182
|
return {
|
|
120
183
|
SessionStart: [{ type: 'command', command: startCmd }],
|
|
@@ -178,9 +241,39 @@ function mergeAntigravityHooks(existing, newHooks) {
|
|
|
178
241
|
return merged;
|
|
179
242
|
}
|
|
180
243
|
|
|
244
|
+
// Scrub AIOSON entries from one Antigravity hooks file, mirroring the
|
|
245
|
+
// `cmd.includes('aioson')` policy the merge uses on install.
|
|
246
|
+
async function scrubAntigravityHookFile(filePath, dryRun, logger, label) {
|
|
247
|
+
let existing;
|
|
248
|
+
try {
|
|
249
|
+
existing = JSON.parse(await fs.readFile(filePath, 'utf8'));
|
|
250
|
+
} catch {
|
|
251
|
+
logger.log(` ${label} not found — nothing to remove`);
|
|
252
|
+
return { tool: 'antigravity', path: filePath, removed: false };
|
|
253
|
+
}
|
|
254
|
+
if (existing.hooks) {
|
|
255
|
+
for (const event of Object.keys(existing.hooks)) {
|
|
256
|
+
existing.hooks[event] = (existing.hooks[event] || []).filter((entry) => {
|
|
257
|
+
const cmd = entry.command || entry.hooks?.[0]?.command || '';
|
|
258
|
+
return !cmd.includes('aioson');
|
|
259
|
+
});
|
|
260
|
+
if (existing.hooks[event].length === 0) delete existing.hooks[event];
|
|
261
|
+
}
|
|
262
|
+
if (Object.keys(existing.hooks).length === 0) delete existing.hooks;
|
|
263
|
+
}
|
|
264
|
+
if (!dryRun) {
|
|
265
|
+
await fs.writeFile(filePath, JSON.stringify(existing, null, 2), 'utf8');
|
|
266
|
+
logger.log(` ✓ ${label} hooks removed — ${filePath}`);
|
|
267
|
+
} else {
|
|
268
|
+
logger.log(` [dry-run] Would remove AIOSON hooks from: ${filePath}`);
|
|
269
|
+
}
|
|
270
|
+
return { tool: 'antigravity', path: filePath, removed: true };
|
|
271
|
+
}
|
|
272
|
+
|
|
181
273
|
// ─── Codex (OpenAI) ───────────────────────────────────────────────────────────
|
|
182
274
|
|
|
183
275
|
async function installCodexHooks(agentName, dryRun, logger) {
|
|
276
|
+
const safeAgentName = normalizeHookAgentName(agentName);
|
|
184
277
|
// Codex CLI does not have a native hook system as of 2026.
|
|
185
278
|
// The workaround: add a shell alias that wraps `codex` and calls live:start before / agent:done after.
|
|
186
279
|
const configPath = path.join(HOME, '.codex', 'config.yaml');
|
|
@@ -188,12 +281,12 @@ async function installCodexHooks(agentName, dryRun, logger) {
|
|
|
188
281
|
|
|
189
282
|
const wrapperScript = `#!/bin/bash
|
|
190
283
|
# AIOSON session wrapper for Codex CLI
|
|
191
|
-
# Generated by: aioson hooks:install --tool=codex --agent=${
|
|
284
|
+
# Generated by: aioson hooks:install --tool=codex --agent=${safeAgentName}
|
|
192
285
|
# Usage: replace \`codex\` calls with \`codex-aioson\` OR add to .bashrc:
|
|
193
286
|
# alias codex='${wrapperPath}'
|
|
194
287
|
|
|
195
288
|
PROJECT_DIR="\${1:-$PWD}"
|
|
196
|
-
AGENT
|
|
289
|
+
AGENT=${shellQuote(safeAgentName)}
|
|
197
290
|
|
|
198
291
|
# Start live session before Codex runs
|
|
199
292
|
aioson live:start "$PROJECT_DIR" --agent="$AGENT" --tool=codex --no-launch 2>/dev/null || true
|
|
@@ -248,8 +341,15 @@ async function detectInstalledTools() {
|
|
|
248
341
|
|
|
249
342
|
async function runHooksInstall({ args, options = {}, logger }) {
|
|
250
343
|
const projectDir = path.resolve(process.cwd(), args[0] || '.');
|
|
251
|
-
|
|
344
|
+
let agentName;
|
|
345
|
+
try {
|
|
346
|
+
agentName = normalizeHookAgentName(options.agent || 'dev');
|
|
347
|
+
} catch (err) {
|
|
348
|
+
logger.log(`Invalid agent name: ${err.message}`);
|
|
349
|
+
return { ok: false, reason: 'invalid_agent_name', error: err.message };
|
|
350
|
+
}
|
|
252
351
|
const dryRun = options['dry-run'] || options.dryRun || false;
|
|
352
|
+
const includeGuard = !(options['no-guard'] || options.noGuard);
|
|
253
353
|
let tool = options.tool ? String(options.tool).trim().toLowerCase() : 'all';
|
|
254
354
|
|
|
255
355
|
if (tool === 'all') {
|
|
@@ -271,7 +371,7 @@ async function runHooksInstall({ args, options = {}, logger }) {
|
|
|
271
371
|
for (const t of tools) {
|
|
272
372
|
try {
|
|
273
373
|
if (t === 'claude') {
|
|
274
|
-
results.push(await installClaudeHooks(agentName, dryRun, logger));
|
|
374
|
+
results.push(await installClaudeHooks(agentName, dryRun, logger, includeGuard));
|
|
275
375
|
} else if (t === 'antigravity') {
|
|
276
376
|
results.push(await installAntigravityHooks(agentName, projectDir, dryRun, logger));
|
|
277
377
|
} else if (t === 'codex') {
|
|
@@ -290,6 +390,9 @@ async function runHooksInstall({ args, options = {}, logger }) {
|
|
|
290
390
|
if (!dryRun) {
|
|
291
391
|
logger.log('');
|
|
292
392
|
logger.log('Hooks installed. From now on:');
|
|
393
|
+
if (includeGuard && tools.includes('claude')) {
|
|
394
|
+
logger.log(' • Before each file write/edit → context:guard injects salient project-rule constraints');
|
|
395
|
+
}
|
|
293
396
|
logger.log(' • Every file write/edit → logged as artifact event');
|
|
294
397
|
logger.log(' • Every bash command → logged as step_done event');
|
|
295
398
|
logger.log(' • Session end → logged as agent:done');
|
|
@@ -306,7 +409,14 @@ async function runHooksInstall({ args, options = {}, logger }) {
|
|
|
306
409
|
}
|
|
307
410
|
|
|
308
411
|
async function runHooksUninstall({ args, options = {}, logger }) {
|
|
309
|
-
|
|
412
|
+
let agentName;
|
|
413
|
+
try {
|
|
414
|
+
agentName = normalizeHookAgentName(options.agent || 'dev');
|
|
415
|
+
} catch (err) {
|
|
416
|
+
logger.log(`Invalid agent name: ${err.message}`);
|
|
417
|
+
return { ok: false, reason: 'invalid_agent_name', error: err.message };
|
|
418
|
+
}
|
|
419
|
+
const projectDir = path.resolve(process.cwd(), args && args[0] ? args[0] : '.');
|
|
310
420
|
const dryRun = options['dry-run'] || options.dryRun || false;
|
|
311
421
|
const tool = options.tool ? String(options.tool).trim().toLowerCase() : 'claude';
|
|
312
422
|
const tools = tool.split(',').map((t) => t.trim()).filter(Boolean);
|
|
@@ -314,6 +424,8 @@ async function runHooksUninstall({ args, options = {}, logger }) {
|
|
|
314
424
|
logger.log(`Hooks Uninstall — agent: @${agentName}${dryRun ? ' [dry-run]' : ''}`);
|
|
315
425
|
logger.log('─'.repeat(50));
|
|
316
426
|
|
|
427
|
+
const results = [];
|
|
428
|
+
|
|
317
429
|
for (const t of tools) {
|
|
318
430
|
if (t === 'claude') {
|
|
319
431
|
try {
|
|
@@ -321,10 +433,7 @@ async function runHooksUninstall({ args, options = {}, logger }) {
|
|
|
321
433
|
const existing = JSON.parse(await fs.readFile(configPath, 'utf8'));
|
|
322
434
|
if (existing.hooks) {
|
|
323
435
|
for (const event of Object.keys(existing.hooks)) {
|
|
324
|
-
existing.hooks[event] = (existing.hooks[event] || []).filter((entry) =>
|
|
325
|
-
const cmd = entry.hooks?.[0]?.command || entry.command || '';
|
|
326
|
-
return !cmd.includes('aioson hooks:emit') && !cmd.includes('aioson agent:done') && !cmd.includes('aioson live:start');
|
|
327
|
-
});
|
|
436
|
+
existing.hooks[event] = (existing.hooks[event] || []).filter((entry) => !isAiosonHookEntry(entry));
|
|
328
437
|
if (existing.hooks[event].length === 0) delete existing.hooks[event];
|
|
329
438
|
}
|
|
330
439
|
if (Object.keys(existing.hooks).length === 0) delete existing.hooks;
|
|
@@ -335,13 +444,47 @@ async function runHooksUninstall({ args, options = {}, logger }) {
|
|
|
335
444
|
} else {
|
|
336
445
|
logger.log(` [dry-run] Would remove AIOSON hooks from: ${configPath}`);
|
|
337
446
|
}
|
|
447
|
+
results.push({ tool: 'claude', path: configPath, removed: true });
|
|
338
448
|
} catch {
|
|
339
449
|
logger.log(` Claude Code settings not found — nothing to remove`);
|
|
450
|
+
results.push({ tool: 'claude', removed: false });
|
|
340
451
|
}
|
|
452
|
+
} else if (t === 'antigravity') {
|
|
453
|
+
// Install writes both a global and a workspace hooks file — scrub both.
|
|
454
|
+
results.push(await scrubAntigravityHookFile(CONFIG_PATHS.antigravity, dryRun, logger, 'Antigravity global'));
|
|
455
|
+
results.push(await scrubAntigravityHookFile(
|
|
456
|
+
path.join(projectDir, CONFIG_PATHS.antigravity_workspace), dryRun, logger, 'Antigravity workspace'
|
|
457
|
+
));
|
|
458
|
+
} else if (t === 'codex') {
|
|
459
|
+
const wrapperPath = path.join(HOME, '.codex', 'aioson-wrapper.sh');
|
|
460
|
+
try {
|
|
461
|
+
if (!dryRun) {
|
|
462
|
+
await fs.unlink(wrapperPath);
|
|
463
|
+
logger.log(` ✓ Codex wrapper removed — ${wrapperPath}`);
|
|
464
|
+
logger.log(` ⚠ Also remove the alias from your shell rc if you added it: alias codex='${wrapperPath}'`);
|
|
465
|
+
} else {
|
|
466
|
+
logger.log(` [dry-run] Would remove: ${wrapperPath}`);
|
|
467
|
+
}
|
|
468
|
+
results.push({ tool: 'codex', path: wrapperPath, removed: true });
|
|
469
|
+
} catch {
|
|
470
|
+
logger.log(` Codex wrapper not found — nothing to remove`);
|
|
471
|
+
results.push({ tool: 'codex', removed: false });
|
|
472
|
+
}
|
|
473
|
+
} else {
|
|
474
|
+
logger.log(` ⚠ Unknown tool: ${t} — supported: claude, antigravity, codex`);
|
|
475
|
+
results.push({ tool: t, removed: false, reason: 'unsupported' });
|
|
341
476
|
}
|
|
342
477
|
}
|
|
343
478
|
|
|
344
|
-
return { ok: true };
|
|
479
|
+
return { ok: true, results };
|
|
345
480
|
}
|
|
346
481
|
|
|
347
|
-
module.exports = {
|
|
482
|
+
module.exports = {
|
|
483
|
+
runHooksInstall,
|
|
484
|
+
runHooksUninstall,
|
|
485
|
+
buildClaudeHooks,
|
|
486
|
+
buildAntigravityHooks,
|
|
487
|
+
scrubAntigravityHookFile,
|
|
488
|
+
normalizeHookAgentName,
|
|
489
|
+
isAiosonHookEntry
|
|
490
|
+
};
|