@nowcrew/daemon 0.6.18 → 0.6.20
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/dist/atomic-no-replace-rename.js +91 -0
- package/dist/control-plane-url.js +4 -2
- package/dist/directory-projection-publication.js +105 -0
- package/dist/directory-projection.js +20 -4
- package/dist/execution-journal.js +40 -4
- package/dist/execution-posix-stop-proof.js +82 -0
- package/dist/execution-runner.js +68 -8
- package/dist/local-executor.js +73 -52
- package/dist/machine-info.js +8 -5
- package/dist/project-skills/capability.js +109 -0
- package/dist/project-skills/controller-convergence.js +57 -0
- package/dist/project-skills/controller.js +80 -24
- package/dist/project-skills/initialized-reconciler.js +4 -4
- package/dist/project-skills/projection-state-domain.js +19 -2
- package/dist/project-skills/projection-state-store.js +3 -2
- package/dist/project-skills/projection-state-transaction.js +5 -1
- package/dist/project-skills/projection-state.js +1 -1
- package/dist/project-skills/reconciler.js +275 -102
- package/dist/project-skills/runtime-launch.js +102 -0
- package/dist/project-skills/runtime-root-bootstrap.js +47 -0
- package/dist/project-skills/runtime-root-domain.js +268 -0
- package/dist/project-skills/runtime-root-gc.js +293 -0
- package/dist/project-skills/runtime-root-lease-artifact.js +46 -0
- package/dist/project-skills/runtime-root-leases.js +487 -0
- package/dist/project-skills/runtime-root-source-identity.js +60 -0
- package/dist/project-skills/runtime-root-startup.js +49 -0
- package/dist/project-skills/runtime-root-state-artifact-domain.js +143 -0
- package/dist/project-skills/runtime-root-state-index.js +356 -0
- package/dist/project-skills/runtime-root-store.js +722 -0
- package/dist/project-skills/serve-capability.js +28 -0
- package/dist/project-skills/serve-startup.js +22 -0
- package/dist/project-skills/types.js +1 -0
- package/dist/provider-env.js +3 -0
- package/dist/runtimes/codex-home.js +50 -0
- package/dist/serve.js +58 -73
- package/dist/supervised-runtime.js +1 -5
- package/package.json +2 -2
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { resolveOrderedUniqueClaudeDirectories } from "../runtimes/claude.js";
|
|
3
|
+
import { ProjectProjectionError, } from "./reconciler.js";
|
|
4
|
+
const runtimeRootSecrets = (root) => Object.freeze([...new Set([
|
|
5
|
+
root.rootDirectory,
|
|
6
|
+
root.codexSkillRoot,
|
|
7
|
+
root.claudeAdditionalDirectory,
|
|
8
|
+
root.rootId,
|
|
9
|
+
].flatMap((value) => [
|
|
10
|
+
value,
|
|
11
|
+
value.replaceAll("\\", "/"),
|
|
12
|
+
value.replaceAll("/", "\\"),
|
|
13
|
+
]))].sort((left, right) => right.length - left.length));
|
|
14
|
+
export function redactProjectSkillRuntimeRootText(text, root) {
|
|
15
|
+
if (root === undefined)
|
|
16
|
+
return text;
|
|
17
|
+
return runtimeRootSecrets(root)
|
|
18
|
+
.reduce((redacted, secret) => redacted.replaceAll(secret, "[project-skill-root]"), text);
|
|
19
|
+
}
|
|
20
|
+
export function redactProjectSkillRuntimeRootError(error, root) {
|
|
21
|
+
if (!(error instanceof Error)) {
|
|
22
|
+
return typeof error === "string" ? redactProjectSkillRuntimeRootText(error, root) : error;
|
|
23
|
+
}
|
|
24
|
+
const message = redactProjectSkillRuntimeRootText(error.message, root);
|
|
25
|
+
if (message === error.message)
|
|
26
|
+
return error;
|
|
27
|
+
const redacted = new Error(message);
|
|
28
|
+
redacted.name = error.name;
|
|
29
|
+
return redacted;
|
|
30
|
+
}
|
|
31
|
+
/** Recursively redacts exact v2 root identities before Runtime output crosses daemon boundaries. */
|
|
32
|
+
export function redactProjectSkillRuntimeRootValue(value, root) {
|
|
33
|
+
if (root === undefined)
|
|
34
|
+
return value;
|
|
35
|
+
if (typeof value === "string")
|
|
36
|
+
return redactProjectSkillRuntimeRootText(value, root);
|
|
37
|
+
if (Array.isArray(value)) {
|
|
38
|
+
return value.map((item) => redactProjectSkillRuntimeRootValue(item, root));
|
|
39
|
+
}
|
|
40
|
+
if (typeof value === "object" && value !== null) {
|
|
41
|
+
return Object.fromEntries(Object.entries(value)
|
|
42
|
+
.map(([key, item]) => [key, redactProjectSkillRuntimeRootValue(item, root)]));
|
|
43
|
+
}
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
/** Maps one captured daemon-local root to the exact native Runtime registration seam. */
|
|
47
|
+
export function projectSkillRuntimeLaunchFacts(runtime, root) {
|
|
48
|
+
if (root === undefined)
|
|
49
|
+
return Object.freeze({});
|
|
50
|
+
if (runtime === "codex") {
|
|
51
|
+
return Object.freeze({ codexSkillRoot: root.codexSkillRoot });
|
|
52
|
+
}
|
|
53
|
+
if (runtime === "claude") {
|
|
54
|
+
return Object.freeze({ claudeAdditionalDirectory: root.claudeAdditionalDirectory });
|
|
55
|
+
}
|
|
56
|
+
throw new ProjectProjectionError("skill_projection_failed");
|
|
57
|
+
}
|
|
58
|
+
/** Builds Runtime-native arrays while keeping v1 shared roots separate from v2 exact roots. */
|
|
59
|
+
export async function projectSkillRuntimeDirectories(input) {
|
|
60
|
+
const facts = projectSkillRuntimeLaunchFacts(input.runtime, input.runtimeRoot);
|
|
61
|
+
const codexSkillRoots = input.runtime === "codex"
|
|
62
|
+
&& (input.runtimeRoot !== undefined || input.projectContext !== undefined)
|
|
63
|
+
? Object.freeze([
|
|
64
|
+
...(facts.codexSkillRoot === undefined
|
|
65
|
+
? input.projectSkillsPresent ? [join(input.agentRoot, ".agents", "skills")] : []
|
|
66
|
+
: [facts.codexSkillRoot]),
|
|
67
|
+
...(input.abilitySkillRoot === undefined ? [] : [input.abilitySkillRoot]),
|
|
68
|
+
])
|
|
69
|
+
: Object.freeze([]);
|
|
70
|
+
if (input.runtime !== "claude") {
|
|
71
|
+
return Object.freeze({ codexSkillRoots, claudeAdditionalDirectories: Object.freeze([]) });
|
|
72
|
+
}
|
|
73
|
+
if (input.runtimeRoot !== undefined) {
|
|
74
|
+
if (facts.claudeAdditionalDirectory === undefined) {
|
|
75
|
+
throw new ProjectProjectionError("skill_projection_failed");
|
|
76
|
+
}
|
|
77
|
+
return Object.freeze({
|
|
78
|
+
codexSkillRoots,
|
|
79
|
+
claudeAdditionalDirectories: await resolveOrderedUniqueClaudeDirectories([
|
|
80
|
+
...(input.projectContext?.secondary.map((project) => project.root) ?? []),
|
|
81
|
+
facts.claudeAdditionalDirectory,
|
|
82
|
+
...(input.abilitySkillRoot === undefined ? [] : [input.abilitySkillRoot]),
|
|
83
|
+
], input.projectContext?.primary === undefined ? [] : [input.projectContext.primary.root]),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const claudeAdditionalDirectories = input.projectContext === undefined
|
|
87
|
+
? !input.projectSkillsPresent && input.abilitySkillRoot === undefined
|
|
88
|
+
? Object.freeze([])
|
|
89
|
+
: await resolveOrderedUniqueClaudeDirectories([
|
|
90
|
+
join(input.agentRoot, ".crew", "claude-skills"),
|
|
91
|
+
input.agentRoot,
|
|
92
|
+
...(input.abilitySkillRoot === undefined ? [] : [input.abilitySkillRoot]),
|
|
93
|
+
])
|
|
94
|
+
: await resolveOrderedUniqueClaudeDirectories([
|
|
95
|
+
...input.projectContext.secondary.map((project) => project.root),
|
|
96
|
+
...(input.projectSkillsPresent
|
|
97
|
+
? [join(input.agentRoot, ".crew", "claude-skills")]
|
|
98
|
+
: []),
|
|
99
|
+
...(input.abilitySkillRoot === undefined ? [] : [input.abilitySkillRoot]),
|
|
100
|
+
], input.projectContext.primary === undefined ? [] : [input.projectContext.primary.root]);
|
|
101
|
+
return Object.freeze({ codexSkillRoots, claudeAdditionalDirectories });
|
|
102
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,268 @@
|
|
|
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
|
+
}
|