@oxgeneral/orch 1.0.2 → 1.0.4

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 (132) hide show
  1. package/dist/App-SSYYVFGW.js +22 -0
  2. package/dist/agent-Q34L27AY.js +9 -0
  3. package/dist/agent-shop-D2RS4BZK.js +2 -0
  4. package/dist/chunk-4MMHVHA6.js +112 -0
  5. package/dist/chunk-64WUDYEM.js +6 -0
  6. package/dist/chunk-6MJ7V6VY.js +2 -0
  7. package/dist/{chunk-DAVHOWGD.js → chunk-BCPUTULS.js} +16 -188
  8. package/dist/{chunk-INZ4O2RI.js → chunk-BSJVYRI3.js} +5 -2
  9. package/dist/chunk-BSJVYRI3.js.map +1 -0
  10. package/dist/chunk-CDFA4IIQ.js +2 -0
  11. package/dist/chunk-CHRW4CLD.js +2 -0
  12. package/dist/chunk-HMMPM7MF.js +3 -0
  13. package/dist/chunk-HXOMNULD.js +2 -0
  14. package/dist/chunk-IKNBPOQL.js +2 -0
  15. package/dist/chunk-KFQTWMZI.js +3 -0
  16. package/dist/chunk-LXNRCJ22.js +2 -0
  17. package/dist/{chunk-C6XZ3FJT.js → chunk-MOWC2CHX.js} +7 -4
  18. package/dist/chunk-MOWC2CHX.js.map +1 -0
  19. package/dist/chunk-P4JTJBWO.js +2 -0
  20. package/dist/chunk-PJ5DKXGR.js +2 -0
  21. package/dist/chunk-QNZ6D63E.js +4 -0
  22. package/dist/chunk-RHFRHCN5.js +16 -0
  23. package/dist/chunk-RHFRHCN5.js.map +1 -0
  24. package/dist/chunk-TPTHLFOB.js +2 -0
  25. package/dist/chunk-UMZEA3JT.js +5 -0
  26. package/dist/chunk-X54D5JZG.js +11 -0
  27. package/dist/{chunk-O2OQCSBL.js → chunk-YHIYJ5OL.js} +105 -29
  28. package/dist/chunk-YHIYJ5OL.js.map +1 -0
  29. package/dist/{claude-WUJU5KIE.js → claude-4R6L6BWY.js} +4 -4
  30. package/dist/{claude-WUJU5KIE.js.map → claude-4R6L6BWY.js.map} +1 -1
  31. package/dist/claude-ZLVOLRUG.js +2 -0
  32. package/dist/cli.js +1 -213
  33. package/dist/clipboard-service-WVON5ZN4.js +25 -0
  34. package/dist/{codex-NYJWEPRQ.js → codex-IMOW5ZUZ.js} +4 -4
  35. package/dist/{codex-NYJWEPRQ.js.map → codex-IMOW5ZUZ.js.map} +1 -1
  36. package/dist/codex-YRSODLH4.js +2 -0
  37. package/dist/config-OOB7QEKM.js +2 -0
  38. package/dist/container-FJI7RN2L.js +4 -0
  39. package/dist/context-FXRERFSP.js +7 -0
  40. package/dist/cursor-2HILMNM3.js +2 -0
  41. package/dist/{cursor-3YHVD4NP.js → cursor-NHV7X3WG.js} +4 -4
  42. package/dist/{cursor-3YHVD4NP.js.map → cursor-NHV7X3WG.js.map} +1 -1
  43. package/dist/doctor-GKTV4YYD.js +2 -0
  44. package/dist/doctor-service-PB7YBH3F.js +2 -0
  45. package/dist/editor-7IFRWVTL.js +8 -0
  46. package/dist/goal-RNNZYMNR.js +8 -0
  47. package/dist/index.d.ts +26 -8
  48. package/dist/index.js +247 -75
  49. package/dist/index.js.map +1 -1
  50. package/dist/init-56QC5QVX.js +53 -0
  51. package/dist/logs-4ISTWUWV.js +12 -0
  52. package/dist/msg-4ELI7Q52.js +9 -0
  53. package/dist/opencode-3S4VDXRG.js +2 -0
  54. package/dist/{opencode-FAMPSA6X.js → opencode-ULT6DYCT.js} +6 -5
  55. package/dist/opencode-ULT6DYCT.js.map +1 -0
  56. package/dist/orchestrator-PM4BW7W5.js +13 -0
  57. package/dist/orchestrator-QFNYZ6AH.js +6 -0
  58. package/dist/{orchestrator-X2CWGFCL.js.map → orchestrator-QFNYZ6AH.js.map} +1 -1
  59. package/dist/org-WAK3CDPG.js +3 -0
  60. package/dist/process-manager-33H27MQF.js +2 -0
  61. package/dist/registry-BO2PPRNG.js +2 -0
  62. package/dist/run-NE5E4JPW.js +3 -0
  63. package/dist/shell-OBHIVC2H.js +2 -0
  64. package/dist/{shell-NJNW3O6K.js → shell-UXEJRK3D.js} +4 -4
  65. package/dist/{shell-NJNW3O6K.js.map → shell-UXEJRK3D.js.map} +1 -1
  66. package/dist/shop-picker-LE3SKFOX.js +5 -0
  67. package/dist/status-NYHZ7Q5G.js +2 -0
  68. package/dist/task-SZBYNAZP.js +20 -0
  69. package/dist/team-VCJSUDWX.js +4 -0
  70. package/dist/template-engine-42PKL5KD.js +2 -0
  71. package/dist/tui-4VRDSRVB.js +2 -0
  72. package/dist/update-FFKCOV63.js +2 -0
  73. package/dist/update-check-HGMBDYHL.js +2 -0
  74. package/dist/{workspace-manager-2SFPKPLZ.js → workspace-manager-ABXFBL2A.js} +3 -3
  75. package/dist/{workspace-manager-2SFPKPLZ.js.map → workspace-manager-ABXFBL2A.js.map} +1 -1
  76. package/dist/workspace-manager-Q6WWXSTR.js +3 -0
  77. package/package.json +1 -1
  78. package/dist/App-YQOT4LBE.js +0 -6727
  79. package/dist/agent-7ZJ3ZDJ7.js +0 -183
  80. package/dist/agent-shop-YN2BSLHM.js +0 -2
  81. package/dist/chunk-2C2TFQ7K.js +0 -136
  82. package/dist/chunk-45K2XID7.js +0 -29
  83. package/dist/chunk-4IFIOMCW.js +0 -86
  84. package/dist/chunk-7X2GI5OV.js +0 -181
  85. package/dist/chunk-C6XZ3FJT.js.map +0 -1
  86. package/dist/chunk-CHIP7O6V.js +0 -83
  87. package/dist/chunk-FRTKB575.js +0 -87
  88. package/dist/chunk-HXYAZGLP.js +0 -15
  89. package/dist/chunk-I3SMISEF.js +0 -29
  90. package/dist/chunk-INZ4O2RI.js.map +0 -1
  91. package/dist/chunk-ITLJKMTP.js +0 -297
  92. package/dist/chunk-K6DMQERQ.js +0 -89
  93. package/dist/chunk-MGGSRXWJ.js +0 -69
  94. package/dist/chunk-O2OQCSBL.js.map +0 -1
  95. package/dist/chunk-P6ATSXGL.js +0 -107
  96. package/dist/chunk-PNE6LQRF.js +0 -5
  97. package/dist/chunk-U2VDNUZL.js +0 -52
  98. package/dist/chunk-VXS2CJFH.js +0 -273
  99. package/dist/chunk-XDVMX2FO.js +0 -8
  100. package/dist/chunk-XDVMX2FO.js.map +0 -1
  101. package/dist/chunk-XJTJ2TJV.js +0 -221
  102. package/dist/claude-ZUEKJJ4X.js +0 -5
  103. package/dist/clipboard-service-RTDUUQQU.js +0 -200
  104. package/dist/codex-7IXXXG5U.js +0 -123
  105. package/dist/config-OTAVSMOD.js +0 -75
  106. package/dist/container-IZZVO4AH.js +0 -1596
  107. package/dist/context-OL4BVUV5.js +0 -83
  108. package/dist/cursor-622RBRHH.js +0 -97
  109. package/dist/doctor-SETNAS4S.js +0 -67
  110. package/dist/doctor-service-TPOMFAIG.js +0 -2
  111. package/dist/goal-C6YGSX5D.js +0 -143
  112. package/dist/init-SWAAXP5H.js +0 -199
  113. package/dist/logs-PHPYWQ6I.js +0 -207
  114. package/dist/msg-FUWWLEKM.js +0 -95
  115. package/dist/opencode-FAMPSA6X.js.map +0 -1
  116. package/dist/opencode-WOR53TSC.js +0 -98
  117. package/dist/orchestrator-O6MFMATT.js +0 -1448
  118. package/dist/orchestrator-X2CWGFCL.js +0 -5
  119. package/dist/org-JSMMBZHI.js +0 -249
  120. package/dist/process-manager-HUVNAPQV.js +0 -2
  121. package/dist/registry-PQWRVNF2.js +0 -2
  122. package/dist/run-N72G5V2H.js +0 -95
  123. package/dist/shell-DVFHHYAZ.js +0 -5
  124. package/dist/shop-picker-2HY67UWP.js +0 -79
  125. package/dist/status-RZWN2C6C.js +0 -56
  126. package/dist/task-XNYZHPCS.js +0 -221
  127. package/dist/team-PFLP4PPL.js +0 -97
  128. package/dist/template-engine-AWIS56BL.js +0 -3
  129. package/dist/tui-JW3DOOKH.js +0 -245
  130. package/dist/update-YLP7FPNY.js +0 -64
  131. package/dist/update-check-4YKLGBFB.js +0 -2
  132. package/dist/workspace-manager-ESPU7WOH.js +0 -215
@@ -1,83 +0,0 @@
1
- #!/usr/bin/env node
2
- import { spawn } from 'child_process';
3
-
4
- var ProcessManager = class {
5
- isAlive(pid) {
6
- try {
7
- process.kill(pid, 0);
8
- return true;
9
- } catch (err) {
10
- if (err.code === "EPERM") return true;
11
- return false;
12
- }
13
- }
14
- kill(pid, signal = "SIGTERM") {
15
- try {
16
- process.kill(-pid, signal);
17
- } catch {
18
- try {
19
- process.kill(pid, signal);
20
- } catch {
21
- }
22
- }
23
- }
24
- async killWithGrace(pid, graceMs = 1e4) {
25
- if (!this.isAlive(pid)) return;
26
- this.kill(pid, "SIGTERM");
27
- const deadline = Date.now() + graceMs;
28
- while (Date.now() < deadline) {
29
- if (!this.isAlive(pid)) return;
30
- await new Promise((r) => setTimeout(r, 200));
31
- }
32
- this.kill(pid, "SIGKILL");
33
- }
34
- spawn(command, args, options) {
35
- const proc = spawn(command, args, {
36
- stdio: ["ignore", "pipe", "pipe"],
37
- detached: true,
38
- // Create new process group so killWithGrace(-pid) kills all children
39
- ...options
40
- });
41
- if (!proc.pid) {
42
- throw new Error(`Failed to spawn process: ${command}`);
43
- }
44
- proc.unref();
45
- return { process: proc, pid: proc.pid };
46
- }
47
- };
48
- var MAX_LINE_LEN = 16384;
49
- function capLine(s) {
50
- return s.length > MAX_LINE_LEN ? s.slice(0, MAX_LINE_LEN) : s;
51
- }
52
- async function* readLines(stream) {
53
- const chunks = [];
54
- let totalLen = 0;
55
- for await (const chunk of stream) {
56
- const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf-8");
57
- if (buf.length === 0) continue;
58
- chunks.push(buf);
59
- totalLen += buf.length;
60
- const buffer = chunks.length === 1 ? chunks[0] : Buffer.concat(chunks, totalLen);
61
- chunks.length = 0;
62
- totalLen = 0;
63
- let offset = 0;
64
- let newlineIdx;
65
- while ((newlineIdx = buffer.indexOf(10, offset)) !== -1) {
66
- if (newlineIdx > offset) {
67
- yield capLine(buffer.toString("utf-8", offset, newlineIdx));
68
- }
69
- offset = newlineIdx + 1;
70
- }
71
- if (offset < buffer.length) {
72
- const remainder = buffer.subarray(offset);
73
- chunks.push(remainder);
74
- totalLen = remainder.length;
75
- }
76
- }
77
- if (totalLen > 0) {
78
- const final = chunks.length === 1 ? chunks[0] : Buffer.concat(chunks, totalLen);
79
- yield capLine(final.toString("utf-8"));
80
- }
81
- }
82
-
83
- export { ProcessManager, readLines };
@@ -1,87 +0,0 @@
1
- #!/usr/bin/env node
2
- import fs from 'fs/promises';
3
- import path from 'path';
4
- import os from 'os';
5
- import { execFile } from 'child_process';
6
-
7
- var PACKAGE_NAME = "@oxgeneral/orch";
8
- var CACHE_DIR = path.join(os.homedir(), ".orchestry");
9
- var CACHE_FILE = path.join(CACHE_DIR, "update-check.json");
10
- var CHECK_INTERVAL_MS = 4 * 60 * 60 * 1e3;
11
- var REVALIDATE_AFTER_MS = CHECK_INTERVAL_MS * 0.75;
12
- function compareSemver(a, b) {
13
- const pa = a.split(".").map(Number);
14
- const pb = b.split(".").map(Number);
15
- for (let i = 0; i < 3; i++) {
16
- const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
17
- if (diff !== 0) return diff > 0 ? 1 : -1;
18
- }
19
- return 0;
20
- }
21
- async function readCache() {
22
- try {
23
- const raw = await fs.readFile(CACHE_FILE, "utf-8");
24
- const data = JSON.parse(raw);
25
- if (Date.now() - data.checked_at < CHECK_INTERVAL_MS) return data;
26
- } catch {
27
- }
28
- return null;
29
- }
30
- async function writeCache(latest) {
31
- await fs.mkdir(CACHE_DIR, { recursive: true });
32
- const data = { latest, checked_at: Date.now() };
33
- const tmp = `${CACHE_FILE}.tmp.${process.pid}`;
34
- await fs.writeFile(tmp, JSON.stringify(data), "utf-8");
35
- await fs.rename(tmp, CACHE_FILE);
36
- }
37
- function fetchLatestVersion() {
38
- return new Promise((resolve) => {
39
- const child = execFile("npm", ["view", PACKAGE_NAME, "version", "--json"], { timeout: 5e3 }, (err, stdout) => {
40
- if (err) return resolve(null);
41
- try {
42
- resolve(JSON.parse(stdout.trim()));
43
- } catch {
44
- resolve(null);
45
- }
46
- });
47
- child.unref();
48
- });
49
- }
50
- function buildUpdateInfo(current, latest) {
51
- return { current, latest, updateAvailable: compareSemver(latest, current) > 0 };
52
- }
53
- async function checkForUpdateNow(currentVersion) {
54
- const latest = await fetchLatestVersion();
55
- if (!latest) return null;
56
- await writeCache(latest).catch(() => {
57
- });
58
- return buildUpdateInfo(currentVersion, latest);
59
- }
60
- async function checkForUpdateSWR(currentVersion) {
61
- try {
62
- const cached = await readCache();
63
- if (!cached) {
64
- checkForUpdateNow(currentVersion).catch(() => {
65
- });
66
- return null;
67
- }
68
- const age = Date.now() - cached.checked_at;
69
- if (age >= REVALIDATE_AFTER_MS) {
70
- checkForUpdateNow(currentVersion).catch(() => {
71
- });
72
- }
73
- return buildUpdateInfo(currentVersion, cached.latest);
74
- } catch {
75
- return null;
76
- }
77
- }
78
- function printUpdateNotification(info) {
79
- if (!info.updateAvailable) return;
80
- const msg = `
81
- Update available: ${info.current} \u2192 ${info.latest}
82
- Run: npm install -g ${PACKAGE_NAME}
83
- `;
84
- process.stderr.write(msg);
85
- }
86
-
87
- export { checkForUpdateNow, checkForUpdateSWR, printUpdateNotification };
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env node
2
- // src/domain/goal.ts
3
- var GOAL_STATUSES = ["active", "paused", "achieved", "abandoned"];
4
- var TERMINAL_GOAL_STATUSES = /* @__PURE__ */ new Set(["achieved", "abandoned"]);
5
- function isGoalTerminal(status) {
6
- return TERMINAL_GOAL_STATUSES.has(status);
7
- }
8
- var GOAL_STATUS_ORDER = {
9
- active: 0,
10
- paused: 1,
11
- achieved: 2,
12
- abandoned: 3
13
- };
14
-
15
- export { GOAL_STATUSES, GOAL_STATUS_ORDER, isGoalTerminal };
@@ -1,29 +0,0 @@
1
- #!/usr/bin/env node
2
- // src/domain/config.ts
3
- var DEFAULT_CONFIG = {
4
- project: {
5
- name: "my-project"
6
- },
7
- defaults: {
8
- agent: {
9
- adapter: "claude",
10
- approval_policy: "auto",
11
- max_turns: 50,
12
- timeout_ms: 36e5,
13
- stall_timeout_ms: 3e5,
14
- workspace_mode: "worktree"
15
- },
16
- task: {
17
- max_attempts: 3,
18
- priority: 3
19
- }
20
- },
21
- scheduling: {
22
- poll_interval_ms: 1e4,
23
- max_concurrent_agents: 6,
24
- retry_base_delay_ms: 1e4,
25
- retry_max_delay_ms: 3e5
26
- }
27
- };
28
-
29
- export { DEFAULT_CONFIG };
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/infrastructure/storage/fs-utils.ts","../src/infrastructure/storage/paths.ts"],"names":["path","lines"],"mappings":"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","file":"chunk-INZ4O2RI.js","sourcesContent":["/**\n * Low-level filesystem utilities.\n *\n * All file persistence goes through these functions.\n * atomicWrite guarantees no partial reads via temp → rename.\n */\n\nimport { randomBytes } from 'node:crypto';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport yaml from 'js-yaml';\n\n/**\n * Write file atomically: write to temp file, then rename.\n * Prevents corrupted reads on concurrent access.\n */\nexport async function atomicWrite(filePath: string, content: string): Promise<void> {\n const dir = path.dirname(filePath);\n await ensureDir(dir);\n\n const tmpPath = path.join(dir, `.${path.basename(filePath)}.${randomBytes(4).toString('hex')}.tmp`);\n\n try {\n await fs.writeFile(tmpPath, content, 'utf-8');\n await fs.rename(tmpPath, filePath);\n } catch (err) {\n // Clean up temp file on failure\n await fs.unlink(tmpPath).catch(() => {});\n throw err;\n }\n}\n\n/**\n * Read and parse a YAML file. Returns null if file does not exist.\n */\nexport async function readYaml<T>(filePath: string): Promise<T | null> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n return yaml.load(content) as T;\n } catch (err) {\n if (isENOENT(err)) return null;\n throw err;\n }\n}\n\n/**\n * Write data as YAML atomically.\n */\nexport async function writeYaml<T>(filePath: string, data: T): Promise<void> {\n const content = yaml.dump(data, {\n indent: 2,\n lineWidth: 120,\n noRefs: true,\n sortKeys: false,\n });\n await atomicWrite(filePath, content);\n}\n\n/**\n * Read and parse a JSON file. Returns null if file does not exist.\n */\nexport async function readJson<T>(filePath: string): Promise<T | null> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(content) as T;\n } catch (err) {\n if (isENOENT(err)) return null;\n throw err;\n }\n}\n\n/**\n * Write data as JSON atomically.\n */\nexport async function writeJson<T>(filePath: string, data: T): Promise<void> {\n const content = JSON.stringify(data, null, 2) + '\\n';\n await atomicWrite(filePath, content);\n}\n\n/**\n * POSIX PIPE_BUF — writes up to this size are guaranteed atomic with O_APPEND.\n * 4096 on Linux/macOS. We leave some room for encoding overhead.\n */\nconst PIPE_BUF = 4096;\n\n/**\n * Append a JSON record to a .jsonl file (newline-delimited JSON).\n *\n * Uses a file handle opened with 'a' (O_APPEND) to ensure atomic writes.\n * On POSIX, O_APPEND guarantees that each write() call appends atomically\n * when the data fits within PIPE_BUF (typically 4096 bytes), preventing\n * interleaving from concurrent writers.\n *\n * If the serialized line exceeds PIPE_BUF, the record's `data` field is\n * truncated so the entire line fits within the atomic-write limit.\n * This prevents interleaving corruption from concurrent writers.\n */\nexport async function appendJsonl(filePath: string, record: unknown): Promise<void> {\n const dir = path.dirname(filePath);\n await ensureDir(dir);\n let line = JSON.stringify(record) + '\\n';\n\n // If the line exceeds PIPE_BUF, truncate the `data` field to fit\n const byteLen = Buffer.byteLength(line, 'utf-8');\n if (byteLen > PIPE_BUF && record !== null && typeof record === 'object') {\n const obj = record as Record<string, unknown>;\n if (typeof obj.data === 'string' && obj.data.length > 0) {\n // Measure overhead without data to know how much room data gets\n const shell = JSON.stringify({ ...obj, data: '' }) + '\\n';\n const overhead = Buffer.byteLength(shell, 'utf-8');\n const budget = PIPE_BUF - overhead - 3; // 3 bytes for the '…' suffix (UTF-8 ellipsis)\n if (budget > 0) {\n // Slice to budget chars — for ASCII (most event data) this equals bytes.\n // For multi-byte chars the result may be slightly over PIPE_BUF,\n // which is acceptable on local filesystems (ext4/APFS hold inode lock).\n const truncated = obj.data.slice(0, budget);\n line = JSON.stringify({ ...obj, data: truncated + '…' }) + '\\n';\n }\n }\n }\n\n const fd = await fs.open(filePath, 'a');\n try {\n await fd.write(line, null, 'utf-8');\n } finally {\n await fd.close();\n }\n}\n\n/** Max file size for full readJsonl (50 MB). Larger files use tail read. */\nconst MAX_JSONL_READ_SIZE = 50 * 1024 * 1024;\n\n/**\n * Read all records from a .jsonl file.\n * Falls back to reading only the last 200 records if the file exceeds MAX_JSONL_READ_SIZE.\n */\nexport async function readJsonl<T>(filePath: string): Promise<T[]> {\n try {\n const stat = await fs.stat(filePath);\n if (stat.size > MAX_JSONL_READ_SIZE) {\n process.stderr.write(\n `[readJsonl] file too large (${(stat.size / 1024 / 1024).toFixed(1)} MB), reading tail only: ${filePath}\\n`,\n );\n return readJsonlTail<T>(filePath, 200);\n }\n return readAndParseJsonl<T>(filePath);\n } catch (err) {\n if (isENOENT(err)) return [];\n throw err;\n }\n}\n\n/**\n * Read the last N records from a .jsonl file.\n *\n * Reads the file in reverse chunks to avoid loading multi-MB files into memory.\n * Falls back to full read for small files (< 32KB).\n */\nexport async function readJsonlTail<T>(filePath: string, count: number): Promise<T[]> {\n try {\n const stat = await fs.stat(filePath);\n // For small files, read directly and slice (avoid mutual recursion with readJsonl)\n if (stat.size < 32768) {\n return (await readAndParseJsonl<T>(filePath)).slice(-count);\n }\n\n // Read from end in chunks to find enough lines\n // Use larger chunks for bigger files (tool_result events can be 8KB+ per line)\n const fd = await fs.open(filePath, 'r');\n try {\n const chunkSize = Math.min(stat.size, stat.size > 1_048_576 ? 131072 : 65536);\n let position = Math.max(0, stat.size - chunkSize);\n let earliestReadPosition = position;\n let tail = '';\n\n // Read up to 4 chunks from the end\n for (let attempt = 0; attempt < 4 && position >= 0; attempt++) {\n earliestReadPosition = position;\n const readSize = Math.min(chunkSize, stat.size - position);\n const buf = Buffer.alloc(readSize);\n await fd.read(buf, 0, readSize, position);\n tail = buf.toString('utf-8') + tail;\n\n const lines = tail.split('\\n').filter((l) => l.trim().length > 0);\n if (lines.length >= count + 1) {\n // +1 because first line might be partial\n return parseJsonlLines<T>(lines.slice(-count));\n }\n if (position === 0) break;\n position = Math.max(0, position - chunkSize);\n }\n\n // Parse whatever we got\n const lines = tail.split('\\n').filter((l) => l.trim().length > 0);\n // Skip first line if we didn't read from start (could be partial)\n const safeLines = earliestReadPosition > 0 ? lines.slice(1) : lines;\n return parseJsonlLines<T>(safeLines.slice(-count));\n } finally {\n await fd.close();\n }\n } catch (err) {\n if (isENOENT(err)) return [];\n throw err;\n }\n}\n\n/** Read a file and parse all JSONL records. */\nasync function readAndParseJsonl<T>(filePath: string): Promise<T[]> {\n const content = await fs.readFile(filePath, 'utf-8');\n const lines = content.split('\\n').filter((l) => l.trim().length > 0);\n return parseJsonlLines<T>(lines);\n}\n\n/**\n * Parse JSONL lines with error tolerance — corrupt lines are logged and skipped.\n */\nfunction parseJsonlLines<T>(lines: string[]): T[] {\n const results: T[] = [];\n for (const raw of lines) {\n const line = raw.trim();\n if (!line) continue;\n try {\n results.push(JSON.parse(line) as T);\n } catch {\n process.stderr.write(`[readJsonl] skipping corrupt line: ${line.slice(0, 200)}\\n`);\n }\n }\n return results;\n}\n\n/**\n * Ensure a directory exists, creating it recursively if needed.\n */\nexport async function ensureDir(dirPath: string): Promise<void> {\n await fs.mkdir(dirPath, { recursive: true });\n}\n\n/**\n * Check if a path exists.\n */\nexport async function pathExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * List files in a directory matching an optional extension filter.\n */\nexport async function listFiles(dirPath: string, ext?: string): Promise<string[]> {\n try {\n const entries = await fs.readdir(dirPath);\n if (ext) {\n return entries.filter((e) => e.endsWith(ext));\n }\n return entries;\n } catch (err) {\n if (isENOENT(err)) return [];\n throw err;\n }\n}\n\nfunction isENOENT(err: unknown): boolean {\n return err instanceof Error && 'code' in err && (err as NodeJS.ErrnoException).code === 'ENOENT';\n}\n","/**\n * Path resolution for .orchestry/ directory.\n *\n * All path construction goes through this module.\n * Validates initialization state and sanitizes identifiers.\n */\n\nimport path from 'node:path';\nimport { accessSync } from 'node:fs';\nimport { NotInitializedError } from '../../domain/errors.js';\nimport { pathExists } from './fs-utils.js';\n\nexport const ORCHESTRY_DIR = '.orchestry';\nconst ID_PATTERN = /^[A-Za-z0-9._-]+$/;\n\nexport class Paths {\n constructor(private readonly projectRoot: string) {}\n\n /** Root .orchestry/ directory */\n get root(): string {\n return path.join(this.projectRoot, ORCHESTRY_DIR);\n }\n\n get configPath(): string {\n return path.join(this.root, 'config.yml');\n }\n\n get statePath(): string {\n return path.join(this.root, 'state.json');\n }\n\n get lockPath(): string {\n return path.join(this.root, 'orchestry.lock');\n }\n\n get tasksDir(): string {\n return path.join(this.root, 'tasks');\n }\n\n get agentsDir(): string {\n return path.join(this.root, 'agents');\n }\n\n get runsDir(): string {\n return path.join(this.root, 'runs');\n }\n\n get templatesDir(): string {\n return path.join(this.root, 'templates');\n }\n\n get logsDir(): string {\n return path.join(this.root, 'logs');\n }\n\n get contextDir(): string {\n return path.join(this.root, 'context');\n }\n\n contextPath(key: string): string {\n return path.join(this.contextDir, `${sanitizeId(key)}.json`);\n }\n\n get messagesDir(): string {\n return path.join(this.root, 'messages');\n }\n\n messagePath(id: string): string {\n return path.join(this.messagesDir, `${sanitizeId(id)}.json`);\n }\n\n get goalsDir(): string {\n return path.join(this.root, 'goals');\n }\n\n goalPath(id: string): string {\n return path.join(this.goalsDir, `${sanitizeId(id)}.yml`);\n }\n\n get teamsDir(): string {\n return path.join(this.root, 'teams');\n }\n\n get attachmentsDir(): string {\n return path.join(this.root, 'attachments');\n }\n\n taskAttachmentsDir(taskId: string): string {\n return path.join(this.attachmentsDir, sanitizeId(taskId));\n }\n\n teamPath(id: string): string {\n return path.join(this.teamsDir, `${sanitizeId(id)}.yml`);\n }\n\n get gitignorePath(): string {\n return path.join(this.root, '.gitignore');\n }\n\n get workspaceExcludePath(): string {\n return path.join(this.root, 'workspace-exclude');\n }\n\n taskPath(id: string): string {\n return path.join(this.tasksDir, `${sanitizeId(id)}.yml`);\n }\n\n agentPath(id: string): string {\n return path.join(this.agentsDir, `${sanitizeId(id)}.yml`);\n }\n\n runPath(id: string): string {\n return path.join(this.runsDir, `${sanitizeId(id)}.json`);\n }\n\n runEventsPath(id: string): string {\n return path.join(this.runsDir, `${sanitizeId(id)}.jsonl`);\n }\n\n defaultTemplatePath(): string {\n return path.join(this.templatesDir, 'default.md');\n }\n\n async isInitialized(): Promise<boolean> {\n return pathExists(this.root);\n }\n\n async requireInit(): Promise<void> {\n if (!(await this.isInitialized())) {\n throw new NotInitializedError();\n }\n }\n}\n\n/**\n * Validate an identifier for use in file paths.\n * Only allows [A-Za-z0-9._-] characters.\n * Rejects identifiers containing forbidden characters (path separators, etc.)\n * to prevent path traversal attacks.\n */\nexport function sanitizeId(id: string): string {\n if (!ID_PATTERN.test(id)) {\n throw new Error(`Invalid identifier: \"${id}\"`);\n }\n return id;\n}\n\n/**\n * Validate that a workspace path is within the project root.\n * Prevents path traversal attacks.\n */\nexport function validateWorkspacePath(workspacePath: string, projectRoot: string): void {\n const resolved = path.resolve(workspacePath);\n const root = path.resolve(projectRoot);\n\n if (!resolved.startsWith(root + path.sep) && resolved !== root) {\n throw new Error(`Workspace path \"${workspacePath}\" is outside project root`);\n }\n}\n\n/**\n * Resolve project root by walking up from cwd looking for .orchestry/.\n * Returns cwd if not found (for init command).\n */\nexport function findProjectRoot(startDir: string = process.cwd()): string {\n let dir = path.resolve(startDir);\n const root = path.parse(dir).root;\n\n while (dir !== root) {\n try {\n accessSync(path.join(dir, '.orchestry'));\n return dir;\n } catch {\n // Not found, go up\n }\n dir = path.dirname(dir);\n }\n\n // Not found — return original dir (for init command)\n return startDir;\n}\n"]}
@@ -1,297 +0,0 @@
1
- #!/usr/bin/env node
2
- import { NotInitializedError } from './chunk-2C2TFQ7K.js';
3
- import { randomBytes } from 'crypto';
4
- import fs from 'fs/promises';
5
- import path2 from 'path';
6
- import yaml from 'js-yaml';
7
- import { accessSync } from 'fs';
8
-
9
- async function atomicWrite(filePath, content) {
10
- const dir = path2.dirname(filePath);
11
- await ensureDir(dir);
12
- const tmpPath = path2.join(dir, `.${path2.basename(filePath)}.${randomBytes(4).toString("hex")}.tmp`);
13
- try {
14
- await fs.writeFile(tmpPath, content, "utf-8");
15
- await fs.rename(tmpPath, filePath);
16
- } catch (err) {
17
- await fs.unlink(tmpPath).catch(() => {
18
- });
19
- throw err;
20
- }
21
- }
22
- async function readYaml(filePath) {
23
- try {
24
- const content = await fs.readFile(filePath, "utf-8");
25
- return yaml.load(content);
26
- } catch (err) {
27
- if (isENOENT(err)) return null;
28
- throw err;
29
- }
30
- }
31
- async function writeYaml(filePath, data) {
32
- const content = yaml.dump(data, {
33
- indent: 2,
34
- lineWidth: 120,
35
- noRefs: true,
36
- sortKeys: false
37
- });
38
- await atomicWrite(filePath, content);
39
- }
40
- async function readJson(filePath) {
41
- try {
42
- const content = await fs.readFile(filePath, "utf-8");
43
- return JSON.parse(content);
44
- } catch (err) {
45
- if (isENOENT(err)) return null;
46
- throw err;
47
- }
48
- }
49
- async function writeJson(filePath, data) {
50
- const content = JSON.stringify(data, null, 2) + "\n";
51
- await atomicWrite(filePath, content);
52
- }
53
- var PIPE_BUF = 4096;
54
- async function appendJsonl(filePath, record) {
55
- const dir = path2.dirname(filePath);
56
- await ensureDir(dir);
57
- let line = JSON.stringify(record) + "\n";
58
- const byteLen = Buffer.byteLength(line, "utf-8");
59
- if (byteLen > PIPE_BUF && record !== null && typeof record === "object") {
60
- const obj = record;
61
- if (typeof obj.data === "string" && obj.data.length > 0) {
62
- const shell = JSON.stringify({ ...obj, data: "" }) + "\n";
63
- const overhead = Buffer.byteLength(shell, "utf-8");
64
- const budget = PIPE_BUF - overhead - 3;
65
- if (budget > 0) {
66
- const truncated = obj.data.slice(0, budget);
67
- line = JSON.stringify({ ...obj, data: truncated + "\u2026" }) + "\n";
68
- }
69
- }
70
- }
71
- const fd = await fs.open(filePath, "a");
72
- try {
73
- await fd.write(line, null, "utf-8");
74
- } finally {
75
- await fd.close();
76
- }
77
- }
78
- var MAX_JSONL_READ_SIZE = 50 * 1024 * 1024;
79
- async function readJsonl(filePath) {
80
- try {
81
- const stat = await fs.stat(filePath);
82
- if (stat.size > MAX_JSONL_READ_SIZE) {
83
- process.stderr.write(
84
- `[readJsonl] file too large (${(stat.size / 1024 / 1024).toFixed(1)} MB), reading tail only: ${filePath}
85
- `
86
- );
87
- return readJsonlTail(filePath, 200);
88
- }
89
- return readAndParseJsonl(filePath);
90
- } catch (err) {
91
- if (isENOENT(err)) return [];
92
- throw err;
93
- }
94
- }
95
- async function readJsonlTail(filePath, count) {
96
- try {
97
- const stat = await fs.stat(filePath);
98
- if (stat.size < 32768) {
99
- return (await readAndParseJsonl(filePath)).slice(-count);
100
- }
101
- const fd = await fs.open(filePath, "r");
102
- try {
103
- const chunkSize = Math.min(stat.size, stat.size > 1048576 ? 131072 : 65536);
104
- let position = Math.max(0, stat.size - chunkSize);
105
- let earliestReadPosition = position;
106
- let tail = "";
107
- for (let attempt = 0; attempt < 4 && position >= 0; attempt++) {
108
- earliestReadPosition = position;
109
- const readSize = Math.min(chunkSize, stat.size - position);
110
- const buf = Buffer.alloc(readSize);
111
- await fd.read(buf, 0, readSize, position);
112
- tail = buf.toString("utf-8") + tail;
113
- const lines2 = tail.split("\n").filter((l) => l.trim().length > 0);
114
- if (lines2.length >= count + 1) {
115
- return parseJsonlLines(lines2.slice(-count));
116
- }
117
- if (position === 0) break;
118
- position = Math.max(0, position - chunkSize);
119
- }
120
- const lines = tail.split("\n").filter((l) => l.trim().length > 0);
121
- const safeLines = earliestReadPosition > 0 ? lines.slice(1) : lines;
122
- return parseJsonlLines(safeLines.slice(-count));
123
- } finally {
124
- await fd.close();
125
- }
126
- } catch (err) {
127
- if (isENOENT(err)) return [];
128
- throw err;
129
- }
130
- }
131
- async function readAndParseJsonl(filePath) {
132
- const content = await fs.readFile(filePath, "utf-8");
133
- const lines = content.split("\n").filter((l) => l.trim().length > 0);
134
- return parseJsonlLines(lines);
135
- }
136
- function parseJsonlLines(lines) {
137
- const results = [];
138
- for (const raw of lines) {
139
- const line = raw.trim();
140
- if (!line) continue;
141
- try {
142
- results.push(JSON.parse(line));
143
- } catch {
144
- process.stderr.write(`[readJsonl] skipping corrupt line: ${line.slice(0, 200)}
145
- `);
146
- }
147
- }
148
- return results;
149
- }
150
- async function ensureDir(dirPath) {
151
- await fs.mkdir(dirPath, { recursive: true });
152
- }
153
- async function pathExists(filePath) {
154
- try {
155
- await fs.access(filePath);
156
- return true;
157
- } catch {
158
- return false;
159
- }
160
- }
161
- async function listFiles(dirPath, ext) {
162
- try {
163
- const entries = await fs.readdir(dirPath);
164
- if (ext) {
165
- return entries.filter((e) => e.endsWith(ext));
166
- }
167
- return entries;
168
- } catch (err) {
169
- if (isENOENT(err)) return [];
170
- throw err;
171
- }
172
- }
173
- function isENOENT(err) {
174
- return err instanceof Error && "code" in err && err.code === "ENOENT";
175
- }
176
- var ORCHESTRY_DIR = ".orchestry";
177
- var ID_PATTERN = /^[A-Za-z0-9._-]+$/;
178
- var Paths = class {
179
- constructor(projectRoot) {
180
- this.projectRoot = projectRoot;
181
- }
182
- /** Root .orchestry/ directory */
183
- get root() {
184
- return path2.join(this.projectRoot, ORCHESTRY_DIR);
185
- }
186
- get configPath() {
187
- return path2.join(this.root, "config.yml");
188
- }
189
- get statePath() {
190
- return path2.join(this.root, "state.json");
191
- }
192
- get lockPath() {
193
- return path2.join(this.root, "orchestry.lock");
194
- }
195
- get tasksDir() {
196
- return path2.join(this.root, "tasks");
197
- }
198
- get agentsDir() {
199
- return path2.join(this.root, "agents");
200
- }
201
- get runsDir() {
202
- return path2.join(this.root, "runs");
203
- }
204
- get templatesDir() {
205
- return path2.join(this.root, "templates");
206
- }
207
- get logsDir() {
208
- return path2.join(this.root, "logs");
209
- }
210
- get contextDir() {
211
- return path2.join(this.root, "context");
212
- }
213
- contextPath(key) {
214
- return path2.join(this.contextDir, `${sanitizeId(key)}.json`);
215
- }
216
- get messagesDir() {
217
- return path2.join(this.root, "messages");
218
- }
219
- messagePath(id) {
220
- return path2.join(this.messagesDir, `${sanitizeId(id)}.json`);
221
- }
222
- get goalsDir() {
223
- return path2.join(this.root, "goals");
224
- }
225
- goalPath(id) {
226
- return path2.join(this.goalsDir, `${sanitizeId(id)}.yml`);
227
- }
228
- get teamsDir() {
229
- return path2.join(this.root, "teams");
230
- }
231
- get attachmentsDir() {
232
- return path2.join(this.root, "attachments");
233
- }
234
- taskAttachmentsDir(taskId) {
235
- return path2.join(this.attachmentsDir, sanitizeId(taskId));
236
- }
237
- teamPath(id) {
238
- return path2.join(this.teamsDir, `${sanitizeId(id)}.yml`);
239
- }
240
- get gitignorePath() {
241
- return path2.join(this.root, ".gitignore");
242
- }
243
- get workspaceExcludePath() {
244
- return path2.join(this.root, "workspace-exclude");
245
- }
246
- taskPath(id) {
247
- return path2.join(this.tasksDir, `${sanitizeId(id)}.yml`);
248
- }
249
- agentPath(id) {
250
- return path2.join(this.agentsDir, `${sanitizeId(id)}.yml`);
251
- }
252
- runPath(id) {
253
- return path2.join(this.runsDir, `${sanitizeId(id)}.json`);
254
- }
255
- runEventsPath(id) {
256
- return path2.join(this.runsDir, `${sanitizeId(id)}.jsonl`);
257
- }
258
- defaultTemplatePath() {
259
- return path2.join(this.templatesDir, "default.md");
260
- }
261
- async isInitialized() {
262
- return pathExists(this.root);
263
- }
264
- async requireInit() {
265
- if (!await this.isInitialized()) {
266
- throw new NotInitializedError();
267
- }
268
- }
269
- };
270
- function sanitizeId(id) {
271
- if (!ID_PATTERN.test(id)) {
272
- throw new Error(`Invalid identifier: "${id}"`);
273
- }
274
- return id;
275
- }
276
- function validateWorkspacePath(workspacePath, projectRoot) {
277
- const resolved = path2.resolve(workspacePath);
278
- const root = path2.resolve(projectRoot);
279
- if (!resolved.startsWith(root + path2.sep) && resolved !== root) {
280
- throw new Error(`Workspace path "${workspacePath}" is outside project root`);
281
- }
282
- }
283
- function findProjectRoot(startDir = process.cwd()) {
284
- let dir = path2.resolve(startDir);
285
- const root = path2.parse(dir).root;
286
- while (dir !== root) {
287
- try {
288
- accessSync(path2.join(dir, ".orchestry"));
289
- return dir;
290
- } catch {
291
- }
292
- dir = path2.dirname(dir);
293
- }
294
- return startDir;
295
- }
296
-
297
- export { ORCHESTRY_DIR, Paths, appendJsonl, atomicWrite, ensureDir, findProjectRoot, listFiles, pathExists, readJson, readJsonl, readJsonlTail, readYaml, sanitizeId, validateWorkspacePath, writeJson, writeYaml };
@@ -1,89 +0,0 @@
1
- #!/usr/bin/env node
2
- import { execFile } from 'child_process';
3
- import { promisify } from 'util';
4
- import fs from 'fs/promises';
5
- import path from 'path';
6
-
7
- var execFileAsync = promisify(execFile);
8
- var DoctorService = class {
9
- constructor(adapterRegistry, processManager, projectRoot) {
10
- this.adapterRegistry = adapterRegistry;
11
- this.processManager = processManager;
12
- this.cwd = projectRoot ?? process.cwd();
13
- }
14
- cwd;
15
- async runAll() {
16
- const checks = [];
17
- const adapters = this.adapterRegistry.list();
18
- let adaptersReady = 0;
19
- for (const adapter of adapters) {
20
- const result = await adapter.test();
21
- if (result.ok) {
22
- adaptersReady++;
23
- checks.push({
24
- name: adapter.kind,
25
- status: "ok",
26
- detail: result.version
27
- });
28
- } else {
29
- checks.push({
30
- name: adapter.kind,
31
- status: "fail",
32
- detail: result.error
33
- });
34
- }
35
- }
36
- checks.push(await this.checkCommand("git", ["--version"], "git"));
37
- checks.push(await this.checkGitRepo());
38
- checks.push(await this.checkGitignore());
39
- checks.push(await this.checkCommand("node", ["--version"], "node"));
40
- return {
41
- checks,
42
- adaptersReady,
43
- adaptersTotal: adapters.length
44
- };
45
- }
46
- async checkCommand(command, args, name) {
47
- try {
48
- const { stdout } = await execFileAsync(command, args);
49
- return { name, status: "ok", detail: stdout.trim() };
50
- } catch {
51
- return { name, status: "fail", detail: `${command}: command not found` };
52
- }
53
- }
54
- async checkGitignore() {
55
- const gitignorePath = path.join(this.cwd, ".gitignore");
56
- try {
57
- const content = await fs.readFile(gitignorePath, "utf-8");
58
- const hasEntry = content.split("\n").some((line) => line.trim() === ".orchestry");
59
- if (hasEntry) {
60
- return { name: ".gitignore", status: "ok", detail: ".orchestry is excluded" };
61
- }
62
- return {
63
- name: ".gitignore",
64
- status: "fail",
65
- detail: ".orchestry not in .gitignore \u2014 worktrees will copy state recursively. Run: orch init"
66
- };
67
- } catch {
68
- return {
69
- name: ".gitignore",
70
- status: "fail",
71
- detail: "no .gitignore found \u2014 .orchestry may be committed to git. Run: orch init"
72
- };
73
- }
74
- }
75
- async checkGitRepo() {
76
- try {
77
- await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], { cwd: this.cwd });
78
- return { name: "git repo", status: "ok", detail: "git repository detected" };
79
- } catch {
80
- return {
81
- name: "git repo",
82
- status: "fail",
83
- detail: "not a git repository \u2014 worktree/isolated modes will fail. Run: git init"
84
- };
85
- }
86
- }
87
- };
88
-
89
- export { DoctorService };