@omerrgocmen/crewctl 1.3.1 → 1.3.3

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.
Files changed (92) hide show
  1. package/README.md +193 -193
  2. package/orchestrator/README.md +473 -473
  3. package/orchestrator/config.default.json +96 -90
  4. package/orchestrator/roles/executor.md +57 -57
  5. package/orchestrator/roles/operator.md +77 -77
  6. package/orchestrator/roles/planner.md +58 -58
  7. package/orchestrator/roles/reviewer.md +63 -63
  8. package/orchestrator/skills/acceptance-criteria.md +18 -18
  9. package/orchestrator/skills/accessibility-audit.md +16 -16
  10. package/orchestrator/skills/accessible-forms.md +16 -16
  11. package/orchestrator/skills/api-design.md +27 -27
  12. package/orchestrator/skills/api-documentation.md +16 -16
  13. package/orchestrator/skills/architecture-decision-record.md +18 -18
  14. package/orchestrator/skills/authentication-design.md +16 -16
  15. package/orchestrator/skills/authorization-review.md +16 -16
  16. package/orchestrator/skills/backward-compatibility.md +17 -17
  17. package/orchestrator/skills/changelog-writing.md +16 -16
  18. package/orchestrator/skills/ci-pipeline-design.md +16 -16
  19. package/orchestrator/skills/cli-design.md +16 -16
  20. package/orchestrator/skills/code-review.md +27 -27
  21. package/orchestrator/skills/configuration-management.md +16 -16
  22. package/orchestrator/skills/container-review.md +16 -16
  23. package/orchestrator/skills/contract-testing.md +16 -16
  24. package/orchestrator/skills/dashboard-design.md +16 -16
  25. package/orchestrator/skills/database-migration.md +16 -16
  26. package/orchestrator/skills/database-schema-design.md +16 -16
  27. package/orchestrator/skills/debugging.md +26 -26
  28. package/orchestrator/skills/dependency-review.md +16 -16
  29. package/orchestrator/skills/design-review.md +29 -29
  30. package/orchestrator/skills/design-system.md +16 -16
  31. package/orchestrator/skills/docs-api-reference.md +16 -16
  32. package/orchestrator/skills/docs-troubleshooting.md +16 -16
  33. package/orchestrator/skills/docs-tutorial.md +16 -16
  34. package/orchestrator/skills/docs-writing.md +25 -25
  35. package/orchestrator/skills/empty-error-loading-states.md +16 -16
  36. package/orchestrator/skills/end-to-end-testing.md +16 -16
  37. package/orchestrator/skills/error-handling.md +16 -16
  38. package/orchestrator/skills/frontend-design.md +28 -28
  39. package/orchestrator/skills/git-commit-writing.md +16 -16
  40. package/orchestrator/skills/graphql-design.md +16 -16
  41. package/orchestrator/skills/incident-runbook.md +18 -18
  42. package/orchestrator/skills/input-validation.md +16 -16
  43. package/orchestrator/skills/integration-testing.md +16 -16
  44. package/orchestrator/skills/interaction-design.md +16 -16
  45. package/orchestrator/skills/landing-page-design.md +16 -16
  46. package/orchestrator/skills/observability-design.md +16 -16
  47. package/orchestrator/skills/openapi-contract.md +16 -16
  48. package/orchestrator/skills/performance-profiling.md +16 -16
  49. package/orchestrator/skills/privacy-review.md +16 -16
  50. package/orchestrator/skills/property-based-testing.md +16 -16
  51. package/orchestrator/skills/pull-request-writing.md +16 -16
  52. package/orchestrator/skills/refactoring.md +16 -16
  53. package/orchestrator/skills/release-readiness.md +16 -16
  54. package/orchestrator/skills/responsive-design.md +16 -16
  55. package/orchestrator/skills/secrets-management.md +16 -16
  56. package/orchestrator/skills/secure-file-upload.md +16 -16
  57. package/orchestrator/skills/security-review.md +26 -26
  58. package/orchestrator/skills/semantic-versioning.md +17 -17
  59. package/orchestrator/skills/seo-on-page.md +16 -16
  60. package/orchestrator/skills/seo-structured-data.md +16 -16
  61. package/orchestrator/skills/seo-technical-audit.md +16 -16
  62. package/orchestrator/skills/sql-query-review.md +16 -16
  63. package/orchestrator/skills/supply-chain-security.md +16 -16
  64. package/orchestrator/skills/test-strategy.md +16 -16
  65. package/orchestrator/skills/threat-modeling.md +16 -16
  66. package/orchestrator/skills/unit-testing.md +16 -16
  67. package/orchestrator/skills/write-tests.md +28 -28
  68. package/orchestrator/src/checkpoints.js +183 -183
  69. package/orchestrator/src/cli-registry.js +125 -3
  70. package/orchestrator/src/cli.js +140 -140
  71. package/orchestrator/src/doctor.js +64 -64
  72. package/orchestrator/src/engine.js +2112 -1914
  73. package/orchestrator/src/schedule.js +124 -124
  74. package/orchestrator/src/server.js +942 -817
  75. package/orchestrator/src/skill-registry.js +272 -272
  76. package/orchestrator/src/store.js +583 -478
  77. package/orchestrator/web/OrbitControls.js +1417 -1417
  78. package/orchestrator/web/board.html +146 -146
  79. package/orchestrator/web/code.html +213 -213
  80. package/orchestrator/web/flow.html +741 -741
  81. package/orchestrator/web/index.html +784 -622
  82. package/orchestrator/web/jsm/postprocessing/EffectComposer.js +231 -231
  83. package/orchestrator/web/jsm/postprocessing/MaskPass.js +104 -104
  84. package/orchestrator/web/jsm/postprocessing/Pass.js +95 -95
  85. package/orchestrator/web/jsm/postprocessing/RenderPass.js +99 -99
  86. package/orchestrator/web/jsm/postprocessing/ShaderPass.js +77 -77
  87. package/orchestrator/web/jsm/postprocessing/UnrealBloomPass.js +415 -415
  88. package/orchestrator/web/jsm/shaders/CopyShader.js +45 -45
  89. package/orchestrator/web/jsm/shaders/LuminosityHighPassShader.js +66 -66
  90. package/orchestrator/web/site.webmanifest +12 -12
  91. package/orchestrator/web/three.module.min.js +6 -6
  92. package/package.json +51 -51
@@ -1,183 +1,183 @@
1
- // checkpoints.js — gorev-basi otomatik surumleme (sifir bagimlilik).
2
- // Her gorev CALISMADAN ONCE calisma klasorunun bir surumu (checkpoint) alinir; ajan kodu
3
- // bozarsa tek tikla o surume donulur. Depolama daima birebir dosya KOPYASIDIR (deterministik,
4
- // git durumundan bagimsiz, geri-alinabilir). "git-farkinda": klasor bir git deposuysa hangi
5
- // dosyalarin yedeklenecegi `git ls-files` ile belirlenir (boylece .gitignore'a uyulur ve
6
- // build ciktilari/gecici dosyalar surume girmez); depoysa degilse guvenli bir walk kullanilir.
7
- // NOT: fs.cpSync Windows'ta non-ASCII yollarda (or. C:\Users\Ömer) cokebiliyor; tum kopyalar
8
- // Unicode-guvenli fs.copyFileSync ile yapilir.
9
- const { spawnSync } = require("child_process");
10
- const fs = require("fs");
11
- const path = require("path");
12
- const store = require("./store");
13
-
14
- const isWin = process.platform === "win32";
15
- const CP_ROOT = path.join(store.ROOT, "state", "checkpoints");
16
- const MAX_FILES = 5000; // Bundan buyuk klasorlerde surum alma (guvenlik/performans).
17
- const MAX_BYTES = 200 * 1024 * 1024;
18
- const DEFAULT_RETENTION = 20;
19
-
20
- // snapshotDir (engine) ile AYNI ignore mantigi: node_modules/.git ve orkestratorun kendi
21
- // runtime durumu (queue/state/memory) surume girmemeli — aksi halde checkpoint kendi icine
22
- // kopyalanip sisebilir.
23
- function ignored(rel) {
24
- const r = String(rel).replace(/\\/g, "/");
25
- return r.includes("node_modules") || r.includes(".git/") || r === ".git" || r.startsWith(".git/") ||
26
- r.startsWith("orchestrator/queue") || r.startsWith("orchestrator/state") ||
27
- r.startsWith("orchestrator/memory") || r.startsWith("orchestrator/node_modules");
28
- }
29
-
30
- function isGitRepo(cwd) {
31
- try {
32
- const r = spawnSync("git", ["-C", cwd, "rev-parse", "--is-inside-work-tree"], {
33
- encoding: "utf8", timeout: 8000, windowsHide: true, shell: isWin,
34
- });
35
- return r.status === 0 && /true/i.test(String(r.stdout || ""));
36
- } catch { return false; }
37
- }
38
-
39
- // Tracked + izlenmeyen ama .gitignore'da olmayan dosyalar; NUL ayrac unicode/bosluk-guvenli.
40
- function gitFileList(cwd) {
41
- try {
42
- const r = spawnSync("git", ["-C", cwd, "ls-files", "--cached", "--others", "--exclude-standard", "-z"], {
43
- encoding: "utf8", timeout: 20000, maxBuffer: 64 * 1024 * 1024, windowsHide: true, shell: isWin,
44
- });
45
- if (r.status !== 0) return null;
46
- return String(r.stdout || "").split("\0").filter(Boolean);
47
- } catch { return null; }
48
- }
49
-
50
- function walkFileList(cwd) {
51
- const out = [];
52
- let count = 0;
53
- const walk = (abs, rel) => {
54
- if (count > MAX_FILES + 1) return;
55
- let entries;
56
- try { entries = fs.readdirSync(abs, { withFileTypes: true }); } catch { return; }
57
- for (const entry of entries) {
58
- const childRel = rel ? `${rel}/${entry.name}` : entry.name;
59
- if (ignored(childRel)) continue;
60
- if (entry.isSymbolicLink()) continue; // Sembolik baglantilari izleme (klasor disina cikmasin).
61
- const childAbs = path.join(abs, entry.name);
62
- if (entry.isDirectory()) walk(childAbs, childRel);
63
- else { out.push(childRel); count++; }
64
- }
65
- };
66
- walk(cwd, "");
67
- return out;
68
- }
69
-
70
- function fileList(cwd) {
71
- if (isGitRepo(cwd)) {
72
- const git = gitFileList(cwd);
73
- // Bos liste (or. calisma klasoru gitignore'da) walk'a duser; aksi halde surum bos kalir
74
- // ve restore hicbir sey yapamaz. Dolu liste .gitignore'a uyan git-farkinda yoldur.
75
- if (git && git.length) return { files: git.filter((rel) => !ignored(rel)), backend: "git" };
76
- }
77
- return { files: walkFileList(cwd), backend: "copy" };
78
- }
79
-
80
- // Yol guvenligi: hedef daima cwd icinde kalmali (path traversal / sembolik kacis engeli).
81
- function within(root, rel) {
82
- const base = path.resolve(root);
83
- const target = path.resolve(base, rel);
84
- return target === base || target.startsWith(base + path.sep) ? target : null;
85
- }
86
-
87
- function ensureRoot() { fs.mkdirSync(CP_ROOT, { recursive: true }); }
88
-
89
- function readManifest(id) {
90
- try { return JSON.parse(fs.readFileSync(path.join(CP_ROOT, path.basename(String(id)), "manifest.json"), "utf8")); }
91
- catch { return null; }
92
- }
93
-
94
- function enforceRetention(cwd, retention) {
95
- const keep = Math.max(1, Number(retention) || DEFAULT_RETENTION);
96
- try {
97
- const mine = fs.readdirSync(CP_ROOT)
98
- .map(readManifest).filter((m) => m && path.resolve(m.cwd) === path.resolve(cwd))
99
- .sort((a, b) => (a.at < b.at ? 1 : -1));
100
- for (const m of mine.slice(keep)) {
101
- try { fs.rmSync(path.join(CP_ROOT, m.id), { recursive: true, force: true }); } catch {}
102
- }
103
- } catch {}
104
- }
105
-
106
- // Calisma klasorunun mevcut halinden bir surum (checkpoint) olusturur. Basarisiz/atlanmis
107
- // durumda gorevi ASLA oldurmez; {ok:false,...} doner ve cagiran log'lar.
108
- function createCheckpoint(cwd, meta = {}) {
109
- try {
110
- ensureRoot();
111
- const resolvedCwd = path.resolve(cwd);
112
- if (!fs.existsSync(resolvedCwd)) return { ok: false, skipped: true, reason: "Calisma klasoru bulunamadi." };
113
- const { files, backend } = fileList(resolvedCwd);
114
- if (files.length > MAX_FILES) return { ok: false, skipped: true, reason: `Klasor cok buyuk (${files.length} dosya > ${MAX_FILES}); surum alinmadi.` };
115
- const id = `cp-${new Date().toISOString().replace(/[-:T.]/g, "").slice(0, 17)}-${Math.random().toString(36).slice(2, 7)}`;
116
- const dir = path.join(CP_ROOT, id);
117
- const filesDir = path.join(dir, "files");
118
- fs.mkdirSync(filesDir, { recursive: true });
119
- const stored = [];
120
- let bytes = 0;
121
- for (const rel of files) {
122
- const src = within(resolvedCwd, rel);
123
- if (!src) continue;
124
- let st;
125
- try { st = fs.lstatSync(src); } catch { continue; }
126
- if (!st.isFile()) continue; // Sembolik baglanti / klasor / silinmis izlenen dosyayi atla.
127
- bytes += st.size;
128
- if (bytes > MAX_BYTES) { try { fs.rmSync(dir, { recursive: true, force: true }); } catch {} return { ok: false, skipped: true, reason: `Klasor cok buyuk (>${Math.round(MAX_BYTES / 1048576)}MB); surum alinmadi.` }; }
129
- const dest = path.join(filesDir, rel);
130
- try { fs.mkdirSync(path.dirname(dest), { recursive: true }); fs.copyFileSync(src, dest); stored.push(rel); } catch {}
131
- }
132
- const manifest = {
133
- id, at: new Date().toISOString(), cwd: resolvedCwd, backend,
134
- fileCount: stored.length, bytes, files: stored,
135
- taskId: meta.taskId || null, label: String(meta.label || "").slice(0, 300), kind: meta.kind || "pre-task",
136
- };
137
- fs.writeFileSync(path.join(dir, "manifest.json"), JSON.stringify(manifest, null, 2));
138
- enforceRetention(resolvedCwd, meta.retention);
139
- return { ok: true, ...manifest };
140
- } catch (error) { return { ok: false, error: error.message }; }
141
- }
142
-
143
- // Bir surumu geri yukler. Once MEVCUT hali de bir surum yapar (redo guvenligi), sonra:
144
- // (1) surumden SONRA olusan dosyalari siler, (2) surumdeki dosyalari geri yazar.
145
- function restoreCheckpoint(id, opts = {}) {
146
- const manifest = readManifest(id);
147
- if (!manifest) return { ok: false, error: "Surum bulunamadi." };
148
- const cwd = path.resolve(manifest.cwd);
149
- if (!fs.existsSync(cwd)) return { ok: false, error: "Calisma klasoru bulunamadi." };
150
- let redoId = null;
151
- if (opts.createRedo !== false) {
152
- const redo = createCheckpoint(cwd, { taskId: manifest.taskId, kind: "pre-restore", label: `Geri alma oncesi (${manifest.id})`, retention: opts.retention });
153
- if (redo.ok) redoId = redo.id;
154
- }
155
- const filesDir = path.join(CP_ROOT, path.basename(String(id)), "files");
156
- const keep = new Set(manifest.files);
157
- let deleted = 0;
158
- for (const rel of fileList(cwd).files) {
159
- if (keep.has(rel)) continue;
160
- const target = within(cwd, rel);
161
- if (!target) continue;
162
- try { if (fs.existsSync(target)) { fs.rmSync(target, { force: true }); deleted++; } } catch {}
163
- }
164
- let restored = 0;
165
- for (const rel of manifest.files) {
166
- const src = path.join(filesDir, rel);
167
- const dest = within(cwd, rel);
168
- if (!dest) continue;
169
- try { if (!fs.existsSync(src)) continue; fs.mkdirSync(path.dirname(dest), { recursive: true }); fs.copyFileSync(src, dest); restored++; } catch {}
170
- }
171
- return { ok: true, id: manifest.id, cwd, restored, deleted, redoId };
172
- }
173
-
174
- function listCheckpoints(cwd) {
175
- try {
176
- ensureRoot();
177
- const all = fs.readdirSync(CP_ROOT).map(readManifest).filter(Boolean);
178
- const filtered = cwd ? all.filter((m) => path.resolve(m.cwd) === path.resolve(cwd)) : all;
179
- return filtered.sort((a, b) => (a.at < b.at ? 1 : -1)).map(({ files, ...rest }) => rest);
180
- } catch { return []; }
181
- }
182
-
183
- module.exports = { CP_ROOT, createCheckpoint, restoreCheckpoint, listCheckpoints, readManifest, fileList, isGitRepo, _internals: { ignored, within, walkFileList } };
1
+ // checkpoints.js — gorev-basi otomatik surumleme (sifir bagimlilik).
2
+ // Her gorev CALISMADAN ONCE calisma klasorunun bir surumu (checkpoint) alinir; ajan kodu
3
+ // bozarsa tek tikla o surume donulur. Depolama daima birebir dosya KOPYASIDIR (deterministik,
4
+ // git durumundan bagimsiz, geri-alinabilir). "git-farkinda": klasor bir git deposuysa hangi
5
+ // dosyalarin yedeklenecegi `git ls-files` ile belirlenir (boylece .gitignore'a uyulur ve
6
+ // build ciktilari/gecici dosyalar surume girmez); depoysa degilse guvenli bir walk kullanilir.
7
+ // NOT: fs.cpSync Windows'ta non-ASCII yollarda (or. C:\Users\Ömer) cokebiliyor; tum kopyalar
8
+ // Unicode-guvenli fs.copyFileSync ile yapilir.
9
+ const { spawnSync } = require("child_process");
10
+ const fs = require("fs");
11
+ const path = require("path");
12
+ const store = require("./store");
13
+
14
+ const isWin = process.platform === "win32";
15
+ const CP_ROOT = path.join(store.ROOT, "state", "checkpoints");
16
+ const MAX_FILES = 5000; // Bundan buyuk klasorlerde surum alma (guvenlik/performans).
17
+ const MAX_BYTES = 200 * 1024 * 1024;
18
+ const DEFAULT_RETENTION = 20;
19
+
20
+ // snapshotDir (engine) ile AYNI ignore mantigi: node_modules/.git ve orkestratorun kendi
21
+ // runtime durumu (queue/state/memory) surume girmemeli — aksi halde checkpoint kendi icine
22
+ // kopyalanip sisebilir.
23
+ function ignored(rel) {
24
+ const r = String(rel).replace(/\\/g, "/");
25
+ return r.includes("node_modules") || r.includes(".git/") || r === ".git" || r.startsWith(".git/") ||
26
+ r.startsWith("orchestrator/queue") || r.startsWith("orchestrator/state") ||
27
+ r.startsWith("orchestrator/memory") || r.startsWith("orchestrator/node_modules");
28
+ }
29
+
30
+ function isGitRepo(cwd) {
31
+ try {
32
+ const r = spawnSync("git", ["-C", cwd, "rev-parse", "--is-inside-work-tree"], {
33
+ encoding: "utf8", timeout: 8000, windowsHide: true, shell: isWin,
34
+ });
35
+ return r.status === 0 && /true/i.test(String(r.stdout || ""));
36
+ } catch { return false; }
37
+ }
38
+
39
+ // Tracked + izlenmeyen ama .gitignore'da olmayan dosyalar; NUL ayrac unicode/bosluk-guvenli.
40
+ function gitFileList(cwd) {
41
+ try {
42
+ const r = spawnSync("git", ["-C", cwd, "ls-files", "--cached", "--others", "--exclude-standard", "-z"], {
43
+ encoding: "utf8", timeout: 20000, maxBuffer: 64 * 1024 * 1024, windowsHide: true, shell: isWin,
44
+ });
45
+ if (r.status !== 0) return null;
46
+ return String(r.stdout || "").split("\0").filter(Boolean);
47
+ } catch { return null; }
48
+ }
49
+
50
+ function walkFileList(cwd) {
51
+ const out = [];
52
+ let count = 0;
53
+ const walk = (abs, rel) => {
54
+ if (count > MAX_FILES + 1) return;
55
+ let entries;
56
+ try { entries = fs.readdirSync(abs, { withFileTypes: true }); } catch { return; }
57
+ for (const entry of entries) {
58
+ const childRel = rel ? `${rel}/${entry.name}` : entry.name;
59
+ if (ignored(childRel)) continue;
60
+ if (entry.isSymbolicLink()) continue; // Sembolik baglantilari izleme (klasor disina cikmasin).
61
+ const childAbs = path.join(abs, entry.name);
62
+ if (entry.isDirectory()) walk(childAbs, childRel);
63
+ else { out.push(childRel); count++; }
64
+ }
65
+ };
66
+ walk(cwd, "");
67
+ return out;
68
+ }
69
+
70
+ function fileList(cwd) {
71
+ if (isGitRepo(cwd)) {
72
+ const git = gitFileList(cwd);
73
+ // Bos liste (or. calisma klasoru gitignore'da) walk'a duser; aksi halde surum bos kalir
74
+ // ve restore hicbir sey yapamaz. Dolu liste .gitignore'a uyan git-farkinda yoldur.
75
+ if (git && git.length) return { files: git.filter((rel) => !ignored(rel)), backend: "git" };
76
+ }
77
+ return { files: walkFileList(cwd), backend: "copy" };
78
+ }
79
+
80
+ // Yol guvenligi: hedef daima cwd icinde kalmali (path traversal / sembolik kacis engeli).
81
+ function within(root, rel) {
82
+ const base = path.resolve(root);
83
+ const target = path.resolve(base, rel);
84
+ return target === base || target.startsWith(base + path.sep) ? target : null;
85
+ }
86
+
87
+ function ensureRoot() { fs.mkdirSync(CP_ROOT, { recursive: true }); }
88
+
89
+ function readManifest(id) {
90
+ try { return JSON.parse(fs.readFileSync(path.join(CP_ROOT, path.basename(String(id)), "manifest.json"), "utf8")); }
91
+ catch { return null; }
92
+ }
93
+
94
+ function enforceRetention(cwd, retention) {
95
+ const keep = Math.max(1, Number(retention) || DEFAULT_RETENTION);
96
+ try {
97
+ const mine = fs.readdirSync(CP_ROOT)
98
+ .map(readManifest).filter((m) => m && path.resolve(m.cwd) === path.resolve(cwd))
99
+ .sort((a, b) => (a.at < b.at ? 1 : -1));
100
+ for (const m of mine.slice(keep)) {
101
+ try { fs.rmSync(path.join(CP_ROOT, m.id), { recursive: true, force: true }); } catch {}
102
+ }
103
+ } catch {}
104
+ }
105
+
106
+ // Calisma klasorunun mevcut halinden bir surum (checkpoint) olusturur. Basarisiz/atlanmis
107
+ // durumda gorevi ASLA oldurmez; {ok:false,...} doner ve cagiran log'lar.
108
+ function createCheckpoint(cwd, meta = {}) {
109
+ try {
110
+ ensureRoot();
111
+ const resolvedCwd = path.resolve(cwd);
112
+ if (!fs.existsSync(resolvedCwd)) return { ok: false, skipped: true, reason: "Calisma klasoru bulunamadi." };
113
+ const { files, backend } = fileList(resolvedCwd);
114
+ if (files.length > MAX_FILES) return { ok: false, skipped: true, reason: `Klasor cok buyuk (${files.length} dosya > ${MAX_FILES}); surum alinmadi.` };
115
+ const id = `cp-${new Date().toISOString().replace(/[-:T.]/g, "").slice(0, 17)}-${Math.random().toString(36).slice(2, 7)}`;
116
+ const dir = path.join(CP_ROOT, id);
117
+ const filesDir = path.join(dir, "files");
118
+ fs.mkdirSync(filesDir, { recursive: true });
119
+ const stored = [];
120
+ let bytes = 0;
121
+ for (const rel of files) {
122
+ const src = within(resolvedCwd, rel);
123
+ if (!src) continue;
124
+ let st;
125
+ try { st = fs.lstatSync(src); } catch { continue; }
126
+ if (!st.isFile()) continue; // Sembolik baglanti / klasor / silinmis izlenen dosyayi atla.
127
+ bytes += st.size;
128
+ if (bytes > MAX_BYTES) { try { fs.rmSync(dir, { recursive: true, force: true }); } catch {} return { ok: false, skipped: true, reason: `Klasor cok buyuk (>${Math.round(MAX_BYTES / 1048576)}MB); surum alinmadi.` }; }
129
+ const dest = path.join(filesDir, rel);
130
+ try { fs.mkdirSync(path.dirname(dest), { recursive: true }); fs.copyFileSync(src, dest); stored.push(rel); } catch {}
131
+ }
132
+ const manifest = {
133
+ id, at: new Date().toISOString(), cwd: resolvedCwd, backend,
134
+ fileCount: stored.length, bytes, files: stored,
135
+ taskId: meta.taskId || null, label: String(meta.label || "").slice(0, 300), kind: meta.kind || "pre-task",
136
+ };
137
+ fs.writeFileSync(path.join(dir, "manifest.json"), JSON.stringify(manifest, null, 2));
138
+ enforceRetention(resolvedCwd, meta.retention);
139
+ return { ok: true, ...manifest };
140
+ } catch (error) { return { ok: false, error: error.message }; }
141
+ }
142
+
143
+ // Bir surumu geri yukler. Once MEVCUT hali de bir surum yapar (redo guvenligi), sonra:
144
+ // (1) surumden SONRA olusan dosyalari siler, (2) surumdeki dosyalari geri yazar.
145
+ function restoreCheckpoint(id, opts = {}) {
146
+ const manifest = readManifest(id);
147
+ if (!manifest) return { ok: false, error: "Surum bulunamadi." };
148
+ const cwd = path.resolve(manifest.cwd);
149
+ if (!fs.existsSync(cwd)) return { ok: false, error: "Calisma klasoru bulunamadi." };
150
+ let redoId = null;
151
+ if (opts.createRedo !== false) {
152
+ const redo = createCheckpoint(cwd, { taskId: manifest.taskId, kind: "pre-restore", label: `Geri alma oncesi (${manifest.id})`, retention: opts.retention });
153
+ if (redo.ok) redoId = redo.id;
154
+ }
155
+ const filesDir = path.join(CP_ROOT, path.basename(String(id)), "files");
156
+ const keep = new Set(manifest.files);
157
+ let deleted = 0;
158
+ for (const rel of fileList(cwd).files) {
159
+ if (keep.has(rel)) continue;
160
+ const target = within(cwd, rel);
161
+ if (!target) continue;
162
+ try { if (fs.existsSync(target)) { fs.rmSync(target, { force: true }); deleted++; } } catch {}
163
+ }
164
+ let restored = 0;
165
+ for (const rel of manifest.files) {
166
+ const src = path.join(filesDir, rel);
167
+ const dest = within(cwd, rel);
168
+ if (!dest) continue;
169
+ try { if (!fs.existsSync(src)) continue; fs.mkdirSync(path.dirname(dest), { recursive: true }); fs.copyFileSync(src, dest); restored++; } catch {}
170
+ }
171
+ return { ok: true, id: manifest.id, cwd, restored, deleted, redoId };
172
+ }
173
+
174
+ function listCheckpoints(cwd) {
175
+ try {
176
+ ensureRoot();
177
+ const all = fs.readdirSync(CP_ROOT).map(readManifest).filter(Boolean);
178
+ const filtered = cwd ? all.filter((m) => path.resolve(m.cwd) === path.resolve(cwd)) : all;
179
+ return filtered.sort((a, b) => (a.at < b.at ? 1 : -1)).map(({ files, ...rest }) => rest);
180
+ } catch { return []; }
181
+ }
182
+
183
+ module.exports = { CP_ROOT, createCheckpoint, restoreCheckpoint, listCheckpoints, readManifest, fileList, isGitRepo, _internals: { ignored, within, walkFileList } };
@@ -19,7 +19,13 @@ const DEFINITIONS = {
19
19
  claude: {
20
20
  command: "claude",
21
21
  versionArgs: ["--version"],
22
- defaultArgs: ["-p", "--permission-mode", "acceptEdits", "--output-format", "text"],
22
+ // stream-json + --verbose: claude 'text'/'json' modunda uzun isi TOPLU (tek seferde) doker;
23
+ // ara adimlarda stdout sessiz kalir ve motorun sessizlik sayaci calisan kosmayi yanlislikla
24
+ // oldururdu. stream-json her adimda (assistant mesaji, tool cagrisi/sonucu) olay akitir; boylece
25
+ // sessizlik sifirlanir. Nihai metin + kullanim son "result" olayindan ayiklanir.
26
+ defaultArgs: ["-p", "--permission-mode", "acceptEdits", "--output-format", "stream-json", "--verbose"],
27
+ // Claude artik akitiyor; kisa sessizlik esigi guvenli. (sizeFactor buyuk gorevde yine acar.)
28
+ silenceTimeoutSeconds: 240,
23
29
  description: "Claude Code uygulama, analiz ve test agenti",
24
30
  capabilities: ["implementation", "debugging", "testing", "review", "web"],
25
31
  roleFile: "roles/executor.md",
@@ -310,7 +316,17 @@ function effectiveAgent(agent, cfg) {
310
316
  }
311
317
  if (adapter === "claude") {
312
318
  if (!copy.args.includes("-p") && !copy.args.includes("--print")) copy.args.unshift("-p");
313
- if (!copy.args.includes("--output-format")) copy.args.push("--output-format", "text");
319
+ // Cikti formatini DAIMA stream-json'a normalize et (eski config.json'lar 'text'/'json' tutuyor
320
+ // olabilir). Boylece claude akitir ve sessizlik-timeout yanlis-pozitifi ortadan kalkar.
321
+ const ofIdx = copy.args.indexOf("--output-format");
322
+ if (ofIdx >= 0) copy.args[ofIdx + 1] = "stream-json";
323
+ else copy.args.push("--output-format", "stream-json");
324
+ // stream-json, -p (print) modunda --verbose ZORUNLU kilar; yoksa claude hata verir.
325
+ if (!copy.args.includes("--verbose")) copy.args.push("--verbose");
326
+ // Claude Code model secimini oturum baslangicinda --model ile kabul eder. Alias kullanmak
327
+ // (sonnet/opus/haiku vb.) sağlayiciya gore guncel, erisilebilir surume cozumlenmesini saglar.
328
+ const model = String(copy.model || settings.model || "").trim();
329
+ if (model && !copy.args.includes("--model") && !copy.args.includes("-m")) copy.args.push("--model", model);
314
330
  }
315
331
  if (adapter === "gemini") {
316
332
  // Otonom, non-interaktif calisma icin onay modu sart; yoksa izin bekleyip takilir.
@@ -733,6 +749,112 @@ function listCodexModels(options = {}) {
733
749
  });
734
750
  }
735
751
 
752
+ // Claude Code'un Agent SDK kontrol protokolu, oturum acilisinda o kullanicinin
753
+ // hesabina/saglayicisina/kurum politikasina gore gercekten secilebilir modelleri dondurur.
754
+ // Statik model kimlikleri tutmak hem hizla eskir hem de baska bir kullanicida gorunmeyen
755
+ // bir modeli secilebilir gosterir. Bu normalizer yalnizca UI'nin ihtiyaci olan alanlari
756
+ // alir; initialize yanitindaki hesap bilgilerini disari sizdirmaz.
757
+ function normalizeClaudeModels(models) {
758
+ const seen = new Set();
759
+ const normalized = [];
760
+ for (const model of Array.isArray(models) ? models : []) {
761
+ const id = String(model?.value || "").trim();
762
+ if (!id || seen.has(id)) continue;
763
+ seen.add(id);
764
+ normalized.push({
765
+ id,
766
+ resolvedModel: String(model.resolvedModel || "").trim(),
767
+ displayName: String(model.displayName || id).trim(),
768
+ description: String(model.description || "").trim(),
769
+ supportsEffort: model.supportsEffort === true,
770
+ supportedEffortLevels: Array.isArray(model.supportedEffortLevels)
771
+ ? model.supportedEffortLevels.map(String).filter(Boolean)
772
+ : [],
773
+ supportsAdaptiveThinking: model.supportsAdaptiveThinking === true,
774
+ supportsFastMode: model.supportsFastMode === true,
775
+ supportsAutoMode: model.supportsAutoMode === true,
776
+ });
777
+ }
778
+ return normalized;
779
+ }
780
+
781
+ function listClaudeModels(options = {}) {
782
+ const args = ["--output-format", "stream-json", "--verbose", "--input-format", "stream-json", "--no-session-persistence"];
783
+ const command = buildCommand(options.command || RESOLVED.get("claude") || DEFINITIONS.claude.command, args);
784
+ const timeoutMs = Math.max(5000, Number(options.timeoutMs || 20000));
785
+ const requestId = "crewctl-claude-models";
786
+ return new Promise((resolve, reject) => {
787
+ let buffer = "", stderr = "", settled = false;
788
+ let child, unregister = () => {};
789
+ const finish = (error, value) => {
790
+ if (settled) return;
791
+ settled = true;
792
+ clearTimeout(timer);
793
+ unregister();
794
+ terminateProbeTree(child);
795
+ if (error) reject(error); else resolve(value);
796
+ };
797
+ const timer = setTimeout(
798
+ () => finish(new Error(`Claude Code model listesi ${Math.round(timeoutMs / 1000)} saniyede alinamadi.`)),
799
+ timeoutMs,
800
+ );
801
+ try {
802
+ child = spawn(command.file, command.args, {
803
+ shell: command.shell,
804
+ windowsHide: true,
805
+ windowsVerbatimArguments: !!command.verbatim,
806
+ stdio: ["pipe", "pipe", "pipe"],
807
+ env: {
808
+ ...process.env,
809
+ CLAUDE_CODE_ENTRYPOINT: "sdk-ts",
810
+ CLAUDE_AGENT_SDK_CLIENT_APP: "crewctl",
811
+ },
812
+ });
813
+ } catch (error) {
814
+ finish(error);
815
+ return;
816
+ }
817
+ unregister = registerProbe(child);
818
+ child.stdout?.setEncoding("utf8");
819
+ child.stderr?.setEncoding("utf8");
820
+ child.stdout?.on("data", (chunk) => {
821
+ buffer += String(chunk);
822
+ const lines = buffer.split(/\r?\n/);
823
+ buffer = lines.pop() || "";
824
+ for (const line of lines) {
825
+ let message;
826
+ try { message = JSON.parse(line); } catch { continue; }
827
+ if (message.type !== "control_response" || message.response?.request_id !== requestId) continue;
828
+ if (message.response?.subtype !== "success") {
829
+ finish(new Error(message.response?.error || "Claude Code model listesi alinamadi."));
830
+ return;
831
+ }
832
+ const models = message.response?.response?.models;
833
+ if (!Array.isArray(models)) {
834
+ finish(new Error("Bu Claude Code surumu dinamik model katalogunu desteklemiyor."));
835
+ return;
836
+ }
837
+ finish(null, normalizeClaudeModels(models));
838
+ return;
839
+ }
840
+ });
841
+ child.stderr?.on("data", (chunk) => {
842
+ stderr = `${stderr}${String(chunk)}`.slice(-2048);
843
+ });
844
+ child.on("error", (error) => finish(error));
845
+ child.on("close", (code) => {
846
+ if (settled) return;
847
+ finish(new Error(stderr.trim() || `Claude Code model katalogu okunamadan cikti (kod ${code}).`));
848
+ });
849
+ child.stdin?.on("error", () => {});
850
+ child.stdin?.write(`${JSON.stringify({
851
+ type: "control_request",
852
+ request_id: requestId,
853
+ request: { subtype: "initialize" },
854
+ })}\n`);
855
+ });
856
+ }
857
+
736
858
  function addMissingAgents(cfg, discovered) {
737
859
  cfg.agents ||= {};
738
860
  const ignored = new Set(Array.isArray(cfg.discoveryIgnoredAdapters) ? cfg.discoveryIgnoredAdapters.map(String) : []);
@@ -845,4 +967,4 @@ function ensureValidOperator(cfg, discovered) {
845
967
  return changed;
846
968
  }
847
969
 
848
- module.exports = { DEFINITIONS, KNOWN_CLIS: Object.keys(DEFINITIONS), adapterId, authHint, normalizeAgentAdapter, normalizeAgentAdapters, effectiveAgent, preparePromptArgs, operatorSpec, buildCommand, agentEnvironment, discoverInstalled, discoveryCacheFrom, applyOpenCodeFallback, healthCheckAll, listCodexModels, abortActiveProbes, currentProbeGeneration, selectOpenCodeModel, parseOpenCodeModels, addMissingAgents, ensureValidOperator };
970
+ module.exports = { DEFINITIONS, KNOWN_CLIS: Object.keys(DEFINITIONS), adapterId, authHint, normalizeAgentAdapter, normalizeAgentAdapters, effectiveAgent, preparePromptArgs, operatorSpec, buildCommand, agentEnvironment, discoverInstalled, discoveryCacheFrom, applyOpenCodeFallback, healthCheckAll, listCodexModels, listClaudeModels, normalizeClaudeModels, abortActiveProbes, currentProbeGeneration, selectOpenCodeModel, parseOpenCodeModels, addMissingAgents, ensureValidOperator };