@nexrall/code-core 1.4.71 → 1.4.72
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/agent/agentRegistry.d.ts.map +1 -1
- package/dist/agent/agentRegistry.js +28 -10
- package/dist/agent/agentTypes.d.ts.map +1 -1
- package/dist/agent/agentTypes.js +159 -48
- package/dist/agent/askOnce.d.ts.map +1 -1
- package/dist/agent/askOnce.js +14 -5
- package/dist/agent/backgroundAgents.d.ts.map +1 -1
- package/dist/agent/backgroundAgents.js +22 -8
- package/dist/agent/claimEvidence.d.ts.map +1 -1
- package/dist/agent/claimEvidence.js +2 -1
- package/dist/agent/compaction.d.ts.map +1 -1
- package/dist/agent/compaction.js +31 -10
- package/dist/agent/crossProcessLock.d.ts.map +1 -1
- package/dist/agent/crossProcessLock.js +14 -6
- package/dist/agent/editCompleteness.d.ts.map +1 -1
- package/dist/agent/fileLocks.d.ts.map +1 -1
- package/dist/agent/fileLocks.js +14 -5
- package/dist/agent/flaky.d.ts.map +1 -1
- package/dist/agent/hooks.d.ts.map +1 -1
- package/dist/agent/hooks.js +284 -75
- package/dist/agent/iterationPolicy.d.ts.map +1 -1
- package/dist/agent/iterationPolicy.js +26 -23
- package/dist/agent/lifecycleHost.d.ts.map +1 -1
- package/dist/agent/lifecycleHost.js +35 -11
- package/dist/agent/loop.d.ts +22 -4
- package/dist/agent/loop.d.ts.map +1 -1
- package/dist/agent/loop.js +223 -51
- package/dist/agent/memory.d.ts.map +1 -1
- package/dist/agent/memory.js +13 -7
- package/dist/agent/modelCatalogue.d.ts.map +1 -1
- package/dist/agent/modelCatalogue.js +4 -1
- package/dist/agent/nestedInstructions.d.ts +122 -0
- package/dist/agent/nestedInstructions.d.ts.map +1 -0
- package/dist/agent/nestedInstructions.js +696 -0
- package/dist/agent/peerRegistry.d.ts.map +1 -1
- package/dist/agent/peerRegistry.js +44 -6
- package/dist/agent/peerTransport.d.ts.map +1 -1
- package/dist/agent/peerTransport.js +18 -6
- package/dist/agent/planMode.d.ts.map +1 -1
- package/dist/agent/planMode.js +194 -41
- package/dist/agent/readDedupe.d.ts.map +1 -1
- package/dist/agent/readDedupe.js +3 -1
- package/dist/agent/securityLint.d.ts.map +1 -1
- package/dist/agent/sharedTasks.d.ts.map +1 -1
- package/dist/agent/sharedTasks.js +20 -5
- package/dist/agent/skills.d.ts +79 -0
- package/dist/agent/skills.d.ts.map +1 -1
- package/dist/agent/skills.js +403 -14
- package/dist/agent/subAgentBudget.d.ts.map +1 -1
- package/dist/agent/subTask.d.ts.map +1 -1
- package/dist/agent/subTask.js +87 -37
- package/dist/agent/subTaskSupport.d.ts.map +1 -1
- package/dist/agent/subTaskSupport.js +43 -14
- package/dist/agent/testIntegrity.d.ts.map +1 -1
- package/dist/agent/testIntegrity.js +4 -2
- package/dist/agent/toolDescriptions.d.ts.map +1 -1
- package/dist/agent/toolPrefetch.d.ts.map +1 -1
- package/dist/agent/toolPrefetch.js +15 -11
- package/dist/agent/trust.d.ts.map +1 -1
- package/dist/agent/trust.js +6 -2
- package/dist/agent/worktree.d.ts.map +1 -1
- package/dist/agent/worktree.js +70 -16
- package/dist/agent/worktreeEnforcement.d.ts.map +1 -1
- package/dist/agent/worktreeEnforcement.js +9 -4
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +63 -31
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +3 -1
- package/dist/checkpoint/manager.d.ts.map +1 -1
- package/dist/checkpoint/manager.js +22 -7
- package/dist/commands/loader.d.ts.map +1 -1
- package/dist/commands/loader.js +6 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/mcp/client.d.ts +34 -0
- package/dist/mcp/client.d.ts.map +1 -1
- package/dist/mcp/client.js +89 -24
- package/dist/mcp/httpClient.d.ts +24 -1
- package/dist/mcp/httpClient.d.ts.map +1 -1
- package/dist/mcp/httpClient.js +80 -14
- package/dist/mcp/instructions.d.ts +11 -0
- package/dist/mcp/instructions.d.ts.map +1 -0
- package/dist/mcp/instructions.js +42 -0
- package/dist/mcp/manager.d.ts +24 -0
- package/dist/mcp/manager.d.ts.map +1 -1
- package/dist/mcp/manager.js +117 -24
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +48 -14
- package/dist/mcp/sseClient.d.ts +9 -1
- package/dist/mcp/sseClient.d.ts.map +1 -1
- package/dist/mcp/sseClient.js +43 -10
- package/dist/mcp/stats.d.ts.map +1 -1
- package/dist/permissions/bashClassify.d.ts.map +1 -1
- package/dist/permissions/bashClassify.js +25 -3
- package/dist/permissions/destructive.d.ts.map +1 -1
- package/dist/permissions/destructive.js +7 -2
- package/dist/permissions/destructiveTokens.d.ts.map +1 -1
- package/dist/permissions/destructiveTokens.js +104 -24
- package/dist/permissions/modePolicy.d.ts.map +1 -1
- package/dist/permissions/modePolicy.js +40 -17
- package/dist/permissions/rules.d.ts.map +1 -1
- package/dist/permissions/rules.js +7 -5
- package/dist/plugins/data.d.ts.map +1 -1
- package/dist/plugins/data.js +6 -2
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +18 -7
- package/dist/plugins/installer.d.ts.map +1 -1
- package/dist/plugins/installer.js +17 -10
- package/dist/plugins/sources.d.ts.map +1 -1
- package/dist/plugins/sources.js +9 -3
- package/dist/tools/executor.d.ts.map +1 -1
- package/dist/tools/executor.js +454 -168
- package/dist/tools/sandbox.d.ts.map +1 -1
- package/dist/tools/sandbox.js +5 -1
- package/dist/tools/symbols.d.ts.map +1 -1
- package/dist/tools/symbols.js +30 -8
- package/dist/tools/tsLangService.d.ts.map +1 -1
- package/dist/tools/tsLangService.js +12 -4
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/util/frontmatter.d.ts.map +1 -1
- package/dist/util/miniYaml.d.ts.map +1 -1
- package/dist/util/miniYaml.js +3 -1
- package/package.json +1 -1
package/dist/agent/subTask.js
CHANGED
|
@@ -67,7 +67,7 @@ fork) {
|
|
|
67
67
|
// still resume it, with the deny rule looking like it was applied. Re-deriving
|
|
68
68
|
// the name from storage also stops a mismatched `subagent_type` from being
|
|
69
69
|
// used to launder a denied agent under an allowed name.
|
|
70
|
-
const resumeId = fork ? '' :
|
|
70
|
+
const resumeId = fork ? '' : typeof input.resume_agent_id === 'string' ? input.resume_agent_id.trim() : '';
|
|
71
71
|
const resumed = resumeId ? (0, agentRegistry_1.getAgent)(resumeId) : undefined;
|
|
72
72
|
// OWNERSHIP, in addition to the deny-rule re-authorisation below.
|
|
73
73
|
//
|
|
@@ -94,7 +94,9 @@ fork) {
|
|
|
94
94
|
}
|
|
95
95
|
const requestedType = resumed
|
|
96
96
|
? (resumed.agentName ?? '')
|
|
97
|
-
:
|
|
97
|
+
: typeof input.subagent_type === 'string'
|
|
98
|
+
? input.subagent_type
|
|
99
|
+
: '';
|
|
98
100
|
// ── Enforce `deny: ["task(<name>)"]` ─────────────────────────────────────────
|
|
99
101
|
//
|
|
100
102
|
// This is the load-bearing check; filtering the catalogue in runAgentLoop only
|
|
@@ -142,7 +144,9 @@ fork) {
|
|
|
142
144
|
const known = knownTypes.map((a) => a.name).join(', ') || '(none defined)';
|
|
143
145
|
return {
|
|
144
146
|
error: `Unknown subagent_type "${requestedType}". Available types: ${known}.\n` +
|
|
145
|
-
'If you just created .nexrall/agents/' +
|
|
147
|
+
'If you just created .nexrall/agents/' +
|
|
148
|
+
requestedType +
|
|
149
|
+
'.md, make sure the write finished in an ' +
|
|
146
150
|
'EARLIER tool call than this one — a file written in the same batch may not be on disk yet.',
|
|
147
151
|
};
|
|
148
152
|
}
|
|
@@ -161,9 +165,7 @@ fork) {
|
|
|
161
165
|
// grant here is a single purpose-built tool that can only ever touch this agent's
|
|
162
166
|
// own notes file — declaring `memory:` cannot hand anything write access to the repo.
|
|
163
167
|
const memoryScope = agent?.memory;
|
|
164
|
-
const agentMemoryNotes = agent && memoryScope
|
|
165
|
-
? (0, memory_1.agentMemoryPreamble)(agent.name, memoryScope, options.workDir)
|
|
166
|
-
: '';
|
|
168
|
+
const agentMemoryNotes = agent && memoryScope ? (0, memory_1.agentMemoryPreamble)(agent.name, memoryScope, options.workDir) : '';
|
|
167
169
|
// `lightPrompt` agents skip the project's nexrall.md — see AgentType.lightPrompt for
|
|
168
170
|
// why. The role prompt and any private notes still apply; only the (potentially very
|
|
169
171
|
// large) project instruction file is dropped.
|
|
@@ -179,10 +181,14 @@ fork) {
|
|
|
179
181
|
let preloadedSkills = '';
|
|
180
182
|
if (agent?.skills?.length) {
|
|
181
183
|
const known = (0, skills_1.loadSkillsWithWarnings)(options.workDir, options._extraSkills ?? []).skills;
|
|
182
|
-
preloadedSkills = agent.skills
|
|
184
|
+
preloadedSkills = agent.skills
|
|
185
|
+
.map((n) => {
|
|
183
186
|
const sk = (0, skills_1.findSkill)(known, n);
|
|
184
|
-
return sk
|
|
185
|
-
|
|
187
|
+
return sk
|
|
188
|
+
? `# Preloaded skill: ${sk.name}\n${sk.body.trim()}`
|
|
189
|
+
: `# Preloaded skill: ${n}\n(not found in this project — ignore)`;
|
|
190
|
+
})
|
|
191
|
+
.join('\n\n');
|
|
186
192
|
}
|
|
187
193
|
// Shared-before-specific order: the project's nexrall.md (usually the largest part, and
|
|
188
194
|
// identical for every non-lightPrompt sibling) goes first; per-agent parts (preamble,
|
|
@@ -199,7 +205,9 @@ fork) {
|
|
|
199
205
|
agent ? `# Sub-agent role: ${agent.name}\n${agent.prompt}` : '',
|
|
200
206
|
preloadedSkills,
|
|
201
207
|
agentMemoryNotes,
|
|
202
|
-
]
|
|
208
|
+
]
|
|
209
|
+
.filter(Boolean)
|
|
210
|
+
.join('\n\n---\n\n');
|
|
203
211
|
// Optional tool allowlist — deny anything outside it for this sub-agent.
|
|
204
212
|
//
|
|
205
213
|
// A refusal here is reported through `deniedReason` rather than the generic
|
|
@@ -267,9 +275,7 @@ fork) {
|
|
|
267
275
|
// `depth + 1`, not `depth`: this closure gates the CHILD's tool calls, and the child
|
|
268
276
|
// runs one level below the `depth` in scope here (which belongs to its parent). Using
|
|
269
277
|
// `depth` would evaluate the parent's right to spawn — permitting one level too many.
|
|
270
|
-
throw new subTaskSupport_1.ToolNotAllowedError(allowed && !allowed.has('task')
|
|
271
|
-
? (0, subTaskSupport_1.noSpawnReason)('denied')
|
|
272
|
-
: (0, subTaskSupport_1.noSpawnReason)('depth', depthLimit));
|
|
278
|
+
throw new subTaskSupport_1.ToolNotAllowedError(allowed && !allowed.has('task') ? (0, subTaskSupport_1.noSpawnReason)('denied') : (0, subTaskSupport_1.noSpawnReason)('depth', depthLimit));
|
|
273
279
|
}
|
|
274
280
|
if (allowed && !allowed.has(req.tool)) {
|
|
275
281
|
throw new subTaskSupport_1.ToolNotAllowedError(
|
|
@@ -341,9 +347,7 @@ fork) {
|
|
|
341
347
|
// the child rewrite the parent's transcript — the user's next turn would then send bytes
|
|
342
348
|
// that no longer match what is on their screen, and `/rewind`/checkpoints index into it.
|
|
343
349
|
// A JSON round-trip is exact here: Message is plain data (role, content blocks, stopReason).
|
|
344
|
-
const forkHistory = fork
|
|
345
|
-
? JSON.parse(JSON.stringify(fork.messages))
|
|
346
|
-
: [];
|
|
350
|
+
const forkHistory = fork ? JSON.parse(JSON.stringify(fork.messages)) : [];
|
|
347
351
|
const subMessages = fork
|
|
348
352
|
? [...forkHistory, { role: 'user', content: [{ type: 'text', text: prompt }] }]
|
|
349
353
|
: resumed
|
|
@@ -376,7 +380,9 @@ fork) {
|
|
|
376
380
|
// also sets the latter, and the two must be reported differently.
|
|
377
381
|
let lastProgressAt = Date.now();
|
|
378
382
|
let stalled = false;
|
|
379
|
-
const bumpProgress = () => {
|
|
383
|
+
const bumpProgress = () => {
|
|
384
|
+
lastProgressAt = Date.now();
|
|
385
|
+
};
|
|
380
386
|
const stallWatchdog = setInterval(() => {
|
|
381
387
|
if (waitingOnUser > 0) {
|
|
382
388
|
lastProgressAt = Date.now();
|
|
@@ -434,8 +440,9 @@ fork) {
|
|
|
434
440
|
let isoNote = '';
|
|
435
441
|
if (isoState) {
|
|
436
442
|
if ((0, worktree_1.worktreeHasWork)(isoState)) {
|
|
437
|
-
isoNote =
|
|
438
|
-
|
|
443
|
+
isoNote =
|
|
444
|
+
`\n[isolated worktree: this sub-agent's changes are in ${isoState.worktreePath}` +
|
|
445
|
+
`${isoState.branch ? ` (branch ${isoState.branch})` : ''} — NOT in the main checkout. Review them, then merge or discard.]`;
|
|
439
446
|
}
|
|
440
447
|
else {
|
|
441
448
|
(0, worktree_1.removeWorktree)(isoState, { force: true });
|
|
@@ -461,12 +468,16 @@ fork) {
|
|
|
461
468
|
return {
|
|
462
469
|
error: `Sub-agent "${resumed.id}" is already being resumed by another task call that is still running. ` +
|
|
463
470
|
'Wait for that result, then resume it again with your follow-up — two parallel resumes of one agent ' +
|
|
464
|
-
|
|
471
|
+
"would overwrite each other's work.",
|
|
465
472
|
};
|
|
466
473
|
}
|
|
467
|
-
const childMeta = (m) =>
|
|
468
|
-
? {
|
|
469
|
-
|
|
474
|
+
const childMeta = (m) => m
|
|
475
|
+
? {
|
|
476
|
+
...m,
|
|
477
|
+
parentId: m.parentId ?? options._taskToolUseId,
|
|
478
|
+
agentName: m.agentName ?? agent?.name ?? 'general-purpose',
|
|
479
|
+
}
|
|
480
|
+
: undefined;
|
|
470
481
|
try {
|
|
471
482
|
// The point of no return: past here a real agent loop exists and the budget slot is spent.
|
|
472
483
|
if (started)
|
|
@@ -474,14 +485,22 @@ fork) {
|
|
|
474
485
|
// SubagentStart: observer (cannot veto — the PreToolUse hook on `task` already can).
|
|
475
486
|
// additionalContext is appended to the brief the child receives.
|
|
476
487
|
{
|
|
477
|
-
const subAgentName = agent?.name ??
|
|
488
|
+
const subAgentName = agent?.name ??
|
|
489
|
+
(typeof input.subagent_type === 'string' && input.subagent_type ? input.subagent_type : 'general-purpose');
|
|
478
490
|
const startItems = (0, hooks_1.loadHooks)(options.workDir).SubagentStart;
|
|
479
491
|
if (startItems?.length) {
|
|
480
|
-
const o = await (0, hooks_1.runLifecycleHooks)(startItems, 'SubagentStart', options.workDir, {
|
|
492
|
+
const o = await (0, hooks_1.runLifecycleHooks)(startItems, 'SubagentStart', options.workDir, {
|
|
493
|
+
session_id: options.sessionId ?? '',
|
|
494
|
+
agent_type: subAgentName,
|
|
495
|
+
description: String(input.description ?? ''),
|
|
496
|
+
}, subAgentName, (0, hooks_1.hookRunOptsFor)(options)).catch(() => ({ block: false }));
|
|
481
497
|
if (o.context) {
|
|
482
498
|
const last = subMessages[subMessages.length - 1];
|
|
483
499
|
if (last && Array.isArray(last.content)) {
|
|
484
|
-
subMessages[subMessages.length - 1] = {
|
|
500
|
+
subMessages[subMessages.length - 1] = {
|
|
501
|
+
...last,
|
|
502
|
+
content: [...last.content, { type: 'text', text: `\n\n<hook-context>\n${o.context}\n</hook-context>` }],
|
|
503
|
+
};
|
|
485
504
|
}
|
|
486
505
|
}
|
|
487
506
|
}
|
|
@@ -542,16 +561,30 @@ fork) {
|
|
|
542
561
|
onPeerMessage: undefined,
|
|
543
562
|
onProgress: undefined,
|
|
544
563
|
backgroundAgents: undefined,
|
|
564
|
+
// Nested instructions: a child gets its OWN run-scoped discovery (files IT works
|
|
565
|
+
// with) but must neither consume nor grow the session's ledger, nor fire the
|
|
566
|
+
// session's InstructionsLoaded hook — its transient load is not a fact about the
|
|
567
|
+
// session's instruction set.
|
|
568
|
+
_nestedInstructions: undefined,
|
|
569
|
+
_onInstructionsDiscovered: undefined,
|
|
545
570
|
_projectNexrallMd: projectMd,
|
|
546
571
|
_disallowedTools: disallowed.size ? disallowed : undefined,
|
|
547
572
|
_mcpServerAllowlist: mcpAllow,
|
|
548
573
|
_agentHooks: agent?.hooks,
|
|
549
|
-
_onStopReason: (reason, notice) => {
|
|
550
|
-
|
|
574
|
+
_onStopReason: (reason, notice) => {
|
|
575
|
+
childStop = reason;
|
|
576
|
+
childNotice = notice;
|
|
577
|
+
},
|
|
578
|
+
_onVerifications: (records) => {
|
|
579
|
+
childVerifications = records;
|
|
580
|
+
},
|
|
551
581
|
onUsage: (u, partial, cost, _sub) => {
|
|
552
582
|
if (!partial) {
|
|
553
|
-
subTokens +=
|
|
554
|
-
|
|
583
|
+
subTokens +=
|
|
584
|
+
(u.input_tokens ?? 0) +
|
|
585
|
+
(u.output_tokens ?? 0) +
|
|
586
|
+
(u.cache_read_input_tokens ?? 0) +
|
|
587
|
+
(u.cache_creation_input_tokens ?? 0);
|
|
555
588
|
subCost += cost ?? 0;
|
|
556
589
|
}
|
|
557
590
|
options.onUsage(u, partial, cost, true);
|
|
@@ -588,17 +621,33 @@ fork) {
|
|
|
588
621
|
// it finishes, so it cannot be mistaken for a hang.
|
|
589
622
|
// `parentId` = the `task` call that spawned THIS child. Set only if not already set,
|
|
590
623
|
// so a grandchild's events keep pointing at their own (nearest) task row.
|
|
591
|
-
onToolUse: (n, i, _s, m) => {
|
|
592
|
-
|
|
624
|
+
onToolUse: (n, i, _s, m) => {
|
|
625
|
+
bumpProgress();
|
|
626
|
+
subToolCalls++;
|
|
627
|
+
options.onToolUse(n, i, true, childMeta(m));
|
|
628
|
+
},
|
|
629
|
+
onToolResult: (n, r, _s, m) => {
|
|
630
|
+
bumpProgress();
|
|
631
|
+
options.onToolResult(n, r, true, childMeta(m));
|
|
632
|
+
},
|
|
593
633
|
// A long command streaming output is working, not hung.
|
|
594
|
-
onToolStreamChunk: (n, c, _s, m) => {
|
|
634
|
+
onToolStreamChunk: (n, c, _s, m) => {
|
|
635
|
+
bumpProgress();
|
|
636
|
+
options.onToolStreamChunk?.(n, c, true, childMeta(m));
|
|
637
|
+
},
|
|
595
638
|
// Thinking is progress (a model reasoning for minutes is working, not stalled), but
|
|
596
639
|
// it is NOT forwarded to the UI: parallel siblings' deltas interleaved into one live
|
|
597
640
|
// thinking block, and Claude Code does not show sub-agent reasoning either. The
|
|
598
641
|
// sub-agent's tool rows (grouped under its task row) are its visible progress.
|
|
599
|
-
onThinking: () => {
|
|
600
|
-
|
|
601
|
-
|
|
642
|
+
onThinking: () => {
|
|
643
|
+
bumpProgress();
|
|
644
|
+
},
|
|
645
|
+
onThinkingDelta: () => {
|
|
646
|
+
bumpProgress();
|
|
647
|
+
},
|
|
648
|
+
onThinkingProgress: () => {
|
|
649
|
+
bumpProgress();
|
|
650
|
+
},
|
|
602
651
|
});
|
|
603
652
|
const raced = await (0, subTaskSupport_1.raceHardStop)(childRun, subAbort);
|
|
604
653
|
if (raced === subTaskSupport_1.HARD_STOPPED) {
|
|
@@ -693,7 +742,8 @@ fork) {
|
|
|
693
742
|
const body = text || '(sub-task completed with no text output)';
|
|
694
743
|
return finalize({
|
|
695
744
|
output: `${body}\n\n[resumable: this sub-agent is "${agentId}". To ask IT a follow-up — keeping ` +
|
|
696
|
-
'everything it already read and concluded — call task again with resume_agent_id="' +
|
|
745
|
+
'everything it already read and concluded — call task again with resume_agent_id="' +
|
|
746
|
+
agentId +
|
|
697
747
|
'" instead of writing a new prompt from scratch.]',
|
|
698
748
|
});
|
|
699
749
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subTaskSupport.d.ts","sourceRoot":"","sources":["../../src/agent/subTaskSupport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAgCpD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,MAAM,CAOzF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAe9E;AAED;;;;;;;;;;;;;;;GAeG;AACH;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,
|
|
1
|
+
{"version":3,"file":"subTaskSupport.d.ts","sourceRoot":"","sources":["../../src/agent/subTaskSupport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAgCpD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,MAAM,CAOzF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAe9E;AAED;;;;;;;;;;;;;;;GAeG;AACH;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAIhH;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAC1B,KAAK,GAAE,MAA+B,GACrC,OAAO,CAMT;AAWD;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAOpF;AAMD;;;;;;;;;;GAUG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAQD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,UAAU,UAAO,GAAG,MAAM,CAYjF;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAc,GAAG,MAAM,CAKtE;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAgCpE;AAMD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CA2B5F;AAqBD,eAAO,MAAM,YAAY,eAAyB,CAAC;AACnD,wBAAgB,eAAe,IAAI,MAAM,CAGxC;AACD,wBAAgB,YAAY,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,CAAC,GAAG,OAAO,YAAY,CAAC,CA0B9G;AAED,wEAAwE;AACxE,eAAO,MAAM,mBAAmB,EAAE,UAGjC,CAAC;AAEF,wBAAgB,YAAY,CAAC,CAAC,EAC5B,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,EACf,KAAK,CAAC,EAAE;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,GAC3B,OAAO,CAAC,CAAC,GAAG,OAAO,mBAAmB,CAAC,CA0BzC;AAED,8EAA8E;AAC9E,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAE9C,8EAA8E;AAC9E,eAAO,MAAM,uBAAuB,aAalC,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QAIlB,CAAC;AAEb;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,QAKzB,CAAC;AAEb,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAGhD"}
|
|
@@ -82,7 +82,7 @@ function resolveMaxSubagentDepth(settingsRaw = {}) {
|
|
|
82
82
|
*/
|
|
83
83
|
function noSpawnReason(kind, limit) {
|
|
84
84
|
if (kind === 'denied') {
|
|
85
|
-
return (
|
|
85
|
+
return ("This sub-agent's definition does not grant `task`, so it may not delegate. That is a " +
|
|
86
86
|
'deliberate restriction on this agent type — do not ask for approval and do not look for ' +
|
|
87
87
|
'a way around it. Do the work with the tools you have, or report back what is missing.');
|
|
88
88
|
}
|
|
@@ -315,9 +315,7 @@ function lastToolResults(messages, count, maxChars) {
|
|
|
315
315
|
if (!text)
|
|
316
316
|
continue;
|
|
317
317
|
const name = nameById.get(String(b.tool_use_id ?? '')) ?? 'tool';
|
|
318
|
-
const body = text.length > maxChars
|
|
319
|
-
? `${(0, safeSlice_1.sliceSafeEnd)(text, maxChars)}\n… [truncated]`
|
|
320
|
-
: text;
|
|
318
|
+
const body = text.length > maxChars ? `${(0, safeSlice_1.sliceSafeEnd)(text, maxChars)}\n… [truncated]` : text;
|
|
321
319
|
out.push(`• ${name}:\n${body}`);
|
|
322
320
|
}
|
|
323
321
|
}
|
|
@@ -352,12 +350,24 @@ function raceHardStop(run, abort) {
|
|
|
352
350
|
let grace = null;
|
|
353
351
|
const poll = setInterval(() => {
|
|
354
352
|
if (abort.aborted && !grace) {
|
|
355
|
-
grace = setTimeout(() => {
|
|
353
|
+
grace = setTimeout(() => {
|
|
354
|
+
clearInterval(poll);
|
|
355
|
+
resolve(exports.HARD_STOPPED);
|
|
356
|
+
}, hardStopGraceMs());
|
|
356
357
|
}
|
|
357
358
|
}, 250);
|
|
358
|
-
const settle = () => {
|
|
359
|
-
|
|
360
|
-
|
|
359
|
+
const settle = () => {
|
|
360
|
+
clearInterval(poll);
|
|
361
|
+
if (grace)
|
|
362
|
+
clearTimeout(grace);
|
|
363
|
+
};
|
|
364
|
+
run.then((v) => {
|
|
365
|
+
settle();
|
|
366
|
+
resolve(v);
|
|
367
|
+
}, (e) => {
|
|
368
|
+
settle();
|
|
369
|
+
reject(e);
|
|
370
|
+
});
|
|
361
371
|
});
|
|
362
372
|
}
|
|
363
373
|
/** Returned instead of waiting forever for a tool that ignored Stop. */
|
|
@@ -373,19 +383,38 @@ function stopAwaiting(run, abort) {
|
|
|
373
383
|
let grace = null;
|
|
374
384
|
const poll = setInterval(() => {
|
|
375
385
|
if (abort.aborted && !grace)
|
|
376
|
-
grace = setTimeout(() => {
|
|
386
|
+
grace = setTimeout(() => {
|
|
387
|
+
clearInterval(poll);
|
|
388
|
+
resolve(exports.STOP_TIMEOUT_RESULT);
|
|
389
|
+
}, STOP_GRACE_MS);
|
|
377
390
|
}, 200);
|
|
378
|
-
const settle = () => {
|
|
379
|
-
|
|
380
|
-
|
|
391
|
+
const settle = () => {
|
|
392
|
+
clearInterval(poll);
|
|
393
|
+
if (grace)
|
|
394
|
+
clearTimeout(grace);
|
|
395
|
+
};
|
|
396
|
+
run.then((v) => {
|
|
397
|
+
settle();
|
|
398
|
+
resolve(v);
|
|
399
|
+
}, (e) => {
|
|
400
|
+
settle();
|
|
401
|
+
reject(e);
|
|
402
|
+
});
|
|
381
403
|
});
|
|
382
404
|
}
|
|
383
405
|
/** Default turn limit for a sub-agent whose definition sets no `maxTurns`. */
|
|
384
406
|
exports.DEFAULT_SUBAGENT_MAX_TURNS = 200;
|
|
385
407
|
/** Stop reasons that mean the sub-agent did NOT deliver a finished report. */
|
|
386
408
|
exports.ABNORMAL_SUBAGENT_STOPS = new Set([
|
|
387
|
-
'budget',
|
|
388
|
-
'
|
|
409
|
+
'budget',
|
|
410
|
+
'stalled',
|
|
411
|
+
'stalled-repeat',
|
|
412
|
+
'output-limit',
|
|
413
|
+
'empty-response',
|
|
414
|
+
'no-balance',
|
|
415
|
+
'no-team-budget',
|
|
416
|
+
'team-unavailable',
|
|
417
|
+
'reported-elsewhere',
|
|
389
418
|
// A hook stopping the batch means the sub-agent stopped short of its report, so the
|
|
390
419
|
// parent must not read the result as a finished one.
|
|
391
420
|
'hook-blocked',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testIntegrity.d.ts","sourceRoot":"","sources":["../../src/agent/testIntegrity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,MAAM,WAAW,eAAe;IAC9B,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,IAAI,EAAE,YAAY,GAAG,mBAAmB,GAAG,iBAAiB,GAAG,kBAAkB,GAAG,gBAAgB,CAAC;CACtG;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAQD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGhD;AA4ED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,mBAAmB,CAmDnG;AAED;;;;;;;GAOG;AACH,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GACzC,mBAAmB,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"testIntegrity.d.ts","sourceRoot":"","sources":["../../src/agent/testIntegrity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,MAAM,WAAW,eAAe;IAC9B,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,IAAI,EAAE,YAAY,GAAG,mBAAmB,GAAG,iBAAiB,GAAG,kBAAkB,GAAG,gBAAgB,CAAC;CACtG;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAQD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGhD;AA4ED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,mBAAmB,CAmDnG;AAED;;;;;;;GAOG;AACH,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GACzC,mBAAmB,GAAG,IAAI,CAiC5B;AAcD,kFAAkF;AAClF,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,MAAM,CAI7E;AAED,8EAA8E;AAC9E,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAQ9E;AAED,gFAAgF;AAChF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAQ3E"}
|
|
@@ -176,8 +176,10 @@ function analyzeTestEdit(path, oldText, newText) {
|
|
|
176
176
|
function analyzeWriteToolForTestIntegrity(toolName, input) {
|
|
177
177
|
if (!input)
|
|
178
178
|
return null;
|
|
179
|
-
const path = typeof input.path === 'string'
|
|
180
|
-
|
|
179
|
+
const path = typeof input.path === 'string'
|
|
180
|
+
? input.path
|
|
181
|
+
: typeof input.file_path === 'string'
|
|
182
|
+
? input.file_path
|
|
181
183
|
: '';
|
|
182
184
|
if (!isTestFile(path))
|
|
183
185
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolDescriptions.d.ts","sourceRoot":"","sources":["../../src/agent/toolDescriptions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"toolDescriptions.d.ts","sourceRoot":"","sources":["../../src/agent/toolDescriptions.ts"],"names":[],"mappings":"AAMA,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,iBAAiB,EAAE,WAAW,EAAE,GAAG,MAAM,CASxF;AAID,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CA2HrF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolPrefetch.d.ts","sourceRoot":"","sources":["../../src/agent/toolPrefetch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C;;;;;;;;;;;;;;;;;;GAkBG;AAEH,kFAAkF;AAClF,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"toolPrefetch.d.ts","sourceRoot":"","sources":["../../src/agent/toolPrefetch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C;;;;;;;;;;;;;;;;;;GAkBG;AAEH,kFAAkF;AAClF,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAAoE,CAAC;AAuBxH,kEAAkE;AAClE,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAE3E;AAED,qFAAqF;AACrF,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAYD,KAAK,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAEpF,qBAAa,cAAc;IAGb,OAAO,CAAC,QAAQ,CAAC,GAAG;IAFhC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkF;gBAE7E,GAAG,EAAE,MAAM;IAExC,kEAAkE;IAClE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;IAaxE;;;OAGG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI;IAQ1F,0FAA0F;IAC1F,KAAK,IAAI,IAAI;IAIb,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
|
|
@@ -23,12 +23,7 @@ exports.toolPrefetchEnabled = toolPrefetchEnabled;
|
|
|
23
23
|
* early read could observe state from BEFORE a write the model ordered first.
|
|
24
24
|
*/
|
|
25
25
|
/** Built-in tools that only read the filesystem — safe to run before approval. */
|
|
26
|
-
exports.PREFETCHABLE_TOOLS = new Set([
|
|
27
|
-
'read_file',
|
|
28
|
-
'list_directory',
|
|
29
|
-
'glob',
|
|
30
|
-
'search_files',
|
|
31
|
-
]);
|
|
26
|
+
exports.PREFETCHABLE_TOOLS = new Set(['read_file', 'list_directory', 'glob', 'search_files']);
|
|
32
27
|
/**
|
|
33
28
|
* Tools that may share a message with a prefetched read without invalidating it:
|
|
34
29
|
* they cannot change files in the workspace.
|
|
@@ -36,12 +31,18 @@ exports.PREFETCHABLE_TOOLS = new Set([
|
|
|
36
31
|
const NON_MUTATING_COMPANIONS = new Set([
|
|
37
32
|
...exports.PREFETCHABLE_TOOLS,
|
|
38
33
|
'notebook_read',
|
|
39
|
-
'todo_write',
|
|
34
|
+
'todo_write',
|
|
35
|
+
'todo_read',
|
|
40
36
|
'memory_read',
|
|
41
37
|
'use_skill',
|
|
42
|
-
'fetch_url',
|
|
43
|
-
'
|
|
44
|
-
'
|
|
38
|
+
'fetch_url',
|
|
39
|
+
'web_search',
|
|
40
|
+
'get_diagnostics',
|
|
41
|
+
'go_to_definition',
|
|
42
|
+
'find_references',
|
|
43
|
+
'get_symbols',
|
|
44
|
+
'get_workspace_symbols',
|
|
45
|
+
'get_hover',
|
|
45
46
|
]);
|
|
46
47
|
/** True when no tool in this message can mutate the workspace. */
|
|
47
48
|
function isPrefetchSafeMessage(toolNames) {
|
|
@@ -57,7 +58,10 @@ function stableKey(value) {
|
|
|
57
58
|
if (Array.isArray(value))
|
|
58
59
|
return `[${value.map(stableKey).join(',')}]`;
|
|
59
60
|
const obj = value;
|
|
60
|
-
return `{${Object.keys(obj)
|
|
61
|
+
return `{${Object.keys(obj)
|
|
62
|
+
.sort()
|
|
63
|
+
.map((k) => `${JSON.stringify(k)}:${stableKey(obj[k])}`)
|
|
64
|
+
.join(',')}}`;
|
|
61
65
|
}
|
|
62
66
|
class ToolPrefetcher {
|
|
63
67
|
constructor(run) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trust.d.ts","sourceRoot":"","sources":["../../src/agent/trust.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"trust.d.ts","sourceRoot":"","sources":["../../src/agent/trust.ts"],"names":[],"mappings":"AA0FA,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CA4ExD"}
|
package/dist/agent/trust.js
CHANGED
|
@@ -118,7 +118,9 @@ function agentFilesWithHooks(dir) {
|
|
|
118
118
|
if (fm && /^hooks\s*:/im.test(fm[1]))
|
|
119
119
|
found.push(path.relative(dir, full).replace(/\\/g, '/'));
|
|
120
120
|
}
|
|
121
|
-
catch {
|
|
121
|
+
catch {
|
|
122
|
+
/* unreadable — not a signal */
|
|
123
|
+
}
|
|
122
124
|
}
|
|
123
125
|
};
|
|
124
126
|
walk(root, 0);
|
|
@@ -163,7 +165,9 @@ function detectTrustSignals(dir) {
|
|
|
163
165
|
const obj = JSON.parse(raw);
|
|
164
166
|
hasHooks = Boolean(obj.hooks && typeof obj.hooks === 'object' && Object.keys(obj.hooks).length > 0);
|
|
165
167
|
}
|
|
166
|
-
catch {
|
|
168
|
+
catch {
|
|
169
|
+
/* absent or malformed — treated as no hooks declared */
|
|
170
|
+
}
|
|
167
171
|
const bits = ['.nexrall/settings.json — project settings and permission rules'];
|
|
168
172
|
if (declaresPluginSources(dir))
|
|
169
173
|
bits.push('declares plugin sources (aliases for remote plugin repos)');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/agent/worktree.ts"],"names":[],"mappings":"AA+CA,MAAM,WAAW,aAAa;IAC5B,mFAAmF;IACnF,YAAY,EAAE,MAAM,CAAC;IACrB,oFAAoF;IACpF,YAAY,EAAE,MAAM,CAAC;IACrB,yGAAyG;IACzG,OAAO,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,IAAI,EAAE,MAAM,CAAC;CACd;
|
|
1
|
+
{"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/agent/worktree.ts"],"names":[],"mappings":"AA+CA,MAAM,WAAW,aAAa;IAC5B,mFAAmF;IACnF,YAAY,EAAE,MAAM,CAAC;IACrB,oFAAoF;IACpF,YAAY,EAAE,MAAM,CAAC;IACrB,yGAAyG;IACzG,OAAO,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,IAAI,EAAE,MAAM,CAAC;CACd;AA0BD,iBAAS,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAY9D;AAED,2FAA2F;AAC3F,wBAAgB,kBAAkB,IAAI,MAAM,CAO3C;AAED,iBAAS,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMtC;AAED;;;;;GAKG;AACH,iBAAS,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAW5F;AAuBD,iBAAS,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAkBtD;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,oBAAoB,CAkD5F;AAED,MAAM,WAAW,qBAAqB;IACpC,sIAAsI;IACtI,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,OAAO,CAAC;IACZ,wIAAwI;IACxI,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,2EAA2E;AAC3E,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAsC7D;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,GAAE,qBAA0B,GAAG,oBAAoB,CA6D3G;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAWnF;AAiDD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAMlF;AAgBD,iBAAS,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAElD;AA6BD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CAoB9D;AAED,2FAA2F;AAC3F,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAEtF;AAED,eAAO,MAAM,iBAAiB;;;;;;;;CAQ7B,CAAC"}
|
package/dist/agent/worktree.js
CHANGED
|
@@ -98,18 +98,31 @@ const WORKTREE_ROOT_DIRNAME = '.nexrall/worktrees';
|
|
|
98
98
|
// reproducible artifacts. A project can still get everything copied verbatim
|
|
99
99
|
// by using its OWN hook instead of the built-in copy fallback.
|
|
100
100
|
const COPY_SKIP_DIRS = new Set([
|
|
101
|
-
'.git',
|
|
102
|
-
'
|
|
101
|
+
'.git',
|
|
102
|
+
'node_modules',
|
|
103
|
+
'dist',
|
|
104
|
+
'build',
|
|
105
|
+
'.next',
|
|
106
|
+
'__pycache__',
|
|
107
|
+
'.venv',
|
|
108
|
+
'venv',
|
|
109
|
+
'.nexrall',
|
|
110
|
+
'.svn',
|
|
111
|
+
'.hg',
|
|
103
112
|
]);
|
|
104
113
|
function isGitRepo(dir) {
|
|
105
114
|
try {
|
|
106
115
|
const r = (0, child_process_1.spawnSync)('git', ['rev-parse', '--show-toplevel'], {
|
|
107
|
-
cwd: dir,
|
|
116
|
+
cwd: dir,
|
|
117
|
+
encoding: 'utf-8',
|
|
118
|
+
timeout: 5000,
|
|
108
119
|
});
|
|
109
120
|
if (r.status === 0 && r.stdout)
|
|
110
121
|
return { ok: true, root: r.stdout.trim() };
|
|
111
122
|
}
|
|
112
|
-
catch {
|
|
123
|
+
catch {
|
|
124
|
+
/* git not installed or not a repo */
|
|
125
|
+
}
|
|
113
126
|
return { ok: false };
|
|
114
127
|
}
|
|
115
128
|
/** Generate a readable random name, same shape Claude Code uses ("bright-running-fox"). */
|
|
@@ -177,7 +190,9 @@ function copyRecursive(src, dest) {
|
|
|
177
190
|
try {
|
|
178
191
|
fs.symlinkSync(fs.readlinkSync(s), d);
|
|
179
192
|
}
|
|
180
|
-
catch {
|
|
193
|
+
catch {
|
|
194
|
+
/* best-effort */
|
|
195
|
+
}
|
|
181
196
|
}
|
|
182
197
|
else if (entry.isDirectory()) {
|
|
183
198
|
copyRecursive(s, d);
|
|
@@ -222,7 +237,11 @@ function createWorktree(workDir, requestedName) {
|
|
|
222
237
|
if (git.ok && git.root) {
|
|
223
238
|
fs.mkdirSync(root, { recursive: true });
|
|
224
239
|
const branch = `worktree-${name}`;
|
|
225
|
-
const r = (0, child_process_1.spawnSync)('git', ['worktree', 'add', '-b', branch, worktreePath], {
|
|
240
|
+
const r = (0, child_process_1.spawnSync)('git', ['worktree', 'add', '-b', branch, worktreePath], {
|
|
241
|
+
cwd: git.root,
|
|
242
|
+
encoding: 'utf-8',
|
|
243
|
+
timeout: 30000,
|
|
244
|
+
});
|
|
226
245
|
if (r.status !== 0) {
|
|
227
246
|
return { ok: false, error: `git worktree add failed: ${(r.stderr ?? r.stdout ?? '').trim() || 'unknown error'}` };
|
|
228
247
|
}
|
|
@@ -246,7 +265,9 @@ function worktreeHasWork(state) {
|
|
|
246
265
|
if (state.backend === 'git') {
|
|
247
266
|
try {
|
|
248
267
|
const status = (0, child_process_1.spawnSync)('git', ['status', '--porcelain'], {
|
|
249
|
-
cwd: state.worktreePath,
|
|
268
|
+
cwd: state.worktreePath,
|
|
269
|
+
encoding: 'utf-8',
|
|
270
|
+
timeout: 10000,
|
|
250
271
|
});
|
|
251
272
|
// Filter our own bookkeeping file out of the porcelain output before
|
|
252
273
|
// deciding — see writeMetadata's comment on why this is filtered here
|
|
@@ -258,7 +279,11 @@ function worktreeHasWork(state) {
|
|
|
258
279
|
if (meaningfulLines.length > 0)
|
|
259
280
|
return true;
|
|
260
281
|
// Also check for unpushed commits on the worktree's own branch.
|
|
261
|
-
const unpushed = (0, child_process_1.spawnSync)('git', ['log', '@{u}..HEAD', '--oneline'], {
|
|
282
|
+
const unpushed = (0, child_process_1.spawnSync)('git', ['log', '@{u}..HEAD', '--oneline'], {
|
|
283
|
+
cwd: state.worktreePath,
|
|
284
|
+
encoding: 'utf-8',
|
|
285
|
+
timeout: 10000,
|
|
286
|
+
});
|
|
262
287
|
if (unpushed.status === 0 && unpushed.stdout && unpushed.stdout.trim().length > 0)
|
|
263
288
|
return true;
|
|
264
289
|
return false;
|
|
@@ -283,7 +308,11 @@ function removeWorktree(state, opts = {}) {
|
|
|
283
308
|
if (!opts.force && worktreeHasWork(state)) {
|
|
284
309
|
return { ok: false, hadWork: true };
|
|
285
310
|
}
|
|
286
|
-
const hookEnv = {
|
|
311
|
+
const hookEnv = {
|
|
312
|
+
NEXRALL_WORKTREE_NAME: state.name,
|
|
313
|
+
NEXRALL_WORKTREE_PATH: state.worktreePath,
|
|
314
|
+
NEXRALL_MAIN_CHECKOUT: state.mainCheckout,
|
|
315
|
+
};
|
|
287
316
|
if (state.backend === 'hook') {
|
|
288
317
|
const hook = runWorktreeHook(state.mainCheckout, 'exit', hookEnv);
|
|
289
318
|
if (hook.ran && !hook.ok)
|
|
@@ -304,10 +333,19 @@ function removeWorktree(state, opts = {}) {
|
|
|
304
333
|
try {
|
|
305
334
|
fs.unlinkSync(metadataPath(state.worktreePath));
|
|
306
335
|
}
|
|
307
|
-
catch {
|
|
308
|
-
|
|
336
|
+
catch {
|
|
337
|
+
/* fine if already gone */
|
|
338
|
+
}
|
|
339
|
+
const r = (0, child_process_1.spawnSync)('git', ['worktree', 'remove', state.worktreePath, ...(opts.force ? ['--force'] : [])], {
|
|
340
|
+
cwd: state.mainCheckout,
|
|
341
|
+
encoding: 'utf-8',
|
|
342
|
+
timeout: 30000,
|
|
343
|
+
});
|
|
309
344
|
if (r.status !== 0) {
|
|
310
|
-
return {
|
|
345
|
+
return {
|
|
346
|
+
ok: false,
|
|
347
|
+
error: `git worktree remove failed: ${(r.stderr ?? r.stdout ?? '').trim() || 'unknown error'}`,
|
|
348
|
+
};
|
|
311
349
|
}
|
|
312
350
|
// Also drop the branch — an unnamed worktree's branch is disposable once
|
|
313
351
|
// its worktree is gone (mirrors Claude Code's automatic cleanup for
|
|
@@ -338,7 +376,11 @@ function removeWorktree(state, opts = {}) {
|
|
|
338
376
|
function enterWorktree(state) {
|
|
339
377
|
if (state.backend !== 'hook')
|
|
340
378
|
return { ok: true };
|
|
341
|
-
const hookEnv = {
|
|
379
|
+
const hookEnv = {
|
|
380
|
+
NEXRALL_WORKTREE_NAME: state.name,
|
|
381
|
+
NEXRALL_WORKTREE_PATH: state.worktreePath,
|
|
382
|
+
NEXRALL_MAIN_CHECKOUT: state.mainCheckout,
|
|
383
|
+
};
|
|
342
384
|
const hook = runWorktreeHook(state.mainCheckout, 'enter', hookEnv);
|
|
343
385
|
if (hook.ran && !hook.ok)
|
|
344
386
|
return { ok: false, error: `worktree-enter hook failed: ${hook.output ?? 'unknown error'}` };
|
|
@@ -374,7 +416,9 @@ function realOrLexical(p) {
|
|
|
374
416
|
try {
|
|
375
417
|
return fs.realpathSync(p);
|
|
376
418
|
}
|
|
377
|
-
catch {
|
|
419
|
+
catch {
|
|
420
|
+
/* fall through — p (or a piece of it) doesn't exist yet */
|
|
421
|
+
}
|
|
378
422
|
let dir = path.dirname(p);
|
|
379
423
|
const tail = [path.basename(p)];
|
|
380
424
|
for (;;) {
|
|
@@ -449,7 +493,9 @@ function writeMetadata(state) {
|
|
|
449
493
|
// filename out of `git status --porcelain`'s output directly — no shared
|
|
450
494
|
// state touched, no risk to the main checkout.
|
|
451
495
|
}
|
|
452
|
-
catch {
|
|
496
|
+
catch {
|
|
497
|
+
/* best-effort */
|
|
498
|
+
}
|
|
453
499
|
}
|
|
454
500
|
function readMetadata(worktreePath) {
|
|
455
501
|
try {
|
|
@@ -498,5 +544,13 @@ function listWorktrees(workDir) {
|
|
|
498
544
|
function findWorktreeByName(workDir, name) {
|
|
499
545
|
return listWorktrees(workDir).find((w) => w.name === name) ?? null;
|
|
500
546
|
}
|
|
501
|
-
exports._worktreeInternal = {
|
|
547
|
+
exports._worktreeInternal = {
|
|
548
|
+
isGitRepo,
|
|
549
|
+
safeName,
|
|
550
|
+
copyRecursive,
|
|
551
|
+
findWorktreeHook,
|
|
552
|
+
COPY_SKIP_DIRS,
|
|
553
|
+
WORKTREE_ROOT_DIRNAME,
|
|
554
|
+
metadataPath,
|
|
555
|
+
};
|
|
502
556
|
//# sourceMappingURL=worktree.js.map
|