nexus-agents 8.74.1 → 8.74.2
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/dist/{chunk-3FK67YI4.js → chunk-6Y24JDBR.js} +7 -7
- package/dist/{chunk-4XP43CH7.js → chunk-D5ST2Y4W.js} +2 -2
- package/dist/{chunk-MPWPST6S.js → chunk-I2KBD37Y.js} +2 -2
- package/dist/{chunk-BQMUX3TR.js → chunk-M6DJ6AE3.js} +3 -3
- package/dist/{chunk-MYEDID77.js → chunk-PWEGOADT.js} +3 -3
- package/dist/{chunk-XJI5YBBR.js → chunk-QW5FSTLJ.js} +2 -2
- package/dist/cli.js +9 -9
- package/dist/{consensus-vote-5RFJPG5F.js → consensus-vote-YCETKP4M.js} +4 -4
- package/dist/{improvement-review-LDBUOL7B.js → improvement-review-CF5SWXUB.js} +4 -4
- package/dist/index.js +6 -6
- package/dist/{init-opencode-UFYH4SDG.js → init-opencode-UTF4K2LR.js} +3 -2
- package/dist/init-opencode-UTF4K2LR.js.map +1 -0
- package/dist/{setup-data-dir-I2Q4KJ7M.js → setup-data-dir-6PEJ3YF7.js} +3 -3
- package/package.json +1 -1
- package/dist/init-opencode-UFYH4SDG.js.map +0 -1
- /package/dist/{chunk-3FK67YI4.js.map → chunk-6Y24JDBR.js.map} +0 -0
- /package/dist/{chunk-4XP43CH7.js.map → chunk-D5ST2Y4W.js.map} +0 -0
- /package/dist/{chunk-MPWPST6S.js.map → chunk-I2KBD37Y.js.map} +0 -0
- /package/dist/{chunk-BQMUX3TR.js.map → chunk-M6DJ6AE3.js.map} +0 -0
- /package/dist/{chunk-MYEDID77.js.map → chunk-PWEGOADT.js.map} +0 -0
- /package/dist/{chunk-XJI5YBBR.js.map → chunk-QW5FSTLJ.js.map} +0 -0
- /package/dist/{consensus-vote-5RFJPG5F.js.map → consensus-vote-YCETKP4M.js.map} +0 -0
- /package/dist/{improvement-review-LDBUOL7B.js.map → improvement-review-CF5SWXUB.js.map} +0 -0
- /package/dist/{setup-data-dir-I2Q4KJ7M.js.map → setup-data-dir-6PEJ3YF7.js.map} +0 -0
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
import {
|
|
22
22
|
DEFAULT_TASK_TTL_MS,
|
|
23
23
|
clampTaskTtl
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-PWEGOADT.js";
|
|
25
25
|
import {
|
|
26
26
|
executeExpert
|
|
27
27
|
} from "./chunk-ZKEULHX6.js";
|
|
@@ -71,7 +71,7 @@ import {
|
|
|
71
71
|
updateStage,
|
|
72
72
|
withWarnings,
|
|
73
73
|
writeJobCancelled
|
|
74
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-M6DJ6AE3.js";
|
|
75
75
|
import {
|
|
76
76
|
allOf,
|
|
77
77
|
anyOf
|
|
@@ -93,7 +93,7 @@ import {
|
|
|
93
93
|
} from "./chunk-ADHIHFBA.js";
|
|
94
94
|
import {
|
|
95
95
|
withPrerequisite
|
|
96
|
-
} from "./chunk-
|
|
96
|
+
} from "./chunk-I2KBD37Y.js";
|
|
97
97
|
import {
|
|
98
98
|
NOOP_NOTIFIER,
|
|
99
99
|
RateLimiter,
|
|
@@ -116,7 +116,7 @@ import {
|
|
|
116
116
|
toolSuccessStructured,
|
|
117
117
|
withProgressHeartbeat,
|
|
118
118
|
wrapToolWithTimeout
|
|
119
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-D5ST2Y4W.js";
|
|
120
120
|
import {
|
|
121
121
|
EventTopics,
|
|
122
122
|
UNRESOLVED_MODEL_ID,
|
|
@@ -45863,7 +45863,7 @@ function buildVotingInput(plan, config) {
|
|
|
45863
45863
|
}
|
|
45864
45864
|
async function executeSingleVote(plan, config, log) {
|
|
45865
45865
|
try {
|
|
45866
|
-
const { executeVoting } = await import("./consensus-vote-
|
|
45866
|
+
const { executeVoting } = await import("./consensus-vote-YCETKP4M.js");
|
|
45867
45867
|
const input = buildVotingInput(plan, config);
|
|
45868
45868
|
const result = await executeVoting(input, log);
|
|
45869
45869
|
return parseVotingResult(result);
|
|
@@ -47667,7 +47667,7 @@ ${contextBlock}`;
|
|
|
47667
47667
|
const strategy = config.votingStrategy ?? "higher_order";
|
|
47668
47668
|
await postProgress(config, "Vote", `Running consensus with ${strategy} strategy...`);
|
|
47669
47669
|
try {
|
|
47670
|
-
const { executeVoting } = await import("./consensus-vote-
|
|
47670
|
+
const { executeVoting } = await import("./consensus-vote-YCETKP4M.js");
|
|
47671
47671
|
const votingResult = await executeVoting(
|
|
47672
47672
|
{
|
|
47673
47673
|
proposal: buildVoteProposal(plan, research),
|
|
@@ -56917,4 +56917,4 @@ export {
|
|
|
56917
56917
|
startPipelineEventBridge,
|
|
56918
56918
|
shutdownPipelineEventBridge
|
|
56919
56919
|
};
|
|
56920
|
-
//# sourceMappingURL=chunk-
|
|
56920
|
+
//# sourceMappingURL=chunk-6Y24JDBR.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
VERSION
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-QW5FSTLJ.js";
|
|
4
4
|
import {
|
|
5
5
|
CACHE_TIMEOUTS,
|
|
6
6
|
MCP_TIMEOUTS,
|
|
@@ -2186,4 +2186,4 @@ export {
|
|
|
2186
2186
|
DEFAULT_CONSENSUS_CONFIG,
|
|
2187
2187
|
ConsensusMetricsSchema
|
|
2188
2188
|
};
|
|
2189
|
-
//# sourceMappingURL=chunk-
|
|
2189
|
+
//# sourceMappingURL=chunk-D5ST2Y4W.js.map
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
toolStructuredError,
|
|
8
8
|
toolSuccessStructured,
|
|
9
9
|
wrapToolWithTimeout
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-D5ST2Y4W.js";
|
|
11
11
|
import {
|
|
12
12
|
JsonlStore,
|
|
13
13
|
SECURITY_KEYWORDS,
|
|
@@ -2282,4 +2282,4 @@ export {
|
|
|
2282
2282
|
runImprovementReview,
|
|
2283
2283
|
registerImprovementReviewTool
|
|
2284
2284
|
};
|
|
2285
|
-
//# sourceMappingURL=chunk-
|
|
2285
|
+
//# sourceMappingURL=chunk-I2KBD37Y.js.map
|
|
@@ -25,10 +25,10 @@ import {
|
|
|
25
25
|
toolSuccessStructured,
|
|
26
26
|
withProgressHeartbeat,
|
|
27
27
|
wrapToolWithTimeout
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-D5ST2Y4W.js";
|
|
29
29
|
import {
|
|
30
30
|
VERSION
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-QW5FSTLJ.js";
|
|
32
32
|
import {
|
|
33
33
|
UNRESOLVED_MODEL_ID,
|
|
34
34
|
assessPanelIndependence,
|
|
@@ -9178,4 +9178,4 @@ export {
|
|
|
9178
9178
|
CONSENSUS_VOTE_TOOL_SCHEMA,
|
|
9179
9179
|
registerConsensusVoteTool
|
|
9180
9180
|
};
|
|
9181
|
-
//# sourceMappingURL=chunk-
|
|
9181
|
+
//# sourceMappingURL=chunk-M6DJ6AE3.js.map
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
NODE_ENGINE_RANGE,
|
|
12
12
|
VERSION,
|
|
13
13
|
isNodeVersionSupported
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-QW5FSTLJ.js";
|
|
15
15
|
import {
|
|
16
16
|
claimGlobalRegistry
|
|
17
17
|
} from "./chunk-TL5NV5JH.js";
|
|
@@ -1342,7 +1342,7 @@ async function runDoctorFix(result) {
|
|
|
1342
1342
|
writeLine2("\u2500".repeat(40));
|
|
1343
1343
|
let fixCount = 0;
|
|
1344
1344
|
if (!result.dataDirectory.rootExists || result.dataDirectory.subdirectories.some((d) => !d.exists || !d.writable)) {
|
|
1345
|
-
const { initDataDirectories: initDataDirectories2, describeDataDirFix: describeDataDirFix2 } = await import("./setup-data-dir-
|
|
1345
|
+
const { initDataDirectories: initDataDirectories2, describeDataDirFix: describeDataDirFix2 } = await import("./setup-data-dir-6PEJ3YF7.js");
|
|
1346
1346
|
const outcome = describeDataDirFix2(initDataDirectories2());
|
|
1347
1347
|
writeLine2(outcome.line);
|
|
1348
1348
|
if (outcome.counted) fixCount++;
|
|
@@ -1444,4 +1444,4 @@ export {
|
|
|
1444
1444
|
startStdioServer,
|
|
1445
1445
|
closeServer
|
|
1446
1446
|
};
|
|
1447
|
-
//# sourceMappingURL=chunk-
|
|
1447
|
+
//# sourceMappingURL=chunk-PWEGOADT.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/version.ts
|
|
2
2
|
import semver from "semver";
|
|
3
|
-
var VERSION = true ? "8.74.
|
|
3
|
+
var VERSION = true ? "8.74.2" : "dev";
|
|
4
4
|
var NODE_ENGINE_RANGE = ">=22.5.0";
|
|
5
5
|
function isNodeVersionSupported(version) {
|
|
6
6
|
return semver.satisfies(version, NODE_ENGINE_RANGE);
|
|
@@ -11,4 +11,4 @@ export {
|
|
|
11
11
|
NODE_ENGINE_RANGE,
|
|
12
12
|
isNodeVersionSupported
|
|
13
13
|
};
|
|
14
|
-
//# sourceMappingURL=chunk-
|
|
14
|
+
//# sourceMappingURL=chunk-QW5FSTLJ.js.map
|
package/dist/cli.js
CHANGED
|
@@ -156,7 +156,7 @@ import {
|
|
|
156
156
|
validateNexusEnv,
|
|
157
157
|
validateWorkflow,
|
|
158
158
|
wrapInMarkdownFence
|
|
159
|
-
} from "./chunk-
|
|
159
|
+
} from "./chunk-6Y24JDBR.js";
|
|
160
160
|
import "./chunk-CYZ3DUQV.js";
|
|
161
161
|
import "./chunk-4GDMHCKX.js";
|
|
162
162
|
import "./chunk-M7DUOIAK.js";
|
|
@@ -176,7 +176,7 @@ import {
|
|
|
176
176
|
doctorCommand,
|
|
177
177
|
initDataDirectories,
|
|
178
178
|
runDoctor
|
|
179
|
-
} from "./chunk-
|
|
179
|
+
} from "./chunk-PWEGOADT.js";
|
|
180
180
|
import "./chunk-43RJNTUZ.js";
|
|
181
181
|
import {
|
|
182
182
|
buildOpenAICompatAdapters,
|
|
@@ -202,7 +202,7 @@ import {
|
|
|
202
202
|
registerConsensusVoteTool,
|
|
203
203
|
seatFallbacks,
|
|
204
204
|
toRecordDecision
|
|
205
|
-
} from "./chunk-
|
|
205
|
+
} from "./chunk-M6DJ6AE3.js";
|
|
206
206
|
import {
|
|
207
207
|
loadUsageEvents,
|
|
208
208
|
rollupByModel
|
|
@@ -243,18 +243,18 @@ import {
|
|
|
243
243
|
registerImprovementReviewTool,
|
|
244
244
|
runImprovementReview,
|
|
245
245
|
scanForSecrets
|
|
246
|
-
} from "./chunk-
|
|
246
|
+
} from "./chunk-I2KBD37Y.js";
|
|
247
247
|
import {
|
|
248
248
|
createDefaultPolicyFirewall,
|
|
249
249
|
setGlobalPolicyFirewall,
|
|
250
250
|
setSecureHandlerAuditLogger,
|
|
251
251
|
stagePolicyFirewallForRollout
|
|
252
|
-
} from "./chunk-
|
|
252
|
+
} from "./chunk-D5ST2Y4W.js";
|
|
253
253
|
import {
|
|
254
254
|
NODE_ENGINE_RANGE,
|
|
255
255
|
VERSION,
|
|
256
256
|
isNodeVersionSupported
|
|
257
|
-
} from "./chunk-
|
|
257
|
+
} from "./chunk-QW5FSTLJ.js";
|
|
258
258
|
import {
|
|
259
259
|
claimGlobalRegistry,
|
|
260
260
|
createUnifiedRegistry,
|
|
@@ -19679,7 +19679,7 @@ function startImprovementReviewScheduler(options) {
|
|
|
19679
19679
|
let running = false;
|
|
19680
19680
|
const runOnce = async () => {
|
|
19681
19681
|
try {
|
|
19682
|
-
const { runImprovementReview: runImprovementReview2, ImprovementReviewInputSchema: ImprovementReviewInputSchema2 } = await import("./improvement-review-
|
|
19682
|
+
const { runImprovementReview: runImprovementReview2, ImprovementReviewInputSchema: ImprovementReviewInputSchema2 } = await import("./improvement-review-CF5SWXUB.js");
|
|
19683
19683
|
const input = ImprovementReviewInputSchema2.parse({ fileIssues });
|
|
19684
19684
|
const result = await runImprovementReview2(input, { logger: logger22 });
|
|
19685
19685
|
logger22.info("Scheduled improvement_review complete", {
|
|
@@ -23839,7 +23839,7 @@ async function runInitPortableFlow(args) {
|
|
|
23839
23839
|
return cliExit(result.success ? EXIT_CODES.SUCCESS : EXIT_CODES.SERVER_START_FAILED);
|
|
23840
23840
|
}
|
|
23841
23841
|
async function runInitOpencodeFlow(args) {
|
|
23842
|
-
const { runInitOpencode } = await import("./init-opencode-
|
|
23842
|
+
const { runInitOpencode } = await import("./init-opencode-UTF4K2LR.js");
|
|
23843
23843
|
const opencodePath = args.options.opencode;
|
|
23844
23844
|
if (opencodePath === void 0 || opencodePath === "") {
|
|
23845
23845
|
process.stderr.write("Error: --opencode requires a path argument.\n");
|
|
@@ -23865,7 +23865,7 @@ async function runInitOpencodeFlow(args) {
|
|
|
23865
23865
|
return cliExit(EXIT_CODES.SUCCESS);
|
|
23866
23866
|
}
|
|
23867
23867
|
async function renderOpencodeValidate(opencodePath) {
|
|
23868
|
-
const { runOpencodeValidate } = await import("./init-opencode-
|
|
23868
|
+
const { runOpencodeValidate } = await import("./init-opencode-UTF4K2LR.js");
|
|
23869
23869
|
const result = await runOpencodeValidate(opencodePath);
|
|
23870
23870
|
if (!result.ok) {
|
|
23871
23871
|
process.stderr.write(`init --opencode --validate: ${result.reason ?? "failed"}
|
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
resetCorrelationTracker,
|
|
11
11
|
runConsensusForGoal,
|
|
12
12
|
unwrapVoteOrThrow
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-M6DJ6AE3.js";
|
|
14
14
|
import "./chunk-47624RRN.js";
|
|
15
15
|
import "./chunk-OQB3XC5O.js";
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-D5ST2Y4W.js";
|
|
17
|
+
import "./chunk-QW5FSTLJ.js";
|
|
18
18
|
import "./chunk-TL5NV5JH.js";
|
|
19
19
|
import "./chunk-B227FYGQ.js";
|
|
20
20
|
import "./chunk-7LP6VJRP.js";
|
|
@@ -47,4 +47,4 @@ export {
|
|
|
47
47
|
runConsensusForGoal,
|
|
48
48
|
unwrapVoteOrThrow
|
|
49
49
|
};
|
|
50
|
-
//# sourceMappingURL=consensus-vote-
|
|
50
|
+
//# sourceMappingURL=consensus-vote-YCETKP4M.js.map
|
|
@@ -10,9 +10,9 @@ import {
|
|
|
10
10
|
loadSelfEvalSignals,
|
|
11
11
|
registerImprovementReviewTool,
|
|
12
12
|
runImprovementReview
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
13
|
+
} from "./chunk-I2KBD37Y.js";
|
|
14
|
+
import "./chunk-D5ST2Y4W.js";
|
|
15
|
+
import "./chunk-QW5FSTLJ.js";
|
|
16
16
|
import "./chunk-4PWDDMLH.js";
|
|
17
17
|
import "./chunk-4UHDDCRB.js";
|
|
18
18
|
import "./chunk-RNDHNRSX.js";
|
|
@@ -30,4 +30,4 @@ export {
|
|
|
30
30
|
registerImprovementReviewTool,
|
|
31
31
|
runImprovementReview
|
|
32
32
|
};
|
|
33
|
-
//# sourceMappingURL=improvement-review-
|
|
33
|
+
//# sourceMappingURL=improvement-review-CF5SWXUB.js.map
|
package/dist/index.js
CHANGED
|
@@ -552,7 +552,7 @@ import {
|
|
|
552
552
|
withLogging,
|
|
553
553
|
withRetry,
|
|
554
554
|
withRetryWrapper
|
|
555
|
-
} from "./chunk-
|
|
555
|
+
} from "./chunk-6Y24JDBR.js";
|
|
556
556
|
import {
|
|
557
557
|
FALLBACK_SCANNER_DATA,
|
|
558
558
|
buildPlanFromAnalysis,
|
|
@@ -585,7 +585,7 @@ import {
|
|
|
585
585
|
connectTransport,
|
|
586
586
|
createServer,
|
|
587
587
|
startStdioServer
|
|
588
|
-
} from "./chunk-
|
|
588
|
+
} from "./chunk-PWEGOADT.js";
|
|
589
589
|
import "./chunk-43RJNTUZ.js";
|
|
590
590
|
import {
|
|
591
591
|
OPENAI_MODELS,
|
|
@@ -644,7 +644,7 @@ import {
|
|
|
644
644
|
generateProposalId,
|
|
645
645
|
parseAgentPairKey,
|
|
646
646
|
registerConsensusVoteTool
|
|
647
|
-
} from "./chunk-
|
|
647
|
+
} from "./chunk-M6DJ6AE3.js";
|
|
648
648
|
import "./chunk-47624RRN.js";
|
|
649
649
|
import {
|
|
650
650
|
allOf
|
|
@@ -711,7 +711,7 @@ import {
|
|
|
711
711
|
import {
|
|
712
712
|
ImprovementReviewInputSchema,
|
|
713
713
|
registerImprovementReviewTool
|
|
714
|
-
} from "./chunk-
|
|
714
|
+
} from "./chunk-I2KBD37Y.js";
|
|
715
715
|
import {
|
|
716
716
|
AgentPerformanceSchema,
|
|
717
717
|
ConsensusAlgorithmSchema,
|
|
@@ -748,10 +748,10 @@ import {
|
|
|
748
748
|
toolSuccess,
|
|
749
749
|
toolSuccessStructured,
|
|
750
750
|
validateToolInput
|
|
751
|
-
} from "./chunk-
|
|
751
|
+
} from "./chunk-D5ST2Y4W.js";
|
|
752
752
|
import {
|
|
753
753
|
VERSION
|
|
754
|
-
} from "./chunk-
|
|
754
|
+
} from "./chunk-QW5FSTLJ.js";
|
|
755
755
|
import {
|
|
756
756
|
RegistryAlreadyInitializedError,
|
|
757
757
|
UnifiedAdapterRegistry,
|
|
@@ -35,7 +35,8 @@ function buildDefaultPermissionBlock() {
|
|
|
35
35
|
function buildNexusMcpBlock(opts) {
|
|
36
36
|
const env = {
|
|
37
37
|
NEXUS_DATA_DIR: "{env:NEXUS_DATA_DIR}",
|
|
38
|
-
NEXUS_OPENCODE_CONFIG: opts.opencodeConfigPath
|
|
38
|
+
NEXUS_OPENCODE_CONFIG: opts.opencodeConfigPath,
|
|
39
|
+
NEXUS_GATEWAY_COST: "openai-compat=free"
|
|
39
40
|
};
|
|
40
41
|
if (opts.sandboxFlavor !== void 0 && opts.sandboxFlavor !== "") {
|
|
41
42
|
env["NEXUS_SANDBOX"] = opts.sandboxFlavor;
|
|
@@ -176,4 +177,4 @@ export {
|
|
|
176
177
|
runInitOpencode,
|
|
177
178
|
runOpencodeValidate
|
|
178
179
|
};
|
|
179
|
-
//# sourceMappingURL=init-opencode-
|
|
180
|
+
//# sourceMappingURL=init-opencode-UTF4K2LR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/init-opencode.ts"],"sourcesContent":["/**\n * `nexus-agents init --opencode <path>` setup helper (#2504, child 4 of #2500).\n *\n * Injects the nexus-agents MCP block + recommended environment into an\n * existing `opencode.json` without overwriting other operator-set keys.\n * Pairs with the existing `init --portable --mcp-config` (which targets\n * Claude Code's `.mcp.json`). Different harness, same merge-not-overwrite\n * pattern.\n *\n * Behaviour:\n * - File exists → merge `mcp.nexus-agents` into the existing JSON.\n * Preserve every other key the operator has set (provider config,\n * model lists, theme, …). Idempotent: re-running produces the same\n * final file.\n * - File missing → write a minimal template with the nexus-agents MCP\n * block + a stubbed `providers.openai-compat` shell the operator\n * fills in (placeholder baseURL + `{env:WORKSPACE_PROXY_KEY}`).\n * - `--dry-run` → print the diff (proposed vs existing) without writing.\n * - `--validate` → after merge (or alongside dry-run), probe\n * `providers.openai-compat.options.baseURL/v1/models` with the\n * resolved apiKey, exit non-zero if unreachable.\n *\n * @module cli/init-opencode\n */\n\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\nimport { createLogger } from '../core/index.js';\nimport { readOpencodeGateway } from '../config/opencode-bridge.js';\nimport { discoverModels } from '../adapters/openai-compat-adapter.js';\n\nconst logger = createLogger({ component: 'init-opencode' });\n\nexport interface InitOpencodeOptions {\n /** Absolute or relative path to opencode.json. */\n readonly path: string;\n /** Path to the nexus-agents CLI binary that the MCP block will spawn. */\n readonly cliPath: string;\n /** Sandbox flavor written to NEXUS_SANDBOX in the MCP environment. */\n readonly sandboxFlavor?: string;\n /** Print the diff without writing. */\n readonly dryRun?: boolean;\n}\n\nexport interface InitOpencodeResult {\n readonly path: string;\n readonly action: 'created' | 'updated' | 'unchanged' | 'dry-run';\n readonly diff: string;\n}\n\ninterface OpencodeMcpBlock {\n type: 'local';\n command: string[];\n enabled: boolean;\n environment: Record<string, string>;\n}\n\ninterface OpencodeFile {\n $schema?: string;\n providers?: Record<string, unknown>;\n mcp?: Record<string, unknown>;\n permission?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * Conservative default OpenCode `permission` block (#2658). OpenCode\n * evaluates a glob map with **last-matching-rule-winning**, so the broad\n * `\"*\"` rule is listed first and the hard `deny` patterns last.\n *\n * - `edit` — everything `ask`s; secrets, keys, and `.git/` are hard-denied\n * regardless of operator confirmation. The deny patterns come after\n * `\"*\"` so last-match-wins makes them stick.\n * - `bash` — `ask` unconditionally. Shell is the highest-risk surface.\n * - `skill` — `allow`. Skills are trusted, in-repo, CI-validated content.\n *\n * Emitted only when the operator has not already set their own\n * `permission` block — never overwrites operator config.\n */\nexport function buildDefaultPermissionBlock(): Record<string, unknown> {\n return {\n edit: {\n '*': 'ask',\n '**/.env': 'deny',\n '**/.env.*': 'deny',\n '**/*.pem': 'deny',\n '**/*.key': 'deny',\n '**/id_rsa*': 'deny',\n '**/secrets/**': 'deny',\n '**/.git/**': 'deny',\n },\n bash: 'ask',\n skill: 'allow',\n };\n}\n\n/**\n * Build the canonical nexus-agents MCP block. Mirrors what\n * `Dockerfile.sandbox` writes today plus the env vars from #2501 + #2503.\n *\n * `NEXUS_GATEWAY_COST` (#4392): the gateway this file configures is the\n * `providers.openai-compat` block, so its arm is declared `free` under\n * that endpoint key. Scoped, never bare — a bare `free` would also declare\n * any second gateway the operator adds later. `free`, not `local` — init\n * cannot know whether the proxy is on-box. A hand-edited value survives a\n * re-run: `mergeNexusBlock` spreads the existing environment over this one.\n */\nexport function buildNexusMcpBlock(opts: {\n readonly cliPath: string;\n readonly sandboxFlavor?: string;\n readonly opencodeConfigPath: string;\n}): OpencodeMcpBlock {\n const env: Record<string, string> = {\n NEXUS_DATA_DIR: '{env:NEXUS_DATA_DIR}',\n NEXUS_OPENCODE_CONFIG: opts.opencodeConfigPath,\n NEXUS_GATEWAY_COST: 'openai-compat=free',\n };\n if (opts.sandboxFlavor !== undefined && opts.sandboxFlavor !== '') {\n env['NEXUS_SANDBOX'] = opts.sandboxFlavor;\n }\n return {\n type: 'local',\n command: ['node', opts.cliPath, '--mode=server'],\n enabled: true,\n environment: env,\n };\n}\n\n/**\n * Execute the merge. Pure with respect to `opts.dryRun: true` — no fs\n * writes. Returns the final-or-proposed JSON + a diff string suitable\n * for printing.\n */\nexport function runInitOpencode(opts: InitOpencodeOptions): InitOpencodeResult {\n const existing = readExisting(opts.path);\n const merged = mergeNexusBlock(existing, opts);\n const before = existing === null ? '' : `${JSON.stringify(existing, null, 2)}\\n`;\n const after = `${JSON.stringify(merged, null, 2)}\\n`;\n const diff = simpleDiff(before, after);\n\n if (opts.dryRun === true) {\n return { path: opts.path, action: 'dry-run', diff };\n }\n\n if (existing !== null && before === after) {\n return { path: opts.path, action: 'unchanged', diff };\n }\n\n writeFileSync(opts.path, after, 'utf8');\n return { path: opts.path, action: existing === null ? 'created' : 'updated', diff };\n}\n\nfunction readExisting(path: string): OpencodeFile | null {\n if (!existsSync(path)) return null;\n try {\n const raw = readFileSync(path, 'utf8');\n const parsed = JSON.parse(raw) as unknown;\n if (typeof parsed !== 'object' || parsed === null) {\n throw new Error('opencode.json root must be an object');\n }\n return parsed as OpencodeFile;\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to parse opencode.json at ${path}: ${msg}`);\n }\n}\n\nfunction mergeNexusBlock(existing: OpencodeFile | null, opts: InitOpencodeOptions): OpencodeFile {\n const block = buildNexusMcpBlock({\n cliPath: opts.cliPath,\n ...(opts.sandboxFlavor !== undefined && { sandboxFlavor: opts.sandboxFlavor }),\n opencodeConfigPath: opts.path,\n });\n\n if (existing === null) {\n return {\n $schema: 'https://opencode.ai/config.json',\n providers: { 'openai-compat': stubOpenaiCompatProvider() },\n permission: buildDefaultPermissionBlock(),\n mcp: { 'nexus-agents': block },\n };\n }\n\n // Idempotent merge: preserve user-customised fields if they exist on the\n // current MCP block (e.g. `enabled: false`). Update anything else.\n const existingMcp: Record<string, unknown> = existing.mcp ?? {};\n const rawNexus = existingMcp['nexus-agents'];\n const existingNexus: Partial<OpencodeMcpBlock> =\n typeof rawNexus === 'object' && rawNexus !== null ? rawNexus : {};\n const mergedBlock: OpencodeMcpBlock = {\n type: 'local',\n command: block.command,\n enabled: existingNexus.enabled ?? block.enabled,\n environment: { ...block.environment, ...(existingNexus.environment ?? {}) },\n };\n\n // Add the default permission block only when the operator has not set\n // their own — never overwrite an existing `permission` key.\n const permission = existing.permission ?? buildDefaultPermissionBlock();\n\n return {\n ...existing,\n permission,\n mcp: { ...existingMcp, 'nexus-agents': mergedBlock },\n };\n}\n\n/**\n * Stub for `providers.openai-compat`. Operators replace the placeholder\n * baseURL + key with their workspace-proxy values. Empty by design — we\n * never overwrite an existing provider block (see `mergeNexusBlock`).\n */\nfunction stubOpenaiCompatProvider(): Record<string, unknown> {\n return {\n npm: '@ai-sdk/openai-compatible',\n options: {\n baseURL: '<replace with workspace proxy URL>',\n apiKey: '{env:WORKSPACE_PROXY_KEY}',\n },\n };\n}\n\n/**\n * Cheap line-based diff. Three-line context, +/- prefixes. Good enough\n * for an operator preview; not a unified-diff replacement.\n */\nfunction simpleDiff(before: string, after: string): string {\n if (before === after) return '(no changes)';\n const beforeLines = before.split('\\n');\n const afterLines = after.split('\\n');\n const out: string[] = [];\n const max = Math.max(beforeLines.length, afterLines.length);\n for (let i = 0; i < max; i += 1) {\n const b = beforeLines[i];\n const a = afterLines[i];\n if (b === a) {\n out.push(` ${b ?? ''}`);\n } else {\n if (b !== undefined) out.push(`- ${b}`);\n if (a !== undefined) out.push(`+ ${a}`);\n }\n }\n return out.join('\\n');\n}\n\nexport function ensureOpencodeDirExists(path: string): void {\n const dir = dirname(path);\n if (!existsSync(dir)) {\n throw new Error(\n `Parent directory does not exist: ${dir}. Create it first or pass a path under an existing dir.`\n );\n }\n logger.debug('opencode.json target directory exists', { dir });\n}\n\n/**\n * --validate flow for `init --opencode` (follow-up to #2504).\n *\n * After the merge step writes the file, optionally probe the gateway it\n * points at. Reuses the same opencode-bridge loader (#2503) that the\n * runtime uses, so what we validate is exactly what the server will see\n * at boot.\n *\n * Returns:\n * - `{ ok: true, models }` when the gateway is reachable and returns ≥1 model\n * - `{ ok: false, reason }` for every failure path (config missing,\n * probe failed, zero models)\n *\n * Caller (cli-commands-handlers) maps to exit codes + stderr / stdout.\n * The API key never reaches the returned object — only model IDs +\n * baseURL appear in the success payload.\n */\nexport interface OpencodeValidateResult {\n readonly ok: boolean;\n readonly baseURL?: string;\n readonly models?: readonly string[];\n readonly reason?: string;\n}\n\nexport async function runOpencodeValidate(opencodePath: string): Promise<OpencodeValidateResult> {\n const config = readOpencodeGateway(opencodePath);\n if (config === null) {\n return {\n ok: false,\n reason:\n 'opencode.json does not resolve a usable gateway. Check that providers.openai-compat.options.{baseURL, apiKey} are set and that any {env:VAR} interpolation references are exported.',\n };\n }\n const result = await discoverModels({ baseUrl: config.baseURL, apiKey: config.apiKey });\n if (!result.ok) {\n return { ok: false, baseURL: config.baseURL, reason: result.error.message };\n }\n if (result.value.length === 0) {\n return {\n ok: false,\n baseURL: config.baseURL,\n reason: 'gateway returned 0 models. Check upstream provider quotas / list filters.',\n };\n }\n return {\n ok: true,\n baseURL: config.baseURL,\n models: result.value.map((m) => m.id),\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -2,12 +2,12 @@ import {
|
|
|
2
2
|
NEXUS_DATA_DIR,
|
|
3
3
|
describeDataDirFix,
|
|
4
4
|
initDataDirectories
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-PWEGOADT.js";
|
|
6
6
|
import "./chunk-43RJNTUZ.js";
|
|
7
7
|
import "./chunk-HO2UPJ7T.js";
|
|
8
8
|
import "./chunk-47624RRN.js";
|
|
9
9
|
import "./chunk-OQB3XC5O.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-QW5FSTLJ.js";
|
|
11
11
|
import "./chunk-TL5NV5JH.js";
|
|
12
12
|
import "./chunk-7LP6VJRP.js";
|
|
13
13
|
import "./chunk-TUTS6S2G.js";
|
|
@@ -28,4 +28,4 @@ export {
|
|
|
28
28
|
describeDataDirFix,
|
|
29
29
|
initDataDirectories
|
|
30
30
|
};
|
|
31
|
-
//# sourceMappingURL=setup-data-dir-
|
|
31
|
+
//# sourceMappingURL=setup-data-dir-6PEJ3YF7.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexus-agents",
|
|
3
|
-
"version": "8.74.
|
|
3
|
+
"version": "8.74.2",
|
|
4
4
|
"description": "Governance substrate for AI coding agents — adversarial PR review, drift-detected rules, tamper-evident audit, and closed-loop outcome routing for Claude, Codex, Gemini, and OpenCode",
|
|
5
5
|
"mcpName": "io.github.nexus-substrate/nexus-agents",
|
|
6
6
|
"license": "MIT",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/init-opencode.ts"],"sourcesContent":["/**\n * `nexus-agents init --opencode <path>` setup helper (#2504, child 4 of #2500).\n *\n * Injects the nexus-agents MCP block + recommended environment into an\n * existing `opencode.json` without overwriting other operator-set keys.\n * Pairs with the existing `init --portable --mcp-config` (which targets\n * Claude Code's `.mcp.json`). Different harness, same merge-not-overwrite\n * pattern.\n *\n * Behaviour:\n * - File exists → merge `mcp.nexus-agents` into the existing JSON.\n * Preserve every other key the operator has set (provider config,\n * model lists, theme, …). Idempotent: re-running produces the same\n * final file.\n * - File missing → write a minimal template with the nexus-agents MCP\n * block + a stubbed `providers.openai-compat` shell the operator\n * fills in (placeholder baseURL + `{env:WORKSPACE_PROXY_KEY}`).\n * - `--dry-run` → print the diff (proposed vs existing) without writing.\n * - `--validate` → after merge (or alongside dry-run), probe\n * `providers.openai-compat.options.baseURL/v1/models` with the\n * resolved apiKey, exit non-zero if unreachable.\n *\n * @module cli/init-opencode\n */\n\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\nimport { createLogger } from '../core/index.js';\nimport { readOpencodeGateway } from '../config/opencode-bridge.js';\nimport { discoverModels } from '../adapters/openai-compat-adapter.js';\n\nconst logger = createLogger({ component: 'init-opencode' });\n\nexport interface InitOpencodeOptions {\n /** Absolute or relative path to opencode.json. */\n readonly path: string;\n /** Path to the nexus-agents CLI binary that the MCP block will spawn. */\n readonly cliPath: string;\n /** Sandbox flavor written to NEXUS_SANDBOX in the MCP environment. */\n readonly sandboxFlavor?: string;\n /** Print the diff without writing. */\n readonly dryRun?: boolean;\n}\n\nexport interface InitOpencodeResult {\n readonly path: string;\n readonly action: 'created' | 'updated' | 'unchanged' | 'dry-run';\n readonly diff: string;\n}\n\ninterface OpencodeMcpBlock {\n type: 'local';\n command: string[];\n enabled: boolean;\n environment: Record<string, string>;\n}\n\ninterface OpencodeFile {\n $schema?: string;\n providers?: Record<string, unknown>;\n mcp?: Record<string, unknown>;\n permission?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * Conservative default OpenCode `permission` block (#2658). OpenCode\n * evaluates a glob map with **last-matching-rule-winning**, so the broad\n * `\"*\"` rule is listed first and the hard `deny` patterns last.\n *\n * - `edit` — everything `ask`s; secrets, keys, and `.git/` are hard-denied\n * regardless of operator confirmation. The deny patterns come after\n * `\"*\"` so last-match-wins makes them stick.\n * - `bash` — `ask` unconditionally. Shell is the highest-risk surface.\n * - `skill` — `allow`. Skills are trusted, in-repo, CI-validated content.\n *\n * Emitted only when the operator has not already set their own\n * `permission` block — never overwrites operator config.\n */\nexport function buildDefaultPermissionBlock(): Record<string, unknown> {\n return {\n edit: {\n '*': 'ask',\n '**/.env': 'deny',\n '**/.env.*': 'deny',\n '**/*.pem': 'deny',\n '**/*.key': 'deny',\n '**/id_rsa*': 'deny',\n '**/secrets/**': 'deny',\n '**/.git/**': 'deny',\n },\n bash: 'ask',\n skill: 'allow',\n };\n}\n\n/**\n * Build the canonical nexus-agents MCP block. Mirrors what\n * `Dockerfile.sandbox` writes today plus the env vars from #2501 + #2503.\n */\nexport function buildNexusMcpBlock(opts: {\n readonly cliPath: string;\n readonly sandboxFlavor?: string;\n readonly opencodeConfigPath: string;\n}): OpencodeMcpBlock {\n const env: Record<string, string> = {\n NEXUS_DATA_DIR: '{env:NEXUS_DATA_DIR}',\n NEXUS_OPENCODE_CONFIG: opts.opencodeConfigPath,\n };\n if (opts.sandboxFlavor !== undefined && opts.sandboxFlavor !== '') {\n env['NEXUS_SANDBOX'] = opts.sandboxFlavor;\n }\n return {\n type: 'local',\n command: ['node', opts.cliPath, '--mode=server'],\n enabled: true,\n environment: env,\n };\n}\n\n/**\n * Execute the merge. Pure with respect to `opts.dryRun: true` — no fs\n * writes. Returns the final-or-proposed JSON + a diff string suitable\n * for printing.\n */\nexport function runInitOpencode(opts: InitOpencodeOptions): InitOpencodeResult {\n const existing = readExisting(opts.path);\n const merged = mergeNexusBlock(existing, opts);\n const before = existing === null ? '' : `${JSON.stringify(existing, null, 2)}\\n`;\n const after = `${JSON.stringify(merged, null, 2)}\\n`;\n const diff = simpleDiff(before, after);\n\n if (opts.dryRun === true) {\n return { path: opts.path, action: 'dry-run', diff };\n }\n\n if (existing !== null && before === after) {\n return { path: opts.path, action: 'unchanged', diff };\n }\n\n writeFileSync(opts.path, after, 'utf8');\n return { path: opts.path, action: existing === null ? 'created' : 'updated', diff };\n}\n\nfunction readExisting(path: string): OpencodeFile | null {\n if (!existsSync(path)) return null;\n try {\n const raw = readFileSync(path, 'utf8');\n const parsed = JSON.parse(raw) as unknown;\n if (typeof parsed !== 'object' || parsed === null) {\n throw new Error('opencode.json root must be an object');\n }\n return parsed as OpencodeFile;\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to parse opencode.json at ${path}: ${msg}`);\n }\n}\n\nfunction mergeNexusBlock(existing: OpencodeFile | null, opts: InitOpencodeOptions): OpencodeFile {\n const block = buildNexusMcpBlock({\n cliPath: opts.cliPath,\n ...(opts.sandboxFlavor !== undefined && { sandboxFlavor: opts.sandboxFlavor }),\n opencodeConfigPath: opts.path,\n });\n\n if (existing === null) {\n return {\n $schema: 'https://opencode.ai/config.json',\n providers: { 'openai-compat': stubOpenaiCompatProvider() },\n permission: buildDefaultPermissionBlock(),\n mcp: { 'nexus-agents': block },\n };\n }\n\n // Idempotent merge: preserve user-customised fields if they exist on the\n // current MCP block (e.g. `enabled: false`). Update anything else.\n const existingMcp: Record<string, unknown> = existing.mcp ?? {};\n const rawNexus = existingMcp['nexus-agents'];\n const existingNexus: Partial<OpencodeMcpBlock> =\n typeof rawNexus === 'object' && rawNexus !== null ? rawNexus : {};\n const mergedBlock: OpencodeMcpBlock = {\n type: 'local',\n command: block.command,\n enabled: existingNexus.enabled ?? block.enabled,\n environment: { ...block.environment, ...(existingNexus.environment ?? {}) },\n };\n\n // Add the default permission block only when the operator has not set\n // their own — never overwrite an existing `permission` key.\n const permission = existing.permission ?? buildDefaultPermissionBlock();\n\n return {\n ...existing,\n permission,\n mcp: { ...existingMcp, 'nexus-agents': mergedBlock },\n };\n}\n\n/**\n * Stub for `providers.openai-compat`. Operators replace the placeholder\n * baseURL + key with their workspace-proxy values. Empty by design — we\n * never overwrite an existing provider block (see `mergeNexusBlock`).\n */\nfunction stubOpenaiCompatProvider(): Record<string, unknown> {\n return {\n npm: '@ai-sdk/openai-compatible',\n options: {\n baseURL: '<replace with workspace proxy URL>',\n apiKey: '{env:WORKSPACE_PROXY_KEY}',\n },\n };\n}\n\n/**\n * Cheap line-based diff. Three-line context, +/- prefixes. Good enough\n * for an operator preview; not a unified-diff replacement.\n */\nfunction simpleDiff(before: string, after: string): string {\n if (before === after) return '(no changes)';\n const beforeLines = before.split('\\n');\n const afterLines = after.split('\\n');\n const out: string[] = [];\n const max = Math.max(beforeLines.length, afterLines.length);\n for (let i = 0; i < max; i += 1) {\n const b = beforeLines[i];\n const a = afterLines[i];\n if (b === a) {\n out.push(` ${b ?? ''}`);\n } else {\n if (b !== undefined) out.push(`- ${b}`);\n if (a !== undefined) out.push(`+ ${a}`);\n }\n }\n return out.join('\\n');\n}\n\nexport function ensureOpencodeDirExists(path: string): void {\n const dir = dirname(path);\n if (!existsSync(dir)) {\n throw new Error(\n `Parent directory does not exist: ${dir}. Create it first or pass a path under an existing dir.`\n );\n }\n logger.debug('opencode.json target directory exists', { dir });\n}\n\n/**\n * --validate flow for `init --opencode` (follow-up to #2504).\n *\n * After the merge step writes the file, optionally probe the gateway it\n * points at. Reuses the same opencode-bridge loader (#2503) that the\n * runtime uses, so what we validate is exactly what the server will see\n * at boot.\n *\n * Returns:\n * - `{ ok: true, models }` when the gateway is reachable and returns ≥1 model\n * - `{ ok: false, reason }` for every failure path (config missing,\n * probe failed, zero models)\n *\n * Caller (cli-commands-handlers) maps to exit codes + stderr / stdout.\n * The API key never reaches the returned object — only model IDs +\n * baseURL appear in the success payload.\n */\nexport interface OpencodeValidateResult {\n readonly ok: boolean;\n readonly baseURL?: string;\n readonly models?: readonly string[];\n readonly reason?: string;\n}\n\nexport async function runOpencodeValidate(opencodePath: string): Promise<OpencodeValidateResult> {\n const config = readOpencodeGateway(opencodePath);\n if (config === null) {\n return {\n ok: false,\n reason:\n 'opencode.json does not resolve a usable gateway. Check that providers.openai-compat.options.{baseURL, apiKey} are set and that any {env:VAR} interpolation references are exported.',\n };\n }\n const result = await discoverModels({ baseUrl: config.baseURL, apiKey: config.apiKey });\n if (!result.ok) {\n return { ok: false, baseURL: config.baseURL, reason: result.error.message };\n }\n if (result.value.length === 0) {\n return {\n ok: false,\n baseURL: config.baseURL,\n reason: 'gateway returned 0 models. Check upstream provider quotas / list filters.',\n };\n }\n return {\n ok: true,\n baseURL: config.baseURL,\n models: result.value.map((m) => m.id),\n };\n}\n"],"mappings":"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","names":[]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|