praxis-agent 0.36.0 → 0.37.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 +16 -2
- package/dist/application/durable-follow-up.d.ts +14 -0
- package/dist/application/durable-follow-up.js +52 -0
- package/dist/application/native-session-transcript.d.ts +72 -0
- package/dist/application/native-session-transcript.js +351 -0
- package/dist/application/native-sidechain-transcript.d.ts +34 -0
- package/dist/application/native-sidechain-transcript.js +156 -0
- package/dist/application/session-service.d.ts +15 -0
- package/dist/application/session-service.js +611 -69
- package/dist/application/subagent-service.d.ts +5 -1
- package/dist/application/subagent-service.js +391 -143
- package/dist/application/team-agent-runtime.d.ts +29 -0
- package/dist/application/team-agent-runtime.js +169 -0
- package/dist/application/team-capability.d.ts +27 -0
- package/dist/application/team-capability.js +41 -0
- package/dist/application/team-lead-operations.d.ts +38 -0
- package/dist/application/team-lead-operations.js +155 -0
- package/dist/application/team-mailbox.d.ts +54 -0
- package/dist/application/team-mailbox.js +196 -0
- package/dist/application/team-manager.d.ts +113 -0
- package/dist/application/team-manager.js +681 -0
- package/dist/application/team-workspace.d.ts +29 -0
- package/dist/application/team-workspace.js +197 -0
- package/dist/application/transcript-projection.d.ts +2 -0
- package/dist/application/transcript-projection.js +30 -1
- package/dist/cli/interactive.d.ts +7 -0
- package/dist/cli/interactive.js +387 -136
- package/dist/cli/tui/claude-style.d.ts +8 -25
- package/dist/cli/tui/claude-style.js +158 -160
- package/dist/cli/tui/decision-surface-model.d.ts +71 -0
- package/dist/cli/tui/decision-surface-model.js +131 -0
- package/dist/cli/tui/decision-surface.d.ts +7 -0
- package/dist/cli/tui/decision-surface.js +41 -0
- package/dist/cli/tui/help-surface-model.d.ts +68 -0
- package/dist/cli/tui/help-surface-model.js +131 -0
- package/dist/cli/tui/mcp-panel.js +1 -2
- package/dist/cli/tui/permission-surface-model.d.ts +195 -0
- package/dist/cli/tui/permission-surface-model.js +360 -0
- package/dist/cli/tui/permission-surface.d.ts +7 -0
- package/dist/cli/tui/permission-surface.js +69 -0
- package/dist/cli/tui/presentation-environment.d.ts +32 -0
- package/dist/cli/tui/presentation-environment.js +149 -0
- package/dist/cli/tui/tool-permission.js +7 -3
- package/dist/cli/tui/transcript-presentation.d.ts +19 -1
- package/dist/cli/tui/transcript-presentation.js +26 -6
- package/dist/cli/tui/transcript-viewport.d.ts +18 -0
- package/dist/cli/tui/transcript-viewport.js +517 -111
- package/dist/cli/tui/transcript-window-model.d.ts +108 -0
- package/dist/cli/tui/transcript-window-model.js +772 -0
- package/dist/cli/tui/tui-screen-model.d.ts +114 -0
- package/dist/cli/tui/tui-screen-model.js +210 -0
- package/dist/cli/tui/tui-view-model.d.ts +2 -49
- package/dist/cli/tui/tui-view-model.js +1 -68
- package/dist/cli-runtime.d.ts +2 -0
- package/dist/cli-runtime.js +397 -32
- package/dist/compatibility/claude/transcript-codec.js +6 -0
- package/dist/core/permission-policy.d.ts +4 -0
- package/dist/core/permission-policy.js +21 -0
- package/dist/core/runtime.d.ts +1 -0
- package/dist/core/runtime.js +5 -1
- package/dist/core/team-mailbox.d.ts +54 -0
- package/dist/core/team-mailbox.js +212 -0
- package/dist/core/team-ownership.d.ts +84 -0
- package/dist/core/team-ownership.js +505 -0
- package/dist/core/tool-execution-scheduler.js +6 -1
- package/dist/core/transcript-event.d.ts +5 -1
- package/dist/core/transcript-event.js +12 -0
- package/dist/persistence/claude-transcript-store.d.ts +2 -1
- package/dist/persistence/claude-transcript-store.js +2 -10
- package/dist/persistence/native-team-mailbox.d.ts +68 -0
- package/dist/persistence/native-team-mailbox.js +542 -0
- package/dist/persistence/native-team-store.d.ts +34 -0
- package/dist/persistence/native-team-store.js +257 -0
- package/dist/persistence/native-transcript-store.d.ts +69 -0
- package/dist/persistence/native-transcript-store.js +321 -0
- package/dist/persistence/transcript-file-append.d.ts +2 -0
- package/dist/persistence/transcript-file-append.js +10 -0
- package/dist/tools/claude-capabilities.d.ts +4 -0
- package/dist/tools/claude-capabilities.js +18 -2
- package/dist/tools/team-lead-tools.d.ts +19 -0
- package/dist/tools/team-lead-tools.js +479 -0
- package/dist/tools/team-member-tools.d.ts +21 -0
- package/dist/tools/team-member-tools.js +259 -0
- package/package.json +1 -1
- package/dist/cli/tui/fullscreen-renderer.d.ts +0 -14
- package/dist/cli/tui/fullscreen-renderer.js +0 -13
|
@@ -12,6 +12,7 @@ import { injectFirstUserMessageContext, projectContextSnapshot, } from '../core/
|
|
|
12
12
|
import { assembleContextSnapshot } from '../core/prompt-composer.js';
|
|
13
13
|
import { ContextBudget } from '../core/context-budget.js';
|
|
14
14
|
import { AgentRuntime, } from '../core/runtime.js';
|
|
15
|
+
import { composePermissionResolvers } from '../core/permission-policy.js';
|
|
15
16
|
import { resolveToolSchedulingPolicy } from '../core/tool-scheduling-policy.js';
|
|
16
17
|
import { BUILTIN_STATUSLINE_AGENT_PATH, } from '../extensions/claude-extensions.js';
|
|
17
18
|
import { ClaudeHookToolCoordinator } from '../hooks/claude-hook-tools.js';
|
|
@@ -23,6 +24,8 @@ import { BackgroundAgentManager, BackgroundAgentRunError, BackgroundAgentShutdow
|
|
|
23
24
|
import { isBackgroundBashTaskId } from './background-task-id.js';
|
|
24
25
|
import { createManagedWorktree, restoreManagedWorktree, } from './managed-worktree.js';
|
|
25
26
|
import { createWorkflowWorktree } from './workflow-worktree.js';
|
|
27
|
+
import { NativeSidechainTranscript, } from './native-sidechain-transcript.js';
|
|
28
|
+
import { DurableFollowUpTracker, } from './durable-follow-up.js';
|
|
26
29
|
const DEFAULT_MAX_DEPTH = 4;
|
|
27
30
|
const DEFAULT_MAX_CALLS = 16;
|
|
28
31
|
const DEFAULT_MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
@@ -128,6 +131,48 @@ async function readSidechainMetadataName(metadataFile) {
|
|
|
128
131
|
return undefined;
|
|
129
132
|
}
|
|
130
133
|
}
|
|
134
|
+
function projectNativeSidechainContinuationMessages(messages) {
|
|
135
|
+
const callCounts = new Map();
|
|
136
|
+
const resultCounts = new Map();
|
|
137
|
+
for (const message of messages) {
|
|
138
|
+
if (message.role === 'assistant') {
|
|
139
|
+
for (const call of message.toolCalls ?? [])
|
|
140
|
+
callCounts.set(call.id, (callCounts.get(call.id) ?? 0) + 1);
|
|
141
|
+
}
|
|
142
|
+
else if (message.role === 'tool') {
|
|
143
|
+
resultCounts.set(message.toolCallId, (resultCounts.get(message.toolCallId) ?? 0) + 1);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
for (const [callId, count] of callCounts) {
|
|
147
|
+
if (count > 1)
|
|
148
|
+
throw new Error(`Native sidechain continuation has duplicate tool ID ${callId}`);
|
|
149
|
+
}
|
|
150
|
+
for (const [callId, count] of resultCounts) {
|
|
151
|
+
if (count > 1)
|
|
152
|
+
throw new Error(`Native sidechain continuation has duplicate tool result ${callId}`);
|
|
153
|
+
}
|
|
154
|
+
const resolved = new Set([...callCounts.keys()].filter((callId) => resultCounts.get(callId) === 1));
|
|
155
|
+
return messages.flatMap((message) => {
|
|
156
|
+
if (message.role === 'assistant') {
|
|
157
|
+
const toolCalls = (message.toolCalls ?? []).filter((call) => resolved.has(call.id));
|
|
158
|
+
if (message.content.trim() === '' && toolCalls.length === 0)
|
|
159
|
+
return [];
|
|
160
|
+
return [
|
|
161
|
+
{
|
|
162
|
+
role: 'assistant',
|
|
163
|
+
content: message.content,
|
|
164
|
+
...(message.thinkingBlocks
|
|
165
|
+
? { thinkingBlocks: message.thinkingBlocks }
|
|
166
|
+
: {}),
|
|
167
|
+
...(toolCalls.length === 0 ? {} : { toolCalls }),
|
|
168
|
+
},
|
|
169
|
+
];
|
|
170
|
+
}
|
|
171
|
+
if (message.role === 'tool' && !resolved.has(message.toolCallId))
|
|
172
|
+
return [];
|
|
173
|
+
return [message];
|
|
174
|
+
});
|
|
175
|
+
}
|
|
131
176
|
export class StructuredOutputRegistry {
|
|
132
177
|
base;
|
|
133
178
|
schema;
|
|
@@ -459,8 +504,19 @@ export class ClaudeSubagentExecutor {
|
|
|
459
504
|
}
|
|
460
505
|
constructor(options) {
|
|
461
506
|
this.options = options;
|
|
507
|
+
if (options.experimentalNativeTranscriptWrites === true &&
|
|
508
|
+
(options.dataPlane !== 'native' || options.persistence !== 'disk')) {
|
|
509
|
+
throw new Error('experimental native transcript writes require native dataPlane and disk persistence');
|
|
510
|
+
}
|
|
511
|
+
if (options.experimentalNativeTranscriptWrites === true &&
|
|
512
|
+
options.hooks !== undefined) {
|
|
513
|
+
throw new Error('experimental native sidechain writes do not support Claude hooks');
|
|
514
|
+
}
|
|
462
515
|
this.schema = selectClaudeSchemaAdapter(options.claudeVersion);
|
|
463
516
|
}
|
|
517
|
+
nativeSidechainWritesEnabled() {
|
|
518
|
+
return this.options.experimentalNativeTranscriptWrites === true;
|
|
519
|
+
}
|
|
464
520
|
async close() {
|
|
465
521
|
for (const agentId of [...this.foreground.keys()]) {
|
|
466
522
|
this.backgroundForegroundTask(agentId);
|
|
@@ -763,20 +819,30 @@ export class ClaudeSubagentExecutor {
|
|
|
763
819
|
return settleInitialSetupFailure(error, initialIsolation);
|
|
764
820
|
}
|
|
765
821
|
const agentCwd = initialIsolation?.cwd ?? parentCwd;
|
|
766
|
-
const
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
822
|
+
const nativeSidechain = this.nativeSidechainWritesEnabled()
|
|
823
|
+
? new NativeSidechainTranscript({
|
|
824
|
+
...sidechainPaths,
|
|
825
|
+
lockFile: join(paths.praxisRoot, 'locks', `${sessionId}-${agentId}.lock`),
|
|
826
|
+
})
|
|
827
|
+
: undefined;
|
|
828
|
+
const claudeSidechain = nativeSidechain
|
|
829
|
+
? undefined
|
|
830
|
+
: this.sidechainStore(sessionId, agentId, sidechainPaths, paths.praxisRoot);
|
|
831
|
+
const root = nativeSidechain
|
|
832
|
+
? undefined
|
|
833
|
+
: createClaudeSidechainRoot({
|
|
834
|
+
sessionId,
|
|
835
|
+
promptId,
|
|
836
|
+
prompt: input.prompt,
|
|
837
|
+
agentId,
|
|
838
|
+
cwd: agentCwd,
|
|
839
|
+
claudeVersion: this.options.claudeVersion,
|
|
840
|
+
gitBranch: null,
|
|
841
|
+
uuid: randomUUID(),
|
|
842
|
+
timestamp: new Date().toISOString(),
|
|
843
|
+
});
|
|
778
844
|
try {
|
|
779
|
-
|
|
845
|
+
const metadata = {
|
|
780
846
|
agentType: input.subagentType,
|
|
781
847
|
description: input.description,
|
|
782
848
|
toolUseId: call.id,
|
|
@@ -788,7 +854,19 @@ export class ClaudeSubagentExecutor {
|
|
|
788
854
|
...(input.isolation ? { isolation: input.isolation } : {}),
|
|
789
855
|
...(parentAgentId ? { parentAgentId } : {}),
|
|
790
856
|
...(initialIsolation ? { worktreePath: initialIsolation.cwd } : {}),
|
|
791
|
-
}
|
|
857
|
+
};
|
|
858
|
+
if (nativeSidechain) {
|
|
859
|
+
await nativeSidechain.create(input.prompt, {
|
|
860
|
+
...metadata,
|
|
861
|
+
cwd: agentCwd,
|
|
862
|
+
promptId,
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
else {
|
|
866
|
+
if (!claudeSidechain || !root)
|
|
867
|
+
throw new Error('Claude sidechain initialization is unavailable');
|
|
868
|
+
await claudeSidechain.create(root, metadata);
|
|
869
|
+
}
|
|
792
870
|
}
|
|
793
871
|
catch (error) {
|
|
794
872
|
return settleInitialSetupFailure(error, initialIsolation);
|
|
@@ -803,21 +881,28 @@ export class ClaudeSubagentExecutor {
|
|
|
803
881
|
...(initialExecution ? { initialExecution } : {}),
|
|
804
882
|
...(initialIsolation ? { initialIsolation } : {}),
|
|
805
883
|
createIsolation: () => this.createAgentWorktree(paths.praxisRoot, sessionId, agentId, parentCwd),
|
|
806
|
-
execute: (cwd, message, signal, continuation) =>
|
|
807
|
-
lease
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
884
|
+
execute: async (cwd, message, signal, continuation) => {
|
|
885
|
+
const run = (lease) => this.runSidechain({
|
|
886
|
+
...lease,
|
|
887
|
+
sessionId,
|
|
888
|
+
input,
|
|
889
|
+
provider,
|
|
890
|
+
agentId,
|
|
891
|
+
spawnDepth,
|
|
892
|
+
promptId,
|
|
893
|
+
toolUseId: call.id,
|
|
894
|
+
transcriptPath: sidechainPaths.transcriptFile,
|
|
895
|
+
toolResultDirectory: join(paths.projectRoot, sessionId, 'tool-results'),
|
|
896
|
+
...(continuation ? { continuationMessage: message } : {}),
|
|
897
|
+
signal,
|
|
898
|
+
cwd,
|
|
899
|
+
});
|
|
900
|
+
if (nativeSidechain)
|
|
901
|
+
return nativeSidechain.withLease((nativeLease) => run({ nativeLease }));
|
|
902
|
+
if (!claudeSidechain)
|
|
903
|
+
throw new Error('Claude sidechain execution is unavailable');
|
|
904
|
+
return claudeSidechain.withLease((claudeLease) => run({ claudeLease }));
|
|
905
|
+
},
|
|
821
906
|
});
|
|
822
907
|
const resolvedModel = provider.model ?? 'praxis/provider';
|
|
823
908
|
const spec = {
|
|
@@ -1314,7 +1399,13 @@ export class ClaudeSubagentExecutor {
|
|
|
1314
1399
|
metadataFile: agentFiles.metadataFile,
|
|
1315
1400
|
};
|
|
1316
1401
|
const sessionPaths = this.sessionPaths(options.sessionId);
|
|
1317
|
-
const
|
|
1402
|
+
const lockFile = join(sessionPaths.praxisRoot, 'locks', `${options.sessionId}-${options.runId}-${options.agentId}.lock`);
|
|
1403
|
+
const nativeSidechain = this.nativeSidechainWritesEnabled()
|
|
1404
|
+
? new NativeSidechainTranscript({ ...paths, lockFile })
|
|
1405
|
+
: undefined;
|
|
1406
|
+
const claudeSidechain = nativeSidechain
|
|
1407
|
+
? undefined
|
|
1408
|
+
: new ClaudeSidechainStore(paths, lockFile, this.schema);
|
|
1318
1409
|
const isolation = options.isolation
|
|
1319
1410
|
? await createWorkflowWorktree({
|
|
1320
1411
|
cwd: this.cwd(),
|
|
@@ -1324,29 +1415,47 @@ export class ClaudeSubagentExecutor {
|
|
|
1324
1415
|
})
|
|
1325
1416
|
: null;
|
|
1326
1417
|
const agentCwd = isolation?.cwd ?? this.cwd();
|
|
1327
|
-
const root =
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1418
|
+
const root = nativeSidechain
|
|
1419
|
+
? undefined
|
|
1420
|
+
: createClaudeSidechainRoot({
|
|
1421
|
+
sessionId: options.sessionId,
|
|
1422
|
+
promptId: options.promptId,
|
|
1423
|
+
prompt: options.prompt,
|
|
1424
|
+
agentId: options.agentId,
|
|
1425
|
+
cwd: agentCwd,
|
|
1426
|
+
claudeVersion: this.options.claudeVersion,
|
|
1427
|
+
gitBranch: null,
|
|
1428
|
+
uuid: randomUUID(),
|
|
1429
|
+
timestamp: new Date().toISOString(),
|
|
1430
|
+
});
|
|
1338
1431
|
const startedAt = Date.now();
|
|
1339
1432
|
const structured = { calls: 0, value: undefined };
|
|
1340
1433
|
let run;
|
|
1341
1434
|
let cleanup;
|
|
1342
1435
|
try {
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1436
|
+
if (nativeSidechain) {
|
|
1437
|
+
await nativeSidechain.create(options.prompt, {
|
|
1438
|
+
agentType: options.agentType ?? 'workflow-subagent',
|
|
1439
|
+
description: input.description,
|
|
1440
|
+
toolUseId: `workflow:${options.runId}`,
|
|
1441
|
+
spawnDepth: 1,
|
|
1442
|
+
cwd: agentCwd,
|
|
1443
|
+
promptId: options.promptId,
|
|
1444
|
+
...(options.isolation ? { isolation: options.isolation } : {}),
|
|
1445
|
+
...(isolation ? { worktreePath: isolation.cwd } : {}),
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1448
|
+
else {
|
|
1449
|
+
if (!claudeSidechain || !root)
|
|
1450
|
+
throw new Error('Claude workflow sidechain is unavailable');
|
|
1451
|
+
await claudeSidechain.createWorkflow(root, {
|
|
1452
|
+
agentType: options.agentType ?? 'workflow-subagent',
|
|
1453
|
+
spawnDepth: 1,
|
|
1454
|
+
});
|
|
1455
|
+
}
|
|
1456
|
+
const runWithLease = (lease) => this.runSidechain({
|
|
1457
|
+
...lease,
|
|
1458
|
+
sessionId: options.sessionId,
|
|
1350
1459
|
input,
|
|
1351
1460
|
provider,
|
|
1352
1461
|
agentId: options.agentId,
|
|
@@ -1360,7 +1469,15 @@ export class ClaudeSubagentExecutor {
|
|
|
1360
1469
|
...(options.effort ? { effort: options.effort } : {}),
|
|
1361
1470
|
...(options.signal ? { signal: options.signal } : {}),
|
|
1362
1471
|
cwd: agentCwd,
|
|
1363
|
-
})
|
|
1472
|
+
});
|
|
1473
|
+
if (nativeSidechain) {
|
|
1474
|
+
run = await nativeSidechain.withLease((nativeLease) => runWithLease({ nativeLease }));
|
|
1475
|
+
}
|
|
1476
|
+
else {
|
|
1477
|
+
if (!claudeSidechain)
|
|
1478
|
+
throw new Error('Claude workflow sidechain is unavailable');
|
|
1479
|
+
run = await claudeSidechain.withLease((claudeLease) => runWithLease({ claudeLease }));
|
|
1480
|
+
}
|
|
1364
1481
|
}
|
|
1365
1482
|
finally {
|
|
1366
1483
|
cleanup = await isolation?.cleanup();
|
|
@@ -1465,7 +1582,7 @@ export class ClaudeSubagentExecutor {
|
|
|
1465
1582
|
}
|
|
1466
1583
|
const agentId = String(call.input.to);
|
|
1467
1584
|
const summary = typeof call.input.summary === 'string' ? call.input.summary : undefined;
|
|
1468
|
-
const owned = this.options.sendOwnedBackgroundAgent?.(sessionId, agentId, String(call.input.message), summary, call.id);
|
|
1585
|
+
const owned = await this.options.sendOwnedBackgroundAgent?.(sessionId, agentId, String(call.input.message), summary, call.id);
|
|
1469
1586
|
if (owned !== undefined && owned !== null) {
|
|
1470
1587
|
return { content: owned, isError: false };
|
|
1471
1588
|
}
|
|
@@ -1528,34 +1645,48 @@ export class ClaudeSubagentExecutor {
|
|
|
1528
1645
|
if (!sidechainPaths)
|
|
1529
1646
|
return;
|
|
1530
1647
|
const agentId = sidechainPaths.agentId;
|
|
1531
|
-
const
|
|
1532
|
-
|
|
1648
|
+
const lockFile = join(paths.praxisRoot, 'locks', `${sessionId}-${agentId}.lock`);
|
|
1649
|
+
const nativeSidechain = this.nativeSidechainWritesEnabled()
|
|
1650
|
+
? new NativeSidechainTranscript({ ...sidechainPaths, lockFile })
|
|
1651
|
+
: undefined;
|
|
1652
|
+
const claudeSidechain = nativeSidechain
|
|
1653
|
+
? undefined
|
|
1654
|
+
: new ClaudeSidechainStore(sidechainPaths, lockFile, this.schema);
|
|
1655
|
+
let metadata = null;
|
|
1656
|
+
let root;
|
|
1657
|
+
let projected;
|
|
1533
1658
|
try {
|
|
1534
|
-
|
|
1659
|
+
if (nativeSidechain) {
|
|
1660
|
+
await nativeSidechain.loadReadOnly();
|
|
1661
|
+
metadata = await nativeSidechain.metadata();
|
|
1662
|
+
projected = await nativeSidechain.withLease(async (lease) => lease.activeMessages());
|
|
1663
|
+
}
|
|
1664
|
+
else {
|
|
1665
|
+
if (!claudeSidechain)
|
|
1666
|
+
throw new Error('Claude persisted sidechain is unavailable');
|
|
1667
|
+
const snapshot = await claudeSidechain.loadReadOnly();
|
|
1668
|
+
metadata = await claudeSidechain.metadata().catch((error) => {
|
|
1669
|
+
if (error.code === 'ENOENT')
|
|
1670
|
+
return null;
|
|
1671
|
+
throw error;
|
|
1672
|
+
});
|
|
1673
|
+
root = snapshot.entries[0];
|
|
1674
|
+
if (!root || root.type !== 'user') {
|
|
1675
|
+
throw new Error(`Background agent ${agentId} has no sidechain root`);
|
|
1676
|
+
}
|
|
1677
|
+
projected = projectClaudeModelMessages(snapshot.entries);
|
|
1678
|
+
}
|
|
1535
1679
|
}
|
|
1536
1680
|
catch (error) {
|
|
1537
1681
|
if (error.code === 'ENOENT')
|
|
1538
1682
|
return;
|
|
1539
1683
|
throw error;
|
|
1540
1684
|
}
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
metadata = await sidechain.metadata();
|
|
1544
|
-
}
|
|
1545
|
-
catch (error) {
|
|
1546
|
-
if (error.code !== 'ENOENT')
|
|
1547
|
-
throw error;
|
|
1548
|
-
}
|
|
1549
|
-
const root = snapshot.entries[0];
|
|
1550
|
-
if (!root || root.type !== 'user') {
|
|
1685
|
+
const rootMessage = projected[0];
|
|
1686
|
+
if (rootMessage?.role !== 'user' || rootMessage.content.trim() === '') {
|
|
1551
1687
|
throw new Error(`Background agent ${agentId} has no sidechain root`);
|
|
1552
1688
|
}
|
|
1553
|
-
const prompt =
|
|
1554
|
-
root.message !== null &&
|
|
1555
|
-
typeof root.message.content === 'string'
|
|
1556
|
-
? String(root.message.content)
|
|
1557
|
-
: '';
|
|
1558
|
-
const projected = projectClaudeModelMessages(snapshot.entries);
|
|
1689
|
+
const prompt = rootMessage.content;
|
|
1559
1690
|
const lastAssistant = projected.at(-1);
|
|
1560
1691
|
const completed = lastAssistant?.role === 'assistant' &&
|
|
1561
1692
|
lastAssistant.content.trim().length > 0 &&
|
|
@@ -1621,7 +1752,9 @@ export class ClaudeSubagentExecutor {
|
|
|
1621
1752
|
}
|
|
1622
1753
|
}
|
|
1623
1754
|
else {
|
|
1624
|
-
const persistedCwd =
|
|
1755
|
+
const persistedCwd = nativeSidechain
|
|
1756
|
+
? metadata.cwd
|
|
1757
|
+
: root?.cwd;
|
|
1625
1758
|
if (typeof persistedCwd === 'string' &&
|
|
1626
1759
|
persistedCwd.length > 0 &&
|
|
1627
1760
|
!persistedCwd.includes('\0') &&
|
|
@@ -1656,6 +1789,9 @@ export class ClaudeSubagentExecutor {
|
|
|
1656
1789
|
runInBackground: true,
|
|
1657
1790
|
};
|
|
1658
1791
|
const provider = this.options.provider;
|
|
1792
|
+
const recoveredPromptId = nativeSidechain
|
|
1793
|
+
? metadata.promptId
|
|
1794
|
+
: String(root?.promptId ?? randomUUID());
|
|
1659
1795
|
const backgroundRun = this.createBackgroundAgentRun({
|
|
1660
1796
|
input,
|
|
1661
1797
|
parentCwd: restoredCwd,
|
|
@@ -1664,21 +1800,28 @@ export class ClaudeSubagentExecutor {
|
|
|
1664
1800
|
initialLifecycleState: lifecycle.lifecycle.state,
|
|
1665
1801
|
...(restoredIsolation ? { initialIsolation: restoredIsolation } : {}),
|
|
1666
1802
|
createIsolation: () => this.createAgentWorktree(paths.praxisRoot, sessionId, agentId, parentCwd),
|
|
1667
|
-
execute: (cwd, message, signal, continuation) =>
|
|
1668
|
-
lease
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1803
|
+
execute: async (cwd, message, signal, continuation) => {
|
|
1804
|
+
const run = (lease) => this.runSidechain({
|
|
1805
|
+
...lease,
|
|
1806
|
+
sessionId,
|
|
1807
|
+
input,
|
|
1808
|
+
provider,
|
|
1809
|
+
agentId,
|
|
1810
|
+
spawnDepth,
|
|
1811
|
+
promptId: recoveredPromptId,
|
|
1812
|
+
toolUseId,
|
|
1813
|
+
transcriptPath: sidechainPaths.transcriptFile,
|
|
1814
|
+
toolResultDirectory: join(paths.projectRoot, sessionId, 'tool-results'),
|
|
1815
|
+
...(continuation ? { continuationMessage: message } : {}),
|
|
1816
|
+
signal,
|
|
1817
|
+
cwd,
|
|
1818
|
+
});
|
|
1819
|
+
if (nativeSidechain)
|
|
1820
|
+
return nativeSidechain.withLease((nativeLease) => run({ nativeLease }));
|
|
1821
|
+
if (!claudeSidechain)
|
|
1822
|
+
throw new Error('Claude persisted sidechain is unavailable');
|
|
1823
|
+
return claudeSidechain.withLease((claudeLease) => run({ claudeLease }));
|
|
1824
|
+
},
|
|
1682
1825
|
});
|
|
1683
1826
|
const spec = {
|
|
1684
1827
|
agentId,
|
|
@@ -1861,42 +2004,77 @@ export class ClaudeSubagentExecutor {
|
|
|
1861
2004
|
async runSidechain(options) {
|
|
1862
2005
|
const cwd = options.cwd ?? this.cwd();
|
|
1863
2006
|
const permissions = options.input.permissionMode && options.input.permissionMode !== 'default'
|
|
1864
|
-
?
|
|
2007
|
+
? (() => {
|
|
2008
|
+
const mode = options.input.permissionMode;
|
|
2009
|
+
if (!mode)
|
|
2010
|
+
return undefined;
|
|
2011
|
+
const child = this.options.permissionResolverForMode?.(mode);
|
|
2012
|
+
return child
|
|
2013
|
+
? composePermissionResolvers(this.options.permissions, child)
|
|
2014
|
+
: undefined;
|
|
2015
|
+
})()
|
|
1865
2016
|
: this.options.permissions;
|
|
1866
2017
|
if (!permissions) {
|
|
1867
2018
|
throw new Error('Agent permission mode overrides are unavailable');
|
|
1868
2019
|
}
|
|
1869
|
-
|
|
2020
|
+
if ((options.claudeLease === undefined) ===
|
|
2021
|
+
(options.nativeLease === undefined))
|
|
2022
|
+
throw new Error('Exactly one sidechain transcript lease is required');
|
|
2023
|
+
const claudeLease = options.claudeLease;
|
|
2024
|
+
const nativeLease = options.nativeLease;
|
|
2025
|
+
let snapshot = claudeLease
|
|
2026
|
+
? await claudeLease.load()
|
|
2027
|
+
: undefined;
|
|
2028
|
+
const requireClaudeSnapshot = () => {
|
|
2029
|
+
if (!snapshot)
|
|
2030
|
+
throw new Error('Claude sidechain snapshot is unavailable');
|
|
2031
|
+
return snapshot;
|
|
2032
|
+
};
|
|
2033
|
+
const nativeInterruption = nativeLease?.interruption();
|
|
2034
|
+
if (nativeInterruption?.kind === 'indeterminate-tools')
|
|
2035
|
+
throw new Error(`Native sidechain tool execution is indeterminate: ${nativeInterruption.callIds.join(', ')}`);
|
|
2036
|
+
const nativeRecoveryCalls = options.continuationMessage === undefined &&
|
|
2037
|
+
nativeInterruption?.kind === 'recoverable-tools'
|
|
2038
|
+
? [...nativeInterruption.calls]
|
|
2039
|
+
: [];
|
|
1870
2040
|
if (options.continuationMessage !== undefined) {
|
|
1871
2041
|
// Validate ambiguous tool linkage before the append-only sidechain is
|
|
1872
2042
|
// mutated. The projection is rebuilt after appending the one explicit
|
|
1873
2043
|
// continuation prompt so that prompt is visible to the provider.
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
}
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
2044
|
+
const continuation = `The coordinator sent a message while you were working:\n${options.continuationMessage}\n\nAddress this before completing your current task.`;
|
|
2045
|
+
if (nativeLease) {
|
|
2046
|
+
projectNativeSidechainContinuationMessages(nativeLease.activeMessages());
|
|
2047
|
+
await nativeLease.appendMessages({
|
|
2048
|
+
messages: [{ role: 'user', content: continuation }],
|
|
2049
|
+
});
|
|
2050
|
+
}
|
|
2051
|
+
else {
|
|
2052
|
+
const current = requireClaudeSnapshot();
|
|
2053
|
+
projectClaudeSidechainContinuationMessages(current.entries);
|
|
2054
|
+
const [entry] = translateProviderEvents([{ type: 'user-text-block', text: continuation }], {
|
|
2055
|
+
sessionId: options.sessionId,
|
|
2056
|
+
parentUuid: current.tail.lastUuid,
|
|
2057
|
+
cwd,
|
|
2058
|
+
claudeVersion: this.options.claudeVersion,
|
|
2059
|
+
gitBranch: null,
|
|
2060
|
+
history: current.entries,
|
|
2061
|
+
});
|
|
2062
|
+
if (!entry)
|
|
2063
|
+
throw new Error('Could not translate subagent message');
|
|
2064
|
+
const sidechainEntry = toClaudeSidechainEntry(entry, options.agentId, options.input.subagentType);
|
|
2065
|
+
if (!claudeLease)
|
|
2066
|
+
throw new Error('Claude sidechain continuation is unavailable');
|
|
2067
|
+
const appendResult = await claudeLease.append(current.tail, sidechainEntry);
|
|
2068
|
+
if (appendResult.status === 'conflict') {
|
|
2069
|
+
throw new Error(`Claude sidechain append conflict: ${appendResult.reason}`);
|
|
2070
|
+
}
|
|
2071
|
+
snapshot = {
|
|
2072
|
+
entries: [...current.entries, sidechainEntry],
|
|
2073
|
+
tail: appendResult.tail,
|
|
2074
|
+
};
|
|
1894
2075
|
}
|
|
1895
|
-
snapshot = {
|
|
1896
|
-
entries: [...snapshot.entries, sidechainEntry],
|
|
1897
|
-
tail: appendResult.tail,
|
|
1898
|
-
};
|
|
1899
2076
|
}
|
|
2077
|
+
const durableFollowUps = new DurableFollowUpTracker();
|
|
1900
2078
|
let toolUseCount = 0;
|
|
1901
2079
|
let taskTokenTotal = 0;
|
|
1902
2080
|
let recordedUsage = { inputTokens: 0, outputTokens: 0 };
|
|
@@ -1907,29 +2085,37 @@ export class ClaudeSubagentExecutor {
|
|
|
1907
2085
|
let recordedApiDurationSeen = false;
|
|
1908
2086
|
let lastToolName;
|
|
1909
2087
|
const taskStartedAt = Date.now();
|
|
1910
|
-
const
|
|
1911
|
-
|
|
2088
|
+
const appendClaude = async (entry) => {
|
|
2089
|
+
if (!claudeLease)
|
|
2090
|
+
throw new Error('Claude sidechain append is unavailable');
|
|
2091
|
+
const current = requireClaudeSnapshot();
|
|
2092
|
+
const result = await claudeLease.append(current.tail, entry);
|
|
1912
2093
|
if (result.status === 'conflict') {
|
|
1913
2094
|
throw new Error(`Claude sidechain append conflict: ${result.reason}`);
|
|
1914
2095
|
}
|
|
1915
|
-
snapshot = { entries: [...
|
|
2096
|
+
snapshot = { entries: [...current.entries, entry], tail: result.tail };
|
|
2097
|
+
};
|
|
2098
|
+
const translationContext = () => {
|
|
2099
|
+
const current = requireClaudeSnapshot();
|
|
2100
|
+
return {
|
|
2101
|
+
sessionId: options.sessionId,
|
|
2102
|
+
parentUuid: current.tail.lastUuid,
|
|
2103
|
+
cwd,
|
|
2104
|
+
claudeVersion: this.options.claudeVersion,
|
|
2105
|
+
gitBranch: null,
|
|
2106
|
+
history: current.entries,
|
|
2107
|
+
};
|
|
1916
2108
|
};
|
|
1917
|
-
const translationContext = () => ({
|
|
1918
|
-
sessionId: String(options.root.sessionId),
|
|
1919
|
-
parentUuid: snapshot.tail.lastUuid,
|
|
1920
|
-
cwd,
|
|
1921
|
-
claudeVersion: this.options.claudeVersion,
|
|
1922
|
-
gitBranch: null,
|
|
1923
|
-
history: snapshot.entries,
|
|
1924
|
-
});
|
|
1925
2109
|
const recordHookOutcome = async (outcome) => {
|
|
2110
|
+
if (nativeLease)
|
|
2111
|
+
throw new Error('Claude hooks are unavailable for native sidechains');
|
|
1926
2112
|
for (const entry of createClaudeHookAttachmentEntries(outcome, translationContext())) {
|
|
1927
|
-
await
|
|
2113
|
+
await appendClaude(toClaudeSidechainEntry(entry, options.agentId, options.input.subagentType));
|
|
1928
2114
|
}
|
|
1929
2115
|
};
|
|
1930
2116
|
const customAgent = this.agentDefinition(options.input);
|
|
1931
2117
|
const hookSession = {
|
|
1932
|
-
session_id:
|
|
2118
|
+
session_id: options.sessionId,
|
|
1933
2119
|
transcript_path: options.transcriptPath,
|
|
1934
2120
|
cwd,
|
|
1935
2121
|
permission_mode: options.input.permissionMode ?? 'default',
|
|
@@ -1979,7 +2165,7 @@ export class ClaudeSubagentExecutor {
|
|
|
1979
2165
|
recordedDurationApiWithoutRetriesMs += withoutRetries;
|
|
1980
2166
|
recordedApiDurationSeen = true;
|
|
1981
2167
|
};
|
|
1982
|
-
const nestedTools = this.registry(
|
|
2168
|
+
const nestedTools = this.registry(options.sessionId, options.spawnDepth, () => options.promptId, options.agentId);
|
|
1983
2169
|
const agentMcp = customAgent?.mcpServers?.length
|
|
1984
2170
|
? await this.options.mcp?.connectAgent?.({
|
|
1985
2171
|
specs: customAgent.mcpServers,
|
|
@@ -2074,8 +2260,29 @@ export class ClaudeSubagentExecutor {
|
|
|
2074
2260
|
maxToolInputBytes: 1024 * 1024,
|
|
2075
2261
|
});
|
|
2076
2262
|
const observer = {
|
|
2263
|
+
toolExecutionStarted: async (call) => {
|
|
2264
|
+
await nativeLease?.beginToolExecution(call.id);
|
|
2265
|
+
},
|
|
2077
2266
|
assistantCompleted: async (message) => {
|
|
2078
2267
|
commitProviderUsage();
|
|
2268
|
+
if (nativeLease) {
|
|
2269
|
+
await nativeLease.appendMessages({
|
|
2270
|
+
messages: [
|
|
2271
|
+
{
|
|
2272
|
+
role: 'assistant',
|
|
2273
|
+
content: message.content,
|
|
2274
|
+
...(message.thinkingBlocks
|
|
2275
|
+
? { thinkingBlocks: message.thinkingBlocks }
|
|
2276
|
+
: {}),
|
|
2277
|
+
...(message.toolCalls?.length
|
|
2278
|
+
? { toolCalls: message.toolCalls }
|
|
2279
|
+
: {}),
|
|
2280
|
+
},
|
|
2281
|
+
],
|
|
2282
|
+
model: options.provider.model ?? 'praxis/provider',
|
|
2283
|
+
});
|
|
2284
|
+
return;
|
|
2285
|
+
}
|
|
2079
2286
|
const [entry] = translateProviderEvents([
|
|
2080
2287
|
{
|
|
2081
2288
|
type: 'assistant-message',
|
|
@@ -2090,7 +2297,7 @@ export class ClaudeSubagentExecutor {
|
|
|
2090
2297
|
], translationContext());
|
|
2091
2298
|
if (!entry)
|
|
2092
2299
|
throw new Error('Could not translate subagent response');
|
|
2093
|
-
await
|
|
2300
|
+
await appendClaude(toClaudeSidechainEntry(entry, options.agentId, options.input.subagentType));
|
|
2094
2301
|
},
|
|
2095
2302
|
toolCompleted: async (call, result) => {
|
|
2096
2303
|
if (result.usage) {
|
|
@@ -2114,6 +2321,16 @@ export class ClaudeSubagentExecutor {
|
|
|
2114
2321
|
nestedToolUseCount > 0) {
|
|
2115
2322
|
toolUseCount += nestedToolUseCount;
|
|
2116
2323
|
}
|
|
2324
|
+
if (nativeLease) {
|
|
2325
|
+
await nativeLease.appendToolCompletion({
|
|
2326
|
+
callId: call.id,
|
|
2327
|
+
result,
|
|
2328
|
+
...(result.followUpUserMessages?.length
|
|
2329
|
+
? { followUpUserMessages: result.followUpUserMessages }
|
|
2330
|
+
: {}),
|
|
2331
|
+
});
|
|
2332
|
+
return;
|
|
2333
|
+
}
|
|
2117
2334
|
const [entry] = translateProviderEvents([
|
|
2118
2335
|
{
|
|
2119
2336
|
type: 'tool-result',
|
|
@@ -2135,16 +2352,19 @@ export class ClaudeSubagentExecutor {
|
|
|
2135
2352
|
], translationContext());
|
|
2136
2353
|
if (!entry)
|
|
2137
2354
|
throw new Error('Could not translate subagent tool result');
|
|
2138
|
-
await
|
|
2355
|
+
await appendClaude(toClaudeSidechainEntry(entry, options.agentId, options.input.subagentType));
|
|
2139
2356
|
},
|
|
2140
2357
|
followUpUserMessagesCompleted: async (messages) => {
|
|
2141
2358
|
for (const text of messages) {
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2359
|
+
if (!nativeLease) {
|
|
2360
|
+
const [entry] = translateProviderEvents([{ type: 'user-text-block', text }], translationContext());
|
|
2361
|
+
if (!entry)
|
|
2362
|
+
throw new Error('Could not translate subagent follow-up');
|
|
2363
|
+
await appendClaude(toClaudeSidechainEntry(entry, options.agentId, options.input.subagentType));
|
|
2364
|
+
}
|
|
2146
2365
|
await this.background.acknowledge([text]);
|
|
2147
2366
|
}
|
|
2367
|
+
await durableFollowUps.followUpUserMessagesCompleted(messages);
|
|
2148
2368
|
},
|
|
2149
2369
|
};
|
|
2150
2370
|
this.options.eventSink?.({
|
|
@@ -2212,11 +2432,16 @@ export class ClaudeSubagentExecutor {
|
|
|
2212
2432
|
});
|
|
2213
2433
|
const contextProjection = projectContextSnapshot(assembledContext);
|
|
2214
2434
|
stableSystemMessageCount = contextProjection.stableSystemSectionCount;
|
|
2435
|
+
const transcriptMessages = nativeLease
|
|
2436
|
+
? options.continuationMessage === undefined
|
|
2437
|
+
? nativeLease.activeMessages()
|
|
2438
|
+
: projectNativeSidechainContinuationMessages(nativeLease.activeMessages())
|
|
2439
|
+
: options.continuationMessage === undefined
|
|
2440
|
+
? projectClaudeModelMessages(requireClaudeSnapshot().entries)
|
|
2441
|
+
: projectClaudeSidechainContinuationMessages(requireClaudeSnapshot().entries);
|
|
2215
2442
|
const messages = [
|
|
2216
2443
|
...contextProjection.systemMessages,
|
|
2217
|
-
...injectFirstUserMessageContext(
|
|
2218
|
-
? projectClaudeModelMessages(snapshot.entries)
|
|
2219
|
-
: projectClaudeSidechainContinuationMessages(snapshot.entries), contextProjection.firstUserMessageContext),
|
|
2444
|
+
...injectFirstUserMessageContext(transcriptMessages, contextProjection.firstUserMessageContext),
|
|
2220
2445
|
...preloadedSkills,
|
|
2221
2446
|
];
|
|
2222
2447
|
observedMessages = messages;
|
|
@@ -2227,9 +2452,27 @@ export class ClaudeSubagentExecutor {
|
|
|
2227
2452
|
};
|
|
2228
2453
|
const configuredEffort = typeof customAgent?.effort === 'string' ? customAgent.effort : undefined;
|
|
2229
2454
|
const effectiveEffort = options.effort ?? configuredEffort;
|
|
2455
|
+
if (nativeRecoveryCalls.length > 0) {
|
|
2456
|
+
if (!nativeLease)
|
|
2457
|
+
throw new Error('Native sidechain recovery lease is unavailable');
|
|
2458
|
+
await runtime.recoverToolCalls(nativeRecoveryCalls, {
|
|
2459
|
+
cwd,
|
|
2460
|
+
toolResultDirectory: options.toolResultDirectory,
|
|
2461
|
+
messages: nativeLease.activeMessages(),
|
|
2462
|
+
observer,
|
|
2463
|
+
...(this.options.approveTool
|
|
2464
|
+
? { approveTool: this.options.approveTool }
|
|
2465
|
+
: {}),
|
|
2466
|
+
permissionUpdates: this.options.permissionUpdates?.() ?? [],
|
|
2467
|
+
...(this.options.onPermissionUpdates
|
|
2468
|
+
? { onPermissionUpdates: this.options.onPermissionUpdates }
|
|
2469
|
+
: {}),
|
|
2470
|
+
...(options.signal ? { signal: options.signal } : {}),
|
|
2471
|
+
});
|
|
2472
|
+
}
|
|
2230
2473
|
const initialMessages = await assembleMessages();
|
|
2231
2474
|
const runtimeRequest = {
|
|
2232
|
-
sessionId:
|
|
2475
|
+
sessionId: options.sessionId,
|
|
2233
2476
|
messages: initialMessages,
|
|
2234
2477
|
collectMetrics: true,
|
|
2235
2478
|
stableSystemMessageCount,
|
|
@@ -2249,10 +2492,17 @@ export class ClaudeSubagentExecutor {
|
|
|
2249
2492
|
...(this.options.onPermissionUpdates
|
|
2250
2493
|
? { onPermissionUpdates: this.options.onPermissionUpdates }
|
|
2251
2494
|
: {}),
|
|
2252
|
-
...(scopedHooks ||
|
|
2495
|
+
...(scopedHooks ||
|
|
2496
|
+
this.options.backgroundTaskNotifications ||
|
|
2497
|
+
this.options.durableFollowUpSource
|
|
2253
2498
|
? {
|
|
2254
2499
|
onStop: async (text) => {
|
|
2255
2500
|
const messages = [];
|
|
2501
|
+
const durableBatch = await this.options.durableFollowUpSource?.();
|
|
2502
|
+
if (durableBatch) {
|
|
2503
|
+
durableFollowUps.register(durableBatch);
|
|
2504
|
+
messages.push(...durableBatch.messages);
|
|
2505
|
+
}
|
|
2256
2506
|
const outcome = await scopedHooks?.run({
|
|
2257
2507
|
...hookSession,
|
|
2258
2508
|
hook_event_name: 'SubagentStop',
|
|
@@ -2269,15 +2519,13 @@ export class ClaudeSubagentExecutor {
|
|
|
2269
2519
|
messages.push(`SubagentStop hook error: ${outcome.blockedReason}`);
|
|
2270
2520
|
}
|
|
2271
2521
|
}
|
|
2272
|
-
await this.hydratePersistedTasks(
|
|
2522
|
+
await this.hydratePersistedTasks(options.sessionId, options.cwd ?? this.cwd());
|
|
2273
2523
|
await this.reconcileDeliveredNotifications((notification) => {
|
|
2274
2524
|
const markers = backgroundAgentNotificationMarkers(notification);
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
return markers.every((marker) => source.includes(marker));
|
|
2280
|
-
});
|
|
2525
|
+
const source = JSON.stringify(nativeLease
|
|
2526
|
+
? nativeLease.activeMessages()
|
|
2527
|
+
: requireClaudeSnapshot().entries);
|
|
2528
|
+
return markers.every((marker) => source.includes(marker));
|
|
2281
2529
|
});
|
|
2282
2530
|
const background = await this.background.notifications({
|
|
2283
2531
|
waitForRunning: false,
|