peaks-loop 3.0.3 → 3.1.1

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,444 @@
1
+ import { z } from 'zod';
2
+ export declare const SliceStateSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.ZodObject<{
3
+ sliceId: z.ZodString;
4
+ label: z.ZodString;
5
+ status: z.ZodEnum<["pending", "in-progress", "done", "failed", "blocked", "skipped"]>;
6
+ commitSha: z.ZodOptional<z.ZodString>;
7
+ finishedAt: z.ZodOptional<z.ZodString>;
8
+ failureReason: z.ZodOptional<z.ZodString>;
9
+ repairCycles: z.ZodDefault<z.ZodNumber>;
10
+ blockedReason: z.ZodOptional<z.ZodString>;
11
+ }, "strip", z.ZodTypeAny, {
12
+ status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
13
+ label: string;
14
+ sliceId: string;
15
+ repairCycles: number;
16
+ commitSha?: string | undefined;
17
+ finishedAt?: string | undefined;
18
+ failureReason?: string | undefined;
19
+ blockedReason?: string | undefined;
20
+ }, {
21
+ status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
22
+ label: string;
23
+ sliceId: string;
24
+ commitSha?: string | undefined;
25
+ finishedAt?: string | undefined;
26
+ failureReason?: string | undefined;
27
+ repairCycles?: number | undefined;
28
+ blockedReason?: string | undefined;
29
+ }>, {
30
+ status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
31
+ label: string;
32
+ sliceId: string;
33
+ repairCycles: number;
34
+ commitSha?: string | undefined;
35
+ finishedAt?: string | undefined;
36
+ failureReason?: string | undefined;
37
+ blockedReason?: string | undefined;
38
+ }, {
39
+ status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
40
+ label: string;
41
+ sliceId: string;
42
+ commitSha?: string | undefined;
43
+ finishedAt?: string | undefined;
44
+ failureReason?: string | undefined;
45
+ repairCycles?: number | undefined;
46
+ blockedReason?: string | undefined;
47
+ }>, {
48
+ status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
49
+ label: string;
50
+ sliceId: string;
51
+ repairCycles: number;
52
+ commitSha?: string | undefined;
53
+ finishedAt?: string | undefined;
54
+ failureReason?: string | undefined;
55
+ blockedReason?: string | undefined;
56
+ }, {
57
+ status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
58
+ label: string;
59
+ sliceId: string;
60
+ commitSha?: string | undefined;
61
+ finishedAt?: string | undefined;
62
+ failureReason?: string | undefined;
63
+ repairCycles?: number | undefined;
64
+ blockedReason?: string | undefined;
65
+ }>, {
66
+ status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
67
+ label: string;
68
+ sliceId: string;
69
+ repairCycles: number;
70
+ commitSha?: string | undefined;
71
+ finishedAt?: string | undefined;
72
+ failureReason?: string | undefined;
73
+ blockedReason?: string | undefined;
74
+ }, {
75
+ status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
76
+ label: string;
77
+ sliceId: string;
78
+ commitSha?: string | undefined;
79
+ finishedAt?: string | undefined;
80
+ failureReason?: string | undefined;
81
+ repairCycles?: number | undefined;
82
+ blockedReason?: string | undefined;
83
+ }>;
84
+ export declare const JobStateSchema: z.ZodObject<{
85
+ jobId: z.ZodString;
86
+ sessionId: z.ZodString;
87
+ startedAt: z.ZodString;
88
+ lastCheckpointAt: z.ZodString;
89
+ parallelismHint: z.ZodDefault<z.ZodEnum<["serial", "llm-decides"]>>;
90
+ exitPolicy: z.ZodDefault<z.ZodEnum<["strict", "best-effort"]>>;
91
+ mainLoopStrategy: z.ZodDefault<z.ZodEnum<["single", "rotating"]>>;
92
+ rotateEvery: z.ZodDefault<z.ZodNumber>;
93
+ mainSessionCycle: z.ZodDefault<z.ZodNumber>;
94
+ mainLoopOverride: z.ZodOptional<z.ZodObject<{
95
+ from: z.ZodLiteral<"rotating">;
96
+ to: z.ZodLiteral<"single">;
97
+ reason: z.ZodString;
98
+ at: z.ZodString;
99
+ }, "strip", z.ZodTypeAny, {
100
+ at: string;
101
+ reason: string;
102
+ from: "rotating";
103
+ to: "single";
104
+ }, {
105
+ at: string;
106
+ reason: string;
107
+ from: "rotating";
108
+ to: "single";
109
+ }>>;
110
+ slices: z.ZodArray<z.ZodEffects<z.ZodEffects<z.ZodEffects<z.ZodObject<{
111
+ sliceId: z.ZodString;
112
+ label: z.ZodString;
113
+ status: z.ZodEnum<["pending", "in-progress", "done", "failed", "blocked", "skipped"]>;
114
+ commitSha: z.ZodOptional<z.ZodString>;
115
+ finishedAt: z.ZodOptional<z.ZodString>;
116
+ failureReason: z.ZodOptional<z.ZodString>;
117
+ repairCycles: z.ZodDefault<z.ZodNumber>;
118
+ blockedReason: z.ZodOptional<z.ZodString>;
119
+ }, "strip", z.ZodTypeAny, {
120
+ status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
121
+ label: string;
122
+ sliceId: string;
123
+ repairCycles: number;
124
+ commitSha?: string | undefined;
125
+ finishedAt?: string | undefined;
126
+ failureReason?: string | undefined;
127
+ blockedReason?: string | undefined;
128
+ }, {
129
+ status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
130
+ label: string;
131
+ sliceId: string;
132
+ commitSha?: string | undefined;
133
+ finishedAt?: string | undefined;
134
+ failureReason?: string | undefined;
135
+ repairCycles?: number | undefined;
136
+ blockedReason?: string | undefined;
137
+ }>, {
138
+ status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
139
+ label: string;
140
+ sliceId: string;
141
+ repairCycles: number;
142
+ commitSha?: string | undefined;
143
+ finishedAt?: string | undefined;
144
+ failureReason?: string | undefined;
145
+ blockedReason?: string | undefined;
146
+ }, {
147
+ status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
148
+ label: string;
149
+ sliceId: string;
150
+ commitSha?: string | undefined;
151
+ finishedAt?: string | undefined;
152
+ failureReason?: string | undefined;
153
+ repairCycles?: number | undefined;
154
+ blockedReason?: string | undefined;
155
+ }>, {
156
+ status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
157
+ label: string;
158
+ sliceId: string;
159
+ repairCycles: number;
160
+ commitSha?: string | undefined;
161
+ finishedAt?: string | undefined;
162
+ failureReason?: string | undefined;
163
+ blockedReason?: string | undefined;
164
+ }, {
165
+ status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
166
+ label: string;
167
+ sliceId: string;
168
+ commitSha?: string | undefined;
169
+ finishedAt?: string | undefined;
170
+ failureReason?: string | undefined;
171
+ repairCycles?: number | undefined;
172
+ blockedReason?: string | undefined;
173
+ }>, {
174
+ status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
175
+ label: string;
176
+ sliceId: string;
177
+ repairCycles: number;
178
+ commitSha?: string | undefined;
179
+ finishedAt?: string | undefined;
180
+ failureReason?: string | undefined;
181
+ blockedReason?: string | undefined;
182
+ }, {
183
+ status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
184
+ label: string;
185
+ sliceId: string;
186
+ commitSha?: string | undefined;
187
+ finishedAt?: string | undefined;
188
+ failureReason?: string | undefined;
189
+ repairCycles?: number | undefined;
190
+ blockedReason?: string | undefined;
191
+ }>, "many">;
192
+ }, "strip", z.ZodTypeAny, {
193
+ sessionId: string;
194
+ startedAt: string;
195
+ slices: {
196
+ status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
197
+ label: string;
198
+ sliceId: string;
199
+ repairCycles: number;
200
+ commitSha?: string | undefined;
201
+ finishedAt?: string | undefined;
202
+ failureReason?: string | undefined;
203
+ blockedReason?: string | undefined;
204
+ }[];
205
+ jobId: string;
206
+ lastCheckpointAt: string;
207
+ parallelismHint: "serial" | "llm-decides";
208
+ exitPolicy: "strict" | "best-effort";
209
+ mainLoopStrategy: "single" | "rotating";
210
+ rotateEvery: number;
211
+ mainSessionCycle: number;
212
+ mainLoopOverride?: {
213
+ at: string;
214
+ reason: string;
215
+ from: "rotating";
216
+ to: "single";
217
+ } | undefined;
218
+ }, {
219
+ sessionId: string;
220
+ startedAt: string;
221
+ slices: {
222
+ status: "pending" | "skipped" | "done" | "failed" | "blocked" | "in-progress";
223
+ label: string;
224
+ sliceId: string;
225
+ commitSha?: string | undefined;
226
+ finishedAt?: string | undefined;
227
+ failureReason?: string | undefined;
228
+ repairCycles?: number | undefined;
229
+ blockedReason?: string | undefined;
230
+ }[];
231
+ jobId: string;
232
+ lastCheckpointAt: string;
233
+ parallelismHint?: "serial" | "llm-decides" | undefined;
234
+ exitPolicy?: "strict" | "best-effort" | undefined;
235
+ mainLoopStrategy?: "single" | "rotating" | undefined;
236
+ rotateEvery?: number | undefined;
237
+ mainSessionCycle?: number | undefined;
238
+ mainLoopOverride?: {
239
+ at: string;
240
+ reason: string;
241
+ from: "rotating";
242
+ to: "single";
243
+ } | undefined;
244
+ }>;
245
+ export declare const ResourceSnapshotSchema: z.ZodObject<{
246
+ capturedAt: z.ZodString;
247
+ cpuPercent: z.ZodNumber;
248
+ memMb: z.ZodNumber;
249
+ diskMb: z.ZodNumber;
250
+ contextRatio: z.ZodNumber;
251
+ }, "strip", z.ZodTypeAny, {
252
+ capturedAt: string;
253
+ cpuPercent: number;
254
+ memMb: number;
255
+ diskMb: number;
256
+ contextRatio: number;
257
+ }, {
258
+ capturedAt: string;
259
+ cpuPercent: number;
260
+ memMb: number;
261
+ diskMb: number;
262
+ contextRatio: number;
263
+ }>;
264
+ export declare const JobStatusSummarySchema: z.ZodObject<{
265
+ total: z.ZodNumber;
266
+ done: z.ZodNumber;
267
+ failed: z.ZodNumber;
268
+ blocked: z.ZodNumber;
269
+ skipped: z.ZodNumber;
270
+ currentSlice: z.ZodOptional<z.ZodString>;
271
+ lastCheckpoint: z.ZodString;
272
+ mainLoopStrategy: z.ZodEnum<["single", "rotating"]>;
273
+ mainSessionCycle: z.ZodNumber;
274
+ etaSec: z.ZodOptional<z.ZodNumber>;
275
+ resourcesNow: z.ZodOptional<z.ZodObject<{
276
+ capturedAt: z.ZodString;
277
+ cpuPercent: z.ZodNumber;
278
+ memMb: z.ZodNumber;
279
+ diskMb: z.ZodNumber;
280
+ contextRatio: z.ZodNumber;
281
+ }, "strip", z.ZodTypeAny, {
282
+ capturedAt: string;
283
+ cpuPercent: number;
284
+ memMb: number;
285
+ diskMb: number;
286
+ contextRatio: number;
287
+ }, {
288
+ capturedAt: string;
289
+ cpuPercent: number;
290
+ memMb: number;
291
+ diskMb: number;
292
+ contextRatio: number;
293
+ }>>;
294
+ }, "strip", z.ZodTypeAny, {
295
+ skipped: number;
296
+ done: number;
297
+ failed: number;
298
+ blocked: number;
299
+ mainLoopStrategy: "single" | "rotating";
300
+ mainSessionCycle: number;
301
+ total: number;
302
+ lastCheckpoint: string;
303
+ currentSlice?: string | undefined;
304
+ etaSec?: number | undefined;
305
+ resourcesNow?: {
306
+ capturedAt: string;
307
+ cpuPercent: number;
308
+ memMb: number;
309
+ diskMb: number;
310
+ contextRatio: number;
311
+ } | undefined;
312
+ }, {
313
+ skipped: number;
314
+ done: number;
315
+ failed: number;
316
+ blocked: number;
317
+ mainLoopStrategy: "single" | "rotating";
318
+ mainSessionCycle: number;
319
+ total: number;
320
+ lastCheckpoint: string;
321
+ currentSlice?: string | undefined;
322
+ etaSec?: number | undefined;
323
+ resourcesNow?: {
324
+ capturedAt: string;
325
+ cpuPercent: number;
326
+ memMb: number;
327
+ diskMb: number;
328
+ contextRatio: number;
329
+ } | undefined;
330
+ }>;
331
+ export type SliceState = z.infer<typeof SliceStateSchema>;
332
+ export type JobState = z.infer<typeof JobStateSchema>;
333
+ export type ResourceSnapshot = z.infer<typeof ResourceSnapshotSchema>;
334
+ export type JobStatusSummary = z.infer<typeof JobStatusSummarySchema>;
335
+ export declare const JobInitInputSchema: z.ZodObject<{
336
+ jobId: z.ZodString;
337
+ sessionId: z.ZodString;
338
+ sliceList: z.ZodArray<z.ZodString, "many">;
339
+ parallelismHint: z.ZodDefault<z.ZodEnum<["serial", "llm-decides"]>>;
340
+ exitPolicy: z.ZodDefault<z.ZodEnum<["strict", "best-effort"]>>;
341
+ mainLoopStrategy: z.ZodDefault<z.ZodEnum<["single", "rotating"]>>;
342
+ rotateEvery: z.ZodDefault<z.ZodNumber>;
343
+ project: z.ZodString;
344
+ json: z.ZodDefault<z.ZodBoolean>;
345
+ }, "strip", z.ZodTypeAny, {
346
+ project: string;
347
+ sessionId: string;
348
+ json: boolean;
349
+ jobId: string;
350
+ parallelismHint: "serial" | "llm-decides";
351
+ exitPolicy: "strict" | "best-effort";
352
+ mainLoopStrategy: "single" | "rotating";
353
+ rotateEvery: number;
354
+ sliceList: string[];
355
+ }, {
356
+ project: string;
357
+ sessionId: string;
358
+ jobId: string;
359
+ sliceList: string[];
360
+ json?: boolean | undefined;
361
+ parallelismHint?: "serial" | "llm-decides" | undefined;
362
+ exitPolicy?: "strict" | "best-effort" | undefined;
363
+ mainLoopStrategy?: "single" | "rotating" | undefined;
364
+ rotateEvery?: number | undefined;
365
+ }>;
366
+ export type JobInitInput = z.infer<typeof JobInitInputSchema>;
367
+ export declare const JobCheckpointInputSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
368
+ jobId: z.ZodString;
369
+ sliceId: z.ZodString;
370
+ state: z.ZodEnum<["done", "failed", "skipped"]>;
371
+ commitSha: z.ZodOptional<z.ZodString>;
372
+ reason: z.ZodOptional<z.ZodString>;
373
+ project: z.ZodString;
374
+ json: z.ZodDefault<z.ZodBoolean>;
375
+ }, "strip", z.ZodTypeAny, {
376
+ project: string;
377
+ json: boolean;
378
+ state: "skipped" | "done" | "failed";
379
+ sliceId: string;
380
+ jobId: string;
381
+ reason?: string | undefined;
382
+ commitSha?: string | undefined;
383
+ }, {
384
+ project: string;
385
+ state: "skipped" | "done" | "failed";
386
+ sliceId: string;
387
+ jobId: string;
388
+ json?: boolean | undefined;
389
+ reason?: string | undefined;
390
+ commitSha?: string | undefined;
391
+ }>, {
392
+ project: string;
393
+ json: boolean;
394
+ state: "skipped" | "done" | "failed";
395
+ sliceId: string;
396
+ jobId: string;
397
+ reason?: string | undefined;
398
+ commitSha?: string | undefined;
399
+ }, {
400
+ project: string;
401
+ state: "skipped" | "done" | "failed";
402
+ sliceId: string;
403
+ jobId: string;
404
+ json?: boolean | undefined;
405
+ reason?: string | undefined;
406
+ commitSha?: string | undefined;
407
+ }>, {
408
+ project: string;
409
+ json: boolean;
410
+ state: "skipped" | "done" | "failed";
411
+ sliceId: string;
412
+ jobId: string;
413
+ reason?: string | undefined;
414
+ commitSha?: string | undefined;
415
+ }, {
416
+ project: string;
417
+ state: "skipped" | "done" | "failed";
418
+ sliceId: string;
419
+ jobId: string;
420
+ json?: boolean | undefined;
421
+ reason?: string | undefined;
422
+ commitSha?: string | undefined;
423
+ }>;
424
+ export type JobCheckpointInput = z.infer<typeof JobCheckpointInputSchema>;
425
+ export declare const JobBlockInputSchema: z.ZodObject<{
426
+ jobId: z.ZodString;
427
+ sliceId: z.ZodString;
428
+ reason: z.ZodString;
429
+ project: z.ZodString;
430
+ json: z.ZodDefault<z.ZodBoolean>;
431
+ }, "strip", z.ZodTypeAny, {
432
+ project: string;
433
+ json: boolean;
434
+ reason: string;
435
+ sliceId: string;
436
+ jobId: string;
437
+ }, {
438
+ project: string;
439
+ reason: string;
440
+ sliceId: string;
441
+ jobId: string;
442
+ json?: boolean | undefined;
443
+ }>;
444
+ export type JobBlockInput = z.infer<typeof JobBlockInputSchema>;
@@ -0,0 +1,87 @@
1
+ import { z } from 'zod';
2
+ // ── Spec §4.2, verbatim from spec ────────────────────────────────────────
3
+ export const SliceStateSchema = z
4
+ .object({
5
+ sliceId: z.string(),
6
+ label: z.string(),
7
+ status: z.enum(['pending', 'in-progress', 'done', 'failed', 'blocked', 'skipped']),
8
+ commitSha: z.string().optional(), // required when status=done
9
+ finishedAt: z.string().datetime().optional(),
10
+ failureReason: z.string().optional(), // required when status=failed
11
+ repairCycles: z.number().int().nonnegative().default(0),
12
+ blockedReason: z.string().optional(), // required when status=blocked
13
+ })
14
+ .refine((v) => v.status !== 'done' || !!(v.commitSha && v.commitSha.length >= 7), { message: 'commitSha required (≥7 hex) when status=done', path: ['commitSha'] })
15
+ .refine((v) => v.status !== 'failed' || !!(v.failureReason && v.failureReason.length >= 1), { message: 'failureReason required when status=failed', path: ['failureReason'] })
16
+ .refine((v) => v.status !== 'blocked' || !!(v.blockedReason && v.blockedReason.length >= 1), { message: 'blockedReason required when status=blocked', path: ['blockedReason'] });
17
+ export const JobStateSchema = z.object({
18
+ jobId: z.string(),
19
+ sessionId: z.string(),
20
+ startedAt: z.string().datetime(),
21
+ lastCheckpointAt: z.string().datetime(),
22
+ parallelismHint: z.enum(['serial', 'llm-decides']).default('llm-decides'),
23
+ exitPolicy: z.enum(['strict', 'best-effort']).default('strict'),
24
+ mainLoopStrategy: z.enum(['single', 'rotating']).default('rotating'),
25
+ rotateEvery: z.number().int().positive().default(3),
26
+ mainSessionCycle: z.number().int().nonnegative().default(0),
27
+ mainLoopOverride: z
28
+ .object({
29
+ from: z.literal('rotating'),
30
+ to: z.literal('single'),
31
+ reason: z.string().min(10),
32
+ at: z.string().datetime(),
33
+ })
34
+ .optional(),
35
+ slices: z.array(SliceStateSchema),
36
+ });
37
+ export const ResourceSnapshotSchema = z.object({
38
+ capturedAt: z.string().datetime(),
39
+ cpuPercent: z.number().min(0).max(100),
40
+ memMb: z.number().nonnegative(),
41
+ diskMb: z.number().nonnegative(),
42
+ contextRatio: z.number().min(0).max(1),
43
+ });
44
+ export const JobStatusSummarySchema = z.object({
45
+ total: z.number().int(),
46
+ done: z.number().int(),
47
+ failed: z.number().int(),
48
+ blocked: z.number().int(),
49
+ skipped: z.number().int(),
50
+ currentSlice: z.string().optional(),
51
+ lastCheckpoint: z.string().datetime(),
52
+ mainLoopStrategy: z.enum(['single', 'rotating']),
53
+ mainSessionCycle: z.number().int(),
54
+ etaSec: z.number().int().optional(),
55
+ resourcesNow: ResourceSnapshotSchema.optional(),
56
+ });
57
+ // ── Spec §4.1 CLI input schemas (used by M3) ─────────────────────────────
58
+ export const JobInitInputSchema = z.object({
59
+ jobId: z.string().min(1),
60
+ sessionId: z.string().min(1),
61
+ sliceList: z.array(z.string().min(1)).min(1),
62
+ parallelismHint: z.enum(['serial', 'llm-decides']).default('llm-decides'),
63
+ exitPolicy: z.enum(['strict', 'best-effort']).default('strict'),
64
+ mainLoopStrategy: z.enum(['single', 'rotating']).default('rotating'),
65
+ rotateEvery: z.number().int().positive().default(3),
66
+ project: z.string(),
67
+ json: z.boolean().default(true),
68
+ });
69
+ export const JobCheckpointInputSchema = z
70
+ .object({
71
+ jobId: z.string(),
72
+ sliceId: z.string(),
73
+ state: z.enum(['done', 'failed', 'skipped']),
74
+ commitSha: z.string().optional(),
75
+ reason: z.string().optional(),
76
+ project: z.string(),
77
+ json: z.boolean().default(true),
78
+ })
79
+ .refine((v) => v.state !== 'done' || (v.commitSha && v.commitSha.length >= 7), { message: 'commitSha required (≥7 hex) when state=done', path: ['commitSha'] })
80
+ .refine((v) => v.state !== 'failed' && v.state !== 'skipped' ? true : !!(v.reason && v.reason.length >= 3), { message: 'reason required (≥3 chars) when state=failed|skipped', path: ['reason'] });
81
+ export const JobBlockInputSchema = z.object({
82
+ jobId: z.string(),
83
+ sliceId: z.string(),
84
+ reason: z.string().min(3),
85
+ project: z.string(),
86
+ json: z.boolean().default(true),
87
+ });
@@ -0,0 +1,35 @@
1
+ import { JobStateStore } from './job-state-store.js';
2
+ export interface WrapInput {
3
+ jobId: string;
4
+ role: 'prd' | 'rd' | 'qa' | 'ui' | 'txt' | 'sc' | 'agent';
5
+ prompt: string;
6
+ budgetMb?: number;
7
+ }
8
+ export interface DispatchResult {
9
+ batchId: string;
10
+ }
11
+ export interface DispatchOpts {
12
+ budgetMb: number;
13
+ jobScope: true;
14
+ batchId: string;
15
+ }
16
+ export type DispatchFn = (role: string, prompt: string, opts: DispatchOpts) => Promise<DispatchResult>;
17
+ export interface WrapOutput {
18
+ batchId: string;
19
+ requiresCleanup: true;
20
+ }
21
+ export declare class SubAgentJobWrapper {
22
+ private readonly store;
23
+ private readonly dispatch;
24
+ private readonly dispatchedBatches;
25
+ constructor(store: JobStateStore, dispatch: DispatchFn);
26
+ wrap(input: WrapInput): Promise<WrapOutput>;
27
+ canCheckpointDone(jobId: string, batchId: string): boolean;
28
+ cleanup(input: {
29
+ jobId: string;
30
+ batchId: string;
31
+ force: boolean;
32
+ }): Promise<{
33
+ cleaned: boolean;
34
+ }>;
35
+ }
@@ -0,0 +1,30 @@
1
+ export class SubAgentJobWrapper {
2
+ store;
3
+ dispatch;
4
+ dispatchedBatches = new Map(); // jobId -> set of batchIds pending cleanup
5
+ constructor(store, dispatch) {
6
+ this.store = store;
7
+ this.dispatch = dispatch;
8
+ }
9
+ async wrap(input) {
10
+ const budgetMb = input.budgetMb ?? 512;
11
+ const candidateBatchId = `batch-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
12
+ const result = await this.dispatch(input.role, input.prompt, { budgetMb, jobScope: true, batchId: candidateBatchId });
13
+ const batchId = result.batchId;
14
+ if (!this.dispatchedBatches.has(input.jobId))
15
+ this.dispatchedBatches.set(input.jobId, new Set());
16
+ this.dispatchedBatches.get(input.jobId).add(batchId);
17
+ return { batchId, requiresCleanup: true };
18
+ }
19
+ canCheckpointDone(jobId, batchId) {
20
+ const set = this.dispatchedBatches.get(jobId);
21
+ return !set?.has(batchId);
22
+ }
23
+ async cleanup(input) {
24
+ const set = this.dispatchedBatches.get(input.jobId);
25
+ if (!set?.has(input.batchId))
26
+ return { cleaned: true };
27
+ set.delete(input.batchId);
28
+ return { cleaned: true };
29
+ }
30
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * v3.1.1 Step 0.8 — Job-shape decision recorder.
3
+ *
4
+ * The CLI is a *recorder and gate*, not a judge. The LLM makes the
5
+ * semantic call ("is this a Job?") and writes the verdict via
6
+ * `peaks solo detect-job`; this service persists the verdict to
7
+ * `.peaks/_runtime/<sessionId>/job-shape.json` and refuses downstream
8
+ * steps that need a decision when the file is missing.
9
+ *
10
+ * Karpathy §2 (Simplicity First): ~100 lines, pure validation + fs
11
+ * writes, NO keyword regex, NO LLM call inside. The LLM is the
12
+ * source of truth for whether the request is Job-shaped; this file
13
+ * just enforces that a decision was made at all.
14
+ *
15
+ * Decision file lives at `.peaks/_runtime/<sessionId>/job-shape.json`
16
+ * (sibling of `session.json`, NOT under `job/<jid>/` because no jid
17
+ * exists yet at the moment of Step 0.8).
18
+ */
19
+ export type JobStrategy = 'single' | 'rotating';
20
+ export type JobConfidence = 'high' | 'medium' | 'low';
21
+ export interface JobShapeDecision {
22
+ readonly isJob: boolean;
23
+ readonly rationale: string;
24
+ readonly suggestedJobId: string;
25
+ readonly suggestedStrategy: JobStrategy;
26
+ readonly confidence: JobConfidence;
27
+ /** ISO 8601; stamped server-side in `writeJobShapeDecision`. */
28
+ readonly decidedAt: string;
29
+ }
30
+ export interface JobShapeRecord {
31
+ readonly sessionId: string;
32
+ /** sha1 of the user prompt (first 16 hex). */
33
+ readonly promptHash: string;
34
+ readonly decision: JobShapeDecision;
35
+ readonly schemaVersion: 1;
36
+ }
37
+ export declare const JOB_SHAPE_SCHEMA_VERSION: 1;
38
+ export declare const JOB_SHAPE_FILE_NAME = "job-shape.json";
39
+ export declare const JOB_SHAPE_ALREADY_DECIDED: "JOB_SHAPE_ALREADY_DECIDED";
40
+ export declare const JOB_SHAPE_NOT_DECIDED: "JOB_SHAPE_NOT_DECIDED";
41
+ export declare const JOB_SHAPE_INVALID: "JOB_SHAPE_INVALID";
42
+ export declare class JobShapeDecisionError extends Error {
43
+ readonly code: typeof JOB_SHAPE_NOT_DECIDED | typeof JOB_SHAPE_ALREADY_DECIDED | typeof JOB_SHAPE_INVALID;
44
+ readonly details?: unknown;
45
+ constructor(opts: {
46
+ code: typeof JobShapeDecisionError.prototype.code;
47
+ message: string;
48
+ details?: unknown;
49
+ });
50
+ }
51
+ /** Pure validator; throws on bad input. No fs IO. */
52
+ export declare function validateJobShapeDecision(input: unknown): JobShapeDecision;
53
+ /** Read the canonical record; throws JOB_SHAPE_NOT_DECIDED if absent or malformed. */
54
+ export declare function readJobShapeDecision(projectRoot: string, sessionId: string): JobShapeRecord;
55
+ export interface WriteJobShapeDecisionInput {
56
+ readonly isJob: boolean;
57
+ readonly rationale: string;
58
+ readonly suggestedJobId: string;
59
+ readonly suggestedStrategy: JobStrategy;
60
+ readonly confidence: JobConfidence;
61
+ readonly prompt: string;
62
+ }
63
+ /**
64
+ * Persist a new decision; refuses overwrite unless `force: true`.
65
+ * Stamps `decidedAt` server-side via `now` (defaults to `new Date()`)
66
+ * so the LLM cannot back-date.
67
+ */
68
+ export declare function writeJobShapeDecision(projectRoot: string, sessionId: string, decision: WriteJobShapeDecisionInput, opts?: {
69
+ force?: boolean;
70
+ now?: () => Date;
71
+ }): JobShapeRecord;