@voybio/ace-swarm 2.4.8 → 2.4.10
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/CHANGELOG.md +52 -14
- package/README.md +14 -10
- package/assets/.agents/ACE/ACE_coders/AGENTS.md +23 -30
- package/assets/.agents/ACE/ACE_coders/INSTRUCTIONS.md +21 -30
- package/assets/.agents/skills/landing-review-watcher/SKILL.md +1 -1
- package/assets/.agents/skills/learn-from-work/SKILL.md +41 -0
- package/assets/agent-state/ACE_WORKFLOW.md +25 -2
- package/assets/agent-state/MODULES/schemas/ACE_RUNTIME_PROFILE.schema.json +143 -2
- package/assets/agent-state/MODULES/schemas/RUNTIME_EXECUTOR_SESSION_REGISTRY.schema.json +2 -2
- package/assets/agent-state/MODULES/schemas/SWARM_HANDOFF.schema.json +10 -0
- package/assets/eval-battery/battery.json +1 -1
- package/assets/instructions/ACE_Coder.instructions.md +9 -13
- package/assets/scripts/ace-hook-dispatch.mjs +16 -411
- package/assets/tasks/SWARM_HANDOFF.example_ui_to_coders.json +1 -2
- package/assets/vendor/README.md +9 -0
- package/assets/vendor/vericify-reader.mjs +272 -0
- package/assets/vendor/vericify-reader.provenance.json +10 -0
- package/dist/ace-autonomy.d.ts +58 -0
- package/dist/ace-autonomy.js +211 -6
- package/dist/ace-internal-tools.d.ts +1 -0
- package/dist/ace-internal-tools.js +3 -3
- package/dist/ace-server-instructions.d.ts +3 -3
- package/dist/ace-server-instructions.js +46 -192
- package/dist/cli.js +44 -6
- package/dist/experience-reflector.d.ts +7 -0
- package/dist/experience-reflector.js +39 -0
- package/dist/goal-engine.d.ts +64 -7
- package/dist/goal-engine.js +197 -41
- package/dist/handoff-registry.d.ts +10 -0
- package/dist/handoff-registry.js +59 -0
- package/dist/helpers/artifacts.d.ts +6 -2
- package/dist/helpers/artifacts.js +8 -6
- package/dist/helpers/bootstrap.js +13 -20
- package/dist/helpers/path-utils.js +2 -0
- package/dist/helpers/store-resolution.js +18 -3
- package/dist/helpers/workspace-root.d.ts +2 -0
- package/dist/helpers/workspace-root.js +9 -0
- package/dist/helpers.d.ts +1 -0
- package/dist/helpers.js +1 -0
- package/dist/hermes/bridge-protocol.d.ts +1 -1
- package/dist/hermes/session-manager.d.ts +17 -0
- package/dist/hermes/session-manager.js +67 -14
- package/dist/host-goal-engine.d.ts +138 -0
- package/dist/host-goal-engine.js +793 -0
- package/dist/host-goal-status.d.ts +113 -0
- package/dist/host-goal-status.js +175 -0
- package/dist/host-learning.d.ts +68 -0
- package/dist/host-learning.js +115 -0
- package/dist/host-observation.d.ts +12 -0
- package/dist/host-observation.js +91 -0
- package/dist/host-plan-revision.d.ts +14 -0
- package/dist/host-plan-revision.js +101 -0
- package/dist/host-verification-job.d.ts +12 -0
- package/dist/host-verification-job.js +183 -0
- package/dist/host-work-context.d.ts +12 -0
- package/dist/host-work-context.js +8 -0
- package/dist/job-scheduler.d.ts +58 -13
- package/dist/job-scheduler.js +298 -48
- package/dist/job-worker.d.ts +3 -1
- package/dist/job-worker.js +10 -3
- package/dist/kanban.d.ts +4 -1
- package/dist/kanban.js +44 -16
- package/dist/learned-artifacts.d.ts +64 -0
- package/dist/learned-artifacts.js +321 -0
- package/dist/learning-controls.d.ts +142 -0
- package/dist/learning-controls.js +135 -0
- package/dist/learning-input-context.d.ts +9 -0
- package/dist/learning-input-context.js +62 -0
- package/dist/learning-lifecycle.d.ts +10 -0
- package/dist/learning-lifecycle.js +11 -0
- package/dist/learning-overlays.d.ts +3 -0
- package/dist/learning-overlays.js +17 -0
- package/dist/learning-policy.d.ts +40 -0
- package/dist/learning-policy.js +38 -0
- package/dist/learning-records.d.ts +35 -0
- package/dist/learning-records.js +17 -0
- package/dist/learning-scorecard.d.ts +82 -0
- package/dist/learning-scorecard.js +86 -0
- package/dist/learning-serving.d.ts +29 -0
- package/dist/learning-serving.js +134 -0
- package/dist/linked-work.d.ts +9 -0
- package/dist/linked-work.js +28 -0
- package/dist/local-model-runtime.js +1 -1
- package/dist/mcp-command-progress.d.ts +16 -0
- package/dist/mcp-command-progress.js +70 -0
- package/dist/model-bridge.d.ts +14 -13
- package/dist/model-bridge.js +73 -41
- package/dist/orchestrator-supervisor.d.ts +111 -6
- package/dist/orchestrator-supervisor.js +67 -43
- package/dist/plan-proposal.js +3 -3
- package/dist/playbook-curator.d.ts +1 -0
- package/dist/playbook-curator.js +11 -9
- package/dist/process-identity.d.ts +8 -0
- package/dist/process-identity.js +38 -0
- package/dist/progress-command.d.ts +34 -0
- package/dist/progress-command.js +153 -0
- package/dist/prompts.js +15 -15
- package/dist/resources.js +2 -2
- package/dist/runtime-command.d.ts +8 -1
- package/dist/runtime-command.js +48 -7
- package/dist/runtime-executor.js +33 -11
- package/dist/runtime-profile-syntax.d.ts +6 -0
- package/dist/runtime-profile-syntax.js +121 -0
- package/dist/runtime-profile.d.ts +37 -5
- package/dist/runtime-profile.js +36 -129
- package/dist/runtime-tool-specs.js +1 -1
- package/dist/safe-edit.d.ts +7 -3
- package/dist/safe-edit.js +40 -47
- package/dist/schemas.js +4 -2
- package/dist/server.d.ts +2 -16
- package/dist/server.js +14 -20
- package/dist/shared.d.ts +2 -0
- package/dist/shared.js +2 -0
- package/dist/skill-auditor.d.ts +19 -0
- package/dist/skill-auditor.js +32 -2
- package/dist/skill-catalog.d.ts +4 -1
- package/dist/skill-catalog.js +6 -5
- package/dist/store/ace-packed-store.d.ts +5 -1
- package/dist/store/ace-packed-store.js +33 -1
- package/dist/store/bootstrap-store.js +19 -12
- package/dist/store/cache-workspace.d.ts +8 -0
- package/dist/store/cache-workspace.js +94 -27
- package/dist/store/importer.js +11 -20
- package/dist/store/knowledge-bake.d.ts +3 -1
- package/dist/store/knowledge-bake.js +10 -1
- package/dist/store/legacy-vericify-posts.d.ts +8 -0
- package/dist/store/legacy-vericify-posts.js +76 -0
- package/dist/store/materializers/hook-context-materializer.d.ts +2 -1
- package/dist/store/materializers/hook-context-materializer.js +6 -2
- package/dist/store/materializers/host-file-materializer.js +2 -2
- package/dist/store/materializers/projection-manager.d.ts +4 -1
- package/dist/store/materializers/projection-manager.js +10 -3
- package/dist/store/materializers/todo-syncer.d.ts +39 -20
- package/dist/store/materializers/todo-syncer.js +208 -110
- package/dist/store/materializers/vericify-projector.js +15 -26
- package/dist/store/repositories/goal-repository.d.ts +51 -2
- package/dist/store/repositories/goal-repository.js +114 -48
- package/dist/store/repositories/playbook-repository.d.ts +41 -3
- package/dist/store/repositories/playbook-repository.js +61 -5
- package/dist/store/repositories/todo-repository.d.ts +8 -2
- package/dist/store/repositories/todo-repository.js +1 -1
- package/dist/store/repositories/vericify-repository.d.ts +4 -0
- package/dist/store/repositories/vericify-repository.js +46 -0
- package/dist/store/skills-install.d.ts +1 -0
- package/dist/store/skills-install.js +20 -16
- package/dist/store/source-preservation.d.ts +24 -0
- package/dist/store/source-preservation.js +79 -0
- package/dist/store/store-artifacts.js +8 -1
- package/dist/store/test-write-boundary.d.ts +16 -0
- package/dist/store/test-write-boundary.js +175 -0
- package/dist/store/types.d.ts +5 -1
- package/dist/store/write-coordinator.js +16 -0
- package/dist/task-plan-context.d.ts +11 -0
- package/dist/task-plan-context.js +59 -0
- package/dist/todo-state.d.ts +19 -9
- package/dist/todo-state.js +204 -321
- package/dist/tools-agent.d.ts +1 -1
- package/dist/tools-agent.js +38 -62
- package/dist/tools-files.d.ts +0 -3
- package/dist/tools-files.js +21 -11
- package/dist/tools-framework.js +16 -25
- package/dist/tools-goal.d.ts +2 -4
- package/dist/tools-goal.js +119 -16
- package/dist/tools-handoff.d.ts +3 -2
- package/dist/tools-handoff.js +53 -23
- package/dist/tools-lifecycle.js +1 -1
- package/dist/tools-memory.d.ts +0 -3
- package/dist/tools-memory.js +51 -6
- package/dist/tools-scheduler.js +20 -17
- package/dist/tools-todo.js +160 -148
- package/dist/vericify-bridge.d.ts +8 -0
- package/dist/vericify-bridge.js +18 -0
- package/dist/vericify-context.d.ts +4 -0
- package/dist/vericify-context.js +26 -5
- package/dist/vericify-native.d.ts +101 -0
- package/dist/vericify-native.js +221 -0
- package/dist/verification-worker.d.ts +2 -0
- package/dist/verification-worker.js +31 -0
- package/docs/mcp-tool-reference.md +50 -10
- package/docs/troubleshooting.md +29 -0
- package/package.json +19 -6
- package/scripts/dev/run-tests-isolated.mjs +165 -0
- package/scripts/dev/run_hermes_crispr_live.mjs +1 -0
- package/scripts/dev/test-isolation-guard.mjs +20 -0
- package/scripts/dev/test-preload.mjs +153 -0
- package/scripts/dev/test-source-inventory.mjs +31 -0
- package/docs/development.md +0 -46
|
@@ -17,6 +17,50 @@
|
|
|
17
17
|
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync, } from "node:fs";
|
|
18
18
|
import { join } from "node:path";
|
|
19
19
|
import { randomUUID } from "node:crypto";
|
|
20
|
+
import { withStoreWriteCoordinatorSync } from "../write-coordinator.js";
|
|
21
|
+
/** Wire representation understood by pre-marker 2.4.x engines, which compare
|
|
22
|
+
* numeric limits directly. In-memory callers continue to use zero for unlimited.
|
|
23
|
+
* This is a finite compatibility sentinel, not a mathematical infinity. */
|
|
24
|
+
export const UNBOUNDED_GOAL_BUDGET_WIRE_VALUE = Number.MAX_SAFE_INTEGER;
|
|
25
|
+
const LEGACY_GOAL_DEFAULTS = { max_wall_clock_ms: 14_400_000, max_ticks: 200, max_replans: 3 };
|
|
26
|
+
function normalizeGoalRecord(goal) {
|
|
27
|
+
const source = goal.budgets ?? {};
|
|
28
|
+
const budgets = { ...source };
|
|
29
|
+
const legacyShape = [source.max_wall_clock_ms, source.max_ticks, source.max_replans]
|
|
30
|
+
.some(value => Number.isFinite(value) && value > 0 && value !== UNBOUNDED_GOAL_BUDGET_WIRE_VALUE);
|
|
31
|
+
const infer = (field) => {
|
|
32
|
+
const value = source[field];
|
|
33
|
+
return Number.isFinite(value) && value >= 0 && value !== UNBOUNDED_GOAL_BUDGET_WIRE_VALUE
|
|
34
|
+
&& value !== LEGACY_GOAL_DEFAULTS[field] && (value > 0 || (field !== 'max_wall_clock_ms' && legacyShape));
|
|
35
|
+
};
|
|
36
|
+
// Old records did not retain whether a value equal to the default was explicit.
|
|
37
|
+
// Those ambiguous defaults follow the approved unlimited upgrade policy.
|
|
38
|
+
const duration = goal.executor === 'host'
|
|
39
|
+
? source.host_deadline_explicit ?? source.deadline_explicit ?? infer('max_wall_clock_ms')
|
|
40
|
+
: source.deadline_explicit ?? infer('max_wall_clock_ms');
|
|
41
|
+
budgets.deadline_explicit = source.deadline_explicit ?? duration;
|
|
42
|
+
if (goal.executor === 'host' || source.host_deadline_explicit !== undefined) {
|
|
43
|
+
budgets.host_deadline_explicit = source.host_deadline_explicit ?? duration;
|
|
44
|
+
}
|
|
45
|
+
budgets.max_wall_clock_ms = duration ? source.max_wall_clock_ms : 0;
|
|
46
|
+
budgets.tick_budget_explicit = source.tick_budget_explicit ?? infer('max_ticks');
|
|
47
|
+
budgets.max_ticks = budgets.tick_budget_explicit ? source.max_ticks : 0;
|
|
48
|
+
budgets.replan_budget_explicit = source.replan_budget_explicit ?? infer('max_replans');
|
|
49
|
+
budgets.max_replans = budgets.replan_budget_explicit ? source.max_replans : 0;
|
|
50
|
+
budgets.max_step_retries = source.max_step_retries ?? 0;
|
|
51
|
+
return { ...goal, budgets };
|
|
52
|
+
}
|
|
53
|
+
function encodeGoalRecord(goal) {
|
|
54
|
+
const budgets = { ...goal.budgets };
|
|
55
|
+
const duration = goal.executor === 'host' ? budgets.host_deadline_explicit : budgets.deadline_explicit;
|
|
56
|
+
if (!duration)
|
|
57
|
+
budgets.max_wall_clock_ms = UNBOUNDED_GOAL_BUDGET_WIRE_VALUE;
|
|
58
|
+
if (!budgets.tick_budget_explicit)
|
|
59
|
+
budgets.max_ticks = UNBOUNDED_GOAL_BUDGET_WIRE_VALUE;
|
|
60
|
+
if (!budgets.replan_budget_explicit)
|
|
61
|
+
budgets.max_replans = UNBOUNDED_GOAL_BUDGET_WIRE_VALUE;
|
|
62
|
+
return { ...goal, budgets };
|
|
63
|
+
}
|
|
20
64
|
export function newGoalId() {
|
|
21
65
|
return `goal-${randomUUID()}`;
|
|
22
66
|
}
|
|
@@ -36,9 +80,13 @@ export class GoalRepository {
|
|
|
36
80
|
}
|
|
37
81
|
}
|
|
38
82
|
goalPath(goalId) {
|
|
83
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(goalId))
|
|
84
|
+
throw new Error("Invalid goal id");
|
|
39
85
|
return join(this.dir, `${goalId}.json`);
|
|
40
86
|
}
|
|
41
87
|
planPath(goalId) {
|
|
88
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(goalId))
|
|
89
|
+
throw new Error("Invalid goal id");
|
|
42
90
|
return join(this.dir, `${goalId}.plan.json`);
|
|
43
91
|
}
|
|
44
92
|
indexPath() {
|
|
@@ -68,31 +116,35 @@ export class GoalRepository {
|
|
|
68
116
|
return stored;
|
|
69
117
|
}
|
|
70
118
|
upsertIndex(goal) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
119
|
+
// Per-goal leases protect records, but independent workers share this index.
|
|
120
|
+
withStoreWriteCoordinatorSync(this.indexPath(), () => {
|
|
121
|
+
const index = this.readIndex();
|
|
122
|
+
const entry = {
|
|
123
|
+
goal_id: goal.goal_id,
|
|
124
|
+
status: goal.status,
|
|
125
|
+
objective: goal.objective,
|
|
126
|
+
updated_at: goal.updated_at,
|
|
127
|
+
};
|
|
128
|
+
const next = index.goals.filter((row) => row.goal_id !== goal.goal_id);
|
|
129
|
+
next.push(entry);
|
|
130
|
+
next.sort((a, b) => (a.updated_at < b.updated_at ? 1 : -1));
|
|
131
|
+
this.writeAtomic(this.indexPath(), {
|
|
132
|
+
version: 1,
|
|
133
|
+
updated_at: nowIso(),
|
|
134
|
+
goals: next,
|
|
135
|
+
});
|
|
136
|
+
}, { operation_label: 'goal_index_upsert' });
|
|
86
137
|
}
|
|
87
138
|
/** Persist a goal record and refresh the index in one call. */
|
|
88
139
|
saveGoal(goal) {
|
|
89
|
-
const record = { ...goal, updated_at: nowIso() };
|
|
90
|
-
this.writeAtomic(this.goalPath(record.goal_id), record);
|
|
140
|
+
const record = normalizeGoalRecord({ ...goal, updated_at: nowIso() });
|
|
141
|
+
this.writeAtomic(this.goalPath(record.goal_id), encodeGoalRecord(record));
|
|
91
142
|
this.upsertIndex(record);
|
|
92
143
|
return record;
|
|
93
144
|
}
|
|
94
145
|
getGoal(goalId) {
|
|
95
|
-
|
|
146
|
+
const record = this.readJson(this.goalPath(goalId));
|
|
147
|
+
return record ? normalizeGoalRecord(record) : undefined;
|
|
96
148
|
}
|
|
97
149
|
savePlan(goalId, plan) {
|
|
98
150
|
this.writeAtomic(this.planPath(goalId), plan);
|
|
@@ -101,7 +153,13 @@ export class GoalRepository {
|
|
|
101
153
|
return this.readJson(this.planPath(goalId));
|
|
102
154
|
}
|
|
103
155
|
listGoals(filter) {
|
|
104
|
-
|
|
156
|
+
// Per-goal writers need not serialize on the shared listing cache. Read the
|
|
157
|
+
// existing authoritative records so concurrent goals cannot disappear there.
|
|
158
|
+
const records = existsSync(this.dir) ? readdirSync(this.dir).filter(name => name.endsWith('.json') && name !== 'index.json' && !name.endsWith('.plan.json')).flatMap(name => {
|
|
159
|
+
const goal = this.readJson(join(this.dir, name));
|
|
160
|
+
return goal?.goal_id ? [{ goal_id: goal.goal_id, status: goal.status, objective: goal.objective, updated_at: goal.updated_at }] : [];
|
|
161
|
+
}) : [];
|
|
162
|
+
return records.sort((a, b) => b.updated_at.localeCompare(a.updated_at)).filter((row) => filter?.status ? row.status === filter.status : true);
|
|
105
163
|
}
|
|
106
164
|
/** Delete a goal, its plan, and its index entry. Returns true if present. */
|
|
107
165
|
deleteGoal(goalId) {
|
|
@@ -111,12 +169,14 @@ export class GoalRepository {
|
|
|
111
169
|
if (existsSync(path))
|
|
112
170
|
rmSync(path);
|
|
113
171
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
172
|
+
withStoreWriteCoordinatorSync(this.indexPath(), () => {
|
|
173
|
+
const index = this.readIndex();
|
|
174
|
+
this.writeAtomic(this.indexPath(), {
|
|
175
|
+
version: 1,
|
|
176
|
+
updated_at: nowIso(),
|
|
177
|
+
goals: index.goals.filter((row) => row.goal_id !== goalId),
|
|
178
|
+
});
|
|
179
|
+
}, { operation_label: 'goal_index_delete' });
|
|
120
180
|
return existed;
|
|
121
181
|
}
|
|
122
182
|
/**
|
|
@@ -124,34 +184,40 @@ export class GoalRepository {
|
|
|
124
184
|
* startup so a hand-deleted or partially-written index never hides live goals.
|
|
125
185
|
*/
|
|
126
186
|
rebuildIndex() {
|
|
127
|
-
this.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
187
|
+
return withStoreWriteCoordinatorSync(this.indexPath(), () => {
|
|
188
|
+
this.ensureDir();
|
|
189
|
+
const goals = [];
|
|
190
|
+
for (const name of readdirSync(this.dir)) {
|
|
191
|
+
if (!name.endsWith(".json") || name.endsWith(".plan.json") || name === "index.json") {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
const record = this.readJson(join(this.dir, name));
|
|
195
|
+
if (record?.goal_id) {
|
|
196
|
+
goals.push({
|
|
197
|
+
goal_id: record.goal_id,
|
|
198
|
+
status: record.status,
|
|
199
|
+
objective: record.objective,
|
|
200
|
+
updated_at: record.updated_at,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
141
203
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
204
|
+
goals.sort((a, b) => (a.updated_at < b.updated_at ? 1 : -1));
|
|
205
|
+
const file = { version: 1, updated_at: nowIso(), goals };
|
|
206
|
+
this.writeAtomic(this.indexPath(), file);
|
|
207
|
+
return file;
|
|
208
|
+
}, { operation_label: 'goal_index_rebuild' });
|
|
147
209
|
}
|
|
148
210
|
}
|
|
149
211
|
export function defaultGoalBudgets() {
|
|
150
212
|
return {
|
|
151
|
-
max_wall_clock_ms:
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
213
|
+
max_wall_clock_ms: 0,
|
|
214
|
+
deadline_explicit: false,
|
|
215
|
+
host_deadline_explicit: false,
|
|
216
|
+
max_ticks: 0,
|
|
217
|
+
tick_budget_explicit: false,
|
|
218
|
+
max_replans: 0,
|
|
219
|
+
replan_budget_explicit: false,
|
|
220
|
+
max_step_retries: 0,
|
|
155
221
|
};
|
|
156
222
|
}
|
|
157
223
|
//# sourceMappingURL=goal-repository.js.map
|
|
@@ -6,6 +6,9 @@ export interface PlaybookScope {
|
|
|
6
6
|
model?: string;
|
|
7
7
|
tool?: string;
|
|
8
8
|
reason_code?: string;
|
|
9
|
+
paths?: string[];
|
|
10
|
+
task_tags?: string[];
|
|
11
|
+
failure_signature?: string;
|
|
9
12
|
}
|
|
10
13
|
export interface PlaybookBullet {
|
|
11
14
|
bullet_id: string;
|
|
@@ -18,9 +21,32 @@ export interface PlaybookBullet {
|
|
|
18
21
|
status: PlaybookBulletStatus;
|
|
19
22
|
evidence_refs: string[];
|
|
20
23
|
provenance: {
|
|
21
|
-
source: "reflector" | "llm_reflector" | "operator" | "migration";
|
|
24
|
+
source: "reflector" | "llm_reflector" | "operator" | "migration" | "harvest";
|
|
22
25
|
run_id?: string;
|
|
26
|
+
note?: string;
|
|
23
27
|
};
|
|
28
|
+
served_count?: number;
|
|
29
|
+
used_count?: number;
|
|
30
|
+
used_goals?: string[];
|
|
31
|
+
scored_attempts?: string[];
|
|
32
|
+
served_outcomes?: {
|
|
33
|
+
done_first_attempt: number;
|
|
34
|
+
failed_same_signature: number;
|
|
35
|
+
other: number;
|
|
36
|
+
};
|
|
37
|
+
evidence_snapshots?: import("../../host-learning.js").Episode[];
|
|
38
|
+
label?: "checked" | "demonstrated";
|
|
39
|
+
validation_checks?: Array<{
|
|
40
|
+
command: string;
|
|
41
|
+
cwd: string;
|
|
42
|
+
ok: boolean;
|
|
43
|
+
}>;
|
|
44
|
+
acceptance_errors?: string[];
|
|
45
|
+
retired_reason?: string;
|
|
46
|
+
ever_active?: boolean;
|
|
47
|
+
activated_at?: string;
|
|
48
|
+
last_active_at?: string;
|
|
49
|
+
retired_at?: string;
|
|
24
50
|
created_at: string;
|
|
25
51
|
updated_at: string;
|
|
26
52
|
}
|
|
@@ -31,6 +57,8 @@ export type PlaybookDeltaOp = {
|
|
|
31
57
|
content: string;
|
|
32
58
|
evidence_refs: string[];
|
|
33
59
|
provenance: PlaybookBullet["provenance"];
|
|
60
|
+
status?: PlaybookBulletStatus;
|
|
61
|
+
evidence_snapshots?: PlaybookBullet["evidence_snapshots"];
|
|
34
62
|
} | {
|
|
35
63
|
type: "TAG";
|
|
36
64
|
bullet_id: string;
|
|
@@ -65,9 +93,10 @@ export declare function isPlaybookSection(value: string): value is PlaybookSecti
|
|
|
65
93
|
export declare function isPlaybookStatus(value: string): value is PlaybookBulletStatus;
|
|
66
94
|
export declare class PlaybookRepository {
|
|
67
95
|
private readonly workspaceRoot;
|
|
96
|
+
private readonly buffered?;
|
|
68
97
|
private readonly dir;
|
|
69
98
|
private migrated;
|
|
70
|
-
constructor(workspaceRoot: string);
|
|
99
|
+
constructor(workspaceRoot: string, buffered?: Map<string, string> | undefined);
|
|
71
100
|
get root(): string;
|
|
72
101
|
private useStore;
|
|
73
102
|
private ensureDir;
|
|
@@ -88,13 +117,19 @@ export declare class PlaybookRepository {
|
|
|
88
117
|
readIndex(): PlaybookIndexFile;
|
|
89
118
|
private upsertIndex;
|
|
90
119
|
saveBullet(bullet: PlaybookBullet): PlaybookBullet;
|
|
91
|
-
createBullet(input: Omit<PlaybookBullet, "bullet_id" | "helpful_count" | "harmful_count" | "observed_count" | "status" | "created_at" | "updated_at">
|
|
120
|
+
createBullet(input: Omit<PlaybookBullet, "bullet_id" | "helpful_count" | "harmful_count" | "observed_count" | "status" | "created_at" | "updated_at"> & {
|
|
121
|
+
status?: PlaybookBulletStatus;
|
|
122
|
+
}): PlaybookBullet;
|
|
92
123
|
getBullet(bulletId: string): PlaybookBullet | undefined;
|
|
93
124
|
listBullets(filter?: {
|
|
94
125
|
section?: PlaybookSection;
|
|
95
126
|
status?: PlaybookBulletStatus;
|
|
96
127
|
scope?: PlaybookScope;
|
|
97
128
|
}): PlaybookBullet[];
|
|
129
|
+
/** Pure listing for assignment/context selection; never migrates or repairs. */
|
|
130
|
+
listBulletsReadOnly(filter?: {
|
|
131
|
+
status?: PlaybookBulletStatus;
|
|
132
|
+
}): PlaybookBullet[];
|
|
98
133
|
applyDeltaOps(ops: PlaybookDeltaOp[], config?: PlaybookConfig): PlaybookApplyResult;
|
|
99
134
|
rebuildIndex(): PlaybookIndexFile;
|
|
100
135
|
}
|
|
@@ -104,4 +139,7 @@ export declare function renderPlaybookMarkdown(repo: PlaybookRepository, filter?
|
|
|
104
139
|
status?: PlaybookBulletStatus;
|
|
105
140
|
}): string;
|
|
106
141
|
export declare function materializePlaybookMarkdown(workspaceRoot: string): string;
|
|
142
|
+
/** One existing-pack transaction; the synchronous repository edits an ephemeral
|
|
143
|
+
* buffer, never recursively taking the non-reentrant cross-process lease. */
|
|
144
|
+
export declare function withPlaybookTransaction<T>(root: string, apply: (repo: PlaybookRepository) => T | Promise<T>): Promise<T>;
|
|
107
145
|
//# sourceMappingURL=playbook-repository.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { learningLifecycle } from '../../learning-lifecycle.js';
|
|
1
2
|
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync, } from "node:fs";
|
|
2
3
|
import { dirname, join } from "node:path";
|
|
3
4
|
import { randomUUID } from "node:crypto";
|
|
@@ -24,14 +25,16 @@ function truncateContent(content) {
|
|
|
24
25
|
function scopeMatches(bulletScope, filter) {
|
|
25
26
|
if (!filter)
|
|
26
27
|
return true;
|
|
27
|
-
return Object.entries(filter).every(([key, value]) => value === undefined || bulletScope[key] === undefined || bulletScope[key] === value);
|
|
28
|
+
return Object.entries(filter).every(([key, value]) => value === undefined || bulletScope[key] === undefined || JSON.stringify(bulletScope[key]) === JSON.stringify(value));
|
|
28
29
|
}
|
|
29
30
|
export class PlaybookRepository {
|
|
30
31
|
workspaceRoot;
|
|
32
|
+
buffered;
|
|
31
33
|
dir;
|
|
32
34
|
migrated = false;
|
|
33
|
-
constructor(workspaceRoot) {
|
|
35
|
+
constructor(workspaceRoot, buffered) {
|
|
34
36
|
this.workspaceRoot = workspaceRoot;
|
|
37
|
+
this.buffered = buffered;
|
|
35
38
|
this.dir = join(workspaceRoot, "agent-state", "playbook");
|
|
36
39
|
}
|
|
37
40
|
get root() {
|
|
@@ -67,6 +70,10 @@ export class PlaybookRepository {
|
|
|
67
70
|
return operationalArtifactKey(relPath);
|
|
68
71
|
}
|
|
69
72
|
writeText(relPath, content) {
|
|
73
|
+
if (this.buffered) {
|
|
74
|
+
this.buffered.set(relPath, content);
|
|
75
|
+
return relPath;
|
|
76
|
+
}
|
|
70
77
|
if (this.useStore()) {
|
|
71
78
|
return writeOperationalArtifactSync(this.workspaceRoot, relPath, content);
|
|
72
79
|
}
|
|
@@ -81,6 +88,8 @@ export class PlaybookRepository {
|
|
|
81
88
|
return this.writeText(relPath, JSON.stringify(value, null, 2));
|
|
82
89
|
}
|
|
83
90
|
readText(relPath) {
|
|
91
|
+
if (this.buffered?.has(relPath))
|
|
92
|
+
return this.buffered.get(relPath);
|
|
84
93
|
if (this.useStore()) {
|
|
85
94
|
const storeText = readStoreBlobSync(this.workspaceRoot, this.artifactKey(relPath));
|
|
86
95
|
if (typeof storeText === "string")
|
|
@@ -92,6 +101,8 @@ export class PlaybookRepository {
|
|
|
92
101
|
return readFileSync(path, "utf8");
|
|
93
102
|
}
|
|
94
103
|
existsRel(relPath) {
|
|
104
|
+
if (this.buffered?.has(relPath))
|
|
105
|
+
return true;
|
|
95
106
|
if (this.useStore() && typeof readStoreBlobSync(this.workspaceRoot, this.artifactKey(relPath)) === "string") {
|
|
96
107
|
return true;
|
|
97
108
|
}
|
|
@@ -109,7 +120,7 @@ export class PlaybookRepository {
|
|
|
109
120
|
}
|
|
110
121
|
}
|
|
111
122
|
listBulletRelPaths() {
|
|
112
|
-
const rels = new Set();
|
|
123
|
+
const rels = new Set([...(this.buffered?.keys() ?? [])].filter(k => /^agent-state\/playbook\/[^/]+\.json$/.test(k) && !k.endsWith("/__index.json")));
|
|
113
124
|
if (this.useStore()) {
|
|
114
125
|
const prefix = this.artifactKey("agent-state/playbook/");
|
|
115
126
|
for (const key of listStoreKeysSync(this.workspaceRoot, prefix)) {
|
|
@@ -164,7 +175,8 @@ export class PlaybookRepository {
|
|
|
164
175
|
}
|
|
165
176
|
saveBullet(bullet) {
|
|
166
177
|
this.ensureDir();
|
|
167
|
-
const
|
|
178
|
+
const at = nowIso(), previous = this.readJson(this.bulletRelPath(bullet.bullet_id));
|
|
179
|
+
const record = { ...bullet, ...learningLifecycle(bullet, previous, at), content: truncateContent(bullet.content), updated_at: at };
|
|
168
180
|
this.writeJson(this.bulletRelPath(record.bullet_id), record);
|
|
169
181
|
this.upsertIndex(record);
|
|
170
182
|
return record;
|
|
@@ -181,7 +193,11 @@ export class PlaybookRepository {
|
|
|
181
193
|
observed_count: input.provenance.source === "llm_reflector" ? 0 : 1,
|
|
182
194
|
// Evidence-free notes from every producer are retained but cannot be injected
|
|
183
195
|
// until evidence is attached through a curated path.
|
|
184
|
-
status: input.evidence_refs.length === 0 ? "quarantined" : "active",
|
|
196
|
+
status: input.evidence_refs.length === 0 ? "quarantined" : input.status ?? "active",
|
|
197
|
+
evidence_snapshots: input.evidence_snapshots,
|
|
198
|
+
label: input.label,
|
|
199
|
+
validation_checks: input.validation_checks,
|
|
200
|
+
acceptance_errors: input.acceptance_errors,
|
|
185
201
|
evidence_refs: input.evidence_refs.slice(0, 5),
|
|
186
202
|
provenance: input.provenance,
|
|
187
203
|
created_at: at,
|
|
@@ -200,6 +216,10 @@ export class PlaybookRepository {
|
|
|
200
216
|
return bullet && scopeMatches(bullet.scope, filter?.scope) ? [bullet] : [];
|
|
201
217
|
});
|
|
202
218
|
}
|
|
219
|
+
/** Pure listing for assignment/context selection; never migrates or repairs. */
|
|
220
|
+
listBulletsReadOnly(filter) {
|
|
221
|
+
return this.listBulletRelPaths().flatMap(rel => { const b = this.readJson(rel); return b?.bullet_id && (!filter?.status || b.status === filter.status) ? [b] : []; });
|
|
222
|
+
}
|
|
203
223
|
applyDeltaOps(ops, config = {}) {
|
|
204
224
|
const result = { added: 0, tagged: 0, refused: [] };
|
|
205
225
|
for (const op of ops) {
|
|
@@ -311,4 +331,40 @@ export function materializePlaybookMarkdown(workspaceRoot) {
|
|
|
311
331
|
writeFileSync(path, renderPlaybookMarkdown(repo), "utf8");
|
|
312
332
|
return path;
|
|
313
333
|
}
|
|
334
|
+
/** One existing-pack transaction; the synchronous repository edits an ephemeral
|
|
335
|
+
* buffer, never recursively taking the non-reentrant cross-process lease. */
|
|
336
|
+
export async function withPlaybookTransaction(root, apply) {
|
|
337
|
+
const { withStoreWriteCoordinator } = await import("../write-coordinator.js");
|
|
338
|
+
const { getWorkspaceStorePath } = await import("../store-snapshot.js");
|
|
339
|
+
const { openStore } = await import("../ace-packed-store.js");
|
|
340
|
+
const lock = storeExistsSync(root) ? getWorkspaceStorePath(root) : join(root, "agent-state/playbook/__index.json");
|
|
341
|
+
return withStoreWriteCoordinator(lock, async () => {
|
|
342
|
+
if (!storeExistsSync(root))
|
|
343
|
+
return apply(new PlaybookRepository(root));
|
|
344
|
+
const store = await openStore(getWorkspaceStorePath(root));
|
|
345
|
+
try {
|
|
346
|
+
const buffer = new Map();
|
|
347
|
+
for await (const key of store.list())
|
|
348
|
+
if (key.startsWith("state/artifacts/agent-state/playbook/") || key === "state/artifacts/agent-state/lessons.md") {
|
|
349
|
+
const value = await store.getBlob(key);
|
|
350
|
+
if (value !== undefined)
|
|
351
|
+
buffer.set(key.slice("state/artifacts/".length), value);
|
|
352
|
+
}
|
|
353
|
+
const prior = new Map(buffer);
|
|
354
|
+
const result = await apply(new PlaybookRepository(root, buffer));
|
|
355
|
+
for (const [rel, value] of buffer)
|
|
356
|
+
if (prior.get(rel) !== value)
|
|
357
|
+
await store.setBlob(operationalArtifactKey(rel), value);
|
|
358
|
+
await store.commit();
|
|
359
|
+
return result;
|
|
360
|
+
}
|
|
361
|
+
catch (error) {
|
|
362
|
+
store.discardPending();
|
|
363
|
+
throw error;
|
|
364
|
+
}
|
|
365
|
+
finally {
|
|
366
|
+
await store.close({ commit: false });
|
|
367
|
+
}
|
|
368
|
+
}, { operation_label: "host_playbook" });
|
|
369
|
+
}
|
|
314
370
|
//# sourceMappingURL=playbook-repository.js.map
|
|
@@ -6,20 +6,26 @@ import { AcePackedStore } from "../ace-packed-store.js";
|
|
|
6
6
|
export interface TodoNode {
|
|
7
7
|
id: string;
|
|
8
8
|
title: string;
|
|
9
|
-
status: "pending" | "in_progress" | "done" | "blocked" | "cancelled";
|
|
9
|
+
status: "pending" | "in_progress" | "done" | "blocked" | "gated" | "cancelled";
|
|
10
10
|
priority?: "high" | "medium" | "low";
|
|
11
11
|
assigned_to?: string;
|
|
12
12
|
depends_on?: string[];
|
|
13
13
|
created_at: number;
|
|
14
14
|
updated_at: number;
|
|
15
15
|
notes?: string;
|
|
16
|
+
section?: string;
|
|
17
|
+
source_line?: number;
|
|
18
|
+
step_ref?: {
|
|
19
|
+
goal_id: string;
|
|
20
|
+
step_id: string;
|
|
21
|
+
};
|
|
16
22
|
}
|
|
17
23
|
type TodoUpsertInput = Omit<TodoNode, "created_at" | "updated_at"> & Partial<Pick<TodoNode, "created_at">>;
|
|
18
24
|
export declare class TodoRepository {
|
|
19
25
|
private store;
|
|
20
26
|
constructor(store: AcePackedStore);
|
|
21
27
|
private key;
|
|
22
|
-
create(todo:
|
|
28
|
+
create(todo: TodoUpsertInput): Promise<TodoNode>;
|
|
23
29
|
get(id: string): Promise<TodoNode | undefined>;
|
|
24
30
|
update(id: string, patch: Partial<TodoNode>): Promise<TodoNode>;
|
|
25
31
|
list(filter?: {
|
|
@@ -14,7 +14,7 @@ export class TodoRepository {
|
|
|
14
14
|
}
|
|
15
15
|
async create(todo) {
|
|
16
16
|
const now = Date.now();
|
|
17
|
-
const record = { ...todo, created_at: now, updated_at: now };
|
|
17
|
+
const record = { ...todo, created_at: todo.created_at ?? now, updated_at: now };
|
|
18
18
|
await this.store.setJSON(this.key(todo.id), record);
|
|
19
19
|
await this.store.appendEntry({
|
|
20
20
|
kind: EntityKind.Todo,
|
|
@@ -13,7 +13,10 @@ export interface VericifyPost {
|
|
|
13
13
|
summary: string;
|
|
14
14
|
ts: number;
|
|
15
15
|
metadata?: Record<string, unknown>;
|
|
16
|
+
/** Exact imported record, including historical spelling and unknown fields. */
|
|
17
|
+
legacy_record?: Record<string, unknown>;
|
|
16
18
|
}
|
|
19
|
+
export declare function projectVericifyPost(post: VericifyPost): Record<string, unknown>;
|
|
17
20
|
export declare class VericifyRepository {
|
|
18
21
|
private store;
|
|
19
22
|
private onMutation?;
|
|
@@ -27,6 +30,7 @@ export declare class VericifyRepository {
|
|
|
27
30
|
agent_id?: string;
|
|
28
31
|
kind?: VericifyPost["kind"];
|
|
29
32
|
}): Promise<VericifyPost[]>;
|
|
33
|
+
importPost(original: Record<string, unknown>): Promise<VericifyPost>;
|
|
30
34
|
private _addToIndex;
|
|
31
35
|
}
|
|
32
36
|
//# sourceMappingURL=vericify-repository.d.ts.map
|
|
@@ -5,6 +5,21 @@
|
|
|
5
5
|
* Also triggers Vericify projection file writes on mutation.
|
|
6
6
|
*/
|
|
7
7
|
import { ContentSource, EntityKind } from "../types.js";
|
|
8
|
+
import { isDeepStrictEqual } from "node:util";
|
|
9
|
+
export function projectVericifyPost(post) {
|
|
10
|
+
if (post.legacy_record)
|
|
11
|
+
return { ...post.legacy_record };
|
|
12
|
+
return {
|
|
13
|
+
process_post_id: post.id, run_id: post.run_id, agent_id: post.agent_id,
|
|
14
|
+
kind: post.kind, summary: post.summary, timestamp: new Date(post.ts).toISOString(),
|
|
15
|
+
branch_id: typeof post.metadata?.branch_id === "string" ? post.metadata.branch_id : undefined,
|
|
16
|
+
lane_id: typeof post.metadata?.lane_id === "string" ? post.metadata.lane_id : undefined,
|
|
17
|
+
blocker_category: typeof post.metadata?.blocker_category === "string" ? post.metadata.blocker_category : undefined,
|
|
18
|
+
checkpoint_ref: typeof post.metadata?.checkpoint_ref === "string" ? post.metadata.checkpoint_ref : undefined,
|
|
19
|
+
tool_refs: Array.isArray(post.metadata?.tool_refs) ? post.metadata.tool_refs.filter((v) => typeof v === "string") : [],
|
|
20
|
+
evidence_refs: Array.isArray(post.metadata?.evidence_refs) ? post.metadata.evidence_refs.filter((v) => typeof v === "string") : [],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
8
23
|
const INDEX_KEY = "state/vericify/posts/index";
|
|
9
24
|
export class VericifyRepository {
|
|
10
25
|
store;
|
|
@@ -47,6 +62,37 @@ export class VericifyRepository {
|
|
|
47
62
|
}
|
|
48
63
|
return posts.sort((a, b) => a.ts - b.ts);
|
|
49
64
|
}
|
|
65
|
+
async importPost(original) {
|
|
66
|
+
const id = original.process_post_id ?? original.id;
|
|
67
|
+
const ts = typeof original.ts === "number" ? original.ts : Date.parse(String(original.timestamp ?? ""));
|
|
68
|
+
if (typeof id !== "string" || !id || id === "index" || !Number.isFinite(ts) ||
|
|
69
|
+
typeof original.run_id !== "string" || typeof original.agent_id !== "string" ||
|
|
70
|
+
typeof original.kind !== "string" || typeof original.summary !== "string") {
|
|
71
|
+
throw new Error("Historical post lacks a valid identity, timestamp or required fields");
|
|
72
|
+
}
|
|
73
|
+
const existing = await this.store.getJSON(this.key(id));
|
|
74
|
+
if (existing) {
|
|
75
|
+
// JSON roundtrip removes undefined optional projection properties.
|
|
76
|
+
const prior = existing.legacy_record ?? JSON.parse(JSON.stringify(projectVericifyPost(existing)));
|
|
77
|
+
if (!isDeepStrictEqual(prior, original))
|
|
78
|
+
throw new Error(`Historical post identity conflict: ${id}`);
|
|
79
|
+
await this._addToIndex(id);
|
|
80
|
+
return existing;
|
|
81
|
+
}
|
|
82
|
+
const metadata = {
|
|
83
|
+
...(original.metadata && typeof original.metadata === "object" && !Array.isArray(original.metadata) ? original.metadata : {}),
|
|
84
|
+
...Object.fromEntries(["branch_id", "lane_id", "blocker_category", "checkpoint_ref", "tool_refs", "evidence_refs"].filter((k) => k in original).map((k) => [k, original[k]])),
|
|
85
|
+
};
|
|
86
|
+
const record = {
|
|
87
|
+
id, ts, run_id: original.run_id, agent_id: original.agent_id,
|
|
88
|
+
kind: original.kind, summary: original.summary,
|
|
89
|
+
metadata, legacy_record: original,
|
|
90
|
+
};
|
|
91
|
+
await this.store.setJSON(this.key(id), record);
|
|
92
|
+
await this.store.appendEntry({ kind: EntityKind.VericifyPost, content_source: ContentSource.User, key: this.key(id), payload: record });
|
|
93
|
+
await this._addToIndex(id);
|
|
94
|
+
return record;
|
|
95
|
+
}
|
|
50
96
|
async _addToIndex(id) {
|
|
51
97
|
const index = await this.store.getJSON(INDEX_KEY) ?? [];
|
|
52
98
|
if (!index.includes(id)) {
|
|
@@ -16,6 +16,7 @@ export interface InstallResult {
|
|
|
16
16
|
skill: string;
|
|
17
17
|
files: number;
|
|
18
18
|
compacted: boolean;
|
|
19
|
+
skipped_files: string[];
|
|
19
20
|
}
|
|
20
21
|
export declare function installSkillPack(workspaceRoot: string, skillName: string): Promise<InstallResult>;
|
|
21
22
|
export declare function installAllSkills(workspaceRoot: string): Promise<InstallResult[]>;
|
|
@@ -16,6 +16,7 @@ import { existsSync } from "fs";
|
|
|
16
16
|
import { dirname, resolve } from "path";
|
|
17
17
|
import { fileURLToPath } from "url";
|
|
18
18
|
import { openStore } from "./ace-packed-store.js";
|
|
19
|
+
import { withStoreWriteCoordinator } from "./write-coordinator.js";
|
|
19
20
|
import { bakeSkillPack, listAvailableSkills } from "./knowledge-bake.js";
|
|
20
21
|
import { ensureCanonicalWorkspaceStore, resolveWorkspaceStorePath, } from "./workspace-store-paths.js";
|
|
21
22
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -40,24 +41,27 @@ export async function installSkillPack(workspaceRoot, skillName) {
|
|
|
40
41
|
if (!available.includes(skillName)) {
|
|
41
42
|
throw new Error(`Skill pack '${skillName}' not found. Available: ${available.join(", ")}`);
|
|
42
43
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
return withStoreWriteCoordinator(resolved.storePath, async () => {
|
|
45
|
+
const store = await openStore(resolved.storePath);
|
|
46
|
+
let compacted = false;
|
|
47
|
+
const skipped = [];
|
|
48
|
+
try {
|
|
49
|
+
const existing = await store.listSkills();
|
|
50
|
+
if (existing.includes(skillName)) {
|
|
51
|
+
console.log(`[skills-install] '${skillName}' already installed — reinstalling`);
|
|
52
|
+
}
|
|
53
|
+
const files = await bakeSkillPack(store, assetsRoot, skillName, { onSkip: (key) => skipped.push(key) });
|
|
54
|
+
await store.commit();
|
|
55
|
+
if (store.deadSpaceRatio > 0.5) {
|
|
56
|
+
await store.compact();
|
|
57
|
+
compacted = true;
|
|
58
|
+
}
|
|
59
|
+
return { skill: skillName, files, compacted, skipped_files: skipped };
|
|
49
60
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (store.deadSpaceRatio > 0.5) {
|
|
53
|
-
await store.compact();
|
|
54
|
-
compacted = true;
|
|
61
|
+
finally {
|
|
62
|
+
await store.close({ commit: false });
|
|
55
63
|
}
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
finally {
|
|
59
|
-
await store.close();
|
|
60
|
-
}
|
|
64
|
+
}, { operation_label: "installSkillPack" });
|
|
61
65
|
}
|
|
62
66
|
export async function installAllSkills(workspaceRoot) {
|
|
63
67
|
const assetsRoot = getAssetsRoot();
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { AcePackedStore } from "./ace-packed-store.js";
|
|
2
|
+
export interface SourceIdentity {
|
|
3
|
+
dev: number;
|
|
4
|
+
ino: number;
|
|
5
|
+
size: number;
|
|
6
|
+
mtimeMs: number;
|
|
7
|
+
ctimeMs: number;
|
|
8
|
+
}
|
|
9
|
+
export interface PreservedSource {
|
|
10
|
+
source_path: string;
|
|
11
|
+
sha256: string;
|
|
12
|
+
byte_length: number;
|
|
13
|
+
content_base64: string;
|
|
14
|
+
identity?: SourceIdentity;
|
|
15
|
+
}
|
|
16
|
+
export declare function sourceFromBytes(sourcePath: string, bytes: Buffer): PreservedSource;
|
|
17
|
+
/** Capture exact bytes without following a replaced final symlink or accepting an unstable read. */
|
|
18
|
+
export declare function captureWorkspaceSource(root: string, path: string): PreservedSource;
|
|
19
|
+
export declare function sourceUnchanged(root: string, path: string, source: PreservedSource): boolean;
|
|
20
|
+
export declare function preservedSourceKey(source: PreservedSource): string;
|
|
21
|
+
export declare function stagePreservedSource(store: AcePackedStore, source: PreservedSource): Promise<string>;
|
|
22
|
+
/** Uses the committed-file reader, never the writer's pending values. */
|
|
23
|
+
export declare function verifyPreservedSource(storePath: string, source: PreservedSource): void;
|
|
24
|
+
//# sourceMappingURL=source-preservation.d.ts.map
|