@oleksandr.rudnychenko/sync_loop 0.2.4 → 0.3.1
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 +25 -4
- package/bin/cli.js +3 -128
- package/bin/cli.ts +171 -0
- package/dist/bin/cli.d.ts +15 -0
- package/dist/bin/cli.js +137 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/src/init.d.ts +24 -0
- package/dist/src/init.js +404 -0
- package/dist/src/init.js.map +1 -0
- package/dist/src/server.d.ts +13 -0
- package/dist/src/server.js +265 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/template/.agent-loop/README.md +75 -0
- package/dist/src/template/.agent-loop/feedback.md +395 -0
- package/dist/src/template/.agent-loop/glossary.md +113 -0
- package/dist/src/template/.agent-loop/patterns/api-standards.md +132 -0
- package/dist/src/template/.agent-loop/patterns/code-patterns.md +300 -0
- package/dist/src/template/.agent-loop/patterns/refactoring-workflow.md +114 -0
- package/dist/src/template/.agent-loop/patterns/testing-guide.md +258 -0
- package/dist/src/template/.agent-loop/patterns.md +256 -0
- package/dist/src/template/.agent-loop/reasoning-kernel.md +521 -0
- package/dist/src/template/.agent-loop/validate-env.md +332 -0
- package/dist/src/template/.agent-loop/validate-n.md +321 -0
- package/dist/src/template/AGENTS.md +157 -0
- package/dist/src/template/README.md +144 -0
- package/dist/src/template/bootstrap-prompt.md +37 -0
- package/dist/src/template/protocol-summary.md +54 -0
- package/dist/src/template/wiring/api-standards.md +15 -0
- package/dist/src/template/wiring/code-patterns.md +15 -0
- package/dist/src/template/wiring/feedback.md +18 -0
- package/dist/src/template/wiring/glossary.md +11 -0
- package/dist/src/template/wiring/patterns.md +18 -0
- package/dist/src/template/wiring/reasoning-kernel.md +18 -0
- package/dist/src/template/wiring/refactoring-workflow.md +15 -0
- package/dist/src/template/wiring/testing-guide.md +15 -0
- package/dist/src/template/wiring/validate-env.md +17 -0
- package/dist/src/template/wiring/validate-n.md +17 -0
- package/package.json +48 -34
- package/src/template/wiring/api-standards.md +15 -0
- package/src/template/wiring/code-patterns.md +15 -0
- package/src/template/wiring/feedback.md +18 -0
- package/src/template/wiring/glossary.md +11 -0
- package/src/template/wiring/patterns.md +18 -0
- package/src/template/wiring/reasoning-kernel.md +18 -0
- package/src/template/wiring/refactoring-workflow.md +15 -0
- package/src/template/wiring/testing-guide.md +15 -0
- package/src/template/wiring/validate-env.md +17 -0
- package/src/template/wiring/validate-n.md +17 -0
- package/src/init.js +0 -569
- package/src/server.js +0 -289
package/README.md
CHANGED
|
@@ -231,14 +231,35 @@ Use the sync_loop init tool — choose: copilot, cursor, claude, or all
|
|
|
231
231
|
|
|
232
232
|
| Target | Files generated |
|
|
233
233
|
|--------|----------------|
|
|
234
|
-
| `copilot` | `.github/copilot-instructions.md` + `.github/instructions/*.instructions.md` |
|
|
235
|
-
| `cursor` | `.cursor/rules/*.md` with frontmatter |
|
|
236
|
-
| `claude` | `CLAUDE.md` + `.claude/rules/*.md` |
|
|
237
|
-
| `all` | All of the above + `AGENTS.md`
|
|
234
|
+
| `copilot` | `.agent-loop/` + `.github/copilot-instructions.md` + `.github/instructions/*.instructions.md` |
|
|
235
|
+
| `cursor` | `.agent-loop/` + `.cursor/rules/*.md` with frontmatter |
|
|
236
|
+
| `claude` | `.agent-loop/` + `CLAUDE.md` + `.claude/rules/*.md` |
|
|
237
|
+
| `all` | All of the above + `AGENTS.md` |
|
|
238
238
|
|
|
239
239
|
After scaffolding, use the `bootstrap` prompt so the agent scans your codebase and populates
|
|
240
240
|
the generated files with real validation commands, architecture layers, and module boundaries.
|
|
241
241
|
|
|
242
|
+
Platform instruction files are lightweight wrappers that delegate to `.agent-loop/*` canonical docs.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Development
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
npm install
|
|
250
|
+
npm run typecheck
|
|
251
|
+
npm test
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
`npm test` runs a full TypeScript build first, then executes the automated test suite.
|
|
255
|
+
|
|
256
|
+
### Publish to npm (public)
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
npm run publish:public:dry-run
|
|
260
|
+
npm run publish:public
|
|
261
|
+
```
|
|
262
|
+
|
|
242
263
|
---
|
|
243
264
|
|
|
244
265
|
## License
|
package/bin/cli.js
CHANGED
|
@@ -1,131 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
const command = args[0];
|
|
5
|
-
|
|
6
|
-
function getOptionValue(optionName) {
|
|
7
|
-
const idx = args.indexOf(optionName);
|
|
8
|
-
if (idx === -1) return undefined;
|
|
9
|
-
return args[idx + 1];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function getPositionalArgs() {
|
|
13
|
-
const positionals = [];
|
|
14
|
-
for (let i = 1; i < args.length; i += 1) {
|
|
15
|
-
const current = args[i];
|
|
16
|
-
if (current === "--target") {
|
|
17
|
-
i += 1;
|
|
18
|
-
continue;
|
|
19
|
-
}
|
|
20
|
-
if (current === "--dry-run" || current === "--overwrite" || current === "--no-overwrite") {
|
|
21
|
-
continue;
|
|
22
|
-
}
|
|
23
|
-
if (current.startsWith("--")) {
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
|
-
positionals.push(current);
|
|
27
|
-
}
|
|
28
|
-
return positionals;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
// Help
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
35
|
-
process.stdout.write(`
|
|
36
|
-
sync_loop - MCP server + CLI for the SyncLoop agent reasoning protocol
|
|
37
|
-
|
|
38
|
-
Usage:
|
|
39
|
-
npx -y -p @oleksandr.rudnychenko/sync_loop sync_loop
|
|
40
|
-
Start MCP server (stdio transport)
|
|
41
|
-
|
|
42
|
-
npx -y -p @oleksandr.rudnychenko/sync_loop sync_loop init [projectPath] [--target <platform>] [--dry-run] [--no-overwrite]
|
|
43
|
-
Scaffold files into the project
|
|
44
|
-
|
|
45
|
-
npx -y -p @oleksandr.rudnychenko/sync_loop sync_loop --help
|
|
46
|
-
Show this help
|
|
47
|
-
|
|
48
|
-
Init targets:
|
|
49
|
-
copilot .github/instructions/ + copilot-instructions.md
|
|
50
|
-
cursor .cursor/rules/ with frontmatter
|
|
51
|
-
claude CLAUDE.md + .claude/rules/
|
|
52
|
-
all All of the above (default)
|
|
53
|
-
|
|
54
|
-
Flags:
|
|
55
|
-
--dry-run Preview writes without modifying files
|
|
56
|
-
--no-overwrite Do not overwrite existing generated files
|
|
57
|
-
|
|
58
|
-
MCP Configuration (add to your client settings):
|
|
59
|
-
|
|
60
|
-
{
|
|
61
|
-
"mcpServers": {
|
|
62
|
-
"sync_loop": {
|
|
63
|
-
"command": "npx",
|
|
64
|
-
"args": ["-y", "-p", "@oleksandr.rudnychenko/sync_loop", "sync_loop"]
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
Resources: Protocol docs on-demand (reasoning kernel, validation, feedback, patterns)
|
|
70
|
-
Tools: init - scaffold platform-specific files
|
|
71
|
-
Prompts: bootstrap - wire SyncLoop to your project; protocol - reasoning loop
|
|
72
|
-
|
|
73
|
-
https://github.com/oleksandr-rud/SyncLoop
|
|
74
|
-
`);
|
|
75
|
-
process.exit(0);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// ---------------------------------------------------------------------------
|
|
79
|
-
// CLI: npx sync_loop init
|
|
80
|
-
// ---------------------------------------------------------------------------
|
|
81
|
-
if (command === "init") {
|
|
82
|
-
const target = getOptionValue("--target") ?? "all";
|
|
83
|
-
const dryRun = args.includes("--dry-run");
|
|
84
|
-
const overwrite = args.includes("--no-overwrite") ? false : true;
|
|
85
|
-
const validTargets = ["copilot", "cursor", "claude", "all"];
|
|
86
|
-
|
|
87
|
-
if (!validTargets.includes(target)) {
|
|
88
|
-
process.stderr.write(`Error: unknown target "${target}". Use one of: ${validTargets.join(", ")}\n`);
|
|
89
|
-
process.exit(1);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const [projectPath] = getPositionalArgs();
|
|
93
|
-
const resolvedProjectPath = projectPath || process.cwd();
|
|
94
|
-
|
|
95
|
-
const { init, detectStacks } = await import("../src/init.js");
|
|
96
|
-
|
|
97
|
-
try {
|
|
98
|
-
const stacks = detectStacks(resolvedProjectPath);
|
|
99
|
-
const result = init(
|
|
100
|
-
resolvedProjectPath,
|
|
101
|
-
target,
|
|
102
|
-
stacks,
|
|
103
|
-
{ dryRun, overwrite },
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
process.stdout.write([
|
|
107
|
-
`SyncLoop initialized for ${target}:`,
|
|
108
|
-
"",
|
|
109
|
-
...result.results,
|
|
110
|
-
"",
|
|
111
|
-
"Detected stacks:",
|
|
112
|
-
...result.stacks.map((stack) => `- ${stack.name}${stack.path ? ` (${stack.path})` : ""}: ${stack.languages.join(", ")} | ${stack.frameworks.join(", ")}`),
|
|
113
|
-
"",
|
|
114
|
-
dryRun
|
|
115
|
-
? "Dry run complete. No files were modified."
|
|
116
|
-
: "Done. Run the bootstrap prompt to wire to your project.",
|
|
117
|
-
"",
|
|
118
|
-
].join("\n"));
|
|
119
|
-
} catch (err) {
|
|
120
|
-
process.stderr.write(`Error: ${err.message}\n`);
|
|
121
|
-
process.exit(1);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
process.exit(0);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// ---------------------------------------------------------------------------
|
|
128
|
-
// Default: start MCP server
|
|
129
|
-
// ---------------------------------------------------------------------------
|
|
130
|
-
import("../src/server.js");
|
|
3
|
+
import { runCli } from "../dist/bin/cli.js";
|
|
131
4
|
|
|
5
|
+
const exitCode = await runCli();
|
|
6
|
+
process.exit(exitCode);
|
package/bin/cli.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { detectStacks, init, type InitTarget, type StackDefinition } from "../src/init.js";
|
|
5
|
+
import { startServer } from "../src/server.js";
|
|
6
|
+
|
|
7
|
+
const VALID_TARGETS: InitTarget[] = ["copilot", "cursor", "claude", "all"];
|
|
8
|
+
|
|
9
|
+
const HELP_TEXT = `
|
|
10
|
+
sync_loop - MCP server + CLI for the SyncLoop agent reasoning protocol
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
npx -y -p @oleksandr.rudnychenko/sync_loop sync_loop
|
|
14
|
+
Start MCP server (stdio transport)
|
|
15
|
+
|
|
16
|
+
npx -y -p @oleksandr.rudnychenko/sync_loop sync_loop init [projectPath] [--target <platform>] [--dry-run] [--no-overwrite]
|
|
17
|
+
Scaffold files into the project
|
|
18
|
+
|
|
19
|
+
npx -y -p @oleksandr.rudnychenko/sync_loop sync_loop --help
|
|
20
|
+
Show this help
|
|
21
|
+
|
|
22
|
+
Init targets:
|
|
23
|
+
copilot .agent-loop/ + .github/instructions/ + copilot-instructions.md
|
|
24
|
+
cursor .agent-loop/ + .cursor/rules/ with frontmatter
|
|
25
|
+
claude .agent-loop/ + CLAUDE.md + .claude/rules/
|
|
26
|
+
all All of the above (default)
|
|
27
|
+
|
|
28
|
+
Flags:
|
|
29
|
+
--dry-run Preview writes without modifying files
|
|
30
|
+
--no-overwrite Do not overwrite existing generated files
|
|
31
|
+
|
|
32
|
+
MCP Configuration (add to your client settings):
|
|
33
|
+
|
|
34
|
+
{
|
|
35
|
+
"mcpServers": {
|
|
36
|
+
"sync_loop": {
|
|
37
|
+
"command": "npx",
|
|
38
|
+
"args": ["-y", "-p", "@oleksandr.rudnychenko/sync_loop", "sync_loop"]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
Resources: Protocol docs on-demand (reasoning kernel, validation, feedback, patterns)
|
|
44
|
+
Tools: init - scaffold platform-specific files
|
|
45
|
+
Prompts: bootstrap - wire SyncLoop to your project; protocol - reasoning loop
|
|
46
|
+
|
|
47
|
+
https://github.com/oleksandr-rud/SyncLoop
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
export interface CliIo {
|
|
51
|
+
stdout: Pick<NodeJS.WritableStream, "write">;
|
|
52
|
+
stderr: Pick<NodeJS.WritableStream, "write">;
|
|
53
|
+
cwd: () => string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface CliDeps {
|
|
57
|
+
detectStacksFn: (projectPath: string) => StackDefinition[];
|
|
58
|
+
initFn: typeof init;
|
|
59
|
+
startServerFn: () => Promise<unknown>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function defaultIo(): CliIo {
|
|
63
|
+
return {
|
|
64
|
+
stdout: process.stdout,
|
|
65
|
+
stderr: process.stderr,
|
|
66
|
+
cwd: () => process.cwd(),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function defaultDeps(): CliDeps {
|
|
71
|
+
return {
|
|
72
|
+
detectStacksFn: detectStacks,
|
|
73
|
+
initFn: init,
|
|
74
|
+
startServerFn: startServer,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function getOptionValue(args: string[], optionName: string): string | undefined {
|
|
79
|
+
const idx = args.indexOf(optionName);
|
|
80
|
+
if (idx === -1) return undefined;
|
|
81
|
+
return args[idx + 1];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function getPositionalArgs(args: string[]): string[] {
|
|
85
|
+
const positionals: string[] = [];
|
|
86
|
+
for (let i = 1; i < args.length; i += 1) {
|
|
87
|
+
const current = args[i];
|
|
88
|
+
if (current === "--target") {
|
|
89
|
+
i += 1;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (current === "--dry-run" || current === "--overwrite" || current === "--no-overwrite") {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (current.startsWith("--")) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
positionals.push(current);
|
|
99
|
+
}
|
|
100
|
+
return positionals;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export async function runCli(
|
|
104
|
+
args: string[] = process.argv.slice(2),
|
|
105
|
+
io: CliIo = defaultIo(),
|
|
106
|
+
deps: CliDeps = defaultDeps(),
|
|
107
|
+
): Promise<number> {
|
|
108
|
+
const command = args[0];
|
|
109
|
+
|
|
110
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
111
|
+
io.stdout.write(HELP_TEXT);
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (command === "init") {
|
|
116
|
+
const target = (getOptionValue(args, "--target") ?? "all") as InitTarget;
|
|
117
|
+
const dryRun = args.includes("--dry-run");
|
|
118
|
+
const overwrite = args.includes("--no-overwrite") ? false : true;
|
|
119
|
+
|
|
120
|
+
if (!VALID_TARGETS.includes(target)) {
|
|
121
|
+
io.stderr.write(`Error: unknown target "${target}". Use one of: ${VALID_TARGETS.join(", ")}\n`);
|
|
122
|
+
return 1;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const [projectPath] = getPositionalArgs(args);
|
|
126
|
+
const resolvedProjectPath = projectPath || io.cwd();
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const stacks = deps.detectStacksFn(resolvedProjectPath);
|
|
130
|
+
const result = deps.initFn(
|
|
131
|
+
resolvedProjectPath,
|
|
132
|
+
target,
|
|
133
|
+
stacks,
|
|
134
|
+
{ dryRun, overwrite },
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
io.stdout.write([
|
|
138
|
+
`SyncLoop initialized for ${target}:`,
|
|
139
|
+
"",
|
|
140
|
+
...result.results,
|
|
141
|
+
"",
|
|
142
|
+
"Detected stacks:",
|
|
143
|
+
...result.stacks.map((stack) => `- ${stack.name}${stack.path ? ` (${stack.path})` : ""}: ${stack.languages.join(", ")} | ${stack.frameworks.join(", ")}`),
|
|
144
|
+
"",
|
|
145
|
+
dryRun
|
|
146
|
+
? "Dry run complete. No files were modified."
|
|
147
|
+
: "Done. Run the bootstrap prompt to wire to your project.",
|
|
148
|
+
"",
|
|
149
|
+
].join("\n"));
|
|
150
|
+
return 0;
|
|
151
|
+
} catch (err) {
|
|
152
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
153
|
+
io.stderr.write(`Error: ${message}\n`);
|
|
154
|
+
return 1;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
await deps.startServerFn();
|
|
159
|
+
return 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function isMainModule(metaUrl: string): boolean {
|
|
163
|
+
const entryFile = process.argv[1];
|
|
164
|
+
if (!entryFile) return false;
|
|
165
|
+
return metaUrl === pathToFileURL(entryFile).href;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (isMainModule(import.meta.url)) {
|
|
169
|
+
const exitCode = await runCli();
|
|
170
|
+
process.exit(exitCode);
|
|
171
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { init, type StackDefinition } from "../src/init.js";
|
|
3
|
+
export interface CliIo {
|
|
4
|
+
stdout: Pick<NodeJS.WritableStream, "write">;
|
|
5
|
+
stderr: Pick<NodeJS.WritableStream, "write">;
|
|
6
|
+
cwd: () => string;
|
|
7
|
+
}
|
|
8
|
+
export interface CliDeps {
|
|
9
|
+
detectStacksFn: (projectPath: string) => StackDefinition[];
|
|
10
|
+
initFn: typeof init;
|
|
11
|
+
startServerFn: () => Promise<unknown>;
|
|
12
|
+
}
|
|
13
|
+
export declare function getOptionValue(args: string[], optionName: string): string | undefined;
|
|
14
|
+
export declare function getPositionalArgs(args: string[]): string[];
|
|
15
|
+
export declare function runCli(args?: string[], io?: CliIo, deps?: CliDeps): Promise<number>;
|
package/dist/bin/cli.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
import { detectStacks, init } from "../src/init.js";
|
|
4
|
+
import { startServer } from "../src/server.js";
|
|
5
|
+
const VALID_TARGETS = ["copilot", "cursor", "claude", "all"];
|
|
6
|
+
const HELP_TEXT = `
|
|
7
|
+
sync_loop - MCP server + CLI for the SyncLoop agent reasoning protocol
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
npx -y -p @oleksandr.rudnychenko/sync_loop sync_loop
|
|
11
|
+
Start MCP server (stdio transport)
|
|
12
|
+
|
|
13
|
+
npx -y -p @oleksandr.rudnychenko/sync_loop sync_loop init [projectPath] [--target <platform>] [--dry-run] [--no-overwrite]
|
|
14
|
+
Scaffold files into the project
|
|
15
|
+
|
|
16
|
+
npx -y -p @oleksandr.rudnychenko/sync_loop sync_loop --help
|
|
17
|
+
Show this help
|
|
18
|
+
|
|
19
|
+
Init targets:
|
|
20
|
+
copilot .agent-loop/ + .github/instructions/ + copilot-instructions.md
|
|
21
|
+
cursor .agent-loop/ + .cursor/rules/ with frontmatter
|
|
22
|
+
claude .agent-loop/ + CLAUDE.md + .claude/rules/
|
|
23
|
+
all All of the above (default)
|
|
24
|
+
|
|
25
|
+
Flags:
|
|
26
|
+
--dry-run Preview writes without modifying files
|
|
27
|
+
--no-overwrite Do not overwrite existing generated files
|
|
28
|
+
|
|
29
|
+
MCP Configuration (add to your client settings):
|
|
30
|
+
|
|
31
|
+
{
|
|
32
|
+
"mcpServers": {
|
|
33
|
+
"sync_loop": {
|
|
34
|
+
"command": "npx",
|
|
35
|
+
"args": ["-y", "-p", "@oleksandr.rudnychenko/sync_loop", "sync_loop"]
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
Resources: Protocol docs on-demand (reasoning kernel, validation, feedback, patterns)
|
|
41
|
+
Tools: init - scaffold platform-specific files
|
|
42
|
+
Prompts: bootstrap - wire SyncLoop to your project; protocol - reasoning loop
|
|
43
|
+
|
|
44
|
+
https://github.com/oleksandr-rud/SyncLoop
|
|
45
|
+
`;
|
|
46
|
+
function defaultIo() {
|
|
47
|
+
return {
|
|
48
|
+
stdout: process.stdout,
|
|
49
|
+
stderr: process.stderr,
|
|
50
|
+
cwd: () => process.cwd(),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function defaultDeps() {
|
|
54
|
+
return {
|
|
55
|
+
detectStacksFn: detectStacks,
|
|
56
|
+
initFn: init,
|
|
57
|
+
startServerFn: startServer,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function getOptionValue(args, optionName) {
|
|
61
|
+
const idx = args.indexOf(optionName);
|
|
62
|
+
if (idx === -1)
|
|
63
|
+
return undefined;
|
|
64
|
+
return args[idx + 1];
|
|
65
|
+
}
|
|
66
|
+
export function getPositionalArgs(args) {
|
|
67
|
+
const positionals = [];
|
|
68
|
+
for (let i = 1; i < args.length; i += 1) {
|
|
69
|
+
const current = args[i];
|
|
70
|
+
if (current === "--target") {
|
|
71
|
+
i += 1;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (current === "--dry-run" || current === "--overwrite" || current === "--no-overwrite") {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (current.startsWith("--")) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
positionals.push(current);
|
|
81
|
+
}
|
|
82
|
+
return positionals;
|
|
83
|
+
}
|
|
84
|
+
export async function runCli(args = process.argv.slice(2), io = defaultIo(), deps = defaultDeps()) {
|
|
85
|
+
const command = args[0];
|
|
86
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
87
|
+
io.stdout.write(HELP_TEXT);
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
if (command === "init") {
|
|
91
|
+
const target = (getOptionValue(args, "--target") ?? "all");
|
|
92
|
+
const dryRun = args.includes("--dry-run");
|
|
93
|
+
const overwrite = args.includes("--no-overwrite") ? false : true;
|
|
94
|
+
if (!VALID_TARGETS.includes(target)) {
|
|
95
|
+
io.stderr.write(`Error: unknown target "${target}". Use one of: ${VALID_TARGETS.join(", ")}\n`);
|
|
96
|
+
return 1;
|
|
97
|
+
}
|
|
98
|
+
const [projectPath] = getPositionalArgs(args);
|
|
99
|
+
const resolvedProjectPath = projectPath || io.cwd();
|
|
100
|
+
try {
|
|
101
|
+
const stacks = deps.detectStacksFn(resolvedProjectPath);
|
|
102
|
+
const result = deps.initFn(resolvedProjectPath, target, stacks, { dryRun, overwrite });
|
|
103
|
+
io.stdout.write([
|
|
104
|
+
`SyncLoop initialized for ${target}:`,
|
|
105
|
+
"",
|
|
106
|
+
...result.results,
|
|
107
|
+
"",
|
|
108
|
+
"Detected stacks:",
|
|
109
|
+
...result.stacks.map((stack) => `- ${stack.name}${stack.path ? ` (${stack.path})` : ""}: ${stack.languages.join(", ")} | ${stack.frameworks.join(", ")}`),
|
|
110
|
+
"",
|
|
111
|
+
dryRun
|
|
112
|
+
? "Dry run complete. No files were modified."
|
|
113
|
+
: "Done. Run the bootstrap prompt to wire to your project.",
|
|
114
|
+
"",
|
|
115
|
+
].join("\n"));
|
|
116
|
+
return 0;
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
120
|
+
io.stderr.write(`Error: ${message}\n`);
|
|
121
|
+
return 1;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
await deps.startServerFn();
|
|
125
|
+
return 0;
|
|
126
|
+
}
|
|
127
|
+
function isMainModule(metaUrl) {
|
|
128
|
+
const entryFile = process.argv[1];
|
|
129
|
+
if (!entryFile)
|
|
130
|
+
return false;
|
|
131
|
+
return metaUrl === pathToFileURL(entryFile).href;
|
|
132
|
+
}
|
|
133
|
+
if (isMainModule(import.meta.url)) {
|
|
134
|
+
const exitCode = await runCli();
|
|
135
|
+
process.exit(exitCode);
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type InitTarget = "copilot" | "cursor" | "claude" | "all";
|
|
2
|
+
export interface StackDefinition {
|
|
3
|
+
name: string;
|
|
4
|
+
languages: string[];
|
|
5
|
+
frameworks: string[];
|
|
6
|
+
testRunner?: string;
|
|
7
|
+
typeChecker?: string;
|
|
8
|
+
linter?: string;
|
|
9
|
+
packageManager?: string;
|
|
10
|
+
path?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface InitOptions {
|
|
13
|
+
dryRun?: boolean;
|
|
14
|
+
overwrite?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function detectStacks(projectPath: string): StackDefinition[];
|
|
17
|
+
export declare function init(projectPath: string, target?: InitTarget, stacks?: StackDefinition[], options?: InitOptions): {
|
|
18
|
+
projectPath: string;
|
|
19
|
+
target: InitTarget;
|
|
20
|
+
dryRun: boolean;
|
|
21
|
+
overwrite: boolean;
|
|
22
|
+
stacks: StackDefinition[];
|
|
23
|
+
results: string[];
|
|
24
|
+
};
|