@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.
- package/LICENSE +201 -0
- package/README.md +64 -2
- package/bin/koed.js +7 -0
- package/package.json +26 -4
- package/third-party-notices.json +92 -0
- package/vendor/chunk-2BWTLF7A.js +13883 -0
- package/vendor/chunk-2DA7EFZV.js +924 -0
- package/vendor/chunk-2S3OGPUC.js +58 -0
- package/vendor/chunk-473OA62O.js +26827 -0
- package/vendor/chunk-6JRWGOQG.js +236 -0
- package/vendor/chunk-7NOQSX4T.js +14 -0
- package/vendor/chunk-7NXKPDF3.js +1586 -0
- package/vendor/chunk-A4NKL2PK.js +153 -0
- package/vendor/chunk-A6WMU2GG.js +48 -0
- package/vendor/chunk-AFLKCQHF.js +73 -0
- package/vendor/chunk-BTS4ZTF3.js +43 -0
- package/vendor/chunk-C3N4N5HR.js +108 -0
- package/vendor/chunk-DXTAWHY3.js +25 -0
- package/vendor/chunk-G4IIVVJO.js +56 -0
- package/vendor/chunk-GELDEJJ2.js +4337 -0
- package/vendor/chunk-HFM6ROJL.js +188 -0
- package/vendor/chunk-HK2H3MVE.js +328 -0
- package/vendor/chunk-HZJK5RWC.js +5088 -0
- package/vendor/chunk-J2L726BC.js +2497 -0
- package/vendor/chunk-JBGD4JLR.js +3779 -0
- package/vendor/chunk-JJNLH5GA.js +2470 -0
- package/vendor/chunk-JKOG52PE.js +128 -0
- package/vendor/chunk-K2EIFEQF.js +89 -0
- package/vendor/chunk-KUIWH33N.js +16 -0
- package/vendor/chunk-NEWIOOM6.js +34 -0
- package/vendor/chunk-NM5NXCVM.js +2404 -0
- package/vendor/chunk-PT3AUPGE.js +459 -0
- package/vendor/chunk-PY5LYLV7.js +143 -0
- package/vendor/chunk-QIIKMG3M.js +103 -0
- package/vendor/chunk-QT24SAW6.js +110 -0
- package/vendor/chunk-RVYJKKWA.js +22 -0
- package/vendor/chunk-SKVYP7NY.js +1647 -0
- package/vendor/chunk-TSRPHKAC.js +780 -0
- package/vendor/chunk-UI5RLBKQ.js +30 -0
- package/vendor/chunk-VPC5NLZG.js +259 -0
- package/vendor/chunk-W2HNI6AA.js +75 -0
- package/vendor/chunk-X6M525ZJ.js +20 -0
- package/vendor/chunk-XIZVLPHZ.js +18 -0
- package/vendor/chunk-XNFVSVBS.js +242 -0
- package/vendor/chunk-YCDEMYY6.js +2076 -0
- package/vendor/chunk-YJ6XUZT6.js +292 -0
- package/vendor/chunk-YJWREXN6.js +26020 -0
- package/vendor/chunk-YK4F4VY2.js +173 -0
- package/vendor/chunk-YOFI4PCH.js +36 -0
- package/vendor/chunk-ZUGNCQZE.js +247 -0
- package/vendor/chunk-ZXX4ZNJY.js +21 -0
- package/vendor/cli.js +7 -0
- package/vendor/component-manifest-catalog.js +8 -0
- package/vendor/control-plane.js +23 -0
- package/vendor/package.json +1 -0
- 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
|
+
};
|