intentdna 1.2.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/hooks/hooks.json +12 -0
- package/.claude-plugin/plugin.json +5 -0
- package/dist/audit/index.d.ts +0 -1
- package/dist/audit/index.js +0 -1
- package/dist/cli/commands/compile.d.ts +0 -1
- package/dist/cli/commands/compile.js +0 -1
- package/dist/cli/commands/epigenetic.d.ts +0 -1
- package/dist/cli/commands/epigenetic.js +0 -1
- package/dist/cli/commands/evolve.d.ts +0 -1
- package/dist/cli/commands/evolve.js +0 -1
- package/dist/cli/commands/guard.d.ts +0 -1
- package/dist/cli/commands/guard.js +0 -3
- package/dist/cli/commands/import.d.ts +0 -1
- package/dist/cli/commands/import.js +0 -1
- package/dist/cli/commands/init.d.ts +0 -1
- package/dist/cli/commands/init.js +0 -1
- package/dist/cli/commands/run.d.ts +0 -1
- package/dist/cli/commands/run.js +4 -27
- package/dist/cli/commands/setup.d.ts +9 -0
- package/dist/cli/commands/setup.js +42 -0
- package/dist/cli/commands/show.d.ts +0 -1
- package/dist/cli/commands/show.js +0 -1
- package/dist/cli/commands/sync.d.ts +13 -1
- package/dist/cli/commands/sync.js +158 -33
- package/dist/cli/commands/validate.d.ts +0 -1
- package/dist/cli/commands/validate.js +0 -1
- package/dist/cli/commands/verify.d.ts +0 -1
- package/dist/cli/commands/verify.js +0 -1
- package/dist/cli/index.d.ts +0 -1
- package/dist/cli/index.js +9 -1
- package/dist/cli/util/format.d.ts +0 -1
- package/dist/cli/util/format.js +0 -1
- package/dist/cli/util/prompt.d.ts +0 -1
- package/dist/cli/util/prompt.js +0 -1
- package/dist/compiler/activate.d.ts +0 -1
- package/dist/compiler/activate.js +0 -1
- package/dist/compiler/cascade.d.ts +1 -3
- package/dist/compiler/cascade.js +1 -10
- package/dist/compiler/compile.d.ts +0 -1
- package/dist/compiler/compile.js +33 -17
- package/dist/compiler/index.d.ts +0 -1
- package/dist/compiler/index.js +0 -1
- package/dist/compiler/workflow.d.ts +0 -1
- package/dist/compiler/workflow.js +0 -2
- package/dist/evolution/collector.d.ts +0 -1
- package/dist/evolution/collector.js +0 -1
- package/dist/evolution/fitness.d.ts +0 -1
- package/dist/evolution/fitness.js +0 -1
- package/dist/evolution/index.d.ts +0 -1
- package/dist/evolution/index.js +0 -1
- package/dist/evolution/marker-gen.d.ts +0 -1
- package/dist/evolution/marker-gen.js +0 -1
- package/dist/evolution/store.d.ts +0 -1
- package/dist/evolution/store.js +0 -1
- package/dist/evolution/types.d.ts +0 -1
- package/dist/evolution/types.js +0 -1
- package/dist/hooks/cli.d.ts +17 -0
- package/dist/hooks/cli.js +156 -0
- package/dist/hooks/enforce.d.ts +106 -0
- package/dist/hooks/enforce.js +431 -0
- package/dist/hooks/index.d.ts +9 -0
- package/dist/hooks/index.js +12 -0
- package/dist/hooks/protocol.d.ts +73 -0
- package/dist/hooks/protocol.js +91 -0
- package/dist/hooks/state.d.ts +53 -0
- package/dist/hooks/state.js +93 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/log/logger.d.ts +0 -1
- package/dist/log/logger.js +0 -1
- package/dist/runtime/agent-md.d.ts +0 -1
- package/dist/runtime/agent-md.js +95 -105
- package/dist/runtime/claude-sdk.d.ts +0 -1
- package/dist/runtime/claude-sdk.js +0 -1
- package/dist/runtime/index.d.ts +3 -3
- package/dist/runtime/index.js +2 -2
- package/dist/runtime/markdown.d.ts +0 -1
- package/dist/runtime/markdown.js +0 -1
- package/dist/runtime/plugin-adapter.d.ts +42 -0
- package/dist/runtime/plugin-adapter.js +77 -0
- package/dist/runtime/settings-adapter.d.ts +8 -9
- package/dist/runtime/settings-adapter.js +57 -46
- package/dist/runtime/skill-adapter.d.ts +0 -1
- package/dist/runtime/skill-adapter.js +94 -71
- package/dist/runtime/workflow-runner.d.ts +0 -1
- package/dist/runtime/workflow-runner.js +0 -14
- package/dist/schema/index.d.ts +0 -1
- package/dist/schema/index.js +0 -1
- package/dist/schema/types.d.ts +33 -20
- package/dist/schema/types.js +0 -1
- package/dist/schema/validate.d.ts +0 -1
- package/dist/schema/validate.js +32 -19
- package/dist/schema/yaml-parser.d.ts +0 -1
- package/dist/schema/yaml-parser.js +0 -1
- package/dist/templates/code-review-pipeline.dna.yaml +0 -11
- package/dist/templates/flutter-behavior-lock.dna.yaml +0 -16
- package/dist/templates/flutter-refactoring-rescue.dna.yaml +0 -12
- package/dist/templates/flutter-rewrite.dna.yaml +0 -27
- package/dist/templates/full-pipeline.dna.yaml +0 -25
- package/dist/templates/multi-perspective-review.dna.yaml +0 -12
- package/dist/templates/subagent-parallel.dna.yaml +0 -16
- package/package.json +4 -2
- package/dist/audit/index.d.ts.map +0 -1
- package/dist/audit/index.js.map +0 -1
- package/dist/cli/commands/compile.d.ts.map +0 -1
- package/dist/cli/commands/compile.js.map +0 -1
- package/dist/cli/commands/epigenetic.d.ts.map +0 -1
- package/dist/cli/commands/epigenetic.js.map +0 -1
- package/dist/cli/commands/evolve.d.ts.map +0 -1
- package/dist/cli/commands/evolve.js.map +0 -1
- package/dist/cli/commands/guard.d.ts.map +0 -1
- package/dist/cli/commands/guard.js.map +0 -1
- package/dist/cli/commands/import.d.ts.map +0 -1
- package/dist/cli/commands/import.js.map +0 -1
- package/dist/cli/commands/init.d.ts.map +0 -1
- package/dist/cli/commands/init.js.map +0 -1
- package/dist/cli/commands/run.d.ts.map +0 -1
- package/dist/cli/commands/run.js.map +0 -1
- package/dist/cli/commands/show.d.ts.map +0 -1
- package/dist/cli/commands/show.js.map +0 -1
- package/dist/cli/commands/sync.d.ts.map +0 -1
- package/dist/cli/commands/sync.js.map +0 -1
- package/dist/cli/commands/validate.d.ts.map +0 -1
- package/dist/cli/commands/validate.js.map +0 -1
- package/dist/cli/commands/verify.d.ts.map +0 -1
- package/dist/cli/commands/verify.js.map +0 -1
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/util/format.d.ts.map +0 -1
- package/dist/cli/util/format.js.map +0 -1
- package/dist/cli/util/prompt.d.ts.map +0 -1
- package/dist/cli/util/prompt.js.map +0 -1
- package/dist/compiler/activate.d.ts.map +0 -1
- package/dist/compiler/activate.js.map +0 -1
- package/dist/compiler/cascade.d.ts.map +0 -1
- package/dist/compiler/cascade.js.map +0 -1
- package/dist/compiler/compile.d.ts.map +0 -1
- package/dist/compiler/compile.js.map +0 -1
- package/dist/compiler/index.d.ts.map +0 -1
- package/dist/compiler/index.js.map +0 -1
- package/dist/compiler/workflow.d.ts.map +0 -1
- package/dist/compiler/workflow.js.map +0 -1
- package/dist/evolution/collector.d.ts.map +0 -1
- package/dist/evolution/collector.js.map +0 -1
- package/dist/evolution/fitness.d.ts.map +0 -1
- package/dist/evolution/fitness.js.map +0 -1
- package/dist/evolution/index.d.ts.map +0 -1
- package/dist/evolution/index.js.map +0 -1
- package/dist/evolution/marker-gen.d.ts.map +0 -1
- package/dist/evolution/marker-gen.js.map +0 -1
- package/dist/evolution/store.d.ts.map +0 -1
- package/dist/evolution/store.js.map +0 -1
- package/dist/evolution/types.d.ts.map +0 -1
- package/dist/evolution/types.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/log/logger.d.ts.map +0 -1
- package/dist/log/logger.js.map +0 -1
- package/dist/runtime/agent-md.d.ts.map +0 -1
- package/dist/runtime/agent-md.js.map +0 -1
- package/dist/runtime/claude-sdk.d.ts.map +0 -1
- package/dist/runtime/claude-sdk.js.map +0 -1
- package/dist/runtime/hooks.d.ts +0 -67
- package/dist/runtime/hooks.d.ts.map +0 -1
- package/dist/runtime/hooks.js +0 -785
- package/dist/runtime/hooks.js.map +0 -1
- package/dist/runtime/index.d.ts.map +0 -1
- package/dist/runtime/index.js.map +0 -1
- package/dist/runtime/markdown.d.ts.map +0 -1
- package/dist/runtime/markdown.js.map +0 -1
- package/dist/runtime/settings-adapter.d.ts.map +0 -1
- package/dist/runtime/settings-adapter.js.map +0 -1
- package/dist/runtime/skill-adapter.d.ts.map +0 -1
- package/dist/runtime/skill-adapter.js.map +0 -1
- package/dist/runtime/workflow-runner.d.ts.map +0 -1
- package/dist/runtime/workflow-runner.js.map +0 -1
- package/dist/schema/index.d.ts.map +0 -1
- package/dist/schema/index.js.map +0 -1
- package/dist/schema/types.d.ts.map +0 -1
- package/dist/schema/types.js.map +0 -1
- package/dist/schema/validate.d.ts.map +0 -1
- package/dist/schema/validate.js.map +0 -1
- package/dist/schema/yaml-parser.d.ts.map +0 -1
- package/dist/schema/yaml-parser.js.map +0 -1
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PreToolUse": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "dna-hook PreToolUse", "timeout": 5000 }] }],
|
|
4
|
+
"PostToolUse": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "dna-hook PostToolUse", "timeout": 3000 }] }],
|
|
5
|
+
"UserPromptSubmit": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "dna-hook UserPromptSubmit", "timeout": 5000 }] }],
|
|
6
|
+
"SubagentStop": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "dna-hook SubagentStop", "timeout": 3000 }] }],
|
|
7
|
+
"PreCompact": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "dna-hook PreCompact", "timeout": 3000 }] }],
|
|
8
|
+
"Notification": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "dna-hook Notification", "timeout": 3000 }] }],
|
|
9
|
+
"Stop": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "dna-hook Stop", "timeout": 3000 }] }],
|
|
10
|
+
"SessionStart": [{ "matcher": "*", "hooks": [{ "type": "command", "command": "dna-hook SessionStart", "timeout": 5000 }] }]
|
|
11
|
+
}
|
|
12
|
+
}
|
package/dist/audit/index.d.ts
CHANGED
package/dist/audit/index.js
CHANGED
|
@@ -177,7 +177,6 @@ export async function runGuard(opts) {
|
|
|
177
177
|
const r = await runSync({
|
|
178
178
|
files: [], target: "claude-md",
|
|
179
179
|
inject: join(cwd, "CLAUDE.md"),
|
|
180
|
-
hooksDir: join(cwd, ".claude", "hooks"),
|
|
181
180
|
evolve: false, remove: true,
|
|
182
181
|
});
|
|
183
182
|
if (r !== 0)
|
|
@@ -215,7 +214,6 @@ export async function runGuard(opts) {
|
|
|
215
214
|
files: [tmpFile],
|
|
216
215
|
target: "claude-md",
|
|
217
216
|
inject: join(cwd, "CLAUDE.md"),
|
|
218
|
-
hooksDir: join(cwd, ".claude", "hooks"),
|
|
219
217
|
evolve: false, remove: false,
|
|
220
218
|
});
|
|
221
219
|
if (r !== 0)
|
|
@@ -254,4 +252,3 @@ export async function runGuard(opts) {
|
|
|
254
252
|
await rm(tmpFile, { force: true });
|
|
255
253
|
}
|
|
256
254
|
}
|
|
257
|
-
//# sourceMappingURL=guard.js.map
|
|
@@ -68,4 +68,3 @@ export declare function parseClaudeMD(content: string): {
|
|
|
68
68
|
export declare function importHarness(dir: string): Promise<ImportResult>;
|
|
69
69
|
export declare function generateDNAYaml(result: ImportResult, projectName?: string): string;
|
|
70
70
|
export declare function runImport(opts: ImportOptions): Promise<number>;
|
|
71
|
-
//# sourceMappingURL=import.d.ts.map
|
|
@@ -56,4 +56,3 @@ export declare function executeGroup(group: ParallelGroup, allSteps: WorkflowSte
|
|
|
56
56
|
export declare function checkRetryNeeded(stepResults: Map<string, StepResult>, transitions: TransitionRule[]): boolean;
|
|
57
57
|
export declare function runRun(opts: RunOptions): Promise<number>;
|
|
58
58
|
export {};
|
|
59
|
-
//# sourceMappingURL=run.d.ts.map
|
package/dist/cli/commands/run.js
CHANGED
|
@@ -13,7 +13,7 @@ import { loadDNA, compileFromFiles } from "../../compiler/index.js";
|
|
|
13
13
|
import { cascadeDNA } from "../../compiler/cascade.js";
|
|
14
14
|
import { compileWorkflow } from "../../compiler/workflow.js";
|
|
15
15
|
import { compileAllRolesToAgentMD, writeAgentMDFiles, toKebabCase, } from "../../runtime/agent-md.js";
|
|
16
|
-
import {
|
|
16
|
+
import { createCompiledIR, writeCompiledIR } from "../../runtime/plugin-adapter.js";
|
|
17
17
|
// ── Template & Condition Helpers ───────────────────────────
|
|
18
18
|
/**
|
|
19
19
|
* Replace {{var}} placeholders in a template string.
|
|
@@ -127,21 +127,6 @@ export async function executeStep(step, vars, opts) {
|
|
|
127
127
|
"--no-session-persistence",
|
|
128
128
|
];
|
|
129
129
|
log(`Running step: ${step.id} (agent: ${agentName})`);
|
|
130
|
-
// Write mode file if step declares a mode
|
|
131
|
-
if (step.mode) {
|
|
132
|
-
const modeData = JSON.stringify({
|
|
133
|
-
active_mode: step.mode,
|
|
134
|
-
set_at: new Date().toISOString(),
|
|
135
|
-
set_by: `run:${step.id}`,
|
|
136
|
-
});
|
|
137
|
-
try {
|
|
138
|
-
const { mkdir: mkdirAsync, writeFile: writeFileAsync } = await import("node:fs/promises");
|
|
139
|
-
await mkdirAsync(".dna", { recursive: true });
|
|
140
|
-
await writeFileAsync(".dna/mode", modeData, "utf-8");
|
|
141
|
-
log(`Mode set: ${step.mode}`);
|
|
142
|
-
}
|
|
143
|
-
catch { /* best effort */ }
|
|
144
|
-
}
|
|
145
130
|
try {
|
|
146
131
|
const output = await spawnAsync("claude", args, prompt);
|
|
147
132
|
await writeFile(resultFile, output, "utf-8");
|
|
@@ -271,7 +256,6 @@ export async function runRun(opts) {
|
|
|
271
256
|
const maxBudget = opts.maxBudget ?? 5;
|
|
272
257
|
const permissionMode = opts.permissionMode ?? "bypassPermissions";
|
|
273
258
|
const agentsDir = opts.agentsDir ?? ".claude/agents";
|
|
274
|
-
const hooksDir = opts.hooksDir ?? ".claude/hooks";
|
|
275
259
|
try {
|
|
276
260
|
// ── Step 1: Load & compile DNA ───────────────────────
|
|
277
261
|
log("Loading DNA files...");
|
|
@@ -311,9 +295,9 @@ export async function runRun(opts) {
|
|
|
311
295
|
const agentResults = compileAllRolesToAgentMD(cascaded.roles, ir);
|
|
312
296
|
await writeAgentMDFiles(agentResults, agentsDir);
|
|
313
297
|
log(`Generated ${agentResults.length} agent file(s) in ${agentsDir}`);
|
|
314
|
-
const hookScripts =
|
|
315
|
-
await
|
|
316
|
-
log(
|
|
298
|
+
const hookScripts = createCompiledIR(ir, cascaded.roles);
|
|
299
|
+
await writeCompiledIR(process.cwd(), hookScripts);
|
|
300
|
+
log("Synced compiled IR for dna-hook enforcement");
|
|
317
301
|
// ── Step 5: Prepare log directory ────────────────────
|
|
318
302
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
319
303
|
const logDir = opts.logDir ?? join(".intentdna", "runs", `${opts.workflowName}-${timestamp}`);
|
|
@@ -367,12 +351,6 @@ export async function runRun(opts) {
|
|
|
367
351
|
// All passed
|
|
368
352
|
break;
|
|
369
353
|
}
|
|
370
|
-
// Clean up mode file after workflow completes
|
|
371
|
-
try {
|
|
372
|
-
const { rm: rmAsync } = await import("node:fs/promises");
|
|
373
|
-
await rmAsync(".dna/mode", { force: true });
|
|
374
|
-
}
|
|
375
|
-
catch { /* best effort */ }
|
|
376
354
|
return printSummary(stepResults, round, logDir, 0);
|
|
377
355
|
}
|
|
378
356
|
catch (err) {
|
|
@@ -428,4 +406,3 @@ function printSummary(results, rounds, logDir, exitCode) {
|
|
|
428
406
|
process.stderr.write(`\nTotal: ${passed} passed, ${failed} failed, ${skipped} skipped\n`);
|
|
429
407
|
return exitCode;
|
|
430
408
|
}
|
|
431
|
-
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dna setup
|
|
3
|
+
*
|
|
4
|
+
* Registers intentdna as a Claude Code plugin.
|
|
5
|
+
* Auto-detects whether claude CLI is available and prints guidance accordingly.
|
|
6
|
+
*/
|
|
7
|
+
export interface SetupOptions {
|
|
8
|
+
}
|
|
9
|
+
export declare function runSetup(_opts: SetupOptions): Promise<number>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dna setup
|
|
3
|
+
*
|
|
4
|
+
* Registers intentdna as a Claude Code plugin.
|
|
5
|
+
* Auto-detects whether claude CLI is available and prints guidance accordingly.
|
|
6
|
+
*/
|
|
7
|
+
import { execSync } from "node:child_process";
|
|
8
|
+
export async function runSetup(_opts) {
|
|
9
|
+
let claudeAvailable = false;
|
|
10
|
+
try {
|
|
11
|
+
execSync("claude --version", { stdio: "ignore" });
|
|
12
|
+
claudeAvailable = true;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// claude CLI not found — fall through to bin mode
|
|
16
|
+
}
|
|
17
|
+
if (claudeAvailable) {
|
|
18
|
+
process.stderr.write("Claude Code CLI detected.\n");
|
|
19
|
+
process.stderr.write("\n");
|
|
20
|
+
process.stderr.write("Intent DNA plugin mode:\n");
|
|
21
|
+
process.stderr.write(" The .claude-plugin/ directory contains plugin.json and hook scripts.\n");
|
|
22
|
+
process.stderr.write(" To register as a plugin, run:\n");
|
|
23
|
+
process.stderr.write("\n");
|
|
24
|
+
let npmRoot = "";
|
|
25
|
+
try {
|
|
26
|
+
npmRoot = execSync("npm root -g", { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// ignore
|
|
30
|
+
}
|
|
31
|
+
const pluginPath = npmRoot ? `${npmRoot}/intentdna` : "<npm-root>/intentdna";
|
|
32
|
+
process.stderr.write(` claude plugin add ${pluginPath}\n`);
|
|
33
|
+
process.stderr.write("\n");
|
|
34
|
+
process.stderr.write(" Or run 'dna sync --plugin' to activate hooks via settings.json.\n");
|
|
35
|
+
process.stderr.write("Intent DNA plugin registered. Run 'dna sync' to activate.\n");
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
process.stderr.write("Claude Code CLI not detected. Using bin mode.\n");
|
|
39
|
+
process.stderr.write("Run 'dna sync' to register dna-hook in settings.json\n");
|
|
40
|
+
}
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
@@ -26,6 +26,18 @@ export interface SyncOptions {
|
|
|
26
26
|
settingsPath?: string;
|
|
27
27
|
lockFile?: string;
|
|
28
28
|
remove: boolean;
|
|
29
|
+
plugin?: boolean;
|
|
29
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Detect whether intentdna is running as a Claude Code plugin or standalone binary.
|
|
33
|
+
*
|
|
34
|
+
* Plugin mode: claude plugin system manages hook dispatch
|
|
35
|
+
* → generate ir.json + agents + skills + .mcp.json
|
|
36
|
+
* → do NOT write settings.json (hooks provided by plugin framework)
|
|
37
|
+
*
|
|
38
|
+
* Bin mode: fallback when plugin not installed
|
|
39
|
+
* → same as above
|
|
40
|
+
* → ALSO write settings.json to register dna-hook events
|
|
41
|
+
*/
|
|
42
|
+
export declare function detectMode(): Promise<"plugin" | "bin">;
|
|
30
43
|
export declare function runSync(opts: SyncOptions): Promise<number>;
|
|
31
|
-
//# sourceMappingURL=sync.d.ts.map
|
|
@@ -17,14 +17,41 @@ import { fileURLToPath } from "node:url";
|
|
|
17
17
|
import { createInterface } from "node:readline";
|
|
18
18
|
import { loadDNA, compileFromFiles } from "../../compiler/index.js";
|
|
19
19
|
import { compileToMarkdown, injectIntoFile, removeFromFile } from "../../runtime/markdown.js";
|
|
20
|
-
import { compileToHooks, writeHookScripts, removeHookScripts } from "../../runtime/hooks.js";
|
|
21
20
|
import { compileAllRolesToAgentMD, writeAgentMDFiles, removeAgentMDFiles } from "../../runtime/agent-md.js";
|
|
22
21
|
import { removeWorkflowScripts } from "../../runtime/workflow-runner.js";
|
|
23
22
|
import { compileWorkflowToSkill, writeSkillFiles } from "../../runtime/skill-adapter.js";
|
|
24
|
-
import {
|
|
23
|
+
import { compilePluginSettings, detectEnabledEvents, mergeSettingsFile } from "../../runtime/settings-adapter.js";
|
|
24
|
+
import { createCompiledIR, writeCompiledIR } from "../../runtime/plugin-adapter.js";
|
|
25
25
|
import { cascadeDNA } from "../../compiler/cascade.js";
|
|
26
26
|
import { EvolutionEngine } from "../../evolution/index.js";
|
|
27
27
|
const VALID_TARGETS = ["claude-md", "soul-md", "cursorrules", "system-prompt"];
|
|
28
|
+
/**
|
|
29
|
+
* Detect whether intentdna is running as a Claude Code plugin or standalone binary.
|
|
30
|
+
*
|
|
31
|
+
* Plugin mode: claude plugin system manages hook dispatch
|
|
32
|
+
* → generate ir.json + agents + skills + .mcp.json
|
|
33
|
+
* → do NOT write settings.json (hooks provided by plugin framework)
|
|
34
|
+
*
|
|
35
|
+
* Bin mode: fallback when plugin not installed
|
|
36
|
+
* → same as above
|
|
37
|
+
* → ALSO write settings.json to register dna-hook events
|
|
38
|
+
*/
|
|
39
|
+
export async function detectMode() {
|
|
40
|
+
// Check: is intentdna registered as a Claude Code plugin?
|
|
41
|
+
try {
|
|
42
|
+
const { execSync } = await import("node:child_process");
|
|
43
|
+
const result = execSync("claude plugin list 2>/dev/null", {
|
|
44
|
+
encoding: "utf-8",
|
|
45
|
+
timeout: 5000,
|
|
46
|
+
});
|
|
47
|
+
if (result.includes("intentdna"))
|
|
48
|
+
return "plugin";
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// claude CLI not available or plugin not registered
|
|
52
|
+
}
|
|
53
|
+
return "bin";
|
|
54
|
+
}
|
|
28
55
|
async function fileExists(path) {
|
|
29
56
|
try {
|
|
30
57
|
await stat(path);
|
|
@@ -35,6 +62,33 @@ async function fileExists(path) {
|
|
|
35
62
|
}
|
|
36
63
|
}
|
|
37
64
|
const DNA_SENTINEL = "intentdna:managed";
|
|
65
|
+
const LEGACY_BASH_HOOKS = [
|
|
66
|
+
"dna-pre-tool-use.sh",
|
|
67
|
+
"dna-post-tool-use.sh",
|
|
68
|
+
"dna-user-prompt-submit.sh",
|
|
69
|
+
"dna-subagent-stop.sh",
|
|
70
|
+
"dna-pre-compact.sh",
|
|
71
|
+
"dna-notification.sh",
|
|
72
|
+
];
|
|
73
|
+
/**
|
|
74
|
+
* Remove legacy bash hook scripts written by previous Intent DNA versions.
|
|
75
|
+
* Only removes files that contain the sentinel comment.
|
|
76
|
+
*/
|
|
77
|
+
async function removeLegacyBashHooks(hooksDir) {
|
|
78
|
+
let removed = 0;
|
|
79
|
+
for (const file of LEGACY_BASH_HOOKS) {
|
|
80
|
+
const path = resolve(hooksDir, file);
|
|
81
|
+
try {
|
|
82
|
+
const content = await readFile(path, "utf-8");
|
|
83
|
+
if (content.includes("intentdna:managed")) {
|
|
84
|
+
await unlink(path);
|
|
85
|
+
removed++;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch { /* File doesn't exist, skip */ }
|
|
89
|
+
}
|
|
90
|
+
return removed;
|
|
91
|
+
}
|
|
38
92
|
/**
|
|
39
93
|
* Remove stale DNA-managed files from a directory.
|
|
40
94
|
* Scans for files/dirs containing the sentinel marker and deletes them.
|
|
@@ -212,11 +266,18 @@ export async function runSync(opts) {
|
|
|
212
266
|
const hasClaudeMd = await fileExists(resolve(cwd, "CLAUDE.md"));
|
|
213
267
|
if (hasClaudeDir || hasClaudeMd || opts.files.length > 0) {
|
|
214
268
|
opts.inject = resolve(cwd, "CLAUDE.md");
|
|
215
|
-
opts.hooksDir = resolve(cwd, ".claude", "hooks");
|
|
216
269
|
opts.agentsDir = resolve(cwd, ".claude", "agents");
|
|
217
270
|
opts.skillsDir = resolve(cwd, ".claude", "skills");
|
|
218
271
|
opts.settingsPath = resolve(cwd, ".claude", "settings.json");
|
|
219
|
-
process.stderr.write(`Auto-detect: Claude Code → CLAUDE.md +
|
|
272
|
+
process.stderr.write(`Auto-detect: Claude Code → CLAUDE.md + agents + skills + settings\n`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
// Auto-detect plugin vs bin mode if --plugin not explicitly set
|
|
276
|
+
if (!opts.remove && opts.plugin === undefined) {
|
|
277
|
+
const mode = await detectMode();
|
|
278
|
+
if (mode === "plugin") {
|
|
279
|
+
opts.plugin = true;
|
|
280
|
+
process.stderr.write("Auto-detect: plugin mode (intentdna registered as Claude Code plugin)\n");
|
|
220
281
|
}
|
|
221
282
|
}
|
|
222
283
|
// Handle --remove
|
|
@@ -235,12 +296,12 @@ export async function runSync(opts) {
|
|
|
235
296
|
}
|
|
236
297
|
}
|
|
237
298
|
if (opts.hooksDir) {
|
|
238
|
-
const count = await
|
|
299
|
+
const count = await removeLegacyBashHooks(opts.hooksDir);
|
|
239
300
|
if (count > 0) {
|
|
240
|
-
process.stderr.write(`Removed ${count}
|
|
301
|
+
process.stderr.write(`Removed ${count} legacy bash hook(s) from ${opts.hooksDir}\n`);
|
|
241
302
|
}
|
|
242
303
|
else {
|
|
243
|
-
process.stderr.write(`No
|
|
304
|
+
process.stderr.write(`No legacy bash hooks found in ${opts.hooksDir}\n`);
|
|
244
305
|
}
|
|
245
306
|
}
|
|
246
307
|
if (opts.agentsDir) {
|
|
@@ -314,26 +375,37 @@ export async function runSync(opts) {
|
|
|
314
375
|
}
|
|
315
376
|
trackedOutputs.push(resolve(opts.inject));
|
|
316
377
|
}
|
|
317
|
-
// Step
|
|
318
|
-
|
|
319
|
-
const
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
}
|
|
378
|
+
// Step 3.5: Write compiled IR (needed for both plugin and bin mode)
|
|
379
|
+
{
|
|
380
|
+
const cwd = process.cwd();
|
|
381
|
+
const dnas = await Promise.all(expandedFiles.map(loadDNA));
|
|
382
|
+
const cascadedForIR = cascadeDNA(dnas);
|
|
383
|
+
const roles = cascadedForIR.roles;
|
|
384
|
+
const compiled = createCompiledIR(ir, roles);
|
|
385
|
+
const irPath = await writeCompiledIR(cwd, compiled);
|
|
386
|
+
process.stderr.write(`Wrote compiled IR: ${irPath}\n`);
|
|
387
|
+
trackedOutputs.push(resolve(irPath));
|
|
388
|
+
// Clean up old bash hooks if they exist
|
|
389
|
+
const oldHooksDir = resolve(cwd, ".claude", "hooks");
|
|
390
|
+
const removed = await removeLegacyBashHooks(oldHooksDir);
|
|
391
|
+
if (removed > 0) {
|
|
392
|
+
process.stderr.write(`Cleaned ${removed} legacy bash hook(s) from ${oldHooksDir}\n`);
|
|
332
393
|
}
|
|
333
|
-
|
|
334
|
-
|
|
394
|
+
}
|
|
395
|
+
// Step 3.6: Register hooks in settings.json (bin mode only)
|
|
396
|
+
// Plugin mode: hooks managed by plugin framework — skip settings.json
|
|
397
|
+
if (!opts.plugin && opts.settingsPath) {
|
|
398
|
+
const enabledEvents = detectEnabledEvents(ir);
|
|
399
|
+
if (enabledEvents.length > 0) {
|
|
400
|
+
const pluginSettings = compilePluginSettings(enabledEvents);
|
|
401
|
+
await mergeSettingsFile(pluginSettings, opts.settingsPath);
|
|
402
|
+
process.stderr.write(`Bin mode: registered ${enabledEvents.length} hook event(s) in ${opts.settingsPath}\n`);
|
|
403
|
+
trackedOutputs.push(resolve(opts.settingsPath));
|
|
335
404
|
}
|
|
336
405
|
}
|
|
406
|
+
else if (opts.plugin && opts.settingsPath) {
|
|
407
|
+
process.stderr.write(`Plugin mode: hooks managed by plugin framework (skipping settings.json)\n`);
|
|
408
|
+
}
|
|
337
409
|
// Step 5: Generate agent MD files
|
|
338
410
|
if (opts.agentsDir) {
|
|
339
411
|
// Clean stale DNA-managed agents before regenerating
|
|
@@ -414,6 +486,20 @@ export async function runSync(opts) {
|
|
|
414
486
|
}
|
|
415
487
|
const configPath = await autoDetectDNA();
|
|
416
488
|
const variables = await resolveVariables(rawVars, configPath);
|
|
489
|
+
// Step 8: Generate .claude/.mcp.json from MCP dependencies (inside skillsDir block, shares variables)
|
|
490
|
+
{
|
|
491
|
+
const mcpDeps = {};
|
|
492
|
+
for (const d of dnas) {
|
|
493
|
+
if (d.mcp)
|
|
494
|
+
Object.assign(mcpDeps, d.mcp);
|
|
495
|
+
}
|
|
496
|
+
if (Object.keys(mcpDeps).length > 0) {
|
|
497
|
+
const cwd = process.cwd();
|
|
498
|
+
const mcpJsonPath = resolve(cwd, ".claude", ".mcp.json");
|
|
499
|
+
await writeMCPConfig(mcpDeps, mcpJsonPath, variables);
|
|
500
|
+
process.stderr.write(`MCP: wrote ${Object.keys(mcpDeps).length} server(s) to ${mcpJsonPath}\n`);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
417
503
|
if (Object.keys(workflows).length === 0) {
|
|
418
504
|
process.stderr.write("No workflow defined — no skills to generate\n");
|
|
419
505
|
}
|
|
@@ -436,14 +522,6 @@ export async function runSync(opts) {
|
|
|
436
522
|
}
|
|
437
523
|
}
|
|
438
524
|
}
|
|
439
|
-
// Step 8: Generate/merge settings file
|
|
440
|
-
if (opts.settingsPath && opts.hooksDir) {
|
|
441
|
-
const hookScripts = compileToHooks(ir);
|
|
442
|
-
const dnaSettings = compileSettingsFromHooks(opts.hooksDir, hookScripts);
|
|
443
|
-
await mergeSettingsFile(dnaSettings, opts.settingsPath);
|
|
444
|
-
process.stderr.write(`Merged DNA hook config into ${opts.settingsPath}\n`);
|
|
445
|
-
trackedOutputs.push(resolve(opts.settingsPath));
|
|
446
|
-
}
|
|
447
525
|
// Also output the compiled content to stderr for visibility
|
|
448
526
|
const directiveCount = ir.prompt_directives.length;
|
|
449
527
|
const gateCount = ir.pre_execution_gates.length;
|
|
@@ -462,4 +540,51 @@ export async function runSync(opts) {
|
|
|
462
540
|
return 1;
|
|
463
541
|
}
|
|
464
542
|
}
|
|
465
|
-
|
|
543
|
+
/**
|
|
544
|
+
* Write MCP server configuration to .claude/.mcp.json.
|
|
545
|
+
* Merges with existing config — DNA-declared servers are added/updated,
|
|
546
|
+
* but existing user-configured servers are NOT overwritten.
|
|
547
|
+
*/
|
|
548
|
+
async function writeMCPConfig(mcpDeps, mcpJsonPath, variables) {
|
|
549
|
+
// Read existing .mcp.json
|
|
550
|
+
let existing = {};
|
|
551
|
+
try {
|
|
552
|
+
const raw = await readFile(mcpJsonPath, "utf-8");
|
|
553
|
+
existing = JSON.parse(raw);
|
|
554
|
+
}
|
|
555
|
+
catch { /* doesn't exist yet */ }
|
|
556
|
+
const mcpServers = (existing.mcpServers ?? {});
|
|
557
|
+
for (const [name, server] of Object.entries(mcpDeps)) {
|
|
558
|
+
// Don't overwrite existing user-configured servers
|
|
559
|
+
if (mcpServers[name])
|
|
560
|
+
continue;
|
|
561
|
+
const entry = {};
|
|
562
|
+
if (server.command) {
|
|
563
|
+
entry.command = server.command;
|
|
564
|
+
if (server.args)
|
|
565
|
+
entry.args = server.args;
|
|
566
|
+
}
|
|
567
|
+
if (server.url) {
|
|
568
|
+
entry.url = server.url;
|
|
569
|
+
}
|
|
570
|
+
if (server.env) {
|
|
571
|
+
// Substitute {{variable}} placeholders
|
|
572
|
+
const resolvedEnv = {};
|
|
573
|
+
for (const [k, v] of Object.entries(server.env)) {
|
|
574
|
+
resolvedEnv[k] = substituteVariables(v, variables);
|
|
575
|
+
}
|
|
576
|
+
entry.env = resolvedEnv;
|
|
577
|
+
}
|
|
578
|
+
if (server.timeout) {
|
|
579
|
+
entry.timeout = server.timeout;
|
|
580
|
+
}
|
|
581
|
+
mcpServers[name] = entry;
|
|
582
|
+
}
|
|
583
|
+
existing.mcpServers = mcpServers;
|
|
584
|
+
await mkdir(dirname(mcpJsonPath), { recursive: true });
|
|
585
|
+
await writeFileAsync(mcpJsonPath, JSON.stringify(existing, null, 2) + "\n", "utf-8");
|
|
586
|
+
}
|
|
587
|
+
/** Replace {{var}} placeholders with resolved variable values */
|
|
588
|
+
function substituteVariables(template, vars) {
|
|
589
|
+
return template.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? `{{${key}}}`);
|
|
590
|
+
}
|
|
@@ -30,4 +30,3 @@ export declare function sha256(content: string): string;
|
|
|
30
30
|
export declare function parseLockFile(raw: string): LockFile;
|
|
31
31
|
export declare function verifyLock(lock: LockFile): Promise<VerifyResult[]>;
|
|
32
32
|
export declare function runVerify(opts: VerifyOptions): Promise<number>;
|
|
33
|
-
//# sourceMappingURL=verify.d.ts.map
|
package/dist/cli/index.d.ts
CHANGED
package/dist/cli/index.js
CHANGED
|
@@ -17,6 +17,7 @@ const HELP = `Intent DNA CLI v0.3.0
|
|
|
17
17
|
Usage: dna <command> [options]
|
|
18
18
|
|
|
19
19
|
Commands:
|
|
20
|
+
setup Register intentdna as a Claude Code plugin (auto-detect mode)
|
|
20
21
|
guard Zero-config guardrails — detect environment, apply safety rules
|
|
21
22
|
sync Compile + inject DNA into target file (CLAUDE.md, SOUL.md, etc.)
|
|
22
23
|
verify Verify synced files match .dna/lock checksums (drift detection)
|
|
@@ -87,6 +88,7 @@ async function main() {
|
|
|
87
88
|
settings: { type: "string" },
|
|
88
89
|
lock: { type: "string", default: ".dna/lock" },
|
|
89
90
|
remove: { type: "boolean", default: false },
|
|
91
|
+
plugin: { type: "boolean", default: false },
|
|
90
92
|
},
|
|
91
93
|
allowPositionals: true,
|
|
92
94
|
strict: false,
|
|
@@ -108,6 +110,7 @@ async function main() {
|
|
|
108
110
|
settingsPath: values.settings,
|
|
109
111
|
lockFile: values.lock,
|
|
110
112
|
remove: values.remove,
|
|
113
|
+
plugin: values.plugin,
|
|
111
114
|
});
|
|
112
115
|
process.exit(code);
|
|
113
116
|
break;
|
|
@@ -353,6 +356,12 @@ async function main() {
|
|
|
353
356
|
process.exit(code);
|
|
354
357
|
break;
|
|
355
358
|
}
|
|
359
|
+
case "setup": {
|
|
360
|
+
const { runSetup } = await import("./commands/setup.js");
|
|
361
|
+
const code = await runSetup({});
|
|
362
|
+
process.exit(code);
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
356
365
|
default:
|
|
357
366
|
process.stderr.write(`Unknown command: ${command}\n\n`);
|
|
358
367
|
process.stderr.write(HELP);
|
|
@@ -363,4 +372,3 @@ main().catch((err) => {
|
|
|
363
372
|
process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
364
373
|
process.exit(1);
|
|
365
374
|
});
|
|
366
|
-
//# sourceMappingURL=index.js.map
|
package/dist/cli/util/format.js
CHANGED
|
@@ -8,4 +8,3 @@ export declare function askString(question: string, defaultVal?: string): Promis
|
|
|
8
8
|
export declare function askNumber(question: string, defaultVal: number): Promise<number>;
|
|
9
9
|
export declare function askChoice(question: string, choices: string[], defaultVal?: string): Promise<string>;
|
|
10
10
|
export declare function askYesNo(question: string, defaultVal: boolean): Promise<boolean>;
|
|
11
|
-
//# sourceMappingURL=prompt.d.ts.map
|
package/dist/cli/util/prompt.js
CHANGED
|
@@ -26,4 +26,3 @@ export interface ActivatedGene {
|
|
|
26
26
|
* Returns the final gene expression state ready for compilation to IR.
|
|
27
27
|
*/
|
|
28
28
|
export declare function activateDNA(cascaded: CascadedDNA, contextName?: string | null, activeRole?: string | null): ActivatedDNA;
|
|
29
|
-
//# sourceMappingURL=activate.d.ts.map
|