@moreih29/nexus-core 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/README.md +48 -63
  2. package/assets/agents/architect/body.ko.md +177 -0
  3. package/{agents → assets/agents}/architect/body.md +16 -0
  4. package/assets/agents/designer/body.ko.md +125 -0
  5. package/{agents → assets/agents}/designer/body.md +16 -0
  6. package/assets/agents/engineer/body.ko.md +106 -0
  7. package/{agents → assets/agents}/engineer/body.md +14 -0
  8. package/assets/agents/lead/body.ko.md +70 -0
  9. package/assets/agents/lead/body.md +70 -0
  10. package/assets/agents/postdoc/body.ko.md +122 -0
  11. package/{agents → assets/agents}/postdoc/body.md +16 -0
  12. package/assets/agents/researcher/body.ko.md +137 -0
  13. package/{agents → assets/agents}/researcher/body.md +15 -0
  14. package/assets/agents/reviewer/body.ko.md +138 -0
  15. package/{agents → assets/agents}/reviewer/body.md +15 -0
  16. package/assets/agents/strategist/body.ko.md +116 -0
  17. package/{agents → assets/agents}/strategist/body.md +16 -0
  18. package/assets/agents/tester/body.ko.md +195 -0
  19. package/{agents → assets/agents}/tester/body.md +15 -0
  20. package/assets/agents/writer/body.ko.md +122 -0
  21. package/{agents → assets/agents}/writer/body.md +14 -0
  22. package/assets/capability-matrix.yml +198 -0
  23. package/assets/hooks/agent-bootstrap/handler.test.ts +368 -0
  24. package/assets/hooks/agent-bootstrap/handler.ts +119 -0
  25. package/assets/hooks/agent-bootstrap/meta.yml +10 -0
  26. package/assets/hooks/agent-finalize/handler.test.ts +368 -0
  27. package/assets/hooks/agent-finalize/handler.ts +76 -0
  28. package/assets/hooks/agent-finalize/meta.yml +10 -0
  29. package/assets/hooks/capability-matrix.yml +313 -0
  30. package/assets/hooks/post-tool-telemetry/handler.test.ts +302 -0
  31. package/assets/hooks/post-tool-telemetry/handler.ts +49 -0
  32. package/assets/hooks/post-tool-telemetry/meta.yml +11 -0
  33. package/assets/hooks/prompt-router/handler.test.ts +801 -0
  34. package/assets/hooks/prompt-router/handler.ts +261 -0
  35. package/assets/hooks/prompt-router/meta.yml +11 -0
  36. package/assets/hooks/session-init/handler.test.ts +274 -0
  37. package/assets/hooks/session-init/handler.ts +30 -0
  38. package/assets/hooks/session-init/meta.yml +9 -0
  39. package/assets/lsp-servers.json +55 -0
  40. package/assets/schema/lsp-servers.schema.json +67 -0
  41. package/assets/skills/nx-init/body.ko.md +197 -0
  42. package/{skills → assets/skills}/nx-init/body.md +11 -0
  43. package/assets/skills/nx-plan/body.ko.md +361 -0
  44. package/{skills → assets/skills}/nx-plan/body.md +13 -0
  45. package/assets/skills/nx-run/body.ko.md +161 -0
  46. package/{skills → assets/skills}/nx-run/body.md +11 -0
  47. package/assets/skills/nx-sync/body.ko.md +92 -0
  48. package/{skills → assets/skills}/nx-sync/body.md +10 -0
  49. package/assets/tools/tool-name-map.yml +353 -0
  50. package/dist/hooks/opencode-mount.d.ts +35 -0
  51. package/dist/hooks/opencode-mount.d.ts.map +1 -0
  52. package/dist/hooks/opencode-mount.js +332 -0
  53. package/dist/hooks/opencode-mount.js.map +1 -0
  54. package/dist/hooks/runtime.d.ts +37 -0
  55. package/dist/hooks/runtime.d.ts.map +1 -0
  56. package/dist/hooks/runtime.js +274 -0
  57. package/dist/hooks/runtime.js.map +1 -0
  58. package/dist/hooks/types.d.ts +196 -0
  59. package/dist/hooks/types.d.ts.map +1 -0
  60. package/dist/hooks/types.js +85 -0
  61. package/dist/hooks/types.js.map +1 -0
  62. package/dist/lsp/cache.d.ts +9 -0
  63. package/dist/lsp/cache.d.ts.map +1 -0
  64. package/dist/lsp/cache.js +216 -0
  65. package/dist/lsp/cache.js.map +1 -0
  66. package/dist/lsp/client.d.ts +24 -0
  67. package/dist/lsp/client.d.ts.map +1 -0
  68. package/dist/lsp/client.js +166 -0
  69. package/dist/lsp/client.js.map +1 -0
  70. package/dist/lsp/detect.d.ts +77 -0
  71. package/dist/lsp/detect.d.ts.map +1 -0
  72. package/dist/lsp/detect.js +116 -0
  73. package/dist/lsp/detect.js.map +1 -0
  74. package/dist/mcp/server.d.ts +5 -0
  75. package/dist/mcp/server.d.ts.map +1 -0
  76. package/dist/mcp/server.js +34 -0
  77. package/dist/mcp/server.js.map +1 -0
  78. package/dist/mcp/tools/artifact.d.ts +4 -0
  79. package/dist/mcp/tools/artifact.d.ts.map +1 -0
  80. package/dist/mcp/tools/artifact.js +36 -0
  81. package/dist/mcp/tools/artifact.js.map +1 -0
  82. package/dist/mcp/tools/history.d.ts +3 -0
  83. package/dist/mcp/tools/history.d.ts.map +1 -0
  84. package/dist/mcp/tools/history.js +29 -0
  85. package/dist/mcp/tools/history.js.map +1 -0
  86. package/dist/mcp/tools/lsp.d.ts +13 -0
  87. package/dist/mcp/tools/lsp.d.ts.map +1 -0
  88. package/dist/mcp/tools/lsp.js +225 -0
  89. package/dist/mcp/tools/lsp.js.map +1 -0
  90. package/dist/mcp/tools/plan.d.ts +3 -0
  91. package/dist/mcp/tools/plan.d.ts.map +1 -0
  92. package/dist/mcp/tools/plan.js +317 -0
  93. package/dist/mcp/tools/plan.js.map +1 -0
  94. package/dist/mcp/tools/task.d.ts +3 -0
  95. package/dist/mcp/tools/task.d.ts.map +1 -0
  96. package/dist/mcp/tools/task.js +252 -0
  97. package/dist/mcp/tools/task.js.map +1 -0
  98. package/dist/shared/invocations.d.ts +74 -0
  99. package/dist/shared/invocations.d.ts.map +1 -0
  100. package/dist/shared/invocations.js +247 -0
  101. package/dist/shared/invocations.js.map +1 -0
  102. package/dist/shared/json-store.d.ts +37 -0
  103. package/dist/shared/json-store.d.ts.map +1 -0
  104. package/dist/shared/json-store.js +163 -0
  105. package/dist/shared/json-store.js.map +1 -0
  106. package/dist/shared/mcp-utils.d.ts +3 -0
  107. package/dist/shared/mcp-utils.d.ts.map +1 -0
  108. package/dist/shared/mcp-utils.js +6 -0
  109. package/dist/shared/mcp-utils.js.map +1 -0
  110. package/dist/shared/paths.d.ts +21 -0
  111. package/dist/shared/paths.d.ts.map +1 -0
  112. package/dist/shared/paths.js +81 -0
  113. package/dist/shared/paths.js.map +1 -0
  114. package/dist/shared/tool-log.d.ts +8 -0
  115. package/dist/shared/tool-log.d.ts.map +1 -0
  116. package/dist/shared/tool-log.js +22 -0
  117. package/dist/shared/tool-log.js.map +1 -0
  118. package/dist/types/state.d.ts +862 -0
  119. package/dist/types/state.d.ts.map +1 -0
  120. package/dist/types/state.js +66 -0
  121. package/dist/types/state.js.map +1 -0
  122. package/docs/consuming/codex-lead-merge.md +106 -0
  123. package/docs/plugin-guide.md +360 -0
  124. package/docs/plugin-template/claude/.github/workflows/build.yml +60 -0
  125. package/docs/plugin-template/claude/README.md +110 -0
  126. package/docs/plugin-template/claude/package.json +16 -0
  127. package/docs/plugin-template/codex/.github/workflows/build.yml +51 -0
  128. package/docs/plugin-template/codex/README.md +147 -0
  129. package/docs/plugin-template/codex/package.json +17 -0
  130. package/docs/plugin-template/opencode/.github/workflows/build.yml +61 -0
  131. package/docs/plugin-template/opencode/README.md +121 -0
  132. package/docs/plugin-template/opencode/package.json +25 -0
  133. package/package.json +21 -21
  134. package/scripts/build-agents.test.ts +1279 -0
  135. package/scripts/build-agents.ts +978 -0
  136. package/scripts/build-hooks.test.ts +1385 -0
  137. package/scripts/build-hooks.ts +584 -0
  138. package/scripts/cli.test.ts +367 -0
  139. package/scripts/cli.ts +547 -0
  140. package/agents/architect/meta.yml +0 -13
  141. package/agents/designer/meta.yml +0 -13
  142. package/agents/engineer/meta.yml +0 -11
  143. package/agents/postdoc/meta.yml +0 -13
  144. package/agents/researcher/meta.yml +0 -12
  145. package/agents/reviewer/meta.yml +0 -12
  146. package/agents/strategist/meta.yml +0 -13
  147. package/agents/tester/meta.yml +0 -12
  148. package/agents/writer/meta.yml +0 -11
  149. package/conformance/README.md +0 -311
  150. package/conformance/examples/plan.extension.schema.example.json +0 -25
  151. package/conformance/lifecycle/README.md +0 -48
  152. package/conformance/lifecycle/agent-complete.json +0 -44
  153. package/conformance/lifecycle/agent-resume.json +0 -43
  154. package/conformance/lifecycle/agent-spawn.json +0 -36
  155. package/conformance/lifecycle/memory-access-record.json +0 -27
  156. package/conformance/lifecycle/session-end.json +0 -48
  157. package/conformance/scenarios/full-plan-cycle.json +0 -147
  158. package/conformance/scenarios/task-deps-ordering.json +0 -95
  159. package/conformance/schema/fixture.schema.json +0 -354
  160. package/conformance/state-schemas/agent-tracker.schema.json +0 -63
  161. package/conformance/state-schemas/history.schema.json +0 -134
  162. package/conformance/state-schemas/memory-access.schema.json +0 -36
  163. package/conformance/state-schemas/plan.schema.json +0 -77
  164. package/conformance/state-schemas/tasks.schema.json +0 -98
  165. package/conformance/tools/artifact-write.json +0 -97
  166. package/conformance/tools/context.json +0 -172
  167. package/conformance/tools/history-search.json +0 -219
  168. package/conformance/tools/plan-decide.json +0 -139
  169. package/conformance/tools/plan-start.json +0 -81
  170. package/conformance/tools/plan-status.json +0 -127
  171. package/conformance/tools/plan-update.json +0 -341
  172. package/conformance/tools/task-add.json +0 -156
  173. package/conformance/tools/task-close.json +0 -161
  174. package/conformance/tools/task-list.json +0 -177
  175. package/conformance/tools/task-update.json +0 -167
  176. package/docs/behavioral-contracts.md +0 -145
  177. package/docs/consumer-implementation-guide.md +0 -852
  178. package/docs/memory-lifecycle-contract.md +0 -119
  179. package/docs/nexus-layout.md +0 -224
  180. package/docs/nexus-outputs-contract.md +0 -344
  181. package/docs/nexus-state-overview.md +0 -170
  182. package/docs/nexus-tools-contract.md +0 -438
  183. package/manifest.json +0 -449
  184. package/schema/README.md +0 -69
  185. package/schema/agent.schema.json +0 -23
  186. package/schema/common.schema.json +0 -17
  187. package/schema/manifest.schema.json +0 -78
  188. package/schema/memory-policy.schema.json +0 -98
  189. package/schema/skill.schema.json +0 -54
  190. package/schema/task-exceptions.schema.json +0 -40
  191. package/schema/vocabulary.schema.json +0 -167
  192. package/scripts/.gitkeep +0 -0
  193. package/scripts/conformance-coverage.ts +0 -466
  194. package/scripts/import-from-claude-nexus.ts +0 -403
  195. package/scripts/lib/frontmatter.ts +0 -71
  196. package/scripts/lib/lint.ts +0 -348
  197. package/scripts/lib/structure.ts +0 -159
  198. package/scripts/lib/validate.ts +0 -794
  199. package/scripts/validate.ts +0 -90
  200. package/skills/nx-init/meta.yml +0 -8
  201. package/skills/nx-plan/meta.yml +0 -10
  202. package/skills/nx-run/meta.yml +0 -9
  203. package/skills/nx-sync/meta.yml +0 -7
  204. package/vocabulary/capabilities.yml +0 -65
  205. package/vocabulary/categories.yml +0 -11
  206. package/vocabulary/invocations.yml +0 -147
  207. package/vocabulary/memory_policy.yml +0 -88
  208. package/vocabulary/resume-tiers.yml +0 -11
  209. package/vocabulary/tags.yml +0 -60
  210. package/vocabulary/task-exceptions.yml +0 -29
@@ -0,0 +1,163 @@
1
+ import fs from "node:fs/promises";
2
+ import { constants as fsConstants, appendFileSync, mkdirSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { randomUUID } from "node:crypto";
5
+ // ---------------------------------------------------------------------------
6
+ // In-process mutex (serialises concurrent calls within the same process)
7
+ // ---------------------------------------------------------------------------
8
+ const inProcessQueues = new Map();
9
+ async function runWithInProcessLock(filePath, action) {
10
+ const previous = inProcessQueues.get(filePath) ?? Promise.resolve();
11
+ let release = () => { };
12
+ const gate = new Promise((resolve) => {
13
+ release = resolve;
14
+ });
15
+ // The entry in the map is the combined promise so the next waiter queues behind both
16
+ const entry = previous.then(() => gate);
17
+ inProcessQueues.set(filePath, entry);
18
+ await previous;
19
+ try {
20
+ return await action();
21
+ }
22
+ finally {
23
+ release();
24
+ entry.finally(() => {
25
+ if (inProcessQueues.get(filePath) === entry) {
26
+ inProcessQueues.delete(filePath);
27
+ }
28
+ });
29
+ }
30
+ }
31
+ // ---------------------------------------------------------------------------
32
+ // Cross-process file-system lock (.lock file, O_EXCL)
33
+ // ---------------------------------------------------------------------------
34
+ const LOCK_RETRY_INTERVAL_MS = 100;
35
+ const LOCK_MAX_RETRIES = 50; // 5 seconds total
36
+ const LOCK_STALE_MS = 30_000; // 30 seconds
37
+ function lockPath(filePath) {
38
+ return `${filePath}.lock`;
39
+ }
40
+ async function acquireFsLock(filePath) {
41
+ const lp = lockPath(filePath);
42
+ for (let attempt = 0; attempt <= LOCK_MAX_RETRIES; attempt++) {
43
+ try {
44
+ // O_EXCL ensures atomic creation — only one process wins
45
+ const fd = await fs.open(lp, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL);
46
+ await fd.close();
47
+ return;
48
+ }
49
+ catch (err) {
50
+ const e = err;
51
+ if (e.code !== "EEXIST")
52
+ throw err;
53
+ // Lock file exists — check if it is stale
54
+ try {
55
+ const stat = await fs.stat(lp);
56
+ const ageMs = Date.now() - stat.mtimeMs;
57
+ if (ageMs > LOCK_STALE_MS) {
58
+ // Stale lock — remove and retry immediately
59
+ await fs.unlink(lp).catch(() => undefined);
60
+ continue;
61
+ }
62
+ }
63
+ catch {
64
+ // stat failed (lock vanished between check and here) — retry
65
+ continue;
66
+ }
67
+ if (attempt === LOCK_MAX_RETRIES) {
68
+ throw new Error(`Failed to acquire lock for "${filePath}" after ${LOCK_MAX_RETRIES} retries`);
69
+ }
70
+ await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_INTERVAL_MS));
71
+ }
72
+ }
73
+ }
74
+ async function releaseFsLock(filePath) {
75
+ await fs.unlink(lockPath(filePath)).catch(() => undefined);
76
+ }
77
+ // ---------------------------------------------------------------------------
78
+ // Public API
79
+ // ---------------------------------------------------------------------------
80
+ /**
81
+ * Read a JSON file, returning `defaultValue` when the file does not exist or
82
+ * its content cannot be parsed.
83
+ */
84
+ export async function readJsonFile(filePath, defaultValue) {
85
+ let raw;
86
+ try {
87
+ raw = await fs.readFile(filePath, "utf8");
88
+ }
89
+ catch (err) {
90
+ const e = err;
91
+ if (e.code === "ENOENT")
92
+ return defaultValue;
93
+ throw err;
94
+ }
95
+ try {
96
+ return JSON.parse(raw);
97
+ }
98
+ catch {
99
+ return defaultValue;
100
+ }
101
+ }
102
+ /**
103
+ * Atomically write a JSON file.
104
+ * Writes to a unique temp file then renames to the target path.
105
+ * Parent directories are created automatically.
106
+ */
107
+ export async function writeJsonFile(filePath, data) {
108
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
109
+ const tmpPath = `${filePath}.tmp.${process.pid}.${Date.now()}.${randomUUID()}`;
110
+ await fs.writeFile(tmpPath, JSON.stringify(data, null, 2) + "\n", "utf8");
111
+ await fs.rename(tmpPath, filePath);
112
+ }
113
+ /**
114
+ * Read-modify-write a JSON file under a two-layer lock.
115
+ *
116
+ * Layer 1 — in-process promise queue: serialises concurrent calls within the
117
+ * same Node/Bun process with zero overhead and no retry cost.
118
+ *
119
+ * Layer 2 — cross-process `.lock` file (O_EXCL): prevents data races between
120
+ * separate processes. Retries every 100 ms for up to 50 attempts (5 s total).
121
+ * Stale locks (mtime > 30 s) are forcibly removed before retry.
122
+ *
123
+ * The lock is always released even when `updater` throws.
124
+ */
125
+ export async function updateJsonFileLocked(filePath, defaultValue, updater) {
126
+ return runWithInProcessLock(filePath, async () => {
127
+ await acquireFsLock(filePath);
128
+ try {
129
+ const current = await readJsonFile(filePath, defaultValue);
130
+ const next = await updater(current);
131
+ await writeJsonFile(filePath, next);
132
+ return next;
133
+ }
134
+ finally {
135
+ await releaseFsLock(filePath);
136
+ }
137
+ });
138
+ }
139
+ // ---------------------------------------------------------------------------
140
+ // Append-only JSONL helper
141
+ // ---------------------------------------------------------------------------
142
+ const APPEND_SIZE_WARN_THRESHOLD = 4 * 1024; // 4KB — OS write atomicity limit
143
+ /**
144
+ * Append a single JSON record as one line to a `.jsonl` file.
145
+ *
146
+ * Uses the OS `write(2)` syscall via `appendFileSync`, which is atomic for
147
+ * writes up to ~4 KB on most POSIX filesystems. Lines exceeding that threshold
148
+ * trigger a `console.error` warning but are still written (best-effort).
149
+ *
150
+ * No lock is acquired — concurrent appenders are safe at the line level
151
+ * because each call is a single `write(2)` syscall.
152
+ * Parent directories are created automatically.
153
+ */
154
+ export function appendJsonLine(filePath, record) {
155
+ const line = JSON.stringify(record) + "\n";
156
+ if (line.length > APPEND_SIZE_WARN_THRESHOLD) {
157
+ console.error(`[json-store] appendJsonLine line exceeds ${APPEND_SIZE_WARN_THRESHOLD} bytes ` +
158
+ `(${line.length}) — write may not be atomic on some filesystems. path=${filePath}`);
159
+ }
160
+ mkdirSync(path.dirname(filePath), { recursive: true });
161
+ appendFileSync(filePath, line);
162
+ }
163
+ //# sourceMappingURL=json-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-store.js","sourceRoot":"","sources":["../../src/shared/json-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
+ export declare function textResult(obj: unknown): CallToolResult;
3
+ //# sourceMappingURL=mcp-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-utils.d.ts","sourceRoot":"","sources":["../../src/shared/mcp-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,CAIvD"}
@@ -0,0 +1,6 @@
1
+ export function textResult(obj) {
2
+ return {
3
+ content: [{ type: "text", text: JSON.stringify(obj, null, 2) }],
4
+ };
5
+ }
6
+ //# sourceMappingURL=mcp-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-utils.js","sourceRoot":"","sources":["../../src/shared/mcp-utils.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,UAAU,CAAC,GAAY;IACrC,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KAChE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * 프로젝트 루트 해석. 우선순위:
3
+ * 1. NEXUS_PROJECT_ROOT env (테스트·명시 주입용)
4
+ * 2. git rev-parse --show-toplevel (cwd 혹은 인자 기준)
5
+ * 3. cwd 상승하며 .git 수동 탐색
6
+ * 4. fallback: start 자체
7
+ */
8
+ export declare function findProjectRoot(cwd?: string): string;
9
+ /** .nexus/ 루트 경로 getter */
10
+ export declare function getNexusRoot(cwd?: string): string;
11
+ /** .nexus/state/ 경로 getter */
12
+ export declare function getStateRoot(cwd?: string): string;
13
+ /** 현재 git 브랜치명 반환. detached HEAD면 "HEAD" 또는 빈 문자열, git 없으면 빈 문자열 */
14
+ export declare function getCurrentBranch(cwd?: string): string;
15
+ /** 디렉토리 생성 (재귀). 이미 존재하면 idempotent */
16
+ export declare function ensureDir(p: string): void;
17
+ /** NEXUS_SESSION_ID env 우선, 없으면 '<branch>-<pid>' 또는 'unknown-<pid>' */
18
+ export declare function getSessionId(cwd?: string): string;
19
+ /** .nexus/state/<session_id>/ 경로 */
20
+ export declare function getSessionRoot(cwd?: string): string;
21
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/shared/paths.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAqBpD;AAED,2BAA2B;AAC3B,wBAAgB,YAAY,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,8BAA8B;AAC9B,wBAAgB,YAAY,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAWrD;AAED,uCAAuC;AACvC,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAEzC;AAOD,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAQjD;AAED,oCAAoC;AACpC,wBAAgB,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAEnD"}
@@ -0,0 +1,81 @@
1
+ import { join, resolve } from 'path';
2
+ import { existsSync, mkdirSync } from 'fs';
3
+ import { execSync } from 'child_process';
4
+ /**
5
+ * 프로젝트 루트 해석. 우선순위:
6
+ * 1. NEXUS_PROJECT_ROOT env (테스트·명시 주입용)
7
+ * 2. git rev-parse --show-toplevel (cwd 혹은 인자 기준)
8
+ * 3. cwd 상승하며 .git 수동 탐색
9
+ * 4. fallback: start 자체
10
+ */
11
+ export function findProjectRoot(cwd) {
12
+ const envOverride = process.env['NEXUS_PROJECT_ROOT'];
13
+ if (envOverride)
14
+ return envOverride;
15
+ const start = cwd ?? process.cwd();
16
+ try {
17
+ return execSync('git rev-parse --show-toplevel', {
18
+ encoding: 'utf8',
19
+ cwd: start,
20
+ stdio: ['ignore', 'pipe', 'ignore'],
21
+ }).trim();
22
+ }
23
+ catch {
24
+ let dir = start;
25
+ while (true) {
26
+ if (existsSync(join(dir, '.git')))
27
+ return dir;
28
+ const parent = resolve(dir, '..');
29
+ if (parent === dir)
30
+ break;
31
+ dir = parent;
32
+ }
33
+ return start;
34
+ }
35
+ }
36
+ /** .nexus/ 루트 경로 getter */
37
+ export function getNexusRoot(cwd) {
38
+ return join(findProjectRoot(cwd), '.nexus');
39
+ }
40
+ /** .nexus/state/ 경로 getter */
41
+ export function getStateRoot(cwd) {
42
+ return join(getNexusRoot(cwd), 'state');
43
+ }
44
+ /** 현재 git 브랜치명 반환. detached HEAD면 "HEAD" 또는 빈 문자열, git 없으면 빈 문자열 */
45
+ export function getCurrentBranch(cwd) {
46
+ const opts = {
47
+ encoding: 'utf8',
48
+ stdio: ['ignore', 'pipe', 'ignore'],
49
+ ...(cwd ? { cwd } : {}),
50
+ };
51
+ try {
52
+ return execSync('git symbolic-ref --short HEAD', opts).trim();
53
+ }
54
+ catch {
55
+ return '';
56
+ }
57
+ }
58
+ /** 디렉토리 생성 (재귀). 이미 존재하면 idempotent */
59
+ export function ensureDir(p) {
60
+ mkdirSync(p, { recursive: true });
61
+ }
62
+ /** branch명에서 파일시스템에 안전한 문자만 남긴다 */
63
+ function sanitizeBranch(name) {
64
+ return name.replace(/[^a-zA-Z0-9_-]+/g, '_');
65
+ }
66
+ /** NEXUS_SESSION_ID env 우선, 없으면 '<branch>-<pid>' 또는 'unknown-<pid>' */
67
+ export function getSessionId(cwd) {
68
+ const envId = process.env['NEXUS_SESSION_ID'];
69
+ if (envId)
70
+ return envId;
71
+ const branch = getCurrentBranch(cwd);
72
+ const pid = process.pid;
73
+ if (!branch)
74
+ return `unknown-${pid}`;
75
+ return `${sanitizeBranch(branch)}-${pid}`;
76
+ }
77
+ /** .nexus/state/<session_id>/ 경로 */
78
+ export function getSessionRoot(cwd) {
79
+ return join(getStateRoot(cwd), getSessionId(cwd));
80
+ }
81
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/shared/paths.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export declare function logToolCall(entry: {
2
+ tool: string;
3
+ args: unknown;
4
+ response: unknown;
5
+ duration_ms: number;
6
+ timestamp?: string;
7
+ }): void;
8
+ //# sourceMappingURL=tool-log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-log.d.ts","sourceRoot":"","sources":["../../src/shared/tool-log.ts"],"names":[],"mappings":"AAIA,wBAAgB,WAAW,CAAC,KAAK,EAAE;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,IAAI,CAkBP"}
@@ -0,0 +1,22 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { getSessionRoot } from "./paths.js";
4
+ export function logToolCall(entry) {
5
+ try {
6
+ const timestamp = entry.timestamp ?? new Date().toISOString();
7
+ const record = { ...entry, timestamp };
8
+ const logDir = getSessionRoot();
9
+ try {
10
+ fs.mkdirSync(logDir, { recursive: true });
11
+ }
12
+ catch {
13
+ return;
14
+ }
15
+ const logFile = path.join(logDir, "tool-log.jsonl");
16
+ fs.appendFileSync(logFile, JSON.stringify(record) + "\n", "utf8");
17
+ }
18
+ catch {
19
+ // best-effort — silently ignore all failures
20
+ }
21
+ }
22
+ //# sourceMappingURL=tool-log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-log.js","sourceRoot":"","sources":["../../src/shared/tool-log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,UAAU,WAAW,CAAC,KAM3B;IACC,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC9D,MAAM,MAAM,GAAG,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,CAAC;QAEvC,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;QAEhC,IAAI,CAAC;YACH,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;QACpD,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,6CAA6C;IAC/C,CAAC;AACH,CAAC"}