@jsleekr/graft 6.0.1 → 6.1.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/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  Write `.gft` files to define multi-agent pipelines. The compiler generates `.claude/` harness structures — agents, hooks, orchestration plans, settings — with compile-time token budget analysis.
10
10
 
11
- **[Documentation](https://jsleekr.github.io/graft/)** | **[User Guide](docs/guide.md)** | **[Examples](examples/)**
11
+ **[Documentation](https://jsleekr.github.io/graft/)** | **[Playground](https://jsleekr.github.io/graft/playground/)** | **[User Guide](docs/guide.md)** | **[Examples](examples/)**
12
12
 
13
13
  ---
14
14
 
@@ -137,7 +137,7 @@ Claude Code reads the .claude/ structure and runs the pipeline
137
137
  ## CLI
138
138
 
139
139
  ```bash
140
- graft init <name> # Scaffold project + inject CLAUDE.md spec
140
+ graft init [name] # New project, or add Graft to current dir
141
141
  graft compile <file.gft> [--out-dir <dir>] # Compile to .claude/ harness
142
142
  graft check <file.gft> # Parse + analyze only
143
143
  graft run <file.gft> --input <json> # Compile and execute
@@ -41,9 +41,9 @@ export function generate(program, report, sourceFile, index, backend) {
41
41
  }
42
42
  }
43
43
  }
44
- // Orchestration
44
+ // Orchestration (separate file — does not overwrite CLAUDE.md)
45
45
  files.push({
46
- path: '.claude/CLAUDE.md',
46
+ path: '.claude/orchestration.md',
47
47
  content: be.generateOrchestration(ctx),
48
48
  });
49
49
  // Settings
package/dist/index.js CHANGED
@@ -137,19 +137,23 @@ program
137
137
  });
138
138
  program
139
139
  .command('init')
140
- .description('Scaffold a new Graft project')
141
- .argument('<name>', 'project name')
140
+ .description('Scaffold a new Graft project, or add Graft to an existing project')
141
+ .argument('[name]', 'project name (omit to set up current directory)')
142
142
  .action(async (name) => {
143
- const dir = path.resolve(name);
144
- if (fs.existsSync(dir)) {
145
- console.error(`Error: directory '${name}' already exists`);
146
- process.exit(1);
143
+ const isExisting = !name;
144
+ const dir = name ? path.resolve(name) : process.cwd();
145
+ if (name) {
146
+ if (fs.existsSync(dir)) {
147
+ console.error(`Error: directory '${name}' already exists`);
148
+ process.exit(1);
149
+ }
150
+ fs.mkdirSync(dir, { recursive: true });
147
151
  }
148
- fs.mkdirSync(dir, { recursive: true });
149
- const baseName = path.basename(name);
152
+ const baseName = path.basename(dir);
150
153
  const safeName = baseName.replace(/[^a-zA-Z0-9]/g, '_').replace(/^_+|_+$/g, '') || 'pipeline';
151
- // Generate pipeline.gft starter template
152
- fs.writeFileSync(path.join(dir, 'pipeline.gft'), `// ${safeName} — a simple two-node pipeline
154
+ // Generate pipeline.gft starter template (only for new projects)
155
+ if (!isExisting) {
156
+ fs.writeFileSync(path.join(dir, 'pipeline.gft'), `// ${safeName} — a simple two-node pipeline
153
157
 
154
158
  context Input(max_tokens: 500) {
155
159
  question: String
@@ -177,23 +181,30 @@ graph ${safeName}(input: Input, output: Output, budget: 10k) {
177
181
  Analyst -> Reviewer -> done
178
182
  }
179
183
  `);
180
- // Generate .claude/CLAUDE.md with .gft spec so Claude Code natively understands Graft
184
+ }
185
+ // Generate .claude/ config files
181
186
  const claudeDir = path.join(dir, '.claude');
182
187
  fs.mkdirSync(claudeDir, { recursive: true });
183
188
  const { buildSystemPrompt } = await import('./generator.js');
184
189
  const gftSpec = buildSystemPrompt();
185
- fs.writeFileSync(path.join(claudeDir, 'CLAUDE.md'), `# ${safeName}
190
+ // 1. Write .gft spec to a separate file (never overwritten by compile)
191
+ const specPath = path.join(claudeDir, 'graft-spec.md');
192
+ const specContent = `# Graft — .gft Language Reference
186
193
 
187
- This project uses **Graft** (.gft) for defining multi-agent pipelines.
194
+ > Auto-generated by \`graft init\`. This file is the .gft syntax reference
195
+ > that Claude Code reads to understand the Graft language.
196
+ > Do NOT delete this file — \`graft compile\` does not touch it.
188
197
 
189
- ## Working with .gft files
198
+ ## Graft Multi-Agent Pipelines
199
+
200
+ This project uses **Graft** (.gft) for defining multi-agent pipelines.
190
201
 
191
202
  When the user asks to create, modify, or manage pipelines:
192
203
  1. Write or edit \`.gft\` files using the syntax below
193
204
  2. Run \`graft compile <file.gft>\` to generate the \`.claude/\` harness structure
194
205
  3. Run \`graft check <file.gft>\` to validate without generating files
195
206
 
196
- ## CLI Commands
207
+ ### CLI Commands
197
208
 
198
209
  \`\`\`bash
199
210
  graft compile <file.gft> [--out-dir <dir>] # Compile to harness structure
@@ -204,30 +215,47 @@ graft visualize <file.gft> # Output pipeline DAG as Mermaid
204
215
  graft watch <file.gft> # Watch and recompile on changes
205
216
  \`\`\`
206
217
 
207
- ## After Pipeline Execution
218
+ ### After Pipeline Execution
208
219
 
209
- When a pipeline run completes, \`graft run\` automatically:
220
+ \`graft run\` automatically:
210
221
  1. Shows a formatted result summary (nodes, tokens, timing)
211
222
  2. Validates output against the .gft schema (types, ranges, empty fields)
212
223
  3. Suggests .gft modifications if quality issues are found
213
224
 
214
- If the quality report shows issues:
215
- - Empty fields → suggest increasing node output budget
216
- - Budget exhaustion → suggest adding edge transforms (select, compact, truncate)
217
- - Node failures → suggest adding on_failure: retry(N)
218
- - Type mismatches → check the node's prompt and produces schema
219
-
220
- Apply the suggested fixes to the .gft file, then run \`graft compile\` and \`graft run\` again.
221
-
222
225
  ${gftSpec}
223
- `);
224
- console.log(`\nCreated ${name}/`);
225
- console.log(` pipeline.gft — starter pipeline template`);
226
- console.log(` .claude/CLAUDE.md — Graft spec for Claude Code`);
227
- console.log(`\nNext steps:`);
228
- console.log(` cd ${name}`);
229
- console.log(` graft compile pipeline.gft`);
230
- console.log(` # Open in Claude Code it already knows .gft syntax`);
226
+ `;
227
+ fs.writeFileSync(specPath, specContent);
228
+ // 2. Add Graft reference to CLAUDE.md (short pointer, not the full spec)
229
+ const claudeMdPath = path.join(claudeDir, 'CLAUDE.md');
230
+ const existingClaudeMd = fs.existsSync(claudeMdPath) ? fs.readFileSync(claudeMdPath, 'utf-8') : '';
231
+ const graftReference = `## Graft
232
+
233
+ This project uses Graft for multi-agent pipelines. Read \`.claude/graft-spec.md\` for the full .gft syntax reference. Run \`graft compile <file.gft>\` to generate harness files.`;
234
+ if (existingClaudeMd && existingClaudeMd.includes('graft-spec.md')) {
235
+ console.log(` .claude/CLAUDE.md already references Graft — skipped`);
236
+ }
237
+ else if (existingClaudeMd) {
238
+ fs.writeFileSync(claudeMdPath, existingClaudeMd.trimEnd() + '\n\n' + graftReference + '\n');
239
+ }
240
+ else {
241
+ fs.writeFileSync(claudeMdPath, `# ${safeName}\n\n` + graftReference + '\n');
242
+ }
243
+ if (isExisting) {
244
+ console.log(`\nGraft added to current project.`);
245
+ console.log(` .claude/CLAUDE.md — Graft spec injected`);
246
+ console.log(`\nNext steps:`);
247
+ console.log(` # Write a .gft file, or open Claude Code — it already knows .gft syntax`);
248
+ console.log(` graft compile <file.gft>`);
249
+ }
250
+ else {
251
+ console.log(`\nCreated ${name}/`);
252
+ console.log(` pipeline.gft — starter pipeline template`);
253
+ console.log(` .claude/CLAUDE.md — Graft spec for Claude Code`);
254
+ console.log(`\nNext steps:`);
255
+ console.log(` cd ${name}`);
256
+ console.log(` graft compile pipeline.gft`);
257
+ console.log(` # Open in Claude Code — it already knows .gft syntax`);
258
+ }
231
259
  console.log('');
232
260
  });
233
261
  program
@@ -0,0 +1,26 @@
1
+ import { TokenReport } from './analyzer/estimator.js';
2
+ import { Program } from './parser/ast.js';
3
+ import { GeneratedFile } from './codegen/codegen.js';
4
+ export interface PlaygroundResult {
5
+ success: boolean;
6
+ program?: Program;
7
+ report?: TokenReport;
8
+ files?: GeneratedFile[];
9
+ errors: Array<{
10
+ message: string;
11
+ line: number;
12
+ column: number;
13
+ severity: string;
14
+ code?: string;
15
+ formatted: string;
16
+ }>;
17
+ warnings: Array<{
18
+ message: string;
19
+ line: number;
20
+ column: number;
21
+ severity: string;
22
+ code?: string;
23
+ formatted: string;
24
+ }>;
25
+ }
26
+ export declare function compilePlayground(source: string, filename?: string): PlaygroundResult;
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Browser entry point for the Graft playground.
3
+ * Exports only the compiler pipeline (no fs, no runtime, no CLI).
4
+ */
5
+ import { Lexer } from './lexer/lexer.js';
6
+ import { Parser } from './parser/parser.js';
7
+ import { ScopeChecker } from './analyzer/scope.js';
8
+ import { TypeChecker } from './analyzer/types.js';
9
+ import { TokenEstimator } from './analyzer/estimator.js';
10
+ import { GraftError } from './errors/diagnostics.js';
11
+ import { ProgramIndex } from './program-index.js';
12
+ import { generate } from './codegen/codegen.js';
13
+ function serializeDiagnostic(e, source, filename) {
14
+ return {
15
+ message: e.message,
16
+ line: e.location.line,
17
+ column: e.location.column,
18
+ severity: e.severity,
19
+ code: e.code,
20
+ formatted: e.format(source, filename),
21
+ };
22
+ }
23
+ export function compilePlayground(source, filename = 'playground.gft') {
24
+ const errors = [];
25
+ const warnings = [];
26
+ // Lex
27
+ let tokens;
28
+ try {
29
+ const lexer = new Lexer(source);
30
+ tokens = lexer.tokenize();
31
+ }
32
+ catch (e) {
33
+ if (e instanceof GraftError) {
34
+ return {
35
+ success: false,
36
+ errors: [serializeDiagnostic(e, source, filename)],
37
+ warnings: [],
38
+ };
39
+ }
40
+ throw e;
41
+ }
42
+ // Parse
43
+ const { program, errors: parseErrors } = new Parser(tokens).parse();
44
+ errors.push(...parseErrors);
45
+ if (parseErrors.length > 0) {
46
+ return {
47
+ success: false,
48
+ program,
49
+ errors: errors.map(e => serializeDiagnostic(e, source, filename)),
50
+ warnings: [],
51
+ };
52
+ }
53
+ // Set sourceFile (no path.resolve — browser-safe)
54
+ for (const c of program.contexts)
55
+ c.sourceFile = filename;
56
+ for (const n of program.nodes)
57
+ n.sourceFile = filename;
58
+ // Build ProgramIndex
59
+ const index = new ProgramIndex(program);
60
+ // Analyze
61
+ const scopeDiagnostics = new ScopeChecker(program, index).check();
62
+ const typeDiagnostics = new TypeChecker(program, index).check();
63
+ for (const d of [...scopeDiagnostics, ...typeDiagnostics]) {
64
+ if (d.severity === 'warning')
65
+ warnings.push(d);
66
+ else
67
+ errors.push(d);
68
+ }
69
+ if (errors.length > 0) {
70
+ return {
71
+ success: false,
72
+ program,
73
+ errors: errors.map(e => serializeDiagnostic(e, source, filename)),
74
+ warnings: warnings.map(w => serializeDiagnostic(w, source, filename)),
75
+ };
76
+ }
77
+ // Token analysis
78
+ const report = new TokenEstimator(program, index).estimate();
79
+ warnings.push(...report.warnings);
80
+ // Generate files (if graph exists)
81
+ let files;
82
+ if (program.graphs.length > 0) {
83
+ files = generate(program, report, filename, index);
84
+ }
85
+ return {
86
+ success: true,
87
+ program,
88
+ report,
89
+ files,
90
+ errors: [],
91
+ warnings: warnings.map(w => serializeDiagnostic(w, source, filename)),
92
+ };
93
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsleekr/graft",
3
- "version": "6.0.1",
3
+ "version": "6.1.0",
4
4
  "description": "Graft compiler — compile .gft graph DSL to Claude Code harness structures",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -15,7 +15,17 @@
15
15
  "dsl",
16
16
  "llm",
17
17
  "claude",
18
- "graph"
18
+ "claude-code",
19
+ "multi-agent",
20
+ "pipeline",
21
+ "infrastructure-as-code",
22
+ "ai-agents",
23
+ "token-optimization",
24
+ "orchestration",
25
+ "graph",
26
+ "code-generation",
27
+ "developer-tools",
28
+ "automation"
19
29
  ],
20
30
  "main": "./dist/index.js",
21
31
  "types": "./dist/index.d.ts",
@@ -59,6 +69,7 @@
59
69
  "test": "vitest run",
60
70
  "test:watch": "vitest",
61
71
  "check": "tsc --noEmit",
72
+ "build:playground": "npx esbuild src/playground-entry.ts --bundle --format=iife --global-name=GraftCompiler --outfile=docs/playground/graft-compiler.js --platform=browser --alias:node:path=./scripts/playground-shims/node-path.js --alias:node:fs=./scripts/playground-shims/node-fs.js --alias:node:module=./scripts/playground-shims/node-module.js --alias:node:child_process=./scripts/playground-shims/node-fs.js --alias:node:url=./scripts/playground-shims/node-fs.js --footer:js=\"if(typeof window!=='undefined')window.Graft=GraftCompiler;\"",
62
73
  "prepublishOnly": "npm run build && npm test"
63
74
  },
64
75
  "engines": {