@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.
- package/README.md +48 -63
- package/assets/agents/architect/body.ko.md +177 -0
- package/{agents → assets/agents}/architect/body.md +16 -0
- package/assets/agents/designer/body.ko.md +125 -0
- package/{agents → assets/agents}/designer/body.md +16 -0
- package/assets/agents/engineer/body.ko.md +106 -0
- package/{agents → assets/agents}/engineer/body.md +14 -0
- package/assets/agents/lead/body.ko.md +70 -0
- package/assets/agents/lead/body.md +70 -0
- package/assets/agents/postdoc/body.ko.md +122 -0
- package/{agents → assets/agents}/postdoc/body.md +16 -0
- package/assets/agents/researcher/body.ko.md +137 -0
- package/{agents → assets/agents}/researcher/body.md +15 -0
- package/assets/agents/reviewer/body.ko.md +138 -0
- package/{agents → assets/agents}/reviewer/body.md +15 -0
- package/assets/agents/strategist/body.ko.md +116 -0
- package/{agents → assets/agents}/strategist/body.md +16 -0
- package/assets/agents/tester/body.ko.md +195 -0
- package/{agents → assets/agents}/tester/body.md +15 -0
- package/assets/agents/writer/body.ko.md +122 -0
- package/{agents → assets/agents}/writer/body.md +14 -0
- package/assets/capability-matrix.yml +198 -0
- package/assets/hooks/agent-bootstrap/handler.test.ts +368 -0
- package/assets/hooks/agent-bootstrap/handler.ts +119 -0
- package/assets/hooks/agent-bootstrap/meta.yml +10 -0
- package/assets/hooks/agent-finalize/handler.test.ts +368 -0
- package/assets/hooks/agent-finalize/handler.ts +76 -0
- package/assets/hooks/agent-finalize/meta.yml +10 -0
- package/assets/hooks/capability-matrix.yml +313 -0
- package/assets/hooks/post-tool-telemetry/handler.test.ts +302 -0
- package/assets/hooks/post-tool-telemetry/handler.ts +49 -0
- package/assets/hooks/post-tool-telemetry/meta.yml +11 -0
- package/assets/hooks/prompt-router/handler.test.ts +801 -0
- package/assets/hooks/prompt-router/handler.ts +261 -0
- package/assets/hooks/prompt-router/meta.yml +11 -0
- package/assets/hooks/session-init/handler.test.ts +274 -0
- package/assets/hooks/session-init/handler.ts +30 -0
- package/assets/hooks/session-init/meta.yml +9 -0
- package/assets/lsp-servers.json +55 -0
- package/assets/schema/lsp-servers.schema.json +67 -0
- package/assets/skills/nx-init/body.ko.md +197 -0
- package/{skills → assets/skills}/nx-init/body.md +11 -0
- package/assets/skills/nx-plan/body.ko.md +361 -0
- package/{skills → assets/skills}/nx-plan/body.md +13 -0
- package/assets/skills/nx-run/body.ko.md +161 -0
- package/{skills → assets/skills}/nx-run/body.md +11 -0
- package/assets/skills/nx-sync/body.ko.md +92 -0
- package/{skills → assets/skills}/nx-sync/body.md +10 -0
- package/assets/tools/tool-name-map.yml +353 -0
- package/dist/hooks/opencode-mount.d.ts +35 -0
- package/dist/hooks/opencode-mount.d.ts.map +1 -0
- package/dist/hooks/opencode-mount.js +332 -0
- package/dist/hooks/opencode-mount.js.map +1 -0
- package/dist/hooks/runtime.d.ts +37 -0
- package/dist/hooks/runtime.d.ts.map +1 -0
- package/dist/hooks/runtime.js +274 -0
- package/dist/hooks/runtime.js.map +1 -0
- package/dist/hooks/types.d.ts +196 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +85 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/lsp/cache.d.ts +9 -0
- package/dist/lsp/cache.d.ts.map +1 -0
- package/dist/lsp/cache.js +216 -0
- package/dist/lsp/cache.js.map +1 -0
- package/dist/lsp/client.d.ts +24 -0
- package/dist/lsp/client.d.ts.map +1 -0
- package/dist/lsp/client.js +166 -0
- package/dist/lsp/client.js.map +1 -0
- package/dist/lsp/detect.d.ts +77 -0
- package/dist/lsp/detect.d.ts.map +1 -0
- package/dist/lsp/detect.js +116 -0
- package/dist/lsp/detect.js.map +1 -0
- package/dist/mcp/server.d.ts +5 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +34 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/artifact.d.ts +4 -0
- package/dist/mcp/tools/artifact.d.ts.map +1 -0
- package/dist/mcp/tools/artifact.js +36 -0
- package/dist/mcp/tools/artifact.js.map +1 -0
- package/dist/mcp/tools/history.d.ts +3 -0
- package/dist/mcp/tools/history.d.ts.map +1 -0
- package/dist/mcp/tools/history.js +29 -0
- package/dist/mcp/tools/history.js.map +1 -0
- package/dist/mcp/tools/lsp.d.ts +13 -0
- package/dist/mcp/tools/lsp.d.ts.map +1 -0
- package/dist/mcp/tools/lsp.js +225 -0
- package/dist/mcp/tools/lsp.js.map +1 -0
- package/dist/mcp/tools/plan.d.ts +3 -0
- package/dist/mcp/tools/plan.d.ts.map +1 -0
- package/dist/mcp/tools/plan.js +317 -0
- package/dist/mcp/tools/plan.js.map +1 -0
- package/dist/mcp/tools/task.d.ts +3 -0
- package/dist/mcp/tools/task.d.ts.map +1 -0
- package/dist/mcp/tools/task.js +252 -0
- package/dist/mcp/tools/task.js.map +1 -0
- package/dist/shared/invocations.d.ts +74 -0
- package/dist/shared/invocations.d.ts.map +1 -0
- package/dist/shared/invocations.js +247 -0
- package/dist/shared/invocations.js.map +1 -0
- package/dist/shared/json-store.d.ts +37 -0
- package/dist/shared/json-store.d.ts.map +1 -0
- package/dist/shared/json-store.js +163 -0
- package/dist/shared/json-store.js.map +1 -0
- package/dist/shared/mcp-utils.d.ts +3 -0
- package/dist/shared/mcp-utils.d.ts.map +1 -0
- package/dist/shared/mcp-utils.js +6 -0
- package/dist/shared/mcp-utils.js.map +1 -0
- package/dist/shared/paths.d.ts +21 -0
- package/dist/shared/paths.d.ts.map +1 -0
- package/dist/shared/paths.js +81 -0
- package/dist/shared/paths.js.map +1 -0
- package/dist/shared/tool-log.d.ts +8 -0
- package/dist/shared/tool-log.d.ts.map +1 -0
- package/dist/shared/tool-log.js +22 -0
- package/dist/shared/tool-log.js.map +1 -0
- package/dist/types/state.d.ts +862 -0
- package/dist/types/state.d.ts.map +1 -0
- package/dist/types/state.js +66 -0
- package/dist/types/state.js.map +1 -0
- package/docs/consuming/codex-lead-merge.md +106 -0
- package/docs/plugin-guide.md +360 -0
- package/docs/plugin-template/claude/.github/workflows/build.yml +60 -0
- package/docs/plugin-template/claude/README.md +110 -0
- package/docs/plugin-template/claude/package.json +16 -0
- package/docs/plugin-template/codex/.github/workflows/build.yml +51 -0
- package/docs/plugin-template/codex/README.md +147 -0
- package/docs/plugin-template/codex/package.json +17 -0
- package/docs/plugin-template/opencode/.github/workflows/build.yml +61 -0
- package/docs/plugin-template/opencode/README.md +121 -0
- package/docs/plugin-template/opencode/package.json +25 -0
- package/package.json +21 -21
- package/scripts/build-agents.test.ts +1279 -0
- package/scripts/build-agents.ts +978 -0
- package/scripts/build-hooks.test.ts +1385 -0
- package/scripts/build-hooks.ts +584 -0
- package/scripts/cli.test.ts +367 -0
- package/scripts/cli.ts +547 -0
- package/agents/architect/meta.yml +0 -13
- package/agents/designer/meta.yml +0 -13
- package/agents/engineer/meta.yml +0 -11
- package/agents/postdoc/meta.yml +0 -13
- package/agents/researcher/meta.yml +0 -12
- package/agents/reviewer/meta.yml +0 -12
- package/agents/strategist/meta.yml +0 -13
- package/agents/tester/meta.yml +0 -12
- package/agents/writer/meta.yml +0 -11
- package/conformance/README.md +0 -311
- package/conformance/examples/plan.extension.schema.example.json +0 -25
- package/conformance/lifecycle/README.md +0 -48
- package/conformance/lifecycle/agent-complete.json +0 -44
- package/conformance/lifecycle/agent-resume.json +0 -43
- package/conformance/lifecycle/agent-spawn.json +0 -36
- package/conformance/lifecycle/memory-access-record.json +0 -27
- package/conformance/lifecycle/session-end.json +0 -48
- package/conformance/scenarios/full-plan-cycle.json +0 -147
- package/conformance/scenarios/task-deps-ordering.json +0 -95
- package/conformance/schema/fixture.schema.json +0 -354
- package/conformance/state-schemas/agent-tracker.schema.json +0 -63
- package/conformance/state-schemas/history.schema.json +0 -134
- package/conformance/state-schemas/memory-access.schema.json +0 -36
- package/conformance/state-schemas/plan.schema.json +0 -77
- package/conformance/state-schemas/tasks.schema.json +0 -98
- package/conformance/tools/artifact-write.json +0 -97
- package/conformance/tools/context.json +0 -172
- package/conformance/tools/history-search.json +0 -219
- package/conformance/tools/plan-decide.json +0 -139
- package/conformance/tools/plan-start.json +0 -81
- package/conformance/tools/plan-status.json +0 -127
- package/conformance/tools/plan-update.json +0 -341
- package/conformance/tools/task-add.json +0 -156
- package/conformance/tools/task-close.json +0 -161
- package/conformance/tools/task-list.json +0 -177
- package/conformance/tools/task-update.json +0 -167
- package/docs/behavioral-contracts.md +0 -145
- package/docs/consumer-implementation-guide.md +0 -852
- package/docs/memory-lifecycle-contract.md +0 -119
- package/docs/nexus-layout.md +0 -224
- package/docs/nexus-outputs-contract.md +0 -344
- package/docs/nexus-state-overview.md +0 -170
- package/docs/nexus-tools-contract.md +0 -438
- package/manifest.json +0 -449
- package/schema/README.md +0 -69
- package/schema/agent.schema.json +0 -23
- package/schema/common.schema.json +0 -17
- package/schema/manifest.schema.json +0 -78
- package/schema/memory-policy.schema.json +0 -98
- package/schema/skill.schema.json +0 -54
- package/schema/task-exceptions.schema.json +0 -40
- package/schema/vocabulary.schema.json +0 -167
- package/scripts/.gitkeep +0 -0
- package/scripts/conformance-coverage.ts +0 -466
- package/scripts/import-from-claude-nexus.ts +0 -403
- package/scripts/lib/frontmatter.ts +0 -71
- package/scripts/lib/lint.ts +0 -348
- package/scripts/lib/structure.ts +0 -159
- package/scripts/lib/validate.ts +0 -794
- package/scripts/validate.ts +0 -90
- package/skills/nx-init/meta.yml +0 -8
- package/skills/nx-plan/meta.yml +0 -10
- package/skills/nx-run/meta.yml +0 -9
- package/skills/nx-sync/meta.yml +0 -7
- package/vocabulary/capabilities.yml +0 -65
- package/vocabulary/categories.yml +0 -11
- package/vocabulary/invocations.yml +0 -147
- package/vocabulary/memory_policy.yml +0 -88
- package/vocabulary/resume-tiers.yml +0 -11
- package/vocabulary/tags.yml +0 -60
- 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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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"}
|