@nowcrew/daemon 0.6.88-beta.7 → 0.6.88-beta.9

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.
Files changed (38) hide show
  1. package/README.md +14 -10
  2. package/dist/agent-memory/policy.js +3 -1
  3. package/dist/execution-protocol.js +1 -1
  4. package/dist/execution-runner.js +3 -2
  5. package/dist/local-executor.js +30 -9
  6. package/dist/native-thread-context.js +59 -0
  7. package/dist/prompt.js +15 -15
  8. package/dist/runner.js +14 -15
  9. package/dist/runtimes/claude-session-start-hook.js +24 -0
  10. package/dist/runtimes/claude-thread-runner.js +266 -0
  11. package/dist/runtimes/claude.js +23 -4
  12. package/dist/runtimes/codex-app-server-runner.js +43 -4
  13. package/dist/runtimes/kimi-acp-runner.js +6 -2
  14. package/dist/runtimes/opencode-runner.js +7 -1
  15. package/dist/serve.js +7 -8
  16. package/dist/session.js +4 -0
  17. package/dist/supervised-runtime.js +11 -16
  18. package/dist/thread-input-delivery.js +217 -0
  19. package/package.json +2 -2
  20. package/dist/project-skills/capability.js +0 -109
  21. package/dist/project-skills/controller-convergence.js +0 -57
  22. package/dist/project-skills/projection-set-switch.js +0 -419
  23. package/dist/project-skills/projection-state-domain.js +0 -170
  24. package/dist/project-skills/projection-state-store.js +0 -842
  25. package/dist/project-skills/projection-state-transaction.js +0 -322
  26. package/dist/project-skills/projection-state.js +0 -3
  27. package/dist/project-skills/runtime-root-bootstrap.js +0 -47
  28. package/dist/project-skills/runtime-root-domain.js +0 -268
  29. package/dist/project-skills/runtime-root-gc.js +0 -293
  30. package/dist/project-skills/runtime-root-lease-artifact.js +0 -46
  31. package/dist/project-skills/runtime-root-leases.js +0 -487
  32. package/dist/project-skills/runtime-root-source-identity.js +0 -60
  33. package/dist/project-skills/runtime-root-startup.js +0 -49
  34. package/dist/project-skills/runtime-root-state-artifact-domain.js +0 -143
  35. package/dist/project-skills/runtime-root-state-index.js +0 -356
  36. package/dist/project-skills/runtime-root-store.js +0 -722
  37. package/dist/project-skills/serve-capability.js +0 -28
  38. package/dist/project-skills/serve-startup.js +0 -37
@@ -1,322 +0,0 @@
1
- import { randomUUID } from "node:crypto";
2
- import { chmod, link, lstat, mkdir, readlink, rename, symlink } from "node:fs/promises";
3
- import { join } from "node:path";
4
- import { appliedProjectSkillManifestPath, projectSkillManifestStoreInternals as store, } from "./projection-state-store.js";
5
- const manifestsMatch = (left, right) => JSON.stringify(left) === JSON.stringify(right);
6
- export const projectSkillManifestUpdateRecord = (update) => Object.freeze({
7
- managedBy: "nowcrew-project-skills-v2-update",
8
- version: 1,
9
- operationId: update.operationId,
10
- previous: update.previous,
11
- next: update.next,
12
- });
13
- export const parseProjectSkillManifestUpdateRecord = (candidate) => {
14
- if (candidate === null || typeof candidate !== "object")
15
- return store.pathUnmanaged();
16
- const record = candidate;
17
- if (record.managedBy !== "nowcrew-project-skills-v2-update"
18
- || record.version !== 1
19
- || typeof record.operationId !== "string"
20
- || !store.ARTIFACT_ID.test(record.operationId)
21
- || !("previous" in record)
22
- || !("next" in record)
23
- || Object.keys(record).sort().join(",") !== "managedBy,next,operationId,previous,version") {
24
- return store.pathUnmanaged();
25
- }
26
- const previous = record.previous === null
27
- ? null
28
- : store.parseAppliedProjectSkillManifest(record.previous);
29
- const next = record.next === null ? null : store.parseAppliedProjectSkillManifest(record.next);
30
- return Object.freeze({
31
- managedBy: "nowcrew-project-skills-v2-update",
32
- version: 1,
33
- operationId: record.operationId,
34
- previous,
35
- next,
36
- });
37
- };
38
- export const preparedProjectSkillManifestUpdateFromRecord = (agentRoot, candidate) => {
39
- const record = parseProjectSkillManifestUpdateRecord(candidate);
40
- return Object.freeze({
41
- agentRoot,
42
- operationId: record.operationId,
43
- previous: record.previous,
44
- next: record.next,
45
- });
46
- };
47
- const stateContext = async (agentRoot, options, settle) => {
48
- const syncDirectory = store.projectionDirectorySync(options);
49
- await store.realOwnedDirectory(agentRoot, false);
50
- const stateDirectory = join(agentRoot, ".crew");
51
- if (!await store.realOwnedDirectory(stateDirectory, true)) {
52
- try {
53
- await mkdir(stateDirectory, { mode: 0o700 });
54
- }
55
- catch (error) {
56
- if (!store.isExisting(error))
57
- return store.pathUnmanaged();
58
- }
59
- await store.realOwnedDirectory(stateDirectory, false);
60
- }
61
- await chmod(stateDirectory, 0o700).catch(() => store.pathUnmanaged());
62
- const manifestPath = appliedProjectSkillManifestPath(agentRoot);
63
- if (settle) {
64
- await store.settleDiscardResidues(stateDirectory, syncDirectory);
65
- await store.settlePreparingResidues(stateDirectory, syncDirectory);
66
- await store.settleAnyExistingOperation(manifestPath, stateDirectory, syncDirectory);
67
- }
68
- return Object.freeze({ manifestPath, stateDirectory, syncDirectory });
69
- };
70
- const operationPath = (stateDirectory, operationId) => {
71
- if (!store.ARTIFACT_ID.test(operationId))
72
- return store.pathUnmanaged();
73
- return join(stateDirectory, `${store.OPERATION_PREFIX}${operationId}${store.OPERATION_SUFFIX}`);
74
- };
75
- const loadBoundUpdate = async (update, options) => {
76
- const context = await stateContext(update.agentRoot, options, false);
77
- const operation = await store.loadOperation(operationPath(context.stateDirectory, update.operationId));
78
- if (operation.intent.nonce !== update.operationId || operation.stage === null)
79
- return store.pathUnmanaged();
80
- const next = store.isAbsenceMarkerRaw(operation.intent.stage.content)
81
- ? null
82
- : store.parseManifestRaw(operation.intent.stage.content);
83
- const previous = operation.intent.previous === null
84
- ? null
85
- : store.parseManifestRaw(operation.intent.previous.content);
86
- if (!manifestsMatch(next, update.next) || !manifestsMatch(previous, update.previous)) {
87
- return store.pathUnmanaged();
88
- }
89
- return Object.freeze({ ...context, operation });
90
- };
91
- const completedWithoutOperation = async (update, expected, options) => {
92
- const context = await stateContext(update.agentRoot, options, false);
93
- const path = operationPath(context.stateDirectory, update.operationId);
94
- try {
95
- await lstat(path);
96
- return false;
97
- }
98
- catch (error) {
99
- if (error.code !== "ENOENT")
100
- return store.pathUnmanaged();
101
- }
102
- await store.settleDiscardResidues(context.stateDirectory, context.syncDirectory);
103
- const current = await store.readStableFile(context.manifestPath, store.MAX_MANIFEST_BYTES);
104
- const manifest = current === null ? null : store.parseManifestRaw(current.raw);
105
- if (!manifestsMatch(manifest, expected))
106
- return store.pathUnmanaged();
107
- return true;
108
- };
109
- const restoreUnknownClaimNoClobber = async (claimedPath, manifestPath, syncDirectory, stateDirectory, afterSlotChecked) => {
110
- const claimedIdentity = await lstat(claimedPath, { bigint: true }).catch(() => store.pathUnmanaged());
111
- if (claimedIdentity.isFile()) {
112
- try {
113
- await link(claimedPath, manifestPath);
114
- await syncDirectory(stateDirectory);
115
- }
116
- catch {
117
- return store.pathUnmanaged();
118
- }
119
- const restored = await lstat(manifestPath, { bigint: true }).catch(() => store.pathUnmanaged());
120
- if (restored.dev !== claimedIdentity.dev || restored.ino !== claimedIdentity.ino) {
121
- return store.pathUnmanaged();
122
- }
123
- return store.pathUnmanaged();
124
- }
125
- try {
126
- await lstat(manifestPath);
127
- return store.pathUnmanaged();
128
- }
129
- catch (error) {
130
- if (error.code !== "ENOENT")
131
- return store.pathUnmanaged();
132
- }
133
- await afterSlotChecked?.();
134
- if (!claimedIdentity.isSymbolicLink())
135
- return store.pathUnmanaged();
136
- const target = await readlink(claimedPath).catch(() => store.pathUnmanaged());
137
- const beforeRestore = await lstat(claimedPath, { bigint: true }).catch(() => store.pathUnmanaged());
138
- if (!beforeRestore.isSymbolicLink()
139
- || beforeRestore.dev !== claimedIdentity.dev
140
- || beforeRestore.ino !== claimedIdentity.ino) {
141
- return store.pathUnmanaged();
142
- }
143
- try {
144
- await symlink(target, manifestPath);
145
- await syncDirectory(stateDirectory);
146
- }
147
- catch {
148
- return store.pathUnmanaged();
149
- }
150
- const restored = await lstat(manifestPath, { bigint: true }).catch(() => store.pathUnmanaged());
151
- if (!restored.isSymbolicLink()
152
- || await readlink(manifestPath).catch(() => store.pathUnmanaged()) !== target) {
153
- return store.pathUnmanaged();
154
- }
155
- return store.pathUnmanaged();
156
- };
157
- const claimPublicManifest = async (context, destinationBasename, expected, beforeClaim, afterClaim, afterRestoreSlotChecked) => {
158
- const claimedPath = join(context.operation.path, destinationBasename);
159
- await beforeClaim?.();
160
- try {
161
- await rename(context.manifestPath, claimedPath);
162
- await context.syncDirectory(context.operation.path);
163
- await context.syncDirectory(context.stateDirectory);
164
- }
165
- catch {
166
- return store.pathUnmanaged();
167
- }
168
- await afterClaim?.(claimedPath);
169
- const claimed = await store.readStableFile(claimedPath, store.MAX_MANIFEST_BYTES).catch(() => restoreUnknownClaimNoClobber(claimedPath, context.manifestPath, context.syncDirectory, context.stateDirectory, afterRestoreSlotChecked === undefined ? undefined : () => afterRestoreSlotChecked(claimedPath)));
170
- if (claimed === null || !store.snapshotMatchesBinding(claimed, expected, true)) {
171
- return restoreUnknownClaimNoClobber(claimedPath, context.manifestPath, context.syncDirectory, context.stateDirectory, afterRestoreSlotChecked === undefined ? undefined : () => afterRestoreSlotChecked(claimedPath));
172
- }
173
- };
174
- const prepareManifestTransition = async (agentRoot, next, options = {}) => {
175
- const context = await stateContext(agentRoot, options, true);
176
- const current = await store.readStableFile(context.manifestPath, store.MAX_MANIFEST_BYTES);
177
- const previous = current === null ? null : store.parseManifestRaw(current.raw);
178
- const content = next === null ? store.ABSENCE_MARKER_RAW : `${JSON.stringify(next)}\n`;
179
- const operation = await store.createOperation(context.stateDirectory, current, content, options.randomId ?? randomUUID, context.syncDirectory, options.afterIntentDurableBeforeActivate);
180
- await options.afterStageDurable?.(join(operation.path, store.STAGE_BASENAME));
181
- const reloaded = await store.loadOperation(operation.path);
182
- const observed = await store.readStableFile(context.manifestPath, store.MAX_MANIFEST_BYTES);
183
- if (!store.sameSnapshot(reloaded.intentSnapshot, operation.intentSnapshot)
184
- || reloaded.stage === null
185
- || !store.snapshotMatchesBinding(reloaded.stage, operation.intent.stage, false)
186
- || (current === null ? observed !== null : observed === null || !store.sameSnapshot(current, observed))) {
187
- await store.cleanupOperation(operation.path, context.syncDirectory);
188
- return store.pathUnmanaged();
189
- }
190
- return Object.freeze({ agentRoot, operationId: operation.intent.nonce, previous, next });
191
- };
192
- export async function prepareAppliedProjectSkillManifestUpdate(agentRoot, manifest, options = {}) {
193
- return prepareManifestTransition(agentRoot, store.parsePublishableAppliedProjectSkillManifest(manifest), options);
194
- }
195
- export async function prepareAppliedProjectSkillManifestRemoval(agentRoot, options = {}) {
196
- return prepareManifestTransition(agentRoot, null, options);
197
- }
198
- /** Settles a durable standalone applied-manifest operation before current-state selection. */
199
- export async function recoverAppliedProjectSkillManifestUpdates(agentRoot, options = {}) {
200
- await stateContext(agentRoot, options, true);
201
- }
202
- export async function publishPreparedProjectSkillManifestUpdate(update, options = {}) {
203
- if (await completedWithoutOperation(update, update.next, options))
204
- return;
205
- const context = await loadBoundUpdate(update, options);
206
- const { operation } = context;
207
- const existing = await store.readStableFile(context.manifestPath, store.MAX_MANIFEST_BYTES);
208
- if (update.next !== null
209
- && existing !== null
210
- && store.snapshotMatchesBinding(existing, operation.intent.stage, true))
211
- return;
212
- if (operation.intent.previous === null) {
213
- if (existing !== null || operation.previous !== null)
214
- return store.pathUnmanaged();
215
- }
216
- else if (operation.previous === null) {
217
- if (existing === null || !store.snapshotMatchesBinding(existing, operation.intent.previous, true)) {
218
- return store.pathUnmanaged();
219
- }
220
- await claimPublicManifest(context, store.PREVIOUS_BASENAME, operation.intent.previous, undefined, options.afterCurrentClaimed);
221
- }
222
- else if (existing !== null) {
223
- return store.pathUnmanaged();
224
- }
225
- const publishable = await store.loadOperation(operation.path);
226
- if (update.next === null && publishable.published !== null) {
227
- if (existing !== null)
228
- return store.pathUnmanaged();
229
- return;
230
- }
231
- const stagePath = join(operation.path, store.STAGE_BASENAME);
232
- const stage = await store.readStableFile(stagePath, store.MAX_MANIFEST_BYTES);
233
- if (!store.sameSnapshot(publishable.intentSnapshot, operation.intentSnapshot)
234
- || stage === null
235
- || !store.snapshotMatchesBinding(stage, operation.intent.stage, false))
236
- return store.pathUnmanaged();
237
- if (update.next === null) {
238
- try {
239
- await link(stagePath, context.manifestPath);
240
- await context.syncDirectory(context.stateDirectory);
241
- }
242
- catch (error) {
243
- if (!store.isExisting(error))
244
- return store.pathUnmanaged();
245
- }
246
- const claim = await store.readStableFile(context.manifestPath, store.MAX_MANIFEST_BYTES);
247
- if (claim === null || !store.snapshotMatchesBinding(claim, operation.intent.stage, true)) {
248
- return store.pathUnmanaged();
249
- }
250
- await claimPublicManifest(context, store.PUBLISHED_BASENAME, operation.intent.stage, options.afterRemovalMarkerPublished === undefined
251
- ? undefined
252
- : () => options.afterRemovalMarkerPublished(context.manifestPath));
253
- return;
254
- }
255
- try {
256
- await link(stagePath, context.manifestPath);
257
- await context.syncDirectory(context.stateDirectory);
258
- }
259
- catch (error) {
260
- if (!store.isExisting(error))
261
- return store.pathUnmanaged();
262
- }
263
- const published = await store.readStableFile(context.manifestPath, store.MAX_MANIFEST_BYTES);
264
- if (published === null
265
- || !store.snapshotMatchesBinding(published, operation.intent.stage, true)
266
- || published.identity.dev !== stage.identity.dev
267
- || published.identity.ino !== stage.identity.ino)
268
- return store.pathUnmanaged();
269
- }
270
- export async function commitPreparedProjectSkillManifestUpdate(update, options = {}) {
271
- if (await completedWithoutOperation(update, update.next, options))
272
- return;
273
- const context = await loadBoundUpdate(update, options);
274
- const published = await store.readStableFile(context.manifestPath, store.MAX_MANIFEST_BYTES);
275
- const removalPublished = update.next === null
276
- && published === null
277
- && context.operation.published !== null;
278
- if (!removalPublished && (published === null
279
- || !store.snapshotMatchesBinding(published, context.operation.intent.stage, true))) {
280
- return store.pathUnmanaged();
281
- }
282
- await store.cleanupOperation(context.operation.path, context.syncDirectory, options);
283
- }
284
- export async function rollbackPreparedProjectSkillManifestUpdate(update, options = {}) {
285
- if (await completedWithoutOperation(update, update.previous, options))
286
- return;
287
- let context = await loadBoundUpdate(update, options);
288
- let current = await store.readStableFile(context.manifestPath, store.MAX_MANIFEST_BYTES);
289
- if (current !== null && store.snapshotMatchesBinding(current, context.operation.intent.stage, true)) {
290
- try {
291
- await lstat(join(context.operation.path, store.PUBLISHED_BASENAME));
292
- return store.pathUnmanaged();
293
- }
294
- catch (error) {
295
- if (error.code !== "ENOENT")
296
- return store.pathUnmanaged();
297
- }
298
- await claimPublicManifest(context, store.PUBLISHED_BASENAME, context.operation.intent.stage, options.afterRollbackFinalCheck === undefined
299
- ? undefined
300
- : () => options.afterRollbackFinalCheck(context.manifestPath), options.afterRollbackUnknownClaimed === undefined
301
- ? undefined
302
- : (claimedPath) => options.afterRollbackUnknownClaimed(claimedPath, context.manifestPath), options.afterRollbackRestoreSlotChecked === undefined
303
- ? undefined
304
- : (claimedPath) => options.afterRollbackRestoreSlotChecked(claimedPath, context.manifestPath));
305
- context = await loadBoundUpdate(update, options);
306
- if (context.operation.published === null)
307
- return store.pathUnmanaged();
308
- current = null;
309
- }
310
- const previousBinding = context.operation.intent.previous;
311
- if (previousBinding === null) {
312
- if (current !== null)
313
- return store.pathUnmanaged();
314
- }
315
- else if (current === null) {
316
- await store.restorePreviousNoClobber(context.operation, context.manifestPath, context.stateDirectory, context.syncDirectory);
317
- }
318
- else if (!store.snapshotMatchesBinding(current, previousBinding, true)) {
319
- return store.pathUnmanaged();
320
- }
321
- await store.cleanupOperation(context.operation.path, context.syncDirectory, options);
322
- }
@@ -1,3 +0,0 @@
1
- export { computeProjectSkillBindingDigest, computeProjectSkillResolutionDigest, createAppliedProjectSkillManifest, normalizeProjectSkillResolutionRecords, ProjectSkillProjectionStateError, } from "./projection-state-domain.js";
2
- export { appliedProjectSkillManifestPath, readAppliedProjectSkillManifest, writeAppliedProjectSkillManifest, } from "./projection-state-store.js";
3
- export { commitPreparedProjectSkillManifestUpdate, parseProjectSkillManifestUpdateRecord, prepareAppliedProjectSkillManifestRemoval, prepareAppliedProjectSkillManifestUpdate, preparedProjectSkillManifestUpdateFromRecord, projectSkillManifestUpdateRecord, publishPreparedProjectSkillManifestUpdate, recoverAppliedProjectSkillManifestUpdates, rollbackPreparedProjectSkillManifestUpdate, } from "./projection-state-transaction.js";
@@ -1,47 +0,0 @@
1
- import { ProjectSkillRuntimeStoreError } from "./runtime-root-domain.js";
2
- /**
3
- * Generic startup hard gate. The callback is the only place a journal owner may be constructed or
4
- * initialized, and is unreachable until every durable lease inventory has populated the synchronous
5
- * retention snapshot. Task 9 wires this gate into `serve`; Task 5 deliberately does not advertise v2.
6
- */
7
- export async function initializeAfterProjectSkillLeaseProtection(input) {
8
- const protectedExecutionIds = new Set();
9
- for (const agentRoot of input.agentRoots) {
10
- for (const executionId of await input.leases.protectedExecutionIds(agentRoot)) {
11
- protectedExecutionIds.add(executionId);
12
- }
13
- }
14
- return input.initialize(protectedExecutionIds);
15
- }
16
- /**
17
- * Runs only after execution-journal restart reconciliation has settled. A lease without a terminal
18
- * journal fact remains durable and prevents the caller from marking Project Skill v2 ready.
19
- */
20
- export async function recoverProjectSkillRuntimeRoots(input) {
21
- for (const agentRoot of input.agentRoots) {
22
- await input.roots.recover(agentRoot);
23
- let unresolvedLease = false;
24
- await input.leases.recover(agentRoot, async (executionId) => {
25
- const entry = await input.journal.get(executionId);
26
- const releasable = entry?.state === "completed" || entry?.state === "interrupted";
27
- if (!releasable)
28
- unresolvedLease = true;
29
- return releasable;
30
- });
31
- if (unresolvedLease) {
32
- throw new ProjectSkillRuntimeStoreError("skill_projection_snapshot_corrupt");
33
- }
34
- }
35
- await input.afterLeaseRecovery?.();
36
- for (const agentRoot of input.agentRoots) {
37
- if (input.gc !== undefined && input.leases.list !== undefined && input.currentRootId !== undefined) {
38
- const leased = await input.leases.list(agentRoot);
39
- const currentRootId = await input.currentRootId(agentRoot);
40
- await input.gc.collect(agentRoot, {
41
- currentRootId,
42
- leasedRootIds: leased.map(({ rootId }) => rootId),
43
- keepHistory: 2,
44
- }).catch(() => undefined);
45
- }
46
- }
47
- }
@@ -1,268 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import { z } from "zod";
3
- import { compareProjectSkillRefs, isProjectId, isProjectSkillName, MAX_AGENT_PROJECT_SKILL_BINDINGS, MAX_PROJECT_ID_LENGTH, MAX_PROJECT_SKILL_NAME_LENGTH, } from "./types.js";
4
- const RUNTIME_ROOT_MANAGED_BY = "nowcrew-project-skill-runtime-root";
5
- const RUNTIME_STORE_MANAGED_BY = "nowcrew-project-skill-runtime-store";
6
- const RUNTIME_LEASE_MANAGED_BY = "nowcrew-project-skill-runtime-lease";
7
- const DIGEST = /^sha256:[a-f0-9]{64}$/u;
8
- const DECIMAL_BIGINT = /^(?:0|[1-9][0-9]*)$/u;
9
- const PATH_FREE_IDENTITY = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/u;
10
- const CANONICAL_ROOT_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u;
11
- const MAX_LOCAL_IDENTITY_LENGTH = 512;
12
- const MAX_PUBLISHED_SEQUENCE = Number.MAX_SAFE_INTEGER - 1;
13
- /** Deployment algorithm/layout revision. This is deliberately not a source-content hash. */
14
- export const PROJECT_SKILL_RUNTIME_MATERIALIZATION_REVISION = 1;
15
- export class ProjectSkillRuntimeStoreError extends Error {
16
- code;
17
- constructor(code) {
18
- super(code);
19
- this.code = code;
20
- this.name = "ProjectSkillRuntimeStoreError";
21
- }
22
- }
23
- const corrupt = () => {
24
- throw new ProjectSkillRuntimeStoreError("skill_projection_snapshot_corrupt");
25
- };
26
- const unmanaged = () => {
27
- throw new ProjectSkillRuntimeStoreError("skill_projection_runtime_root_unmanaged");
28
- };
29
- const SafeSequenceSchema = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
30
- const PublishedSequenceSchema = SafeSequenceSchema.max(MAX_PUBLISHED_SEQUENCE);
31
- const PositiveMaterializationRevisionSchema = z.number().int().positive().max(Number.MAX_SAFE_INTEGER);
32
- export const isCanonicalProjectSkillRuntimeRootId = (value) => CANONICAL_ROOT_ID.test(value);
33
- const RootIdSchema = z.string().refine(isCanonicalProjectSkillRuntimeRootId);
34
- const DigestSchema = z.string().regex(DIGEST);
35
- const DirectoryIdentitySchema = z.object({
36
- dev: z.string().regex(DECIMAL_BIGINT),
37
- ino: z.string().regex(DECIMAL_BIGINT),
38
- birthtimeNs: z.string().regex(DECIMAL_BIGINT),
39
- }).strict();
40
- const ProjectionModeSchema = z.object({
41
- projectId: z.string().min(1).max(MAX_PROJECT_ID_LENGTH),
42
- skillName: z.string().min(1).max(MAX_PROJECT_SKILL_NAME_LENGTH),
43
- mode: z.enum(["symlink", "junction", "copy", "missing"]),
44
- }).strict();
45
- const RuntimeRootManifestSchema = z.object({
46
- managedBy: z.literal(RUNTIME_ROOT_MANAGED_BY),
47
- version: z.literal(1),
48
- rootId: RootIdSchema,
49
- publishedSequence: PublishedSequenceSchema,
50
- materializationRevision: PositiveMaterializationRevisionSchema,
51
- directoryIdentity: DirectoryIdentitySchema,
52
- bindingDigest: DigestSchema,
53
- resolutionDigest: DigestSchema,
54
- projectionModes: z.array(ProjectionModeSchema).max(MAX_AGENT_PROJECT_SKILL_BINDINGS),
55
- }).strict();
56
- const RuntimeRootManifestInputSchema = RuntimeRootManifestSchema
57
- .omit({ managedBy: true, version: true, materializationRevision: true })
58
- .partial({ publishedSequence: true, directoryIdentity: true });
59
- const RuntimeRootRecordSchema = z.object({
60
- rootId: RootIdSchema,
61
- publishedSequence: PublishedSequenceSchema,
62
- materializationRevision: PositiveMaterializationRevisionSchema,
63
- directoryIdentity: DirectoryIdentitySchema,
64
- bindingDigest: DigestSchema,
65
- resolutionDigest: DigestSchema,
66
- }).strict();
67
- const RuntimeStoreStateSchema = z.object({
68
- managedBy: z.literal(RUNTIME_STORE_MANAGED_BY),
69
- version: z.literal(1),
70
- nextSequence: SafeSequenceSchema,
71
- roots: z.array(RuntimeRootRecordSchema),
72
- }).strict();
73
- const RuntimeStoreStateInputSchema = RuntimeStoreStateSchema.omit({ managedBy: true, version: true });
74
- const PathFreeIdentitySchema = z.string()
75
- .min(1)
76
- .max(MAX_LOCAL_IDENTITY_LENGTH)
77
- .regex(PATH_FREE_IDENTITY);
78
- const RuntimeLeaseRecordSchema = z.object({
79
- managedBy: z.literal(RUNTIME_LEASE_MANAGED_BY),
80
- version: z.literal(1),
81
- executionId: PathFreeIdentitySchema,
82
- rootId: RootIdSchema,
83
- nonce: PathFreeIdentitySchema,
84
- }).strict();
85
- const RuntimeLeaseRecordInputSchema = RuntimeLeaseRecordSchema.omit({ managedBy: true, version: true });
86
- const immutableDirectoryIdentity = (identity) => Object.freeze({
87
- dev: identity.dev,
88
- ino: identity.ino,
89
- birthtimeNs: identity.birthtimeNs,
90
- });
91
- const sameProjectionRef = (left, right) => left.projectId === right.projectId && left.skillName === right.skillName;
92
- const immutableProjectionMode = (projection) => Object.freeze({
93
- projectId: projection.projectId,
94
- skillName: projection.skillName,
95
- mode: projection.mode,
96
- });
97
- const canonicalProjectionModes = (modes) => {
98
- const seen = new Set();
99
- const canonical = modes.map((mode) => {
100
- if (!isProjectId(mode.projectId) || !isProjectSkillName(mode.skillName))
101
- return corrupt();
102
- const key = `${mode.projectId}\0${mode.skillName}`;
103
- if (seen.has(key))
104
- return corrupt();
105
- seen.add(key);
106
- return immutableProjectionMode(mode);
107
- }).sort(compareProjectSkillRefs);
108
- return Object.freeze(canonical);
109
- };
110
- const requireCanonicalProjectionModes = (modes) => {
111
- const canonical = canonicalProjectionModes(modes);
112
- if (canonical.some((mode, index) => {
113
- const input = modes[index];
114
- return input === undefined || !sameProjectionRef(mode, input) || mode.mode !== input.mode;
115
- }))
116
- return corrupt();
117
- return canonical;
118
- };
119
- const immutableRootRecord = (record) => Object.freeze({
120
- rootId: record.rootId,
121
- publishedSequence: record.publishedSequence,
122
- materializationRevision: record.materializationRevision,
123
- directoryIdentity: immutableDirectoryIdentity(record.directoryIdentity),
124
- bindingDigest: record.bindingDigest,
125
- resolutionDigest: record.resolutionDigest,
126
- });
127
- const compareRootRecords = (left, right) => left.publishedSequence - right.publishedSequence
128
- || (left.rootId < right.rootId ? -1 : left.rootId > right.rootId ? 1 : 0);
129
- const canonicalRootRecords = (records) => {
130
- const rootIds = new Set();
131
- const sequences = new Set();
132
- const canonical = records.map((record) => {
133
- const parsed = RuntimeRootRecordSchema.safeParse(record);
134
- if (!parsed.success)
135
- return corrupt();
136
- if (rootIds.has(parsed.data.rootId) || sequences.has(parsed.data.publishedSequence))
137
- return corrupt();
138
- rootIds.add(parsed.data.rootId);
139
- sequences.add(parsed.data.publishedSequence);
140
- return immutableRootRecord(parsed.data);
141
- }).sort(compareRootRecords);
142
- return Object.freeze(canonical);
143
- };
144
- const requireCanonicalRootRecords = (records) => {
145
- const canonical = canonicalRootRecords(records);
146
- if (canonical.some((record, index) => {
147
- const input = records[index];
148
- return input === undefined
149
- || record.rootId !== input.rootId
150
- || record.publishedSequence !== input.publishedSequence;
151
- }))
152
- return corrupt();
153
- return canonical;
154
- };
155
- const requireNextSequence = (nextSequence, roots) => {
156
- const latest = roots.at(-1);
157
- if (latest !== undefined && latest.publishedSequence >= nextSequence)
158
- corrupt();
159
- };
160
- const rejectUnknownOwner = (candidate, expected) => {
161
- if (candidate && typeof candidate === "object" && "managedBy" in candidate
162
- && candidate.managedBy !== expected)
163
- unmanaged();
164
- };
165
- export function createProjectSkillRuntimeRootManifest(input) {
166
- const parsedInput = RuntimeRootManifestInputSchema.safeParse(input);
167
- if (!parsedInput.success)
168
- return corrupt();
169
- const candidate = RuntimeRootManifestSchema.safeParse({
170
- managedBy: RUNTIME_ROOT_MANAGED_BY,
171
- version: 1,
172
- rootId: parsedInput.data.rootId,
173
- publishedSequence: parsedInput.data.publishedSequence ?? 0,
174
- materializationRevision: PROJECT_SKILL_RUNTIME_MATERIALIZATION_REVISION,
175
- directoryIdentity: parsedInput.data.directoryIdentity ?? { dev: "0", ino: "0", birthtimeNs: "0" },
176
- bindingDigest: parsedInput.data.bindingDigest,
177
- resolutionDigest: parsedInput.data.resolutionDigest,
178
- projectionModes: parsedInput.data.projectionModes,
179
- });
180
- if (!candidate.success)
181
- return corrupt();
182
- return Object.freeze({
183
- ...candidate.data,
184
- directoryIdentity: immutableDirectoryIdentity(candidate.data.directoryIdentity),
185
- projectionModes: canonicalProjectionModes(candidate.data.projectionModes),
186
- });
187
- }
188
- export function parseProjectSkillRuntimeRootManifest(candidate) {
189
- rejectUnknownOwner(candidate, RUNTIME_ROOT_MANAGED_BY);
190
- const parsed = RuntimeRootManifestSchema.safeParse(candidate);
191
- if (!parsed.success)
192
- return corrupt();
193
- return Object.freeze({
194
- ...parsed.data,
195
- directoryIdentity: immutableDirectoryIdentity(parsed.data.directoryIdentity),
196
- projectionModes: requireCanonicalProjectionModes(parsed.data.projectionModes),
197
- });
198
- }
199
- export function createProjectSkillRuntimeRootRecord(input) {
200
- const parsed = RuntimeRootRecordSchema.safeParse(input);
201
- if (!parsed.success)
202
- return corrupt();
203
- return immutableRootRecord(parsed.data);
204
- }
205
- export function parseProjectSkillRuntimeRootRecord(candidate) {
206
- const parsed = RuntimeRootRecordSchema.safeParse(candidate);
207
- if (!parsed.success)
208
- return corrupt();
209
- return immutableRootRecord(parsed.data);
210
- }
211
- export function createProjectSkillRuntimeStoreState(input) {
212
- const parsedInput = RuntimeStoreStateInputSchema.safeParse(input);
213
- if (!parsedInput.success)
214
- return corrupt();
215
- const parsed = RuntimeStoreStateSchema.safeParse({
216
- managedBy: RUNTIME_STORE_MANAGED_BY,
217
- version: 1,
218
- nextSequence: parsedInput.data.nextSequence,
219
- roots: parsedInput.data.roots,
220
- });
221
- if (!parsed.success)
222
- return corrupt();
223
- const roots = canonicalRootRecords(parsed.data.roots);
224
- requireNextSequence(parsed.data.nextSequence, roots);
225
- return Object.freeze({
226
- managedBy: RUNTIME_STORE_MANAGED_BY,
227
- version: 1,
228
- nextSequence: parsed.data.nextSequence,
229
- roots,
230
- });
231
- }
232
- export function parseProjectSkillRuntimeStoreState(candidate) {
233
- rejectUnknownOwner(candidate, RUNTIME_STORE_MANAGED_BY);
234
- const parsed = RuntimeStoreStateSchema.safeParse(candidate);
235
- if (!parsed.success)
236
- return corrupt();
237
- const roots = requireCanonicalRootRecords(parsed.data.roots);
238
- requireNextSequence(parsed.data.nextSequence, roots);
239
- return Object.freeze({
240
- managedBy: RUNTIME_STORE_MANAGED_BY,
241
- version: 1,
242
- nextSequence: parsed.data.nextSequence,
243
- roots,
244
- });
245
- }
246
- export function createProjectSkillRuntimeLeaseRecord(input) {
247
- const parsedInput = RuntimeLeaseRecordInputSchema.safeParse(input);
248
- if (!parsedInput.success)
249
- return corrupt();
250
- const parsed = RuntimeLeaseRecordSchema.safeParse({
251
- managedBy: RUNTIME_LEASE_MANAGED_BY,
252
- version: 1,
253
- ...parsedInput.data,
254
- });
255
- if (!parsed.success)
256
- return corrupt();
257
- return Object.freeze(parsed.data);
258
- }
259
- export function parseProjectSkillRuntimeLeaseRecord(candidate) {
260
- rejectUnknownOwner(candidate, RUNTIME_LEASE_MANAGED_BY);
261
- const parsed = RuntimeLeaseRecordSchema.safeParse(candidate);
262
- if (!parsed.success)
263
- return corrupt();
264
- return Object.freeze(parsed.data);
265
- }
266
- export function projectSkillRuntimeLeaseKey(executionId) {
267
- return createHash("sha256").update(executionId, "utf8").digest("hex");
268
- }