@directive-run/cli 0.2.0 → 0.5.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/dist/cli.js CHANGED
@@ -1,124 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import * as p from '@clack/prompts';
3
- import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync } from 'fs';
4
- import { join, relative, dirname, resolve } from 'path';
5
- import pc5 from 'picocolors';
6
- import { getAllExamples, getExample, getKnowledge } from '@directive-run/knowledge';
7
-
8
- // src/lib/constants.ts
9
- var CLI_NAME = "directive";
10
- var SECTION_START = "<!-- directive:start -->";
11
- var SECTION_END = "<!-- directive:end -->";
12
- var TOOL_SIGNALS = [
13
- {
14
- id: "cursor",
15
- name: "Cursor",
16
- signals: [".cursor", ".cursorrules"],
17
- outputPath: ".cursorrules"
18
- },
19
- {
20
- id: "claude",
21
- name: "Claude Code",
22
- signals: [".claude"],
23
- outputPath: ".claude/CLAUDE.md"
24
- },
25
- {
26
- id: "copilot",
27
- name: "GitHub Copilot",
28
- signals: [".github"],
29
- outputPath: ".github/copilot-instructions.md"
30
- },
31
- {
32
- id: "windsurf",
33
- name: "Windsurf",
34
- signals: [".windsurfrules"],
35
- outputPath: ".windsurfrules"
36
- },
37
- {
38
- id: "cline",
39
- name: "Cline",
40
- signals: [".clinerules"],
41
- outputPath: ".clinerules"
42
- }
43
- ];
44
- function detectTools(rootDir) {
45
- const detected = [];
46
- for (const tool of TOOL_SIGNALS) {
47
- const hasSignal = tool.signals.some(
48
- (signal) => existsSync(join(rootDir, signal))
49
- );
50
- if (hasSignal) {
51
- detected.push({
52
- name: tool.name,
53
- id: tool.id,
54
- outputPath: join(rootDir, tool.outputPath)
55
- });
56
- }
57
- }
58
- return detected;
59
- }
60
- function getToolConfig(id) {
61
- const tool = TOOL_SIGNALS.find((t) => t.id === id);
62
- if (!tool) {
63
- throw new Error(`Unknown tool: ${id}`);
64
- }
65
- return tool;
66
- }
67
- function getAllToolIds() {
68
- return TOOL_SIGNALS.map((t) => t.id);
69
- }
2
+ import*as u from'@clack/prompts';import {existsSync,mkdirSync,writeFileSync,readFileSync,readdirSync}from'fs';import {join,relative,dirname,resolve}from'path';import d from'picocolors';import {getAllExamples,getExample,getKnowledge}from'@directive-run/knowledge';var y="directive";var _="<!-- directive:start -->",W="<!-- directive:end -->";var J=[{id:"cursor",name:"Cursor",signals:[".cursor",".cursorrules"],outputPath:".cursorrules"},{id:"claude",name:"Claude Code",signals:[".claude"],outputPath:".claude/CLAUDE.md"},{id:"copilot",name:"GitHub Copilot",signals:[".github"],outputPath:".github/copilot-instructions.md"},{id:"windsurf",name:"Windsurf",signals:[".windsurfrules"],outputPath:".windsurfrules"},{id:"cline",name:"Cline",signals:[".clinerules"],outputPath:".clinerules"}];function ae(e){let t=[];for(let r of J)r.signals.some(o=>existsSync(join(e,o)))&&t.push({name:r.name,id:r.id,outputPath:join(e,r.outputPath)});return t}function L(e){let t=J.find(r=>r.id===e);if(!t)throw new Error(`Unknown tool: ${e}`);return t}function ce(){return J.map(e=>e.id)}function I(e,t){let r=e.indexOf(_),s=e.indexOf(W),o=`${_}
3
+ ${t}
4
+ ${W}`;if(r!==-1&&s!==-1&&s>r)return e.slice(0,r)+o+e.slice(s+W.length);let i=e.endsWith(`
5
+ `)?`
6
+ `:`
70
7
 
71
- // src/lib/merge.ts
72
- function mergeSection(existingContent, newSection) {
73
- const startIdx = existingContent.indexOf(SECTION_START);
74
- const endIdx = existingContent.indexOf(SECTION_END);
75
- const wrapped = `${SECTION_START}
76
- ${newSection}
77
- ${SECTION_END}`;
78
- if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
79
- return existingContent.slice(0, startIdx) + wrapped + existingContent.slice(endIdx + SECTION_END.length);
80
- }
81
- const separator = existingContent.endsWith("\n") ? "\n" : "\n\n";
82
- return existingContent + separator + wrapped + "\n";
83
- }
84
- function hasDirectiveSection(content) {
85
- return content.includes(SECTION_START) && content.includes(SECTION_END);
86
- }
87
- var MONOREPO_SIGNALS = [
88
- { file: "pnpm-workspace.yaml", tool: "pnpm" },
89
- { file: "turbo.json", tool: "turbo" }
90
- ];
91
- function detectMonorepo(startDir) {
92
- let dir = resolve(startDir);
93
- while (dir !== dirname(dir)) {
94
- for (const signal of MONOREPO_SIGNALS) {
95
- if (existsSync(join(dir, signal.file))) {
96
- return { isMonorepo: true, rootDir: dir, tool: signal.tool };
97
- }
98
- }
99
- const pkgPath = join(dir, "package.json");
100
- if (existsSync(pkgPath)) {
101
- try {
102
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
103
- if (pkg.workspaces) {
104
- const tool = existsSync(join(dir, "yarn.lock")) ? "yarn" : "npm";
105
- return { isMonorepo: true, rootDir: dir, tool };
106
- }
107
- } catch {
108
- }
109
- }
110
- dir = dirname(dir);
111
- }
112
- return { isMonorepo: false, rootDir: startDir };
113
- }
114
-
115
- // src/templates/claude.ts
116
- function generateClaudeRules() {
117
- const corePatterns = getKnowledge("core-patterns");
118
- const antiPatterns = getKnowledge("anti-patterns");
119
- const naming = getKnowledge("naming");
120
- const schemaTypes = getKnowledge("schema-types");
121
- return `# Directive \u2014 Complete AI Coding Rules
8
+ `;return e+i+o+`
9
+ `}function P(e){return e.includes(_)&&e.includes(W)}var Fe=[{file:"pnpm-workspace.yaml",tool:"pnpm"},{file:"turbo.json",tool:"turbo"}];function ue(e){let t=resolve(e);for(;t!==dirname(t);){for(let s of Fe)if(existsSync(join(t,s.file)))return {isMonorepo:true,rootDir:t,tool:s.tool};let r=join(t,"package.json");if(existsSync(r))try{if(JSON.parse(readFileSync(r,"utf-8")).workspaces){let o=existsSync(join(t,"yarn.lock"))?"yarn":"npm";return {isMonorepo:!0,rootDir:t,tool:o}}}catch{}t=dirname(t);}return {isMonorepo:false,rootDir:e}}function me(){let e=getKnowledge("core-patterns"),t=getKnowledge("anti-patterns"),r=getKnowledge("naming"),s=getKnowledge("schema-types");return `# Directive \u2014 Complete AI Coding Rules
122
10
 
123
11
  > Constraint-driven runtime for TypeScript. Declare requirements, let the runtime resolve them.
124
12
  > https://directive.run | \`npm install @directive-run/core\`
@@ -126,13 +14,13 @@ function generateClaudeRules() {
126
14
 
127
15
  ## Core Patterns
128
16
 
129
- ${corePatterns}
17
+ ${e}
130
18
 
131
19
  ---
132
20
 
133
21
  ## Anti-Patterns (All 36)
134
22
 
135
- ${antiPatterns}
23
+ ${t}
136
24
 
137
25
  ### AI Package Anti-Patterns (21-36)
138
26
 
@@ -159,13 +47,13 @@ ${antiPatterns}
159
47
 
160
48
  ## Naming Conventions
161
49
 
162
- ${naming}
50
+ ${r}
163
51
 
164
52
  ---
165
53
 
166
54
  ## Schema Type Builders
167
55
 
168
- ${schemaTypes}
56
+ ${s}
169
57
 
170
58
  ---
171
59
 
@@ -338,120 +226,7 @@ for await (const chunk of streamResult.stream) {
338
226
  \`\`\`
339
227
 
340
228
  Backpressure: \`"buffer"\` (default), \`"block"\`, \`"drop"\`
341
- `;
342
- }
343
-
344
- // src/templates/cursor.ts
345
- function generateCursorRules() {
346
- return `# Directive \u2014 AI Coding Rules
347
-
348
- > Constraint-driven runtime for TypeScript. \`npm install @directive-run/core\`
349
- > Full reference: https://directive.run/llms.txt
350
-
351
- ## Schema Shape (CRITICAL)
352
-
353
- \`\`\`typescript
354
- import { createModule, createSystem, t } from "@directive-run/core";
355
-
356
- const myModule = createModule("name", {
357
- schema: {
358
- facts: { count: t.number(), items: t.array<string>() },
359
- derivations: { total: "number" },
360
- events: { increment: "void", addItem: "string" },
361
- requirements: { FETCH_DATA: { url: "string" } },
362
- },
363
- init: (facts) => { facts.count = 0; facts.items = []; },
364
- derive: {
365
- total: (facts) => facts.items.length + facts.count,
366
- },
367
- events: {
368
- increment: (facts) => { facts.count += 1; },
369
- addItem: (facts, item) => { facts.items = [...facts.items, item]; },
370
- },
371
- constraints: {
372
- fetchWhenReady: {
373
- when: (facts) => facts.count > 0 && facts.items.length === 0,
374
- require: (facts) => ({ type: "FETCH_DATA", url: "/api/items" }),
375
- },
376
- },
377
- resolvers: {
378
- fetchData: {
379
- requirement: "FETCH_DATA",
380
- resolve: async (req, context) => {
381
- const data = await fetch(req.url).then(r => r.json());
382
- context.facts.items = data;
383
- },
384
- },
385
- },
386
- });
387
-
388
- const system = createSystem({ module: myModule });
389
- await system.settle();
390
- \`\`\`
391
-
392
- ## Top 10 Anti-Patterns
393
-
394
- | # | WRONG | CORRECT |
395
- |---|-------|---------|
396
- | 1 | \`facts.profile as ResourceState<Profile>\` | Remove cast \u2014 schema provides types |
397
- | 2 | \`{ phase: t.string() }\` flat schema | \`schema: { facts: { phase: t.string() } }\` |
398
- | 3 | \`facts.items\` in multi-module | \`facts.self.items\` |
399
- | 4 | \`t.map()\`, \`t.set()\`, \`t.promise()\` | Don't exist. Use \`t.object<Map<K,V>>()\` |
400
- | 5 | \`(req, ctx)\` in resolver | \`(req, context)\` \u2014 never abbreviate |
401
- | 6 | \`createModule("n", { phase: t.string() })\` | Must wrap: \`schema: { facts: { ... } }\` |
402
- | 7 | \`system.dispatch('login', {...})\` | \`system.events.login({...})\` |
403
- | 8 | \`facts.items.push(item)\` | \`facts.items = [...facts.items, item]\` |
404
- | 9 | \`useDirective(system)\` | \`useSelector(system, s => s.facts.count)\` |
405
- | 10 | \`facts['auth::status']\` | \`facts.auth.status\` dot notation |
406
-
407
- ## Naming
408
-
409
- - \`req\` = requirement (not request). Parameter: \`(req, context)\`
410
- - \`derive\` / derivations \u2014 never "computed" or "selectors"
411
- - Resolvers return \`void\` \u2014 mutate \`context.facts\` instead
412
- - Always use braces for returns: \`if (x) { return y; }\`
413
- - Multi-module: \`facts.self.fieldName\` for own module facts
414
- - Events: \`system.events.eventName(payload)\` \u2014 not \`system.dispatch()\`
415
- - Import from main: \`import { createModule } from '@directive-run/core'\`
416
-
417
- ## Schema Types That Exist
418
-
419
- \`t.string<T>()\`, \`t.number()\`, \`t.boolean()\`, \`t.array<T>()\`, \`t.object<T>()\`,
420
- \`t.enum("a","b")\`, \`t.literal(value)\`, \`t.nullable(inner)\`, \`t.optional(inner)\`, \`t.union(...)\`
421
-
422
- Chainable: \`.default()\`, \`.validate()\`, \`.transform()\`, \`.brand<>()\`, \`.refine()\`
423
-
424
- **DO NOT USE** (hallucinations): \`t.map()\`, \`t.set()\`, \`t.date()\`, \`t.tuple()\`, \`t.record()\`, \`t.promise()\`, \`t.any()\`
425
-
426
- ## Key Pattern: Constraint \u2192 Requirement \u2192 Resolver
427
-
428
- When the user wants "do X when Y": create THREE things:
429
- 1. **Constraint**: \`when: (facts) => Y_condition\` \u2192 \`require: { type: "DO_X" }\`
430
- 2. **Resolver**: handles "DO_X", calls API, sets \`context.facts\`
431
- 3. They are **decoupled**. Constraint declares need, resolver fulfills it.
432
- `;
433
- }
434
-
435
- // src/templates/copilot.ts
436
- function generateCopilotRules() {
437
- const base = generateCursorRules();
438
- const extraAntiPatterns = `
439
- ## Anti-Patterns 11-20
440
-
441
- | # | WRONG | CORRECT |
442
- |---|-------|---------|
443
- | 11 | \`module("name").schema({...}).build()\` | Prefer \`createModule("name", {...})\` object syntax |
444
- | 12 | Returning data from \`resolve\` | Resolvers return \`void\` \u2014 mutate \`context.facts\` |
445
- | 13 | Async logic in \`init\` | \`init\` is synchronous, facts assignment only |
446
- | 14 | \`await system.start()\` without settle | Add \`await system.settle()\` after start |
447
- | 15 | Missing \`crossModuleDeps\` | Declare \`crossModuleDeps: { auth: authSchema }\` |
448
- | 16 | \`require: "TYPE"\` string literal | \`require: { type: "TYPE" }\` object form |
449
- | 17 | Passthrough derivation \`(f) => f.count\` | Remove \u2014 read fact directly |
450
- | 18 | \`from '@directive-run/core/module'\` | \`from '@directive-run/core'\` (main export) |
451
- | 19 | \`async when()\` without \`deps\` | Add \`deps: ['factName']\` for async constraints |
452
- | 20 | No error boundary on resolver | Use try-catch or module error boundary config |
453
- `;
454
- const multiModule = `
229
+ `}function z(){return '# Directive \u2014 AI Coding Rules\n\n> Constraint-driven runtime for TypeScript. `npm install @directive-run/core`\n> Full reference: https://directive.run/llms.txt\n\n## Schema Shape (CRITICAL)\n\n```typescript\nimport { createModule, createSystem, t } from "@directive-run/core";\n\nconst myModule = createModule("name", {\n schema: {\n facts: { count: t.number(), items: t.array<string>() },\n derivations: { total: "number" },\n events: { increment: "void", addItem: "string" },\n requirements: { FETCH_DATA: { url: "string" } },\n },\n init: (facts) => { facts.count = 0; facts.items = []; },\n derive: {\n total: (facts) => facts.items.length + facts.count,\n },\n events: {\n increment: (facts) => { facts.count += 1; },\n addItem: (facts, item) => { facts.items = [...facts.items, item]; },\n },\n constraints: {\n fetchWhenReady: {\n when: (facts) => facts.count > 0 && facts.items.length === 0,\n require: (facts) => ({ type: "FETCH_DATA", url: "/api/items" }),\n },\n },\n resolvers: {\n fetchData: {\n requirement: "FETCH_DATA",\n resolve: async (req, context) => {\n const data = await fetch(req.url).then(r => r.json());\n context.facts.items = data;\n },\n },\n },\n});\n\nconst system = createSystem({ module: myModule });\nawait system.settle();\n```\n\n## Top 10 Anti-Patterns\n\n| # | WRONG | CORRECT |\n|---|-------|---------|\n| 1 | `facts.profile as ResourceState<Profile>` | Remove cast \u2014 schema provides types |\n| 2 | `{ phase: t.string() }` flat schema | `schema: { facts: { phase: t.string() } }` |\n| 3 | `facts.items` in multi-module | `facts.self.items` |\n| 4 | `t.map()`, `t.set()`, `t.promise()` | Don\'t exist. Use `t.object<Map<K,V>>()` |\n| 5 | `(req, ctx)` in resolver | `(req, context)` \u2014 never abbreviate |\n| 6 | `createModule("n", { phase: t.string() })` | Must wrap: `schema: { facts: { ... } }` |\n| 7 | `system.dispatch(\'login\', {...})` | `system.events.login({...})` |\n| 8 | `facts.items.push(item)` | `facts.items = [...facts.items, item]` |\n| 9 | `useDirective(system)` | `useSelector(system, s => s.facts.count)` |\n| 10 | `facts[\'auth::status\']` | `facts.auth.status` dot notation |\n\n## Naming\n\n- `req` = requirement (not request). Parameter: `(req, context)`\n- `derive` / derivations \u2014 never "computed" or "selectors"\n- Resolvers return `void` \u2014 mutate `context.facts` instead\n- Always use braces for returns: `if (x) { return y; }`\n- Multi-module: `facts.self.fieldName` for own module facts\n- Events: `system.events.eventName(payload)` \u2014 not `system.dispatch()`\n- Import from main: `import { createModule } from \'@directive-run/core\'`\n\n## Schema Types That Exist\n\n`t.string<T>()`, `t.number()`, `t.boolean()`, `t.array<T>()`, `t.object<T>()`,\n`t.enum("a","b")`, `t.literal(value)`, `t.nullable(inner)`, `t.optional(inner)`, `t.union(...)`\n\nChainable: `.default()`, `.validate()`, `.transform()`, `.brand<>()`, `.refine()`\n\n**DO NOT USE** (hallucinations): `t.map()`, `t.set()`, `t.date()`, `t.tuple()`, `t.record()`, `t.promise()`, `t.any()`\n\n## Key Pattern: Constraint \u2192 Requirement \u2192 Resolver\n\nWhen the user wants "do X when Y": create THREE things:\n1. **Constraint**: `when: (facts) => Y_condition` \u2192 `require: { type: "DO_X" }`\n2. **Resolver**: handles "DO_X", calls API, sets `context.facts`\n3. They are **decoupled**. Constraint declares need, resolver fulfills it.\n'}function E(){return z()+'\n## Anti-Patterns 11-20\n\n| # | WRONG | CORRECT |\n|---|-------|---------|\n| 11 | `module("name").schema({...}).build()` | Prefer `createModule("name", {...})` object syntax |\n| 12 | Returning data from `resolve` | Resolvers return `void` \u2014 mutate `context.facts` |\n| 13 | Async logic in `init` | `init` is synchronous, facts assignment only |\n| 14 | `await system.start()` without settle | Add `await system.settle()` after start |\n| 15 | Missing `crossModuleDeps` | Declare `crossModuleDeps: { auth: authSchema }` |\n| 16 | `require: "TYPE"` string literal | `require: { type: "TYPE" }` object form |\n| 17 | Passthrough derivation `(f) => f.count` | Remove \u2014 read fact directly |\n| 18 | `from \'@directive-run/core/module\'` | `from \'@directive-run/core\'` (main export) |\n| 19 | `async when()` without `deps` | Add `deps: [\'factName\']` for async constraints |\n| 20 | No error boundary on resolver | Use try-catch or module error boundary config |\n'+`
455
230
  ## Multi-Module
456
231
 
457
232
  \`\`\`typescript
@@ -463,8 +238,7 @@ const system = createSystem({
463
238
  // In constraints/resolvers: use facts.self.* for own module
464
239
  // Declare deps: crossModuleDeps: { auth: authSchema }
465
240
  \`\`\`
466
- `;
467
- const aiBasics = `
241
+ `+`
468
242
  ## AI Package Basics (\`@directive-run/ai\`)
469
243
 
470
244
  \`\`\`typescript
@@ -485,448 +259,10 @@ const result = await orchestrator.run(agent, "analyze this");
485
259
  - Subpath imports: \`from '@directive-run/ai/anthropic'\` not \`from '@directive-run/ai'\`
486
260
  - Token usage normalized: \`{ inputTokens, outputTokens }\` (not provider-specific)
487
261
  - \`facts.cache = [...facts.cache, item]\` not \`facts.cache.push(item)\`
488
- `;
489
- return base + extraAntiPatterns + multiModule + aiBasics;
490
- }
491
-
492
- // src/templates/cline.ts
493
- function generateClineRules() {
494
- return generateCopilotRules();
495
- }
496
-
497
- // src/templates/windsurf.ts
498
- function generateWindsurfRules() {
499
- return generateCopilotRules();
500
- }
501
-
502
- // src/templates/index.ts
503
- var generators = {
504
- cursor: generateCursorRules,
505
- claude: generateClaudeRules,
506
- copilot: generateCopilotRules,
507
- windsurf: generateWindsurfRules,
508
- cline: generateClineRules
509
- };
510
- function getTemplate(toolId) {
511
- const generator = generators[toolId];
512
- if (!generator) {
513
- throw new Error(`No template for tool: ${toolId}`);
514
- }
515
- return generator();
516
- }
517
-
518
- // src/commands/ai-rules.ts
519
- function parseArgs(args) {
520
- const opts = {
521
- force: false,
522
- merge: false,
523
- tools: [],
524
- dir: process.cwd()
525
- };
526
- for (let i = 0; i < args.length; i++) {
527
- const arg = args[i];
528
- switch (arg) {
529
- case "--force":
530
- opts.force = true;
531
- break;
532
- case "--merge":
533
- opts.merge = true;
534
- break;
535
- case "--tool": {
536
- const val = args[++i];
537
- if (val) {
538
- opts.tools.push(val);
539
- }
540
- break;
541
- }
542
- case "--dir": {
543
- const val = args[++i];
544
- if (val) {
545
- opts.dir = val;
546
- }
547
- break;
548
- }
549
- }
550
- }
551
- return opts;
552
- }
553
- async function aiRulesCommand(args) {
554
- const opts = parseArgs(args);
555
- p.intro(pc5.bgCyan(pc5.black(" directive ai-rules ")));
556
- const mono = detectMonorepo(opts.dir);
557
- let targetDir = opts.dir;
558
- if (mono.isMonorepo && mono.rootDir !== opts.dir) {
559
- const placement = await p.select({
560
- message: "Monorepo detected. Where should AI rules be installed?",
561
- options: [
562
- {
563
- value: "root",
564
- label: `Monorepo root (${relative(opts.dir, mono.rootDir) || "."})`,
565
- hint: "recommended"
566
- },
567
- {
568
- value: "workspace",
569
- label: `Current workspace (${relative(mono.rootDir, opts.dir)})`
570
- }
571
- ]
572
- });
573
- if (p.isCancel(placement)) {
574
- p.cancel("Cancelled.");
575
- process.exit(0);
576
- }
577
- if (placement === "root") {
578
- targetDir = mono.rootDir;
579
- }
580
- }
581
- let selectedTools;
582
- if (opts.tools.length > 0) {
583
- selectedTools = opts.tools.map((id) => {
584
- const config = getToolConfig(id);
585
- return {
586
- name: config.name,
587
- id: config.id,
588
- outputPath: join(targetDir, config.outputPath)
589
- };
590
- });
591
- } else {
592
- const detected = detectTools(targetDir);
593
- if (detected.length > 0) {
594
- const choices = await p.multiselect({
595
- message: `Detected ${detected.length} AI tool(s). Which should get Directive rules?`,
596
- options: detected.map((t) => ({
597
- value: t.id,
598
- label: t.name,
599
- hint: relative(targetDir, t.outputPath)
600
- })),
601
- initialValues: detected.map((t) => t.id),
602
- required: true
603
- });
604
- if (p.isCancel(choices)) {
605
- p.cancel("Cancelled.");
606
- process.exit(0);
607
- }
608
- selectedTools = choices.map((id) => {
609
- const config = getToolConfig(id);
610
- return {
611
- name: config.name,
612
- id: config.id,
613
- outputPath: join(targetDir, config.outputPath)
614
- };
615
- });
616
- } else {
617
- const choices = await p.multiselect({
618
- message: "No AI tools detected. Which tools do you use?",
619
- options: getAllToolIds().map((id) => {
620
- const config = getToolConfig(id);
621
- return { value: id, label: config.name };
622
- }),
623
- required: true
624
- });
625
- if (p.isCancel(choices)) {
626
- p.cancel("Cancelled.");
627
- process.exit(0);
628
- }
629
- selectedTools = choices.map((id) => {
630
- const config = getToolConfig(id);
631
- return {
632
- name: config.name,
633
- id: config.id,
634
- outputPath: join(targetDir, config.outputPath)
635
- };
636
- });
637
- }
638
- }
639
- if (selectedTools.length === 0) {
640
- p.cancel("No tools selected.");
641
- process.exit(0);
642
- }
643
- const s = p.spinner();
644
- for (const tool of selectedTools) {
645
- s.start(`Generating ${tool.name} rules...`);
646
- const content = getTemplate(tool.id);
647
- const filePath = tool.outputPath;
648
- const fileExists = existsSync(filePath);
649
- s.stop(`Generated ${tool.name} rules.`);
650
- if (fileExists && !opts.force) {
651
- const existingContent = readFileSync(filePath, "utf-8");
652
- if (opts.merge) {
653
- writeFile(filePath, mergeSection(existingContent, content));
654
- p.log.success(
655
- `${pc5.green("Merged")} Directive section into ${pc5.dim(relative(targetDir, filePath))}`
656
- );
657
- continue;
658
- }
659
- if (hasDirectiveSection(existingContent)) {
660
- const action = await p.select({
661
- message: `${relative(targetDir, filePath)} already has a Directive section. What should we do?`,
662
- options: [
663
- {
664
- value: "merge",
665
- label: "Update Directive section only",
666
- hint: "recommended"
667
- },
668
- { value: "overwrite", label: "Overwrite entire file" },
669
- { value: "skip", label: "Skip this file" }
670
- ]
671
- });
672
- if (p.isCancel(action)) {
673
- p.cancel("Cancelled.");
674
- process.exit(0);
675
- }
676
- if (action === "merge") {
677
- writeFile(filePath, mergeSection(existingContent, content));
678
- p.log.success(
679
- `${pc5.green("Updated")} ${pc5.dim(relative(targetDir, filePath))}`
680
- );
681
- } else if (action === "overwrite") {
682
- writeFile(filePath, content);
683
- p.log.success(
684
- `${pc5.green("Wrote")} ${pc5.dim(relative(targetDir, filePath))}`
685
- );
686
- } else {
687
- p.log.info(`Skipped ${pc5.dim(relative(targetDir, filePath))}`);
688
- }
689
- } else {
690
- const action = await p.select({
691
- message: `${relative(targetDir, filePath)} already exists. What should we do?`,
692
- options: [
693
- {
694
- value: "append",
695
- label: "Append Directive section",
696
- hint: "preserves existing content"
697
- },
698
- { value: "overwrite", label: "Overwrite entire file" },
699
- { value: "skip", label: "Skip this file" }
700
- ]
701
- });
702
- if (p.isCancel(action)) {
703
- p.cancel("Cancelled.");
704
- process.exit(0);
705
- }
706
- if (action === "append") {
707
- writeFile(filePath, mergeSection(existingContent, content));
708
- p.log.success(
709
- `${pc5.green("Appended")} to ${pc5.dim(relative(targetDir, filePath))}`
710
- );
711
- } else if (action === "overwrite") {
712
- writeFile(filePath, content);
713
- p.log.success(
714
- `${pc5.green("Wrote")} ${pc5.dim(relative(targetDir, filePath))}`
715
- );
716
- } else {
717
- p.log.info(`Skipped ${pc5.dim(relative(targetDir, filePath))}`);
718
- }
719
- }
720
- } else {
721
- writeFile(filePath, content);
722
- p.log.success(
723
- `${pc5.green("Created")} ${pc5.dim(relative(targetDir, filePath))}`
724
- );
725
- }
726
- }
727
- p.outro(
728
- `Done! Run ${pc5.cyan(`${CLI_NAME} ai-rules init --merge`)} anytime to update.`
729
- );
730
- }
731
- function writeFile(filePath, content) {
732
- const dir = dirname(filePath);
733
- if (!existsSync(dir)) {
734
- mkdirSync(dir, { recursive: true });
735
- }
736
- writeFileSync(filePath, content, "utf-8");
737
- }
738
- async function aiRulesUpdateCommand(args) {
739
- const opts = parseArgs(args);
740
- const targetDir = opts.dir;
741
- const ruleFiles = [
742
- { id: "cursor", path: join(targetDir, ".cursorrules") },
743
- { id: "claude", path: join(targetDir, ".claude/CLAUDE.md") },
744
- { id: "copilot", path: join(targetDir, ".github/copilot-instructions.md") },
745
- { id: "windsurf", path: join(targetDir, ".windsurfrules") },
746
- { id: "cline", path: join(targetDir, ".clinerules") }
747
- ];
748
- let updated = 0;
749
- for (const file of ruleFiles) {
750
- if (!existsSync(file.path)) {
751
- continue;
752
- }
753
- const existing = readFileSync(file.path, "utf-8");
754
- if (!hasDirectiveSection(existing)) {
755
- continue;
756
- }
757
- const newContent = getTemplate(file.id);
758
- const merged = mergeSection(existing, newContent);
759
- writeFile(file.path, merged);
760
- console.log(
761
- `${pc5.green("Updated")} ${pc5.dim(relative(targetDir, file.path))}`
762
- );
763
- updated++;
764
- }
765
- if (updated === 0) {
766
- console.log(
767
- pc5.dim(
768
- `No existing rule files found. Run ${pc5.cyan(`${CLI_NAME} ai-rules init`)} first.`
769
- )
770
- );
771
- } else {
772
- console.log(
773
- pc5.green(`
774
- Updated ${updated} file(s) to latest knowledge version.`)
775
- );
776
- }
777
- }
778
- async function aiRulesCheckCommand(args) {
779
- const opts = parseArgs(args);
780
- const targetDir = opts.dir;
781
- const ruleFiles = [
782
- { id: "cursor", path: join(targetDir, ".cursorrules"), name: "Cursor" },
783
- { id: "claude", path: join(targetDir, ".claude/CLAUDE.md"), name: "Claude Code" },
784
- { id: "copilot", path: join(targetDir, ".github/copilot-instructions.md"), name: "GitHub Copilot" },
785
- { id: "windsurf", path: join(targetDir, ".windsurfrules"), name: "Windsurf" },
786
- { id: "cline", path: join(targetDir, ".clinerules"), name: "Cline" }
787
- ];
788
- let checked = 0;
789
- let stale = 0;
790
- for (const file of ruleFiles) {
791
- if (!existsSync(file.path)) {
792
- continue;
793
- }
794
- const existing = readFileSync(file.path, "utf-8");
795
- if (!hasDirectiveSection(existing)) {
796
- continue;
797
- }
798
- checked++;
799
- const freshContent = getTemplate(file.id);
800
- const merged = mergeSection(existing, freshContent);
801
- if (merged !== existing) {
802
- console.log(`${pc5.red("\u2717")} ${file.name} rules are ${pc5.yellow("stale")}`);
803
- stale++;
804
- } else {
805
- console.log(`${pc5.green("\u2713")} ${file.name} rules are ${pc5.green("current")}`);
806
- }
807
- }
808
- if (checked === 0) {
809
- console.log(pc5.dim("No rule files found to check."));
810
- return;
811
- }
812
- if (stale > 0) {
813
- console.log(
814
- `
815
- ${pc5.yellow(`${stale} file(s) are stale.`)} Run ${pc5.cyan(`${CLI_NAME} ai-rules update`)} to refresh.`
816
- );
817
- process.exit(1);
818
- } else {
819
- console.log(pc5.green("\nAll rule files are current."));
820
- }
821
- }
822
- function parseArgs2(args) {
823
- const opts = {
824
- dir: process.cwd(),
825
- noInteractive: false
826
- };
827
- for (let i = 0; i < args.length; i++) {
828
- const arg = args[i];
829
- switch (arg) {
830
- case "--template": {
831
- const val = args[++i];
832
- if (val) {
833
- opts.template = val;
834
- }
835
- break;
836
- }
837
- case "--dir": {
838
- const val = args[++i];
839
- if (val) {
840
- opts.dir = val;
841
- }
842
- break;
843
- }
844
- case "--no-interactive":
845
- opts.noInteractive = true;
846
- break;
847
- }
848
- }
849
- return opts;
850
- }
851
- function detectPackageManager(dir) {
852
- if (existsSync(join(dir, "pnpm-lock.yaml"))) {
853
- return "pnpm";
854
- }
855
- if (existsSync(join(dir, "bun.lockb")) || existsSync(join(dir, "bun.lock"))) {
856
- return "bun";
857
- }
858
- if (existsSync(join(dir, "yarn.lock"))) {
859
- return "yarn";
860
- }
861
- return "npm";
862
- }
863
- function installCmd(pm, pkg) {
864
- switch (pm) {
865
- case "pnpm":
866
- return `pnpm add ${pkg}`;
867
- case "yarn":
868
- return `yarn add ${pkg}`;
869
- case "bun":
870
- return `bun add ${pkg}`;
871
- default:
872
- return `npm install ${pkg}`;
873
- }
874
- }
875
- function getTemplates(moduleName) {
876
- return {
877
- counter: {
878
- id: "counter",
879
- label: "Counter (minimal)",
880
- hint: "schema + init + derive + events \u2014 simplest starting point",
881
- files: [
882
- {
883
- path: `src/${moduleName}.ts`,
884
- content: generateCounterModule(moduleName)
885
- },
886
- {
887
- path: "src/main.ts",
888
- content: generateCounterMain(moduleName)
889
- }
890
- ],
891
- deps: ["@directive-run/core"]
892
- },
893
- "auth-flow": {
894
- id: "auth-flow",
895
- label: "Auth flow (constraints + resolvers)",
896
- hint: "login flow with constraints, resolvers, retry, and effects",
897
- files: [
898
- {
899
- path: `src/${moduleName}.ts`,
900
- content: generateAuthModule(moduleName)
901
- },
902
- {
903
- path: "src/main.ts",
904
- content: generateAuthMain(moduleName)
905
- }
906
- ],
907
- deps: ["@directive-run/core"]
908
- },
909
- "ai-orchestrator": {
910
- id: "ai-orchestrator",
911
- label: "AI orchestrator",
912
- hint: "agent orchestrator with guardrails and streaming",
913
- files: [
914
- {
915
- path: `src/${moduleName}.ts`,
916
- content: generateAIModule(moduleName)
917
- },
918
- {
919
- path: "src/main.ts",
920
- content: generateAIMain(moduleName)
921
- }
922
- ],
923
- deps: ["@directive-run/core", "@directive-run/ai"]
924
- }
925
- };
926
- }
927
- function generateCounterModule(name) {
928
- const camelName = toCamelCase(name);
929
- return `import { type ModuleSchema, createModule, t } from "@directive-run/core";
262
+ `}function pe(){return E()}function fe(){return E()}var ze={cursor:z,claude:me,copilot:E,windsurf:fe,cline:pe};function H(e){let t=ze[e];if(!t)throw new Error(`No template for tool: ${e}`);return t()}function te(e){let t={force:false,merge:false,tools:[],dir:process.cwd()};for(let r=0;r<e.length;r++)switch(e[r]){case "--force":t.force=true;break;case "--merge":t.merge=true;break;case "--tool":{let o=e[++r];o&&t.tools.push(o);break}case "--dir":{let o=e[++r];o&&(t.dir=o);break}}return t}async function ge(e){let t=te(e);u.intro(d.bgCyan(d.black(" directive ai-rules ")));let r=ue(t.dir),s=t.dir;if(r.isMonorepo&&r.rootDir!==t.dir){let n=await u.select({message:"Monorepo detected. Where should AI rules be installed?",options:[{value:"root",label:`Monorepo root (${relative(t.dir,r.rootDir)||"."})`,hint:"recommended"},{value:"workspace",label:`Current workspace (${relative(r.rootDir,t.dir)})`}]});u.isCancel(n)&&(u.cancel("Cancelled."),process.exit(0)),n==="root"&&(s=r.rootDir);}let o;if(t.tools.length>0)o=t.tools.map(n=>{let a=L(n);return {name:a.name,id:a.id,outputPath:join(s,a.outputPath)}});else {let n=ae(s);if(n.length>0){let a=await u.multiselect({message:`Detected ${n.length} AI tool(s). Which should get Directive rules?`,options:n.map(c=>({value:c.id,label:c.name,hint:relative(s,c.outputPath)})),initialValues:n.map(c=>c.id),required:true});u.isCancel(a)&&(u.cancel("Cancelled."),process.exit(0)),o=a.map(c=>{let m=L(c);return {name:m.name,id:m.id,outputPath:join(s,m.outputPath)}});}else {let a=await u.multiselect({message:"No AI tools detected. Which tools do you use?",options:ce().map(c=>{let m=L(c);return {value:c,label:m.name}}),required:true});u.isCancel(a)&&(u.cancel("Cancelled."),process.exit(0)),o=a.map(c=>{let m=L(c);return {name:m.name,id:m.id,outputPath:join(s,m.outputPath)}});}}o.length===0&&(u.cancel("No tools selected."),process.exit(0));let i=u.spinner();for(let n of o){i.start(`Generating ${n.name} rules...`);let a=H(n.id),c=n.outputPath,m=existsSync(c);if(i.stop(`Generated ${n.name} rules.`),m&&!t.force){let w=readFileSync(c,"utf-8");if(t.merge){T(c,I(w,a)),u.log.success(`${d.green("Merged")} Directive section into ${d.dim(relative(s,c))}`);continue}if(P(w)){let f=await u.select({message:`${relative(s,c)} already has a Directive section. What should we do?`,options:[{value:"merge",label:"Update Directive section only",hint:"recommended"},{value:"overwrite",label:"Overwrite entire file"},{value:"skip",label:"Skip this file"}]});u.isCancel(f)&&(u.cancel("Cancelled."),process.exit(0)),f==="merge"?(T(c,I(w,a)),u.log.success(`${d.green("Updated")} ${d.dim(relative(s,c))}`)):f==="overwrite"?(T(c,a),u.log.success(`${d.green("Wrote")} ${d.dim(relative(s,c))}`)):u.log.info(`Skipped ${d.dim(relative(s,c))}`);}else {let f=await u.select({message:`${relative(s,c)} already exists. What should we do?`,options:[{value:"append",label:"Append Directive section",hint:"preserves existing content"},{value:"overwrite",label:"Overwrite entire file"},{value:"skip",label:"Skip this file"}]});u.isCancel(f)&&(u.cancel("Cancelled."),process.exit(0)),f==="append"?(T(c,I(w,a)),u.log.success(`${d.green("Appended")} to ${d.dim(relative(s,c))}`)):f==="overwrite"?(T(c,a),u.log.success(`${d.green("Wrote")} ${d.dim(relative(s,c))}`)):u.log.info(`Skipped ${d.dim(relative(s,c))}`);}}else T(c,a),u.log.success(`${d.green("Created")} ${d.dim(relative(s,c))}`);}u.outro(`Done! Run ${d.cyan(`${y} ai-rules init --merge`)} anytime to update.`);}function T(e,t){let r=dirname(e);existsSync(r)||mkdirSync(r,{recursive:true}),writeFileSync(e,t,"utf-8");}async function he(e){let r=te(e).dir,s=[{id:"cursor",path:join(r,".cursorrules")},{id:"claude",path:join(r,".claude/CLAUDE.md")},{id:"copilot",path:join(r,".github/copilot-instructions.md")},{id:"windsurf",path:join(r,".windsurfrules")},{id:"cline",path:join(r,".clinerules")}],o=0;for(let i of s){if(!existsSync(i.path))continue;let n=readFileSync(i.path,"utf-8");if(!P(n))continue;let a=H(i.id),c=I(n,a);T(i.path,c),console.log(`${d.green("Updated")} ${d.dim(relative(r,i.path))}`),o++;}console.log(o===0?d.dim(`No existing rule files found. Run ${d.cyan(`${y} ai-rules init`)} first.`):d.green(`
263
+ Updated ${o} file(s) to latest knowledge version.`));}async function ye(e){let r=te(e).dir,s=[{id:"cursor",path:join(r,".cursorrules"),name:"Cursor"},{id:"claude",path:join(r,".claude/CLAUDE.md"),name:"Claude Code"},{id:"copilot",path:join(r,".github/copilot-instructions.md"),name:"GitHub Copilot"},{id:"windsurf",path:join(r,".windsurfrules"),name:"Windsurf"},{id:"cline",path:join(r,".clinerules"),name:"Cline"}],o=0,i=0;for(let n of s){if(!existsSync(n.path))continue;let a=readFileSync(n.path,"utf-8");if(!P(a))continue;o++;let c=H(n.id);I(a,c)!==a?(console.log(`${d.red("\u2717")} ${n.name} rules are ${d.yellow("stale")}`),i++):console.log(`${d.green("\u2713")} ${n.name} rules are ${d.green("current")}`);}if(o===0){console.log(d.dim("No rule files found to check."));return}i>0?(console.log(`
264
+ ${d.yellow(`${i} file(s) are stale.`)} Run ${d.cyan(`${y} ai-rules update`)} to refresh.`),process.exit(1)):console.log(d.green(`
265
+ All rule files are current.`));}function Qe(e){let t={dir:process.cwd(),noInteractive:false};for(let r=0;r<e.length;r++)switch(e[r]){case "--template":{let o=e[++r];o&&(t.template=o);break}case "--dir":{let o=e[++r];o&&(t.dir=o);break}case "--no-interactive":t.noInteractive=true;break}return t}function Ze(e){return existsSync(join(e,"pnpm-lock.yaml"))?"pnpm":existsSync(join(e,"bun.lockb"))||existsSync(join(e,"bun.lock"))?"bun":existsSync(join(e,"yarn.lock"))?"yarn":"npm"}function et(e,t){switch(e){case "pnpm":return `pnpm add ${t}`;case "yarn":return `yarn add ${t}`;case "bun":return `bun add ${t}`;default:return `npm install ${t}`}}function re(e){return {counter:{id:"counter",label:"Counter (minimal)",hint:"schema + init + derive + events \u2014 simplest starting point",files:[{path:`src/${e}.ts`,content:tt(e)},{path:"src/main.ts",content:rt(e)}],deps:["@directive-run/core"]},"auth-flow":{id:"auth-flow",label:"Auth flow (constraints + resolvers)",hint:"login flow with constraints, resolvers, retry, and effects",files:[{path:`src/${e}.ts`,content:st(e)},{path:"src/main.ts",content:nt(e)}],deps:["@directive-run/core"]},"ai-orchestrator":{id:"ai-orchestrator",label:"AI orchestrator",hint:"agent orchestrator with guardrails and streaming",files:[{path:`src/${e}.ts`,content:ot(e)},{path:"src/main.ts",content:it(e)}],deps:["@directive-run/core","@directive-run/ai"]}}}function tt(e){return `import { type ModuleSchema, createModule, t } from "@directive-run/core";
930
266
 
931
267
  const schema = {
932
268
  facts: {
@@ -945,12 +281,12 @@ const schema = {
945
281
  },
946
282
  } satisfies ModuleSchema;
947
283
 
948
- export const ${camelName} = createModule("${name}", {
284
+ export const ${j(e)} = createModule("${e}", {
949
285
  schema,
950
286
 
951
287
  init: (facts) => {
952
288
  facts.count = 0;
953
- facts.label = "${name}";
289
+ facts.label = "${e}";
954
290
  },
955
291
 
956
292
  derive: {
@@ -973,15 +309,11 @@ export const ${camelName} = createModule("${name}", {
973
309
  },
974
310
  },
975
311
  });
976
- `;
977
- }
978
- function generateCounterMain(name) {
979
- const camelName = toCamelCase(name);
980
- return `import { createSystem } from "@directive-run/core";
981
- import { ${camelName} } from "./${name}.js";
312
+ `}function rt(e){let t=j(e);return `import { createSystem } from "@directive-run/core";
313
+ import { ${t} } from "./${e}.js";
982
314
 
983
315
  const system = createSystem({
984
- module: ${camelName},
316
+ module: ${t},
985
317
  });
986
318
 
987
319
  system.start();
@@ -1003,11 +335,7 @@ system.events.increment();
1003
335
  system.events.increment();
1004
336
 
1005
337
  export default system;
1006
- `;
1007
- }
1008
- function generateAuthModule(name) {
1009
- const camelName = toCamelCase(name);
1010
- return `import { type ModuleSchema, createModule, t } from "@directive-run/core";
338
+ `}function st(e){return `import { type ModuleSchema, createModule, t } from "@directive-run/core";
1011
339
 
1012
340
  type AuthStatus = "idle" | "authenticating" | "authenticated" | "expired";
1013
341
 
@@ -1034,7 +362,7 @@ const schema = {
1034
362
  },
1035
363
  } satisfies ModuleSchema;
1036
364
 
1037
- export const ${camelName} = createModule("${name}", {
365
+ export const ${j(e)} = createModule("${e}", {
1038
366
  schema,
1039
367
 
1040
368
  init: (facts) => {
@@ -1111,15 +439,11 @@ export const ${camelName} = createModule("${name}", {
1111
439
  },
1112
440
  },
1113
441
  });
1114
- `;
1115
- }
1116
- function generateAuthMain(name) {
1117
- const camelName = toCamelCase(name);
1118
- return `import { createSystem } from "@directive-run/core";
1119
- import { ${camelName} } from "./${name}.js";
442
+ `}function nt(e){let t=j(e);return `import { createSystem } from "@directive-run/core";
443
+ import { ${t} } from "./${e}.js";
1120
444
 
1121
445
  const system = createSystem({
1122
- module: ${camelName},
446
+ module: ${t},
1123
447
  });
1124
448
 
1125
449
  system.start();
@@ -1136,11 +460,7 @@ console.log("authenticated:", system.read("isAuthenticated"));
1136
460
  console.log("token:", system.facts.token);
1137
461
 
1138
462
  export default system;
1139
- `;
1140
- }
1141
- function generateAIModule(name) {
1142
- const camelName = toCamelCase(name);
1143
- return `import { type ModuleSchema, createModule, t } from "@directive-run/core";
463
+ `}function ot(e){return `import { type ModuleSchema, createModule, t } from "@directive-run/core";
1144
464
  import {
1145
465
  createAgentOrchestrator,
1146
466
  createAgentMemory,
@@ -1174,7 +494,7 @@ const schema = {
1174
494
  },
1175
495
  } satisfies ModuleSchema;
1176
496
 
1177
- export const ${camelName} = createModule("${name}", {
497
+ export const ${j(e)} = createModule("${e}", {
1178
498
  schema,
1179
499
 
1180
500
  init: (facts) => {
@@ -1248,15 +568,11 @@ export const memory = createAgentMemory({
1248
568
  // maxTokenBudget: 50000,
1249
569
  // memory,
1250
570
  // });
1251
- `;
1252
- }
1253
- function generateAIMain(name) {
1254
- const camelName = toCamelCase(name);
1255
- return `import { createSystem } from "@directive-run/core";
1256
- import { ${camelName} } from "./${name}.js";
571
+ `}function it(e){let t=j(e);return `import { createSystem } from "@directive-run/core";
572
+ import { ${t} } from "./${e}.js";
1257
573
 
1258
574
  const system = createSystem({
1259
- module: ${camelName},
575
+ module: ${t},
1260
576
  });
1261
577
 
1262
578
  system.start();
@@ -1271,298 +587,79 @@ await system.settle();
1271
587
  console.log("output:", system.facts.output);
1272
588
 
1273
589
  export default system;
1274
- `;
1275
- }
1276
- function toCamelCase(name) {
1277
- return name.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
1278
- }
1279
- function writeFile2(filePath, content) {
1280
- const dir = dirname(filePath);
1281
- if (!existsSync(dir)) {
1282
- mkdirSync(dir, { recursive: true });
1283
- }
1284
- writeFileSync(filePath, content, "utf-8");
1285
- }
1286
- async function initCommand(args) {
1287
- const opts = parseArgs2(args);
1288
- p.intro(pc5.bgCyan(pc5.black(" directive init ")));
1289
- let moduleName;
1290
- if (opts.noInteractive) {
1291
- moduleName = "my-module";
1292
- } else {
1293
- const nameResult = await p.text({
1294
- message: "Module name:",
1295
- placeholder: "my-module",
1296
- defaultValue: "my-module",
1297
- validate: (val) => {
1298
- if (!/^[a-z][a-z0-9-]*$/.test(val)) {
1299
- return "Must start with a letter, use lowercase letters, numbers, and hyphens";
1300
- }
1301
- }
1302
- });
1303
- if (p.isCancel(nameResult)) {
1304
- p.cancel("Cancelled.");
1305
- process.exit(0);
1306
- }
1307
- moduleName = nameResult;
1308
- }
1309
- let templateId;
1310
- if (opts.template) {
1311
- const templates2 = getTemplates(moduleName);
1312
- if (!(opts.template in templates2)) {
1313
- p.log.error(
1314
- `Unknown template: ${opts.template}. Available: ${Object.keys(templates2).join(", ")}`
1315
- );
1316
- process.exit(1);
1317
- }
1318
- templateId = opts.template;
1319
- } else if (opts.noInteractive) {
1320
- templateId = "counter";
1321
- } else {
1322
- const templates2 = getTemplates(moduleName);
1323
- const choice = await p.select({
1324
- message: "Project template:",
1325
- options: Object.values(templates2).map((t) => ({
1326
- value: t.id,
1327
- label: t.label,
1328
- hint: t.hint
1329
- }))
1330
- });
1331
- if (p.isCancel(choice)) {
1332
- p.cancel("Cancelled.");
1333
- process.exit(0);
1334
- }
1335
- templateId = choice;
1336
- }
1337
- const templates = getTemplates(moduleName);
1338
- const template = templates[templateId];
1339
- const pm = detectPackageManager(opts.dir);
1340
- p.log.info(`Package manager: ${pc5.cyan(pm)}`);
1341
- const s = p.spinner();
1342
- s.start("Creating project files...");
1343
- let skipped = 0;
1344
- for (const file of template.files) {
1345
- const filePath = join(opts.dir, file.path);
1346
- if (existsSync(filePath)) {
1347
- skipped++;
1348
- continue;
1349
- }
1350
- writeFile2(filePath, file.content);
1351
- }
1352
- s.stop("Project files created.");
1353
- for (const file of template.files) {
1354
- const filePath = join(opts.dir, file.path);
1355
- const rel = relative(opts.dir, filePath);
1356
- if (existsSync(filePath)) {
1357
- p.log.success(`${pc5.green("Created")} ${pc5.dim(rel)}`);
1358
- }
1359
- }
1360
- if (skipped > 0) {
1361
- p.log.warn(`Skipped ${skipped} file(s) that already exist.`);
1362
- }
1363
- const depsCmd = installCmd(pm, template.deps.join(" "));
1364
- p.outro(
1365
- `Next steps:
1366
- ${pc5.cyan(depsCmd)}
1367
- ${pc5.cyan(`${CLI_NAME} ai-rules init`)}
1368
- ${pc5.dim("Start building!")}`
1369
- );
1370
- }
1371
- function parseArgs3(args) {
1372
- const opts = {
1373
- with: [],
1374
- minimal: false,
1375
- dir: process.cwd()
1376
- };
1377
- for (let i = 0; i < args.length; i++) {
1378
- const arg = args[i];
1379
- switch (arg) {
1380
- case "--with": {
1381
- const val = args[++i];
1382
- if (val) {
1383
- opts.with = val.split(",").map((s) => s.trim());
1384
- }
1385
- break;
1386
- }
1387
- case "--minimal":
1388
- opts.minimal = true;
1389
- break;
1390
- case "--dir": {
1391
- const val = args[++i];
1392
- if (val) {
1393
- opts.dir = val;
1394
- }
1395
- break;
1396
- }
1397
- }
1398
- }
1399
- return opts;
1400
- }
1401
- var ALL_SECTIONS = [
1402
- "derive",
1403
- "events",
1404
- "constraints",
1405
- "resolvers",
1406
- "effects"
1407
- ];
1408
- function generateModule(name, sections) {
1409
- const camelName = toCamelCase2(name);
1410
- const hasConstraints = sections.includes("constraints");
1411
- const hasResolvers = sections.includes("resolvers");
1412
- const imports = ["type ModuleSchema", "createModule", "t"];
1413
- let code = `import { ${imports.join(", ")} } from "@directive-run/core";
1414
-
1415
- `;
1416
- code += `const schema = {
1417
- `;
1418
- code += ` facts: {
1419
- `;
1420
- code += ` // Add your facts here
1421
- `;
1422
- code += ` status: t.string(),
1423
- `;
1424
- code += ` },
1425
- `;
1426
- if (sections.includes("derive")) {
1427
- code += ` derivations: {
1428
- `;
1429
- code += ` // Add derivation types here
1430
- `;
1431
- code += ` isReady: t.boolean(),
1432
- `;
1433
- code += ` },
1434
- `;
1435
- }
1436
- if (sections.includes("events")) {
1437
- code += ` events: {
1438
- `;
1439
- code += ` // Add event shapes here
1440
- `;
1441
- code += ` setStatus: { value: t.string() },
1442
- `;
1443
- code += ` },
1444
- `;
1445
- }
1446
- if (hasConstraints || hasResolvers) {
1447
- code += ` requirements: {
1448
- `;
1449
- code += ` // Add requirement shapes here
1450
- `;
1451
- code += ` PROCESS: { input: t.string() },
1452
- `;
1453
- code += ` },
1454
- `;
1455
- }
1456
- code += `} satisfies ModuleSchema;
1457
-
1458
- `;
1459
- code += `export const ${camelName} = createModule("${name}", {
1460
- `;
1461
- code += ` schema,
1462
-
1463
- `;
1464
- code += ` init: (facts) => {
1465
- `;
1466
- code += ` facts.status = "idle";
1467
- `;
1468
- code += ` },
1469
- `;
1470
- if (sections.includes("derive")) {
1471
- code += `
590
+ `}function j(e){return e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase())}function at(e,t){let r=dirname(e);existsSync(r)||mkdirSync(r,{recursive:true}),writeFileSync(e,t,"utf-8");}async function ve(e){let t=Qe(e);u.intro(d.bgCyan(d.black(" directive init ")));let r;if(t.noInteractive)r="my-module";else {let f=await u.text({message:"Module name:",placeholder:"my-module",defaultValue:"my-module",validate:x=>{if(!/^[a-z][a-z0-9-]*$/.test(x))return "Must start with a letter, use lowercase letters, numbers, and hyphens"}});u.isCancel(f)&&(u.cancel("Cancelled."),process.exit(0)),r=f;}let s;if(t.template){let f=re(r);t.template in f||(u.log.error(`Unknown template: ${t.template}. Available: ${Object.keys(f).join(", ")}`),process.exit(1)),s=t.template;}else if(t.noInteractive)s="counter";else {let f=re(r),x=await u.select({message:"Project template:",options:Object.values(f).map(R=>({value:R.id,label:R.label,hint:R.hint}))});u.isCancel(x)&&(u.cancel("Cancelled."),process.exit(0)),s=x;}let i=re(r)[s],n=Ze(t.dir);u.log.info(`Package manager: ${d.cyan(n)}`);let a=u.spinner();a.start("Creating project files...");let m=0;for(let f of i.files){let x=join(t.dir,f.path);if(existsSync(x)){m++;continue}at(x,f.content);}a.stop("Project files created.");for(let f of i.files){let x=join(t.dir,f.path),R=relative(t.dir,x);existsSync(x)&&u.log.success(`${d.green("Created")} ${d.dim(R)}`);}m>0&&u.log.warn(`Skipped ${m} file(s) that already exist.`);let w=et(n,i.deps.join(" "));u.outro(`Next steps:
591
+ ${d.cyan(w)}
592
+ ${d.cyan(`${y} ai-rules init`)}
593
+ ${d.dim("Start building!")}`);}function be(e){let t={with:[],minimal:false,dir:process.cwd()};for(let r=0;r<e.length;r++)switch(e[r]){case "--with":{let o=e[++r];o&&(t.with=o.split(",").map(i=>i.trim()));break}case "--minimal":t.minimal=true;break;case "--dir":{let o=e[++r];o&&(t.dir=o);break}}return t}var we=["derive","events","constraints","resolvers","effects"];function dt(e,t){let r=xe(e),s=t.includes("constraints"),o=t.includes("resolvers"),n=`import { ${["type ModuleSchema","createModule","t"].join(", ")} } from "@directive-run/core";
594
+
595
+ `;return n+=`const schema = {
596
+ `,n+=` facts: {
597
+ `,n+=` // Add your facts here
598
+ `,n+=` status: t.string(),
599
+ `,n+=` },
600
+ `,t.includes("derive")&&(n+=` derivations: {
601
+ `,n+=` // Add derivation types here
602
+ `,n+=` isReady: t.boolean(),
603
+ `,n+=` },
604
+ `),t.includes("events")&&(n+=` events: {
605
+ `,n+=` // Add event shapes here
606
+ `,n+=` setStatus: { value: t.string() },
607
+ `,n+=` },
608
+ `),(s||o)&&(n+=` requirements: {
609
+ `,n+=` // Add requirement shapes here
610
+ `,n+=` PROCESS: { input: t.string() },
611
+ `,n+=` },
612
+ `),n+=`} satisfies ModuleSchema;
613
+
614
+ `,n+=`export const ${r} = createModule("${e}", {
615
+ `,n+=` schema,
616
+
617
+ `,n+=` init: (facts) => {
618
+ `,n+=` facts.status = "idle";
619
+ `,n+=` },
620
+ `,t.includes("derive")&&(n+=`
1472
621
  derive: {
1473
- `;
1474
- code += ` isReady: (facts) => facts.status === "ready",
1475
- `;
1476
- code += ` },
1477
- `;
1478
- }
1479
- if (sections.includes("events")) {
1480
- code += `
622
+ `,n+=` isReady: (facts) => facts.status === "ready",
623
+ `,n+=` },
624
+ `),t.includes("events")&&(n+=`
1481
625
  events: {
1482
- `;
1483
- code += ` setStatus: (facts, { value }) => {
1484
- `;
1485
- code += ` facts.status = value;
1486
- `;
1487
- code += ` },
1488
- `;
1489
- code += ` },
1490
- `;
1491
- }
1492
- if (hasConstraints) {
1493
- code += `
626
+ `,n+=` setStatus: (facts, { value }) => {
627
+ `,n+=` facts.status = value;
628
+ `,n+=` },
629
+ `,n+=` },
630
+ `),s&&(n+=`
1494
631
  constraints: {
1495
- `;
1496
- code += ` needsProcessing: {
1497
- `;
1498
- code += ` priority: 100,
1499
- `;
1500
- code += ` when: (facts) => facts.status === "pending",
1501
- `;
1502
- code += ` require: (facts) => ({
1503
- `;
1504
- code += ` type: "PROCESS",
1505
- `;
1506
- code += ` input: facts.status,
1507
- `;
1508
- code += ` }),
1509
- `;
1510
- code += ` },
1511
- `;
1512
- code += ` },
1513
- `;
1514
- }
1515
- if (hasResolvers) {
1516
- code += `
632
+ `,n+=` needsProcessing: {
633
+ `,n+=` priority: 100,
634
+ `,n+=` when: (facts) => facts.status === "pending",
635
+ `,n+=` require: (facts) => ({
636
+ `,n+=` type: "PROCESS",
637
+ `,n+=` input: facts.status,
638
+ `,n+=` }),
639
+ `,n+=` },
640
+ `,n+=` },
641
+ `),o&&(n+=`
1517
642
  resolvers: {
1518
- `;
1519
- code += ` process: {
1520
- `;
1521
- code += ` requirement: "PROCESS",
1522
- `;
1523
- code += ` resolve: async (req, context) => {
1524
- `;
1525
- code += ` // Implement resolution logic here
1526
- `;
1527
- code += ` context.facts.status = "done";
1528
- `;
1529
- code += ` },
1530
- `;
1531
- code += ` },
1532
- `;
1533
- code += ` },
1534
- `;
1535
- }
1536
- if (sections.includes("effects")) {
1537
- code += `
643
+ `,n+=` process: {
644
+ `,n+=` requirement: "PROCESS",
645
+ `,n+=` resolve: async (req, context) => {
646
+ `,n+=` // Implement resolution logic here
647
+ `,n+=` context.facts.status = "done";
648
+ `,n+=` },
649
+ `,n+=` },
650
+ `,n+=` },
651
+ `),t.includes("effects")&&(n+=`
1538
652
  effects: {
1539
- `;
1540
- code += ` logChange: {
1541
- `;
1542
- code += ` deps: ["status"],
1543
- `;
1544
- code += ` run: (facts, prev) => {
1545
- `;
1546
- code += ` if (prev && prev.status !== facts.status) {
1547
- `;
1548
- code += ` console.log(\`Status: \${prev.status} \u2192 \${facts.status}\`);
1549
- `;
1550
- code += ` }
1551
- `;
1552
- code += ` },
1553
- `;
1554
- code += ` },
1555
- `;
1556
- code += ` },
1557
- `;
1558
- }
1559
- code += `});
1560
- `;
1561
- return code;
1562
- }
1563
- function generateOrchestrator(name) {
1564
- const camelName = toCamelCase2(name);
1565
- return `import { type ModuleSchema, createModule, createSystem, t } from "@directive-run/core";
653
+ `,n+=` logChange: {
654
+ `,n+=` deps: ["status"],
655
+ `,n+=` run: (facts, prev) => {
656
+ `,n+=` if (prev && prev.status !== facts.status) {
657
+ `,n+=" console.log(`Status: ${prev.status} \u2192 ${facts.status}`);\n",n+=` }
658
+ `,n+=` },
659
+ `,n+=` },
660
+ `,n+=` },
661
+ `),n+=`});
662
+ `,n}function mt(e){let t=xe(e);return `import { type ModuleSchema, createModule, createSystem, t } from "@directive-run/core";
1566
663
  import {
1567
664
  createAgentOrchestrator,
1568
665
  createAgentMemory,
@@ -1605,7 +702,7 @@ const schema = {
1605
702
  // Module
1606
703
  // ============================================================================
1607
704
 
1608
- export const ${camelName} = createModule("${name}", {
705
+ export const ${t} = createModule("${e}", {
1609
706
  schema,
1610
707
 
1611
708
  init: (facts) => {
@@ -1691,688 +788,38 @@ export const memory = createAgentMemory({
1691
788
  // ============================================================================
1692
789
 
1693
790
  export const system = createSystem({
1694
- module: ${camelName},
791
+ module: ${t},
1695
792
  });
1696
- `;
1697
- }
1698
- function toCamelCase2(name) {
1699
- return name.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
1700
- }
1701
- function writeFile3(filePath, content) {
1702
- const dir = dirname(filePath);
1703
- if (!existsSync(dir)) {
1704
- mkdirSync(dir, { recursive: true });
1705
- }
1706
- writeFileSync(filePath, content, "utf-8");
1707
- }
1708
- function findModulesDir(dir) {
1709
- if (existsSync(join(dir, "src"))) {
1710
- return join(dir, "src");
1711
- }
1712
- return join(dir, "src");
1713
- }
1714
- async function newModuleCommand(name, args) {
1715
- const opts = parseArgs3(args);
1716
- if (!name || !/^[a-z][a-z0-9-]*$/.test(name)) {
1717
- console.error(
1718
- `Invalid module name: ${name || "(none)"}
1719
- Must start with a letter, use lowercase letters, numbers, and hyphens.`
1720
- );
1721
- process.exit(1);
1722
- }
1723
- let sections;
1724
- if (opts.minimal) {
1725
- sections = [];
1726
- } else if (opts.with.length > 0) {
1727
- sections = opts.with.filter(
1728
- (s) => ALL_SECTIONS.includes(s)
1729
- );
1730
- } else {
1731
- sections = ALL_SECTIONS;
1732
- }
1733
- const targetDir = findModulesDir(opts.dir);
1734
- const filePath = join(targetDir, `${name}.ts`);
1735
- if (existsSync(filePath)) {
1736
- console.error(`File already exists: ${relative(opts.dir, filePath)}`);
1737
- process.exit(1);
1738
- }
1739
- const content = generateModule(name, sections);
1740
- writeFile3(filePath, content);
1741
- const rel = relative(opts.dir, filePath);
1742
- console.log(`${pc5.green("Created")} ${pc5.dim(rel)}`);
1743
- if (sections.length === 0) {
1744
- console.log(pc5.dim(" Minimal module (schema + init only)"));
1745
- } else {
1746
- console.log(pc5.dim(` Sections: ${sections.join(", ")}`));
1747
- }
1748
- }
1749
- async function newOrchestratorCommand(name, args) {
1750
- const opts = parseArgs3(args);
1751
- if (!name || !/^[a-z][a-z0-9-]*$/.test(name)) {
1752
- console.error(
1753
- `Invalid orchestrator name: ${name || "(none)"}
1754
- Must start with a letter, use lowercase letters, numbers, and hyphens.`
1755
- );
1756
- process.exit(1);
1757
- }
1758
- const targetDir = findModulesDir(opts.dir);
1759
- const filePath = join(targetDir, `${name}.ts`);
1760
- if (existsSync(filePath)) {
1761
- console.error(`File already exists: ${relative(opts.dir, filePath)}`);
1762
- process.exit(1);
1763
- }
1764
- const content = generateOrchestrator(name);
1765
- writeFile3(filePath, content);
1766
- const rel = relative(opts.dir, filePath);
1767
- console.log(`${pc5.green("Created")} ${pc5.dim(rel)}`);
1768
- console.log(pc5.dim(" AI orchestrator with memory, guardrails, and streaming"));
1769
- }
1770
- async function loadSystem(filePath) {
1771
- const resolved = resolve(filePath);
1772
- if (!existsSync(resolved)) {
1773
- throw new Error(`File not found: ${resolved}`);
1774
- }
1775
- try {
1776
- const mod = await import(resolved);
1777
- if (mod.default && isSystem(mod.default)) {
1778
- return mod.default;
1779
- }
1780
- if (mod.system && isSystem(mod.system)) {
1781
- return mod.system;
1782
- }
1783
- for (const key of Object.keys(mod)) {
1784
- if (isSystem(mod[key])) {
1785
- return mod[key];
1786
- }
1787
- }
1788
- throw new Error(
1789
- `No Directive system found in ${pc5.dim(filePath)}
793
+ `}function xe(e){return e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase())}function $e(e,t){let r=dirname(e);existsSync(r)||mkdirSync(r,{recursive:true}),writeFileSync(e,t,"utf-8");}function ke(e){return join(e,"src")}async function Se(e,t){let r=be(t);(!e||!/^[a-z][a-z0-9-]*$/.test(e))&&(console.error(`Invalid module name: ${e||"(none)"}
794
+ Must start with a letter, use lowercase letters, numbers, and hyphens.`),process.exit(1));let s;r.minimal?s=[]:r.with.length>0?s=r.with.filter(c=>we.includes(c)):s=we;let o=ke(r.dir),i=join(o,`${e}.ts`);existsSync(i)&&(console.error(`File already exists: ${relative(r.dir,i)}`),process.exit(1));let n=dt(e,s);$e(i,n);let a=relative(r.dir,i);console.log(`${d.green("Created")} ${d.dim(a)}`),s.length===0?console.log(d.dim(" Minimal module (schema + init only)")):console.log(d.dim(` Sections: ${s.join(", ")}`));}async function Ce(e,t){let r=be(t);(!e||!/^[a-z][a-z0-9-]*$/.test(e))&&(console.error(`Invalid orchestrator name: ${e||"(none)"}
795
+ Must start with a letter, use lowercase letters, numbers, and hyphens.`),process.exit(1));let s=ke(r.dir),o=join(s,`${e}.ts`);existsSync(o)&&(console.error(`File already exists: ${relative(r.dir,o)}`),process.exit(1));let i=mt(e);$e(o,i);let n=relative(r.dir,o);console.log(`${d.green("Created")} ${d.dim(n)}`),console.log(d.dim(" AI orchestrator with memory, guardrails, and streaming"));}async function U(e){let t=resolve(e);if(!existsSync(t))throw new Error(`File not found: ${t}`);try{let r=await import(t);if(r.default&&oe(r.default))return r.default;if(r.system&&oe(r.system))return r.system;for(let s of Object.keys(r))if(oe(r[s]))return r[s];throw new Error(`No Directive system found in ${d.dim(e)}
1790
796
  Export a system as default or named "system":
1791
797
 
1792
- ${pc5.cyan("export default")} createSystem({ module: myModule });
1793
- ${pc5.cyan("export const system")} = createSystem({ module: myModule });`
1794
- );
1795
- } catch (err) {
1796
- if (err instanceof Error && err.message.includes("No Directive system")) {
1797
- throw err;
1798
- }
1799
- throw new Error(
1800
- `Failed to load ${pc5.dim(filePath)}: ${err instanceof Error ? err.message : String(err)}
798
+ ${d.cyan("export default")} createSystem({ module: myModule });
799
+ ${d.cyan("export const system")} = createSystem({ module: myModule });`)}catch(r){throw r instanceof Error&&r.message.includes("No Directive system")?r:new Error(`Failed to load ${d.dim(e)}: ${r instanceof Error?r.message:String(r)}
1801
800
 
1802
801
  Make sure the file is valid TypeScript and tsx is installed:
1803
- ${pc5.cyan("npm install -D tsx")}`
1804
- );
1805
- }
1806
- }
1807
- function isSystem(obj) {
1808
- if (typeof obj !== "object" || obj === null) {
1809
- return false;
1810
- }
1811
- const sys = obj;
1812
- return typeof sys.inspect === "function" && typeof sys.start === "function" && typeof sys.stop === "function" && "facts" in sys;
1813
- }
1814
-
1815
- // src/commands/inspect.ts
1816
- function parseArgs4(args) {
1817
- const opts = { json: false };
1818
- let filePath = "";
1819
- for (let i = 0; i < args.length; i++) {
1820
- const arg = args[i];
1821
- switch (arg) {
1822
- case "--json":
1823
- opts.json = true;
1824
- break;
1825
- case "--module": {
1826
- const val = args[++i];
1827
- if (val) {
1828
- opts.module = val;
1829
- }
1830
- break;
1831
- }
1832
- default:
1833
- if (arg && !arg.startsWith("-") && !filePath) {
1834
- filePath = arg;
1835
- }
1836
- }
1837
- }
1838
- return { filePath, opts };
1839
- }
1840
- function formatFacts(facts) {
1841
- const lines = [];
1842
- lines.push(pc5.bold("Facts:"));
1843
- const entries = Object.entries(facts);
1844
- if (entries.length === 0) {
1845
- lines.push(" (none)");
1846
- return lines.join("\n");
1847
- }
1848
- for (const [key, value] of entries) {
1849
- const formatted = formatValue(value);
1850
- lines.push(` ${pc5.cyan(key)} = ${formatted}`);
1851
- }
1852
- return lines.join("\n");
1853
- }
1854
- function formatConstraints(constraints) {
1855
- const lines = [];
1856
- lines.push(pc5.bold("Constraints:"));
1857
- if (constraints.length === 0) {
1858
- lines.push(" (none)");
1859
- return lines.join("\n");
1860
- }
1861
- for (const c of constraints) {
1862
- const status = c.disabled ? pc5.dim("disabled") : c.active ? pc5.green("active") : pc5.dim("inactive");
1863
- const hits = c.hitCount > 0 ? pc5.yellow(` (${c.hitCount} hits)`) : "";
1864
- lines.push(
1865
- ` ${pc5.cyan(c.id)} ${status} priority=${c.priority}${hits}`
1866
- );
1867
- }
1868
- return lines.join("\n");
1869
- }
1870
- function formatResolverDefs(resolverDefs, resolvers) {
1871
- const lines = [];
1872
- lines.push(pc5.bold("Resolvers:"));
1873
- if (resolverDefs.length === 0) {
1874
- lines.push(" (none)");
1875
- return lines.join("\n");
1876
- }
1877
- for (const def of resolverDefs) {
1878
- const status = resolvers[def.id];
1879
- const stateStr = status ? formatResolverState(status.state, status.error, status.duration) : pc5.dim("idle");
1880
- lines.push(
1881
- ` ${pc5.cyan(def.id)} \u2192 ${def.requirement} ${stateStr}`
1882
- );
1883
- }
1884
- return lines.join("\n");
1885
- }
1886
- function formatUnmet(unmet) {
1887
- const lines = [];
1888
- lines.push(pc5.bold("Unmet Requirements:"));
1889
- if (unmet.length === 0) {
1890
- lines.push(` ${pc5.green("(all requirements met)")}`);
1891
- return lines.join("\n");
1892
- }
1893
- for (const u of unmet) {
1894
- lines.push(
1895
- ` ${pc5.yellow(u.requirement.type)} (id: ${pc5.dim(u.id)}) from ${pc5.dim(u.fromConstraint)}`
1896
- );
1897
- }
1898
- return lines.join("\n");
1899
- }
1900
- function formatInflight(inflight) {
1901
- const lines = [];
1902
- lines.push(pc5.bold("Inflight:"));
1903
- if (inflight.length === 0) {
1904
- lines.push(` ${pc5.green("(none)")}`);
1905
- return lines.join("\n");
1906
- }
1907
- const now = Date.now();
1908
- for (const inf of inflight) {
1909
- const elapsed = now - inf.startedAt;
1910
- lines.push(
1911
- ` ${pc5.cyan(inf.resolverId)} \u2192 req ${pc5.dim(inf.id)} ${pc5.yellow(`${elapsed}ms`)}`
1912
- );
1913
- }
1914
- return lines.join("\n");
1915
- }
1916
- function formatResolverState(state, error, duration) {
1917
- const dur = duration !== void 0 ? ` ${duration}ms` : "";
1918
- switch (state) {
1919
- case "resolved":
1920
- return pc5.green(`resolved${dur}`);
1921
- case "errored":
1922
- return pc5.red(`errored${dur}${error ? ` \u2014 ${error}` : ""}`);
1923
- case "inflight":
1924
- return pc5.yellow("inflight");
1925
- case "cancelled":
1926
- return pc5.dim("cancelled");
1927
- default:
1928
- return pc5.dim(state);
1929
- }
1930
- }
1931
- function formatValue(value) {
1932
- if (value === null) {
1933
- return pc5.dim("null");
1934
- }
1935
- if (value === void 0) {
1936
- return pc5.dim("undefined");
1937
- }
1938
- if (typeof value === "string") {
1939
- return value.length > 60 ? `"${value.slice(0, 57)}..."` : `"${value}"`;
1940
- }
1941
- if (typeof value === "number" || typeof value === "boolean") {
1942
- return String(value);
1943
- }
1944
- if (Array.isArray(value)) {
1945
- return `[${value.length} items]`;
1946
- }
1947
- return JSON.stringify(value).slice(0, 60);
1948
- }
1949
- function findWarnings(inspection) {
1950
- const warnings = [];
1951
- new Set(inspection.unmet.map((u) => u.requirement.type));
1952
- new Set(
1953
- inspection.resolverDefs.map((r) => r.requirement)
1954
- );
1955
- for (const def of inspection.resolverDefs) {
1956
- if (def.requirement === "(predicate)") {
1957
- continue;
1958
- }
1959
- }
1960
- for (const u of inspection.unmet) {
1961
- const hasResolver = inspection.resolverDefs.some(
1962
- (r) => r.requirement === u.requirement.type || r.requirement === "(predicate)"
1963
- );
1964
- if (!hasResolver) {
1965
- warnings.push(
1966
- `No resolver for requirement type "${u.requirement.type}"`
1967
- );
1968
- }
1969
- }
1970
- return warnings;
1971
- }
1972
- async function inspectCommand(args) {
1973
- const { filePath, opts } = parseArgs4(args);
1974
- if (!filePath) {
1975
- console.error(
1976
- "Usage: directive inspect <file> [--json] [--module <name>]"
1977
- );
1978
- process.exit(1);
1979
- }
1980
- const system = await loadSystem(filePath);
1981
- if (!system.isRunning) {
1982
- system.start();
1983
- }
1984
- const inspection = system.inspect();
1985
- if (opts.json) {
1986
- const factsObj2 = {};
1987
- if (system.facts) {
1988
- for (const key of Object.keys(system.facts)) {
1989
- try {
1990
- factsObj2[key] = system.facts[key];
1991
- } catch {
1992
- factsObj2[key] = "(error reading)";
1993
- }
1994
- }
1995
- }
1996
- console.log(
1997
- JSON.stringify(
1998
- {
1999
- facts: factsObj2,
2000
- ...inspection
2001
- },
2002
- null,
2003
- 2
2004
- )
2005
- );
2006
- system.stop();
2007
- return;
2008
- }
2009
- console.log();
2010
- console.log(pc5.bold(pc5.cyan("Directive System Inspection")));
2011
- console.log(pc5.dim("\u2500".repeat(40)));
2012
- console.log();
2013
- const factsObj = {};
2014
- if (system.facts) {
2015
- for (const key of Object.keys(system.facts)) {
2016
- try {
2017
- factsObj[key] = system.facts[key];
2018
- } catch {
2019
- factsObj[key] = "(error reading)";
2020
- }
2021
- }
2022
- }
2023
- console.log(formatFacts(factsObj));
2024
- console.log();
2025
- console.log(formatConstraints(inspection.constraints));
2026
- console.log();
2027
- console.log(formatResolverDefs(inspection.resolverDefs, inspection.resolvers));
2028
- console.log();
2029
- console.log(formatUnmet(inspection.unmet));
2030
- console.log();
2031
- if (inspection.inflight.length > 0) {
2032
- console.log(formatInflight(inspection.inflight));
2033
- console.log();
2034
- }
2035
- const warnings = findWarnings(inspection);
2036
- if (warnings.length > 0) {
2037
- console.log(pc5.bold(pc5.yellow("Warnings:")));
2038
- for (const w of warnings) {
2039
- console.log(` ${pc5.yellow("\u26A0")} ${w}`);
2040
- }
2041
- console.log();
2042
- }
2043
- system.stop();
2044
- }
2045
- function parseArgs5(args) {
2046
- const opts = {};
2047
- let filePath = "";
2048
- let requirementId;
2049
- for (let i = 0; i < args.length; i++) {
2050
- const arg = args[i];
2051
- switch (arg) {
2052
- case "--module": {
2053
- const val = args[++i];
2054
- if (val) {
2055
- opts.module = val;
2056
- }
2057
- break;
2058
- }
2059
- default:
2060
- if (arg && !arg.startsWith("-")) {
2061
- if (!filePath) {
2062
- filePath = arg;
2063
- } else if (!requirementId) {
2064
- requirementId = arg;
2065
- }
2066
- }
2067
- }
2068
- }
2069
- return { filePath, requirementId, opts };
2070
- }
2071
- async function explainCommand(args) {
2072
- const { filePath, requirementId } = parseArgs5(args);
2073
- if (!filePath) {
2074
- console.error(
2075
- "Usage: directive explain <file> [requirement-id]"
2076
- );
2077
- process.exit(1);
2078
- }
2079
- const system = await loadSystem(filePath);
2080
- if (!system.isRunning) {
2081
- system.start();
2082
- }
2083
- const inspection = system.inspect();
2084
- if (requirementId) {
2085
- const explanation = system.explain(requirementId);
2086
- if (!explanation) {
2087
- console.error(
2088
- `Requirement "${requirementId}" not found.
2089
-
2090
- Current requirements:`
2091
- );
2092
- if (inspection.unmet.length === 0) {
2093
- console.log(pc5.dim(" (no unmet requirements)"));
2094
- } else {
2095
- for (const u of inspection.unmet) {
2096
- console.log(
2097
- ` ${pc5.cyan(u.id)} \u2014 ${u.requirement.type} (from ${u.fromConstraint})`
2098
- );
2099
- }
2100
- }
2101
- system.stop();
2102
- process.exit(1);
2103
- }
2104
- console.log();
2105
- console.log(pc5.bold(pc5.cyan("Requirement Explanation")));
2106
- console.log(pc5.dim("\u2500".repeat(40)));
2107
- console.log();
2108
- console.log(explanation);
2109
- console.log();
2110
- } else {
2111
- console.log();
2112
- console.log(pc5.bold(pc5.cyan("All Requirements")));
2113
- console.log(pc5.dim("\u2500".repeat(40)));
2114
- console.log();
2115
- if (inspection.unmet.length === 0) {
2116
- console.log(pc5.green("All requirements are met."));
2117
- console.log();
2118
- const resolverEntries = Object.entries(
2119
- inspection.resolvers
2120
- );
2121
- if (resolverEntries.length > 0) {
2122
- console.log(pc5.bold("Recent Resolver Activity:"));
2123
- for (const [key, status] of resolverEntries) {
2124
- const state = formatState(status.state);
2125
- const dur = status.duration !== void 0 ? ` (${status.duration}ms)` : "";
2126
- console.log(` ${pc5.cyan(key)} ${state}${dur}`);
2127
- }
2128
- console.log();
2129
- }
2130
- } else {
2131
- console.log(
2132
- `${pc5.yellow(String(inspection.unmet.length))} unmet requirement(s):
2133
- `
2134
- );
2135
- for (const u of inspection.unmet) {
2136
- console.log(
2137
- `${pc5.yellow("\u25CF")} ${pc5.bold(u.requirement.type)} (id: ${pc5.dim(u.id)})`
2138
- );
2139
- console.log(` From constraint: ${pc5.cyan(u.fromConstraint)}`);
2140
- const payload = { ...u.requirement };
2141
- delete payload.type;
2142
- const payloadKeys = Object.keys(payload);
2143
- if (payloadKeys.length > 0) {
2144
- console.log(` Payload: ${JSON.stringify(payload)}`);
2145
- }
2146
- const resolverStatus = inspection.resolvers[u.id];
2147
- if (resolverStatus) {
2148
- console.log(
2149
- ` Resolver: ${formatState(resolverStatus.state)}${resolverStatus.error ? ` \u2014 ${resolverStatus.error}` : ""}`
2150
- );
2151
- } else {
2152
- const hasResolver = inspection.resolverDefs.some(
2153
- (r) => r.requirement === u.requirement.type || r.requirement === "(predicate)"
2154
- );
2155
- if (!hasResolver) {
2156
- console.log(` ${pc5.red("No resolver registered for this type")}`);
2157
- }
2158
- }
2159
- console.log();
2160
- }
2161
- console.log(
2162
- pc5.dim(
2163
- `Run ${pc5.cyan(`directive explain <file> <requirement-id>`)} for detailed explanation.`
2164
- )
2165
- );
2166
- }
2167
- }
2168
- system.stop();
2169
- }
2170
- function formatState(state) {
2171
- switch (state) {
2172
- case "resolved":
2173
- return pc5.green("resolved");
2174
- case "errored":
2175
- return pc5.red("errored");
2176
- case "inflight":
2177
- return pc5.yellow("inflight");
2178
- case "pending":
2179
- return pc5.yellow("pending");
2180
- case "cancelled":
2181
- return pc5.dim("cancelled");
2182
- default:
2183
- return pc5.dim(state);
2184
- }
2185
- }
2186
- function parseArgs6(args) {
2187
- const opts = { ascii: false, open: true };
2188
- let filePath = "";
2189
- for (let i = 0; i < args.length; i++) {
2190
- const arg = args[i];
2191
- switch (arg) {
2192
- case "--ascii":
2193
- opts.ascii = true;
2194
- break;
2195
- case "--no-open":
2196
- opts.open = false;
2197
- break;
2198
- case "--output": {
2199
- const val = args[++i];
2200
- if (val) {
2201
- opts.output = val;
2202
- }
2203
- break;
2204
- }
2205
- default:
2206
- if (arg && !arg.startsWith("-") && !filePath) {
2207
- filePath = arg;
2208
- }
2209
- }
2210
- }
2211
- return { filePath, opts };
2212
- }
2213
- function renderAsciiGraph(inspection) {
2214
- const lines = [];
2215
- lines.push(pc5.bold("Dependency Graph"));
2216
- lines.push(pc5.dim("\u2550".repeat(50)));
2217
- lines.push("");
2218
- const constraintMap = /* @__PURE__ */ new Map();
2219
- for (const c of inspection.constraints) {
2220
- constraintMap.set(c.id, {
2221
- reqTypes: /* @__PURE__ */ new Set(),
2222
- active: c.active,
2223
- priority: c.priority
2224
- });
2225
- }
2226
- for (const u of inspection.unmet) {
2227
- const entry = constraintMap.get(u.fromConstraint);
2228
- if (entry) {
2229
- entry.reqTypes.add(u.requirement.type);
2230
- }
2231
- }
2232
- const resolversByType = /* @__PURE__ */ new Map();
2233
- for (const r of inspection.resolverDefs) {
2234
- if (!resolversByType.has(r.requirement)) {
2235
- resolversByType.set(r.requirement, []);
2236
- }
2237
- resolversByType.get(r.requirement).push(r.id);
2238
- }
2239
- lines.push(pc5.bold("Constraints \u2192 Requirements \u2192 Resolvers"));
2240
- lines.push("");
2241
- for (const [id, info] of constraintMap) {
2242
- const status = info.active ? pc5.green("\u25CF") : pc5.dim("\u25CB");
2243
- lines.push(`${status} ${pc5.cyan(id)} (priority: ${info.priority})`);
2244
- if (info.reqTypes.size > 0) {
2245
- for (const reqType of info.reqTypes) {
2246
- lines.push(` \u2514\u2500\u25B6 ${pc5.yellow(reqType)}`);
2247
- const resolvers = resolversByType.get(reqType) || [];
2248
- if (resolvers.length > 0) {
2249
- for (const r of resolvers) {
2250
- lines.push(` \u2514\u2500\u25B6 ${pc5.magenta(r)}`);
2251
- }
2252
- } else {
2253
- lines.push(` \u2514\u2500\u25B6 ${pc5.red("(no resolver)")}`);
2254
- }
2255
- }
2256
- } else {
2257
- lines.push(` \u2514\u2500\u25B6 ${pc5.dim("(no active requirements)")}`);
2258
- }
2259
- lines.push("");
2260
- }
2261
- const usedResolvers = /* @__PURE__ */ new Set();
2262
- for (const resolvers of resolversByType.values()) {
2263
- for (const r of resolvers) {
2264
- usedResolvers.add(r);
2265
- }
2266
- }
2267
- const allResolverIds = inspection.resolverDefs.map((r) => r.id);
2268
- const orphanedCount = allResolverIds.filter(
2269
- (r) => !usedResolvers.has(r)
2270
- ).length;
2271
- if (orphanedCount > 0) {
2272
- lines.push(pc5.bold("Standalone Resolvers:"));
2273
- for (const r of inspection.resolverDefs) {
2274
- if (!usedResolvers.has(r.id)) {
2275
- lines.push(
2276
- ` ${pc5.magenta(r.id)} handles ${pc5.yellow(r.requirement)}`
2277
- );
2278
- }
2279
- }
2280
- }
2281
- return lines.join("\n");
2282
- }
2283
- function renderHtmlGraph(inspection, facts) {
2284
- const nodes = [];
2285
- const edges = [];
2286
- const colWidth = 220;
2287
- const rowHeight = 50;
2288
- const startX = 40;
2289
- const startY = 60;
2290
- const factKeys = Object.keys(facts);
2291
- for (let i = 0; i < factKeys.length; i++) {
2292
- const key = factKeys[i];
2293
- nodes.push({
2294
- id: `fact-${key}`,
2295
- label: key,
2296
- type: "fact",
2297
- x: startX,
2298
- y: startY + i * rowHeight,
2299
- color: "#3b82f6"
2300
- });
2301
- }
2302
- for (let i = 0; i < inspection.constraints.length; i++) {
2303
- const c = inspection.constraints[i];
2304
- nodes.push({
2305
- id: `constraint-${c.id}`,
2306
- label: c.id,
2307
- type: "constraint",
2308
- x: startX + colWidth,
2309
- y: startY + i * rowHeight,
2310
- color: c.active ? "#22c55e" : "#6b7280"
2311
- });
2312
- }
2313
- const reqTypes = /* @__PURE__ */ new Set();
2314
- for (const u of inspection.unmet) {
2315
- reqTypes.add(u.requirement.type);
2316
- }
2317
- let reqIdx = 0;
2318
- for (const reqType of reqTypes) {
2319
- nodes.push({
2320
- id: `req-${reqType}`,
2321
- label: reqType,
2322
- type: "requirement",
2323
- x: startX + colWidth * 2,
2324
- y: startY + reqIdx * rowHeight,
2325
- color: "#eab308"
2326
- });
2327
- reqIdx++;
2328
- }
2329
- for (let i = 0; i < inspection.resolverDefs.length; i++) {
2330
- const r = inspection.resolverDefs[i];
2331
- nodes.push({
2332
- id: `resolver-${r.id}`,
2333
- label: r.id,
2334
- type: "resolver",
2335
- x: startX + colWidth * 3,
2336
- y: startY + i * rowHeight,
2337
- color: "#a855f7"
2338
- });
2339
- }
2340
- for (const u of inspection.unmet) {
2341
- edges.push({
2342
- from: `constraint-${u.fromConstraint}`,
2343
- to: `req-${u.requirement.type}`
2344
- });
2345
- }
2346
- for (const r of inspection.resolverDefs) {
2347
- if (reqTypes.has(r.requirement)) {
2348
- edges.push({
2349
- from: `req-${r.requirement}`,
2350
- to: `resolver-${r.id}`
2351
- });
2352
- }
2353
- }
2354
- const nodeMap = new Map(nodes.map((n) => [n.id, n]));
2355
- const svgWidth = startX + colWidth * 4 + 40;
2356
- const maxY = Math.max(...nodes.map((n) => n.y)) + rowHeight + 20;
2357
- const edgeSvg = edges.map((e) => {
2358
- const from = nodeMap.get(e.from);
2359
- const to = nodeMap.get(e.to);
2360
- if (!from || !to) {
2361
- return "";
2362
- }
2363
- return `<line x1="${from.x + 90}" y1="${from.y + 15}" x2="${to.x}" y2="${to.y + 15}" stroke="#94a3b8" stroke-width="1.5" marker-end="url(#arrow)"/>`;
2364
- }).join("\n ");
2365
- const nodeSvg = nodes.map(
2366
- (n) => `<g>
2367
- <rect x="${n.x}" y="${n.y}" width="180" height="30" rx="6" fill="${n.color}" opacity="0.15" stroke="${n.color}" stroke-width="1.5"/>
2368
- <text x="${n.x + 90}" y="${n.y + 19}" text-anchor="middle" font-size="12" font-family="monospace" fill="${n.color}">${escapeHtml(n.label)}</text>
2369
- </g>`
2370
- ).join("\n ");
2371
- const headers = ["Facts", "Constraints", "Requirements", "Resolvers"];
2372
- const headerSvg = headers.map(
2373
- (h, i) => `<text x="${startX + i * colWidth + 90}" y="35" text-anchor="middle" font-size="14" font-weight="bold" font-family="system-ui" fill="#e2e8f0">${h}</text>`
2374
- ).join("\n ");
2375
- return `<!DOCTYPE html>
802
+ ${d.cyan("npm install -D tsx")}`)}}function oe(e){if(typeof e!="object"||e===null)return false;let t=e;return typeof t.inspect=="function"&&typeof t.start=="function"&&typeof t.stop=="function"&&"facts"in t}function gt(e){let t={json:false},r="";for(let s=0;s<e.length;s++){let o=e[s];switch(o){case "--json":t.json=true;break;case "--module":{let i=e[++s];i&&(t.module=i);break}default:o&&!o.startsWith("-")&&!r&&(r=o);}}return {filePath:r,opts:t}}function ht(e){let t=[];t.push(d.bold("Facts:"));let r=Object.entries(e);if(r.length===0)return t.push(" (none)"),t.join(`
803
+ `);for(let[s,o]of r){let i=$t(o);t.push(` ${d.cyan(s)} = ${i}`);}return t.join(`
804
+ `)}function yt(e){let t=[];if(t.push(d.bold("Constraints:")),e.length===0)return t.push(" (none)"),t.join(`
805
+ `);for(let r of e){let s=r.disabled?d.dim("disabled"):r.active?d.green("active"):d.dim("inactive"),o=r.hitCount>0?d.yellow(` (${r.hitCount} hits)`):"";t.push(` ${d.cyan(r.id)} ${s} priority=${r.priority}${o}`);}return t.join(`
806
+ `)}function vt(e,t){let r=[];if(r.push(d.bold("Resolvers:")),e.length===0)return r.push(" (none)"),r.join(`
807
+ `);for(let s of e){let o=t[s.id],i=o?xt(o.state,o.error,o.duration):d.dim("idle");r.push(` ${d.cyan(s.id)} \u2192 ${s.requirement} ${i}`);}return r.join(`
808
+ `)}function wt(e){let t=[];if(t.push(d.bold("Unmet Requirements:")),e.length===0)return t.push(` ${d.green("(all requirements met)")}`),t.join(`
809
+ `);for(let r of e)t.push(` ${d.yellow(r.requirement.type)} (id: ${d.dim(r.id)}) from ${d.dim(r.fromConstraint)}`);return t.join(`
810
+ `)}function bt(e){let t=[];if(t.push(d.bold("Inflight:")),e.length===0)return t.push(` ${d.green("(none)")}`),t.join(`
811
+ `);let r=Date.now();for(let s of e){let o=r-s.startedAt;t.push(` ${d.cyan(s.resolverId)} \u2192 req ${d.dim(s.id)} ${d.yellow(`${o}ms`)}`);}return t.join(`
812
+ `)}function xt(e,t,r){let s=r!==void 0?` ${r}ms`:"";switch(e){case "resolved":return d.green(`resolved${s}`);case "errored":return d.red(`errored${s}${t?` \u2014 ${t}`:""}`);case "inflight":return d.yellow("inflight");case "cancelled":return d.dim("cancelled");default:return d.dim(e)}}function $t(e){return e===null?d.dim("null"):e===void 0?d.dim("undefined"):typeof e=="string"?e.length>60?`"${e.slice(0,57)}..."`:`"${e}"`:typeof e=="number"||typeof e=="boolean"?String(e):Array.isArray(e)?`[${e.length} items]`:JSON.stringify(e).slice(0,60)}function kt(e){let t=[];new Set(e.unmet.map(i=>i.requirement.type));new Set(e.resolverDefs.map(i=>i.requirement));for(let i of e.resolverDefs)i.requirement;for(let i of e.unmet)e.resolverDefs.some(a=>a.requirement===i.requirement.type||a.requirement==="(predicate)")||t.push(`No resolver for requirement type "${i.requirement.type}"`);return t}async function Ae(e){let{filePath:t,opts:r}=gt(e);t||(console.error("Usage: directive inspect <file> [--json] [--module <name>]"),process.exit(1));let s=await U(t);s.isRunning||s.start();let o=s.inspect();if(r.json){let a={};if(s.facts)for(let c of Object.keys(s.facts))try{a[c]=s.facts[c];}catch{a[c]="(error reading)";}console.log(JSON.stringify({facts:a,...o},null,2)),s.stop();return}console.log(),console.log(d.bold(d.cyan("Directive System Inspection"))),console.log(d.dim("\u2500".repeat(40))),console.log();let i={};if(s.facts)for(let a of Object.keys(s.facts))try{i[a]=s.facts[a];}catch{i[a]="(error reading)";}console.log(ht(i)),console.log(),console.log(yt(o.constraints)),console.log(),console.log(vt(o.resolverDefs,o.resolvers)),console.log(),console.log(wt(o.unmet)),console.log(),o.inflight.length>0&&(console.log(bt(o.inflight)),console.log());let n=kt(o);if(n.length>0){console.log(d.bold(d.yellow("Warnings:")));for(let a of n)console.log(` ${d.yellow("\u26A0")} ${a}`);console.log();}s.stop();}function St(e){let t={},r="",s;for(let o=0;o<e.length;o++){let i=e[o];if(i==="--module"){let n=e[++o];n&&(t.module=n);}else i&&!i.startsWith("-")&&(r?s||(s=i):r=i);}return {filePath:r,requirementId:s,opts:t}}async function Te(e){let{filePath:t,requirementId:r}=St(e);t||(console.error("Usage: directive explain <file> [requirement-id]"),process.exit(1));let s=await U(t);s.isRunning||s.start();let o=s.inspect();if(r){let i=s.explain(r);if(!i){if(console.error(`Requirement "${r}" not found.
813
+
814
+ Current requirements:`),o.unmet.length===0)console.log(d.dim(" (no unmet requirements)"));else for(let n of o.unmet)console.log(` ${d.cyan(n.id)} \u2014 ${n.requirement.type} (from ${n.fromConstraint})`);s.stop(),process.exit(1);}console.log(),console.log(d.bold(d.cyan("Requirement Explanation"))),console.log(d.dim("\u2500".repeat(40))),console.log(),console.log(i),console.log();}else if(console.log(),console.log(d.bold(d.cyan("All Requirements"))),console.log(d.dim("\u2500".repeat(40))),console.log(),o.unmet.length===0){console.log(d.green("All requirements are met.")),console.log();let i=Object.entries(o.resolvers);if(i.length>0){console.log(d.bold("Recent Resolver Activity:"));for(let[n,a]of i){let c=Re(a.state),m=a.duration!==void 0?` (${a.duration}ms)`:"";console.log(` ${d.cyan(n)} ${c}${m}`);}console.log();}}else {console.log(`${d.yellow(String(o.unmet.length))} unmet requirement(s):
815
+ `);for(let i of o.unmet){console.log(`${d.yellow("\u25CF")} ${d.bold(i.requirement.type)} (id: ${d.dim(i.id)})`),console.log(` From constraint: ${d.cyan(i.fromConstraint)}`);let n={...i.requirement};delete n.type,Object.keys(n).length>0&&console.log(` Payload: ${JSON.stringify(n)}`);let c=o.resolvers[i.id];c?console.log(` Resolver: ${Re(c.state)}${c.error?` \u2014 ${c.error}`:""}`):o.resolverDefs.some(w=>w.requirement===i.requirement.type||w.requirement==="(predicate)")||console.log(` ${d.red("No resolver registered for this type")}`),console.log();}console.log(d.dim(`Run ${d.cyan("directive explain <file> <requirement-id>")} for detailed explanation.`));}s.stop();}function Re(e){switch(e){case "resolved":return d.green("resolved");case "errored":return d.red("errored");case "inflight":return d.yellow("inflight");case "pending":return d.yellow("pending");case "cancelled":return d.dim("cancelled");default:return d.dim(e)}}function Rt(e){let t={ascii:false,open:true},r="";for(let s=0;s<e.length;s++){let o=e[s];switch(o){case "--ascii":t.ascii=true;break;case "--no-open":t.open=false;break;case "--output":{let i=e[++s];i&&(t.output=i);break}default:o&&!o.startsWith("-")&&!r&&(r=o);}}return {filePath:r,opts:t}}function Tt(e){let t=[];t.push(d.bold("Dependency Graph")),t.push(d.dim("\u2550".repeat(50))),t.push("");let r=new Map;for(let a of e.constraints)r.set(a.id,{reqTypes:new Set,active:a.active,priority:a.priority});for(let a of e.unmet){let c=r.get(a.fromConstraint);c&&c.reqTypes.add(a.requirement.type);}let s=new Map;for(let a of e.resolverDefs)s.has(a.requirement)||s.set(a.requirement,[]),s.get(a.requirement).push(a.id);t.push(d.bold("Constraints \u2192 Requirements \u2192 Resolvers")),t.push("");for(let[a,c]of r){let m=c.active?d.green("\u25CF"):d.dim("\u25CB");if(t.push(`${m} ${d.cyan(a)} (priority: ${c.priority})`),c.reqTypes.size>0)for(let w of c.reqTypes){t.push(` \u2514\u2500\u25B6 ${d.yellow(w)}`);let f=s.get(w)||[];if(f.length>0)for(let x of f)t.push(` \u2514\u2500\u25B6 ${d.magenta(x)}`);else t.push(` \u2514\u2500\u25B6 ${d.red("(no resolver)")}`);}else t.push(` \u2514\u2500\u25B6 ${d.dim("(no active requirements)")}`);t.push("");}let o=new Set;for(let a of s.values())for(let c of a)o.add(c);if(e.resolverDefs.map(a=>a.id).filter(a=>!o.has(a)).length>0){t.push(d.bold("Standalone Resolvers:"));for(let a of e.resolverDefs)o.has(a.id)||t.push(` ${d.magenta(a.id)} handles ${d.yellow(a.requirement)}`);}return t.join(`
816
+ `)}function Mt(e,t){let r=[],s=[],c=Object.keys(t);for(let l=0;l<c.length;l++){let b=c[l];r.push({id:`fact-${b}`,label:b,type:"fact",x:40,y:60+l*50,color:"#3b82f6"});}for(let l=0;l<e.constraints.length;l++){let b=e.constraints[l];r.push({id:`constraint-${b.id}`,label:b.id,type:"constraint",x:260,y:60+l*50,color:b.active?"#22c55e":"#6b7280"});}let m=new Set;for(let l of e.unmet)m.add(l.requirement.type);let w=0;for(let l of m)r.push({id:`req-${l}`,label:l,type:"requirement",x:480,y:60+w*50,color:"#eab308"}),w++;for(let l=0;l<e.resolverDefs.length;l++){let b=e.resolverDefs[l];r.push({id:`resolver-${b.id}`,label:b.id,type:"resolver",x:700,y:60+l*50,color:"#a855f7"});}for(let l of e.unmet)s.push({from:`constraint-${l.fromConstraint}`,to:`req-${l.requirement.type}`});for(let l of e.resolverDefs)m.has(l.requirement)&&s.push({from:`req-${l.requirement}`,to:`resolver-${l.id}`});let f=new Map(r.map(l=>[l.id,l])),x=960,R=Math.max(...r.map(l=>l.y))+50+20,Ne=s.map(l=>{let b=f.get(l.from),X=f.get(l.to);return !b||!X?"":`<line x1="${b.x+90}" y1="${b.y+15}" x2="${X.x}" y2="${X.y+15}" stroke="#94a3b8" stroke-width="1.5" marker-end="url(#arrow)"/>`}).join(`
817
+ `),je=r.map(l=>`<g>
818
+ <rect x="${l.x}" y="${l.y}" width="180" height="30" rx="6" fill="${l.color}" opacity="0.15" stroke="${l.color}" stroke-width="1.5"/>
819
+ <text x="${l.x+90}" y="${l.y+19}" text-anchor="middle" font-size="12" font-family="monospace" fill="${l.color}">${qt(l.label)}</text>
820
+ </g>`).join(`
821
+ `),Ue=["Facts","Constraints","Requirements","Resolvers"].map((l,b)=>`<text x="${40+b*220+90}" y="35" text-anchor="middle" font-size="14" font-weight="bold" font-family="system-ui" fill="#e2e8f0">${l}</text>`).join(`
822
+ `);return `<!DOCTYPE html>
2376
823
  <html>
2377
824
  <head>
2378
825
  <title>Directive System Graph</title>
@@ -2382,448 +829,22 @@ function renderHtmlGraph(inspection, facts) {
2382
829
  </style>
2383
830
  </head>
2384
831
  <body>
2385
- <svg width="${svgWidth}" height="${maxY}" xmlns="http://www.w3.org/2000/svg">
832
+ <svg width="${x}" height="${R}" xmlns="http://www.w3.org/2000/svg">
2386
833
  <defs>
2387
834
  <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
2388
835
  <path d="M 0 0 L 10 5 L 0 10 z" fill="#94a3b8"/>
2389
836
  </marker>
2390
837
  </defs>
2391
- ${headerSvg}
2392
- ${edgeSvg}
2393
- ${nodeSvg}
838
+ ${Ue}
839
+ ${Ne}
840
+ ${je}
2394
841
  </svg>
2395
842
  </body>
2396
- </html>`;
2397
- }
2398
- function escapeHtml(text2) {
2399
- return text2.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
2400
- }
2401
- async function graphCommand(args) {
2402
- const { filePath, opts } = parseArgs6(args);
2403
- if (!filePath) {
2404
- console.error("Usage: directive graph <file> [--ascii] [--no-open] [--output <path>]");
2405
- process.exit(1);
2406
- }
2407
- const system = await loadSystem(filePath);
2408
- if (!system.isRunning) {
2409
- system.start();
2410
- }
2411
- const inspection = system.inspect();
2412
- if (opts.ascii) {
2413
- console.log(renderAsciiGraph(inspection));
2414
- system.stop();
2415
- return;
2416
- }
2417
- const factsObj = {};
2418
- if (system.facts) {
2419
- for (const key of Object.keys(system.facts)) {
2420
- try {
2421
- factsObj[key] = system.facts[key];
2422
- } catch {
2423
- factsObj[key] = null;
2424
- }
2425
- }
2426
- }
2427
- const html = renderHtmlGraph(inspection, factsObj);
2428
- const outputPath = opts.output || join(process.cwd(), ".directive-graph.html");
2429
- writeFileSync(outputPath, html, "utf-8");
2430
- console.log(`${pc5.green("Generated")} ${pc5.dim(outputPath)}`);
2431
- if (opts.open) {
2432
- try {
2433
- const { exec } = await import('child_process');
2434
- const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
2435
- exec(`${openCmd} "${outputPath}"`);
2436
- console.log(pc5.dim("Opened in browser."));
2437
- } catch {
2438
- console.log(
2439
- pc5.dim(`Open ${outputPath} in your browser to view the graph.`)
2440
- );
2441
- }
2442
- }
2443
- system.stop();
2444
- }
2445
- function parseArgs7(args) {
2446
- const opts = { dir: process.cwd() };
2447
- for (let i = 0; i < args.length; i++) {
2448
- if (args[i] === "--dir") {
2449
- const val = args[++i];
2450
- if (val) {
2451
- opts.dir = val;
2452
- }
2453
- }
2454
- }
2455
- return opts;
2456
- }
2457
- function checkCoreInstalled(dir) {
2458
- const pkgPath = join(dir, "package.json");
2459
- if (!existsSync(pkgPath)) {
2460
- return {
2461
- label: "@directive-run/core installed",
2462
- passed: false,
2463
- message: "No package.json found",
2464
- fix: "Run `npm init` to create a package.json"
2465
- };
2466
- }
2467
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
2468
- const deps = { ...pkg.dependencies, ...pkg.devDependencies };
2469
- if (!deps["@directive-run/core"]) {
2470
- return {
2471
- label: "@directive-run/core installed",
2472
- passed: false,
2473
- message: "Not found in dependencies",
2474
- fix: "Run `npm install @directive-run/core`"
2475
- };
2476
- }
2477
- return {
2478
- label: "@directive-run/core installed",
2479
- passed: true,
2480
- message: `v${deps["@directive-run/core"]}`
2481
- };
2482
- }
2483
- function checkVersionCompatibility(dir) {
2484
- const pkgPath = join(dir, "package.json");
2485
- if (!existsSync(pkgPath)) {
2486
- return {
2487
- label: "Package version compatibility",
2488
- passed: true,
2489
- message: "Skipped (no package.json)"
2490
- };
2491
- }
2492
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
2493
- const deps = { ...pkg.dependencies, ...pkg.devDependencies };
2494
- const directivePackages = Object.keys(deps).filter(
2495
- (k) => k.startsWith("@directive-run/")
2496
- );
2497
- if (directivePackages.length <= 1) {
2498
- return {
2499
- label: "Package version compatibility",
2500
- passed: true,
2501
- message: directivePackages.length === 0 ? "No packages found" : "Single package"
2502
- };
2503
- }
2504
- return {
2505
- label: "Package version compatibility",
2506
- passed: true,
2507
- message: `${directivePackages.length} packages: ${directivePackages.join(", ")}`
2508
- };
2509
- }
2510
- function checkTypeScript(dir) {
2511
- const tsconfigPath = join(dir, "tsconfig.json");
2512
- if (!existsSync(tsconfigPath)) {
2513
- return {
2514
- label: "TypeScript configuration",
2515
- passed: false,
2516
- message: "No tsconfig.json found",
2517
- fix: "Run `tsc --init` to create a TypeScript configuration"
2518
- };
2519
- }
2520
- try {
2521
- const raw = readFileSync(tsconfigPath, "utf-8");
2522
- const stripped = raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
2523
- const config = JSON.parse(stripped);
2524
- const co = config.compilerOptions || {};
2525
- const issues = [];
2526
- if (co.strict !== true) {
2527
- issues.push("strict mode not enabled");
2528
- }
2529
- if (co.moduleResolution && !["bundler", "nodenext", "node16"].includes(
2530
- co.moduleResolution.toLowerCase()
2531
- )) {
2532
- issues.push(`moduleResolution is "${co.moduleResolution}"`);
2533
- }
2534
- if (issues.length > 0) {
2535
- return {
2536
- label: "TypeScript configuration",
2537
- passed: false,
2538
- message: issues.join(", "),
2539
- fix: 'Set "strict": true and "moduleResolution": "bundler" in tsconfig.json'
2540
- };
2541
- }
2542
- return {
2543
- label: "TypeScript configuration",
2544
- passed: true,
2545
- message: "strict mode, correct module resolution"
2546
- };
2547
- } catch {
2548
- return {
2549
- label: "TypeScript configuration",
2550
- passed: true,
2551
- message: "Found (could not parse for detailed checks)"
2552
- };
2553
- }
2554
- }
2555
- function checkDuplicateInstances(dir) {
2556
- const nodeModules = join(dir, "node_modules");
2557
- if (!existsSync(nodeModules)) {
2558
- return {
2559
- label: "No duplicate Directive instances",
2560
- passed: true,
2561
- message: "No node_modules found"
2562
- };
2563
- }
2564
- const duplicates = [];
2565
- try {
2566
- const scopeDir = join(nodeModules, "@directive-run");
2567
- if (existsSync(scopeDir)) {
2568
- const packages = readdirSync(scopeDir);
2569
- for (const pkg of packages) {
2570
- const nestedCore = join(
2571
- scopeDir,
2572
- pkg,
2573
- "node_modules",
2574
- "@directive-run",
2575
- "core"
2576
- );
2577
- if (existsSync(nestedCore)) {
2578
- duplicates.push(`@directive-run/${pkg}/node_modules/@directive-run/core`);
2579
- }
2580
- }
2581
- }
2582
- } catch {
2583
- }
2584
- if (duplicates.length > 0) {
2585
- return {
2586
- label: "No duplicate Directive instances",
2587
- passed: false,
2588
- message: `Found ${duplicates.length} duplicate(s): ${duplicates.join(", ")}`,
2589
- fix: "Run `npm dedupe` or check for version mismatches"
2590
- };
2591
- }
2592
- return {
2593
- label: "No duplicate Directive instances",
2594
- passed: true,
2595
- message: "No duplicates detected"
2596
- };
2597
- }
2598
- function checkAIRulesFreshness(dir) {
2599
- const ruleFiles = [
2600
- ".cursorrules",
2601
- ".claude/CLAUDE.md",
2602
- ".github/copilot-instructions.md",
2603
- ".windsurfrules",
2604
- ".clinerules"
2605
- ];
2606
- const found = [];
2607
- for (const file of ruleFiles) {
2608
- const filePath = join(dir, file);
2609
- if (existsSync(filePath)) {
2610
- const content = readFileSync(filePath, "utf-8");
2611
- if (hasDirectiveSection(content)) {
2612
- found.push(file);
2613
- }
2614
- }
2615
- }
2616
- if (found.length === 0) {
2617
- return {
2618
- label: "AI coding rules",
2619
- passed: true,
2620
- message: "Not installed (optional)"
2621
- };
2622
- }
2623
- return {
2624
- label: "AI coding rules",
2625
- passed: true,
2626
- message: `Installed for: ${found.join(", ")}`
2627
- };
2628
- }
2629
- async function doctorCommand(args) {
2630
- const opts = parseArgs7(args);
2631
- console.log();
2632
- console.log(pc5.bold(pc5.cyan("Directive Doctor")));
2633
- console.log(pc5.dim("\u2500".repeat(40)));
2634
- console.log();
2635
- const checks = [
2636
- checkCoreInstalled(opts.dir),
2637
- checkVersionCompatibility(opts.dir),
2638
- checkTypeScript(opts.dir),
2639
- checkDuplicateInstances(opts.dir),
2640
- checkAIRulesFreshness(opts.dir)
2641
- ];
2642
- let failures = 0;
2643
- for (const check of checks) {
2644
- const icon = check.passed ? pc5.green("\u2713") : pc5.red("\u2717");
2645
- console.log(`${icon} ${pc5.bold(check.label)}`);
2646
- console.log(` ${pc5.dim(check.message)}`);
2647
- if (!check.passed && check.fix) {
2648
- console.log(` ${pc5.yellow("Fix:")} ${check.fix}`);
2649
- failures++;
2650
- }
2651
- console.log();
2652
- }
2653
- if (failures > 0) {
2654
- console.log(
2655
- pc5.yellow(`${failures} issue(s) found. See suggested fixes above.`)
2656
- );
2657
- process.exit(1);
2658
- } else {
2659
- console.log(pc5.green("All checks passed!"));
2660
- }
2661
- }
2662
- var CATEGORIES = {
2663
- "Getting Started": ["counter", "contact-form", "auth-flow"],
2664
- "Core Patterns": [
2665
- "async-chains",
2666
- "batch-resolver",
2667
- "debounce-constraints",
2668
- "error-boundaries",
2669
- "feature-flags",
2670
- "multi-module",
2671
- "optimistic-updates",
2672
- "pagination",
2673
- "permissions"
2674
- ],
2675
- "Real-World": [
2676
- "dashboard-loader",
2677
- "form-wizard",
2678
- "newsletter",
2679
- "notifications",
2680
- "shopping-cart",
2681
- "theme-locale",
2682
- "url-sync",
2683
- "websocket",
2684
- "server"
2685
- ],
2686
- Games: ["checkers", "sudoku", "goal-heist", "ab-testing"],
2687
- AI: [
2688
- "ai-orchestrator",
2689
- "ai-checkpoint",
2690
- "ai-guardrails",
2691
- "fraud-analysis",
2692
- "provider-routing",
2693
- "topic-guard",
2694
- "dynamic-modules",
2695
- "time-machine"
2696
- ]
2697
- };
2698
- function getCategory(name) {
2699
- for (const [cat, names] of Object.entries(CATEGORIES)) {
2700
- if (names.includes(name)) {
2701
- return cat;
2702
- }
2703
- }
2704
- return "Other";
2705
- }
2706
- function getDescription(content) {
2707
- const lines = content.split("\n");
2708
- for (const line of lines) {
2709
- const trimmed = line.trim();
2710
- if (trimmed.startsWith("// Example:")) {
2711
- continue;
2712
- }
2713
- if (trimmed.startsWith("// Source:")) {
2714
- continue;
2715
- }
2716
- if (trimmed.startsWith("// Extracted")) {
2717
- continue;
2718
- }
2719
- const jsdocMatch = trimmed.match(/^\*\s+(.+?)(?:\s*\*\/)?$/);
2720
- if (jsdocMatch?.[1] && !jsdocMatch[1].startsWith("@")) {
2721
- return jsdocMatch[1];
2722
- }
2723
- if (trimmed.startsWith("//") && trimmed.length > 3) {
2724
- return trimmed.slice(2).trim();
2725
- }
2726
- if (trimmed !== "" && !trimmed.startsWith("//") && !trimmed.startsWith("/*") && !trimmed.startsWith("*")) {
2727
- break;
2728
- }
2729
- }
2730
- return "";
2731
- }
2732
- async function examplesListCommand(args) {
2733
- let filter;
2734
- for (let i = 0; i < args.length; i++) {
2735
- if (args[i] === "--filter") {
2736
- filter = args[++i]?.toLowerCase();
2737
- }
2738
- }
2739
- const examples = getAllExamples();
2740
- console.log();
2741
- console.log(pc5.bold(pc5.cyan("Directive Examples")));
2742
- console.log(pc5.dim("\u2500".repeat(50)));
2743
- console.log();
2744
- const byCategory = /* @__PURE__ */ new Map();
2745
- for (const [name, content] of examples) {
2746
- const cat = getCategory(name);
2747
- if (filter && !cat.toLowerCase().includes(filter) && !name.includes(filter)) {
2748
- continue;
2749
- }
2750
- if (!byCategory.has(cat)) {
2751
- byCategory.set(cat, []);
2752
- }
2753
- byCategory.get(cat).push({ name, desc: getDescription(content) });
2754
- }
2755
- if (byCategory.size === 0) {
2756
- console.log(pc5.dim("No examples match the filter."));
2757
- return;
2758
- }
2759
- const categoryOrder = Object.keys(CATEGORIES);
2760
- const sortedCategories = [...byCategory.keys()].sort(
2761
- (a, b) => (categoryOrder.indexOf(a) ?? 99) - (categoryOrder.indexOf(b) ?? 99)
2762
- );
2763
- for (const cat of sortedCategories) {
2764
- const items = byCategory.get(cat);
2765
- console.log(pc5.bold(cat));
2766
- for (const item of items) {
2767
- const desc = item.desc ? pc5.dim(` \u2014 ${item.desc}`) : "";
2768
- console.log(` ${pc5.cyan(item.name)}${desc}`);
2769
- }
2770
- console.log();
2771
- }
2772
- console.log(
2773
- pc5.dim(`${examples.size} examples available. Run ${pc5.cyan("directive examples copy <name>")} to extract one.`)
2774
- );
2775
- }
2776
- async function examplesCopyCommand(name, args) {
2777
- let dest = process.cwd();
2778
- for (let i = 0; i < args.length; i++) {
2779
- if (args[i] === "--dest") {
2780
- const val = args[++i];
2781
- if (val) {
2782
- dest = val;
2783
- }
2784
- }
2785
- }
2786
- if (!name) {
2787
- console.error("Usage: directive examples copy <name> [--dest <dir>]");
2788
- process.exit(1);
2789
- }
2790
- const content = getExample(name);
2791
- if (!content) {
2792
- console.error(`Example "${name}" not found.`);
2793
- console.error(
2794
- `Run ${pc5.cyan("directive examples list")} to see available examples.`
2795
- );
2796
- process.exit(1);
2797
- }
2798
- const rewritten = content.replace(
2799
- /from\s+["']@directive-run\/core\/plugins["']/g,
2800
- 'from "@directive-run/core/plugins"'
2801
- ).replace(
2802
- /from\s+["']@directive-run\/core["']/g,
2803
- 'from "@directive-run/core"'
2804
- ).replace(
2805
- /from\s+["']@directive-run\/ai["']/g,
2806
- 'from "@directive-run/ai"'
2807
- );
2808
- const filePath = join(dest, `${name}.ts`);
2809
- if (existsSync(filePath)) {
2810
- console.error(`File already exists: ${relative(process.cwd(), filePath)}`);
2811
- process.exit(1);
2812
- }
2813
- const dir = dirname(filePath);
2814
- if (!existsSync(dir)) {
2815
- mkdirSync(dir, { recursive: true });
2816
- }
2817
- writeFileSync(filePath, rewritten, "utf-8");
2818
- const rel = relative(process.cwd(), filePath);
2819
- console.log(`${pc5.green("Copied")} ${pc5.cyan(name)} \u2192 ${pc5.dim(rel)}`);
2820
- }
843
+ </html>`}function qt(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}async function Me(e){let{filePath:t,opts:r}=Rt(e);t||(console.error("Usage: directive graph <file> [--ascii] [--no-open] [--output <path>]"),process.exit(1));let s=await U(t);s.isRunning||s.start();let o=s.inspect();if(r.ascii){console.log(Tt(o)),s.stop();return}let i={};if(s.facts)for(let c of Object.keys(s.facts))try{i[c]=s.facts[c];}catch{i[c]=null;}let n=Mt(o,i),a=r.output||join(process.cwd(),".directive-graph.html");if(writeFileSync(a,n,"utf-8"),console.log(`${d.green("Generated")} ${d.dim(a)}`),r.open)try{let{execFile:c}=await import('child_process'),m=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";c(m,[a]),console.log(d.dim("Opened in browser."));}catch{console.log(d.dim(`Open ${a} in your browser to view the graph.`));}s.stop();}function Dt(e){let t={dir:process.cwd()};for(let r=0;r<e.length;r++)if(e[r]==="--dir"){let s=e[++r];s&&(t.dir=s);}return t}function It(e){let t=join(e,"package.json");if(!existsSync(t))return {label:"@directive-run/core installed",passed:false,message:"No package.json found",fix:"Run `npm init` to create a package.json"};let r=JSON.parse(readFileSync(t,"utf-8")),s={...r.dependencies,...r.devDependencies};return s["@directive-run/core"]?{label:"@directive-run/core installed",passed:true,message:`v${s["@directive-run/core"]}`}:{label:"@directive-run/core installed",passed:false,message:"Not found in dependencies",fix:"Run `npm install @directive-run/core`"}}function Pt(e){let t=join(e,"package.json");if(!existsSync(t))return {label:"Package version compatibility",passed:true,message:"Skipped (no package.json)"};let r=JSON.parse(readFileSync(t,"utf-8")),s={...r.dependencies,...r.devDependencies},o=Object.keys(s).filter(i=>i.startsWith("@directive-run/"));return o.length<=1?{label:"Package version compatibility",passed:true,message:o.length===0?"No packages found":"Single package"}:{label:"Package version compatibility",passed:true,message:`${o.length} packages: ${o.join(", ")}`}}function Et(e){let t=join(e,"tsconfig.json");if(!existsSync(t))return {label:"TypeScript configuration",passed:false,message:"No tsconfig.json found",fix:"Run `tsc --init` to create a TypeScript configuration"};try{let s=readFileSync(t,"utf-8").replace(/\/\/.*$/gm,"").replace(/\/\*[\s\S]*?\*\//g,""),i=JSON.parse(s).compilerOptions||{},n=[];return i.strict!==!0&&n.push("strict mode not enabled"),i.moduleResolution&&!["bundler","nodenext","node16"].includes(i.moduleResolution.toLowerCase())&&n.push(`moduleResolution is "${i.moduleResolution}"`),n.length>0?{label:"TypeScript configuration",passed:!1,message:n.join(", "),fix:'Set "strict": true and "moduleResolution": "bundler" in tsconfig.json'}:{label:"TypeScript configuration",passed:!0,message:"strict mode, correct module resolution"}}catch{return {label:"TypeScript configuration",passed:true,message:"Found (could not parse for detailed checks)"}}}function Nt(e){let t=join(e,"node_modules");if(!existsSync(t))return {label:"No duplicate Directive instances",passed:true,message:"No node_modules found"};let r=[];try{let s=join(t,"@directive-run");if(existsSync(s)){let o=readdirSync(s);for(let i of o){let n=join(s,i,"node_modules","@directive-run","core");existsSync(n)&&r.push(`@directive-run/${i}/node_modules/@directive-run/core`);}}}catch{}return r.length>0?{label:"No duplicate Directive instances",passed:false,message:`Found ${r.length} duplicate(s): ${r.join(", ")}`,fix:"Run `npm dedupe` or check for version mismatches"}:{label:"No duplicate Directive instances",passed:true,message:"No duplicates detected"}}function jt(e){let t=[".cursorrules",".claude/CLAUDE.md",".github/copilot-instructions.md",".windsurfrules",".clinerules"],r=[];for(let s of t){let o=join(e,s);if(existsSync(o)){let i=readFileSync(o,"utf-8");P(i)&&r.push(s);}}return r.length===0?{label:"AI coding rules",passed:true,message:"Not installed (optional)"}:{label:"AI coding rules",passed:true,message:`Installed for: ${r.join(", ")}`}}async function qe(e){let t=Dt(e);console.log(),console.log(d.bold(d.cyan("Directive Doctor"))),console.log(d.dim("\u2500".repeat(40))),console.log();let r=[It(t.dir),Pt(t.dir),Et(t.dir),Nt(t.dir),jt(t.dir)],s=0;for(let o of r){let i=o.passed?d.green("\u2713"):d.red("\u2717");console.log(`${i} ${d.bold(o.label)}`),console.log(` ${d.dim(o.message)}`),!o.passed&&o.fix&&(console.log(` ${d.yellow("Fix:")} ${o.fix}`),s++),console.log();}s>0?(console.log(d.yellow(`${s} issue(s) found. See suggested fixes above.`)),process.exit(1)):console.log(d.green("All checks passed!"));}var Ie={"Getting Started":["counter","contact-form","auth-flow"],"Core Patterns":["async-chains","batch-resolver","debounce-constraints","error-boundaries","feature-flags","multi-module","optimistic-updates","pagination","permissions"],"Real-World":["dashboard-loader","form-wizard","newsletter","notifications","shopping-cart","theme-locale","url-sync","websocket","server"],Games:["checkers","sudoku","goal-heist","ab-testing"],AI:["ai-orchestrator","ai-checkpoint","ai-guardrails","fraud-analysis","provider-routing","topic-guard","dynamic-modules","time-machine"]};function Ft(e){for(let[t,r]of Object.entries(Ie))if(r.includes(e))return t;return "Other"}function _t(e){let t=e.split(`
844
+ `);for(let r of t){let s=r.trim();if(s.startsWith("// Example:")||s.startsWith("// Source:")||s.startsWith("// Extracted"))continue;let o=s.match(/^\*\s+(.+?)(?:\s*\*\/)?$/);if(o?.[1]&&!o[1].startsWith("@"))return o[1];if(s.startsWith("//")&&s.length>3)return s.slice(2).trim();if(s!==""&&!s.startsWith("//")&&!s.startsWith("/*")&&!s.startsWith("*"))break}return ""}async function Pe(e){let t;for(let n=0;n<e.length;n++)e[n]==="--filter"&&(t=e[++n]?.toLowerCase());let r=getAllExamples();console.log(),console.log(d.bold(d.cyan("Directive Examples"))),console.log(d.dim("\u2500".repeat(50))),console.log();let s=new Map;for(let[n,a]of r){let c=Ft(n);t&&!c.toLowerCase().includes(t)&&!n.includes(t)||(s.has(c)||s.set(c,[]),s.get(c).push({name:n,desc:_t(a)}));}if(s.size===0){console.log(d.dim("No examples match the filter."));return}let o=Object.keys(Ie),i=[...s.keys()].sort((n,a)=>(o.indexOf(n)??99)-(o.indexOf(a)??99));for(let n of i){let a=s.get(n);console.log(d.bold(n));for(let c of a){let m=c.desc?d.dim(` \u2014 ${c.desc}`):"";console.log(` ${d.cyan(c.name)}${m}`);}console.log();}console.log(d.dim(`${r.size} examples available. Run ${d.cyan("directive examples copy <name>")} to extract one.`));}async function Ee(e,t){let r=process.cwd();for(let c=0;c<t.length;c++)if(t[c]==="--dest"){let m=t[++c];m&&(r=m);}e||(console.error("Usage: directive examples copy <name> [--dest <dir>]"),process.exit(1));let s=getExample(e);s||(console.error(`Example "${e}" not found.`),console.error(`Run ${d.cyan("directive examples list")} to see available examples.`),process.exit(1));let o=s.replace(/from\s+["']@directive-run\/core\/plugins["']/g,'from "@directive-run/core/plugins"').replace(/from\s+["']@directive-run\/core["']/g,'from "@directive-run/core"').replace(/from\s+["']@directive-run\/ai["']/g,'from "@directive-run/ai"'),i=join(r,`${e}.ts`);existsSync(i)&&(console.error(`File already exists: ${relative(process.cwd(),i)}`),process.exit(1));let n=dirname(i);existsSync(n)||mkdirSync(n,{recursive:true}),writeFileSync(i,o,"utf-8");let a=relative(process.cwd(),i);console.log(`${d.green("Copied")} ${d.cyan(e)} \u2192 ${d.dim(a)}`);}var zt=`
845
+ ${y} \u2014 CLI tools for Directive
2821
846
 
2822
- // src/cli.ts
2823
- var HELP = `
2824
- ${CLI_NAME} \u2014 CLI tools for Directive
2825
-
2826
- Usage: ${CLI_NAME} <command> [options]
847
+ Usage: ${y} <command> [options]
2827
848
 
2828
849
  Commands:
2829
850
  init Project scaffolding wizard
@@ -2871,122 +892,13 @@ ai-rules init options:
2871
892
  examples options:
2872
893
  --filter <category> Filter by category or name
2873
894
  --dest <dir> Destination directory for copy
2874
- `.trim();
2875
- async function main() {
2876
- const args = process.argv.slice(2);
2877
- if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
2878
- console.log(HELP);
2879
- process.exit(0);
2880
- }
2881
- if (args.includes("--version") || args.includes("-v")) {
2882
- const { readFileSync: readFileSync4 } = await import('fs');
2883
- const { fileURLToPath } = await import('url');
2884
- const { dirname: dirname6, join: join9 } = await import('path');
2885
- const __dirname = dirname6(fileURLToPath(import.meta.url));
2886
- const pkg = JSON.parse(
2887
- readFileSync4(join9(__dirname, "..", "package.json"), "utf-8")
2888
- );
2889
- console.log(pkg.version);
2890
- process.exit(0);
2891
- }
2892
- const command = args[0];
2893
- switch (command) {
2894
- case "init": {
2895
- await initCommand(args.slice(1));
2896
- break;
2897
- }
2898
- case "new": {
2899
- const subcommand = args[1];
2900
- const name = args[2];
2901
- if (subcommand === "module") {
2902
- if (!name) {
2903
- console.error("Usage: directive new module <name>");
2904
- process.exit(1);
2905
- }
2906
- await newModuleCommand(name, args.slice(3));
2907
- } else if (subcommand === "orchestrator") {
2908
- if (!name) {
2909
- console.error("Usage: directive new orchestrator <name>");
2910
- process.exit(1);
2911
- }
2912
- await newOrchestratorCommand(name, args.slice(3));
2913
- } else {
2914
- console.error(
2915
- `Unknown subcommand: ${subcommand ?? "(none)"}
2916
- Usage: ${CLI_NAME} new module <name>
2917
- ${CLI_NAME} new orchestrator <name>`
2918
- );
2919
- process.exit(1);
2920
- }
2921
- break;
2922
- }
2923
- case "inspect": {
2924
- await inspectCommand(args.slice(1));
2925
- break;
2926
- }
2927
- case "explain": {
2928
- await explainCommand(args.slice(1));
2929
- break;
2930
- }
2931
- case "graph": {
2932
- await graphCommand(args.slice(1));
2933
- break;
2934
- }
2935
- case "doctor": {
2936
- await doctorCommand(args.slice(1));
2937
- break;
2938
- }
2939
- case "ai-rules": {
2940
- const subcommand = args[1];
2941
- if (subcommand === "init") {
2942
- await aiRulesCommand(args.slice(2));
2943
- } else if (subcommand === "update") {
2944
- await aiRulesUpdateCommand(args.slice(2));
2945
- } else if (subcommand === "check") {
2946
- await aiRulesCheckCommand(args.slice(2));
2947
- } else {
2948
- console.error(
2949
- `Unknown subcommand: ${subcommand ?? "(none)"}
2950
- Usage: ${CLI_NAME} ai-rules init
2951
- ${CLI_NAME} ai-rules update
2952
- ${CLI_NAME} ai-rules check`
2953
- );
2954
- process.exit(1);
2955
- }
2956
- break;
2957
- }
2958
- case "examples": {
2959
- const subcommand = args[1];
2960
- if (subcommand === "list") {
2961
- await examplesListCommand(args.slice(2));
2962
- } else if (subcommand === "copy") {
2963
- const name = args[2];
2964
- if (!name) {
2965
- console.error("Usage: directive examples copy <name>");
2966
- process.exit(1);
2967
- }
2968
- await examplesCopyCommand(name, args.slice(3));
2969
- } else {
2970
- console.error(
2971
- `Unknown subcommand: ${subcommand ?? "(none)"}
2972
- Usage: ${CLI_NAME} examples list [--filter <category>]
2973
- ${CLI_NAME} examples copy <name> [--dest <dir>]`
2974
- );
2975
- process.exit(1);
2976
- }
2977
- break;
2978
- }
2979
- default:
2980
- console.error(
2981
- `Unknown command: ${command}
2982
- Run '${CLI_NAME} --help' for usage.`
2983
- );
2984
- process.exit(1);
2985
- }
2986
- }
2987
- main().catch((err) => {
2988
- console.error(err.message || err);
2989
- process.exit(1);
2990
- });
2991
- //# sourceMappingURL=cli.js.map
895
+ `.trim();async function Ht(){let e=process.argv.slice(2);if((e.length===0||e.includes("--help")||e.includes("-h"))&&(console.log(zt),process.exit(0)),e.includes("--version")||e.includes("-v")){let{readFileSync:r}=await import('fs'),{fileURLToPath:s}=await import('url'),{dirname:o,join:i}=await import('path'),n=o(s(import.meta.url)),a=JSON.parse(r(i(n,"..","package.json"),"utf-8"));console.log(a.version),process.exit(0);}let t=e[0];switch(t){case "init":{await ve(e.slice(1));break}case "new":{let r=e[1],s=e[2];r==="module"?(s||(console.error("Usage: directive new module <name>"),process.exit(1)),await Se(s,e.slice(3))):r==="orchestrator"?(s||(console.error("Usage: directive new orchestrator <name>"),process.exit(1)),await Ce(s,e.slice(3))):(console.error(`Unknown subcommand: ${r??"(none)"}
896
+ Usage: ${y} new module <name>
897
+ ${y} new orchestrator <name>`),process.exit(1));break}case "inspect":{await Ae(e.slice(1));break}case "explain":{await Te(e.slice(1));break}case "graph":{await Me(e.slice(1));break}case "doctor":{await qe(e.slice(1));break}case "ai-rules":{let r=e[1];r==="init"?await ge(e.slice(2)):r==="update"?await he(e.slice(2)):r==="check"?await ye(e.slice(2)):(console.error(`Unknown subcommand: ${r??"(none)"}
898
+ Usage: ${y} ai-rules init
899
+ ${y} ai-rules update
900
+ ${y} ai-rules check`),process.exit(1));break}case "examples":{let r=e[1];if(r==="list")await Pe(e.slice(2));else if(r==="copy"){let s=e[2];s||(console.error("Usage: directive examples copy <name>"),process.exit(1)),await Ee(s,e.slice(3));}else console.error(`Unknown subcommand: ${r??"(none)"}
901
+ Usage: ${y} examples list [--filter <category>]
902
+ ${y} examples copy <name> [--dest <dir>]`),process.exit(1);break}default:console.error(`Unknown command: ${t}
903
+ Run '${y} --help' for usage.`),process.exit(1);}}Ht().catch(e=>{console.error(e.message||e),process.exit(1);});//# sourceMappingURL=cli.js.map
2992
904
  //# sourceMappingURL=cli.js.map