agent-step-gate 0.3.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/ARCHITECTURE.md +393 -0
- package/README.md +662 -0
- package/SKILL.md +190 -0
- package/Weaver.md +140 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +573 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/errors.d.ts +16 -0
- package/dist/core/errors.js +32 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/gate.d.ts +20 -0
- package/dist/core/gate.js +82 -0
- package/dist/core/gate.js.map +1 -0
- package/dist/core/keys.d.ts +18 -0
- package/dist/core/keys.js +37 -0
- package/dist/core/keys.js.map +1 -0
- package/dist/core/plan.d.ts +2 -0
- package/dist/core/plan.js +135 -0
- package/dist/core/plan.js.map +1 -0
- package/dist/core/program.d.ts +69 -0
- package/dist/core/program.js +191 -0
- package/dist/core/program.js.map +1 -0
- package/dist/core/reconcile.d.ts +37 -0
- package/dist/core/reconcile.js +198 -0
- package/dist/core/reconcile.js.map +1 -0
- package/dist/core/session.d.ts +25 -0
- package/dist/core/session.js +88 -0
- package/dist/core/session.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/storage/db.d.ts +3 -0
- package/dist/storage/db.js +117 -0
- package/dist/storage/db.js.map +1 -0
- package/dist/storage/repository.d.ts +24 -0
- package/dist/storage/repository.js +449 -0
- package/dist/storage/repository.js.map +1 -0
- package/dist/tools/activeTask.d.ts +2 -0
- package/dist/tools/activeTask.js +41 -0
- package/dist/tools/activeTask.js.map +1 -0
- package/dist/tools/cancelTask.d.ts +2 -0
- package/dist/tools/cancelTask.js +39 -0
- package/dist/tools/cancelTask.js.map +1 -0
- package/dist/tools/checkpoint.d.ts +2 -0
- package/dist/tools/checkpoint.js +71 -0
- package/dist/tools/checkpoint.js.map +1 -0
- package/dist/tools/current.d.ts +2 -0
- package/dist/tools/current.js +64 -0
- package/dist/tools/current.js.map +1 -0
- package/dist/tools/finalize.d.ts +2 -0
- package/dist/tools/finalize.js +95 -0
- package/dist/tools/finalize.js.map +1 -0
- package/dist/tools/index.d.ts +6 -0
- package/dist/tools/index.js +7 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/startPlan.d.ts +2 -0
- package/dist/tools/startPlan.js +124 -0
- package/dist/tools/startPlan.js.map +1 -0
- package/dist/types/index.d.ts +142 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +48 -0
- package/scripts/interactive-demo.ts +394 -0
- package/scripts/mcp-call.mjs +56 -0
- package/scripts/prompt-check-hook.sh +27 -0
- package/scripts/session-start-hook.sh +47 -0
- package/scripts/stop-hook.mjs +83 -0
- package/scripts/stop-hook.sh +75 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,kDAAkD;AAClD,cAAc;AACd,+EAA+E;AAI/E,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E,MAAM,CAAN,IAAY,aASX;AATD,WAAY,aAAa;IACvB,kDAAiC,CAAA;IACjC,kEAAiD,CAAA;IACjD,sCAAqB,CAAA;IACrB,8DAA6C,CAAA;IAC7C,sDAAqC,CAAA;IACrC,wDAAuC,CAAA;IACvC,4DAA2C,CAAA;IAC3C,kDAAiC,CAAA;AACnC,CAAC,EATW,aAAa,KAAb,aAAa,QASxB;AAED,8EAA8E;AAC9E,kEAAkE;AAClE,8EAA8E;AAE9E,MAAM,OAAO,SAAU,SAAQ,KAAK;IAClC,IAAI,CAAgB;IACpB,WAAW,CAAmB;IAE9B,YAAY,IAAmB,EAAE,OAAe,EAAE,WAA6B;QAC7E,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACjC,CAAC;CACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { TaskRow, StepRow, CurrentStepInfo } from '../types/index.js';
|
|
2
|
+
export interface GateRepository {
|
|
3
|
+
getTask(taskId: string): TaskRow | undefined;
|
|
4
|
+
getCurrentSteps(taskId: string): StepRow[];
|
|
5
|
+
getTaskSteps(taskId: string): StepRow[];
|
|
6
|
+
getStep(stepId: string): StepRow | undefined;
|
|
7
|
+
completeAndAdvance(completedStepId: string, nextStepIds: string[], nextKeyHashes: string[], taskId: string, taskKeyHash: string | null): void;
|
|
8
|
+
updateTaskStatus(taskId: string, status: string): void;
|
|
9
|
+
verifyTaskKey(taskId: string, keyPlaintext: string): boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function validateCheckpoint(repo: GateRepository, taskId: string, stepId: string, stepKey: string): {
|
|
12
|
+
task: TaskRow;
|
|
13
|
+
currentStep: StepRow;
|
|
14
|
+
};
|
|
15
|
+
export declare function advanceSteps(repo: GateRepository, task: TaskRow, completedStepId: string): {
|
|
16
|
+
nextSteps?: CurrentStepInfo[];
|
|
17
|
+
nextStepKeys?: Record<string, string>;
|
|
18
|
+
allStepsCompleted?: boolean;
|
|
19
|
+
taskKey?: string;
|
|
20
|
+
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { GateError, GateErrorCode } from './errors.js';
|
|
2
|
+
import { generateStepKey, generateTaskKey, hashKey } from './keys.js';
|
|
3
|
+
export function validateCheckpoint(repo, taskId, stepId, stepKey) {
|
|
4
|
+
const task = repo.getTask(taskId);
|
|
5
|
+
if (!task) {
|
|
6
|
+
throw new GateError(GateErrorCode.TASK_NOT_FOUND, `Task not found: ${taskId}`);
|
|
7
|
+
}
|
|
8
|
+
if (task.status !== 'active') {
|
|
9
|
+
throw new GateError(GateErrorCode.TASK_ALREADY_COMPLETED, `Task already completed: ${taskId}`);
|
|
10
|
+
}
|
|
11
|
+
const currentSteps = repo.getCurrentSteps(taskId);
|
|
12
|
+
if (currentSteps.length === 0) {
|
|
13
|
+
throw new GateError(GateErrorCode.INTERNAL_ERROR, 'No current step found');
|
|
14
|
+
}
|
|
15
|
+
const currentStep = currentSteps.find(s => s.id === stepId);
|
|
16
|
+
if (!currentStep) {
|
|
17
|
+
throw new GateError(GateErrorCode.INVALID_CURRENT_STEP, `Step ${stepId} is not a current step. Current steps: [${currentSteps.map(s => s.id).join(', ')}]`, {
|
|
18
|
+
stepId: currentSteps[0].id,
|
|
19
|
+
path: currentSteps[0].path,
|
|
20
|
+
index: currentSteps[0].orderIndex,
|
|
21
|
+
total: task.totalSteps,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
const keyHash = hashKey(stepKey);
|
|
25
|
+
if (keyHash !== currentStep.stepKeyHash) {
|
|
26
|
+
throw new GateError(GateErrorCode.INVALID_STEP_KEY, `Invalid step key for step ${stepId}`, {
|
|
27
|
+
stepId: currentStep.id,
|
|
28
|
+
path: currentStep.path,
|
|
29
|
+
index: currentStep.orderIndex,
|
|
30
|
+
total: task.totalSteps,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return { task, currentStep };
|
|
34
|
+
}
|
|
35
|
+
export function advanceSteps(repo, task, completedStepId) {
|
|
36
|
+
const allSteps = repo.getTaskSteps(task.id);
|
|
37
|
+
// 1. Find all pending steps whose dependencies are all satisfied.
|
|
38
|
+
// Treat completedStepId as already completed since it's about to be in the transaction.
|
|
39
|
+
const unlockedSteps = allSteps.filter(s => {
|
|
40
|
+
if (s.status !== 'pending')
|
|
41
|
+
return false;
|
|
42
|
+
return s.dependsOn.every(depId => {
|
|
43
|
+
const dep = allSteps.find(x => x.id === depId);
|
|
44
|
+
if (!dep)
|
|
45
|
+
return false;
|
|
46
|
+
return dep.status === 'completed' || dep.status === 'skipped' || dep.id === completedStepId;
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
if (unlockedSteps.length > 0) {
|
|
50
|
+
// Generate keys for newly activated steps
|
|
51
|
+
const nextStepKeys = {};
|
|
52
|
+
const nextKeyHashes = [];
|
|
53
|
+
for (const step of unlockedSteps) {
|
|
54
|
+
const { plaintext, hash } = generateStepKey();
|
|
55
|
+
nextStepKeys[step.id] = plaintext;
|
|
56
|
+
nextKeyHashes.push(hash);
|
|
57
|
+
}
|
|
58
|
+
repo.completeAndAdvance(completedStepId, unlockedSteps.map(s => s.id), nextKeyHashes, task.id, null);
|
|
59
|
+
return {
|
|
60
|
+
nextSteps: unlockedSteps.map(s => ({
|
|
61
|
+
stepId: s.id,
|
|
62
|
+
path: s.path,
|
|
63
|
+
index: s.orderIndex,
|
|
64
|
+
total: task.totalSteps,
|
|
65
|
+
})),
|
|
66
|
+
nextStepKeys,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// 2. No pending steps unlocked → check if everything is completed
|
|
70
|
+
const allCompleted = allSteps.every(s => s.status === 'completed' || s.status === 'skipped' || s.id === completedStepId);
|
|
71
|
+
if (allCompleted) {
|
|
72
|
+
const { plaintext, hash } = generateTaskKey();
|
|
73
|
+
repo.completeAndAdvance(completedStepId, [], [], task.id, hash);
|
|
74
|
+
return { allStepsCompleted: true, taskKey: plaintext };
|
|
75
|
+
}
|
|
76
|
+
// 3. There are pending steps but their dependencies aren't satisfied yet.
|
|
77
|
+
// This happens when completing a parallel branch — other branches are still running.
|
|
78
|
+
// Just complete this step without activating anything new.
|
|
79
|
+
repo.completeAndAdvance(completedStepId, [], [], task.id, null);
|
|
80
|
+
return {};
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../../src/core/gate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYtE,MAAM,UAAU,kBAAkB,CAChC,IAAoB,EACpB,MAAc,EACd,MAAc,EACd,OAAe;IAEf,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,SAAS,CAAC,aAAa,CAAC,cAAc,EAAE,mBAAmB,MAAM,EAAE,CAAC,CAAC;IACjF,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC7B,MAAM,IAAI,SAAS,CAAC,aAAa,CAAC,sBAAsB,EAAE,2BAA2B,MAAM,EAAE,CAAC,CAAC;IACjG,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IAClD,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,SAAS,CAAC,aAAa,CAAC,cAAc,EAAE,uBAAuB,CAAC,CAAC;IAC7E,CAAC;IAED,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC;IAC5D,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,SAAS,CACjB,aAAa,CAAC,oBAAoB,EAClC,QAAQ,MAAM,2CAA2C,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAClG;YACE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE;YAC1B,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI;YAC1B,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,UAAU;YACjC,KAAK,EAAE,IAAI,CAAC,UAAU;SACvB,CACF,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,OAAO,KAAK,WAAW,CAAC,WAAW,EAAE,CAAC;QACxC,MAAM,IAAI,SAAS,CACjB,aAAa,CAAC,gBAAgB,EAC9B,6BAA6B,MAAM,EAAE,EACrC;YACE,MAAM,EAAE,WAAW,CAAC,EAAE;YACtB,IAAI,EAAE,WAAW,CAAC,IAAI;YACtB,KAAK,EAAE,WAAW,CAAC,UAAU;YAC7B,KAAK,EAAE,IAAI,CAAC,UAAU;SACvB,CACF,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,IAAoB,EACpB,IAAa,EACb,eAAuB;IAOvB,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAE5C,kEAAkE;IAClE,2FAA2F;IAC3F,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;QACxC,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QACzC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;YAC/B,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC;YAC/C,IAAI,CAAC,GAAG;gBAAE,OAAO,KAAK,CAAC;YACvB,OAAO,GAAG,CAAC,MAAM,KAAK,WAAW,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,GAAG,CAAC,EAAE,KAAK,eAAe,CAAC;QAC9F,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,0CAA0C;QAC1C,MAAM,YAAY,GAA2B,EAAE,CAAC;QAChD,MAAM,aAAa,GAAa,EAAE,CAAC;QACnC,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;YACjC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,eAAe,EAAE,CAAC;YAC9C,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;YAClC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;QAED,IAAI,CAAC,kBAAkB,CACrB,eAAe,EACf,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAC5B,aAAa,EACb,IAAI,CAAC,EAAE,EACP,IAAI,CACL,CAAC;QAEF,OAAO;YACL,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACjC,MAAM,EAAE,CAAC,CAAC,EAAE;gBACZ,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,KAAK,EAAE,CAAC,CAAC,UAAU;gBACnB,KAAK,EAAE,IAAI,CAAC,UAAU;aACvB,CAAC,CAAC;YACH,YAAY;SACb,CAAC;IACJ,CAAC;IAED,kEAAkE;IAClE,MAAM,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,EAAE,KAAK,eAAe,CAAC,CAAC;IACzH,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,eAAe,EAAE,CAAC;QAC9C,IAAI,CAAC,kBAAkB,CAAC,eAAe,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAChE,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IACzD,CAAC;IAED,0EAA0E;IAC1E,wFAAwF;IACxF,8DAA8D;IAC9D,IAAI,CAAC,kBAAkB,CAAC,eAAe,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAChE,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare function randomCode(length: number): string;
|
|
2
|
+
export declare function generateStepKey(): {
|
|
3
|
+
plaintext: string;
|
|
4
|
+
hash: string;
|
|
5
|
+
};
|
|
6
|
+
/** Task-level key — proves all steps in a task were checkpointed */
|
|
7
|
+
export declare function generateTaskKey(): {
|
|
8
|
+
plaintext: string;
|
|
9
|
+
hash: string;
|
|
10
|
+
};
|
|
11
|
+
/** @deprecated use generateTaskKey */
|
|
12
|
+
export declare const generateFinalKey: typeof generateTaskKey;
|
|
13
|
+
/** Node-level key — system-generated receipt when all tasks in a node are done */
|
|
14
|
+
export declare function generateNodeKey(): {
|
|
15
|
+
plaintext: string;
|
|
16
|
+
hash: string;
|
|
17
|
+
};
|
|
18
|
+
export declare function hashKey(plaintext: string): string;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
const CHARSET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
|
3
|
+
export function randomCode(length) {
|
|
4
|
+
const bytes = crypto.randomBytes(length * 2); // oversample to avoid modulo bias
|
|
5
|
+
let result = '';
|
|
6
|
+
let byteIdx = 0;
|
|
7
|
+
for (let i = 0; i < length; i++) {
|
|
8
|
+
// rejection sampling: skip bytes >= 252 (the largest multiple of 36 under 256)
|
|
9
|
+
let val;
|
|
10
|
+
do {
|
|
11
|
+
val = bytes[byteIdx++];
|
|
12
|
+
} while (val >= 252 && byteIdx < bytes.length);
|
|
13
|
+
result += CHARSET[val % CHARSET.length];
|
|
14
|
+
}
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
export function generateStepKey() {
|
|
18
|
+
const plaintext = randomCode(6);
|
|
19
|
+
const hash = hashKey(plaintext);
|
|
20
|
+
return { plaintext, hash };
|
|
21
|
+
}
|
|
22
|
+
/** Task-level key — proves all steps in a task were checkpointed */
|
|
23
|
+
export function generateTaskKey() {
|
|
24
|
+
const plaintext = randomCode(6);
|
|
25
|
+
return { plaintext, hash: hashKey(plaintext) };
|
|
26
|
+
}
|
|
27
|
+
/** @deprecated use generateTaskKey */
|
|
28
|
+
export const generateFinalKey = generateTaskKey;
|
|
29
|
+
/** Node-level key — system-generated receipt when all tasks in a node are done */
|
|
30
|
+
export function generateNodeKey() {
|
|
31
|
+
const plaintext = randomCode(6);
|
|
32
|
+
return { plaintext, hash: hashKey(plaintext) };
|
|
33
|
+
}
|
|
34
|
+
export function hashKey(plaintext) {
|
|
35
|
+
return crypto.createHash('sha256').update(plaintext).digest('hex');
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/core/keys.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,MAAM,OAAO,GAAG,sCAAsC,CAAC;AAEvD,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,kCAAkC;IAChF,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,+EAA+E;QAC/E,IAAI,GAAW,CAAC;QAChB,GAAG,CAAC;YACF,GAAG,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACzB,CAAC,QAAQ,GAAG,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,CAAC,MAAM,EAAE;QAC/C,MAAM,IAAI,OAAO,CAAC,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AAC7B,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,eAAe;IAC7B,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IAChC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;AACjD,CAAC;AAED,sCAAsC;AACtC,MAAM,CAAC,MAAM,gBAAgB,GAAG,eAAe,CAAC;AAEhD,kFAAkF;AAClF,MAAM,UAAU,eAAe;IAC7B,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IAChC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,SAAiB;IACvC,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { GateError, GateErrorCode } from './errors.js';
|
|
2
|
+
export function flattenPlan(nodes, taskId, parentPath) {
|
|
3
|
+
if (!nodes || nodes.length === 0) {
|
|
4
|
+
throw new GateError(GateErrorCode.PLAN_SCHEMA_INVALID, 'Plan must have at least one step');
|
|
5
|
+
}
|
|
6
|
+
const now = new Date().toISOString();
|
|
7
|
+
const leaves = [];
|
|
8
|
+
let idCounter = 0;
|
|
9
|
+
// Maps original node ID → leaf step IDs (container IDs map to all descendants)
|
|
10
|
+
const nodeToLeafStepIds = new Map();
|
|
11
|
+
function dfs(nodeList, pathPrefix, inheritedDependsOn) {
|
|
12
|
+
for (const node of nodeList) {
|
|
13
|
+
if (!node.title) {
|
|
14
|
+
throw new GateError(GateErrorCode.PLAN_SCHEMA_INVALID, 'Each step must have a title');
|
|
15
|
+
}
|
|
16
|
+
const nodePath = pathPrefix ? `${pathPrefix} / ${node.title}` : node.title;
|
|
17
|
+
// Merge this node's deps into the inheritance chain for children (F3b)
|
|
18
|
+
const mergedInherited = [...inheritedDependsOn, ...(node.dependsOn || [])];
|
|
19
|
+
const childInherited = [...new Set(mergedInherited)];
|
|
20
|
+
if (!node.children || node.children.length === 0) {
|
|
21
|
+
idCounter++;
|
|
22
|
+
const stepId = node.id ? `${taskId}_${node.id}` : `${taskId}_step_${idCounter}`;
|
|
23
|
+
if (node.id) {
|
|
24
|
+
nodeToLeafStepIds.set(node.id, [stepId]);
|
|
25
|
+
}
|
|
26
|
+
leaves.push({
|
|
27
|
+
stepId,
|
|
28
|
+
nodeId: node.id,
|
|
29
|
+
title: node.title,
|
|
30
|
+
path: nodePath,
|
|
31
|
+
ownDependsOn: node.dependsOn,
|
|
32
|
+
inheritedDependsOn,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
const beforeCount = leaves.length;
|
|
37
|
+
dfs(node.children, nodePath, childInherited);
|
|
38
|
+
if (node.id) {
|
|
39
|
+
const descendantIds = leaves.slice(beforeCount).map(l => l.stepId);
|
|
40
|
+
nodeToLeafStepIds.set(node.id, descendantIds);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
dfs(nodes, parentPath ?? '', []);
|
|
46
|
+
if (leaves.length === 0) {
|
|
47
|
+
throw new GateError(GateErrorCode.PLAN_SCHEMA_INVALID, 'Plan must have at least one step');
|
|
48
|
+
}
|
|
49
|
+
// ---- Phase 2: Resolve node IDs → leaf step IDs ----
|
|
50
|
+
// Container references expand to all descendant leaf IDs.
|
|
51
|
+
const resolvedDeps = leaves.map(() => []);
|
|
52
|
+
for (let i = 0; i < leaves.length; i++) {
|
|
53
|
+
const leaf = leaves[i];
|
|
54
|
+
const effectiveDependsOn = [
|
|
55
|
+
...leaf.inheritedDependsOn,
|
|
56
|
+
...(leaf.ownDependsOn || []),
|
|
57
|
+
];
|
|
58
|
+
const uniqueDeps = [...new Set(effectiveDependsOn)];
|
|
59
|
+
const resolved = [];
|
|
60
|
+
for (const depId of uniqueDeps) {
|
|
61
|
+
const targetIds = nodeToLeafStepIds.get(depId);
|
|
62
|
+
if (targetIds && targetIds.length > 0) {
|
|
63
|
+
for (const sid of targetIds)
|
|
64
|
+
resolved.push(sid);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
resolvedDeps[i] = [...new Set(resolved)];
|
|
68
|
+
}
|
|
69
|
+
// ---- Phase 3 (F1): Cycle detection via DFS three-color ----
|
|
70
|
+
const leafIdToIndex = new Map();
|
|
71
|
+
for (let i = 0; i < leaves.length; i++) {
|
|
72
|
+
leafIdToIndex.set(leaves[i].stepId, i);
|
|
73
|
+
}
|
|
74
|
+
let Color;
|
|
75
|
+
(function (Color) {
|
|
76
|
+
Color[Color["WHITE"] = 0] = "WHITE";
|
|
77
|
+
Color[Color["GRAY"] = 1] = "GRAY";
|
|
78
|
+
Color[Color["BLACK"] = 2] = "BLACK";
|
|
79
|
+
})(Color || (Color = {}));
|
|
80
|
+
const colors = leaves.map(() => Color.WHITE);
|
|
81
|
+
function detectCycle(idx, path) {
|
|
82
|
+
if (colors[idx] === Color.GRAY) {
|
|
83
|
+
const cycleStart = path.indexOf(leaves[idx].stepId);
|
|
84
|
+
const cyclePath = [...path.slice(cycleStart), leaves[idx].stepId].join(' → ');
|
|
85
|
+
throw new GateError(GateErrorCode.PLAN_SCHEMA_INVALID, `Circular dependency detected: ${cyclePath}`);
|
|
86
|
+
}
|
|
87
|
+
if (colors[idx] === Color.BLACK)
|
|
88
|
+
return;
|
|
89
|
+
colors[idx] = Color.GRAY;
|
|
90
|
+
path.push(leaves[idx].stepId);
|
|
91
|
+
for (const depId of resolvedDeps[idx]) {
|
|
92
|
+
const depIdx = leafIdToIndex.get(depId);
|
|
93
|
+
if (depIdx !== undefined) {
|
|
94
|
+
detectCycle(depIdx, path);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
path.pop();
|
|
98
|
+
colors[idx] = Color.BLACK;
|
|
99
|
+
}
|
|
100
|
+
for (let i = 0; i < leaves.length; i++) {
|
|
101
|
+
if (colors[i] === Color.WHITE) {
|
|
102
|
+
detectCycle(i, []);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// ---- Phase 4: Build result with auto-serial fallback ----
|
|
106
|
+
const result = [];
|
|
107
|
+
for (let i = 0; i < leaves.length; i++) {
|
|
108
|
+
const leaf = leaves[i];
|
|
109
|
+
let finalDependsOn;
|
|
110
|
+
const hasExplicitDeps = leaf.ownDependsOn !== undefined || leaf.inheritedDependsOn.length > 0;
|
|
111
|
+
if (hasExplicitDeps) {
|
|
112
|
+
finalDependsOn = resolvedDeps[i];
|
|
113
|
+
}
|
|
114
|
+
else if (i === 0) {
|
|
115
|
+
finalDependsOn = [];
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
finalDependsOn = [leaves[i - 1].stepId];
|
|
119
|
+
}
|
|
120
|
+
result.push({
|
|
121
|
+
id: leaf.stepId,
|
|
122
|
+
taskId,
|
|
123
|
+
parentPath: parentPath ?? null,
|
|
124
|
+
title: leaf.title,
|
|
125
|
+
path: leaf.path,
|
|
126
|
+
orderIndex: i + 1,
|
|
127
|
+
dependsOn: finalDependsOn,
|
|
128
|
+
status: 'pending',
|
|
129
|
+
completedAt: null,
|
|
130
|
+
createdAt: now,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/core/plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export interface ProgramInfo {
|
|
2
|
+
programId: string;
|
|
3
|
+
title: string;
|
|
4
|
+
totalNodes: number;
|
|
5
|
+
nodes: ProgramNodeInfo[];
|
|
6
|
+
}
|
|
7
|
+
export interface ProgramNodeInfo {
|
|
8
|
+
nodeId: string;
|
|
9
|
+
title: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
orderIndex: number;
|
|
12
|
+
status: string;
|
|
13
|
+
sessionId?: string;
|
|
14
|
+
}
|
|
15
|
+
/** Create a new program from a plan (JSON array of nodes with optional dependsOn). */
|
|
16
|
+
export declare function createProgram(title: string, nodes: {
|
|
17
|
+
id?: string;
|
|
18
|
+
title: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
dependsOn?: string[];
|
|
21
|
+
}[]): ProgramInfo;
|
|
22
|
+
/** Get program status with all nodes. */
|
|
23
|
+
export declare function getProgramStatus(programId: string): ProgramInfo | null;
|
|
24
|
+
/** Find ready nodes (all deps satisfied, not yet started). */
|
|
25
|
+
export declare function getReadyNodes(programId: string): ProgramNodeInfo[];
|
|
26
|
+
/** Start a program node — creates a new session bound to it. */
|
|
27
|
+
export declare function startProgramNode(programId: string, nodeId: string, sessionId: string): boolean;
|
|
28
|
+
/** Commit parent: mark the program node as completed, auto-generating a nodeKey receipt. */
|
|
29
|
+
export declare function commitProgramNode(sessionId: string): {
|
|
30
|
+
programId: string;
|
|
31
|
+
nodeId: string;
|
|
32
|
+
nodeKey?: string;
|
|
33
|
+
allDone: boolean;
|
|
34
|
+
} | null;
|
|
35
|
+
/** Rebuild manifest: what's done and what will be lost if we rebuild this program/node. */
|
|
36
|
+
export interface RebuildManifest {
|
|
37
|
+
scope: {
|
|
38
|
+
programId: string;
|
|
39
|
+
nodeId?: string;
|
|
40
|
+
};
|
|
41
|
+
programTitle: string;
|
|
42
|
+
completedSteps: Array<{
|
|
43
|
+
oldTaskId: string;
|
|
44
|
+
taskTitle: string;
|
|
45
|
+
stepId: string;
|
|
46
|
+
stepPath: string;
|
|
47
|
+
status: string;
|
|
48
|
+
nodeId?: string;
|
|
49
|
+
}>;
|
|
50
|
+
pendingSteps: Array<{
|
|
51
|
+
taskId: string;
|
|
52
|
+
taskTitle: string;
|
|
53
|
+
stepId: string;
|
|
54
|
+
stepPath: string;
|
|
55
|
+
}>;
|
|
56
|
+
activeTaskCount: number;
|
|
57
|
+
completedTaskCount: number;
|
|
58
|
+
}
|
|
59
|
+
export declare function getRebuildManifest(programId: string, nodeId?: string): RebuildManifest | null;
|
|
60
|
+
/** Execute rebuild: cancel active tasks, reset node(s) to pending. */
|
|
61
|
+
export declare function executeRebuild(programId: string, nodeId?: string): {
|
|
62
|
+
cancelled: number;
|
|
63
|
+
resetNodes: string[];
|
|
64
|
+
};
|
|
65
|
+
/** Finalize program: check all nodes complete. */
|
|
66
|
+
export declare function finalizeProgram(programId: string): {
|
|
67
|
+
ok: boolean;
|
|
68
|
+
pending: ProgramNodeInfo[];
|
|
69
|
+
};
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import db from '../storage/db.js';
|
|
3
|
+
import { randomCode, generateNodeKey } from './keys.js';
|
|
4
|
+
function now() { return new Date().toISOString(); }
|
|
5
|
+
function sha256(s) { return crypto.createHash('sha256').update(s).digest('hex'); }
|
|
6
|
+
/** Create a new program from a plan (JSON array of nodes with optional dependsOn). */
|
|
7
|
+
export function createProgram(title, nodes) {
|
|
8
|
+
const programId = `pgm_${randomCode(6)}`;
|
|
9
|
+
const ts = now();
|
|
10
|
+
db.prepare('INSERT INTO programs (program_id, title, status, total_nodes, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)')
|
|
11
|
+
.run(programId, title, 'active', nodes.length, ts, ts);
|
|
12
|
+
const programNodes = nodes.map((n, i) => {
|
|
13
|
+
const nodeId = n.id ?? `pg_${programId}_${i + 1}`;
|
|
14
|
+
db.prepare('INSERT INTO program_nodes (node_id, program_id, title, description, order_index, status, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)')
|
|
15
|
+
.run(nodeId, programId, n.title, n.description ?? null, i + 1, 'pending', ts);
|
|
16
|
+
return { nodeId, title: n.title, description: n.description, orderIndex: i + 1, status: 'pending' };
|
|
17
|
+
});
|
|
18
|
+
return { programId, title, totalNodes: nodes.length, nodes: programNodes };
|
|
19
|
+
}
|
|
20
|
+
/** Get program status with all nodes. */
|
|
21
|
+
export function getProgramStatus(programId) {
|
|
22
|
+
const p = db.prepare('SELECT * FROM programs WHERE program_id = ?').get(programId);
|
|
23
|
+
if (!p)
|
|
24
|
+
return null;
|
|
25
|
+
const nodes = db.prepare('SELECT * FROM program_nodes WHERE program_id = ? ORDER BY order_index').all(programId);
|
|
26
|
+
return {
|
|
27
|
+
programId: p.program_id,
|
|
28
|
+
title: p.title,
|
|
29
|
+
totalNodes: p.total_nodes,
|
|
30
|
+
nodes: nodes.map((n) => ({
|
|
31
|
+
nodeId: n.node_id, title: n.title, description: n.description,
|
|
32
|
+
orderIndex: n.order_index, status: n.status, sessionId: n.session_id,
|
|
33
|
+
})),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** Find ready nodes (all deps satisfied, not yet started). */
|
|
37
|
+
export function getReadyNodes(programId) {
|
|
38
|
+
const nodes = db.prepare("SELECT * FROM program_nodes WHERE program_id = ? AND status = 'pending' ORDER BY order_index").all(programId);
|
|
39
|
+
// For now, no DAG at program level — just return ordered pending nodes.
|
|
40
|
+
// Future: filter by depends_on satisfaction.
|
|
41
|
+
return nodes.map((n) => ({
|
|
42
|
+
nodeId: n.node_id, title: n.title, description: n.description,
|
|
43
|
+
orderIndex: n.order_index, status: n.status, sessionId: n.session_id,
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
/** Start a program node — creates a new session bound to it. */
|
|
47
|
+
export function startProgramNode(programId, nodeId, sessionId) {
|
|
48
|
+
const node = db.prepare('SELECT * FROM program_nodes WHERE node_id = ? AND program_id = ?').get(nodeId, programId);
|
|
49
|
+
if (!node || node.status !== 'pending')
|
|
50
|
+
return false;
|
|
51
|
+
db.prepare("UPDATE program_nodes SET status = 'in_progress', session_id = ? WHERE node_id = ?")
|
|
52
|
+
.run(sessionId, nodeId);
|
|
53
|
+
db.prepare('UPDATE sessions SET program_id = ?, program_node_id = ? WHERE session_id = ?')
|
|
54
|
+
.run(programId, nodeId, sessionId);
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
/** Commit parent: mark the program node as completed, auto-generating a nodeKey receipt. */
|
|
58
|
+
export function commitProgramNode(sessionId) {
|
|
59
|
+
const session = db.prepare('SELECT program_id, program_node_id FROM sessions WHERE session_id = ?').get(sessionId);
|
|
60
|
+
if (!session?.program_node_id)
|
|
61
|
+
return null;
|
|
62
|
+
// Generate nodeKey as a completion receipt
|
|
63
|
+
const { plaintext: nodeKey, hash: nodeKeyHash } = generateNodeKey();
|
|
64
|
+
db.prepare("UPDATE program_nodes SET status = 'completed', completed_at = ?, node_key_hash = ? WHERE node_id = ?")
|
|
65
|
+
.run(now(), nodeKeyHash, session.program_node_id);
|
|
66
|
+
// Check if all nodes are completed
|
|
67
|
+
const pending = db.prepare("SELECT COUNT(*) as cnt FROM program_nodes WHERE program_id = ? AND status != 'completed'")
|
|
68
|
+
.get(session.program_id);
|
|
69
|
+
if (pending.cnt === 0) {
|
|
70
|
+
db.prepare("UPDATE programs SET status = 'completed', updated_at = ? WHERE program_id = ?")
|
|
71
|
+
.run(now(), session.program_id);
|
|
72
|
+
return { programId: session.program_id, nodeId: session.program_node_id, nodeKey, allDone: true };
|
|
73
|
+
}
|
|
74
|
+
return { programId: session.program_id, nodeId: session.program_node_id, nodeKey, allDone: false };
|
|
75
|
+
}
|
|
76
|
+
export function getRebuildManifest(programId, nodeId) {
|
|
77
|
+
const prog = db.prepare('SELECT * FROM programs WHERE program_id = ?').get(programId);
|
|
78
|
+
if (!prog)
|
|
79
|
+
return null;
|
|
80
|
+
// Find sessions under this program (optionally filtered by node)
|
|
81
|
+
let sessions;
|
|
82
|
+
if (nodeId) {
|
|
83
|
+
sessions = db.prepare("SELECT * FROM sessions WHERE program_id = ? AND program_node_id = ?").all(programId, nodeId);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
sessions = db.prepare("SELECT * FROM sessions WHERE program_id = ?").all(programId);
|
|
87
|
+
}
|
|
88
|
+
const sessionIds = sessions.map((s) => s.session_id);
|
|
89
|
+
if (sessionIds.length === 0) {
|
|
90
|
+
return {
|
|
91
|
+
scope: { programId, nodeId },
|
|
92
|
+
programTitle: prog.title,
|
|
93
|
+
completedSteps: [],
|
|
94
|
+
pendingSteps: [],
|
|
95
|
+
activeTaskCount: 0,
|
|
96
|
+
completedTaskCount: 0,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
// Find all tasks from these sessions
|
|
100
|
+
const placeholders = sessionIds.map(() => '?').join(',');
|
|
101
|
+
const tasks = db.prepare(`SELECT * FROM tasks WHERE session_id IN (${placeholders})`).all(...sessionIds);
|
|
102
|
+
const completedSteps = [];
|
|
103
|
+
const pendingSteps = [];
|
|
104
|
+
let activeCount = 0;
|
|
105
|
+
let completedCount = 0;
|
|
106
|
+
for (const task of tasks) {
|
|
107
|
+
if (task.status === 'completed')
|
|
108
|
+
completedCount++;
|
|
109
|
+
if (task.status === 'active' || task.status === 'cancelled')
|
|
110
|
+
activeCount++;
|
|
111
|
+
const steps = db.prepare('SELECT * FROM steps WHERE task_id = ? ORDER BY order_index').all(task.id);
|
|
112
|
+
const node = sessions.find((s) => s.session_id === task.session_id);
|
|
113
|
+
for (const step of steps) {
|
|
114
|
+
if (step.status === 'completed') {
|
|
115
|
+
completedSteps.push({
|
|
116
|
+
oldTaskId: task.id,
|
|
117
|
+
taskTitle: task.title,
|
|
118
|
+
stepId: step.id,
|
|
119
|
+
stepPath: step.path,
|
|
120
|
+
status: 'completed',
|
|
121
|
+
nodeId: node?.program_node_id,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
else if (step.status === 'current' || step.status === 'pending') {
|
|
125
|
+
pendingSteps.push({
|
|
126
|
+
taskId: task.id,
|
|
127
|
+
taskTitle: task.title,
|
|
128
|
+
stepId: step.id,
|
|
129
|
+
stepPath: step.path,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
scope: { programId, nodeId },
|
|
136
|
+
programTitle: prog.title,
|
|
137
|
+
completedSteps,
|
|
138
|
+
pendingSteps,
|
|
139
|
+
activeTaskCount: activeCount,
|
|
140
|
+
completedTaskCount: completedCount,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/** Execute rebuild: cancel active tasks, reset node(s) to pending. */
|
|
144
|
+
export function executeRebuild(programId, nodeId) {
|
|
145
|
+
let sessions;
|
|
146
|
+
if (nodeId) {
|
|
147
|
+
sessions = db.prepare("SELECT * FROM sessions WHERE program_id = ? AND program_node_id = ?").all(programId, nodeId);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
sessions = db.prepare("SELECT * FROM sessions WHERE program_id = ?").all(programId);
|
|
151
|
+
}
|
|
152
|
+
const sessionIds = sessions.map((s) => s.session_id);
|
|
153
|
+
if (sessionIds.length === 0)
|
|
154
|
+
return { cancelled: 0, resetNodes: [] };
|
|
155
|
+
const placeholders = sessionIds.map(() => '?').join(',');
|
|
156
|
+
// Cancel all active tasks under these sessions
|
|
157
|
+
const result = db.prepare(`UPDATE tasks SET status = 'cancelled', updated_at = ? WHERE session_id IN (${placeholders}) AND status = 'active'`).run(now(), ...sessionIds);
|
|
158
|
+
// Reset affected nodes to pending
|
|
159
|
+
const resetNodes = [];
|
|
160
|
+
if (nodeId) {
|
|
161
|
+
db.prepare("UPDATE program_nodes SET status = 'pending', session_id = NULL, completed_at = NULL, node_key_hash = NULL WHERE node_id = ?")
|
|
162
|
+
.run(nodeId);
|
|
163
|
+
resetNodes.push(nodeId);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
const nodes = db.prepare("SELECT node_id FROM program_nodes WHERE program_id = ? AND status != 'pending'").all(programId);
|
|
167
|
+
for (const n of nodes) {
|
|
168
|
+
db.prepare("UPDATE program_nodes SET status = 'pending', session_id = NULL, completed_at = NULL, node_key_hash = NULL WHERE node_id = ?")
|
|
169
|
+
.run(n.node_id);
|
|
170
|
+
resetNodes.push(n.node_id);
|
|
171
|
+
}
|
|
172
|
+
db.prepare("UPDATE programs SET status = 'active', updated_at = ? WHERE program_id = ?").run(now(), programId);
|
|
173
|
+
}
|
|
174
|
+
return { cancelled: result.changes, resetNodes };
|
|
175
|
+
}
|
|
176
|
+
/** Finalize program: check all nodes complete. */
|
|
177
|
+
export function finalizeProgram(programId) {
|
|
178
|
+
const nodes = db.prepare("SELECT * FROM program_nodes WHERE program_id = ? AND status != 'completed'").all(programId);
|
|
179
|
+
if (nodes.length > 0) {
|
|
180
|
+
return {
|
|
181
|
+
ok: false,
|
|
182
|
+
pending: nodes.map((n) => ({
|
|
183
|
+
nodeId: n.node_id, title: n.title, description: n.description,
|
|
184
|
+
orderIndex: n.order_index, status: n.status, sessionId: n.session_id,
|
|
185
|
+
})),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
db.prepare("UPDATE programs SET status = 'completed', updated_at = ? WHERE program_id = ?").run(now(), programId);
|
|
189
|
+
return { ok: true, pending: [] };
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=program.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"program.js","sourceRoot":"","sources":["../../src/core/program.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface ReconcileReport {
|
|
2
|
+
timestamp: string;
|
|
3
|
+
scope: {
|
|
4
|
+
programId?: string;
|
|
5
|
+
};
|
|
6
|
+
summary: {
|
|
7
|
+
totalPrograms: number;
|
|
8
|
+
totalNodes: number;
|
|
9
|
+
totalTasks: number;
|
|
10
|
+
totalSteps: number;
|
|
11
|
+
healthy: number;
|
|
12
|
+
stale: number;
|
|
13
|
+
orphan: number;
|
|
14
|
+
drift: number;
|
|
15
|
+
};
|
|
16
|
+
orphans: Array<{
|
|
17
|
+
type: 'step_orphan' | 'step_stale';
|
|
18
|
+
stepId: string;
|
|
19
|
+
taskId: string;
|
|
20
|
+
path: string;
|
|
21
|
+
detail: string;
|
|
22
|
+
}>;
|
|
23
|
+
staleTasks: Array<{
|
|
24
|
+
taskId: string;
|
|
25
|
+
title: string;
|
|
26
|
+
status: string;
|
|
27
|
+
sessionId: string;
|
|
28
|
+
createdAt: string;
|
|
29
|
+
updatedAt: string;
|
|
30
|
+
}>;
|
|
31
|
+
drifts: Array<{
|
|
32
|
+
type: 'task_done_node_pending' | 'task_active_node_done';
|
|
33
|
+
detail: string;
|
|
34
|
+
}>;
|
|
35
|
+
suggestions: string[];
|
|
36
|
+
}
|
|
37
|
+
export declare function reconcile(programId?: string): ReconcileReport;
|