@moreih29/nexus-core 0.12.0 → 0.14.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 +76 -57
- 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/assets/hooks/agent-bootstrap/handler.d.ts +4 -0
- package/dist/assets/hooks/agent-bootstrap/handler.d.ts.map +1 -0
- package/dist/assets/hooks/agent-bootstrap/handler.js +100 -0
- package/dist/assets/hooks/agent-bootstrap/handler.js.map +1 -0
- package/dist/assets/hooks/agent-finalize/handler.d.ts +4 -0
- package/dist/assets/hooks/agent-finalize/handler.d.ts.map +1 -0
- package/dist/assets/hooks/agent-finalize/handler.js +63 -0
- package/dist/assets/hooks/agent-finalize/handler.js.map +1 -0
- package/dist/assets/hooks/post-tool-telemetry/handler.d.ts +4 -0
- package/dist/assets/hooks/post-tool-telemetry/handler.d.ts.map +1 -0
- package/dist/assets/hooks/post-tool-telemetry/handler.js +40 -0
- package/dist/assets/hooks/post-tool-telemetry/handler.js.map +1 -0
- package/dist/assets/hooks/prompt-router/handler.d.ts +4 -0
- package/dist/assets/hooks/prompt-router/handler.d.ts.map +1 -0
- package/dist/assets/hooks/prompt-router/handler.js +204 -0
- package/dist/assets/hooks/prompt-router/handler.js.map +1 -0
- package/dist/assets/hooks/session-init/handler.d.ts +4 -0
- package/dist/assets/hooks/session-init/handler.d.ts.map +1 -0
- package/dist/assets/hooks/session-init/handler.js +23 -0
- package/dist/assets/hooks/session-init/handler.js.map +1 -0
- package/dist/hooks/agent-bootstrap.js +105 -0
- package/dist/hooks/agent-finalize.js +164 -0
- package/dist/hooks/post-tool-telemetry.js +55 -0
- package/dist/hooks/prompt-router.js +7300 -0
- package/dist/hooks/session-init.js +21 -0
- package/dist/manifests/claude-hooks.json +52 -0
- package/dist/manifests/codex-hooks.json +28 -0
- package/dist/manifests/opencode-manifest.json +44 -0
- package/dist/manifests/portability-report.json +87 -0
- package/dist/scripts/build-agents.d.ts +157 -0
- package/dist/scripts/build-agents.d.ts.map +1 -0
- package/dist/scripts/build-agents.js +737 -0
- package/dist/scripts/build-agents.js.map +1 -0
- package/dist/scripts/build-hooks.d.ts +16 -0
- package/dist/scripts/build-hooks.d.ts.map +1 -0
- package/dist/scripts/build-hooks.js +388 -0
- package/dist/scripts/build-hooks.js.map +1 -0
- package/dist/scripts/cli.d.ts +54 -0
- package/dist/scripts/cli.d.ts.map +1 -0
- package/dist/scripts/cli.js +467 -0
- package/dist/scripts/cli.js.map +1 -0
- package/dist/src/hooks/opencode-mount.d.ts +35 -0
- package/dist/src/hooks/opencode-mount.d.ts.map +1 -0
- package/dist/src/hooks/opencode-mount.js +352 -0
- package/dist/src/hooks/opencode-mount.js.map +1 -0
- package/dist/src/hooks/runtime.d.ts +37 -0
- package/dist/src/hooks/runtime.d.ts.map +1 -0
- package/dist/src/hooks/runtime.js +274 -0
- package/dist/src/hooks/runtime.js.map +1 -0
- package/dist/src/hooks/types.d.ts +196 -0
- package/dist/src/hooks/types.d.ts.map +1 -0
- package/dist/src/hooks/types.js +85 -0
- package/dist/src/hooks/types.js.map +1 -0
- package/dist/src/lsp/cache.d.ts +9 -0
- package/dist/src/lsp/cache.d.ts.map +1 -0
- package/dist/src/lsp/cache.js +216 -0
- package/dist/src/lsp/cache.js.map +1 -0
- package/dist/src/lsp/client.d.ts +24 -0
- package/dist/src/lsp/client.d.ts.map +1 -0
- package/dist/src/lsp/client.js +166 -0
- package/dist/src/lsp/client.js.map +1 -0
- package/dist/src/lsp/detect.d.ts +77 -0
- package/dist/src/lsp/detect.d.ts.map +1 -0
- package/dist/src/lsp/detect.js +116 -0
- package/dist/src/lsp/detect.js.map +1 -0
- package/dist/src/mcp/server.d.ts +5 -0
- package/dist/src/mcp/server.d.ts.map +1 -0
- package/dist/src/mcp/server.js +34 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/mcp/tools/artifact.d.ts +4 -0
- package/dist/src/mcp/tools/artifact.d.ts.map +1 -0
- package/dist/src/mcp/tools/artifact.js +36 -0
- package/dist/src/mcp/tools/artifact.js.map +1 -0
- package/dist/src/mcp/tools/history.d.ts +3 -0
- package/dist/src/mcp/tools/history.d.ts.map +1 -0
- package/dist/src/mcp/tools/history.js +29 -0
- package/dist/src/mcp/tools/history.js.map +1 -0
- package/dist/src/mcp/tools/lsp.d.ts +13 -0
- package/dist/src/mcp/tools/lsp.d.ts.map +1 -0
- package/dist/src/mcp/tools/lsp.js +225 -0
- package/dist/src/mcp/tools/lsp.js.map +1 -0
- package/dist/src/mcp/tools/plan.d.ts +3 -0
- package/dist/src/mcp/tools/plan.d.ts.map +1 -0
- package/dist/src/mcp/tools/plan.js +317 -0
- package/dist/src/mcp/tools/plan.js.map +1 -0
- package/dist/src/mcp/tools/task.d.ts +3 -0
- package/dist/src/mcp/tools/task.d.ts.map +1 -0
- package/dist/src/mcp/tools/task.js +252 -0
- package/dist/src/mcp/tools/task.js.map +1 -0
- package/dist/src/shared/invocations.d.ts +74 -0
- package/dist/src/shared/invocations.d.ts.map +1 -0
- package/dist/src/shared/invocations.js +247 -0
- package/dist/src/shared/invocations.js.map +1 -0
- package/dist/src/shared/json-store.d.ts +37 -0
- package/dist/src/shared/json-store.d.ts.map +1 -0
- package/dist/src/shared/json-store.js +163 -0
- package/dist/src/shared/json-store.js.map +1 -0
- package/dist/src/shared/mcp-utils.d.ts +3 -0
- package/dist/src/shared/mcp-utils.d.ts.map +1 -0
- package/dist/src/shared/mcp-utils.js +6 -0
- package/dist/src/shared/mcp-utils.js.map +1 -0
- package/dist/src/shared/paths.d.ts +21 -0
- package/dist/src/shared/paths.d.ts.map +1 -0
- package/dist/src/shared/paths.js +81 -0
- package/dist/src/shared/paths.js.map +1 -0
- package/dist/src/shared/tool-log.d.ts +8 -0
- package/dist/src/shared/tool-log.d.ts.map +1 -0
- package/dist/src/shared/tool-log.js +22 -0
- package/dist/src/shared/tool-log.js.map +1 -0
- package/dist/src/types/state.d.ts +862 -0
- package/dist/src/types/state.d.ts.map +1 -0
- package/dist/src/types/state.js +66 -0
- package/dist/src/types/state.js.map +1 -0
- package/docs/consuming/codex-lead-merge.md +106 -0
- package/docs/plugin-guide.md +396 -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 +36 -28
- 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 -840
- 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 -448
- 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 -796
- 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 -8
- 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,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/shared/invocations.ts
|
|
3
|
+
*
|
|
4
|
+
* expandInvocation — cross-harness invocation template expansion.
|
|
5
|
+
*
|
|
6
|
+
* Resolves {{template_name key=value ...}} placeholders in agent/skill body.md
|
|
7
|
+
* to harness-native call syntax as defined in assets/tools/tool-name-map.yml
|
|
8
|
+
* invocations section.
|
|
9
|
+
*
|
|
10
|
+
* Supported templates (4):
|
|
11
|
+
* {{subagent_spawn target_role=<role> prompt=<text> [name=<label>]}}
|
|
12
|
+
* {{skill_activation skill=<name> [mode=<mode>]}}
|
|
13
|
+
* {{task_register label=<text> state=<text>}}
|
|
14
|
+
* {{user_question question=<text> options=<json-array>}}
|
|
15
|
+
*/
|
|
16
|
+
export type Harness = "claude" | "opencode" | "codex";
|
|
17
|
+
export interface InvocationTemplate {
|
|
18
|
+
args: string[];
|
|
19
|
+
templates: Record<Harness, string>;
|
|
20
|
+
}
|
|
21
|
+
export interface InvocationsMap {
|
|
22
|
+
[name: string]: InvocationTemplate;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Parse a {{...}} invocation call string into its template name and key=value args.
|
|
26
|
+
*
|
|
27
|
+
* Format: {{template_name key1=value1 key2=value2 ...}}
|
|
28
|
+
* Values may be:
|
|
29
|
+
* - double-quoted strings: "..."
|
|
30
|
+
* - bracket-balanced arrays: [...]
|
|
31
|
+
* - brace-balanced objects: {...}
|
|
32
|
+
* - plain non-whitespace tokens
|
|
33
|
+
*
|
|
34
|
+
* Returns null if the format is invalid.
|
|
35
|
+
*/
|
|
36
|
+
export declare function parseInvocationCall(call: string): {
|
|
37
|
+
name: string;
|
|
38
|
+
args: Record<string, string>;
|
|
39
|
+
} | null;
|
|
40
|
+
/**
|
|
41
|
+
* Apply a single invocation template for the given harness.
|
|
42
|
+
*
|
|
43
|
+
* Substitutes {placeholder} tokens in the template string with arg values.
|
|
44
|
+
* Optional args (those not in the args map) are omitted along with their
|
|
45
|
+
* surrounding delimiters when absent.
|
|
46
|
+
*
|
|
47
|
+
* Returns the harness-native syntax string, or an error comment if the
|
|
48
|
+
* template name is unknown or a required arg is missing.
|
|
49
|
+
*/
|
|
50
|
+
export declare function applyTemplate(templateStr: string, args: Record<string, string>, templateDef: InvocationTemplate): string;
|
|
51
|
+
/**
|
|
52
|
+
* Expand a single {{...}} invocation expression to harness-native syntax.
|
|
53
|
+
*
|
|
54
|
+
* @param expression The content inside {{ }}, e.g. "subagent_spawn target_role=engineer prompt=Fix the bug"
|
|
55
|
+
* @param harness Target harness: "claude" | "opencode" | "codex"
|
|
56
|
+
* @param invocations Parsed invocations map from tool-name-map.yml
|
|
57
|
+
*
|
|
58
|
+
* Returns the expanded string, or a comment if unknown/invalid.
|
|
59
|
+
*/
|
|
60
|
+
export declare function expandInvocationExpression(expression: string, harness: Harness, invocations: InvocationsMap): string;
|
|
61
|
+
/**
|
|
62
|
+
* Expand all {{...}} invocation placeholders in a body string.
|
|
63
|
+
*
|
|
64
|
+
* Uses a balance-counter scanner so that nested `{}` inside argument values
|
|
65
|
+
* (e.g. options=[{label: "Set up"}]) are correctly included in the match.
|
|
66
|
+
*
|
|
67
|
+
* @param input Raw body.md content (may contain multiple {{}} blocks)
|
|
68
|
+
* @param harness Target harness
|
|
69
|
+
* @param invocations Parsed invocations map
|
|
70
|
+
*
|
|
71
|
+
* Returns the body with all {{}} templates replaced by harness-native syntax.
|
|
72
|
+
*/
|
|
73
|
+
export declare function expandInvocations(input: string, harness: Harness, invocations: InvocationsMap): string;
|
|
74
|
+
//# sourceMappingURL=invocations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invocations.d.ts","sourceRoot":"","sources":["../../../src/shared/invocations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;AAEtD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC7B,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,CAAC;CACpC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B,GAAG,IAAI,CAmGP;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,WAAW,EAAE,kBAAkB,GAC9B,MAAM,CAgBR;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,cAAc,GAC1B,MAAM,CAiBR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,cAAc,GAC1B,MAAM,CAqDR"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/shared/invocations.ts
|
|
3
|
+
*
|
|
4
|
+
* expandInvocation — cross-harness invocation template expansion.
|
|
5
|
+
*
|
|
6
|
+
* Resolves {{template_name key=value ...}} placeholders in agent/skill body.md
|
|
7
|
+
* to harness-native call syntax as defined in assets/tools/tool-name-map.yml
|
|
8
|
+
* invocations section.
|
|
9
|
+
*
|
|
10
|
+
* Supported templates (4):
|
|
11
|
+
* {{subagent_spawn target_role=<role> prompt=<text> [name=<label>]}}
|
|
12
|
+
* {{skill_activation skill=<name> [mode=<mode>]}}
|
|
13
|
+
* {{task_register label=<text> state=<text>}}
|
|
14
|
+
* {{user_question question=<text> options=<json-array>}}
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Parse a {{...}} invocation call string into its template name and key=value args.
|
|
18
|
+
*
|
|
19
|
+
* Format: {{template_name key1=value1 key2=value2 ...}}
|
|
20
|
+
* Values may be:
|
|
21
|
+
* - double-quoted strings: "..."
|
|
22
|
+
* - bracket-balanced arrays: [...]
|
|
23
|
+
* - brace-balanced objects: {...}
|
|
24
|
+
* - plain non-whitespace tokens
|
|
25
|
+
*
|
|
26
|
+
* Returns null if the format is invalid.
|
|
27
|
+
*/
|
|
28
|
+
export function parseInvocationCall(call) {
|
|
29
|
+
// call is the content inside {{ }}
|
|
30
|
+
const trimmed = call.trim();
|
|
31
|
+
if (!trimmed)
|
|
32
|
+
return null;
|
|
33
|
+
// Extract template name (first token)
|
|
34
|
+
const firstSpace = trimmed.indexOf(" ");
|
|
35
|
+
const name = firstSpace === -1 ? trimmed : trimmed.slice(0, firstSpace);
|
|
36
|
+
const rest = firstSpace === -1 ? "" : trimmed.slice(firstSpace + 1).trim();
|
|
37
|
+
const args = {};
|
|
38
|
+
if (rest) {
|
|
39
|
+
// Manual tokenizer: scan for key=<value> pairs where <value> may contain
|
|
40
|
+
// nested brackets/braces or quoted strings.
|
|
41
|
+
let i = 0;
|
|
42
|
+
while (i < rest.length) {
|
|
43
|
+
// Skip whitespace
|
|
44
|
+
while (i < rest.length && /\s/.test(rest[i]))
|
|
45
|
+
i++;
|
|
46
|
+
if (i >= rest.length)
|
|
47
|
+
break;
|
|
48
|
+
// Read key (word chars up to '=')
|
|
49
|
+
const keyStart = i;
|
|
50
|
+
while (i < rest.length && /\w/.test(rest[i]))
|
|
51
|
+
i++;
|
|
52
|
+
if (i >= rest.length || rest[i] !== "=") {
|
|
53
|
+
// Not a valid key=value pair — skip this token
|
|
54
|
+
while (i < rest.length && !/\s/.test(rest[i]))
|
|
55
|
+
i++;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const key = rest.slice(keyStart, i);
|
|
59
|
+
i++; // consume '='
|
|
60
|
+
if (i >= rest.length)
|
|
61
|
+
break;
|
|
62
|
+
// Read value: dispatch on first character
|
|
63
|
+
let value = "";
|
|
64
|
+
const ch = rest[i];
|
|
65
|
+
if (ch === '"') {
|
|
66
|
+
// Quoted string — scan to closing unescaped quote
|
|
67
|
+
i++; // consume opening quote
|
|
68
|
+
const start = i;
|
|
69
|
+
while (i < rest.length) {
|
|
70
|
+
if (rest[i] === "\\" && i + 1 < rest.length) {
|
|
71
|
+
i += 2; // skip escape sequence
|
|
72
|
+
}
|
|
73
|
+
else if (rest[i] === '"') {
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
i++;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
value = rest.slice(start, i).replace(/\\"/g, '"');
|
|
81
|
+
if (i < rest.length)
|
|
82
|
+
i++; // consume closing quote
|
|
83
|
+
}
|
|
84
|
+
else if (ch === "[" || ch === "{") {
|
|
85
|
+
// Bracket/brace balanced scan
|
|
86
|
+
const open = ch;
|
|
87
|
+
const close = open === "[" ? "]" : "}";
|
|
88
|
+
let depth = 0;
|
|
89
|
+
const start = i;
|
|
90
|
+
while (i < rest.length) {
|
|
91
|
+
const c = rest[i];
|
|
92
|
+
if (c === '"') {
|
|
93
|
+
// Skip quoted section inside array/object
|
|
94
|
+
i++;
|
|
95
|
+
while (i < rest.length) {
|
|
96
|
+
if (rest[i] === "\\" && i + 1 < rest.length) {
|
|
97
|
+
i += 2;
|
|
98
|
+
}
|
|
99
|
+
else if (rest[i] === '"') {
|
|
100
|
+
i++;
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
i++;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (c === open)
|
|
110
|
+
depth++;
|
|
111
|
+
else if (c === close) {
|
|
112
|
+
depth--;
|
|
113
|
+
if (depth === 0) {
|
|
114
|
+
i++; // consume closing bracket
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
i++;
|
|
119
|
+
}
|
|
120
|
+
value = rest.slice(start, i);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
// Plain non-whitespace token
|
|
124
|
+
const start = i;
|
|
125
|
+
while (i < rest.length && !/\s/.test(rest[i]))
|
|
126
|
+
i++;
|
|
127
|
+
value = rest.slice(start, i);
|
|
128
|
+
}
|
|
129
|
+
if (key)
|
|
130
|
+
args[key] = value;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return { name, args };
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Apply a single invocation template for the given harness.
|
|
137
|
+
*
|
|
138
|
+
* Substitutes {placeholder} tokens in the template string with arg values.
|
|
139
|
+
* Optional args (those not in the args map) are omitted along with their
|
|
140
|
+
* surrounding delimiters when absent.
|
|
141
|
+
*
|
|
142
|
+
* Returns the harness-native syntax string, or an error comment if the
|
|
143
|
+
* template name is unknown or a required arg is missing.
|
|
144
|
+
*/
|
|
145
|
+
export function applyTemplate(templateStr, args, templateDef) {
|
|
146
|
+
let result = templateStr;
|
|
147
|
+
// Replace all {key} tokens with their values
|
|
148
|
+
for (const [key, value] of Object.entries(args)) {
|
|
149
|
+
result = result.replace(new RegExp(`\\{${key}\\}`, "g"), value);
|
|
150
|
+
}
|
|
151
|
+
// Remove any remaining optional placeholders that have no value
|
|
152
|
+
// Pattern: `, "description": "{name}"` or similar — strip the whole field segment
|
|
153
|
+
// We handle this by removing ", key: "{remaining_token}"" patterns
|
|
154
|
+
result = result.replace(/,?\s*\w+:\s*"\{[^}]+\}"/g, "");
|
|
155
|
+
// Also handle ", description: {name}" without quotes (less common but defensive)
|
|
156
|
+
result = result.replace(/,?\s*\w+:\s*\{[^}]+\}/g, "");
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Expand a single {{...}} invocation expression to harness-native syntax.
|
|
161
|
+
*
|
|
162
|
+
* @param expression The content inside {{ }}, e.g. "subagent_spawn target_role=engineer prompt=Fix the bug"
|
|
163
|
+
* @param harness Target harness: "claude" | "opencode" | "codex"
|
|
164
|
+
* @param invocations Parsed invocations map from tool-name-map.yml
|
|
165
|
+
*
|
|
166
|
+
* Returns the expanded string, or a comment if unknown/invalid.
|
|
167
|
+
*/
|
|
168
|
+
export function expandInvocationExpression(expression, harness, invocations) {
|
|
169
|
+
const parsed = parseInvocationCall(expression);
|
|
170
|
+
if (!parsed) {
|
|
171
|
+
return `/* [nexus] invalid invocation: ${expression.trim()} */`;
|
|
172
|
+
}
|
|
173
|
+
const def = invocations[parsed.name];
|
|
174
|
+
if (!def) {
|
|
175
|
+
return `/* [nexus] unknown invocation: ${parsed.name} */`;
|
|
176
|
+
}
|
|
177
|
+
const templateStr = def.templates[harness];
|
|
178
|
+
if (!templateStr) {
|
|
179
|
+
return `/* [nexus] no template for harness ${harness}: ${parsed.name} */`;
|
|
180
|
+
}
|
|
181
|
+
return applyTemplate(templateStr, parsed.args, def);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Expand all {{...}} invocation placeholders in a body string.
|
|
185
|
+
*
|
|
186
|
+
* Uses a balance-counter scanner so that nested `{}` inside argument values
|
|
187
|
+
* (e.g. options=[{label: "Set up"}]) are correctly included in the match.
|
|
188
|
+
*
|
|
189
|
+
* @param input Raw body.md content (may contain multiple {{}} blocks)
|
|
190
|
+
* @param harness Target harness
|
|
191
|
+
* @param invocations Parsed invocations map
|
|
192
|
+
*
|
|
193
|
+
* Returns the body with all {{}} templates replaced by harness-native syntax.
|
|
194
|
+
*/
|
|
195
|
+
export function expandInvocations(input, harness, invocations) {
|
|
196
|
+
let result = "";
|
|
197
|
+
let i = 0;
|
|
198
|
+
while (i < input.length) {
|
|
199
|
+
// Find the next '{{'
|
|
200
|
+
const openIdx = input.indexOf("{{", i);
|
|
201
|
+
if (openIdx === -1) {
|
|
202
|
+
result += input.slice(i);
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
// Append text before the '{{'
|
|
206
|
+
result += input.slice(i, openIdx);
|
|
207
|
+
i = openIdx + 2; // move past '{{'
|
|
208
|
+
// Scan forward with brace depth to find the matching '}}'
|
|
209
|
+
// We start after '{{', depth tracks inner '{' vs '}'
|
|
210
|
+
let depth = 0;
|
|
211
|
+
let innerStart = i;
|
|
212
|
+
let found = false;
|
|
213
|
+
while (i < input.length) {
|
|
214
|
+
if (input[i] === "{") {
|
|
215
|
+
depth++;
|
|
216
|
+
i++;
|
|
217
|
+
}
|
|
218
|
+
else if (input[i] === "}") {
|
|
219
|
+
if (depth === 0 && input[i + 1] === "}") {
|
|
220
|
+
// Found the closing '}}'
|
|
221
|
+
const inner = input.slice(innerStart, i);
|
|
222
|
+
result += expandInvocationExpression(inner, harness, invocations);
|
|
223
|
+
i += 2; // consume '}}'
|
|
224
|
+
found = true;
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
else if (depth > 0) {
|
|
228
|
+
depth--;
|
|
229
|
+
i++;
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
// Single '}' with no matching depth — treat as literal
|
|
233
|
+
i++;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
i++;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (!found) {
|
|
241
|
+
// No closing '}}' — treat the '{{' as literal text
|
|
242
|
+
result += "{{" + input.slice(innerStart, i);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return result;
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=invocations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invocations.js","sourceRoot":"","sources":["../../../src/shared/invocations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read a JSON file, returning `defaultValue` when the file does not exist or
|
|
3
|
+
* its content cannot be parsed.
|
|
4
|
+
*/
|
|
5
|
+
export declare function readJsonFile<T>(filePath: string, defaultValue: T): Promise<T>;
|
|
6
|
+
/**
|
|
7
|
+
* Atomically write a JSON file.
|
|
8
|
+
* Writes to a unique temp file then renames to the target path.
|
|
9
|
+
* Parent directories are created automatically.
|
|
10
|
+
*/
|
|
11
|
+
export declare function writeJsonFile<T>(filePath: string, data: T): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Read-modify-write a JSON file under a two-layer lock.
|
|
14
|
+
*
|
|
15
|
+
* Layer 1 — in-process promise queue: serialises concurrent calls within the
|
|
16
|
+
* same Node/Bun process with zero overhead and no retry cost.
|
|
17
|
+
*
|
|
18
|
+
* Layer 2 — cross-process `.lock` file (O_EXCL): prevents data races between
|
|
19
|
+
* separate processes. Retries every 100 ms for up to 50 attempts (5 s total).
|
|
20
|
+
* Stale locks (mtime > 30 s) are forcibly removed before retry.
|
|
21
|
+
*
|
|
22
|
+
* The lock is always released even when `updater` throws.
|
|
23
|
+
*/
|
|
24
|
+
export declare function updateJsonFileLocked<T>(filePath: string, defaultValue: T, updater: (current: T) => T | Promise<T>): Promise<T>;
|
|
25
|
+
/**
|
|
26
|
+
* Append a single JSON record as one line to a `.jsonl` file.
|
|
27
|
+
*
|
|
28
|
+
* Uses the OS `write(2)` syscall via `appendFileSync`, which is atomic for
|
|
29
|
+
* writes up to ~4 KB on most POSIX filesystems. Lines exceeding that threshold
|
|
30
|
+
* trigger a `console.error` warning but are still written (best-effort).
|
|
31
|
+
*
|
|
32
|
+
* No lock is acquired — concurrent appenders are safe at the line level
|
|
33
|
+
* because each call is a single `write(2)` syscall.
|
|
34
|
+
* Parent directories are created automatically.
|
|
35
|
+
*/
|
|
36
|
+
export declare function appendJsonLine(filePath: string, record: unknown): void;
|
|
37
|
+
//# sourceMappingURL=json-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-store.d.ts","sourceRoot":"","sources":["../../../src/shared/json-store.ts"],"names":[],"mappings":"AA0FA;;;GAGG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAenF;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAK/E;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,EAC1C,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,CAAC,EACf,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACtC,OAAO,CAAC,CAAC,CAAC,CAYZ;AAQD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAYtE"}
|
|
@@ -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"}
|