@directive-run/knowledge 0.2.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/LICENSE +21 -0
- package/README.md +63 -0
- package/ai/ai-adapters.md +250 -0
- package/ai/ai-agents-streaming.md +269 -0
- package/ai/ai-budget-resilience.md +235 -0
- package/ai/ai-communication.md +281 -0
- package/ai/ai-debug-observability.md +243 -0
- package/ai/ai-guardrails-memory.md +332 -0
- package/ai/ai-mcp-rag.md +288 -0
- package/ai/ai-multi-agent.md +274 -0
- package/ai/ai-orchestrator.md +227 -0
- package/ai/ai-security.md +293 -0
- package/ai/ai-tasks.md +261 -0
- package/ai/ai-testing-evals.md +378 -0
- package/api-skeleton.md +5 -0
- package/core/anti-patterns.md +382 -0
- package/core/constraints.md +263 -0
- package/core/core-patterns.md +228 -0
- package/core/error-boundaries.md +322 -0
- package/core/multi-module.md +315 -0
- package/core/naming.md +283 -0
- package/core/plugins.md +344 -0
- package/core/react-adapter.md +262 -0
- package/core/resolvers.md +357 -0
- package/core/schema-types.md +262 -0
- package/core/system-api.md +271 -0
- package/core/testing.md +257 -0
- package/core/time-travel.md +238 -0
- package/dist/index.cjs +111 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +102 -0
- package/dist/index.js.map +1 -0
- package/examples/ab-testing.ts +385 -0
- package/examples/ai-checkpoint.ts +509 -0
- package/examples/ai-guardrails.ts +319 -0
- package/examples/ai-orchestrator.ts +589 -0
- package/examples/async-chains.ts +287 -0
- package/examples/auth-flow.ts +371 -0
- package/examples/batch-resolver.ts +341 -0
- package/examples/checkers.ts +589 -0
- package/examples/contact-form.ts +176 -0
- package/examples/counter.ts +393 -0
- package/examples/dashboard-loader.ts +512 -0
- package/examples/debounce-constraints.ts +105 -0
- package/examples/dynamic-modules.ts +293 -0
- package/examples/error-boundaries.ts +430 -0
- package/examples/feature-flags.ts +220 -0
- package/examples/form-wizard.ts +347 -0
- package/examples/fraud-analysis.ts +663 -0
- package/examples/goal-heist.ts +341 -0
- package/examples/multi-module.ts +57 -0
- package/examples/newsletter.ts +241 -0
- package/examples/notifications.ts +210 -0
- package/examples/optimistic-updates.ts +317 -0
- package/examples/pagination.ts +260 -0
- package/examples/permissions.ts +337 -0
- package/examples/provider-routing.ts +403 -0
- package/examples/server.ts +316 -0
- package/examples/shopping-cart.ts +422 -0
- package/examples/sudoku.ts +630 -0
- package/examples/theme-locale.ts +204 -0
- package/examples/time-machine.ts +225 -0
- package/examples/topic-guard.ts +306 -0
- package/examples/url-sync.ts +333 -0
- package/examples/websocket.ts +404 -0
- package/package.json +65 -0
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
// Example: ai-checkpoint
|
|
2
|
+
// Source: examples/ai-checkpoint/src/main.ts
|
|
3
|
+
// Extracted for AI rules — DOM wiring stripped
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* AI Pipeline Checkpoint — 4-Stage Document Processing with Save/Restore
|
|
7
|
+
*
|
|
8
|
+
* 4-stage pipeline (extract → summarize → classify → archive) with checkpoint
|
|
9
|
+
* at every stage. Save/restore/delete checkpoints. Retry with backoff on failures.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
type Checkpoint,
|
|
14
|
+
InMemoryCheckpointStore,
|
|
15
|
+
createCheckpointId,
|
|
16
|
+
validateCheckpoint,
|
|
17
|
+
} from "@directive-run/ai";
|
|
18
|
+
import {
|
|
19
|
+
type ModuleSchema,
|
|
20
|
+
createModule,
|
|
21
|
+
createSystem,
|
|
22
|
+
t,
|
|
23
|
+
} from "@directive-run/core";
|
|
24
|
+
import { devtoolsPlugin } from "@directive-run/core/plugins";
|
|
25
|
+
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// Types
|
|
28
|
+
// ============================================================================
|
|
29
|
+
|
|
30
|
+
type PipelineStage =
|
|
31
|
+
| "idle"
|
|
32
|
+
| "extract"
|
|
33
|
+
| "summarize"
|
|
34
|
+
| "classify"
|
|
35
|
+
| "archive"
|
|
36
|
+
| "done"
|
|
37
|
+
| "error";
|
|
38
|
+
|
|
39
|
+
interface StageResult {
|
|
40
|
+
stage: string;
|
|
41
|
+
output: string;
|
|
42
|
+
tokens: number;
|
|
43
|
+
durationMs: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface CheckpointEntry {
|
|
47
|
+
id: string;
|
|
48
|
+
label: string;
|
|
49
|
+
createdAt: string;
|
|
50
|
+
stage: PipelineStage;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface TimelineEntry {
|
|
54
|
+
time: number;
|
|
55
|
+
event: string;
|
|
56
|
+
detail: string;
|
|
57
|
+
type: "stage" | "checkpoint" | "retry" | "error" | "info" | "success";
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ============================================================================
|
|
61
|
+
// Constants
|
|
62
|
+
// ============================================================================
|
|
63
|
+
|
|
64
|
+
const STAGES: PipelineStage[] = ["extract", "summarize", "classify", "archive"];
|
|
65
|
+
|
|
66
|
+
const STAGE_CONFIG = {
|
|
67
|
+
extract: {
|
|
68
|
+
tokens: 150,
|
|
69
|
+
baseLatency: 300,
|
|
70
|
+
output: "Extracted 3 sections, 2 tables, 5 figures from document.",
|
|
71
|
+
},
|
|
72
|
+
summarize: {
|
|
73
|
+
tokens: 200,
|
|
74
|
+
baseLatency: 400,
|
|
75
|
+
output:
|
|
76
|
+
"Summary: Key findings include efficiency gains of 23% and cost reduction of $1.2M annually.",
|
|
77
|
+
},
|
|
78
|
+
classify: {
|
|
79
|
+
tokens: 80,
|
|
80
|
+
baseLatency: 200,
|
|
81
|
+
output:
|
|
82
|
+
"Classification: category=research, confidence=0.94, tags=[efficiency, cost, annual-review]",
|
|
83
|
+
},
|
|
84
|
+
archive: {
|
|
85
|
+
tokens: 50,
|
|
86
|
+
baseLatency: 150,
|
|
87
|
+
output: "Archived to /documents/2026/research/efficiency-report.json",
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// ============================================================================
|
|
92
|
+
// Timeline
|
|
93
|
+
// ============================================================================
|
|
94
|
+
|
|
95
|
+
const timeline: TimelineEntry[] = [];
|
|
96
|
+
|
|
97
|
+
function addTimeline(
|
|
98
|
+
event: string,
|
|
99
|
+
detail: string,
|
|
100
|
+
type: TimelineEntry["type"],
|
|
101
|
+
) {
|
|
102
|
+
timeline.unshift({ time: Date.now(), event, detail, type });
|
|
103
|
+
if (timeline.length > 50) {
|
|
104
|
+
timeline.length = 50;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ============================================================================
|
|
109
|
+
// Checkpoint Store
|
|
110
|
+
// ============================================================================
|
|
111
|
+
|
|
112
|
+
const checkpointStore = new InMemoryCheckpointStore({ maxCheckpoints: 20 });
|
|
113
|
+
|
|
114
|
+
// ============================================================================
|
|
115
|
+
// Schema
|
|
116
|
+
// ============================================================================
|
|
117
|
+
|
|
118
|
+
const schema = {
|
|
119
|
+
facts: {
|
|
120
|
+
currentStage: t.string<PipelineStage>(),
|
|
121
|
+
stageResults: t.object<StageResult[]>(),
|
|
122
|
+
totalTokens: t.number(),
|
|
123
|
+
retryCount: t.number(),
|
|
124
|
+
maxRetries: t.number(),
|
|
125
|
+
failStage: t.string(),
|
|
126
|
+
isRunning: t.boolean(),
|
|
127
|
+
lastError: t.string(),
|
|
128
|
+
checkpoints: t.object<CheckpointEntry[]>(),
|
|
129
|
+
selectedCheckpoint: t.string(),
|
|
130
|
+
},
|
|
131
|
+
derivations: {
|
|
132
|
+
completionPercentage: t.number(),
|
|
133
|
+
currentStageIndex: t.number(),
|
|
134
|
+
canAdvance: t.boolean(),
|
|
135
|
+
isPipelineDone: t.boolean(),
|
|
136
|
+
stageCount: t.number(),
|
|
137
|
+
},
|
|
138
|
+
events: {
|
|
139
|
+
setFailStage: { value: t.string() },
|
|
140
|
+
setMaxRetries: { value: t.number() },
|
|
141
|
+
selectCheckpoint: { id: t.string() },
|
|
142
|
+
reset: {},
|
|
143
|
+
},
|
|
144
|
+
requirements: {},
|
|
145
|
+
} satisfies ModuleSchema;
|
|
146
|
+
|
|
147
|
+
// ============================================================================
|
|
148
|
+
// Module
|
|
149
|
+
// ============================================================================
|
|
150
|
+
|
|
151
|
+
const pipelineModule = createModule("pipeline", {
|
|
152
|
+
schema,
|
|
153
|
+
|
|
154
|
+
init: (facts) => {
|
|
155
|
+
facts.currentStage = "idle";
|
|
156
|
+
facts.stageResults = [];
|
|
157
|
+
facts.totalTokens = 0;
|
|
158
|
+
facts.retryCount = 0;
|
|
159
|
+
facts.maxRetries = 2;
|
|
160
|
+
facts.failStage = "";
|
|
161
|
+
facts.isRunning = false;
|
|
162
|
+
facts.lastError = "";
|
|
163
|
+
facts.checkpoints = [];
|
|
164
|
+
facts.selectedCheckpoint = "";
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
derive: {
|
|
168
|
+
completionPercentage: (facts) => {
|
|
169
|
+
if (facts.currentStage === "idle") {
|
|
170
|
+
return 0;
|
|
171
|
+
}
|
|
172
|
+
if (facts.currentStage === "done") {
|
|
173
|
+
return 100;
|
|
174
|
+
}
|
|
175
|
+
if (facts.currentStage === "error") {
|
|
176
|
+
const idx = (facts.stageResults as StageResult[]).length;
|
|
177
|
+
|
|
178
|
+
return Math.round((idx / STAGES.length) * 100);
|
|
179
|
+
}
|
|
180
|
+
const idx = STAGES.indexOf(facts.currentStage as PipelineStage);
|
|
181
|
+
|
|
182
|
+
return Math.round((idx / STAGES.length) * 100);
|
|
183
|
+
},
|
|
184
|
+
currentStageIndex: (facts) => {
|
|
185
|
+
if (facts.currentStage === "idle") {
|
|
186
|
+
return -1;
|
|
187
|
+
}
|
|
188
|
+
if (facts.currentStage === "done") {
|
|
189
|
+
return STAGES.length;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return STAGES.indexOf(facts.currentStage as PipelineStage);
|
|
193
|
+
},
|
|
194
|
+
canAdvance: (facts) => {
|
|
195
|
+
return (
|
|
196
|
+
!facts.isRunning &&
|
|
197
|
+
facts.currentStage !== "done" &&
|
|
198
|
+
facts.currentStage !== "error"
|
|
199
|
+
);
|
|
200
|
+
},
|
|
201
|
+
isPipelineDone: (facts) => facts.currentStage === "done",
|
|
202
|
+
stageCount: () => STAGES.length,
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
events: {
|
|
206
|
+
setFailStage: (facts, { value }) => {
|
|
207
|
+
facts.failStage = value;
|
|
208
|
+
},
|
|
209
|
+
setMaxRetries: (facts, { value }) => {
|
|
210
|
+
facts.maxRetries = value;
|
|
211
|
+
},
|
|
212
|
+
selectCheckpoint: (facts, { id }) => {
|
|
213
|
+
facts.selectedCheckpoint = id;
|
|
214
|
+
},
|
|
215
|
+
reset: (facts) => {
|
|
216
|
+
facts.currentStage = "idle";
|
|
217
|
+
facts.stageResults = [];
|
|
218
|
+
facts.totalTokens = 0;
|
|
219
|
+
facts.retryCount = 0;
|
|
220
|
+
facts.isRunning = false;
|
|
221
|
+
facts.lastError = "";
|
|
222
|
+
facts.selectedCheckpoint = "";
|
|
223
|
+
timeline.length = 0;
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// ============================================================================
|
|
229
|
+
// System
|
|
230
|
+
// ============================================================================
|
|
231
|
+
|
|
232
|
+
const system = createSystem({
|
|
233
|
+
module: pipelineModule,
|
|
234
|
+
debug: { runHistory: true },
|
|
235
|
+
plugins: [devtoolsPlugin({ name: "ai-checkpoint" })],
|
|
236
|
+
});
|
|
237
|
+
system.start();
|
|
238
|
+
|
|
239
|
+
// ============================================================================
|
|
240
|
+
// Pipeline Logic
|
|
241
|
+
// ============================================================================
|
|
242
|
+
|
|
243
|
+
async function runStage(stage: PipelineStage): Promise<StageResult> {
|
|
244
|
+
const config = STAGE_CONFIG[stage as keyof typeof STAGE_CONFIG];
|
|
245
|
+
if (!config) {
|
|
246
|
+
throw new Error(`Unknown stage: ${stage}`);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Simulate latency
|
|
250
|
+
const latency = config.baseLatency + Math.random() * 100;
|
|
251
|
+
await new Promise((resolve) => setTimeout(resolve, latency));
|
|
252
|
+
|
|
253
|
+
// Check for injected failure
|
|
254
|
+
if (system.facts.failStage === stage) {
|
|
255
|
+
throw new Error(`${stage}: simulated failure`);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return {
|
|
259
|
+
stage,
|
|
260
|
+
output: config.output,
|
|
261
|
+
tokens: config.tokens + Math.floor(Math.random() * 30),
|
|
262
|
+
durationMs: Math.round(latency),
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
async function runStageWithRetry(stage: PipelineStage): Promise<StageResult> {
|
|
267
|
+
const maxRetries = system.facts.maxRetries as number;
|
|
268
|
+
let lastError: Error | null = null;
|
|
269
|
+
|
|
270
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
271
|
+
try {
|
|
272
|
+
if (attempt > 0) {
|
|
273
|
+
const delay = Math.min(500 * 2 ** (attempt - 1), 4000);
|
|
274
|
+
const jitter = Math.random() * delay * 0.1;
|
|
275
|
+
system.facts.retryCount = (system.facts.retryCount as number) + 1;
|
|
276
|
+
"retry",
|
|
277
|
+
`${stage}: attempt ${attempt + 1}/${maxRetries + 1} (delay ${Math.round(delay)}ms)`,
|
|
278
|
+
"retry",
|
|
279
|
+
);
|
|
280
|
+
render();
|
|
281
|
+
await new Promise((resolve) => setTimeout(resolve, delay + jitter));
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return await runStage(stage);
|
|
285
|
+
} catch (err) {
|
|
286
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
throw lastError!;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
async function advancePipeline() {
|
|
294
|
+
if (system.facts.isRunning) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const current = system.facts.currentStage as PipelineStage;
|
|
299
|
+
let nextStage: PipelineStage;
|
|
300
|
+
|
|
301
|
+
if (current === "idle") {
|
|
302
|
+
nextStage = STAGES[0]!;
|
|
303
|
+
} else if (current === "done" || current === "error") {
|
|
304
|
+
return;
|
|
305
|
+
} else {
|
|
306
|
+
const idx = STAGES.indexOf(current);
|
|
307
|
+
if (idx < 0 || idx >= STAGES.length - 1) {
|
|
308
|
+
// Current stage should be run first
|
|
309
|
+
nextStage = current;
|
|
310
|
+
} else {
|
|
311
|
+
nextStage = STAGES[idx + 1]!;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
system.facts.isRunning = true;
|
|
316
|
+
system.facts.currentStage = nextStage;
|
|
317
|
+
render();
|
|
318
|
+
|
|
319
|
+
try {
|
|
320
|
+
const result = await runStageWithRetry(nextStage);
|
|
321
|
+
const results = [...(system.facts.stageResults as StageResult[]), result];
|
|
322
|
+
system.facts.stageResults = results;
|
|
323
|
+
system.facts.totalTokens =
|
|
324
|
+
(system.facts.totalTokens as number) + result.tokens;
|
|
325
|
+
"success",
|
|
326
|
+
`${nextStage}: complete (${result.tokens} tokens)`,
|
|
327
|
+
"success",
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
const idx = STAGES.indexOf(nextStage);
|
|
331
|
+
if (idx >= STAGES.length - 1) {
|
|
332
|
+
system.facts.currentStage = "done";
|
|
333
|
+
} else {
|
|
334
|
+
system.facts.currentStage = nextStage;
|
|
335
|
+
}
|
|
336
|
+
} catch (err) {
|
|
337
|
+
system.facts.currentStage = "error";
|
|
338
|
+
system.facts.lastError = err instanceof Error ? err.message : String(err);
|
|
339
|
+
} finally {
|
|
340
|
+
system.facts.isRunning = false;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
async function autoRun() {
|
|
345
|
+
if (system.facts.isRunning) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
system.facts.currentStage = "idle";
|
|
350
|
+
system.facts.stageResults = [];
|
|
351
|
+
system.facts.totalTokens = 0;
|
|
352
|
+
system.facts.retryCount = 0;
|
|
353
|
+
system.facts.lastError = "";
|
|
354
|
+
|
|
355
|
+
for (const stage of STAGES) {
|
|
356
|
+
system.facts.isRunning = true;
|
|
357
|
+
system.facts.currentStage = stage;
|
|
358
|
+
render();
|
|
359
|
+
|
|
360
|
+
try {
|
|
361
|
+
const result = await runStageWithRetry(stage);
|
|
362
|
+
const results = [...(system.facts.stageResults as StageResult[]), result];
|
|
363
|
+
system.facts.stageResults = results;
|
|
364
|
+
system.facts.totalTokens =
|
|
365
|
+
(system.facts.totalTokens as number) + result.tokens;
|
|
366
|
+
"success",
|
|
367
|
+
`${stage}: complete (${result.tokens} tokens)`,
|
|
368
|
+
"success",
|
|
369
|
+
);
|
|
370
|
+
} catch (err) {
|
|
371
|
+
system.facts.currentStage = "error";
|
|
372
|
+
system.facts.lastError = err instanceof Error ? err.message : String(err);
|
|
373
|
+
system.facts.isRunning = false;
|
|
374
|
+
"error",
|
|
375
|
+
`pipeline halted at ${stage}: ${system.facts.lastError}`,
|
|
376
|
+
"error",
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
system.facts.isRunning = false;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
system.facts.currentStage = "done";
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// ============================================================================
|
|
389
|
+
// Checkpoint Logic
|
|
390
|
+
// ============================================================================
|
|
391
|
+
|
|
392
|
+
async function saveCheckpoint() {
|
|
393
|
+
const stage = system.facts.currentStage as PipelineStage;
|
|
394
|
+
const id = createCheckpointId();
|
|
395
|
+
const label = `Stage: ${stage} (${new Date().toLocaleTimeString()})`;
|
|
396
|
+
|
|
397
|
+
const checkpoint: Checkpoint = {
|
|
398
|
+
version: 1,
|
|
399
|
+
id,
|
|
400
|
+
createdAt: new Date().toISOString(),
|
|
401
|
+
label,
|
|
402
|
+
systemExport: JSON.stringify({
|
|
403
|
+
currentStage: system.facts.currentStage,
|
|
404
|
+
stageResults: system.facts.stageResults,
|
|
405
|
+
totalTokens: system.facts.totalTokens,
|
|
406
|
+
retryCount: system.facts.retryCount,
|
|
407
|
+
lastError: system.facts.lastError,
|
|
408
|
+
}),
|
|
409
|
+
timelineExport: JSON.stringify(timeline.slice(0, 20)),
|
|
410
|
+
localState: { type: "single" },
|
|
411
|
+
memoryExport: null,
|
|
412
|
+
orchestratorType: "single",
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
await checkpointStore.save(checkpoint);
|
|
416
|
+
|
|
417
|
+
const entry: CheckpointEntry = {
|
|
418
|
+
id,
|
|
419
|
+
label,
|
|
420
|
+
createdAt: checkpoint.createdAt,
|
|
421
|
+
stage,
|
|
422
|
+
};
|
|
423
|
+
system.facts.checkpoints = [
|
|
424
|
+
...(system.facts.checkpoints as CheckpointEntry[]),
|
|
425
|
+
entry,
|
|
426
|
+
];
|
|
427
|
+
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
async function restoreCheckpoint(checkpointId: string) {
|
|
431
|
+
const checkpoint = await checkpointStore.load(checkpointId);
|
|
432
|
+
if (!checkpoint) {
|
|
433
|
+
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (!validateCheckpoint(checkpoint)) {
|
|
438
|
+
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const saved = JSON.parse(checkpoint.systemExport);
|
|
443
|
+
system.facts.currentStage = saved.currentStage;
|
|
444
|
+
system.facts.stageResults = saved.stageResults;
|
|
445
|
+
system.facts.totalTokens = saved.totalTokens;
|
|
446
|
+
system.facts.retryCount = saved.retryCount;
|
|
447
|
+
system.facts.lastError = saved.lastError;
|
|
448
|
+
system.facts.isRunning = false;
|
|
449
|
+
|
|
450
|
+
if (checkpoint.timelineExport) {
|
|
451
|
+
timeline.length = 0;
|
|
452
|
+
for (const entry of savedTimeline) {
|
|
453
|
+
timeline.push(entry);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
async function deleteCheckpoint(checkpointId: string) {
|
|
460
|
+
const deleted = await checkpointStore.delete(checkpointId);
|
|
461
|
+
if (deleted) {
|
|
462
|
+
const checkpoints = (system.facts.checkpoints as CheckpointEntry[]).filter(
|
|
463
|
+
(c) => c.id !== checkpointId,
|
|
464
|
+
);
|
|
465
|
+
system.facts.checkpoints = checkpoints;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// ============================================================================
|
|
470
|
+
// DOM References
|
|
471
|
+
// ============================================================================
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
// ============================================================================
|
|
475
|
+
// Render
|
|
476
|
+
// ============================================================================
|
|
477
|
+
|
|
478
|
+
function escapeHtml(text: string): string {
|
|
479
|
+
|
|
480
|
+
return div.innerHTML;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
// ============================================================================
|
|
485
|
+
// Subscribe
|
|
486
|
+
// ============================================================================
|
|
487
|
+
|
|
488
|
+
const allKeys = [
|
|
489
|
+
...Object.keys(schema.facts),
|
|
490
|
+
...Object.keys(schema.derivations),
|
|
491
|
+
];
|
|
492
|
+
system.subscribe(allKeys, render);
|
|
493
|
+
|
|
494
|
+
// ============================================================================
|
|
495
|
+
// Controls
|
|
496
|
+
// ============================================================================
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
"cp-fail-stage",
|
|
500
|
+
|
|
501
|
+
// Delegated click for checkpoint restore/delete
|
|
502
|
+
|
|
503
|
+
"cp-max-retries",
|
|
504
|
+
|
|
505
|
+
// ============================================================================
|
|
506
|
+
// Initial Render
|
|
507
|
+
// ============================================================================
|
|
508
|
+
|
|
509
|
+
render();
|