engineering-loop 1.0.1 → 1.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
@@ -2,13 +2,14 @@
2
2
 
3
3
  CLI for the [Engineering Loop Standard](../../README.md): scaffolds
4
4
  `engineering-loop.json`, persistent `docs/memory/`, and generated adapters
5
- for Claude Code, Cursor, Aider, and Codex/Gemini.
5
+ for Claude Code, Cursor, Aider, Codex/Gemini, and Windsurf.
6
6
 
7
7
  ## Usage
8
8
 
9
9
  ```bash
10
10
  npx engineering-loop init
11
11
  npx engineering-loop init --adapters claude,cursor --name my-app
12
+ npx engineering-loop sync
12
13
  npx engineering-loop doctor
13
14
  ```
14
15
 
@@ -20,9 +21,32 @@ npx engineering-loop doctor
20
21
  |---|---|---|
21
22
  | `-d, --dir <path>` | Target directory | current directory |
22
23
  | `-n, --name <name>` | Project name written into `engineering-loop.json` | directory name |
23
- | `-a, --adapters <list>` | Comma-separated adapter ids (`claude,cursor,aider,codex,gemini`) | `claude,cursor,aider,codex` |
24
+ | `-a, --adapters <list>` | Comma-separated adapter ids (`claude,cursor,aider,codex,gemini,windsurf`) | `claude,cursor,aider,codex,windsurf` |
24
25
  | `-f, --force` | Overwrite existing files | `false` |
25
26
 
27
+ ### `sync`
28
+
29
+ Re-renders adapter files from the current `engineering-loop.json` without
30
+ clobbering hand-edited content. Each generated file wraps its content in a
31
+ `<!-- engineering-loop:managed:start/end -->` block; `sync` replaces only
32
+ what's inside that block, leaving anything outside it (notes you appended,
33
+ for instance) exactly as you left it. A file with no managed block at all —
34
+ hand-authored, or produced by a pre-1.1.0 version of this CLI — is skipped
35
+ entirely rather than risk overwriting content that isn't actually managed.
36
+
37
+ | Flag | Description | Default |
38
+ |---|---|---|
39
+ | `-d, --dir <path>` | Project directory | current directory |
40
+ | `-a, --adapters <list>` | Comma-separated adapters to sync | the config's own `adapters` list |
41
+
42
+ ```bash
43
+ npx engineering-loop sync
44
+ ✔ Created AGENTS.md
45
+ ✔ Updated CLAUDE.md
46
+ = Unchanged .cursorrules
47
+ – Skipped CONVENTIONS.md (no managed block found ...)
48
+ ```
49
+
26
50
  ### `doctor`
27
51
 
28
52
  | Flag | Description | Default |
@@ -38,8 +62,9 @@ is missing.
38
62
  ```bash
39
63
  npm install
40
64
  npm run build # compiles src/ -> dist/, syncs the schema first
41
- npm test # vitest
65
+ npm test # vitest (needs Node >= 20; see ADR-006)
42
66
  npm run lint # tsc --noEmit
43
67
  ```
44
68
 
45
- See [../../docs/ADAPTERS.md](../../docs/ADAPTERS.md) to add a new adapter.
69
+ See [../../docs/ADAPTERS.md](../../docs/ADAPTERS.md) to add a new adapter
70
+ including the managed-block requirement `sync` depends on.
@@ -1,14 +1,15 @@
1
- import { LOOP_PHASES, MANIFESTO_PRINCIPLES, renderCommandsBlock, renderLanguagePolicyLine, renderMemorySection, } from "./shared.js";
1
+ import { LOOP_PHASES, MANIFESTO_PRINCIPLES, renderCommandsBlock, renderLanguagePolicyLine, renderMemorySection, wrapManaged, } from "./shared.js";
2
2
  function render(config) {
3
3
  const name = config.project.name;
4
4
  const manifesto = MANIFESTO_PRINCIPLES.map((p) => `* ${p}`).join("\n");
5
5
  const phases = LOOP_PHASES.map((p, i) => `${i + 1}. ${p}`).join("\n");
6
6
  const commands = renderCommandsBlock(config);
7
- return `# Conventions — ${name}
7
+ return wrapManaged(`# Conventions — ${name}
8
8
 
9
9
  Pass this file to Aider with \`--read CONVENTIONS.md\` (or add it to
10
10
  \`.aider.conf.yml\`). Generated by the ELS Aider adapter from
11
- \`engineering-loop.json\`.
11
+ \`engineering-loop.json\`. Content outside the markers below survives
12
+ \`engineering-loop sync\`.
12
13
 
13
14
  ## Engineering principles
14
15
 
@@ -25,7 +26,7 @@ ${phases}
25
26
  ## Project memory
26
27
 
27
28
  ${renderMemorySection(config)}
28
- ${commands.length > 0 ? `\n## Verification commands\n\n${commands.join("\n")}\n` : ""}`;
29
+ ${commands.length > 0 ? `\n## Verification commands\n\n${commands.join("\n")}\n` : ""}`);
29
30
  }
30
31
  export const aiderAdapter = {
31
32
  id: "aider",
@@ -1 +1 @@
1
- {"version":3,"file":"aider.js","sourceRoot":"","sources":["../../src/adapters/aider.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAErB,SAAS,MAAM,CAAC,MAA6B;IAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;IACjC,MAAM,SAAS,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAE7C,OAAO,mBAAmB,IAAI;;;;;;;;EAQ9B,SAAS;;;;EAIT,wBAAwB,CAAC,MAAM,CAAC;;;;EAIhC,MAAM;;;;EAIN,mBAAmB,CAAC,MAAM,CAAC;EAC3B,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,iCAAiC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACxF,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAY;IACnC,EAAE,EAAE,OAAO;IACX,KAAK,EAAE,OAAO;IACd,UAAU,EAAE,gBAAgB;IAC5B,MAAM;CACP,CAAC"}
1
+ {"version":3,"file":"aider.js","sourceRoot":"","sources":["../../src/adapters/aider.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACxB,mBAAmB,EACnB,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,SAAS,MAAM,CAAC,MAA6B;IAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;IACjC,MAAM,SAAS,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAE7C,OAAO,WAAW,CAAC,mBAAmB,IAAI;;;;;;;;;EAS1C,SAAS;;;;EAIT,wBAAwB,CAAC,MAAM,CAAC;;;;EAIhC,MAAM;;;;EAIN,mBAAmB,CAAC,MAAM,CAAC;EAC3B,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,iCAAiC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACzF,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAY;IACnC,EAAE,EAAE,OAAO;IACX,KAAK,EAAE,OAAO;IACd,UAAU,EAAE,gBAAgB;IAC5B,MAAM;CACP,CAAC"}
@@ -1,15 +1,16 @@
1
- import { LOOP_PHASES, MANIFESTO_PRINCIPLES, renderCommandsBlock, renderLanguagePolicyLine, renderMemorySection, } from "./shared.js";
1
+ import { LOOP_PHASES, MANIFESTO_PRINCIPLES, renderCommandsBlock, renderLanguagePolicyLine, renderMemorySection, wrapManaged, } from "./shared.js";
2
2
  function render(config) {
3
3
  const name = config.project.name;
4
4
  const manifesto = MANIFESTO_PRINCIPLES.map((p, i) => `${i + 1}. **${p}**`).join("\n");
5
5
  const phases = LOOP_PHASES.map((p, i) => `${i + 1}. ${p}`).join("\n");
6
6
  const commands = renderCommandsBlock(config);
7
- return `# CLAUDE.md - ${name}
7
+ return wrapManaged(`# CLAUDE.md - ${name}
8
8
 
9
9
  Generated by the Engineering Loop Standard (ELS) Claude Code adapter. This
10
10
  file is the binding contract for Claude Code working in this repository. See
11
11
  \`engineering-loop.json\` for the machine-readable source of truth this file
12
- is generated from.
12
+ is generated from. Content outside the markers below survives
13
+ \`engineering-loop sync\`.
13
14
 
14
15
  ## Agentic Engineering Manifesto
15
16
 
@@ -30,8 +31,7 @@ ${phases}
30
31
 
31
32
  ${renderMemorySection(config)}
32
33
 
33
- ${commands.length > 0 ? `## Commands\n\n${commands.join("\n")}\n` : ""}
34
- `;
34
+ ${commands.length > 0 ? `## Commands\n\n${commands.join("\n")}\n` : ""}`);
35
35
  }
36
36
  export const claudeAdapter = {
37
37
  id: "claude",
@@ -1 +1 @@
1
- {"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/adapters/claude.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAErB,SAAS,MAAM,CAAC,MAA6B;IAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;IACjC,MAAM,SAAS,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtF,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAE7C,OAAO,iBAAiB,IAAI;;;;;;;;;EAS5B,SAAS;;;;EAIT,wBAAwB,CAAC,MAAM,CAAC;;;;;;;EAOhC,MAAM;;;;EAIN,mBAAmB,CAAC,MAAM,CAAC;;EAE3B,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,kBAAkB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;CACrE,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAY;IACpC,EAAE,EAAE,QAAQ;IACZ,KAAK,EAAE,aAAa;IACpB,UAAU,EAAE,WAAW;IACvB,MAAM;CACP,CAAC"}
1
+ {"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/adapters/claude.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACxB,mBAAmB,EACnB,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,SAAS,MAAM,CAAC,MAA6B;IAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;IACjC,MAAM,SAAS,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtF,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAE7C,OAAO,WAAW,CAAC,iBAAiB,IAAI;;;;;;;;;;EAUxC,SAAS;;;;EAIT,wBAAwB,CAAC,MAAM,CAAC;;;;;;;EAOhC,MAAM;;;;EAIN,mBAAmB,CAAC,MAAM,CAAC;;EAE3B,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,kBAAkB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAY;IACpC,EAAE,EAAE,QAAQ;IACZ,KAAK,EAAE,aAAa;IACpB,UAAU,EAAE,WAAW;IACvB,MAAM;CACP,CAAC"}
@@ -1,13 +1,14 @@
1
- import { LOOP_PHASES, MANIFESTO_PRINCIPLES, renderCommandsBlock, renderLanguagePolicyLine, renderMemorySection, } from "./shared.js";
1
+ import { LOOP_PHASES, MANIFESTO_PRINCIPLES, renderCommandsBlock, renderLanguagePolicyLine, renderMemorySection, wrapManaged, } from "./shared.js";
2
2
  function render(config) {
3
3
  const name = config.project.name;
4
4
  const manifesto = MANIFESTO_PRINCIPLES.map((p, i) => `${i + 1}. ${p}`).join("\n");
5
5
  const phases = LOOP_PHASES.map((p, i) => `${i + 1}. ${p}`).join("\n");
6
6
  const commands = renderCommandsBlock(config);
7
- return `# AGENTS.md — ${name}
7
+ return wrapManaged(`# AGENTS.md — ${name}
8
8
 
9
9
  Read by Codex, Gemini, and any other agent that honors the AGENTS.md
10
10
  convention. Generated by the ELS adapter from \`engineering-loop.json\`.
11
+ Content outside the markers below survives \`engineering-loop sync\`.
11
12
 
12
13
  ## Manifesto
13
14
 
@@ -26,7 +27,7 @@ ${phases}
26
27
  ## Memory
27
28
 
28
29
  ${renderMemorySection(config)}
29
- ${commands.length > 0 ? `\n## Commands\n\n${commands.join("\n")}\n` : ""}`;
30
+ ${commands.length > 0 ? `\n## Commands\n\n${commands.join("\n")}\n` : ""}`);
30
31
  }
31
32
  export const codexAdapter = {
32
33
  id: "codex",
@@ -1 +1 @@
1
- {"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/adapters/codex.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAErB,SAAS,MAAM,CAAC,MAA6B;IAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;IACjC,MAAM,SAAS,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClF,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAE7C,OAAO,iBAAiB,IAAI;;;;;;;EAO5B,SAAS;;;;EAIT,wBAAwB,CAAC,MAAM,CAAC;;;;;;EAMhC,MAAM;;;;EAIN,mBAAmB,CAAC,MAAM,CAAC;EAC3B,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,oBAAoB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAC3E,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAY;IACnC,EAAE,EAAE,OAAO;IACX,KAAK,EAAE,gBAAgB;IACvB,UAAU,EAAE,WAAW;IACvB,MAAM;CACP,CAAC"}
1
+ {"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/adapters/codex.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACxB,mBAAmB,EACnB,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,SAAS,MAAM,CAAC,MAA6B;IAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;IACjC,MAAM,SAAS,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClF,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAE7C,OAAO,WAAW,CAAC,iBAAiB,IAAI;;;;;;;;EAQxC,SAAS;;;;EAIT,wBAAwB,CAAC,MAAM,CAAC;;;;;;EAMhC,MAAM;;;;EAIN,mBAAmB,CAAC,MAAM,CAAC;EAC3B,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,oBAAoB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAY;IACnC,EAAE,EAAE,OAAO;IACX,KAAK,EAAE,gBAAgB;IACvB,UAAU,EAAE,WAAW;IACvB,MAAM;CACP,CAAC"}
@@ -1,12 +1,13 @@
1
- import { LOOP_PHASES, MANIFESTO_PRINCIPLES, renderCommandsBlock, renderLanguagePolicyLine, renderMemorySection, } from "./shared.js";
1
+ import { LOOP_PHASES, MANIFESTO_PRINCIPLES, renderCommandsBlock, renderLanguagePolicyLine, renderMemorySection, wrapManaged, } from "./shared.js";
2
2
  function render(config) {
3
3
  const name = config.project.name;
4
4
  const manifesto = MANIFESTO_PRINCIPLES.map((p) => `- ${p}`).join("\n");
5
5
  const phases = LOOP_PHASES.map((p, i) => `${i + 1}. ${p}`).join("\n");
6
6
  const commands = renderCommandsBlock(config);
7
- return `# ${name} — Engineering Loop Standard rules
7
+ return wrapManaged(`# ${name} — Engineering Loop Standard rules
8
8
 
9
- Generated by the ELS Cursor adapter from \`engineering-loop.json\`.
9
+ Generated by the ELS Cursor adapter from \`engineering-loop.json\`. Content
10
+ outside the markers below survives \`engineering-loop sync\`.
10
11
 
11
12
  ## Principles
12
13
 
@@ -25,7 +26,7 @@ ${phases}
25
26
  ## Memory
26
27
 
27
28
  ${renderMemorySection(config)}
28
- ${commands.length > 0 ? `\n## Commands\n\n${commands.join("\n")}\n` : ""}`;
29
+ ${commands.length > 0 ? `\n## Commands\n\n${commands.join("\n")}\n` : ""}`);
29
30
  }
30
31
  export const cursorAdapter = {
31
32
  id: "cursor",
@@ -1 +1 @@
1
- {"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/adapters/cursor.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAErB,SAAS,MAAM,CAAC,MAA6B;IAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;IACjC,MAAM,SAAS,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAE7C,OAAO,KAAK,IAAI;;;;;;EAMhB,SAAS;;;;EAIT,wBAAwB,CAAC,MAAM,CAAC;;;;;;EAMhC,MAAM;;;;EAIN,mBAAmB,CAAC,MAAM,CAAC;EAC3B,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,oBAAoB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAC3E,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAY;IACpC,EAAE,EAAE,QAAQ;IACZ,KAAK,EAAE,QAAQ;IACf,UAAU,EAAE,cAAc;IAC1B,MAAM;CACP,CAAC"}
1
+ {"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/adapters/cursor.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACxB,mBAAmB,EACnB,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,SAAS,MAAM,CAAC,MAA6B;IAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;IACjC,MAAM,SAAS,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAE7C,OAAO,WAAW,CAAC,KAAK,IAAI;;;;;;;EAO5B,SAAS;;;;EAIT,wBAAwB,CAAC,MAAM,CAAC;;;;;;EAMhC,MAAM;;;;EAIN,mBAAmB,CAAC,MAAM,CAAC;EAC3B,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,oBAAoB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAY;IACpC,EAAE,EAAE,QAAQ;IACZ,KAAK,EAAE,QAAQ;IACf,UAAU,EAAE,cAAc;IAC1B,MAAM;CACP,CAAC"}
@@ -2,6 +2,7 @@ import { aiderAdapter } from "./aider.js";
2
2
  import { claudeAdapter } from "./claude.js";
3
3
  import { codexAdapter } from "./codex.js";
4
4
  import { cursorAdapter } from "./cursor.js";
5
+ import { windsurfAdapter } from "./windsurf.js";
5
6
  export const ADAPTERS = {
6
7
  claude: claudeAdapter,
7
8
  cursor: cursorAdapter,
@@ -9,6 +10,7 @@ export const ADAPTERS = {
9
10
  codex: codexAdapter,
10
11
  // Gemini currently shares the AGENTS.md convention with Codex.
11
12
  gemini: codexAdapter,
13
+ windsurf: windsurfAdapter,
12
14
  };
13
15
  export function resolveAdapters(ids) {
14
16
  const seen = new Set();
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,MAAM,CAAC,MAAM,QAAQ,GAA+B;IAClD,MAAM,EAAE,aAAa;IACrB,MAAM,EAAE,aAAa;IACrB,KAAK,EAAE,YAAY;IACnB,KAAK,EAAE,YAAY;IACnB,+DAA+D;IAC/D,MAAM,EAAE,YAAY;CACrB,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,GAAgB;IAC9C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACrB,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC;QAC/C,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC;YAAE,SAAS;QAC3C,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,CAAC,MAAM,QAAQ,GAA+B;IAClD,MAAM,EAAE,aAAa;IACrB,MAAM,EAAE,aAAa;IACrB,KAAK,EAAE,YAAY;IACnB,KAAK,EAAE,YAAY;IACnB,+DAA+D;IAC/D,MAAM,EAAE,YAAY;IACpB,QAAQ,EAAE,eAAe;CAC1B,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,GAAgB;IAC9C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACrB,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC;QAC/C,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC;YAAE,SAAS;QAC3C,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -1,4 +1,7 @@
1
1
  import type { EngineeringLoopConfig } from "../types.js";
2
+ export declare const MANAGED_START = "<!-- engineering-loop:managed:start -->";
3
+ export declare const MANAGED_END = "<!-- engineering-loop:managed:end -->";
4
+ export declare function wrapManaged(body: string): string;
2
5
  export declare const MANIFESTO_PRINCIPLES: string[];
3
6
  export declare const LOOP_PHASES: string[];
4
7
  export declare function renderLanguagePolicyLine(config: EngineeringLoopConfig): string;
@@ -1,3 +1,16 @@
1
+ // `engineering-loop sync` re-renders only the block between these markers,
2
+ // leaving anything a human added above/below it untouched. A file with no
3
+ // markers at all (hand-authored, or generated by a pre-1.1.0 CLI) is never
4
+ // touched by sync - it's indistinguishable from a fully hand-written file.
5
+ export const MANAGED_START = "<!-- engineering-loop:managed:start -->";
6
+ export const MANAGED_END = "<!-- engineering-loop:managed:end -->";
7
+ // No trailing newline after MANAGED_END - callers that write a brand new
8
+ // file add their own EOF newline; `sync`'s splice reuses whatever trailing
9
+ // whitespace the existing file already had after the marker instead, so
10
+ // the two must not both contribute one or they compound on every sync.
11
+ export function wrapManaged(body) {
12
+ return `${MANAGED_START}\n${body.trim()}\n${MANAGED_END}`;
13
+ }
1
14
  export const MANIFESTO_PRINCIPLES = [
2
15
  "Understand before acting. Never write code without full contextual knowledge.",
3
16
  "Research before building. Search the repository for existing patterns before creating new ones.",
@@ -1 +1 @@
1
- {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/adapters/shared.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,+EAA+E;IAC/E,iGAAiG;IACjG,iGAAiG;IACjG,8GAA8G;IAC9G,yEAAyE;IACzE,yGAAyG;CAC1G,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,mBAAmB;IACnB,qBAAqB;IACrB,qBAAqB;IACrB,0BAA0B;IAC1B,gBAAgB;IAChB,kCAAkC;IAClC,2BAA2B;IAC3B,aAAa;IACb,+BAA+B;IAC/B,cAAc;CACf,CAAC;AAEF,MAAM,UAAU,wBAAwB,CAAC,MAA6B;IACpE,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,CAAC;IACtC,IAAI,CAAC,MAAM;QAAE,OAAO,mEAAmE,CAAC;IACxF,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;SACjC,MAAM,CAAC,CAAC,KAAK,EAA6B,EAAE,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC;SAC1E,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC;IAC5C,OAAO,mCAAmC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAA6B;IAC/D,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;IACvC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpD,IAAI,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,OAAO,KAAK,IAAI,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAA6B;IAC/D,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;IACpC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtD,OAAO,wCAAwC,GAAG,QAAQ,KAAK,kIAAkI,CAAC;AACpM,CAAC"}
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/adapters/shared.ts"],"names":[],"mappings":"AAEA,2EAA2E;AAC3E,0EAA0E;AAC1E,2EAA2E;AAC3E,2EAA2E;AAC3E,MAAM,CAAC,MAAM,aAAa,GAAG,yCAAyC,CAAC;AACvE,MAAM,CAAC,MAAM,WAAW,GAAG,uCAAuC,CAAC;AAEnE,yEAAyE;AACzE,2EAA2E;AAC3E,wEAAwE;AACxE,uEAAuE;AACvE,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,GAAG,aAAa,KAAK,IAAI,CAAC,IAAI,EAAE,KAAK,WAAW,EAAE,CAAC;AAC5D,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,+EAA+E;IAC/E,iGAAiG;IACjG,iGAAiG;IACjG,8GAA8G;IAC9G,yEAAyE;IACzE,yGAAyG;CAC1G,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,mBAAmB;IACnB,qBAAqB;IACrB,qBAAqB;IACrB,0BAA0B;IAC1B,gBAAgB;IAChB,kCAAkC;IAClC,2BAA2B;IAC3B,aAAa;IACb,+BAA+B;IAC/B,cAAc;CACf,CAAC;AAEF,MAAM,UAAU,wBAAwB,CAAC,MAA6B;IACpE,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,CAAC;IACtC,IAAI,CAAC,MAAM;QAAE,OAAO,mEAAmE,CAAC;IACxF,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;SACjC,MAAM,CAAC,CAAC,KAAK,EAA6B,EAAE,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC;SAC1E,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC;IAC5C,OAAO,mCAAmC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAA6B;IAC/D,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;IACvC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpD,IAAI,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,OAAO,KAAK,IAAI,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAA6B;IAC/D,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;IACpC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtD,OAAO,wCAAwC,GAAG,QAAQ,KAAK,kIAAkI,CAAC;AACpM,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Adapter } from "./types.js";
2
+ export declare const windsurfAdapter: Adapter;
@@ -0,0 +1,37 @@
1
+ import { LOOP_PHASES, MANIFESTO_PRINCIPLES, renderCommandsBlock, renderLanguagePolicyLine, renderMemorySection, wrapManaged, } from "./shared.js";
2
+ function render(config) {
3
+ const name = config.project.name;
4
+ const manifesto = MANIFESTO_PRINCIPLES.map((p) => `- ${p}`).join("\n");
5
+ const phases = LOOP_PHASES.map((p, i) => `${i + 1}. ${p}`).join("\n");
6
+ const commands = renderCommandsBlock(config);
7
+ return wrapManaged(`# ${name} — Engineering Loop Standard rules
8
+
9
+ Generated by the ELS Windsurf adapter from \`engineering-loop.json\`.
10
+ Content outside the markers below survives \`engineering-loop sync\`.
11
+
12
+ ## Principles
13
+
14
+ ${manifesto}
15
+
16
+ ## Language policy
17
+
18
+ ${renderLanguagePolicyLine(config)}
19
+
20
+ ## Loop
21
+
22
+ Work through this sequence for any non-trivial change:
23
+
24
+ ${phases}
25
+
26
+ ## Memory
27
+
28
+ ${renderMemorySection(config)}
29
+ ${commands.length > 0 ? `\n## Commands\n\n${commands.join("\n")}\n` : ""}`);
30
+ }
31
+ export const windsurfAdapter = {
32
+ id: "windsurf",
33
+ label: "Windsurf",
34
+ outputPath: ".windsurfrules",
35
+ render,
36
+ };
37
+ //# sourceMappingURL=windsurf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windsurf.js","sourceRoot":"","sources":["../../src/adapters/windsurf.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACxB,mBAAmB,EACnB,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,SAAS,MAAM,CAAC,MAA6B;IAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;IACjC,MAAM,SAAS,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAE7C,OAAO,WAAW,CAAC,KAAK,IAAI;;;;;;;EAO5B,SAAS;;;;EAIT,wBAAwB,CAAC,MAAM,CAAC;;;;;;EAMhC,MAAM;;;;EAIN,mBAAmB,CAAC,MAAM,CAAC;EAC3B,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,oBAAoB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAY;IACtC,EAAE,EAAE,UAAU;IACd,KAAK,EAAE,UAAU;IACjB,UAAU,EAAE,gBAAgB;IAC5B,MAAM;CACP,CAAC"}
@@ -1,52 +1,71 @@
1
1
  import { existsSync } from "node:fs";
2
- import { readFile } from "node:fs/promises";
3
- import { join } from "node:path";
4
- import { validateConfig } from "../schema.js";
2
+ import { isAbsolute, join, relative, resolve } from "node:path";
3
+ import { loadConfig } from "../loadConfig.js";
4
+ // engineering-loop.json is often a file the current user didn't author
5
+ // themselves (e.g. `doctor` run against a cloned project). memory.directory
6
+ // and memory.required_files come straight from it, so a crafted "../../"
7
+ // entry must not let a filesystem existence check escape the project dir.
8
+ function isInside(parentDir, candidate) {
9
+ const rel = relative(resolve(parentDir), resolve(candidate));
10
+ return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
11
+ }
5
12
  export async function runDoctor(dir) {
6
13
  const checks = [];
7
- const configPath = join(dir, "engineering-loop.json");
8
- if (!existsSync(configPath)) {
14
+ const loaded = await loadConfig(dir);
15
+ if (!loaded.ok && loaded.reason === "missing") {
9
16
  checks.push({
10
17
  name: "engineering-loop.json exists",
11
18
  passed: false,
12
- detail: `not found at ${configPath}`,
19
+ detail: `not found at ${loaded.configPath}`,
13
20
  });
14
21
  return { ok: false, checks };
15
22
  }
16
23
  checks.push({ name: "engineering-loop.json exists", passed: true });
17
- let raw;
18
- let parsed;
19
- try {
20
- raw = await readFile(configPath, "utf-8");
21
- parsed = JSON.parse(raw);
22
- checks.push({ name: "engineering-loop.json is valid JSON", passed: true });
23
- }
24
- catch (error) {
24
+ if (!loaded.ok && loaded.reason === "invalid-json") {
25
25
  checks.push({
26
26
  name: "engineering-loop.json is valid JSON",
27
27
  passed: false,
28
- detail: error instanceof Error ? error.message : String(error),
28
+ detail: loaded.detail,
29
+ });
30
+ return { ok: false, checks };
31
+ }
32
+ checks.push({ name: "engineering-loop.json is valid JSON", passed: true });
33
+ if (!loaded.ok) {
34
+ checks.push({
35
+ name: "engineering-loop.json conforms to schema",
36
+ passed: false,
37
+ detail: loaded.detail,
29
38
  });
30
39
  return { ok: false, checks };
31
40
  }
32
- const { valid, errors } = validateConfig(parsed);
33
- checks.push({
34
- name: "engineering-loop.json conforms to schema",
35
- passed: valid,
36
- detail: valid ? undefined : errors.join("; "),
37
- });
38
- if (valid) {
39
- const config = parsed;
40
- const memoryDir = join(dir, config.memory.directory);
41
- for (const file of config.memory.required_files) {
42
- const filePath = join(memoryDir, file);
43
- const exists = existsSync(filePath);
41
+ checks.push({ name: "engineering-loop.json conforms to schema", passed: true });
42
+ const config = loaded.config;
43
+ const memoryDir = join(dir, config.memory.directory);
44
+ if (!isInside(dir, memoryDir)) {
45
+ checks.push({
46
+ name: "memory.directory stays inside the project",
47
+ passed: false,
48
+ detail: `"${config.memory.directory}" resolves outside ${dir}`,
49
+ });
50
+ return { ok: false, checks };
51
+ }
52
+ for (const file of config.memory.required_files) {
53
+ const filePath = join(memoryDir, file);
54
+ const label = `memory file present: ${config.memory.directory}/${file}`;
55
+ if (!isInside(memoryDir, filePath)) {
44
56
  checks.push({
45
- name: `memory file present: ${config.memory.directory}/${file}`,
46
- passed: exists,
47
- detail: exists ? undefined : `missing at ${filePath}`,
57
+ name: label,
58
+ passed: false,
59
+ detail: `"${file}" resolves outside ${memoryDir}`,
48
60
  });
61
+ continue;
49
62
  }
63
+ const exists = existsSync(filePath);
64
+ checks.push({
65
+ name: label,
66
+ passed: exists,
67
+ detail: exists ? undefined : `missing at ${filePath}`,
68
+ });
50
69
  }
51
70
  return { ok: checks.every((c) => c.passed), checks };
52
71
  }
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAc9C,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW;IACzC,MAAM,MAAM,GAAkB,EAAE,CAAC;IACjC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAC;IAEtD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,8BAA8B;YACpC,MAAM,EAAE,KAAK;YACb,MAAM,EAAE,gBAAgB,UAAU,EAAE;SACrC,CAAC,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC/B,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,8BAA8B,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAEpE,IAAI,GAAW,CAAC;IAChB,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC1C,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,qCAAqC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,qCAAqC;YAC3C,MAAM,EAAE,KAAK;YACb,MAAM,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SAC/D,CAAC,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC/B,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACjD,MAAM,CAAC,IAAI,CAAC;QACV,IAAI,EAAE,0CAA0C;QAChD,MAAM,EAAE,KAAK;QACb,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;KAC9C,CAAC,CAAC;IAEH,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,MAAM,GAAG,MAA+B,CAAC;QAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACrD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;YAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YACvC,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;YACpC,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,wBAAwB,MAAM,CAAC,MAAM,CAAC,SAAS,IAAI,IAAI,EAAE;gBAC/D,MAAM,EAAE,MAAM;gBACd,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,QAAQ,EAAE;aACtD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;AACvD,CAAC"}
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -39,7 +39,7 @@ export async function runInit(options) {
39
39
  const adapters = resolveAdapters(adapterIds);
40
40
  for (const adapter of adapters) {
41
41
  const outputPath = join(targetDir, adapter.outputPath);
42
- await writeIfAllowed(outputPath, adapter.render(config), Boolean(options.force), result);
42
+ await writeIfAllowed(outputPath, `${adapter.render(config)}\n`, Boolean(options.force), result);
43
43
  }
44
44
  return result;
45
45
  }
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { AdapterId } from "../types.js";
2
+ export interface SyncOptions {
3
+ dir: string;
4
+ adapters?: AdapterId[];
5
+ }
6
+ export interface SyncSkip {
7
+ path: string;
8
+ reason: string;
9
+ }
10
+ export interface SyncResult {
11
+ created: string[];
12
+ updated: string[];
13
+ unchanged: string[];
14
+ skipped: SyncSkip[];
15
+ }
16
+ export declare function runSync(options: SyncOptions): Promise<SyncResult>;
@@ -0,0 +1,60 @@
1
+ import { existsSync } from "node:fs";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { resolveAdapters } from "../adapters/index.js";
5
+ import { MANAGED_END, MANAGED_START } from "../adapters/shared.js";
6
+ import { loadConfig } from "../loadConfig.js";
7
+ // Replaces only the block between MANAGED_START/MANAGED_END, preserving
8
+ // everything outside it byte-for-byte. Returns undefined if the existing
9
+ // file has no managed block at all - it's then indistinguishable from a
10
+ // fully hand-authored file, so sync must not touch it.
11
+ function spliceManaged(existing, freshManagedBlock) {
12
+ const startIdx = existing.indexOf(MANAGED_START);
13
+ const endIdx = existing.indexOf(MANAGED_END);
14
+ if (startIdx === -1 || endIdx === -1 || endIdx < startIdx) {
15
+ return undefined;
16
+ }
17
+ const before = existing.slice(0, startIdx);
18
+ const after = existing.slice(endIdx + MANAGED_END.length);
19
+ return `${before}${freshManagedBlock}${after}`;
20
+ }
21
+ export async function runSync(options) {
22
+ const result = { created: [], updated: [], unchanged: [], skipped: [] };
23
+ const loaded = await loadConfig(options.dir);
24
+ if (!loaded.ok) {
25
+ const message = loaded.reason === "missing"
26
+ ? `No engineering-loop.json found in ${options.dir}. Run \`engineering-loop init\` first.`
27
+ : `engineering-loop.json is invalid (${loaded.reason}): ${loaded.detail}`;
28
+ throw new Error(message);
29
+ }
30
+ const config = loaded.config;
31
+ const adapterIds = options.adapters && options.adapters.length > 0 ? options.adapters : (config.adapters ?? []);
32
+ const adapters = resolveAdapters(adapterIds);
33
+ await mkdir(options.dir, { recursive: true });
34
+ for (const adapter of adapters) {
35
+ const outputPath = join(options.dir, adapter.outputPath);
36
+ const fresh = adapter.render(config);
37
+ if (!existsSync(outputPath)) {
38
+ await writeFile(outputPath, `${fresh}\n`, "utf-8");
39
+ result.created.push(outputPath);
40
+ continue;
41
+ }
42
+ const existing = await readFile(outputPath, "utf-8");
43
+ const spliced = spliceManaged(existing, fresh);
44
+ if (spliced === undefined) {
45
+ result.skipped.push({
46
+ path: outputPath,
47
+ reason: "no managed block found (hand-authored, or generated by a pre-1.1.0 CLI) - edit manually or delete and re-run init",
48
+ });
49
+ continue;
50
+ }
51
+ if (spliced === existing) {
52
+ result.unchanged.push(outputPath);
53
+ continue;
54
+ }
55
+ await writeFile(outputPath, spliced, "utf-8");
56
+ result.updated.push(outputPath);
57
+ }
58
+ return result;
59
+ }
60
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"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"}
@@ -10,7 +10,7 @@ export const DEFAULT_MEMORY_FILES = [
10
10
  "DECISIONS.md",
11
11
  "KNOWLEDGE.md",
12
12
  ];
13
- export const DEFAULT_ADAPTERS = ["claude", "cursor", "aider", "codex"];
13
+ export const DEFAULT_ADAPTERS = ["claude", "cursor", "aider", "codex", "windsurf"];
14
14
  export function buildDefaultConfig(projectName) {
15
15
  return {
16
16
  $schema: SCHEMA_URL,
@@ -1 +1 @@
1
- {"version":3,"file":"defaultConfig.js","sourceRoot":"","sources":["../src/defaultConfig.ts"],"names":[],"mappings":"AAEA,sEAAsE;AACtE,yEAAyE;AACzE,sDAAsD;AACtD,MAAM,CAAC,MAAM,UAAU,GACrB,iHAAiH,CAAC;AAEpH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,YAAY;IACZ,iBAAiB;IACjB,YAAY;IACZ,UAAU;IACV,cAAc;IACd,cAAc;CACf,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAEpF,MAAM,UAAU,kBAAkB,CAAC,WAAmB;IACpD,OAAO;QACL,OAAO,EAAE,UAAU;QACnB,OAAO,EAAE,OAAO;QAChB,OAAO,EAAE;YACP,IAAI,EAAE,WAAW;SAClB;QACD,MAAM,EAAE;YACN,SAAS,EAAE,aAAa;YACxB,cAAc,EAAE,CAAC,GAAG,oBAAoB,CAAC;SAC1C;QACD,QAAQ,EAAE;YACR,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,CAAC;YAC9B,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,CAAC;SACvD;QACD,QAAQ,EAAE;YACR,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,cAAc;YACpB,KAAK,EAAE,eAAe;SACvB;QACD,eAAe,EAAE;YACf,IAAI,EAAE,IAAI;YACV,QAAQ,EAAE,IAAI;YACd,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,IAAI;SACd;QACD,MAAM,EAAE;YACN,cAAc,EAAE,IAAI;YACpB,qBAAqB,EAAE,CAAC;SACzB;QACD,QAAQ,EAAE,CAAC,GAAG,gBAAgB,CAAC;KAChC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"defaultConfig.js","sourceRoot":"","sources":["../src/defaultConfig.ts"],"names":[],"mappings":"AAEA,sEAAsE;AACtE,yEAAyE;AACzE,sDAAsD;AACtD,MAAM,CAAC,MAAM,UAAU,GACrB,iHAAiH,CAAC;AAEpH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,YAAY;IACZ,iBAAiB;IACjB,YAAY;IACZ,UAAU;IACV,cAAc;IACd,cAAc;CACf,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;AAEhG,MAAM,UAAU,kBAAkB,CAAC,WAAmB;IACpD,OAAO;QACL,OAAO,EAAE,UAAU;QACnB,OAAO,EAAE,OAAO;QAChB,OAAO,EAAE;YACP,IAAI,EAAE,WAAW;SAClB;QACD,MAAM,EAAE;YACN,SAAS,EAAE,aAAa;YACxB,cAAc,EAAE,CAAC,GAAG,oBAAoB,CAAC;SAC1C;QACD,QAAQ,EAAE;YACR,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,CAAC;YAC9B,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,CAAC;SACvD;QACD,QAAQ,EAAE;YACR,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,cAAc;YACpB,KAAK,EAAE,eAAe;SACvB;QACD,eAAe,EAAE;YACf,IAAI,EAAE,IAAI;YACV,QAAQ,EAAE,IAAI;YACd,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,IAAI;SACd;QACD,MAAM,EAAE;YACN,cAAc,EAAE,IAAI;YACpB,qBAAqB,EAAE,CAAC;SACzB;QACD,QAAQ,EAAE,CAAC,GAAG,gBAAgB,CAAC;KAChC,CAAC;AACJ,CAAC"}
package/dist/index.js CHANGED
@@ -4,9 +4,17 @@ import { join } from "node:path";
4
4
  import { Command } from "commander";
5
5
  import { runDoctor } from "./commands/doctor.js";
6
6
  import { runInit } from "./commands/init.js";
7
+ import { runSync } from "./commands/sync.js";
7
8
  import { PACKAGE_ROOT } from "./paths.js";
8
9
  const pkg = JSON.parse(readFileSync(join(PACKAGE_ROOT, "package.json"), "utf-8"));
9
- const VALID_ADAPTER_IDS = ["claude", "cursor", "aider", "codex", "gemini"];
10
+ const VALID_ADAPTER_IDS = [
11
+ "claude",
12
+ "cursor",
13
+ "aider",
14
+ "codex",
15
+ "gemini",
16
+ "windsurf",
17
+ ];
10
18
  function parseAdapters(value) {
11
19
  const ids = value.split(",").map((s) => s.trim());
12
20
  for (const id of ids) {
@@ -26,7 +34,7 @@ program
26
34
  .description("Create engineering-loop.json, docs/memory/, and generate agent adapters")
27
35
  .option("-d, --dir <path>", "target directory", process.cwd())
28
36
  .option("-n, --name <name>", "project name (defaults to the directory name)")
29
- .option("-a, --adapters <list>", "comma-separated adapters to generate (claude,cursor,aider,codex,gemini)")
37
+ .option("-a, --adapters <list>", "comma-separated adapters to generate (claude,cursor,aider,codex,gemini,windsurf)")
30
38
  .option("-f, --force", "overwrite existing files", false)
31
39
  .action(async (opts) => {
32
40
  try {
@@ -65,5 +73,33 @@ program
65
73
  process.exitCode = 1;
66
74
  }
67
75
  });
76
+ program
77
+ .command("sync")
78
+ .description("Re-render agent adapters from engineering-loop.json, preserving hand-edited content outside the managed block")
79
+ .option("-d, --dir <path>", "project directory", process.cwd())
80
+ .option("-a, --adapters <list>", "comma-separated adapters to sync (defaults to the config's own \"adapters\" list)")
81
+ .action(async (opts) => {
82
+ try {
83
+ const adapters = opts.adapters ? parseAdapters(opts.adapters) : undefined;
84
+ const result = await runSync({ dir: opts.dir, adapters });
85
+ for (const file of result.created) {
86
+ console.log(`✔ Created ${file}`);
87
+ }
88
+ for (const file of result.updated) {
89
+ console.log(`✔ Updated ${file}`);
90
+ }
91
+ for (const file of result.unchanged) {
92
+ console.log(`= Unchanged ${file}`);
93
+ }
94
+ for (const skip of result.skipped) {
95
+ console.log(`– Skipped ${skip.path} (${skip.reason})`);
96
+ }
97
+ console.log("\nEngineering Loop synced.");
98
+ }
99
+ catch (error) {
100
+ console.error(error instanceof Error ? error.message : String(error));
101
+ process.exitCode = 1;
102
+ }
103
+ });
68
104
  program.parseAsync(process.argv);
69
105
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { EngineeringLoopConfig } from "./types.js";
2
+ export type LoadConfigResult = {
3
+ ok: true;
4
+ config: EngineeringLoopConfig;
5
+ } | {
6
+ ok: false;
7
+ reason: "missing";
8
+ configPath: string;
9
+ } | {
10
+ ok: false;
11
+ reason: "invalid-json";
12
+ configPath: string;
13
+ detail: string;
14
+ } | {
15
+ ok: false;
16
+ reason: "invalid-schema";
17
+ configPath: string;
18
+ detail: string;
19
+ };
20
+ export declare function loadConfig(dir: string): Promise<LoadConfigResult>;
@@ -0,0 +1,29 @@
1
+ import { existsSync } from "node:fs";
2
+ import { readFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { validateConfig } from "./schema.js";
5
+ export async function loadConfig(dir) {
6
+ const configPath = join(dir, "engineering-loop.json");
7
+ if (!existsSync(configPath)) {
8
+ return { ok: false, reason: "missing", configPath };
9
+ }
10
+ let parsed;
11
+ try {
12
+ const raw = await readFile(configPath, "utf-8");
13
+ parsed = JSON.parse(raw);
14
+ }
15
+ catch (error) {
16
+ return {
17
+ ok: false,
18
+ reason: "invalid-json",
19
+ configPath,
20
+ detail: error instanceof Error ? error.message : String(error),
21
+ };
22
+ }
23
+ const { valid, errors } = validateConfig(parsed);
24
+ if (!valid) {
25
+ return { ok: false, reason: "invalid-schema", configPath, detail: errors.join("; ") };
26
+ }
27
+ return { ok: true, config: parsed };
28
+ }
29
+ //# sourceMappingURL=loadConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadConfig.js","sourceRoot":"","sources":["../src/loadConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAS7C,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW;IAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAC;IACtD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC;IACtD,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAChD,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,cAAc;YACtB,UAAU;YACV,MAAM,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SAC/D,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACjD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IACxF,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAA+B,EAAE,CAAC;AAC/D,CAAC"}
package/dist/types.d.ts CHANGED
@@ -34,4 +34,4 @@ export interface EngineeringLoopConfig {
34
34
  };
35
35
  adapters?: AdapterId[];
36
36
  }
37
- export type AdapterId = "claude" | "cursor" | "aider" | "codex" | "gemini";
37
+ export type AdapterId = "claude" | "cursor" | "aider" | "codex" | "gemini" | "windsurf";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "engineering-loop",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "CLI for the Engineering Loop Standard: scaffold engineering-loop.json, persistent project memory, and multi-tool AI agent adapters.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -33,7 +33,7 @@
33
33
  "@types/node": "^20.14.0",
34
34
  "tsx": "^4.16.0",
35
35
  "typescript": "^5.5.0",
36
- "vitest": "^1.6.0"
36
+ "vitest": "^4.1.10"
37
37
  },
38
38
  "keywords": [
39
39
  "engineering-loop",
@@ -122,9 +122,9 @@
122
122
  "description": "Adapters to generate when running `engineering-loop init` or `engineering-loop sync`.",
123
123
  "items": {
124
124
  "type": "string",
125
- "enum": ["claude", "cursor", "aider", "codex", "gemini"]
125
+ "enum": ["claude", "cursor", "aider", "codex", "gemini", "windsurf"]
126
126
  },
127
- "default": ["claude", "cursor", "aider", "codex"]
127
+ "default": ["claude", "cursor", "aider", "codex", "windsurf"]
128
128
  }
129
129
  }
130
130
  }