jg-agent-hq 0.2.0 → 0.4.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/CHANGELOG.md +12 -0
- package/README.md +7 -4
- package/api/README.md +35 -17
- package/dist/actions/live/live.d.ts +4 -1
- package/dist/actions/live/live.js +22 -6
- package/dist/actions/reads.d.ts +1 -1
- package/dist/actions/reads.js +4 -2
- package/dist/contracts/actions/types.d.ts +6 -6
- package/dist/contracts/actions/types.js +1 -1
- package/dist/contracts/browser/index.d.ts +4 -0
- package/dist/contracts/browser/index.js +6 -0
- package/dist/contracts/browser/types.d.ts +2475 -0
- package/dist/contracts/browser/types.js +109 -0
- package/dist/contracts/handoffs/types.d.ts +5 -5
- package/dist/contracts/index.d.ts +4 -0
- package/dist/contracts/index.js +6 -0
- package/dist/contracts/plans/types.d.ts +25 -25
- package/dist/contracts/plans/types.js +9 -10
- package/dist/contracts/types.d.ts +96 -30
- package/dist/contracts/types.js +10 -2
- package/dist/handoffs/types.d.ts +6 -6
- package/dist/plans/admission.d.ts +2 -2
- package/dist/plans/admission.js +24 -16
- package/dist/plans/authority.d.ts +6 -0
- package/dist/plans/authority.js +39 -8
- package/dist/plans/finalization.d.ts +1 -1
- package/dist/plans/finalization.js +4 -3
- package/dist/plans/plans.d.ts +3 -3
- package/dist/plans/plans.js +9 -11
- package/dist/plans/reconciliation.js +3 -3
- package/dist/plans/revisions.d.ts +2 -2
- package/dist/plans/revisions.js +21 -3
- package/dist/plans/types.d.ts +4 -4
- package/dist/providers/claude/control/control.d.ts +1 -1
- package/dist/providers/claude/history/types.d.ts +39 -11
- package/dist/runtime/browser/browser.d.ts +8 -0
- package/dist/runtime/browser/browser.js +55 -0
- package/dist/runtime/browser/index.d.ts +1 -0
- package/dist/runtime/browser/index.js +2 -0
- package/dist/runtime/runtime.js +12 -1
- package/dist/runtime/types.d.ts +19 -1
- package/dist/store/browser/browser.model.d.ts +24 -0
- package/dist/store/browser/browser.model.js +75 -0
- package/dist/store/browser/index.d.ts +1 -0
- package/dist/store/browser/index.js +2 -0
- package/dist/store/control/types.d.ts +6 -6
- package/dist/store/plans/plans.model.d.ts +2 -2
- package/dist/store/plans/plans.model.js +1 -1
- package/dist/store/schema.sql +15 -2
- package/dist/store/store.js +4 -1
- package/dist/store/store.worker.js +11 -0
- package/dist/store/types.d.ts +1545 -510
- package/dist/store/types.js +17 -1
- package/errors/README.md +11 -1
- package/package.json +1 -1
package/dist/plans/authority.js
CHANGED
|
@@ -12,9 +12,7 @@ export const describePlan = (artifacts, pendingActionId = null) => {
|
|
|
12
12
|
const isPlanApproved = !!coordination.planApproval &&
|
|
13
13
|
!coordination.planApproval.revokedBy &&
|
|
14
14
|
coordination.planApproval.revision.planDigest === revision.planDigest;
|
|
15
|
-
const isFinalized = !!coordination.finalized &&
|
|
16
|
-
revision.breakdownDigest !== null &&
|
|
17
|
-
isSamePlanRevision(coordination.finalized.revision, revision);
|
|
15
|
+
const isFinalized = !!coordination.finalized && isSamePlanRevision(coordination.finalized.revision, revision);
|
|
18
16
|
const isSequenceApproved = isPlanApproved &&
|
|
19
17
|
isFinalized &&
|
|
20
18
|
!!coordination.sequenceApproval &&
|
|
@@ -22,6 +20,12 @@ export const describePlan = (artifacts, pendingActionId = null) => {
|
|
|
22
20
|
isSamePlanRevision(coordination.sequenceApproval.revision, revision);
|
|
23
21
|
const verified = createCompletionLookup(coordination.completions, coordination.correspondences);
|
|
24
22
|
const workflow = coordination.revision;
|
|
23
|
+
const invalidated = new Set(coordination.correspondences.flatMap((record) => record.invalidatedReceiptIds));
|
|
24
|
+
const isWholePlanComplete = artifacts.milestones === null &&
|
|
25
|
+
coordination.completions.some((receipt) => receipt.milestoneId === null &&
|
|
26
|
+
receipt.contractDigest === revision.planDigest &&
|
|
27
|
+
receipt.revision.breakdownDigest === null &&
|
|
28
|
+
!invalidated.has(receipt.id));
|
|
25
29
|
const state = coordination.observedConflict ||
|
|
26
30
|
pendingActionId ||
|
|
27
31
|
workflow?.phase === 'blocked' ||
|
|
@@ -38,10 +42,11 @@ export const describePlan = (artifacts, pendingActionId = null) => {
|
|
|
38
42
|
? 'plan-approval-required'
|
|
39
43
|
: !isFinalized
|
|
40
44
|
? 'breakdown-required'
|
|
41
|
-
: !isSequenceApproved
|
|
45
|
+
: artifacts.milestones !== null && !isSequenceApproved
|
|
42
46
|
? 'sequence-approval-required'
|
|
43
|
-
:
|
|
44
|
-
artifacts.parsed.
|
|
47
|
+
: isWholePlanComplete ||
|
|
48
|
+
(artifacts.parsed.length > 0 &&
|
|
49
|
+
artifacts.parsed.every((milestone) => milestone.status === 'done' && verified(milestone)))
|
|
45
50
|
? 'completed'
|
|
46
51
|
: artifacts.parsed.some((milestone) => milestone.status === 'in progress')
|
|
47
52
|
? 'in-progress'
|
|
@@ -89,6 +94,26 @@ export const describePlan = (artifacts, pendingActionId = null) => {
|
|
|
89
94
|
},
|
|
90
95
|
};
|
|
91
96
|
};
|
|
97
|
+
/**
|
|
98
|
+
* Checks the current approved unfinished unit, with null identifying an undivided plan.
|
|
99
|
+
* Runtime epoch, action identity and mode remain the caller's separate admission checks.
|
|
100
|
+
* @returns Whether the exact unit is selected by current execution authority.
|
|
101
|
+
*/
|
|
102
|
+
export const canExecutePlanUnit = (artifacts, milestoneId) => {
|
|
103
|
+
const status = describePlan(artifacts);
|
|
104
|
+
const execution = artifacts.coordination.execution;
|
|
105
|
+
if (!execution ||
|
|
106
|
+
!status.isPlanApproved ||
|
|
107
|
+
!status.isFinalized ||
|
|
108
|
+
['blocked', 'completed', 'revising'].includes(status.state))
|
|
109
|
+
return false;
|
|
110
|
+
return artifacts.milestones === null
|
|
111
|
+
? milestoneId === null && execution.milestoneIds.length === 0
|
|
112
|
+
: status.isSequenceApproved &&
|
|
113
|
+
milestoneId !== null &&
|
|
114
|
+
execution.milestoneIds.includes(milestoneId) &&
|
|
115
|
+
artifacts.parsed.some((milestone) => milestone.id === milestoneId && milestone.status !== 'done');
|
|
116
|
+
};
|
|
92
117
|
/** Revocation records operator provenance without granting any replacement authority. */
|
|
93
118
|
const revokeExecution = (coordination, action) => {
|
|
94
119
|
if (coordination.execution)
|
|
@@ -104,7 +129,8 @@ export const updatePlanAuthority = (artifacts, command, runtimeEpoch) => {
|
|
|
104
129
|
const coordination = structuredClone(artifacts.coordination);
|
|
105
130
|
if (command.kind === 'approve') {
|
|
106
131
|
const status = describePlan(artifacts);
|
|
107
|
-
if (command.scope === 'sequence' &&
|
|
132
|
+
if (command.scope === 'sequence' &&
|
|
133
|
+
(artifacts.milestones === null || !status.isFinalized || !status.isPlanApproved))
|
|
108
134
|
conflict();
|
|
109
135
|
const presentation = command.scope === 'plan' ? artifacts.hashes.plan : artifacts.hashes.milestones;
|
|
110
136
|
if (presentation !== command.presentationHash)
|
|
@@ -139,7 +165,12 @@ export const updatePlanAuthority = (artifacts, command, runtimeEpoch) => {
|
|
|
139
165
|
coordination.revision.phase !== 'finished')
|
|
140
166
|
conflict();
|
|
141
167
|
if (status.state === 'blocked' ||
|
|
142
|
-
|
|
168
|
+
status.state === 'completed' ||
|
|
169
|
+
!status.isPlanApproved ||
|
|
170
|
+
!status.isFinalized ||
|
|
171
|
+
(artifacts.milestones === null
|
|
172
|
+
? command.milestoneIds.length !== 0
|
|
173
|
+
: !status.isSequenceApproved || command.milestoneIds.length === 0) ||
|
|
143
174
|
command.milestoneIds.some((id) => !artifacts.parsed.some((milestone) => milestone.id === id && milestone.status !== 'done')))
|
|
144
175
|
conflict();
|
|
145
176
|
if (coordination.revision)
|
|
@@ -14,10 +14,11 @@ const conflict = () => {
|
|
|
14
14
|
* - -1: The HQ plan is invalid
|
|
15
15
|
*/
|
|
16
16
|
export const finalizeInitialSequence = (artifacts) => {
|
|
17
|
-
if (artifacts.
|
|
18
|
-
(artifacts.coordination.finalized
|
|
19
|
-
!isSamePlanRevision(artifacts.coordination.finalized.revision, artifacts.revision)))
|
|
17
|
+
if (artifacts.coordination.finalized &&
|
|
18
|
+
!isSamePlanRevision(artifacts.coordination.finalized.revision, artifacts.revision))
|
|
20
19
|
conflict();
|
|
20
|
+
if (artifacts.milestones === null)
|
|
21
|
+
return { content: null, revision: artifacts.revision };
|
|
21
22
|
let milestones = artifacts.milestones.replace(/\r\n?/g, '\n');
|
|
22
23
|
// insertion offsets are applied backwards so original positions stay valid
|
|
23
24
|
for (const milestone of [...artifacts.parsed].reverse())
|
package/dist/plans/plans.d.ts
CHANGED
|
@@ -116,7 +116,7 @@ export declare const createPlans: (coordinationRoot: string, roots: string[], st
|
|
|
116
116
|
* - -1: HQ lock ownership changed before release
|
|
117
117
|
*/
|
|
118
118
|
checkpoint(target: IPlanCommand["target"], revisionId: string, phaseActionId: string): Promise<void>;
|
|
119
|
-
admitNative(action: import("../contracts/index.js").IActionEnvelope, prepared: import("../store/control/types.
|
|
119
|
+
admitNative(action: import("../contracts/index.js").IActionEnvelope, prepared: import("../store/control/types.ts").IAdmission["prepared"]): Promise<{
|
|
120
120
|
receipt: {
|
|
121
121
|
id: string;
|
|
122
122
|
digest: string;
|
|
@@ -134,7 +134,7 @@ export declare const createPlans: (coordinationRoot: string, roots: string[], st
|
|
|
134
134
|
scope: {
|
|
135
135
|
kind: "execution";
|
|
136
136
|
authorizationId: string;
|
|
137
|
-
milestoneId: string;
|
|
137
|
+
milestoneId: string | null;
|
|
138
138
|
mode: "supervised" | "auto";
|
|
139
139
|
revision: {
|
|
140
140
|
planDigest: string;
|
|
@@ -192,7 +192,7 @@ export declare const createPlans: (coordinationRoot: string, roots: string[], st
|
|
|
192
192
|
scope: {
|
|
193
193
|
kind: "execution";
|
|
194
194
|
authorizationId: string;
|
|
195
|
-
milestoneId: string;
|
|
195
|
+
milestoneId: string | null;
|
|
196
196
|
mode: "supervised" | "auto";
|
|
197
197
|
revision: {
|
|
198
198
|
planDigest: string;
|
package/dist/plans/plans.js
CHANGED
|
@@ -4,7 +4,7 @@ import { PlanMilestoneSchema, } from '../contracts/index.js';
|
|
|
4
4
|
import { getErrorKind } from '../errors/index.js';
|
|
5
5
|
import { withHqLock } from '../locks/index.js';
|
|
6
6
|
import { resolveWorkspaceTarget } from '../runtime/state/index.js';
|
|
7
|
-
import { describePlan, updatePlanAuthority } from './authority.js';
|
|
7
|
+
import { canExecutePlanUnit, describePlan, updatePlanAuthority } from './authority.js';
|
|
8
8
|
import { createPlanAdmission } from './admission.js';
|
|
9
9
|
import { readPlanPage } from './projections.js';
|
|
10
10
|
import { finalizeInitialSequence } from './finalization.js';
|
|
@@ -340,16 +340,14 @@ export const createPlans = (coordinationRoot, roots, store, runtimeEpoch, parseC
|
|
|
340
340
|
const execution = artifacts.coordination.execution;
|
|
341
341
|
if (pendingActionId ||
|
|
342
342
|
status.state === 'blocked' ||
|
|
343
|
-
!status.isSequenceApproved ||
|
|
344
343
|
!execution ||
|
|
345
344
|
execution.runtimeEpoch !== runtimeEpoch ||
|
|
346
345
|
execution.revokedBy ||
|
|
347
346
|
execution.action.id !== command.authorizationId ||
|
|
348
347
|
execution.mode !== command.mode ||
|
|
349
|
-
!
|
|
348
|
+
!canExecutePlanUnit(artifacts, command.milestoneId) ||
|
|
350
349
|
!isSamePlanRevision(command.expected, artifacts.revision) ||
|
|
351
|
-
!isSamePlanRevision(execution.revision, artifacts.revision)
|
|
352
|
-
!artifacts.parsed.some((milestone) => milestone.id === command.milestoneId && milestone.status !== 'done'))
|
|
350
|
+
!isSamePlanRevision(execution.revision, artifacts.revision))
|
|
353
351
|
conflict();
|
|
354
352
|
return {
|
|
355
353
|
kind: 'execution-check',
|
|
@@ -367,9 +365,7 @@ export const createPlans = (coordinationRoot, roots, store, runtimeEpoch, parseC
|
|
|
367
365
|
await apply(previous);
|
|
368
366
|
artifacts = await readPlanArtifacts(command.target, roots, parseContract);
|
|
369
367
|
const current = describeCurrent(artifacts, await store.getPendingPlanOperationId(artifacts.directory));
|
|
370
|
-
return command.kind === 'finalize' &&
|
|
371
|
-
current.isFinalized &&
|
|
372
|
-
artifacts.milestones !== null
|
|
368
|
+
return command.kind === 'finalize' && current.isFinalized
|
|
373
369
|
? { kind: 'finalized', result: current, content: artifacts.milestones }
|
|
374
370
|
: { kind: 'status', result: current };
|
|
375
371
|
}
|
|
@@ -449,7 +445,7 @@ export const createPlans = (coordinationRoot, roots, store, runtimeEpoch, parseC
|
|
|
449
445
|
conflict();
|
|
450
446
|
if ((await store.getPlanThreads(artifacts.directory)).length)
|
|
451
447
|
conflict();
|
|
452
|
-
if (!workflow.checkpoint?.isQuiescent
|
|
448
|
+
if (!workflow.checkpoint?.isQuiescent)
|
|
453
449
|
conflict();
|
|
454
450
|
const proposal = workflow.proposal ?? proposeReconciliation(artifacts, command.action);
|
|
455
451
|
if (proposal.inspectionHash !== artifacts.hashes.milestones ||
|
|
@@ -475,7 +471,9 @@ export const createPlans = (coordinationRoot, roots, store, runtimeEpoch, parseC
|
|
|
475
471
|
}
|
|
476
472
|
else if (command.confirmation)
|
|
477
473
|
conflict();
|
|
478
|
-
const content =
|
|
474
|
+
const content = artifacts.milestones === null
|
|
475
|
+
? null
|
|
476
|
+
: renderReconciledSequence(artifacts.milestones, drafts);
|
|
479
477
|
const revision = computePlanRevision({
|
|
480
478
|
...artifacts.contract,
|
|
481
479
|
milestones: content,
|
|
@@ -498,7 +496,7 @@ export const createPlans = (coordinationRoot, roots, store, runtimeEpoch, parseC
|
|
|
498
496
|
coordination.finalized = {
|
|
499
497
|
action: command.action,
|
|
500
498
|
revision: finalized.revision,
|
|
501
|
-
fileHash: hashPlanContent(milestones),
|
|
499
|
+
fileHash: milestones === null ? null : hashPlanContent(milestones),
|
|
502
500
|
createdAt: Date.now(),
|
|
503
501
|
};
|
|
504
502
|
coordination.baseline = refreshPlanBaseline(artifacts, milestones, finalized.revision);
|
|
@@ -22,7 +22,7 @@ export const createCompletionLookup = (completions, records) => {
|
|
|
22
22
|
});
|
|
23
23
|
const direct = new Set(completions
|
|
24
24
|
.filter((receipt) => !invalidated.has(receipt.id) &&
|
|
25
|
-
receipt.reopenActionId === (reopened.get(receipt.milestoneId)?.id ?? null))
|
|
25
|
+
receipt.reopenActionId === (reopened.get(receipt.milestoneId ?? '')?.id ?? null))
|
|
26
26
|
.map((receipt) => JSON.stringify([receipt.milestoneId, receipt.contractDigest])));
|
|
27
27
|
const links = new Map();
|
|
28
28
|
for (const [recordIndex, record] of records.entries()) {
|
|
@@ -67,7 +67,7 @@ export const createCompletionLookup = (completions, records) => {
|
|
|
67
67
|
*/
|
|
68
68
|
export const proposeReconciliation = (artifacts, action) => {
|
|
69
69
|
const checkpoint = artifacts.coordination.revision?.checkpoint;
|
|
70
|
-
if (!checkpoint
|
|
70
|
+
if (!checkpoint)
|
|
71
71
|
conflict();
|
|
72
72
|
const sources = checkpoint.entries;
|
|
73
73
|
const oldByContract = new Map();
|
|
@@ -186,7 +186,7 @@ export const confirmReconciliation = (artifacts, proposal, action, decisions) =>
|
|
|
186
186
|
}
|
|
187
187
|
const invalidatedReceiptIds = decision.relation === 'reopened'
|
|
188
188
|
? artifacts.coordination.completions
|
|
189
|
-
.filter((receipt) => decision.sourceIds.includes(receipt.milestoneId))
|
|
189
|
+
.filter((receipt) => receipt.milestoneId !== null && decision.sourceIds.includes(receipt.milestoneId))
|
|
190
190
|
.map((receipt) => receipt.id)
|
|
191
191
|
: [];
|
|
192
192
|
records.push({
|
|
@@ -37,7 +37,7 @@ export declare const finishPlanCheckpoint: (artifacts: IPlanArtifacts, revisionI
|
|
|
37
37
|
*/
|
|
38
38
|
export declare const recordPlanCompletion: (artifacts: IPlanArtifacts, input: {
|
|
39
39
|
action: IPlanOperatorAction;
|
|
40
|
-
milestoneId: string;
|
|
40
|
+
milestoneId: string | null;
|
|
41
41
|
checks: IPlanCompletion["checks"];
|
|
42
42
|
}, checkouts: IPlanWorktreeProof[]) => IPlanCompletion;
|
|
43
43
|
/**
|
|
@@ -46,6 +46,6 @@ export declare const recordPlanCompletion: (artifacts: IPlanArtifacts, input: {
|
|
|
46
46
|
* @throws
|
|
47
47
|
* - -1: The HQ plan is invalid
|
|
48
48
|
*/
|
|
49
|
-
export declare const refreshPlanBaseline: (artifacts: IPlanArtifacts, content: string, revision: IPlanCheckpoint["revision"]) => IPlanCheckpoint;
|
|
49
|
+
export declare const refreshPlanBaseline: (artifacts: IPlanArtifacts, content: string | null, revision: IPlanCheckpoint["revision"]) => IPlanCheckpoint;
|
|
50
50
|
/** Builds indexed retained evidence without exposing whole coordination collections to clients. */
|
|
51
51
|
export declare const projectPlanRevision: (artifacts: IPlanArtifacts) => IPlanRevisionProjection;
|
package/dist/plans/revisions.js
CHANGED
|
@@ -24,8 +24,6 @@ export const capturePlanCheckpoint = (artifacts, threadIds) => {
|
|
|
24
24
|
isQuiescent: false,
|
|
25
25
|
capturedAt: Date.now(),
|
|
26
26
|
};
|
|
27
|
-
if (artifacts.milestones === null || !artifacts.revision.breakdownDigest)
|
|
28
|
-
conflict();
|
|
29
27
|
return {
|
|
30
28
|
revision: artifacts.revision,
|
|
31
29
|
plan: artifacts.plan,
|
|
@@ -120,6 +118,24 @@ export const finishPlanCheckpoint = (artifacts, revisionId, checkouts) => {
|
|
|
120
118
|
* - -1: The HQ action conflicts with its recorded state
|
|
121
119
|
*/
|
|
122
120
|
export const recordPlanCompletion = (artifacts, input, checkouts) => {
|
|
121
|
+
if (input.milestoneId === null) {
|
|
122
|
+
if (artifacts.milestones !== null)
|
|
123
|
+
conflict();
|
|
124
|
+
return {
|
|
125
|
+
id: input.action.id,
|
|
126
|
+
action: input.action,
|
|
127
|
+
milestoneId: null,
|
|
128
|
+
revision: artifacts.revision,
|
|
129
|
+
contractDigest: artifacts.revision.planDigest,
|
|
130
|
+
title: 'Whole plan',
|
|
131
|
+
contract: artifacts.contract.body,
|
|
132
|
+
sharedDigest: null,
|
|
133
|
+
checkouts,
|
|
134
|
+
checks: input.checks,
|
|
135
|
+
completedAt: Date.now(),
|
|
136
|
+
reopenActionId: null,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
123
139
|
const milestone = artifacts.parsed.find((entry) => entry.id === input.milestoneId) ??
|
|
124
140
|
artifacts.coordination.revision?.checkpoint?.entries.find((entry) => entry.id === input.milestoneId);
|
|
125
141
|
if (!milestone?.id || !milestone.contractDigest)
|
|
@@ -155,7 +171,9 @@ export const refreshPlanBaseline = (artifacts, content, revision) => {
|
|
|
155
171
|
revision,
|
|
156
172
|
plan: artifacts.plan,
|
|
157
173
|
milestones: content,
|
|
158
|
-
entries:
|
|
174
|
+
entries: content === null
|
|
175
|
+
? []
|
|
176
|
+
: parsePlanMilestones(content).map((entry) => PlanSnapshotMilestoneSchema.parse(entry)),
|
|
159
177
|
checkouts: previous?.checkouts ?? [],
|
|
160
178
|
threadIds: previous?.threadIds ?? [],
|
|
161
179
|
isQuiescent: previous?.isQuiescent ?? true,
|
package/dist/plans/types.d.ts
CHANGED
|
@@ -156,7 +156,7 @@ export declare const PlanRevisionProjectionSchema: z.ZodObject<{
|
|
|
156
156
|
reference: z.ZodString;
|
|
157
157
|
}, z.core.$strict>;
|
|
158
158
|
}, z.core.$strict>;
|
|
159
|
-
milestoneId: z.ZodUUID
|
|
159
|
+
milestoneId: z.ZodNullable<z.ZodUUID>;
|
|
160
160
|
revision: z.ZodObject<{
|
|
161
161
|
planDigest: z.ZodString;
|
|
162
162
|
breakdownDigest: z.ZodNullable<z.ZodString>;
|
|
@@ -164,7 +164,7 @@ export declare const PlanRevisionProjectionSchema: z.ZodObject<{
|
|
|
164
164
|
contractDigest: z.ZodString;
|
|
165
165
|
title: z.ZodString;
|
|
166
166
|
contract: z.ZodString;
|
|
167
|
-
sharedDigest: z.ZodString
|
|
167
|
+
sharedDigest: z.ZodNullable<z.ZodString>;
|
|
168
168
|
checkouts: z.ZodArray<z.ZodObject<{
|
|
169
169
|
repository: z.ZodString;
|
|
170
170
|
directory: z.ZodString;
|
|
@@ -290,7 +290,7 @@ export declare const PlanRevisionPageResultSchema: z.ZodObject<{
|
|
|
290
290
|
reference: z.ZodString;
|
|
291
291
|
}, z.core.$strict>;
|
|
292
292
|
}, z.core.$strict>;
|
|
293
|
-
milestoneId: z.ZodUUID
|
|
293
|
+
milestoneId: z.ZodNullable<z.ZodUUID>;
|
|
294
294
|
revision: z.ZodObject<{
|
|
295
295
|
planDigest: z.ZodString;
|
|
296
296
|
breakdownDigest: z.ZodNullable<z.ZodString>;
|
|
@@ -298,7 +298,7 @@ export declare const PlanRevisionPageResultSchema: z.ZodObject<{
|
|
|
298
298
|
contractDigest: z.ZodString;
|
|
299
299
|
title: z.ZodString;
|
|
300
300
|
contract: z.ZodString;
|
|
301
|
-
sharedDigest: z.ZodString
|
|
301
|
+
sharedDigest: z.ZodNullable<z.ZodString>;
|
|
302
302
|
checkouts: z.ZodArray<z.ZodObject<{
|
|
303
303
|
repository: z.ZodString;
|
|
304
304
|
directory: z.ZodString;
|
|
@@ -47,7 +47,7 @@ export declare const createClaudeControl: (additionalDirectories?: string[]) =>
|
|
|
47
47
|
* @throws
|
|
48
48
|
* - -1: The Claude integration failed
|
|
49
49
|
*/
|
|
50
|
-
readSkills(nativeId: string): Promise<import("../../types.
|
|
50
|
+
readSkills(nativeId: string): Promise<import("../../types.ts").IProviderSkills>;
|
|
51
51
|
/**
|
|
52
52
|
* Names only the native session selected by the admitted action.
|
|
53
53
|
* @returns Native acknowledgement of the name change.
|
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export declare const ClaudeHistoryReadSchema: z.ZodUnion<readonly [z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
3
|
+
kind: z.ZodLiteral<"thread-plan">;
|
|
4
|
+
result: z.ZodNullable<z.ZodObject<{
|
|
5
|
+
directory: z.ZodString;
|
|
6
|
+
scope: z.ZodNullable<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
7
|
+
kind: z.ZodLiteral<"execution">;
|
|
8
|
+
authorizationId: z.ZodUUID;
|
|
9
|
+
milestoneId: z.ZodNullable<z.ZodUUID>;
|
|
10
|
+
mode: z.ZodEnum<{
|
|
11
|
+
supervised: "supervised";
|
|
12
|
+
auto: "auto";
|
|
13
|
+
}>;
|
|
14
|
+
revision: z.ZodObject<{
|
|
15
|
+
planDigest: z.ZodString;
|
|
16
|
+
breakdownDigest: z.ZodNullable<z.ZodString>;
|
|
17
|
+
}, z.core.$strict>;
|
|
18
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
19
|
+
kind: z.ZodLiteral<"planning">;
|
|
20
|
+
revisionId: z.ZodUUID;
|
|
21
|
+
invocationId: z.ZodUUID;
|
|
22
|
+
}, z.core.$strict>], "kind">>;
|
|
23
|
+
observedRevision: z.ZodObject<{
|
|
24
|
+
planDigest: z.ZodString;
|
|
25
|
+
breakdownDigest: z.ZodNullable<z.ZodString>;
|
|
26
|
+
}, z.core.$strict>;
|
|
27
|
+
}, z.core.$strict>>;
|
|
28
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
3
29
|
kind: z.ZodLiteral<"status">;
|
|
4
30
|
result: z.ZodObject<{
|
|
5
31
|
runtimeEpoch: z.ZodUUID;
|
|
@@ -110,7 +136,7 @@ export declare const ClaudeHistoryReadSchema: z.ZodUnion<readonly [z.ZodDiscrimi
|
|
|
110
136
|
planDigest: z.ZodString;
|
|
111
137
|
breakdownDigest: z.ZodNullable<z.ZodString>;
|
|
112
138
|
}, z.core.$strict>;
|
|
113
|
-
fileHash: z.ZodString
|
|
139
|
+
fileHash: z.ZodNullable<z.ZodString>;
|
|
114
140
|
createdAt: z.ZodNumber;
|
|
115
141
|
}, z.core.$strict>>;
|
|
116
142
|
planApproval: z.ZodNullable<z.ZodObject<{
|
|
@@ -330,7 +356,7 @@ export declare const ClaudeHistoryReadSchema: z.ZodUnion<readonly [z.ZodDiscrimi
|
|
|
330
356
|
planDigest: z.ZodString;
|
|
331
357
|
breakdownDigest: z.ZodNullable<z.ZodString>;
|
|
332
358
|
}, z.core.$strict>;
|
|
333
|
-
fileHash: z.ZodString
|
|
359
|
+
fileHash: z.ZodNullable<z.ZodString>;
|
|
334
360
|
createdAt: z.ZodNumber;
|
|
335
361
|
}, z.core.$strict>>;
|
|
336
362
|
planApproval: z.ZodNullable<z.ZodObject<{
|
|
@@ -518,7 +544,7 @@ export declare const ClaudeHistoryReadSchema: z.ZodUnion<readonly [z.ZodDiscrimi
|
|
|
518
544
|
reference: z.ZodString;
|
|
519
545
|
}, z.core.$strict>;
|
|
520
546
|
}, z.core.$strict>;
|
|
521
|
-
milestoneId: z.ZodUUID
|
|
547
|
+
milestoneId: z.ZodNullable<z.ZodUUID>;
|
|
522
548
|
revision: z.ZodObject<{
|
|
523
549
|
planDigest: z.ZodString;
|
|
524
550
|
breakdownDigest: z.ZodNullable<z.ZodString>;
|
|
@@ -526,7 +552,7 @@ export declare const ClaudeHistoryReadSchema: z.ZodUnion<readonly [z.ZodDiscrimi
|
|
|
526
552
|
contractDigest: z.ZodString;
|
|
527
553
|
title: z.ZodString;
|
|
528
554
|
contract: z.ZodString;
|
|
529
|
-
sharedDigest: z.ZodString
|
|
555
|
+
sharedDigest: z.ZodNullable<z.ZodString>;
|
|
530
556
|
checkouts: z.ZodArray<z.ZodObject<{
|
|
531
557
|
repository: z.ZodString;
|
|
532
558
|
directory: z.ZodString;
|
|
@@ -674,7 +700,7 @@ export declare const ClaudeHistoryReadSchema: z.ZodUnion<readonly [z.ZodDiscrimi
|
|
|
674
700
|
planDigest: z.ZodString;
|
|
675
701
|
breakdownDigest: z.ZodNullable<z.ZodString>;
|
|
676
702
|
}, z.core.$strict>;
|
|
677
|
-
fileHash: z.ZodString
|
|
703
|
+
fileHash: z.ZodNullable<z.ZodString>;
|
|
678
704
|
createdAt: z.ZodNumber;
|
|
679
705
|
}, z.core.$strict>>;
|
|
680
706
|
planApproval: z.ZodNullable<z.ZodObject<{
|
|
@@ -813,7 +839,7 @@ export declare const ClaudeHistoryReadSchema: z.ZodUnion<readonly [z.ZodDiscrimi
|
|
|
813
839
|
}, z.core.$strict>>;
|
|
814
840
|
}, z.core.$strict>;
|
|
815
841
|
}, z.core.$strip>;
|
|
816
|
-
content: z.ZodString
|
|
842
|
+
content: z.ZodNullable<z.ZodString>;
|
|
817
843
|
}, z.core.$strip>, z.ZodObject<{
|
|
818
844
|
kind: z.ZodLiteral<"milestones">;
|
|
819
845
|
result: z.ZodObject<{
|
|
@@ -894,7 +920,7 @@ export declare const ClaudeHistoryReadSchema: z.ZodUnion<readonly [z.ZodDiscrimi
|
|
|
894
920
|
scope: z.ZodNullable<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
895
921
|
kind: z.ZodLiteral<"execution">;
|
|
896
922
|
authorizationId: z.ZodUUID;
|
|
897
|
-
milestoneId: z.ZodUUID
|
|
923
|
+
milestoneId: z.ZodNullable<z.ZodUUID>;
|
|
898
924
|
mode: z.ZodEnum<{
|
|
899
925
|
supervised: "supervised";
|
|
900
926
|
auto: "auto";
|
|
@@ -1027,7 +1053,7 @@ export declare const ClaudeHistoryReadSchema: z.ZodUnion<readonly [z.ZodDiscrimi
|
|
|
1027
1053
|
scope: z.ZodNullable<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
1028
1054
|
kind: z.ZodLiteral<"execution">;
|
|
1029
1055
|
authorizationId: z.ZodUUID;
|
|
1030
|
-
milestoneId: z.ZodUUID
|
|
1056
|
+
milestoneId: z.ZodNullable<z.ZodUUID>;
|
|
1031
1057
|
mode: z.ZodEnum<{
|
|
1032
1058
|
supervised: "supervised";
|
|
1033
1059
|
auto: "auto";
|
|
@@ -1364,7 +1390,7 @@ export declare const ClaudeHistoryReadSchema: z.ZodUnion<readonly [z.ZodDiscrimi
|
|
|
1364
1390
|
scope: z.ZodNullable<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
1365
1391
|
kind: z.ZodLiteral<"execution">;
|
|
1366
1392
|
authorizationId: z.ZodUUID;
|
|
1367
|
-
milestoneId: z.ZodUUID
|
|
1393
|
+
milestoneId: z.ZodNullable<z.ZodUUID>;
|
|
1368
1394
|
mode: z.ZodEnum<{
|
|
1369
1395
|
supervised: "supervised";
|
|
1370
1396
|
auto: "auto";
|
|
@@ -1440,7 +1466,7 @@ export declare const ClaudeHistoryReadSchema: z.ZodUnion<readonly [z.ZodDiscrimi
|
|
|
1440
1466
|
scope: z.ZodNullable<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
1441
1467
|
kind: z.ZodLiteral<"execution">;
|
|
1442
1468
|
authorizationId: z.ZodUUID;
|
|
1443
|
-
milestoneId: z.ZodUUID
|
|
1469
|
+
milestoneId: z.ZodNullable<z.ZodUUID>;
|
|
1444
1470
|
mode: z.ZodEnum<{
|
|
1445
1471
|
supervised: "supervised";
|
|
1446
1472
|
auto: "auto";
|
|
@@ -1628,7 +1654,7 @@ export declare const ClaudeHistoryReadSchema: z.ZodUnion<readonly [z.ZodDiscrimi
|
|
|
1628
1654
|
scope: z.ZodNullable<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
1629
1655
|
kind: z.ZodLiteral<"execution">;
|
|
1630
1656
|
authorizationId: z.ZodUUID;
|
|
1631
|
-
milestoneId: z.ZodUUID
|
|
1657
|
+
milestoneId: z.ZodNullable<z.ZodUUID>;
|
|
1632
1658
|
mode: z.ZodEnum<{
|
|
1633
1659
|
supervised: "supervised";
|
|
1634
1660
|
auto: "auto";
|
|
@@ -1719,6 +1745,8 @@ export declare const ClaudeHistoryReadSchema: z.ZodUnion<readonly [z.ZodDiscrimi
|
|
|
1719
1745
|
}, z.core.$strip>, z.ZodObject<{
|
|
1720
1746
|
kind: z.ZodLiteral<"live-items">;
|
|
1721
1747
|
result: z.ZodObject<{
|
|
1748
|
+
revision: z.ZodNumber;
|
|
1749
|
+
unchanged: z.ZodBoolean;
|
|
1722
1750
|
data: z.ZodArray<z.ZodObject<{
|
|
1723
1751
|
nativeId: z.ZodString;
|
|
1724
1752
|
turnId: z.ZodString;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type IBrowserAction, type IBrowserReceipt } from '../../contracts/index.js';
|
|
2
|
+
import type { IStore } from '../../store/index.js';
|
|
3
|
+
/** Serializes host admission and owns effects independently of an HTTP connection. */
|
|
4
|
+
export declare const createBrowserActions: (store: IStore) => {
|
|
5
|
+
read: (id: string, operatorId: string) => Promise<IBrowserReceipt | null>;
|
|
6
|
+
perform: (input: IBrowserAction, operatorId: string, execute: (action: IBrowserAction, nativeActionId: string) => Promise<void>) => Promise<IBrowserReceipt>;
|
|
7
|
+
close: () => Promise<void>;
|
|
8
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Exception } from 'error-message-utils';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { BrowserActionSchema, } from '../../contracts/index.js';
|
|
4
|
+
const OperatorSchema = z.string().min(1).max(256);
|
|
5
|
+
/** Serializes host admission and owns effects independently of an HTTP connection. */
|
|
6
|
+
export const createBrowserActions = (store) => {
|
|
7
|
+
const pending = new Set();
|
|
8
|
+
let isClosing = false;
|
|
9
|
+
const read = async (id, operatorId) => {
|
|
10
|
+
const parsed = z
|
|
11
|
+
.object({ id: z.uuid(), operatorId: OperatorSchema })
|
|
12
|
+
.safeParse({ id, operatorId });
|
|
13
|
+
if (!parsed.success)
|
|
14
|
+
throw new Exception('The HQ request is invalid', undefined, { kind: 'invalid-request' });
|
|
15
|
+
const receipt = await store.getBrowserAction(id, operatorId);
|
|
16
|
+
if (receipt?.kind === 'native')
|
|
17
|
+
receipt.native = await store.getAction(receipt.nativeActionId);
|
|
18
|
+
return receipt;
|
|
19
|
+
};
|
|
20
|
+
const perform = (input, operatorId, execute) => {
|
|
21
|
+
if (isClosing || pending.size >= 32)
|
|
22
|
+
return Promise.reject(new Exception('The HQ action conflicts with its recorded state', undefined, {
|
|
23
|
+
kind: 'state-conflict',
|
|
24
|
+
}));
|
|
25
|
+
const task = (async () => {
|
|
26
|
+
const action = BrowserActionSchema.safeParse(input);
|
|
27
|
+
if (!action.success || !OperatorSchema.safeParse(operatorId).success)
|
|
28
|
+
throw new Exception('The HQ request is invalid', undefined, { kind: 'invalid-request' });
|
|
29
|
+
const admission = await store.admitBrowserAction(action.data, operatorId);
|
|
30
|
+
if (admission.isNew) {
|
|
31
|
+
try {
|
|
32
|
+
await execute(action.data, admission.receipt.nativeActionId);
|
|
33
|
+
await store.settleBrowserAction(action.data.id, operatorId, 'acknowledged');
|
|
34
|
+
}
|
|
35
|
+
catch (cause) {
|
|
36
|
+
// effects may have committed before an error; only reconciliation can establish their outcome
|
|
37
|
+
await store.settleBrowserAction(action.data.id, operatorId, 'uncertain');
|
|
38
|
+
throw cause;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return (await read(action.data.id, operatorId));
|
|
42
|
+
})();
|
|
43
|
+
pending.add(task);
|
|
44
|
+
void task.finally(() => pending.delete(task)).catch(() => undefined);
|
|
45
|
+
return task;
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
read,
|
|
49
|
+
perform,
|
|
50
|
+
close: async () => {
|
|
51
|
+
isClosing = true;
|
|
52
|
+
await Promise.allSettled([...pending]);
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createBrowserActions } from './browser.js';
|
package/dist/runtime/runtime.js
CHANGED
|
@@ -12,6 +12,7 @@ import { createSkills } from '../skills/index.js';
|
|
|
12
12
|
import { createStore } from '../store/index.js';
|
|
13
13
|
import { createPlans } from '../plans/index.js';
|
|
14
14
|
import { claimRuntimeOwner, prepareDatabase, prepareActionKey, prepareStateRoot, resolveAllowedRoots, resolveWorkspaceTarget, } from './state/index.js';
|
|
15
|
+
import { createBrowserActions } from './browser/index.js';
|
|
15
16
|
import { AgentHqOptionsSchema } from './types.js';
|
|
16
17
|
const UnconfirmedCleanupSchema = z.object({ cleanupUnconfirmed: z.literal(true) });
|
|
17
18
|
/**
|
|
@@ -67,6 +68,7 @@ export const createAgentHq = async (options) => {
|
|
|
67
68
|
await ownership.release();
|
|
68
69
|
throw error;
|
|
69
70
|
}
|
|
71
|
+
const browser = createBrowserActions(store);
|
|
70
72
|
const native = provider;
|
|
71
73
|
const projection = store;
|
|
72
74
|
const claude = createClaudeProvider(projection);
|
|
@@ -137,6 +139,7 @@ export const createAgentHq = async (options) => {
|
|
|
137
139
|
});
|
|
138
140
|
const close = () => (closing ??= (async () => {
|
|
139
141
|
try {
|
|
142
|
+
await browser.close();
|
|
140
143
|
await Promise.allSettled([...revisionJobs.values()]);
|
|
141
144
|
const results = await Promise.allSettled([ipc?.close(), actions.close(), claude.close()]);
|
|
142
145
|
const storeCleanup = await Promise.allSettled([projection.close()]);
|
|
@@ -213,6 +216,7 @@ export const createAgentHq = async (options) => {
|
|
|
213
216
|
kind: command.kind,
|
|
214
217
|
result: { name: await projection.suggestThreadName(suggestThreadName(command.topic)) },
|
|
215
218
|
};
|
|
219
|
+
case 'thread-plan':
|
|
216
220
|
case 'managed-thread-name':
|
|
217
221
|
case 'receipt':
|
|
218
222
|
case 'managed-threads':
|
|
@@ -264,5 +268,12 @@ export const createAgentHq = async (options) => {
|
|
|
264
268
|
await close();
|
|
265
269
|
throw error;
|
|
266
270
|
}
|
|
267
|
-
return {
|
|
271
|
+
return {
|
|
272
|
+
stateRoot,
|
|
273
|
+
closed,
|
|
274
|
+
request,
|
|
275
|
+
close,
|
|
276
|
+
performBrowserAction: browser.perform,
|
|
277
|
+
readBrowserAction: browser.read,
|
|
278
|
+
};
|
|
268
279
|
};
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import type { IHqRequestInput, IHqResponse } from '../contracts/index.js';
|
|
2
|
+
import type { IHqRequestInput, IHqResponse, IBrowserAction, IBrowserReceipt } from '../contracts/index.js';
|
|
3
3
|
import type { IPlanContractParser } from '../plans/index.js';
|
|
4
4
|
export declare const AgentHqOptionsSchema: z.ZodObject<{
|
|
5
5
|
stateRoot: z.ZodString;
|
|
@@ -11,6 +11,24 @@ export declare const AgentHqOptionsSchema: z.ZodObject<{
|
|
|
11
11
|
}, z.core.$strict>;
|
|
12
12
|
export type IAgentHqOptions = z.infer<typeof AgentHqOptionsSchema>;
|
|
13
13
|
export type IAgentHq = {
|
|
14
|
+
/**
|
|
15
|
+
* Runs one trusted host dispatcher after durable admission. Never expose the callback as RPC.
|
|
16
|
+
* Dispatcher failures propagate after the receipt becomes uncertain.
|
|
17
|
+
* @returns Its receipt; replays do not execute the dispatcher.
|
|
18
|
+
* @throws
|
|
19
|
+
* - -1: The HQ request is invalid
|
|
20
|
+
* - -1: The HQ action conflicts with its recorded state
|
|
21
|
+
* - -1: The HQ store failed
|
|
22
|
+
*/
|
|
23
|
+
performBrowserAction(input: IBrowserAction, operatorId: string, execute: (action: IBrowserAction, nativeActionId: string) => Promise<void>): Promise<IBrowserReceipt>;
|
|
24
|
+
/**
|
|
25
|
+
* Reconciles a selected receipt for its authenticated operator without repeating effects.
|
|
26
|
+
* @returns The receipt, or null for another operator or unknown ID.
|
|
27
|
+
* @throws
|
|
28
|
+
* - -1: The HQ request is invalid
|
|
29
|
+
* - -1: The HQ store failed
|
|
30
|
+
*/
|
|
31
|
+
readBrowserAction(id: string, operatorId: string): Promise<IBrowserReceipt | null>;
|
|
14
32
|
stateRoot: string;
|
|
15
33
|
closed: Promise<void>;
|
|
16
34
|
/**
|