@koed-labs/server 0.0.0-stage → 0.10.3

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 (56) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +64 -2
  3. package/bin/koed.js +7 -0
  4. package/package.json +26 -4
  5. package/third-party-notices.json +92 -0
  6. package/vendor/chunk-2BWTLF7A.js +13883 -0
  7. package/vendor/chunk-2DA7EFZV.js +924 -0
  8. package/vendor/chunk-2S3OGPUC.js +58 -0
  9. package/vendor/chunk-473OA62O.js +26827 -0
  10. package/vendor/chunk-6JRWGOQG.js +236 -0
  11. package/vendor/chunk-7NOQSX4T.js +14 -0
  12. package/vendor/chunk-7NXKPDF3.js +1586 -0
  13. package/vendor/chunk-A4NKL2PK.js +153 -0
  14. package/vendor/chunk-A6WMU2GG.js +48 -0
  15. package/vendor/chunk-AFLKCQHF.js +73 -0
  16. package/vendor/chunk-BTS4ZTF3.js +43 -0
  17. package/vendor/chunk-C3N4N5HR.js +108 -0
  18. package/vendor/chunk-DXTAWHY3.js +25 -0
  19. package/vendor/chunk-G4IIVVJO.js +56 -0
  20. package/vendor/chunk-GELDEJJ2.js +4337 -0
  21. package/vendor/chunk-HFM6ROJL.js +188 -0
  22. package/vendor/chunk-HK2H3MVE.js +328 -0
  23. package/vendor/chunk-HZJK5RWC.js +5088 -0
  24. package/vendor/chunk-J2L726BC.js +2497 -0
  25. package/vendor/chunk-JBGD4JLR.js +3779 -0
  26. package/vendor/chunk-JJNLH5GA.js +2470 -0
  27. package/vendor/chunk-JKOG52PE.js +128 -0
  28. package/vendor/chunk-K2EIFEQF.js +89 -0
  29. package/vendor/chunk-KUIWH33N.js +16 -0
  30. package/vendor/chunk-NEWIOOM6.js +34 -0
  31. package/vendor/chunk-NM5NXCVM.js +2404 -0
  32. package/vendor/chunk-PT3AUPGE.js +459 -0
  33. package/vendor/chunk-PY5LYLV7.js +143 -0
  34. package/vendor/chunk-QIIKMG3M.js +103 -0
  35. package/vendor/chunk-QT24SAW6.js +110 -0
  36. package/vendor/chunk-RVYJKKWA.js +22 -0
  37. package/vendor/chunk-SKVYP7NY.js +1647 -0
  38. package/vendor/chunk-TSRPHKAC.js +780 -0
  39. package/vendor/chunk-UI5RLBKQ.js +30 -0
  40. package/vendor/chunk-VPC5NLZG.js +259 -0
  41. package/vendor/chunk-W2HNI6AA.js +75 -0
  42. package/vendor/chunk-X6M525ZJ.js +20 -0
  43. package/vendor/chunk-XIZVLPHZ.js +18 -0
  44. package/vendor/chunk-XNFVSVBS.js +242 -0
  45. package/vendor/chunk-YCDEMYY6.js +2076 -0
  46. package/vendor/chunk-YJ6XUZT6.js +292 -0
  47. package/vendor/chunk-YJWREXN6.js +26020 -0
  48. package/vendor/chunk-YK4F4VY2.js +173 -0
  49. package/vendor/chunk-YOFI4PCH.js +36 -0
  50. package/vendor/chunk-ZUGNCQZE.js +247 -0
  51. package/vendor/chunk-ZXX4ZNJY.js +21 -0
  52. package/vendor/cli.js +7 -0
  53. package/vendor/component-manifest-catalog.js +8 -0
  54. package/vendor/control-plane.js +23 -0
  55. package/vendor/package.json +1 -0
  56. package/vendor/privacy-service-bootstrap.js +6 -0
@@ -0,0 +1,780 @@
1
+ import { createRequire as createKoedRequire } from "node:module"; const require = createKoedRequire(import.meta.url);
2
+ import {
3
+ resolveActiveIntegrationApiToken
4
+ } from "./chunk-QT24SAW6.js";
5
+ import {
6
+ applyPersistedLocalPorts
7
+ } from "./chunk-HFM6ROJL.js";
8
+ import {
9
+ readActiveRuntimeState
10
+ } from "./chunk-G4IIVVJO.js";
11
+ import {
12
+ require_proper_lockfile
13
+ } from "./chunk-7NXKPDF3.js";
14
+ import {
15
+ loadRepoEnv,
16
+ resolveApiUrl
17
+ } from "./chunk-W2HNI6AA.js";
18
+ import {
19
+ deriveLocalProjectId,
20
+ external_exports,
21
+ fetchBoundedJsonObject,
22
+ hmacProjectValue,
23
+ isLoopbackHostname,
24
+ isPortableGitRemote,
25
+ normalizeGitRemoteUrl,
26
+ normalizeProjectDisplayName,
27
+ normalizeRecordedProjectDirectory,
28
+ repositoryChangeInputSchema,
29
+ repositoryIdentityMatches,
30
+ repositoryIdentitySchema
31
+ } from "./chunk-473OA62O.js";
32
+ import {
33
+ __toESM
34
+ } from "./chunk-BTS4ZTF3.js";
35
+
36
+ // packages/koed-server/dist/project-metadata.js
37
+ import { execFile as nodeExecFile } from "node:child_process";
38
+ import { randomUUID } from "node:crypto";
39
+ import { existsSync, mkdirSync as mkdirSync2, readFileSync, renameSync, writeFileSync, statSync as statSync2, rmSync } from "node:fs";
40
+ import path, { dirname as dirname3, relative, resolve as resolve2 } from "node:path";
41
+
42
+ // packages/koed-server/dist/git-project-probe.js
43
+ import { execFile } from "node:child_process";
44
+ import { statSync } from "node:fs";
45
+ import { dirname, resolve } from "node:path";
46
+ var createGitProjectProbe = (deps = {}) => {
47
+ const execute = deps.execFile ?? execFile;
48
+ const stat = deps.statSync ?? statSync;
49
+ const now = deps.now ?? Date.now;
50
+ const ttl = deps.ttlMs ?? 2e3;
51
+ const cache = /* @__PURE__ */ new Map();
52
+ const signature = (paths) => JSON.stringify(paths.map((file) => {
53
+ try {
54
+ const value = stat(file);
55
+ return [
56
+ file,
57
+ value.dev,
58
+ value.ino,
59
+ value.size,
60
+ value.mtimeMs,
61
+ value.ctimeMs
62
+ ];
63
+ } catch {
64
+ return [file, null];
65
+ }
66
+ }));
67
+ const command = (cwd, args) => new Promise((done) => {
68
+ const finish = (error, stdout, stderr) => {
69
+ done({
70
+ value: error ? null : String(stdout).trim() || null,
71
+ failed: Boolean(error),
72
+ nonGit: Boolean(error) && /not a git repository/i.test(typeof stderr === "string" ? stderr : "")
73
+ });
74
+ };
75
+ try {
76
+ execute("git", ["-C", cwd, ...args], {
77
+ timeout: 5e3,
78
+ maxBuffer: 1024 * 1024,
79
+ encoding: "utf8"
80
+ }, finish);
81
+ } catch (error) {
82
+ finish(error instanceof Error ? error : new Error("Git execution failed"), "");
83
+ }
84
+ });
85
+ return async (input) => {
86
+ const cwd = resolve(input.cwd);
87
+ const key = JSON.stringify([
88
+ resolve(input.profile),
89
+ cwd,
90
+ input.deviceSalt,
91
+ input.configurationRevision ?? ""
92
+ ]);
93
+ const cached = cache.get(key);
94
+ if (cached && cached.expiresAt > now() && cached.signature === signature(cached.watchedPaths)) {
95
+ return structuredClone(cached.result);
96
+ }
97
+ const result = {
98
+ status: "non_git",
99
+ failedCommands: [],
100
+ root: null,
101
+ remotes: [],
102
+ branch: null,
103
+ headCommit: null,
104
+ commonDir: null,
105
+ gitDir: null
106
+ };
107
+ const root = await command(cwd, ["rev-parse", "--show-toplevel"]);
108
+ if (root.failed) {
109
+ result.status = root.nonGit ? "non_git" : "failed";
110
+ if (!root.nonGit)
111
+ result.failedCommands.push("rev-parse --show-toplevel");
112
+ return result;
113
+ }
114
+ if (!root.value || root.value.includes("\n")) {
115
+ result.status = "ambiguous";
116
+ return result;
117
+ }
118
+ result.root = resolve(root.value);
119
+ result.status = "git";
120
+ const read = async (args) => {
121
+ const observation = await command(result.root, args);
122
+ if (observation.failed) {
123
+ result.failedCommands.push(args.join(" "));
124
+ result.status = "failed";
125
+ }
126
+ return observation.value;
127
+ };
128
+ const rawRemotes = await read(["remote", "-v"]);
129
+ const remotes = /* @__PURE__ */ new Map();
130
+ for (const line of rawRemotes?.split("\n") ?? []) {
131
+ const match = line.match(/^(\S+)\s+(\S+)\s+\((fetch|push)\)$/);
132
+ if (!match) {
133
+ if (result.failedCommands.length === 0)
134
+ result.status = "ambiguous";
135
+ continue;
136
+ }
137
+ const [, name, url] = match;
138
+ remotes.set(`${name}
139
+ ${url}`, normalizeGitRemoteUrl(url, name));
140
+ }
141
+ result.remotes = [...remotes.values()].sort((a, b) => `${a.name}:${a.fingerprint}`.localeCompare(`${b.name}:${b.fingerprint}`));
142
+ result.branch = await read(["branch", "--show-current"]);
143
+ result.headCommit = await read(["rev-parse", "HEAD"]);
144
+ const commonDir = await read(["rev-parse", "--git-common-dir"]);
145
+ const gitDir = await read(["rev-parse", "--git-dir"]);
146
+ result.commonDir = commonDir ? resolve(result.root, commonDir) : null;
147
+ result.gitDir = gitDir ? resolve(result.root, gitDir) : null;
148
+ if (result.status === "git") {
149
+ const watchedPaths = /* @__PURE__ */ new Set();
150
+ for (let parent = cwd; ; parent = dirname(parent)) {
151
+ watchedPaths.add(resolve(parent, ".git"));
152
+ if (dirname(parent) === parent)
153
+ break;
154
+ }
155
+ for (const directory of [result.commonDir, result.gitDir]) {
156
+ if (!directory)
157
+ continue;
158
+ watchedPaths.add(directory);
159
+ for (const file of [
160
+ "config",
161
+ "config.worktree",
162
+ "HEAD",
163
+ "commondir",
164
+ "packed-refs"
165
+ ]) {
166
+ watchedPaths.add(resolve(directory, file));
167
+ }
168
+ if (result.branch)
169
+ watchedPaths.add(resolve(directory, "refs", "heads", result.branch));
170
+ }
171
+ if (cache.size >= 256)
172
+ cache.delete(cache.keys().next().value);
173
+ const paths = [...watchedPaths];
174
+ cache.set(key, {
175
+ result: structuredClone(result),
176
+ watchedPaths: paths,
177
+ signature: signature(paths),
178
+ expiresAt: now() + ttl
179
+ });
180
+ }
181
+ return result;
182
+ };
183
+ };
184
+ var probeGitProject = createGitProjectProbe();
185
+
186
+ // packages/koed-server/dist/repository-identity.js
187
+ var resolveRepositoryIdentity = (input) => {
188
+ const { observation, deviceSalt, checkoutId } = input;
189
+ const base = {
190
+ root: observation.root ?? input.cwd,
191
+ branch: observation.branch,
192
+ checkoutId,
193
+ originatingDeviceId: deviceSalt,
194
+ selectedRemote: null,
195
+ anchorDisplay: null
196
+ };
197
+ const unresolved = (reason, selectedRemote = null) => ({
198
+ ...base,
199
+ kind: "unresolved",
200
+ key: null,
201
+ reason,
202
+ selectedRemote
203
+ });
204
+ if (observation.status === "failed" && (!observation.root || observation.failedCommands.some((command) => !["branch --show-current", "rev-parse HEAD"].includes(command))))
205
+ return unresolved("probe_failed");
206
+ if (observation.status === "ambiguous")
207
+ return unresolved("probe_ambiguous");
208
+ if (!checkoutId)
209
+ return unresolved("checkout_unavailable");
210
+ const selected = (remoteName, reason) => {
211
+ const candidates = observation.remotes.filter((remote2) => remote2.name === remoteName);
212
+ if (!candidates.length)
213
+ return unresolved("selection_missing", remoteName);
214
+ const keys = new Set(candidates.map((remote2) => remote2.fingerprint));
215
+ if (keys.size !== 1)
216
+ return unresolved("selection_conflict", remoteName);
217
+ const remote = candidates[0];
218
+ if (!isPortableGitRemote(remote))
219
+ return unresolved("selection_not_portable", remoteName);
220
+ return {
221
+ ...base,
222
+ kind: "portable_repository",
223
+ key: remote.fingerprint,
224
+ reason,
225
+ selectedRemote: remoteName,
226
+ anchorDisplay: remote.display
227
+ };
228
+ };
229
+ if (input.localSelection !== void 0)
230
+ return selected(input.localSelection, "local_selection");
231
+ if (input.associatedSelection) {
232
+ const { selection } = input.associatedSelection;
233
+ if (selection.state === "conflict")
234
+ return unresolved("selection_conflict");
235
+ const remote = observation.remotes.find((entry) => isPortableGitRemote(entry) && entry.fingerprint === selection.anchorFingerprint);
236
+ if (!remote)
237
+ return unresolved("replicated_anchor_missing");
238
+ return selected(remote.name, "replicated_selection");
239
+ }
240
+ if (observation.status === "non_git") {
241
+ return {
242
+ ...base,
243
+ kind: "non_git_project",
244
+ key: `ng_${hmacProjectValue(deviceSalt, `${input.cwd}
245
+ ${checkoutId}`).slice(12)}`,
246
+ reason: "non_git"
247
+ };
248
+ }
249
+ for (const remoteName of ["upstream", "origin"]) {
250
+ const remotes = observation.remotes.filter((remote) => remote.name === remoteName);
251
+ if (remotes.some(isPortableGitRemote))
252
+ return selected(remoteName, remoteName);
253
+ }
254
+ if (!observation.commonDir || !input.commonDirMarker)
255
+ return unresolved("probe_failed");
256
+ return {
257
+ ...base,
258
+ kind: "device_local_repository",
259
+ key: `dl_${hmacProjectValue(deviceSalt, `${observation.commonDir}
260
+ ${input.commonDirMarker}`).slice(12)}`,
261
+ reason: "local_fallback"
262
+ };
263
+ };
264
+
265
+ // packages/koed-server/dist/project-associated-selection.js
266
+ var selectionSchema = external_exports.discriminatedUnion("state", [
267
+ external_exports.object({
268
+ state: external_exports.literal("selected"),
269
+ anchorFingerprint: external_exports.string().min(1).max(512)
270
+ }).strict(),
271
+ external_exports.object({ state: external_exports.literal("conflict") }).strict()
272
+ ]);
273
+ var responseSchema = external_exports.object({
274
+ association: external_exports.object({
275
+ groupId: external_exports.string().min(1),
276
+ associationId: external_exports.string().min(1),
277
+ selectionId: external_exports.string().min(1),
278
+ selection: selectionSchema.nullable()
279
+ }).strict().nullable()
280
+ }).strict();
281
+ var lookupAcceptedProjectSelection = async (paths, checkout, deps = {}) => {
282
+ const environment = deps.environment ?? process.env;
283
+ const repoEnv = loadRepoEnv(paths.repoRoot);
284
+ const token = resolveActiveIntegrationApiToken(paths, environment, repoEnv);
285
+ if (!token)
286
+ throw new Error("Project association lookup requires the local API credential");
287
+ const runtime = readActiveRuntimeState(paths.runtimeStatePath);
288
+ const origin = new URL(runtime?.apiUrl ?? resolveApiUrl(applyPersistedLocalPorts(paths, environment, { force: true }), repoEnv));
289
+ if (!isLoopbackHostname(origin.hostname) || !["http:", "https:"].includes(origin.protocol) || origin.username || origin.password)
290
+ throw new Error("Project association lookup requires the local Personal API");
291
+ const url = new URL("/v1/memory/repository-selection", origin);
292
+ url.search = new URLSearchParams(checkout).toString();
293
+ const { response, payload } = await fetchBoundedJsonObject(deps.fetch ?? globalThis.fetch, url, {
294
+ headers: { authorization: `Bearer ${token.token}` },
295
+ redirect: "error"
296
+ }, { timeoutMs: 1e4, maxBytes: 64 * 1024 });
297
+ if (!response.ok) {
298
+ throw new Error("Project association lookup is unavailable; retry discovery");
299
+ }
300
+ const result = responseSchema.parse(payload);
301
+ const association = result.association;
302
+ return association?.selection ? {
303
+ associationId: association.associationId,
304
+ selection: association.selection
305
+ } : void 0;
306
+ };
307
+
308
+ // packages/koed-server/dist/project-metadata-lock.js
309
+ var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
310
+ import { mkdirSync } from "node:fs";
311
+ import { dirname as dirname2 } from "node:path";
312
+ var withProjectMetadataLock = (file, operation) => {
313
+ mkdirSync(dirname2(file), { recursive: true, mode: 448 });
314
+ const deadline = Date.now() + 5e3;
315
+ let release;
316
+ while (true) {
317
+ try {
318
+ release = import_proper_lockfile.default.lockSync(file, { realpath: false, stale: 3e4 });
319
+ break;
320
+ } catch (error) {
321
+ if (error.code !== "ELOCKED" || Date.now() >= deadline)
322
+ throw error;
323
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 10);
324
+ }
325
+ }
326
+ try {
327
+ return operation();
328
+ } finally {
329
+ release();
330
+ }
331
+ };
332
+
333
+ // packages/koed-server/dist/project-metadata.js
334
+ var depsWithDefaults = (deps = {}) => ({
335
+ existsSync: deps.existsSync ?? existsSync,
336
+ readFileSync: deps.readFileSync ?? readFileSync,
337
+ writeFileSync: deps.writeFileSync ?? writeFileSync,
338
+ renameSync: deps.renameSync ?? renameSync,
339
+ mkdirSync: deps.mkdirSync ?? mkdirSync2,
340
+ statSync: deps.statSync ?? statSync2,
341
+ lookupAssociatedSelection: deps.lookupAssociatedSelection ?? lookupAcceptedProjectSelection,
342
+ execFile: deps.execFile ?? nodeExecFile,
343
+ now: deps.now ?? (() => /* @__PURE__ */ new Date()),
344
+ randomId: deps.randomId ?? randomUUID,
345
+ probeGit: deps.probeGit ?? (deps.execFile ? createGitProjectProbe({ execFile: deps.execFile }) : probeGitProject)
346
+ });
347
+ var defaultStore = (now, deps) => ({
348
+ schemaVersion: 3,
349
+ updatedAt: now,
350
+ deviceSaltId: `pms_${deps.randomId()}`,
351
+ repositoryChanges: [],
352
+ checkouts: [],
353
+ namedProjects: [],
354
+ projects: []
355
+ });
356
+ var historicalFolderRepositoryIdentity = (paths, cwd, depsInput = {}) => {
357
+ const root = normalizeRecordedProjectDirectory(cwd);
358
+ if (!root)
359
+ return null;
360
+ const deps = depsWithDefaults(depsInput);
361
+ const store = readStore(paths, deps);
362
+ return {
363
+ kind: "non_git_project",
364
+ key: `ng_${hmacProjectValue(store.deviceSaltId, JSON.stringify(["historical_folder", root])).slice(12)}`,
365
+ root,
366
+ branch: null,
367
+ reason: "non_git",
368
+ checkoutId: null,
369
+ originatingDeviceId: store.deviceSaltId,
370
+ selectedRemote: null,
371
+ anchorDisplay: null
372
+ };
373
+ };
374
+ var readStoreUnlocked = (paths, deps) => {
375
+ const now = deps.now().toISOString();
376
+ if (!deps.existsSync(paths.projectMetadataPath)) {
377
+ return defaultStore(now, deps);
378
+ }
379
+ try {
380
+ const parsed = JSON.parse(deps.readFileSync(paths.projectMetadataPath, "utf8"));
381
+ const store = {
382
+ schemaVersion: 3,
383
+ updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : now,
384
+ deviceSaltId: typeof parsed.deviceSaltId === "string" && parsed.deviceSaltId.trim() ? parsed.deviceSaltId.trim() : `pms_${deps.randomId()}`,
385
+ repositoryChanges: Array.isArray(parsed.repositoryChanges) ? parsed.repositoryChanges.map((change) => repositoryChangeInputSchema.parse(change)) : [],
386
+ checkouts: Array.isArray(parsed.checkouts) ? parsed.checkouts.filter((entry) => typeof entry.id === "string" && typeof entry.root === "string" && typeof entry.marker === "string" && (entry.selectedRemote === void 0 || typeof entry.selectedRemote === "string") && (entry.associationLookupRequired === void 0 || typeof entry.associationLookupRequired === "boolean")) : [],
387
+ projects: Array.isArray(parsed.projects) ? parsed.projects.filter(isProjectMetadata).map(normalizeProjectMetadata) : [],
388
+ namedProjects: Array.isArray(parsed.namedProjects) ? parsed.namedProjects.map((project) => {
389
+ if (!project || typeof project.id !== "string" || typeof project.name !== "string" || !project.name.trim() || project.name.length > 160 || typeof project.createdAt !== "string")
390
+ throw new Error("Invalid named Project");
391
+ const repository = repositoryIdentitySchema.parse(project.repository);
392
+ if (repository.kind !== "local_project")
393
+ throw new Error("Invalid named Project identity");
394
+ return {
395
+ id: project.id,
396
+ name: project.name,
397
+ createdAt: project.createdAt,
398
+ repository
399
+ };
400
+ }) : []
401
+ };
402
+ if (parsed.schemaVersion !== 3 || parsed.deviceSaltId !== store.deviceSaltId) {
403
+ writeStore(paths, store, deps);
404
+ }
405
+ return store;
406
+ } catch (error) {
407
+ throw new Error("Project metadata config is malformed.", { cause: error });
408
+ }
409
+ };
410
+ var updateStore = (paths, deps, mutate) => withProjectMetadataLock(paths.projectMetadataPath, () => {
411
+ const store = readStoreUnlocked(paths, deps);
412
+ const result = mutate(store);
413
+ writeStore(paths, store, deps);
414
+ return result;
415
+ });
416
+ var readStore = (paths, deps) => withProjectMetadataLock(paths.projectMetadataPath, () => {
417
+ const store = readStoreUnlocked(paths, deps);
418
+ if (!deps.existsSync(paths.projectMetadataPath))
419
+ writeStore(paths, store, deps);
420
+ return store;
421
+ });
422
+ var writeStore = (paths, store, deps) => {
423
+ deps.mkdirSync(dirname3(paths.projectMetadataPath), {
424
+ recursive: true,
425
+ mode: 448
426
+ });
427
+ const tmpPath = `${paths.projectMetadataPath}.${randomUUID()}.tmp`;
428
+ try {
429
+ deps.writeFileSync(tmpPath, `${JSON.stringify(store, null, 2)}
430
+ `, {
431
+ mode: 384
432
+ });
433
+ deps.renameSync(tmpPath, paths.projectMetadataPath);
434
+ } finally {
435
+ rmSync(tmpPath, { force: true });
436
+ }
437
+ };
438
+ var isProjectMetadata = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value) && value.schemaVersion === 1 && typeof value.localProjectId === "string" && typeof value.displayName === "string" && Boolean(value.path);
439
+ var isNormalizedGitRemote = (value) => {
440
+ if (!value || typeof value !== "object" || Array.isArray(value))
441
+ return false;
442
+ const remote = value;
443
+ return typeof remote.name === "string" && (remote.host === null || typeof remote.host === "string") && (remote.namespace === null || typeof remote.namespace === "string") && (remote.repo === null || typeof remote.repo === "string") && (remote.display === null || typeof remote.display === "string") && typeof remote.fingerprint === "string";
444
+ };
445
+ var withoutFields = (value, ...fields) => {
446
+ const copy = { ...value };
447
+ for (const field of fields)
448
+ delete copy[field];
449
+ return copy;
450
+ };
451
+ var normalizeProjectMetadata = (value) => {
452
+ const metadata = withoutFields(value, "sourceProjectId");
453
+ if (!metadata.git)
454
+ return metadata;
455
+ const git = withoutFields(metadata.git, "remoteSetFingerprint", "remoteAliases", "commonDirHash");
456
+ const remotes = Array.isArray(git.remotes) ? git.remotes.filter(isNormalizedGitRemote) : [];
457
+ return {
458
+ ...metadata,
459
+ git: {
460
+ ...git,
461
+ remotes
462
+ }
463
+ };
464
+ };
465
+ var readPackageName = (packageJsonPath, deps) => {
466
+ try {
467
+ const parsed = JSON.parse(deps.readFileSync(packageJsonPath, "utf8"));
468
+ return typeof parsed.name === "string" && parsed.name.trim() ? parsed.name.trim() : null;
469
+ } catch {
470
+ return null;
471
+ }
472
+ };
473
+ var discoverPackages = (projectRoot, cwd, deps) => {
474
+ const root = projectRoot ?? cwd;
475
+ const packageJsonPath = resolve2(root, "package.json");
476
+ if (!deps.existsSync(packageJsonPath)) {
477
+ return [];
478
+ }
479
+ const manager = deps.existsSync(resolve2(root, "pnpm-lock.yaml")) ? "pnpm" : deps.existsSync(resolve2(root, "package-lock.json")) ? "npm" : deps.existsSync(resolve2(root, "yarn.lock")) ? "yarn" : deps.existsSync(resolve2(root, "bun.lockb")) ? "bun" : "unknown";
480
+ return [
481
+ {
482
+ manager,
483
+ name: readPackageName(packageJsonPath, deps),
484
+ relativePath: relative(root, packageJsonPath) || "package.json"
485
+ }
486
+ ];
487
+ };
488
+ var discoverProjectMetadata = async (paths, input, depsInput = {}) => {
489
+ const deps = depsWithDefaults(depsInput);
490
+ const initial = readStore(paths, deps);
491
+ const now = deps.now().toISOString();
492
+ const cwd = resolve2(input.cwd);
493
+ const observation = await deps.probeGit({
494
+ profile: paths.projectMetadataPath,
495
+ cwd,
496
+ deviceSalt: initial.deviceSaltId
497
+ });
498
+ const gitRoot = observation.root;
499
+ const remotes = observation.remotes;
500
+ const checkoutRoot = gitRoot ?? cwd;
501
+ let checkoutMarker = null;
502
+ try {
503
+ const stat = deps.statSync(observation.gitDir ?? checkoutRoot);
504
+ checkoutMarker = JSON.stringify([stat.dev, stat.ino, stat.birthtimeMs]);
505
+ } catch {
506
+ }
507
+ const observedCheckout = updateStore(paths, deps, (store) => {
508
+ let checkout = store.checkouts.find((entry) => entry.root === checkoutRoot && entry.marker === checkoutMarker);
509
+ if (!checkout && checkoutMarker) {
510
+ checkout = {
511
+ id: `checkout_${deps.randomId()}`,
512
+ root: checkoutRoot,
513
+ marker: checkoutMarker
514
+ };
515
+ store.checkouts.push(checkout);
516
+ }
517
+ return checkout;
518
+ });
519
+ let associatedSelection = input.associatedSelection;
520
+ const lookedUp = !associatedSelection && observedCheckout?.associationLookupRequired && observedCheckout.selectedRemote === void 0;
521
+ if (lookedUp) {
522
+ associatedSelection = await deps.lookupAssociatedSelection(paths, {
523
+ originatingDeviceId: initial.deviceSaltId,
524
+ checkoutId: observedCheckout.id
525
+ });
526
+ }
527
+ return updateStore(paths, deps, (store) => {
528
+ const checkout = store.checkouts.find((entry) => entry.id === observedCheckout?.id);
529
+ if (store.deviceSaltId !== initial.deviceSaltId || observedCheckout && !checkout)
530
+ throw new Error("Checkout changed during discovery; retry discovery");
531
+ if (checkoutMarker) {
532
+ const currentStat = deps.statSync(observation.gitDir ?? checkoutRoot);
533
+ if (JSON.stringify([
534
+ currentStat.dev,
535
+ currentStat.ino,
536
+ currentStat.birthtimeMs
537
+ ]) !== checkoutMarker)
538
+ throw new Error("Checkout changed during discovery; retry discovery");
539
+ }
540
+ if (lookedUp && !checkout?.associationLookupRequired)
541
+ associatedSelection = void 0;
542
+ const repository = resolveRepositoryIdentity({
543
+ observation,
544
+ cwd,
545
+ deviceSalt: store.deviceSaltId,
546
+ checkoutId: checkout?.id ?? null,
547
+ localSelection: checkout?.selectedRemote,
548
+ associatedSelection,
549
+ commonDirMarker: (() => {
550
+ try {
551
+ const stat = deps.statSync(observation.commonDir);
552
+ return JSON.stringify([stat.dev, stat.ino, stat.birthtimeMs]);
553
+ } catch {
554
+ return null;
555
+ }
556
+ })()
557
+ });
558
+ const packages = discoverPackages(gitRoot, cwd, deps);
559
+ const localProjectId = deriveLocalProjectId({
560
+ salt: store.deviceSaltId,
561
+ projectRoot: gitRoot,
562
+ cwd
563
+ });
564
+ const previousProject = store.projects.find((entry) => entry.localProjectId === localProjectId && entry.repository?.checkoutId === repository.checkoutId);
565
+ const previous = previousProject?.repository;
566
+ if (checkout && previous && previous.checkoutId === repository.checkoutId && !(previous.kind === "unresolved" && repository.kind === "unresolved" && previous.reason === repository.reason) && !repositoryIdentityMatches(previous, repository)) {
567
+ checkout.repositoryRevision = (checkout.repositoryRevision ?? 0) + 1;
568
+ store.repositoryChanges.push(repositoryChangeInputSchema.parse({
569
+ id: randomUUID(),
570
+ kind: "anchor_change",
571
+ originatingDeviceId: repository.originatingDeviceId,
572
+ checkoutId: checkout.id,
573
+ originatingRevision: checkout.repositoryRevision,
574
+ previousIdentity: previous,
575
+ targetIdentity: repository
576
+ }));
577
+ }
578
+ const { branch, headCommit, commonDir: resolvedCommonDir, gitDir: resolvedGitDir } = observation;
579
+ const isWorktree = Boolean(resolvedCommonDir && resolvedGitDir && resolvedCommonDir !== resolvedGitDir);
580
+ const displayName = normalizeProjectDisplayName({
581
+ cwd,
582
+ projectRoot: gitRoot,
583
+ packages,
584
+ remotes
585
+ });
586
+ const project = {
587
+ schemaVersion: 1,
588
+ discoveredAt: previousProject?.discoveredAt ?? now,
589
+ lastSeenAt: now,
590
+ localProjectId,
591
+ displayName,
592
+ path: {
593
+ cwd,
594
+ projectRoot: gitRoot,
595
+ basename: path.basename(gitRoot ?? cwd),
596
+ localPathHash: hmacProjectValue(store.deviceSaltId, gitRoot ?? cwd)
597
+ },
598
+ ...gitRoot ? {
599
+ git: {
600
+ rootHash: hmacProjectValue(store.deviceSaltId, gitRoot),
601
+ remotes,
602
+ branch,
603
+ headCommit,
604
+ isWorktree,
605
+ worktreeHash: isWorktree ? hmacProjectValue(store.deviceSaltId, gitRoot) : null
606
+ }
607
+ } : {},
608
+ repository,
609
+ packages,
610
+ ...input.aiClientSource ? {
611
+ aiClient: {
612
+ cwdHash: hmacProjectValue(store.deviceSaltId, cwd),
613
+ cwdBasename: path.basename(cwd),
614
+ source: input.aiClientSource
615
+ }
616
+ } : {}
617
+ };
618
+ const projects = [
619
+ ...store.projects.filter((entry) => entry.localProjectId !== localProjectId),
620
+ project
621
+ ].sort((left, right) => left.displayName.localeCompare(right.displayName));
622
+ store.updatedAt = now;
623
+ store.projects = projects;
624
+ return {
625
+ ok: true,
626
+ state: "discovered",
627
+ message: "Project metadata discovered.",
628
+ gitProbe: {
629
+ status: observation.status,
630
+ failedCommands: observation.failedCommands
631
+ },
632
+ project
633
+ };
634
+ });
635
+ };
636
+ var listProjectMetadata = (paths, depsInput = {}) => {
637
+ const store = readStore(paths, depsWithDefaults(depsInput));
638
+ return {
639
+ ok: true,
640
+ state: "listed",
641
+ message: `Found ${store.projects.length} Project metadata record(s).`,
642
+ projects: store.projects
643
+ };
644
+ };
645
+ var listNamedProjects = (paths, depsInput = {}) => readStore(paths, depsWithDefaults(depsInput)).namedProjects;
646
+ var createNamedProject = (paths, name, depsInput = {}) => {
647
+ const trimmed = name.trim();
648
+ if (!trimmed || trimmed.length > 160)
649
+ throw new Error("Enter a Project name of 1 to 160 characters.");
650
+ const deps = depsWithDefaults(depsInput);
651
+ return updateStore(paths, deps, (store) => {
652
+ if (store.namedProjects.length >= 500)
653
+ throw new Error("The local Project catalog is full.");
654
+ const id = `project_${deps.randomId()}`;
655
+ const project = {
656
+ id,
657
+ name: trimmed,
658
+ createdAt: deps.now().toISOString(),
659
+ repository: {
660
+ kind: "local_project",
661
+ key: id,
662
+ reason: "manual",
663
+ originatingDeviceId: store.deviceSaltId,
664
+ root: null,
665
+ branch: null,
666
+ checkoutId: null,
667
+ selectedRemote: null,
668
+ anchorDisplay: null
669
+ }
670
+ };
671
+ store.updatedAt = project.createdAt;
672
+ store.namedProjects.push(project);
673
+ return project;
674
+ });
675
+ };
676
+ var getProjectMetadataForCwd = (paths, cwd, depsInput = {}) => {
677
+ const resolvedCwd = resolve2(cwd);
678
+ const store = readStore(paths, depsWithDefaults(depsInput));
679
+ const project = store.projects.find((entry) => entry.path.cwd === resolvedCwd || entry.path.projectRoot === resolvedCwd) ?? null;
680
+ if (!project) {
681
+ return {
682
+ ok: false,
683
+ state: "missing",
684
+ message: "Project metadata not found."
685
+ };
686
+ }
687
+ return {
688
+ ok: true,
689
+ state: "found",
690
+ message: "Project metadata found.",
691
+ project
692
+ };
693
+ };
694
+ var forgetProjectMetadata = (paths, localProjectId, depsInput = {}) => {
695
+ const deps = depsWithDefaults(depsInput);
696
+ return updateStore(paths, deps, (store) => {
697
+ const project = store.projects.find((entry) => entry.localProjectId === localProjectId);
698
+ if (!project) {
699
+ return {
700
+ ok: false,
701
+ state: "missing",
702
+ message: "Project metadata not found."
703
+ };
704
+ }
705
+ const now = deps.now().toISOString();
706
+ store.updatedAt = now;
707
+ store.projects = store.projects.filter((entry) => entry.localProjectId !== localProjectId);
708
+ return {
709
+ ok: true,
710
+ state: "forgotten",
711
+ message: "Project metadata forgotten.",
712
+ project
713
+ };
714
+ });
715
+ };
716
+ var setProjectRepositoryAnchor = async (paths, input, depsInput = {}) => {
717
+ if (input.remoteName !== null && (!input.remoteName.trim() || input.remoteName.length > 512 || /\s/.test(input.remoteName)))
718
+ throw new Error("Repository remote name is invalid.");
719
+ const deps = depsWithDefaults(depsInput);
720
+ const original = readStore(paths, deps).projects.find((project) => project.localProjectId === input.localProjectId);
721
+ if (!original)
722
+ throw new Error("Project metadata not found.");
723
+ const discovery = await discoverProjectMetadata(paths, { cwd: original.path.projectRoot ?? original.path.cwd }, depsInput);
724
+ if (discovery.project?.repository?.checkoutId !== input.expectedCheckoutId)
725
+ throw new Error("Checkout changed. Inspect the Project again before selecting an anchor.");
726
+ updateStore(paths, deps, (store) => {
727
+ const checkout = store.checkouts.find((entry) => entry.id === input.expectedCheckoutId);
728
+ if (!checkout)
729
+ throw new Error("Checkout provenance is unavailable.");
730
+ if (input.remoteName === null)
731
+ delete checkout.selectedRemote;
732
+ else
733
+ checkout.selectedRemote = input.remoteName;
734
+ });
735
+ return discoverProjectMetadata(paths, { cwd: original.path.projectRoot ?? original.path.cwd }, depsInput);
736
+ };
737
+ var setProjectAssociationLookup = async (paths, input, depsInput = {}) => {
738
+ const deps = depsWithDefaults(depsInput);
739
+ const original = readStore(paths, deps).projects.find((entry) => entry.localProjectId === input.localProjectId);
740
+ if (!original)
741
+ throw new Error("Local Project is unavailable");
742
+ const discovery = await discoverProjectMetadata(paths, { cwd: original.path.projectRoot ?? original.path.cwd }, depsInput);
743
+ if (discovery.project?.repository?.checkoutId !== input.expectedCheckoutId)
744
+ throw new Error("Checkout changed; inspect the Project again");
745
+ updateStore(paths, deps, (store) => {
746
+ const checkout = store.checkouts.find((entry) => entry.id === input.expectedCheckoutId);
747
+ if (!checkout)
748
+ throw new Error("Checkout provenance is unavailable");
749
+ checkout.associationLookupRequired = input.enabled;
750
+ });
751
+ };
752
+ var refreshProjectAssociations = async (paths, depsInput = {}) => {
753
+ const store = readStore(paths, depsWithDefaults(depsInput));
754
+ for (const project of store.projects) {
755
+ if (!store.checkouts.some((entry) => entry.id === project.repository?.checkoutId && entry.associationLookupRequired))
756
+ continue;
757
+ await discoverProjectMetadata(paths, { cwd: project.path.projectRoot ?? project.path.cwd }, depsInput);
758
+ }
759
+ };
760
+ var listPendingRepositoryChanges = (paths, depsInput = {}) => readStore(paths, depsWithDefaults(depsInput)).repositoryChanges;
761
+ var acknowledgeRepositoryChange = (paths, id, depsInput = {}) => {
762
+ const deps = depsWithDefaults(depsInput);
763
+ updateStore(paths, deps, (store) => {
764
+ store.repositoryChanges = store.repositoryChanges.filter((change) => change.id !== id);
765
+ });
766
+ };
767
+ export {
768
+ acknowledgeRepositoryChange,
769
+ createNamedProject,
770
+ discoverProjectMetadata,
771
+ forgetProjectMetadata,
772
+ getProjectMetadataForCwd,
773
+ historicalFolderRepositoryIdentity,
774
+ listNamedProjects,
775
+ listPendingRepositoryChanges,
776
+ listProjectMetadata,
777
+ refreshProjectAssociations,
778
+ setProjectAssociationLookup,
779
+ setProjectRepositoryAnchor
780
+ };