@quantiya/codevibe-claude-plugin 2.0.17 → 2.0.19
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/.claude-plugin/plugin.json +1 -1
- package/dist/server.js +18 -18
- package/node_modules/@quantiya/codevibe-core/dist/__tests__/mobile-prompt-input.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/appsync/__tests__/group-operation-result.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/appsync/appsync-client.d.ts +155 -0
- package/node_modules/@quantiya/codevibe-core/dist/appsync/queries.d.ts +14 -0
- package/node_modules/@quantiya/codevibe-core/dist/crypto/__tests__/crypto-service.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/crypto/crypto-service.d.ts +7 -0
- package/node_modules/@quantiya/codevibe-core/dist/index.d.ts +2 -0
- package/node_modules/@quantiya/codevibe-core/dist/index.js +525 -304
- package/node_modules/@quantiya/codevibe-core/dist/local-executor/local-executor-impl.d.ts +34 -0
- package/node_modules/@quantiya/codevibe-core/dist/local-executor/snapshot-merge.d.ts +6 -0
- package/node_modules/@quantiya/codevibe-core/dist/local-executor/types.d.ts +6 -0
- package/node_modules/@quantiya/codevibe-core/dist/mobile-prompt-input.d.ts +13 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/__tests__/decision-attempt-live-handoff.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/__tests__/decision-attempt-recovery.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/__tests__/decision-attempt-session-serialization.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/__tests__/decision-attempt.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/__tests__/decision-effect.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/__tests__/gate-resolution-event.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/__tests__/supervision-catch-up.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/__tests__/workspace-outcome.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/__tests__/workspace-terminal-coordinator.test.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/cli.d.ts +3 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/cli.js +5621 -1758
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/components/ConversationPane.d.ts +2 -1
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/components/GatePromptEntry.d.ts +1 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/decision-attempt-recovery.d.ts +70 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/decision-attempt.d.ts +211 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/decision-effect.d.ts +39 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/emit-shell-event.d.ts +20 -2
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/gate-decision-submit.d.ts +20 -2
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/gate-prompts.d.ts +4 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/gate-resolution-event.d.ts +10 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/index.d.ts +6 -2
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/quorum-loop.d.ts +11 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/supervision-catch-up.d.ts +7 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/types.d.ts +57 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/workspace-outcome.d.ts +20 -0
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/workspace-terminal-coordinator.d.ts +114 -0
- package/node_modules/@quantiya/codevibe-core/dist/types/events.d.ts +7 -0
- package/node_modules/@quantiya/codevibe-core/dist/types/session.d.ts +2 -0
- package/node_modules/@quantiya/codevibe-core/package.json +1 -1
- package/node_modules/fs-ext/build/Makefile +1 -1
- package/node_modules/fs-ext/build/Release/fs_ext.node +0 -0
- package/node_modules/fs-ext/build/config.gypi +0 -2
- package/package.json +2 -2
|
@@ -8,6 +8,7 @@ export interface ConversationPaneProps {
|
|
|
8
8
|
* decision. `null`/absent for single-implementor / Companion sessions.
|
|
9
9
|
*/
|
|
10
10
|
trackLabelByTaskId?: Map<string, string> | null;
|
|
11
|
+
gateActionRecoveryBlocked?: boolean;
|
|
11
12
|
}
|
|
12
|
-
export declare function renderConversationEntry(entry: ConversationEntry, trackLabelByTaskId?: Map<string, string> | null): React.ReactElement;
|
|
13
|
+
export declare function renderConversationEntry(entry: ConversationEntry, trackLabelByTaskId?: Map<string, string> | null, gateActionRecoveryBlocked?: boolean): React.ReactElement;
|
|
13
14
|
export declare function ConversationPane(props: ConversationPaneProps): React.ReactElement;
|
|
@@ -4,6 +4,7 @@ export interface GatePromptEntryProps {
|
|
|
4
4
|
entry: Extract<ConversationEntry, {
|
|
5
5
|
kind: 'gate-prompt';
|
|
6
6
|
}>;
|
|
7
|
+
gateActionRecoveryBlocked?: boolean;
|
|
7
8
|
/**
|
|
8
9
|
* [#469 gate-pin] Best-effort "Track N" label for the gate's owning team
|
|
9
10
|
* track, derived by `<OrchestrationApp>` from `state.team` (taskId → index).
|
package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/decision-attempt-recovery.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Event } from '../types/events';
|
|
2
|
+
import { DecisionAttemptReceiptStore, type DecisionAttemptReceipt, type DecisionAttemptResult, type DecisionSubmissionResult } from './decision-attempt';
|
|
3
|
+
import type { DurableGateResolution } from './types';
|
|
4
|
+
export interface DecisionAttemptRecoveryClient {
|
|
5
|
+
getDecisionAttempt(input: {
|
|
6
|
+
sessionId: string;
|
|
7
|
+
promptId: string;
|
|
8
|
+
decisionAttemptId: string;
|
|
9
|
+
}): Promise<DecisionAttemptResult>;
|
|
10
|
+
getGateResolution(input: {
|
|
11
|
+
sessionId: string;
|
|
12
|
+
promptId: string;
|
|
13
|
+
}): Promise<unknown>;
|
|
14
|
+
submitGateDecisionV2?(request: Extract<DecisionAttemptReceipt['request'], {
|
|
15
|
+
promptKind: 'GATE';
|
|
16
|
+
}>, canonicalRequestHash: string): Promise<DecisionSubmissionResult>;
|
|
17
|
+
submitGroupDecisionV2?(request: Extract<DecisionAttemptReceipt['request'], {
|
|
18
|
+
promptKind: 'TASK_GROUP';
|
|
19
|
+
}>, canonicalRequestHash: string): Promise<DecisionSubmissionResult>;
|
|
20
|
+
}
|
|
21
|
+
export interface GateResolutionQueryResult {
|
|
22
|
+
sessionId: string;
|
|
23
|
+
promptId: string;
|
|
24
|
+
state: 'NOT_FOUND' | 'CLAIMED' | 'RESOLVED';
|
|
25
|
+
actionable: false;
|
|
26
|
+
decisionClaimId: string | null;
|
|
27
|
+
resolutionEventId: string | null;
|
|
28
|
+
resolutionTimestamp: string | null;
|
|
29
|
+
resolutionEvent: Event | null;
|
|
30
|
+
resolution: DurableGateResolution | null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Delete one local attempt fence only after a strict durable resolution has
|
|
34
|
+
* taken authority for the same prompt. A rejected race loser is deliberately
|
|
35
|
+
* eligible: its own attempt can never become RESOLVED, so the winning
|
|
36
|
+
* resolution is the handoff that makes deletion safe.
|
|
37
|
+
*/
|
|
38
|
+
export declare function acknowledgeDecisionAttemptAfterResolution(args: {
|
|
39
|
+
store: DecisionAttemptReceiptStore;
|
|
40
|
+
receipt: DecisionAttemptReceipt;
|
|
41
|
+
attempt: DecisionAttemptResult;
|
|
42
|
+
resolution: DurableGateResolution;
|
|
43
|
+
}): Promise<boolean>;
|
|
44
|
+
/**
|
|
45
|
+
* Production live/catch-up composition: finish the receipt-backed desktop
|
|
46
|
+
* effect first, then hand every matching decision-attempt fence to the same
|
|
47
|
+
* classified durable authority. The returned callback is shared with focused
|
|
48
|
+
* integration tests so they execute the exact production ordering.
|
|
49
|
+
*/
|
|
50
|
+
export interface DurableResolutionAttemptHandoff {
|
|
51
|
+
(resolution: DurableGateResolution): Promise<void>;
|
|
52
|
+
acknowledgeDelayedRejection(receipt: DecisionAttemptReceipt, resolution: DurableGateResolution): Promise<boolean>;
|
|
53
|
+
}
|
|
54
|
+
export declare function createDurableResolutionAttemptHandoff(args: {
|
|
55
|
+
store: DecisionAttemptReceiptStore;
|
|
56
|
+
client: Pick<DecisionAttemptRecoveryClient, 'getDecisionAttempt'>;
|
|
57
|
+
dispatchEffect: (resolution: DurableGateResolution) => Promise<void>;
|
|
58
|
+
}): DurableResolutionAttemptHandoff;
|
|
59
|
+
/**
|
|
60
|
+
* Reconcile every crash-durable receipt before the composer is enabled.
|
|
61
|
+
* Ambiguous states remain fenced. Only an explicit actionable terminal reject
|
|
62
|
+
* removes the receipt without a durable resolution Event.
|
|
63
|
+
*/
|
|
64
|
+
export declare function recoverDecisionAttemptReceipts(args: {
|
|
65
|
+
sessionId: string;
|
|
66
|
+
client: DecisionAttemptRecoveryClient;
|
|
67
|
+
store?: DecisionAttemptReceiptStore;
|
|
68
|
+
onResolutionEvent: (event: Event) => Promise<DurableGateResolution | null> | DurableGateResolution | null;
|
|
69
|
+
onActionableRejection: (receipt: DecisionAttemptReceipt, rejectionCode: string) => void;
|
|
70
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
export declare const DECISION_ATTEMPT_DOMAIN = "codevibe.decision_attempt.v1\0";
|
|
2
|
+
export declare const DECISION_ATTEMPT_RECEIPT_VERSION: 1;
|
|
3
|
+
export type GateDecisionKind = 'ACCEPT' | 'ACCEPT_WITH_NOTES' | 'REJECT_WITH_NOTES' | 'REJECT_RESTART' | 'ABORT_TASK' | 'APPROVE' | 'CANCEL' | 'CONTINUE_WITH';
|
|
4
|
+
export type GroupDecisionKind = Exclude<GateDecisionKind, 'APPROVE' | 'CANCEL' | 'CONTINUE_WITH'>;
|
|
5
|
+
export interface DecisionEncryptedNotes {
|
|
6
|
+
ciphertextB64: string;
|
|
7
|
+
keyVersion: 1;
|
|
8
|
+
sessionId: string;
|
|
9
|
+
}
|
|
10
|
+
export interface CanonicalGateDecisionRequest {
|
|
11
|
+
decision: GateDecisionKind;
|
|
12
|
+
decisionAttemptId: string;
|
|
13
|
+
gateId: string;
|
|
14
|
+
promptKind: 'GATE';
|
|
15
|
+
currentRound: number;
|
|
16
|
+
sessionId: string;
|
|
17
|
+
taskId: string;
|
|
18
|
+
notes?: DecisionEncryptedNotes;
|
|
19
|
+
}
|
|
20
|
+
export interface CanonicalGroupDecisionRequest {
|
|
21
|
+
decision: GroupDecisionKind;
|
|
22
|
+
decisionAttemptId: string;
|
|
23
|
+
groupGeneration: number;
|
|
24
|
+
promptId: string;
|
|
25
|
+
promptKind: 'TASK_GROUP';
|
|
26
|
+
sessionId: string;
|
|
27
|
+
taskGroupId: string;
|
|
28
|
+
notes?: DecisionEncryptedNotes;
|
|
29
|
+
}
|
|
30
|
+
export type CanonicalDecisionRequest = CanonicalGateDecisionRequest | CanonicalGroupDecisionRequest;
|
|
31
|
+
export type DecisionAttemptTerminal = {
|
|
32
|
+
state: 'RESOLVED';
|
|
33
|
+
decisionClaimId: string;
|
|
34
|
+
resolutionEventId: string;
|
|
35
|
+
resolutionTimestamp: string;
|
|
36
|
+
} | {
|
|
37
|
+
state: 'REJECTED';
|
|
38
|
+
rejectionCode: string;
|
|
39
|
+
actionable: boolean;
|
|
40
|
+
};
|
|
41
|
+
export interface DecisionAttemptReceipt {
|
|
42
|
+
version: typeof DECISION_ATTEMPT_RECEIPT_VERSION;
|
|
43
|
+
request: CanonicalDecisionRequest;
|
|
44
|
+
canonicalRequestHash: string;
|
|
45
|
+
canonicalRequestBytesB64: string;
|
|
46
|
+
createdAt: string;
|
|
47
|
+
updatedAt: string;
|
|
48
|
+
terminal?: DecisionAttemptTerminal;
|
|
49
|
+
}
|
|
50
|
+
export type DecisionRejectionCode = 'INVALID_PROMPT' | 'STALE_GENERATION' | 'DECISION_RACE_LOST' | 'ATTEMPT_LIMIT' | 'REQUEST_MISMATCH' | 'ACCOUNT_DELETING' | 'POLICY_REJECTED';
|
|
51
|
+
export type DecisionProgressStatus = 'PENDING' | 'PENDING_ERROR' | 'COMPLETE';
|
|
52
|
+
export type DecisionSubmissionResult = {
|
|
53
|
+
decisionAttemptId: string;
|
|
54
|
+
acceptanceStatus: 'SUBMITTED_PENDING';
|
|
55
|
+
promptId: string;
|
|
56
|
+
actionable: false;
|
|
57
|
+
decisionClaimId: null;
|
|
58
|
+
resolutionStatus: null;
|
|
59
|
+
workflowStatus: null;
|
|
60
|
+
resolutionEventId: null;
|
|
61
|
+
resolutionTimestamp: null;
|
|
62
|
+
rejectionCode: null;
|
|
63
|
+
} | {
|
|
64
|
+
decisionAttemptId: string;
|
|
65
|
+
acceptanceStatus: 'REJECTED';
|
|
66
|
+
promptId: string;
|
|
67
|
+
actionable: boolean;
|
|
68
|
+
decisionClaimId: null;
|
|
69
|
+
resolutionStatus: null;
|
|
70
|
+
workflowStatus: null;
|
|
71
|
+
resolutionEventId: null;
|
|
72
|
+
resolutionTimestamp: null;
|
|
73
|
+
rejectionCode: DecisionRejectionCode;
|
|
74
|
+
} | {
|
|
75
|
+
decisionAttemptId: string;
|
|
76
|
+
acceptanceStatus: 'ACCEPTED_PENDING';
|
|
77
|
+
promptId: string;
|
|
78
|
+
actionable: false;
|
|
79
|
+
decisionClaimId: string;
|
|
80
|
+
resolutionStatus: 'PENDING' | 'PENDING_ERROR';
|
|
81
|
+
workflowStatus: 'PENDING';
|
|
82
|
+
resolutionEventId: string;
|
|
83
|
+
resolutionTimestamp: null;
|
|
84
|
+
rejectionCode: null;
|
|
85
|
+
} | {
|
|
86
|
+
decisionAttemptId: string;
|
|
87
|
+
acceptanceStatus: 'ACCEPTED_RESOLVED';
|
|
88
|
+
promptId: string;
|
|
89
|
+
actionable: false;
|
|
90
|
+
decisionClaimId: string;
|
|
91
|
+
resolutionStatus: 'COMPLETE';
|
|
92
|
+
workflowStatus: DecisionProgressStatus;
|
|
93
|
+
resolutionEventId: string;
|
|
94
|
+
resolutionTimestamp: string;
|
|
95
|
+
rejectionCode: null;
|
|
96
|
+
};
|
|
97
|
+
export type DecisionAttemptResult = {
|
|
98
|
+
sessionId: string;
|
|
99
|
+
promptId: string;
|
|
100
|
+
decisionAttemptId: string;
|
|
101
|
+
state: 'NOT_FOUND';
|
|
102
|
+
canonicalRequestHash: null;
|
|
103
|
+
decisionClaimId: null;
|
|
104
|
+
resolutionEventId: null;
|
|
105
|
+
resolutionTimestamp: null;
|
|
106
|
+
rejectionCode: null;
|
|
107
|
+
actionable: false;
|
|
108
|
+
} | {
|
|
109
|
+
sessionId: string;
|
|
110
|
+
promptId: string;
|
|
111
|
+
decisionAttemptId: string;
|
|
112
|
+
state: 'SUBMITTED';
|
|
113
|
+
canonicalRequestHash: string;
|
|
114
|
+
decisionClaimId: null;
|
|
115
|
+
resolutionEventId: null;
|
|
116
|
+
resolutionTimestamp: null;
|
|
117
|
+
rejectionCode: null;
|
|
118
|
+
actionable: false;
|
|
119
|
+
} | {
|
|
120
|
+
sessionId: string;
|
|
121
|
+
promptId: string;
|
|
122
|
+
decisionAttemptId: string;
|
|
123
|
+
state: 'CLAIMED';
|
|
124
|
+
canonicalRequestHash: string;
|
|
125
|
+
decisionClaimId: string;
|
|
126
|
+
resolutionEventId: string;
|
|
127
|
+
resolutionTimestamp: null;
|
|
128
|
+
rejectionCode: null;
|
|
129
|
+
actionable: false;
|
|
130
|
+
} | {
|
|
131
|
+
sessionId: string;
|
|
132
|
+
promptId: string;
|
|
133
|
+
decisionAttemptId: string;
|
|
134
|
+
state: 'RESOLVED';
|
|
135
|
+
canonicalRequestHash: string;
|
|
136
|
+
decisionClaimId: string;
|
|
137
|
+
resolutionEventId: string;
|
|
138
|
+
resolutionTimestamp: string;
|
|
139
|
+
rejectionCode: null;
|
|
140
|
+
actionable: false;
|
|
141
|
+
} | {
|
|
142
|
+
sessionId: string;
|
|
143
|
+
promptId: string;
|
|
144
|
+
decisionAttemptId: string;
|
|
145
|
+
state: 'REJECTED';
|
|
146
|
+
canonicalRequestHash: string | null;
|
|
147
|
+
decisionClaimId: null;
|
|
148
|
+
resolutionEventId: null;
|
|
149
|
+
resolutionTimestamp: null;
|
|
150
|
+
rejectionCode: DecisionRejectionCode;
|
|
151
|
+
actionable: boolean;
|
|
152
|
+
};
|
|
153
|
+
export declare function canonicalizeGateDecisionRequest(input: Omit<CanonicalGateDecisionRequest, 'promptKind'> & {
|
|
154
|
+
promptKind?: 'GATE';
|
|
155
|
+
}): CanonicalGateDecisionRequest;
|
|
156
|
+
export declare function canonicalizeGroupDecisionRequest(input: Omit<CanonicalGroupDecisionRequest, 'promptKind' | 'promptId'> & {
|
|
157
|
+
promptKind?: 'TASK_GROUP';
|
|
158
|
+
promptId?: string;
|
|
159
|
+
}): CanonicalGroupDecisionRequest;
|
|
160
|
+
export declare function canonicalDecisionRequestBytes(request: CanonicalDecisionRequest): Buffer;
|
|
161
|
+
export declare function canonicalDecisionRequestHash(request: CanonicalDecisionRequest): string;
|
|
162
|
+
export declare function makeDecisionAttemptReceipt(request: CanonicalDecisionRequest, now?: Date): DecisionAttemptReceipt;
|
|
163
|
+
export declare function parseDecisionSubmissionResult(value: unknown): DecisionSubmissionResult;
|
|
164
|
+
export declare function parseDecisionAttemptResult(value: unknown): DecisionAttemptResult;
|
|
165
|
+
export declare class DecisionAttemptReceiptStore {
|
|
166
|
+
/**
|
|
167
|
+
* Every store instance targeting the same root shares one session queue.
|
|
168
|
+
* Production injects one store through submit, subscription/catch-up, and
|
|
169
|
+
* startup recovery; the process-wide map also keeps accidental sibling
|
|
170
|
+
* instances from exposing atomic-write temporaries to enumeration.
|
|
171
|
+
*/
|
|
172
|
+
private static readonly sessionQueues;
|
|
173
|
+
private readonly rootDir;
|
|
174
|
+
private readonly syncDirectory;
|
|
175
|
+
constructor(options?: {
|
|
176
|
+
rootDir?: string;
|
|
177
|
+
directorySync?: (directory: string) => Promise<void>;
|
|
178
|
+
});
|
|
179
|
+
private receiptPath;
|
|
180
|
+
private sessionQueueKey;
|
|
181
|
+
private withSessionLock;
|
|
182
|
+
private assertNoSymlinkComponents;
|
|
183
|
+
private atomicWrite;
|
|
184
|
+
/**
|
|
185
|
+
* Remove one receipt name and persist that directory-entry transition before
|
|
186
|
+
* returning. ENOENT is idempotent only after the still-present directory is
|
|
187
|
+
* synced; an absent directory has no entry that can be resurrected.
|
|
188
|
+
*/
|
|
189
|
+
private removeDirectoryEntryDurably;
|
|
190
|
+
private readUnlocked;
|
|
191
|
+
private sameImmutableIdentity;
|
|
192
|
+
write(receipt: DecisionAttemptReceipt): Promise<void>;
|
|
193
|
+
read(sessionId: string, promptId: string, decisionAttemptId: string): Promise<DecisionAttemptReceipt | null>;
|
|
194
|
+
/**
|
|
195
|
+
* Return the bounded set of unacknowledged receipts for one session. Paths
|
|
196
|
+
* are opaque hashes, regular files only, and every receipt is revalidated
|
|
197
|
+
* against its canonical bytes before it can participate in recovery.
|
|
198
|
+
*/
|
|
199
|
+
private listForSessionUnlocked;
|
|
200
|
+
listForSession(sessionId: string): Promise<DecisionAttemptReceipt[]>;
|
|
201
|
+
markTerminal(receipt: DecisionAttemptReceipt, terminal: DecisionAttemptTerminal, now?: Date): Promise<DecisionAttemptReceipt | null>;
|
|
202
|
+
/**
|
|
203
|
+
* Remove an exact receipt only while its caller still owns the synchronous
|
|
204
|
+
* pre-submit boundary. This transition is intentionally separate from
|
|
205
|
+
* `acknowledge`: no server attempt exists yet, so inventing a terminal state
|
|
206
|
+
* would make later recovery contradict the server. The caller MUST invoke it
|
|
207
|
+
* before calling the submission transport.
|
|
208
|
+
*/
|
|
209
|
+
abandonUnsubmitted(receipt: DecisionAttemptReceipt): Promise<void>;
|
|
210
|
+
acknowledge(receipt: DecisionAttemptReceipt): Promise<void>;
|
|
211
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { DurableGateResolution, PostDecisionAction } from './types';
|
|
2
|
+
declare const RECEIPT_VERSION: 1;
|
|
3
|
+
export interface DecisionEffectReceipt {
|
|
4
|
+
version: typeof RECEIPT_VERSION;
|
|
5
|
+
sessionId: string;
|
|
6
|
+
promptId: string;
|
|
7
|
+
decisionClaimId: string;
|
|
8
|
+
resolutionEventId: string;
|
|
9
|
+
descriptorHash: string;
|
|
10
|
+
resolution: DurableGateResolution;
|
|
11
|
+
state: 'PENDING' | 'COMPLETE';
|
|
12
|
+
createdAt: string;
|
|
13
|
+
updatedAt: string;
|
|
14
|
+
}
|
|
15
|
+
export type DecisionEffectHandler = (resolution: DurableGateResolution, postAction: PostDecisionAction | null) => Promise<void> | void;
|
|
16
|
+
export declare function durableResolutionDescriptorHash(resolution: DurableGateResolution): string;
|
|
17
|
+
export declare class DecisionEffectReceiptStore {
|
|
18
|
+
private readonly rootDir;
|
|
19
|
+
constructor(options?: {
|
|
20
|
+
rootDir?: string;
|
|
21
|
+
});
|
|
22
|
+
private receiptPath;
|
|
23
|
+
private assertNoSymlinkComponents;
|
|
24
|
+
private atomicWrite;
|
|
25
|
+
read(sessionId: string, decisionClaimId: string): Promise<DecisionEffectReceipt | null>;
|
|
26
|
+
reserve(resolution: DurableGateResolution, now?: Date): Promise<DecisionEffectReceipt>;
|
|
27
|
+
complete(receipt: DecisionEffectReceipt, now?: Date): Promise<DecisionEffectReceipt>;
|
|
28
|
+
listForSession(sessionId: string): Promise<DecisionEffectReceipt[]>;
|
|
29
|
+
}
|
|
30
|
+
export declare function postDecisionActionForResolution(resolution: DurableGateResolution): PostDecisionAction | null;
|
|
31
|
+
export declare class DecisionEffectDispatcher {
|
|
32
|
+
private readonly store;
|
|
33
|
+
private readonly handler;
|
|
34
|
+
private readonly afterComplete?;
|
|
35
|
+
constructor(store: DecisionEffectReceiptStore, handler: DecisionEffectHandler, afterComplete?: ((resolution: DurableGateResolution) => Promise<void> | void) | undefined);
|
|
36
|
+
dispatch(resolution: DurableGateResolution): Promise<void>;
|
|
37
|
+
replayPending(sessionId: string): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AppSyncClient } from '../appsync';
|
|
2
|
-
import { type Session } from '../types';
|
|
2
|
+
import { CreateEventInput, type Session } from '../types';
|
|
3
3
|
import type { E1ProducerKind } from '../e1';
|
|
4
4
|
/**
|
|
5
5
|
* §3 LOCK lines 173-181. Names + per-type metadata shapes are part of
|
|
@@ -33,6 +33,18 @@ export interface ShellEventEmit {
|
|
|
33
33
|
timestamp?: string;
|
|
34
34
|
/** Pre-minted nonce when encrypted metadata must bind the response nonce. */
|
|
35
35
|
writerEventNonce?: string;
|
|
36
|
+
/** P16/P20 encrypted terminal-result authority. All four fields are atomic. */
|
|
37
|
+
writerEventKind?: 'WORKSPACE_OUTCOME';
|
|
38
|
+
writerSessionGenerationId?: string;
|
|
39
|
+
writerOutcomeSubject?: {
|
|
40
|
+
subjectKind: 'task';
|
|
41
|
+
subjectId: string;
|
|
42
|
+
} | {
|
|
43
|
+
subjectKind: 'task_group';
|
|
44
|
+
subjectId: string;
|
|
45
|
+
groupGeneration: number;
|
|
46
|
+
};
|
|
47
|
+
writerCausalPredecessor?: Record<string, unknown>;
|
|
36
48
|
/** Proven local key mismatch: emit the safe legacy joined fallback. */
|
|
37
49
|
disableWriterAttestation?: boolean;
|
|
38
50
|
ownerToken?: string;
|
|
@@ -51,6 +63,12 @@ export interface EmitShellEventDeps {
|
|
|
51
63
|
appsyncClient: Pick<AppSyncClient, 'createEvent'>;
|
|
52
64
|
getSessionKey: (sessionId: string) => Promise<string | null>;
|
|
53
65
|
session?: Session;
|
|
66
|
+
/**
|
|
67
|
+
* Persist an exact encrypted/signed input without sending it. Reserved for
|
|
68
|
+
* crash-safe workspace-outcome drafts that must remain undiscoverable until
|
|
69
|
+
* their hosted COMMIT boundary is confirmed.
|
|
70
|
+
*/
|
|
71
|
+
prepareOnly?: (input: CreateEventInput) => Promise<void>;
|
|
54
72
|
}
|
|
55
73
|
export type ShellEventEmitResult = {
|
|
56
74
|
emitted: true;
|
|
@@ -66,7 +84,7 @@ export type ShellEventEmitResult = {
|
|
|
66
84
|
};
|
|
67
85
|
} | {
|
|
68
86
|
emitted: false;
|
|
69
|
-
reason: 'missing_session_key' | 'auth_required' | 'auth_unavailable' | 'create_failed' | 'definitive_rejection' | 'invalid_response' | 'writer_ineligible';
|
|
87
|
+
reason: 'missing_session_key' | 'auth_required' | 'auth_unavailable' | 'create_failed' | 'definitive_rejection' | 'invalid_response' | 'prepared_only' | 'writer_ineligible';
|
|
70
88
|
error?: unknown;
|
|
71
89
|
};
|
|
72
90
|
/**
|
package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/gate-decision-submit.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { OrchestrationStore } from './store';
|
|
2
|
-
import type { ConversationEntry, PostDecisionAction } from './types';
|
|
2
|
+
import type { ConversationEntry, DurableGateResolution, PostDecisionAction } from './types';
|
|
3
|
+
import { DecisionAttemptReceiptStore, type CanonicalGateDecisionRequest, type CanonicalGroupDecisionRequest, type DecisionAttemptReceipt, type DecisionSubmissionResult } from './decision-attempt';
|
|
3
4
|
/**
|
|
4
5
|
* Minimal SDK contract for the `applyUserDecision` wire. Structurally
|
|
5
6
|
* compatible with the full `AppSyncClient.applyUserDecision` signature — keeps
|
|
@@ -7,6 +8,9 @@ import type { ConversationEntry, PostDecisionAction } from './types';
|
|
|
7
8
|
* inject a stub). Mirrors `ApplyUserDecisionClient` in `<OrchestrationApp>`.
|
|
8
9
|
*/
|
|
9
10
|
export interface ApplyUserDecisionClient {
|
|
11
|
+
submitGateDecisionV2?(request: CanonicalGateDecisionRequest, canonicalRequestHash: string): Promise<DecisionSubmissionResult>;
|
|
12
|
+
submitGroupDecisionV2?(request: CanonicalGroupDecisionRequest, canonicalRequestHash: string): Promise<DecisionSubmissionResult>;
|
|
13
|
+
/** Retained only as a structural compatibility member for older test/plugin clients. */
|
|
10
14
|
applyUserDecision(input: {
|
|
11
15
|
gateId: string;
|
|
12
16
|
taskId: string;
|
|
@@ -18,7 +22,10 @@ export interface ApplyUserDecisionClient {
|
|
|
18
22
|
decision: string;
|
|
19
23
|
postAction: PostDecisionAction;
|
|
20
24
|
}>;
|
|
25
|
+
/** Test-only structural injection; the production AppSync client omits it. */
|
|
26
|
+
decisionAttemptReceiptStore?: DecisionAttemptReceiptStoreSurface;
|
|
21
27
|
}
|
|
28
|
+
type DecisionAttemptReceiptStoreSurface = Pick<DecisionAttemptReceiptStore, 'write' | 'markTerminal' | 'abandonUnsubmitted' | 'acknowledge'>;
|
|
22
29
|
/** Dependencies common to both the TTY + non-TTY gate-resolution paths. */
|
|
23
30
|
export interface GateDecisionSubmitDeps {
|
|
24
31
|
store: OrchestrationStore;
|
|
@@ -26,6 +33,14 @@ export interface GateDecisionSubmitDeps {
|
|
|
26
33
|
appsyncClient: ApplyUserDecisionClient;
|
|
27
34
|
/** Just-in-time session-key resolver (only consulted when notes are present). */
|
|
28
35
|
getSessionKey: (sessionId: string) => Promise<string | null>;
|
|
36
|
+
/** Optional override for isolated tests; production uses the durable 0600 store. */
|
|
37
|
+
decisionAttemptReceiptStore?: DecisionAttemptReceiptStoreSurface;
|
|
38
|
+
/**
|
|
39
|
+
* Production effect-completion barrier for a response that loses after the
|
|
40
|
+
* winner Event was already classified. It returns false when no matching
|
|
41
|
+
* completed/in-flight durable handoff exists, leaving the receipt fenced.
|
|
42
|
+
*/
|
|
43
|
+
acknowledgeDelayedRejection?: (receipt: DecisionAttemptReceipt, resolution: DurableGateResolution) => Promise<boolean>;
|
|
29
44
|
/**
|
|
30
45
|
* Optional — notified after a successful `applyUserDecision` with the engine's
|
|
31
46
|
* `postAction` (the QuorumLoop wires it to discard the shadow on a
|
|
@@ -47,7 +62,7 @@ export interface GateDecisionSubmitDeps {
|
|
|
47
62
|
* 2026-06-11, option-4 "Reject and restart"). `undefined` when no shadow was
|
|
48
63
|
* mapped at decision time (or no loop is wired).
|
|
49
64
|
*/
|
|
50
|
-
onTerminalDecision?: (taskId: string, postAction: PostDecisionAction, expectedShadow?: unknown) => void;
|
|
65
|
+
onTerminalDecision?: (taskId: string, postAction: PostDecisionAction, expectedShadow?: unknown) => Promise<void> | void;
|
|
51
66
|
/**
|
|
52
67
|
* Optional — resolves the live shadow INSTANCE for a task at decision time. Read
|
|
53
68
|
* ONCE at the TOP of `submitGateDecision` (BEFORE the `applyUserDecision` SDK
|
|
@@ -94,6 +109,7 @@ export declare function submitGateDecision(deps: GateDecisionSubmitDeps, promptE
|
|
|
94
109
|
taskId: string;
|
|
95
110
|
sessionId: string;
|
|
96
111
|
currentRound: number;
|
|
112
|
+
decisionProtocolVersion?: 1 | 2;
|
|
97
113
|
decision: string;
|
|
98
114
|
notes?: string;
|
|
99
115
|
}): Promise<void>;
|
|
@@ -157,6 +173,8 @@ export interface GroupDecisionSubmitDeps {
|
|
|
157
173
|
* post-image proof before marking accepted or clearing reviewed bundles.
|
|
158
174
|
*/
|
|
159
175
|
finalizeAcceptedGroup: (taskGroupId: string) => Promise<void>;
|
|
176
|
+
/** Count the exact distinct materialized paths before accepted-state GC. */
|
|
177
|
+
getRetainedFileCount?: (taskGroupId: string) => Promise<number>;
|
|
160
178
|
/**
|
|
161
179
|
* HIGH-1 / LOCK #589-J — persist the CLAIMED-but-not-COMMITted decision to the
|
|
162
180
|
* durable record, called IMMEDIATELY after the CLAIM phase mints `claimToken`
|
|
@@ -99,6 +99,8 @@ export interface GatePromptOption {
|
|
|
99
99
|
*/
|
|
100
100
|
export interface GatePromptEnvelope {
|
|
101
101
|
readonly promptKind: GatePromptKind;
|
|
102
|
+
/** Immutable server stamp; absent only on legacy v1 prompt Events. */
|
|
103
|
+
readonly decisionProtocolVersion?: 1 | 2;
|
|
102
104
|
readonly taskId: string;
|
|
103
105
|
readonly gateId: string;
|
|
104
106
|
readonly currentRound: number;
|
|
@@ -120,6 +122,8 @@ export interface GatePromptEnvelope {
|
|
|
120
122
|
readonly packetHash?: string;
|
|
121
123
|
readonly groupEscalation?: {
|
|
122
124
|
readonly taskGroupId: string;
|
|
125
|
+
readonly groupGeneration?: number;
|
|
126
|
+
readonly protocolVersion: 1 | 2;
|
|
123
127
|
};
|
|
124
128
|
}
|
|
125
129
|
/**
|
package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/gate-resolution-event.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Event } from '../types/events';
|
|
2
|
+
import type { DurableGateResolution } from './types';
|
|
3
|
+
/** A known decision may execute only through its exact closed recipe pair. */
|
|
4
|
+
export declare function supportedResolutionLabel(decision: unknown, effectRecipe: unknown): string | null;
|
|
5
|
+
/**
|
|
6
|
+
* Accept only the unforgeable server-authored P16/P20 resolution profile.
|
|
7
|
+
* Returning null is intentionally fail-open for prompt availability: an
|
|
8
|
+
* untrusted Notification remains generic and can never retire an action.
|
|
9
|
+
*/
|
|
10
|
+
export declare function classifyDurableGateResolution(event: Event, displayedSessionId: string): DurableGateResolution | null;
|
|
@@ -5,6 +5,7 @@ import { OrchestrationStore } from './store';
|
|
|
5
5
|
import { AdvisoryAttachmentJournal } from './advisory-attachment-journal';
|
|
6
6
|
import type { ImageAttachment } from './types';
|
|
7
7
|
import { type GateDecisionSubmitDeps, type GroupDecisionSubmitDeps } from './gate-decision-submit';
|
|
8
|
+
import { type WorkspaceOutcomeSinkTap } from './workspace-terminal-coordinator';
|
|
8
9
|
import { type ContinuationCliResult, type ContinuationCliDeps } from './slash-routes/continuation';
|
|
9
10
|
import { loadReviewerWizardData } from './slash-routes/reviewers';
|
|
10
11
|
import { createShellEventEmitter } from './emit-shell-event';
|
|
@@ -13,7 +14,7 @@ import { type BrainstormPanelActiveAgent } from './brainstorm-quorum';
|
|
|
13
14
|
import { type RunAuditBrowserResult } from './audit-runner';
|
|
14
15
|
import { type RunFlagCommandResult } from './flag-command';
|
|
15
16
|
import { Tier } from './types';
|
|
16
|
-
import type { ConversationEntry, PendingClarification } from './types';
|
|
17
|
+
import type { ConversationEntry, DurableGateResolution, PendingClarification } from './types';
|
|
17
18
|
import { type GatePromptEnvelope, type DecryptedReviewSummaryInput } from './gate-prompts';
|
|
18
19
|
import type { Event, UpdateEventStatusInput } from '../types/events';
|
|
19
20
|
import { type StructuralSummaryGenerator } from '../structural-summary';
|
|
@@ -116,6 +117,8 @@ export interface RunOrchestrationShellArgs {
|
|
|
116
117
|
* subscription, no team mode, no status node (byte-identical behavior).
|
|
117
118
|
*/
|
|
118
119
|
localExecutor?: LocalExecutor;
|
|
120
|
+
/** Shell-installed writer-outcome coordinator used by v2 team promotion. */
|
|
121
|
+
workspaceOutcomeTap?: WorkspaceOutcomeSinkTap;
|
|
119
122
|
/**
|
|
120
123
|
* CP-12 W3 §3.5 — store-tap installed by `cli.ts` so the team-mode LE's
|
|
121
124
|
* per-track shell events (W2.b `emitTrackProgress` NOTIFICATIONs carrying
|
|
@@ -362,7 +365,7 @@ export declare const TASK_REVIEW_SUMMARY_FETCH_TIMEOUT_MS = 5000;
|
|
|
362
365
|
* unit-testable with a mock).
|
|
363
366
|
*/
|
|
364
367
|
export type ReviewSummaryFetcher = (taskId: string, gateId: string, sessionId: string) => Promise<DecryptedReviewSummaryInput | null>;
|
|
365
|
-
export declare function handleSubscribedEvent(event: Event, store: OrchestrationStore, sessionKeyResolver?: (sessionId: string) => Promise<string | null>, reviewSummaryFetcher?: ReviewSummaryFetcher, maybeAutoContinue?: (envelope: GatePromptEnvelope) => boolean): void;
|
|
368
|
+
export declare function handleSubscribedEvent(event: Event, store: OrchestrationStore, sessionKeyResolver?: (sessionId: string) => Promise<string | null>, reviewSummaryFetcher?: ReviewSummaryFetcher, maybeAutoContinue?: (envelope: GatePromptEnvelope) => boolean, onDurableGateResolution?: (resolution: DurableGateResolution) => Promise<void> | void): void;
|
|
366
369
|
/**
|
|
367
370
|
* Route a `USER_PROMPT` sent from the paired MOBILE companion into the shell's
|
|
368
371
|
* SERIALIZED submission pipeline so the planner processes it EXACTLY like a typed
|
|
@@ -427,6 +430,7 @@ export declare function createSubscribedEventDispatcher(deps: {
|
|
|
427
430
|
sessionKeyResolver?: (sessionId: string) => Promise<string | null>;
|
|
428
431
|
reviewSummaryFetcher?: ReviewSummaryFetcher;
|
|
429
432
|
maybeAutoContinue?: (envelope: GatePromptEnvelope) => boolean;
|
|
433
|
+
onDurableGateResolution?: (resolution: DurableGateResolution) => Promise<void> | void;
|
|
430
434
|
updateEventStatus?: (input: UpdateEventStatusInput) => Promise<unknown>;
|
|
431
435
|
}): (event: Event) => void;
|
|
432
436
|
/**
|
|
@@ -21,6 +21,7 @@ import type { SubstrateHandle } from '../substrate/types';
|
|
|
21
21
|
import type { VerdictClassifier } from '../reviewer/verdict-classifier';
|
|
22
22
|
import type { AgentKind as ReviewerAgentKind, ReviewerRole, VerdictKind } from '../reviewer/types';
|
|
23
23
|
import type { OnProgress } from './task-progress';
|
|
24
|
+
import type { WorkspaceOutcomeSink } from './workspace-terminal-coordinator';
|
|
24
25
|
import { runShellCommand } from '../local-executor/verification-gates/shell-runner';
|
|
25
26
|
import type { PostDecisionAction, Tier } from './types';
|
|
26
27
|
import type { ContinuationPacketWriter } from '../continuation/packet-writer';
|
|
@@ -552,6 +553,7 @@ export declare function teamRound0GateId(taskId: string, taskGroupId: string, tr
|
|
|
552
553
|
export declare class QuorumLoop {
|
|
553
554
|
private readonly deps;
|
|
554
555
|
private readonly sleep;
|
|
556
|
+
private workspaceOutcomeSink?;
|
|
555
557
|
/** The active task this desktop is driving (set at start_task). */
|
|
556
558
|
private activeTaskId;
|
|
557
559
|
/** Tasks whose next automatic revise round must start a fresh review baseline. */
|
|
@@ -1146,6 +1148,9 @@ export declare class QuorumLoop {
|
|
|
1146
1148
|
*/
|
|
1147
1149
|
private lastWorkspaceOutcome;
|
|
1148
1150
|
constructor(deps: QuorumLoopDeps);
|
|
1151
|
+
/** Installed by the session-owning shell after both objects are constructed. */
|
|
1152
|
+
setWorkspaceOutcomeSink(sink: WorkspaceOutcomeSink | undefined): void;
|
|
1153
|
+
isWorkspaceTaskTerminallyRetired(taskId: string): boolean;
|
|
1149
1154
|
/** The current active task id (for the recovery poll). */
|
|
1150
1155
|
get activeTask(): string | null;
|
|
1151
1156
|
/** Arm an explicit, one-shot comprehensive baseline for the active task. */
|
|
@@ -1402,6 +1407,12 @@ export declare class QuorumLoop {
|
|
|
1402
1407
|
private ensureShadowLocked;
|
|
1403
1408
|
/** The shadow for `taskId` (introspection / the terminal promote/discard handlers). */
|
|
1404
1409
|
shadowForTask(taskId: string): WorkspaceShadow | undefined;
|
|
1410
|
+
/**
|
|
1411
|
+
* Durable-decision restart guard. Once the deterministic successor gate has
|
|
1412
|
+
* entered execution, the task's mapped shadow belongs to that successor and
|
|
1413
|
+
* must never be discarded as the parent gate's rejected snapshot.
|
|
1414
|
+
*/
|
|
1415
|
+
gateExecutionHasStarted(gateId: string): boolean;
|
|
1405
1416
|
/**
|
|
1406
1417
|
* Spawn the EXECUTE-mode implementor for one round in the task's SHADOW,
|
|
1407
1418
|
* capture the shadow-vs-real diff, and submit it as the execute-first
|
package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/supervision-catch-up.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Event } from '../types/events';
|
|
2
|
+
/**
|
|
3
|
+
* `listSupervisionEvents` returns one globally newest-first DynamoDB walk.
|
|
4
|
+
* Reverse a copy only after every page has been drained so page boundaries do
|
|
5
|
+
* not invert causal prompt → resolution → workspace-outcome ordering.
|
|
6
|
+
*/
|
|
7
|
+
export declare function chronologicalSupervisionEvents(newestFirstEvents: readonly Event[]): Event[];
|