@nowcrew/daemon 0.6.16 → 0.6.18

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 (43) hide show
  1. package/dist/agent-ability/runtime-context.js +7 -1
  2. package/dist/atomic-private-write.js +54 -1
  3. package/dist/automatic-install-target.js +40 -11
  4. package/dist/console.js +9 -0
  5. package/dist/control-plane-url.js +2 -2
  6. package/dist/daemon-migration-controller.js +198 -0
  7. package/dist/daemon-migration-wiring.js +22 -0
  8. package/dist/daemon-update-eligibility.js +1 -1
  9. package/dist/directory-projection-identity.js +32 -0
  10. package/dist/directory-projection.js +922 -0
  11. package/dist/execution-protocol.js +78 -11
  12. package/dist/execution-runner.js +50 -2
  13. package/dist/i18n.js +1 -0
  14. package/dist/local-execution-prompt.js +57 -0
  15. package/dist/local-executor.js +99 -40
  16. package/dist/machine-info.js +45 -9
  17. package/dist/main.js +0 -0
  18. package/dist/normalize.js +5 -0
  19. package/dist/profile-layout.js +41 -0
  20. package/dist/project-skills/controller.js +74 -14
  21. package/dist/project-skills/execution-adapter.js +11 -0
  22. package/dist/project-skills/initialized-reconciler.js +20 -0
  23. package/dist/project-skills/projection-set-switch.js +419 -0
  24. package/dist/project-skills/projection-state-domain.js +153 -0
  25. package/dist/project-skills/projection-state-store.js +841 -0
  26. package/dist/project-skills/projection-state-transaction.js +318 -0
  27. package/dist/project-skills/projection-state.js +3 -0
  28. package/dist/project-skills/reconciler.js +299 -68
  29. package/dist/project-skills/runtime-warning.js +6 -0
  30. package/dist/project-skills/scanner.js +30 -1
  31. package/dist/project-skills/types.js +9 -0
  32. package/dist/project-workspaces/resolver.js +179 -0
  33. package/dist/project-workspaces/types.js +1 -0
  34. package/dist/prompt.js +40 -0
  35. package/dist/runtimes/claude.js +235 -4
  36. package/dist/runtimes/codex-app-server-runner.js +100 -25
  37. package/dist/runtimes/codex-contract.js +123 -0
  38. package/dist/runtimes/codex.js +2 -0
  39. package/dist/serve.js +31 -17
  40. package/dist/session.js +3 -0
  41. package/dist/supervised-runtime.js +12 -4
  42. package/dist/workspace.js +14 -5
  43. package/package.json +10 -9
@@ -0,0 +1,318 @@
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.parseAppliedProjectSkillManifest(manifest), options);
194
+ }
195
+ export async function prepareAppliedProjectSkillManifestRemoval(agentRoot, options = {}) {
196
+ return prepareManifestTransition(agentRoot, null, options);
197
+ }
198
+ export async function publishPreparedProjectSkillManifestUpdate(update, options = {}) {
199
+ if (await completedWithoutOperation(update, update.next, options))
200
+ return;
201
+ const context = await loadBoundUpdate(update, options);
202
+ const { operation } = context;
203
+ const existing = await store.readStableFile(context.manifestPath, store.MAX_MANIFEST_BYTES);
204
+ if (update.next !== null
205
+ && existing !== null
206
+ && store.snapshotMatchesBinding(existing, operation.intent.stage, true))
207
+ return;
208
+ if (operation.intent.previous === null) {
209
+ if (existing !== null || operation.previous !== null)
210
+ return store.pathUnmanaged();
211
+ }
212
+ else if (operation.previous === null) {
213
+ if (existing === null || !store.snapshotMatchesBinding(existing, operation.intent.previous, true)) {
214
+ return store.pathUnmanaged();
215
+ }
216
+ await claimPublicManifest(context, store.PREVIOUS_BASENAME, operation.intent.previous, undefined, options.afterCurrentClaimed);
217
+ }
218
+ else if (existing !== null) {
219
+ return store.pathUnmanaged();
220
+ }
221
+ const publishable = await store.loadOperation(operation.path);
222
+ if (update.next === null && publishable.published !== null) {
223
+ if (existing !== null)
224
+ return store.pathUnmanaged();
225
+ return;
226
+ }
227
+ const stagePath = join(operation.path, store.STAGE_BASENAME);
228
+ const stage = await store.readStableFile(stagePath, store.MAX_MANIFEST_BYTES);
229
+ if (!store.sameSnapshot(publishable.intentSnapshot, operation.intentSnapshot)
230
+ || stage === null
231
+ || !store.snapshotMatchesBinding(stage, operation.intent.stage, false))
232
+ return store.pathUnmanaged();
233
+ if (update.next === null) {
234
+ try {
235
+ await link(stagePath, context.manifestPath);
236
+ await context.syncDirectory(context.stateDirectory);
237
+ }
238
+ catch (error) {
239
+ if (!store.isExisting(error))
240
+ return store.pathUnmanaged();
241
+ }
242
+ const claim = await store.readStableFile(context.manifestPath, store.MAX_MANIFEST_BYTES);
243
+ if (claim === null || !store.snapshotMatchesBinding(claim, operation.intent.stage, true)) {
244
+ return store.pathUnmanaged();
245
+ }
246
+ await claimPublicManifest(context, store.PUBLISHED_BASENAME, operation.intent.stage, options.afterRemovalMarkerPublished === undefined
247
+ ? undefined
248
+ : () => options.afterRemovalMarkerPublished(context.manifestPath));
249
+ return;
250
+ }
251
+ try {
252
+ await link(stagePath, context.manifestPath);
253
+ await context.syncDirectory(context.stateDirectory);
254
+ }
255
+ catch (error) {
256
+ if (!store.isExisting(error))
257
+ return store.pathUnmanaged();
258
+ }
259
+ const published = await store.readStableFile(context.manifestPath, store.MAX_MANIFEST_BYTES);
260
+ if (published === null
261
+ || !store.snapshotMatchesBinding(published, operation.intent.stage, true)
262
+ || published.identity.dev !== stage.identity.dev
263
+ || published.identity.ino !== stage.identity.ino)
264
+ return store.pathUnmanaged();
265
+ }
266
+ export async function commitPreparedProjectSkillManifestUpdate(update, options = {}) {
267
+ if (await completedWithoutOperation(update, update.next, options))
268
+ return;
269
+ const context = await loadBoundUpdate(update, options);
270
+ const published = await store.readStableFile(context.manifestPath, store.MAX_MANIFEST_BYTES);
271
+ const removalPublished = update.next === null
272
+ && published === null
273
+ && context.operation.published !== null;
274
+ if (!removalPublished && (published === null
275
+ || !store.snapshotMatchesBinding(published, context.operation.intent.stage, true))) {
276
+ return store.pathUnmanaged();
277
+ }
278
+ await store.cleanupOperation(context.operation.path, context.syncDirectory, options);
279
+ }
280
+ export async function rollbackPreparedProjectSkillManifestUpdate(update, options = {}) {
281
+ if (await completedWithoutOperation(update, update.previous, options))
282
+ return;
283
+ let context = await loadBoundUpdate(update, options);
284
+ let current = await store.readStableFile(context.manifestPath, store.MAX_MANIFEST_BYTES);
285
+ if (current !== null && store.snapshotMatchesBinding(current, context.operation.intent.stage, true)) {
286
+ try {
287
+ await lstat(join(context.operation.path, store.PUBLISHED_BASENAME));
288
+ return store.pathUnmanaged();
289
+ }
290
+ catch (error) {
291
+ if (error.code !== "ENOENT")
292
+ return store.pathUnmanaged();
293
+ }
294
+ await claimPublicManifest(context, store.PUBLISHED_BASENAME, context.operation.intent.stage, options.afterRollbackFinalCheck === undefined
295
+ ? undefined
296
+ : () => options.afterRollbackFinalCheck(context.manifestPath), options.afterRollbackUnknownClaimed === undefined
297
+ ? undefined
298
+ : (claimedPath) => options.afterRollbackUnknownClaimed(claimedPath, context.manifestPath), options.afterRollbackRestoreSlotChecked === undefined
299
+ ? undefined
300
+ : (claimedPath) => options.afterRollbackRestoreSlotChecked(claimedPath, context.manifestPath));
301
+ context = await loadBoundUpdate(update, options);
302
+ if (context.operation.published === null)
303
+ return store.pathUnmanaged();
304
+ current = null;
305
+ }
306
+ const previousBinding = context.operation.intent.previous;
307
+ if (previousBinding === null) {
308
+ if (current !== null)
309
+ return store.pathUnmanaged();
310
+ }
311
+ else if (current === null) {
312
+ await store.restorePreviousNoClobber(context.operation, context.manifestPath, context.stateDirectory, context.syncDirectory);
313
+ }
314
+ else if (!store.snapshotMatchesBinding(current, previousBinding, true)) {
315
+ return store.pathUnmanaged();
316
+ }
317
+ await store.cleanupOperation(context.operation.path, context.syncDirectory, options);
318
+ }
@@ -0,0 +1,3 @@
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, rollbackPreparedProjectSkillManifestUpdate, } from "./projection-state-transaction.js";