newmark-agent 0.6.2 → 0.6.4

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.
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ /**
3
+ * continuation-v1 contracts.
4
+ *
5
+ * These are the runtime-checked boundaries shared by the PC GUI, the hosted
6
+ * mobile API and the isolated runtimes. A view may read a snapshot, but it can
7
+ * never supply the execution identity that a write is allowed to use.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.ContinuationError = exports.CONTINUATION_SCHEMA_VERSION = void 0;
11
+ exports.stableJson = stableJson;
12
+ exports.emptyLedger = emptyLedger;
13
+ exports.defaultGuard = defaultGuard;
14
+ exports.commandKey = commandKey;
15
+ exports.buildInputHash = buildInputHash;
16
+ exports.requestHash = requestHash;
17
+ exports.CONTINUATION_SCHEMA_VERSION = 1;
18
+ class ContinuationError extends Error {
19
+ code;
20
+ detail;
21
+ constructor(code, message, detail) {
22
+ super(message);
23
+ this.code = code;
24
+ this.detail = detail;
25
+ this.name = 'ContinuationError';
26
+ }
27
+ }
28
+ exports.ContinuationError = ContinuationError;
29
+ function stableJson(value) {
30
+ if (value === null || typeof value !== 'object')
31
+ return JSON.stringify(value);
32
+ if (Array.isArray(value))
33
+ return `[${value.map(item => stableJson(item)).join(',')}]`;
34
+ const record = value;
35
+ return `{${Object.keys(record).sort().map(key => `${JSON.stringify(key)}:${stableJson(record[key])}`).join(',')}}`;
36
+ }
37
+ function emptyLedger(workspaceId) {
38
+ return {
39
+ version: exports.CONTINUATION_SCHEMA_VERSION,
40
+ workspaceId,
41
+ roots: {},
42
+ branches: {},
43
+ builds: {},
44
+ attempts: {},
45
+ guards: {},
46
+ commands: {},
47
+ finals: {},
48
+ events: [],
49
+ nextEventCursor: 1,
50
+ nextQueueSequence: 1,
51
+ };
52
+ }
53
+ function defaultGuard(branchId) {
54
+ return { branchId, activeBuildId: null, activeAttemptId: null, fence: 0, leaseUntil: 0, workerCapability: '' };
55
+ }
56
+ function commandKey(actorId, commandId) {
57
+ return `${actorId}\u0000${commandId}`;
58
+ }
59
+ function buildInputHash(input) {
60
+ return require('crypto').createHash('sha256').update(stableJson(input)).digest('hex').slice(0, 24);
61
+ }
62
+ function requestHash(command) {
63
+ return require('crypto').createHash('sha256').update(stableJson({
64
+ type: command.type,
65
+ target: command.target,
66
+ expectedTailBuildId: command.expectedTailBuildId,
67
+ expectedQueueRevision: command.expectedQueueRevision,
68
+ input: command.input,
69
+ recipeSnapshotId: command.recipeSnapshotId,
70
+ })).digest('hex');
71
+ }
72
+ //# sourceMappingURL=contracts.js.map
@@ -0,0 +1,206 @@
1
+ import { BranchId, BranchRecord, BuildId, BuildInput, BuildRecord, CommandReceipt, ContinuationEvent, EnqueueBuildCommand, ExecutionScope, FinalRecord, QueueSnapshot, RootId, SnapshotId } from './contracts';
2
+ export interface GuardedContinuationStoreOptions {
3
+ /** Lease duration for one attempt. */
4
+ leaseMs?: number;
5
+ /** Maximum retained append-only events per workspace ledger. */
6
+ eventRetention?: number;
7
+ }
8
+ /**
9
+ * Single-writer continuation ledger for one workspace.
10
+ *
11
+ * The spec's reference uses SQLite. This implementation keeps the same
12
+ * boundaries with a lock-file + atomic-replace JSON ledger because the project
13
+ * does not ship a native SQLite module and an Electron native dependency would
14
+ * change the packaging/signing contract. All continuation writes must go
15
+ * through this class; callers never mutate the ledger directly.
16
+ */
17
+ export declare class GuardedContinuationStore {
18
+ private readonly workspacePath;
19
+ private readonly workspaceId;
20
+ private readonly ledgerPath;
21
+ private readonly lockPath;
22
+ private readonly leaseMs;
23
+ private readonly eventRetention;
24
+ private fingerprint;
25
+ private cached;
26
+ constructor(workspacePath: string, workspaceId: string, options?: GuardedContinuationStoreOptions);
27
+ get filePath(): string;
28
+ ensureRoot(rootId: RootId, defaultBranchId: BranchId): void;
29
+ ensureBranch(input: {
30
+ rootId: RootId;
31
+ branchId: BranchId;
32
+ parentAnchorBuildId: BuildId | null;
33
+ }): BranchRecord;
34
+ getReceipt(actorId: string, commandId: string): CommandReceipt | undefined;
35
+ enqueueBuild(command: EnqueueBuildCommand): CommandReceipt;
36
+ claimBuild(input: {
37
+ workspaceId: string;
38
+ rootId: RootId;
39
+ branchId: BranchId;
40
+ workerCapability: string;
41
+ now?: number;
42
+ }): ExecutionScope | null;
43
+ updateQueuedBuild(input: {
44
+ workspaceId: string;
45
+ rootId: RootId;
46
+ branchId: BranchId;
47
+ buildId: BuildId;
48
+ input: BuildInput;
49
+ }): BuildRecord;
50
+ /**
51
+ * dev-0.6.4 hotfix: 当某个被受理的 Build 失败/取消后,它的后继会永远无法被
52
+ * claim(`claimBuild` 只认「父 = 已提交 frontier」),整条队列就此卡死,新提交
53
+ * 也只是接在失败链后面。
54
+ *
55
+ * 这里提供一条**显式**修复通道:把被阻断的排队 Build 重新挂到当前已提交的
56
+ * frontier 上,保持原有队列顺序,并为每一次改挂写入 `BuildQueueRepaired`
57
+ * 审计事件(记录旧 parent / 新 parent / 原因)。它不是静默 rebase:调用方是
58
+ * 用户的显式动作(恢复队列)或一次新的入队命令。
59
+ */
60
+ repairBlockedQueue(input: {
61
+ workspaceId: string;
62
+ rootId: RootId;
63
+ branchId: BranchId;
64
+ reason?: string;
65
+ }): {
66
+ repaired: BuildId[];
67
+ frontier: BuildId | null;
68
+ };
69
+ /**
70
+ * dev-0.6.4 hotfix: 读取视角的受阻推导。
71
+ *
72
+ * 一个 QUEUED Build 只有在它的父正好是「已提交 frontier」或队列里位于它之前
73
+ * 的可执行 Build 时才可能被 claim(见 `claimBuild`)。这里按队列顺序推导哪些行
74
+ * 目前不可执行:父不是链上前驱、或父已 FAILED/CANCELLED 的行即为受阻,且受阻点
75
+ * 之后的所有行同样受阻。
76
+ */
77
+ private blockedQueuedBuildIds;
78
+ deleteQueuedBuild(input: {
79
+ workspaceId: string;
80
+ rootId: RootId;
81
+ branchId: BranchId;
82
+ buildId: BuildId;
83
+ }): void;
84
+ reorderQueuedBuilds(input: {
85
+ workspaceId: string;
86
+ rootId: RootId;
87
+ branchId: BranchId;
88
+ orderedBuildIds: BuildId[];
89
+ }): QueueSnapshot;
90
+ heartbeat(scope: Pick<ExecutionScope, 'branchId' | 'buildId' | 'attemptId' | 'fence'>, now?: number): boolean;
91
+ commitFinal(input: {
92
+ scope: ExecutionScope;
93
+ text: string;
94
+ finalHash?: string;
95
+ stateSnapshotId?: SnapshotId;
96
+ now?: number;
97
+ }): FinalRecord;
98
+ /**
99
+ * Trusted external-owner completion.
100
+ *
101
+ * A Flow is a kernel-owned external run, not a leased model worker. It still
102
+ * has to be a durable build so queued Goal/Next successors have a committed
103
+ * parent. This path validates the parent/head relation transactionally but
104
+ * does not require a BranchGuard attempt; the kernel owns the Flow lifetime.
105
+ * If the build is not the next ready build, it stays QUEUED and the caller
106
+ * must retry after the predecessor commits.
107
+ */
108
+ commitExternalBuild(input: {
109
+ workspaceId: string;
110
+ rootId: RootId;
111
+ branchId: BranchId;
112
+ buildId: BuildId;
113
+ text?: string;
114
+ now?: number;
115
+ }): boolean;
116
+ /**
117
+ * Claim a new attempt for an existing external Flow build (suspend/resume).
118
+ * The build identity and fixed parent are preserved; only the attempt/fence
119
+ * advance. This is the external-owner equivalent of retryBuild.
120
+ */
121
+ claimExternalBuild(input: {
122
+ workspaceId: string;
123
+ rootId: RootId;
124
+ branchId: BranchId;
125
+ buildId: BuildId;
126
+ workerCapability?: string;
127
+ now?: number;
128
+ }): ExecutionScope;
129
+ failBuild(input: {
130
+ scope: ExecutionScope;
131
+ reason: string;
132
+ now?: number;
133
+ }): void;
134
+ cancelBuild(input: {
135
+ workspaceId: string;
136
+ rootId: RootId;
137
+ branchId: BranchId;
138
+ buildId: BuildId;
139
+ now?: number;
140
+ }): void;
141
+ retryBuild(input: {
142
+ workspaceId: string;
143
+ rootId: RootId;
144
+ branchId: BranchId;
145
+ buildId: BuildId;
146
+ }): BuildRecord;
147
+ /**
148
+ * Idempotent failure recovery for an input that was never accepted.
149
+ *
150
+ * Stop/archive may release the branch guard before the runtime reports the
151
+ * failure. In that case the build is still the same durable row and must be
152
+ * returned to QUEUED for an explicit resume instead of being stranded in
153
+ * RUNNING (or permanently FAILED). A committed build is never requeued.
154
+ */
155
+ requeueBuild(input: {
156
+ workspaceId: string;
157
+ rootId: RootId;
158
+ branchId: BranchId;
159
+ buildId: BuildId;
160
+ }): BuildRecord;
161
+ forkBranch(input: {
162
+ commandId: string;
163
+ actorId: string;
164
+ workspaceId: string;
165
+ sourceBranchId: BranchId;
166
+ anchorBuildId: BuildId;
167
+ newBranchId: BranchId;
168
+ }): BranchRecord;
169
+ setPaused(input: {
170
+ workspaceId: string;
171
+ rootId: RootId;
172
+ branchId: BranchId;
173
+ paused: boolean;
174
+ }): boolean;
175
+ snapshot(input: {
176
+ workspaceId: string;
177
+ rootId: RootId;
178
+ branchId: BranchId;
179
+ }): QueueSnapshot;
180
+ private snapshotUnlocked;
181
+ events(afterCursor?: number, limit?: number): ContinuationEvent[];
182
+ recoverExpiredLeases(now?: number): number;
183
+ private terminateAttempt;
184
+ private releaseExpiredGuard;
185
+ private markDependentsBlocked;
186
+ private hasCommittedDescendant;
187
+ private isAncestorOfHead;
188
+ private ensureBranchRecord;
189
+ private requireBranch;
190
+ private ensureGuard;
191
+ /**
192
+ * Release the active attempt without ever moving the branch fence backward.
193
+ * A recovered/completed attempt's fence stays as the monotonic high-water
194
+ * mark; the next claim increments it again.
195
+ */
196
+ private releaseGuard;
197
+ private appendEvent;
198
+ private mutate;
199
+ private acquireLock;
200
+ private readLedger;
201
+ private readLedgerUnlocked;
202
+ private writeLedgerUnlocked;
203
+ private ensureLedgerExists;
204
+ private invalidateCache;
205
+ }
206
+ //# sourceMappingURL=store.d.ts.map