superbee 0.1.3-pre.1 → 0.1.3-pre.2
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/superbee.mjs
CHANGED
|
@@ -44,7 +44,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
44
44
|
var define_SUPERBEE_BUILD_IDENTITY_default;
|
|
45
45
|
var init_define_SUPERBEE_BUILD_IDENTITY = __esm({
|
|
46
46
|
"<define:__SUPERBEE_BUILD_IDENTITY__>"() {
|
|
47
|
-
define_SUPERBEE_BUILD_IDENTITY_default = { schema: "superbee.build-identity.v1", package: { name: "superbee", version: "0.1.3-pre.
|
|
47
|
+
define_SUPERBEE_BUILD_IDENTITY_default = { schema: "superbee.build-identity.v1", package: { name: "superbee", version: "0.1.3-pre.2" }, source: { commit: "8042c5d90a0c7b6945a2ff06022b82721fe40b60", dirty: false }, artifact: { channel: "npm-package" }, compatibility_contracts: { skill: 1, hook: 1, mcp: 1 } };
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
50
|
|
|
@@ -52,7 +52,7 @@ var init_define_SUPERBEE_BUILD_IDENTITY = __esm({
|
|
|
52
52
|
var define_SUPERBEE_UPDATE_POLICY_default;
|
|
53
53
|
var init_define_SUPERBEE_UPDATE_POLICY = __esm({
|
|
54
54
|
"<define:__SUPERBEE_UPDATE_POLICY__>"() {
|
|
55
|
-
define_SUPERBEE_UPDATE_POLICY_default = { enabled:
|
|
55
|
+
define_SUPERBEE_UPDATE_POLICY_default = { enabled: false };
|
|
56
56
|
}
|
|
57
57
|
});
|
|
58
58
|
|
|
@@ -1143,7 +1143,7 @@ var require_kind_of = __commonJS({
|
|
|
1143
1143
|
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
1144
1144
|
init_define_SUPERBEE_UPDATE_POLICY();
|
|
1145
1145
|
var toString2 = Object.prototype.toString;
|
|
1146
|
-
module2.exports = function
|
|
1146
|
+
module2.exports = function kindOf2(val) {
|
|
1147
1147
|
if (val === void 0) return "undefined";
|
|
1148
1148
|
if (val === null) return "null";
|
|
1149
1149
|
var type = typeof val;
|
|
@@ -4872,7 +4872,7 @@ var init_content_type = __esm({
|
|
|
4872
4872
|
});
|
|
4873
4873
|
|
|
4874
4874
|
// ../core/src/errors.ts
|
|
4875
|
-
var InvalidInputError;
|
|
4875
|
+
var InvalidInputError, FilesystemIdentityAliasError, ConcurrentReplacementError;
|
|
4876
4876
|
var init_errors = __esm({
|
|
4877
4877
|
"../core/src/errors.ts"() {
|
|
4878
4878
|
"use strict";
|
|
@@ -4884,6 +4884,26 @@ var init_errors = __esm({
|
|
|
4884
4884
|
this.name = "InvalidInputError";
|
|
4885
4885
|
}
|
|
4886
4886
|
};
|
|
4887
|
+
FilesystemIdentityAliasError = class extends InvalidInputError {
|
|
4888
|
+
rel;
|
|
4889
|
+
segment;
|
|
4890
|
+
constructor(rel, segment) {
|
|
4891
|
+
super(
|
|
4892
|
+
`Path '${rel}' does not match the exact spelling of an existing filesystem entry at segment '${segment}'; ids that differ only by case or Unicode normalization cannot share one file.`
|
|
4893
|
+
);
|
|
4894
|
+
this.name = "FilesystemIdentityAliasError";
|
|
4895
|
+
this.rel = rel;
|
|
4896
|
+
this.segment = segment;
|
|
4897
|
+
}
|
|
4898
|
+
};
|
|
4899
|
+
ConcurrentReplacementError = class extends Error {
|
|
4900
|
+
rel;
|
|
4901
|
+
constructor(rel, attempts) {
|
|
4902
|
+
super(`Path '${rel}' was replaced concurrently on each of ${attempts} observation attempts; retry.`);
|
|
4903
|
+
this.name = "ConcurrentReplacementError";
|
|
4904
|
+
this.rel = rel;
|
|
4905
|
+
}
|
|
4906
|
+
};
|
|
4887
4907
|
}
|
|
4888
4908
|
});
|
|
4889
4909
|
|
|
@@ -5121,7 +5141,7 @@ async function canonicalTargetInDirectory(directory, requestedBasename) {
|
|
|
5121
5141
|
}
|
|
5122
5142
|
return requested;
|
|
5123
5143
|
}
|
|
5124
|
-
function timeoutError(lockPath, owner) {
|
|
5144
|
+
function timeoutError(lockPath, owner, guarded) {
|
|
5125
5145
|
const malformed2 = owner === null;
|
|
5126
5146
|
const sameHost = owner?.hostname === hostname();
|
|
5127
5147
|
const stale = owner !== null && sameHost && !processExists(owner.pid);
|
|
@@ -5133,28 +5153,20 @@ function timeoutError(lockPath, owner) {
|
|
|
5133
5153
|
} else {
|
|
5134
5154
|
message = `timed out waiting for filesystem mutation lock '${lockPath}' held by PID ${owner.pid} on ${owner.hostname}; retry the mutation.`;
|
|
5135
5155
|
}
|
|
5136
|
-
return new FilesystemMutationLockError(message
|
|
5156
|
+
return new FilesystemMutationLockError(`${message} The lock guards '${guarded}'.`, { lockPath, owner, stale, malformed: malformed2 });
|
|
5137
5157
|
}
|
|
5138
|
-
async function
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
const
|
|
5144
|
-
await fs.mkdir(targetDir, { recursive: true });
|
|
5145
|
-
const canonicalDir = await fs.realpath(targetDir);
|
|
5146
|
-
const targetCanonical = await canonicalTargetInDirectory(canonicalDir, path.basename(targetResolved));
|
|
5147
|
-
const portableRoot = options2.portableRoot ? await fs.realpath(options2.portableRoot).catch(() => path.resolve(options2.portableRoot)) : void 0;
|
|
5158
|
+
async function resolvedPortableRoot(portableRoot) {
|
|
5159
|
+
if (portableRoot === void 0) return void 0;
|
|
5160
|
+
return fs.realpath(portableRoot).catch(() => path.resolve(portableRoot));
|
|
5161
|
+
}
|
|
5162
|
+
async function selectLockRoot(options2) {
|
|
5163
|
+
const portableRoot = await resolvedPortableRoot(options2.portableRoot);
|
|
5148
5164
|
const lockRoot = options2.lockRoot !== void 0 ? explicitFilesystemMutationLockRoot(options2.lockRoot, portableRoot) : filesystemMutationLockRoot(portableRoot);
|
|
5149
5165
|
await ensurePrivateLockRoot(lockRoot);
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
created_at_ms: started,
|
|
5155
|
-
token: randomUUID(),
|
|
5156
|
-
target: targetCanonical
|
|
5157
|
-
};
|
|
5166
|
+
return lockRoot;
|
|
5167
|
+
}
|
|
5168
|
+
async function claimLockPath(lockPath, owner, waitMs, pollMs) {
|
|
5169
|
+
const started = owner.created_at_ms;
|
|
5158
5170
|
while (true) {
|
|
5159
5171
|
try {
|
|
5160
5172
|
await fs.mkdir(lockPath, { mode: 448 });
|
|
@@ -5191,10 +5203,43 @@ async function acquireFilesystemMutationLock(target, options2 = {}) {
|
|
|
5191
5203
|
} catch (err) {
|
|
5192
5204
|
if (err.code !== "EEXIST") throw err;
|
|
5193
5205
|
}
|
|
5194
|
-
if (Date.now() - started >= waitMs) throw timeoutError(lockPath, await readOwner(lockPath));
|
|
5206
|
+
if (Date.now() - started >= waitMs) throw timeoutError(lockPath, await readOwner(lockPath), owner.target);
|
|
5195
5207
|
await delay(pollMs);
|
|
5196
5208
|
}
|
|
5197
5209
|
}
|
|
5210
|
+
function newOwner(target) {
|
|
5211
|
+
return {
|
|
5212
|
+
pid: process.pid,
|
|
5213
|
+
hostname: hostname(),
|
|
5214
|
+
created_at_ms: Date.now(),
|
|
5215
|
+
token: randomUUID(),
|
|
5216
|
+
target
|
|
5217
|
+
};
|
|
5218
|
+
}
|
|
5219
|
+
async function acquireFilesystemMutationLock(target, options2 = {}) {
|
|
5220
|
+
const waitMs = positiveOption(options2.waitMs, DEFAULT_WAIT_MS, "waitMs");
|
|
5221
|
+
const pollMs = positiveOption(options2.pollMs, DEFAULT_POLL_MS, "pollMs");
|
|
5222
|
+
const targetResolved = path.resolve(target);
|
|
5223
|
+
const targetDir = path.dirname(targetResolved);
|
|
5224
|
+
const owner = newOwner(targetResolved);
|
|
5225
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
5226
|
+
const canonicalDir = await fs.realpath(targetDir);
|
|
5227
|
+
const targetCanonical = await canonicalTargetInDirectory(canonicalDir, path.basename(targetResolved));
|
|
5228
|
+
const lockRoot = await selectLockRoot(options2);
|
|
5229
|
+
const lockPath = filesystemMutationLockPathInRoot(targetCanonical, lockRoot);
|
|
5230
|
+
return claimLockPath(lockPath, { ...owner, target: targetCanonical }, waitMs, pollMs);
|
|
5231
|
+
}
|
|
5232
|
+
function assertIdentityKey(key) {
|
|
5233
|
+
if (!IDENTITY_KEY_SHAPE.test(key)) throw new TypeError("identity key must be a lowercase hex sha256 digest");
|
|
5234
|
+
}
|
|
5235
|
+
async function acquireFilesystemIdentityLock(key, identity, options2 = {}) {
|
|
5236
|
+
assertIdentityKey(key);
|
|
5237
|
+
const waitMs = positiveOption(options2.waitMs, DEFAULT_WAIT_MS, "waitMs");
|
|
5238
|
+
const pollMs = positiveOption(options2.pollMs, DEFAULT_POLL_MS, "pollMs");
|
|
5239
|
+
const owner = newOwner(identity);
|
|
5240
|
+
const lockRoot = await selectLockRoot(options2);
|
|
5241
|
+
return claimLockPath(path.join(lockRoot, `${key}.lock`), owner, waitMs, pollMs);
|
|
5242
|
+
}
|
|
5198
5243
|
async function withFilesystemMutationLock(target, fn, options2 = {}) {
|
|
5199
5244
|
const release = await acquireFilesystemMutationLock(target, options2);
|
|
5200
5245
|
try {
|
|
@@ -5203,7 +5248,7 @@ async function withFilesystemMutationLock(target, fn, options2 = {}) {
|
|
|
5203
5248
|
await release();
|
|
5204
5249
|
}
|
|
5205
5250
|
}
|
|
5206
|
-
var OWNER_FILE, DEFAULT_WAIT_MS, DEFAULT_POLL_MS, FilesystemMutationLockError;
|
|
5251
|
+
var OWNER_FILE, DEFAULT_WAIT_MS, DEFAULT_POLL_MS, FilesystemMutationLockError, IDENTITY_KEY_SHAPE;
|
|
5207
5252
|
var init_filesystem_lock = __esm({
|
|
5208
5253
|
"../core/src/filesystem-lock.ts"() {
|
|
5209
5254
|
"use strict";
|
|
@@ -5226,6 +5271,427 @@ var init_filesystem_lock = __esm({
|
|
|
5226
5271
|
this.malformed = details.malformed;
|
|
5227
5272
|
}
|
|
5228
5273
|
};
|
|
5274
|
+
IDENTITY_KEY_SHAPE = /^[0-9a-f]{64}$/;
|
|
5275
|
+
}
|
|
5276
|
+
});
|
|
5277
|
+
|
|
5278
|
+
// ../core/src/filesystem-identity.ts
|
|
5279
|
+
import { promises as fs2 } from "node:fs";
|
|
5280
|
+
import path2 from "node:path";
|
|
5281
|
+
import { createHash as createHash3, randomUUID as randomUUID2 } from "node:crypto";
|
|
5282
|
+
function isAbsentPathError(err) {
|
|
5283
|
+
return ABSENT_PATH_CODES.has(err?.code ?? "");
|
|
5284
|
+
}
|
|
5285
|
+
function relSegments(rel) {
|
|
5286
|
+
if (typeof rel !== "string" || rel.startsWith("/")) {
|
|
5287
|
+
throw new InvalidInputError(`Path '${String(rel)}' resolves outside the bundle root.`);
|
|
5288
|
+
}
|
|
5289
|
+
const segments = rel.split("/").filter((segment) => segment !== "" && segment !== ".");
|
|
5290
|
+
if (segments.length === 0 || segments.some((segment) => segment === "..")) {
|
|
5291
|
+
throw new InvalidInputError(`Path '${rel}' resolves outside the bundle root.`);
|
|
5292
|
+
}
|
|
5293
|
+
return segments;
|
|
5294
|
+
}
|
|
5295
|
+
function foldSegment(segment) {
|
|
5296
|
+
return segment.normalize("NFKD").toLowerCase().toUpperCase().toLowerCase();
|
|
5297
|
+
}
|
|
5298
|
+
async function existingAnchor(resolved) {
|
|
5299
|
+
const tail = [];
|
|
5300
|
+
let candidate = resolved;
|
|
5301
|
+
for (; ; ) {
|
|
5302
|
+
try {
|
|
5303
|
+
return { anchor: await fs2.realpath(candidate), tail };
|
|
5304
|
+
} catch (err) {
|
|
5305
|
+
if (!isAbsentPathError(err)) throw err;
|
|
5306
|
+
}
|
|
5307
|
+
const parent = path2.dirname(candidate);
|
|
5308
|
+
if (parent === candidate) return { anchor: candidate, tail };
|
|
5309
|
+
tail.unshift(path2.basename(candidate));
|
|
5310
|
+
candidate = parent;
|
|
5311
|
+
}
|
|
5312
|
+
}
|
|
5313
|
+
async function identityKey(root, rel) {
|
|
5314
|
+
const foldedRel = relSegments(rel).map(foldSegment).join("/");
|
|
5315
|
+
const { anchor, tail } = await existingAnchor(path2.resolve(root));
|
|
5316
|
+
const anchorSegments = anchor.split(path2.sep).filter((segment, index2) => index2 === 0 || segment !== "");
|
|
5317
|
+
const foldedRoot = [...anchorSegments, ...tail].map(foldSegment).join("/");
|
|
5318
|
+
return createHash3("sha256").update(`superbee-identity/v1\0${foldedRoot}\0${foldedRel}`).digest("hex");
|
|
5319
|
+
}
|
|
5320
|
+
function sameWitness(a, b) {
|
|
5321
|
+
return a.dev === b.dev && a.ino === b.ino;
|
|
5322
|
+
}
|
|
5323
|
+
function confirmAlias(listingHasExact, probe, recorded) {
|
|
5324
|
+
if (probe === null) return "absent";
|
|
5325
|
+
if (!sameWitness(probe, recorded)) return "restart";
|
|
5326
|
+
return listingHasExact ? "continue" : "aliased";
|
|
5327
|
+
}
|
|
5328
|
+
function classifyLeaf(snapshot2) {
|
|
5329
|
+
if (snapshot2.probe === null) return "absent";
|
|
5330
|
+
if (!sameWitness(snapshot2.probe, snapshot2.handle)) return "replaced";
|
|
5331
|
+
return snapshot2.listed ? "exact" : "aliased";
|
|
5332
|
+
}
|
|
5333
|
+
function classifyMkdir(outcome, listing, segment, isTail) {
|
|
5334
|
+
if (outcome === "created") return "created";
|
|
5335
|
+
const exact = listing.find((entry) => entry.name === segment);
|
|
5336
|
+
if (exact === void 0) return isTail ? "exact" : "aliased";
|
|
5337
|
+
return exact.kind === "directory" ? "exact" : "shape-mismatch";
|
|
5338
|
+
}
|
|
5339
|
+
async function probeSegment(port, candidate, rel, segment) {
|
|
5340
|
+
const probed = await port.probe(candidate);
|
|
5341
|
+
if (probed !== null && probed.kind === "symlink") throw new FilesystemSymlinkEntryError(rel, segment);
|
|
5342
|
+
return probed;
|
|
5343
|
+
}
|
|
5344
|
+
function hasExact(listing, segment) {
|
|
5345
|
+
return listing.some((entry) => entry.name === segment);
|
|
5346
|
+
}
|
|
5347
|
+
async function walkExact(port, rootResolved, segments, rel) {
|
|
5348
|
+
let parent = rootResolved;
|
|
5349
|
+
for (let index2 = 0; index2 < segments.length; index2++) {
|
|
5350
|
+
const segment = segments[index2];
|
|
5351
|
+
const candidate = path2.join(parent, segment);
|
|
5352
|
+
const probed = await probeSegment(port, candidate, rel, segment);
|
|
5353
|
+
if (probed === null) return { state: "absent", depth: index2 };
|
|
5354
|
+
const listing = await port.entries(parent);
|
|
5355
|
+
if (listing === null) return { state: "absent", depth: index2 };
|
|
5356
|
+
if (!hasExact(listing, segment)) throw new FilesystemIdentityAliasError(rel, segment);
|
|
5357
|
+
if (index2 === segments.length - 1) return { state: "exact", leaf: probed };
|
|
5358
|
+
if (probed.kind !== "directory") return { state: "shape-mismatch", segment };
|
|
5359
|
+
parent = candidate;
|
|
5360
|
+
}
|
|
5361
|
+
throw new InvalidInputError(`Path '${rel}' resolves outside the bundle root.`);
|
|
5362
|
+
}
|
|
5363
|
+
async function recordWalk(port, rootResolved, segments, rel) {
|
|
5364
|
+
const recorded = [];
|
|
5365
|
+
let parent = rootResolved;
|
|
5366
|
+
for (let index2 = 0; index2 < segments.length; index2++) {
|
|
5367
|
+
const segment = segments[index2];
|
|
5368
|
+
const candidate = path2.join(parent, segment);
|
|
5369
|
+
const probed = await probeSegment(port, candidate, rel, segment);
|
|
5370
|
+
if (probed === null) return null;
|
|
5371
|
+
if (index2 < segments.length - 1 && probed.kind !== "directory") return null;
|
|
5372
|
+
recorded.push(probed);
|
|
5373
|
+
parent = candidate;
|
|
5374
|
+
}
|
|
5375
|
+
return recorded;
|
|
5376
|
+
}
|
|
5377
|
+
async function confirmedWalk(port, rootResolved, segments, rel, recorded, handle) {
|
|
5378
|
+
let parent = rootResolved;
|
|
5379
|
+
for (let index2 = 0; index2 < segments.length; index2++) {
|
|
5380
|
+
const segment = segments[index2];
|
|
5381
|
+
const candidate = path2.join(parent, segment);
|
|
5382
|
+
const listing = await port.entries(parent);
|
|
5383
|
+
if (listing === null) return "absent";
|
|
5384
|
+
const listed = hasExact(listing, segment);
|
|
5385
|
+
if (handle !== null && index2 === segments.length - 1) {
|
|
5386
|
+
const verdict = classifyLeaf({ listed, probe: await probeSegment(port, candidate, rel, segment), handle });
|
|
5387
|
+
if (verdict === "aliased") throw new FilesystemIdentityAliasError(rel, segment);
|
|
5388
|
+
return verdict === "replaced" ? "restart" : verdict;
|
|
5389
|
+
}
|
|
5390
|
+
if (index2 < segments.length - 1 || !listed) {
|
|
5391
|
+
const verdict = confirmAlias(listed, await probeSegment(port, candidate, rel, segment), recorded[index2]);
|
|
5392
|
+
if (verdict === "aliased") throw new FilesystemIdentityAliasError(rel, segment);
|
|
5393
|
+
if (verdict !== "continue") return verdict;
|
|
5394
|
+
}
|
|
5395
|
+
parent = candidate;
|
|
5396
|
+
}
|
|
5397
|
+
return "continue";
|
|
5398
|
+
}
|
|
5399
|
+
function countRestart(restarts, rel) {
|
|
5400
|
+
if (restarts >= MAX_RESTARTS) throw new ConcurrentReplacementError(rel, restarts + 1);
|
|
5401
|
+
return restarts + 1;
|
|
5402
|
+
}
|
|
5403
|
+
async function observeExact(port, root, rel, read) {
|
|
5404
|
+
const segments = relSegments(rel);
|
|
5405
|
+
const rootResolved = path2.resolve(root);
|
|
5406
|
+
const target = path2.join(rootResolved, ...segments);
|
|
5407
|
+
for (let restarts = 0; ; ) {
|
|
5408
|
+
const recorded = await recordWalk(port, rootResolved, segments, rel);
|
|
5409
|
+
if (recorded === null) return { state: "absent" };
|
|
5410
|
+
const verified = await confirmedWalk(port, rootResolved, segments, rel, recorded, null);
|
|
5411
|
+
if (verified === "absent") return { state: "absent" };
|
|
5412
|
+
if (verified === "restart") {
|
|
5413
|
+
restarts = countRestart(restarts, rel);
|
|
5414
|
+
continue;
|
|
5415
|
+
}
|
|
5416
|
+
let opened;
|
|
5417
|
+
try {
|
|
5418
|
+
opened = await port.open(target);
|
|
5419
|
+
} catch (err) {
|
|
5420
|
+
if (isAbsentPathError(err)) return { state: "absent" };
|
|
5421
|
+
throw err;
|
|
5422
|
+
}
|
|
5423
|
+
let value;
|
|
5424
|
+
let verdict;
|
|
5425
|
+
try {
|
|
5426
|
+
value = await read(opened.handle, target);
|
|
5427
|
+
if (value === null) return { state: "absent" };
|
|
5428
|
+
verdict = await confirmedWalk(port, rootResolved, segments, rel, recorded, opened);
|
|
5429
|
+
} finally {
|
|
5430
|
+
await port.close(opened.handle);
|
|
5431
|
+
}
|
|
5432
|
+
if (verdict === "exact") return { state: "exact", value };
|
|
5433
|
+
if (verdict === "absent") return { state: "absent" };
|
|
5434
|
+
restarts = countRestart(restarts, rel);
|
|
5435
|
+
}
|
|
5436
|
+
}
|
|
5437
|
+
async function probeExact(port, root, rel) {
|
|
5438
|
+
const segments = relSegments(rel);
|
|
5439
|
+
const rootResolved = path2.resolve(root);
|
|
5440
|
+
for (let restarts = 0; ; ) {
|
|
5441
|
+
const recorded = await recordWalk(port, rootResolved, segments, rel);
|
|
5442
|
+
if (recorded === null) return { state: "absent" };
|
|
5443
|
+
const leaf = recorded[recorded.length - 1];
|
|
5444
|
+
const verified = await confirmedWalk(port, rootResolved, segments, rel, recorded, null);
|
|
5445
|
+
const verdict = verified === "continue" ? await confirmedWalk(port, rootResolved, segments, rel, recorded, leaf) : verified;
|
|
5446
|
+
if (verdict === "exact") return { state: "exact", value: leaf };
|
|
5447
|
+
if (verdict === "absent") return { state: "absent" };
|
|
5448
|
+
restarts = countRestart(restarts, rel);
|
|
5449
|
+
}
|
|
5450
|
+
}
|
|
5451
|
+
function enqueue(key, fn) {
|
|
5452
|
+
const tail = queues.get(key) ?? Promise.resolve();
|
|
5453
|
+
const run = tail.then(fn, fn);
|
|
5454
|
+
const settled = run.then(
|
|
5455
|
+
() => void 0,
|
|
5456
|
+
() => void 0
|
|
5457
|
+
);
|
|
5458
|
+
queues.set(key, settled);
|
|
5459
|
+
void settled.then(() => {
|
|
5460
|
+
if (queues.get(key) === settled) queues.delete(key);
|
|
5461
|
+
});
|
|
5462
|
+
return run;
|
|
5463
|
+
}
|
|
5464
|
+
function absentDirectoryError(dir) {
|
|
5465
|
+
const err = new Error(`ENOENT: no such file or directory, scandir '${dir}'`);
|
|
5466
|
+
err.code = "ENOENT";
|
|
5467
|
+
err.syscall = "scandir";
|
|
5468
|
+
err.path = dir;
|
|
5469
|
+
return err;
|
|
5470
|
+
}
|
|
5471
|
+
async function readWhole(port, target) {
|
|
5472
|
+
let opened;
|
|
5473
|
+
try {
|
|
5474
|
+
opened = await port.open(target);
|
|
5475
|
+
} catch (err) {
|
|
5476
|
+
if (ABSENT_FILE_CODES.has(err?.code ?? "")) return null;
|
|
5477
|
+
throw err;
|
|
5478
|
+
}
|
|
5479
|
+
try {
|
|
5480
|
+
return await port.readAll(opened.handle);
|
|
5481
|
+
} catch (err) {
|
|
5482
|
+
if (ABSENT_FILE_CODES.has(err?.code ?? "")) return null;
|
|
5483
|
+
throw err;
|
|
5484
|
+
} finally {
|
|
5485
|
+
await port.close(opened.handle);
|
|
5486
|
+
}
|
|
5487
|
+
}
|
|
5488
|
+
async function mkdirExact(port, parent, segment, isTail, rel) {
|
|
5489
|
+
const outcome = await port.mkdir(path2.join(parent, segment));
|
|
5490
|
+
if (outcome === "created") return;
|
|
5491
|
+
const listing = await port.entries(parent);
|
|
5492
|
+
if (listing === null) throw absentDirectoryError(parent);
|
|
5493
|
+
if (listing.some((entry) => entry.name === segment && entry.kind === "symlink")) {
|
|
5494
|
+
throw new FilesystemSymlinkEntryError(rel, segment);
|
|
5495
|
+
}
|
|
5496
|
+
const verdict = classifyMkdir(outcome, listing, segment, isTail);
|
|
5497
|
+
if (verdict === "aliased") throw new FilesystemIdentityAliasError(rel, segment);
|
|
5498
|
+
if (verdict === "shape-mismatch") throw new FilesystemShapeMismatchError(rel, segment);
|
|
5499
|
+
}
|
|
5500
|
+
async function ensureExactDirectories(port, rootResolved, segments, existingDepth, rel) {
|
|
5501
|
+
if (existingDepth === 0 && await port.probe(rootResolved) === null) {
|
|
5502
|
+
const tail = [];
|
|
5503
|
+
let candidate = rootResolved;
|
|
5504
|
+
for (; ; ) {
|
|
5505
|
+
const parent2 = path2.dirname(candidate);
|
|
5506
|
+
if (parent2 === candidate) break;
|
|
5507
|
+
tail.unshift(path2.basename(candidate));
|
|
5508
|
+
candidate = parent2;
|
|
5509
|
+
if (await port.probe(candidate) !== null) break;
|
|
5510
|
+
}
|
|
5511
|
+
for (const segment of tail) {
|
|
5512
|
+
await mkdirExact(port, candidate, segment, true, rel);
|
|
5513
|
+
candidate = path2.join(candidate, segment);
|
|
5514
|
+
}
|
|
5515
|
+
}
|
|
5516
|
+
let parent = path2.join(rootResolved, ...segments.slice(0, existingDepth));
|
|
5517
|
+
for (const segment of segments.slice(existingDepth, -1)) {
|
|
5518
|
+
await mkdirExact(port, parent, segment, false, rel);
|
|
5519
|
+
parent = path2.join(parent, segment);
|
|
5520
|
+
}
|
|
5521
|
+
}
|
|
5522
|
+
async function createExactLeaf(port, tmp, target, rel, leaf, rootResolved) {
|
|
5523
|
+
const outcome = await port.link(tmp, target);
|
|
5524
|
+
if (outcome === "linked") {
|
|
5525
|
+
await port.unlink(tmp).catch(() => {
|
|
5526
|
+
});
|
|
5527
|
+
return;
|
|
5528
|
+
}
|
|
5529
|
+
if (outcome === "unsupported") {
|
|
5530
|
+
linkUnsupportedRoots.add(rootResolved);
|
|
5531
|
+
await port.rename(tmp, target);
|
|
5532
|
+
return;
|
|
5533
|
+
}
|
|
5534
|
+
const listing = await port.entries(path2.dirname(target)) ?? [];
|
|
5535
|
+
if (hasExact(listing, leaf)) throw new ConcurrentReplacementError(rel, 1);
|
|
5536
|
+
throw new FilesystemIdentityAliasError(rel, leaf);
|
|
5537
|
+
}
|
|
5538
|
+
async function mutateExact(port, root, rel, body) {
|
|
5539
|
+
const segments = relSegments(rel);
|
|
5540
|
+
const rootResolved = path2.resolve(root);
|
|
5541
|
+
const target = path2.join(rootResolved, ...segments);
|
|
5542
|
+
const leaf = segments[segments.length - 1];
|
|
5543
|
+
const key = await identityKey(root, rel);
|
|
5544
|
+
return enqueue(key, async () => {
|
|
5545
|
+
const release = await port.claim(key, { root: rootResolved, rel });
|
|
5546
|
+
try {
|
|
5547
|
+
const realized = await walkExact(port, rootResolved, segments, rel);
|
|
5548
|
+
if (realized.state === "shape-mismatch") throw new FilesystemShapeMismatchError(rel, realized.segment);
|
|
5549
|
+
const existingDepth = realized.state === "absent" ? realized.depth : segments.length - 1;
|
|
5550
|
+
const context = {
|
|
5551
|
+
state: realized.state,
|
|
5552
|
+
async current() {
|
|
5553
|
+
return realized.state === "exact" ? readWhole(port, target) : null;
|
|
5554
|
+
},
|
|
5555
|
+
async replace(bytes) {
|
|
5556
|
+
await ensureExactDirectories(port, rootResolved, segments, existingDepth, rel);
|
|
5557
|
+
const dir = path2.dirname(target);
|
|
5558
|
+
const tmpName = `.${leaf}.${process.pid}.${Date.now()}.${randomUUID2()}.tmp`;
|
|
5559
|
+
const tmp = path2.join(dir, tmpName);
|
|
5560
|
+
await port.writeTemp(dir, tmpName, bytes);
|
|
5561
|
+
try {
|
|
5562
|
+
if (realized.state === "exact" || linkUnsupportedRoots.has(rootResolved)) {
|
|
5563
|
+
await port.rename(tmp, target);
|
|
5564
|
+
return;
|
|
5565
|
+
}
|
|
5566
|
+
await createExactLeaf(port, tmp, target, rel, leaf, rootResolved);
|
|
5567
|
+
} catch (err) {
|
|
5568
|
+
await port.unlink(tmp).catch(() => {
|
|
5569
|
+
});
|
|
5570
|
+
throw err;
|
|
5571
|
+
}
|
|
5572
|
+
},
|
|
5573
|
+
async remove() {
|
|
5574
|
+
await port.unlink(target);
|
|
5575
|
+
}
|
|
5576
|
+
};
|
|
5577
|
+
return await body(context);
|
|
5578
|
+
} finally {
|
|
5579
|
+
await release();
|
|
5580
|
+
}
|
|
5581
|
+
});
|
|
5582
|
+
}
|
|
5583
|
+
function kindOf(stats) {
|
|
5584
|
+
if (stats.isSymbolicLink()) return "symlink";
|
|
5585
|
+
if (stats.isDirectory()) return "directory";
|
|
5586
|
+
if (stats.isFile()) return "file";
|
|
5587
|
+
return "other";
|
|
5588
|
+
}
|
|
5589
|
+
var FilesystemSymlinkEntryError, FilesystemShapeMismatchError, ABSENT_PATH_CODES, MAX_RESTARTS, linkUnsupportedRoots, queues, ABSENT_FILE_CODES, nodeFilesystemIdentityPort;
|
|
5590
|
+
var init_filesystem_identity = __esm({
|
|
5591
|
+
"../core/src/filesystem-identity.ts"() {
|
|
5592
|
+
"use strict";
|
|
5593
|
+
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
5594
|
+
init_define_SUPERBEE_UPDATE_POLICY();
|
|
5595
|
+
init_errors();
|
|
5596
|
+
init_filesystem_lock();
|
|
5597
|
+
FilesystemSymlinkEntryError = class extends InvalidInputError {
|
|
5598
|
+
rel;
|
|
5599
|
+
segment;
|
|
5600
|
+
constructor(rel, segment) {
|
|
5601
|
+
super(`Path '${rel}' reaches a symbolic link at segment '${segment}'; symlinked entries inside a bundle are unsupported.`);
|
|
5602
|
+
this.name = "FilesystemSymlinkEntryError";
|
|
5603
|
+
this.rel = rel;
|
|
5604
|
+
this.segment = segment;
|
|
5605
|
+
}
|
|
5606
|
+
};
|
|
5607
|
+
FilesystemShapeMismatchError = class extends Error {
|
|
5608
|
+
rel;
|
|
5609
|
+
segment;
|
|
5610
|
+
constructor(rel, segment) {
|
|
5611
|
+
super(`Path '${rel}' needs a directory at segment '${segment}' but a regular file exists there.`);
|
|
5612
|
+
this.name = "FilesystemShapeMismatchError";
|
|
5613
|
+
this.rel = rel;
|
|
5614
|
+
this.segment = segment;
|
|
5615
|
+
}
|
|
5616
|
+
};
|
|
5617
|
+
ABSENT_PATH_CODES = /* @__PURE__ */ new Set(["ENOENT", "ENOTDIR"]);
|
|
5618
|
+
MAX_RESTARTS = 3;
|
|
5619
|
+
linkUnsupportedRoots = /* @__PURE__ */ new Set();
|
|
5620
|
+
queues = /* @__PURE__ */ new Map();
|
|
5621
|
+
ABSENT_FILE_CODES = /* @__PURE__ */ new Set(["ENOENT", "ENOTDIR", "EISDIR"]);
|
|
5622
|
+
nodeFilesystemIdentityPort = Object.freeze({
|
|
5623
|
+
async probe(target) {
|
|
5624
|
+
let lstats;
|
|
5625
|
+
try {
|
|
5626
|
+
lstats = await fs2.lstat(target);
|
|
5627
|
+
} catch (err) {
|
|
5628
|
+
if (isAbsentPathError(err)) return null;
|
|
5629
|
+
throw err;
|
|
5630
|
+
}
|
|
5631
|
+
return { kind: kindOf(lstats), dev: lstats.dev, ino: lstats.ino };
|
|
5632
|
+
},
|
|
5633
|
+
async entries(dir) {
|
|
5634
|
+
try {
|
|
5635
|
+
const dirents = await fs2.readdir(dir, { withFileTypes: true });
|
|
5636
|
+
return dirents.map((dirent) => ({ name: dirent.name, kind: kindOf(dirent) }));
|
|
5637
|
+
} catch (err) {
|
|
5638
|
+
if (isAbsentPathError(err)) return null;
|
|
5639
|
+
throw err;
|
|
5640
|
+
}
|
|
5641
|
+
},
|
|
5642
|
+
async open(target) {
|
|
5643
|
+
const handle = await fs2.open(target, "r");
|
|
5644
|
+
try {
|
|
5645
|
+
const stats = await handle.stat();
|
|
5646
|
+
return { handle, dev: stats.dev, ino: stats.ino };
|
|
5647
|
+
} catch (err) {
|
|
5648
|
+
await handle.close().catch(() => {
|
|
5649
|
+
});
|
|
5650
|
+
throw err;
|
|
5651
|
+
}
|
|
5652
|
+
},
|
|
5653
|
+
readAll(handle) {
|
|
5654
|
+
return handle.readFile();
|
|
5655
|
+
},
|
|
5656
|
+
close(handle) {
|
|
5657
|
+
return handle.close();
|
|
5658
|
+
},
|
|
5659
|
+
async stat(target) {
|
|
5660
|
+
return { mtime: (await fs2.stat(target)).mtime };
|
|
5661
|
+
},
|
|
5662
|
+
async mkdir(dir) {
|
|
5663
|
+
try {
|
|
5664
|
+
await fs2.mkdir(dir);
|
|
5665
|
+
return "created";
|
|
5666
|
+
} catch (err) {
|
|
5667
|
+
if (err.code === "EEXIST") return "exists";
|
|
5668
|
+
throw err;
|
|
5669
|
+
}
|
|
5670
|
+
},
|
|
5671
|
+
async writeTemp(dir, name, bytes) {
|
|
5672
|
+
await fs2.writeFile(path2.join(dir, name), bytes);
|
|
5673
|
+
},
|
|
5674
|
+
async link(from, to) {
|
|
5675
|
+
try {
|
|
5676
|
+
await fs2.link(from, to);
|
|
5677
|
+
return "linked";
|
|
5678
|
+
} catch (err) {
|
|
5679
|
+
const code3 = err.code;
|
|
5680
|
+
if (code3 === "EEXIST") return "exists";
|
|
5681
|
+
if (code3 === "EPERM" || code3 === "ENOTSUP" || code3 === "EOPNOTSUPP" || code3 === "EXDEV") return "unsupported";
|
|
5682
|
+
throw err;
|
|
5683
|
+
}
|
|
5684
|
+
},
|
|
5685
|
+
async rename(from, to) {
|
|
5686
|
+
await fs2.rename(from, to);
|
|
5687
|
+
},
|
|
5688
|
+
async unlink(target) {
|
|
5689
|
+
await fs2.unlink(target);
|
|
5690
|
+
},
|
|
5691
|
+
claim(key, identity) {
|
|
5692
|
+
return acquireFilesystemIdentityLock(key, `${identity.root}:${identity.rel}`, { portableRoot: identity.root });
|
|
5693
|
+
}
|
|
5694
|
+
});
|
|
5229
5695
|
}
|
|
5230
5696
|
});
|
|
5231
5697
|
|
|
@@ -5262,9 +5728,9 @@ var init_mutation_attribution = __esm({
|
|
|
5262
5728
|
});
|
|
5263
5729
|
|
|
5264
5730
|
// ../core/src/versioning.ts
|
|
5265
|
-
import { createHash as
|
|
5731
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
5266
5732
|
function sha256Hex(input) {
|
|
5267
|
-
return
|
|
5733
|
+
return createHash4("sha256").update(input, "utf8").digest("hex");
|
|
5268
5734
|
}
|
|
5269
5735
|
function contentVersion(doc2) {
|
|
5270
5736
|
return `sha256:${sha256Hex(stringifyDoc(doc2.frontmatter, doc2.body ?? ""))}`;
|
|
@@ -5273,7 +5739,7 @@ function versionOfBytes(raw) {
|
|
|
5273
5739
|
return `sha256:${sha256Hex(raw)}`;
|
|
5274
5740
|
}
|
|
5275
5741
|
function blobVersion(bytes) {
|
|
5276
|
-
return `sha256:${
|
|
5742
|
+
return `sha256:${createHash4("sha256").update(bytes).digest("hex")}`;
|
|
5277
5743
|
}
|
|
5278
5744
|
function stripETagWrapper(raw) {
|
|
5279
5745
|
let v2 = raw.trim();
|
|
@@ -5312,82 +5778,47 @@ var init_versioning = __esm({
|
|
|
5312
5778
|
});
|
|
5313
5779
|
|
|
5314
5780
|
// ../core/src/backend.ts
|
|
5315
|
-
import
|
|
5316
|
-
import path2 from "node:path";
|
|
5317
|
-
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
5781
|
+
import path3 from "node:path";
|
|
5318
5782
|
function firstString(...vals) {
|
|
5319
5783
|
for (const v2 of vals) {
|
|
5320
5784
|
if (typeof v2 === "string" && v2.trim() !== "") return v2;
|
|
5321
5785
|
}
|
|
5322
5786
|
return void 0;
|
|
5323
5787
|
}
|
|
5324
|
-
async function pathExists(p2) {
|
|
5325
|
-
try {
|
|
5326
|
-
await fs2.stat(p2);
|
|
5327
|
-
return true;
|
|
5328
|
-
} catch {
|
|
5329
|
-
return false;
|
|
5330
|
-
}
|
|
5331
|
-
}
|
|
5332
|
-
async function pathIsFile(p2) {
|
|
5333
|
-
try {
|
|
5334
|
-
return (await fs2.stat(p2)).isFile();
|
|
5335
|
-
} catch {
|
|
5336
|
-
return false;
|
|
5337
|
-
}
|
|
5338
|
-
}
|
|
5339
5788
|
function isAbsentFileError(err) {
|
|
5340
5789
|
const code3 = err?.code;
|
|
5341
|
-
return code3 === "ENOENT" || code3 === "EISDIR";
|
|
5342
|
-
}
|
|
5343
|
-
|
|
5344
|
-
const
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
await fs2.writeFile(tmp, content3);
|
|
5351
|
-
}
|
|
5352
|
-
await fs2.rename(tmp, filePath);
|
|
5790
|
+
return code3 === "ENOENT" || code3 === "ENOTDIR" || code3 === "EISDIR";
|
|
5791
|
+
}
|
|
5792
|
+
function notFound(root, rel) {
|
|
5793
|
+
const target = path3.join(root, rel);
|
|
5794
|
+
const err = new Error(`ENOENT: no such file or directory, open '${target}'`);
|
|
5795
|
+
err.code = "ENOENT";
|
|
5796
|
+
err.syscall = "open";
|
|
5797
|
+
err.path = target;
|
|
5798
|
+
return err;
|
|
5353
5799
|
}
|
|
5354
|
-
async function
|
|
5800
|
+
async function readBytes(handle) {
|
|
5355
5801
|
try {
|
|
5356
|
-
return await
|
|
5357
|
-
} catch {
|
|
5358
|
-
return
|
|
5802
|
+
return await nodeFilesystemIdentityPort.readAll(handle);
|
|
5803
|
+
} catch (err) {
|
|
5804
|
+
if (isAbsentFileError(err)) return null;
|
|
5805
|
+
throw err;
|
|
5359
5806
|
}
|
|
5360
5807
|
}
|
|
5361
|
-
async function
|
|
5362
|
-
const
|
|
5363
|
-
const entries = await safeReaddir(abs);
|
|
5808
|
+
async function walkFiles(root, keep, sub = "") {
|
|
5809
|
+
const entries = await nodeFilesystemIdentityPort.entries(path3.join(root, sub)) ?? [];
|
|
5364
5810
|
const out = [];
|
|
5365
5811
|
for (const entry of entries) {
|
|
5366
5812
|
if (entry.name.startsWith(".")) continue;
|
|
5367
5813
|
const rel = sub === "" ? entry.name : `${sub}/${entry.name}`;
|
|
5368
|
-
if (entry.
|
|
5369
|
-
out.push(...await
|
|
5370
|
-
} else if (entry.
|
|
5814
|
+
if (entry.kind === "directory") {
|
|
5815
|
+
out.push(...await walkFiles(root, keep, rel));
|
|
5816
|
+
} else if (entry.kind === "file" && keep(entry.name)) {
|
|
5371
5817
|
out.push(rel);
|
|
5372
5818
|
}
|
|
5373
5819
|
}
|
|
5374
5820
|
return out;
|
|
5375
5821
|
}
|
|
5376
|
-
async function walkBlobs(root, sub = "") {
|
|
5377
|
-
const abs = path2.join(root, sub);
|
|
5378
|
-
const entries = await safeReaddir(abs);
|
|
5379
|
-
const out = [];
|
|
5380
|
-
for (const entry of entries) {
|
|
5381
|
-
if (entry.name.startsWith(".")) continue;
|
|
5382
|
-
const rel = sub === "" ? entry.name : `${sub}/${entry.name}`;
|
|
5383
|
-
if (entry.isDirectory()) {
|
|
5384
|
-
out.push(...await walkBlobs(root, rel));
|
|
5385
|
-
} else if (entry.isFile() && !entry.name.toLowerCase().endsWith(".md")) {
|
|
5386
|
-
out.push(toPosix(rel));
|
|
5387
|
-
}
|
|
5388
|
-
}
|
|
5389
|
-
return out;
|
|
5390
|
-
}
|
|
5391
5822
|
function reservedPath(dir, name) {
|
|
5392
5823
|
const d2 = toPosix(dir).replace(/^\.?\//, "").replace(/\/$/, "");
|
|
5393
5824
|
return d2 === "" ? name : `${d2}/${name}`;
|
|
@@ -5402,93 +5833,25 @@ var init_backend = __esm({
|
|
|
5402
5833
|
init_content_type();
|
|
5403
5834
|
init_paths();
|
|
5404
5835
|
init_errors();
|
|
5405
|
-
|
|
5836
|
+
init_filesystem_identity();
|
|
5406
5837
|
init_mutation_attribution();
|
|
5407
5838
|
init_versioning();
|
|
5408
|
-
FilesystemBackend = class
|
|
5409
|
-
root;
|
|
5839
|
+
FilesystemBackend = class {
|
|
5840
|
+
#root;
|
|
5410
5841
|
/**
|
|
5411
|
-
*
|
|
5412
|
-
*
|
|
5413
|
-
*
|
|
5414
|
-
* `write()`/`writeReserved()`'s compare-and-swap is check-then-write across two
|
|
5415
|
-
* `await`s (read the current version, then `atomicWrite`): without serialization, N
|
|
5416
|
-
* concurrent writers targeting the SAME file can all observe the SAME pre-write
|
|
5417
|
-
* version, all pass the CAS check, and all proceed to write — every writer reports
|
|
5418
|
-
* success, only the last write survives, and no `VersionConflict` is ever thrown to
|
|
5419
|
-
* trigger a caller's retry loop. Queuing each write's full check-then-write critical
|
|
5420
|
-
* section behind this per-key chain avoids needless polling between local callers.
|
|
5421
|
-
* `withFilesystemMutationLock` then makes the same critical section exclusive across
|
|
5422
|
-
* independent processes, so at most one writer can satisfy a given version premise.
|
|
5423
|
-
* Reads stay lock-free because target replacement is atomic.
|
|
5424
|
-
*
|
|
5425
|
-
* STATIC, not per-instance: `core/src/bundle.ts`'s `backendFor()` constructs a FRESH
|
|
5426
|
-
* `FilesystemBackend` on every bundle operation when the caller passes a bare
|
|
5427
|
-
* `{ root }` (no explicit `backend`) — which is the shape `serve`/`openBundle` use
|
|
5428
|
-
* for every request. An instance-level map would give every concurrent write its own
|
|
5429
|
-
* empty lock table and serialize nothing; a process-wide map keyed by the RESOLVED
|
|
5430
|
-
* absolute path is what actually makes concurrent writers to the same physical file
|
|
5431
|
-
* queue behind each other, regardless of how many `FilesystemBackend` objects front
|
|
5432
|
-
* them. Different bundle roots never collide because their resolved paths differ, so
|
|
5433
|
-
* sharing the map across instances cannot cross-serialize unrelated bundles.
|
|
5434
|
-
*
|
|
5435
|
-
* Keyed by the RESOLVED absolute path so both `write()` (concept documents) and
|
|
5436
|
-
* `writeReserved()` (`index.md`/`log.md`) share one queue per physical file — the
|
|
5437
|
-
* only thing that actually needs serializing is contention on the same bytes.
|
|
5438
|
-
*
|
|
5439
|
-
* The external runtime lock is used for conditional and unconditional mutations alike: an
|
|
5440
|
-
* unconditional writer must not move the target between another process's version
|
|
5441
|
-
* check and write. A crash leftover fails closed with inspectable owner metadata.
|
|
5842
|
+
* The root is resolved once here: a relative root would otherwise re-resolve against the
|
|
5843
|
+
* process's current directory on every operation, so a later `chdir` would silently move the
|
|
5844
|
+
* bundle and derive a different identity key.
|
|
5442
5845
|
*/
|
|
5443
|
-
static locks = /* @__PURE__ */ new Map();
|
|
5444
5846
|
constructor(root) {
|
|
5445
|
-
this
|
|
5446
|
-
}
|
|
5447
|
-
/**
|
|
5448
|
-
* Run `fn` after any prior write queued under `key` has settled (success or
|
|
5449
|
-
* failure), guaranteeing at most one in-flight critical section per key at a time —
|
|
5450
|
-
* across ALL `FilesystemBackend` instances in this process (see `locks`'s doc
|
|
5451
|
-
* comment on why the map is static). Must be called with NO prior `await` in the
|
|
5452
|
-
* caller since acquiring the tail from the map and re-registering it happen
|
|
5453
|
-
* synchronously here — that is what makes concurrent callers queue in call order
|
|
5454
|
-
* rather than racing each other for the map entry. The chain entry is deleted once
|
|
5455
|
-
* it drains and no newer waiter has replaced it, so a long-lived `serve` process
|
|
5456
|
-
* does not accumulate one `Map` entry per ever-written file.
|
|
5457
|
-
*/
|
|
5458
|
-
withLock(key, fn) {
|
|
5459
|
-
const locks = _FilesystemBackend.locks;
|
|
5460
|
-
const tail = locks.get(key) ?? Promise.resolve();
|
|
5461
|
-
const locked = () => withFilesystemMutationLock(key, fn, { portableRoot: this.root });
|
|
5462
|
-
const run = tail.then(locked, locked);
|
|
5463
|
-
const settled = run.then(
|
|
5464
|
-
() => void 0,
|
|
5465
|
-
() => void 0
|
|
5466
|
-
);
|
|
5467
|
-
locks.set(key, settled);
|
|
5468
|
-
void settled.then(() => {
|
|
5469
|
-
if (locks.get(key) === settled) locks.delete(key);
|
|
5470
|
-
});
|
|
5471
|
-
return run;
|
|
5472
|
-
}
|
|
5473
|
-
/**
|
|
5474
|
-
* Join `rel` onto the bundle root and resolve it. Belt-and-suspenders containment: even
|
|
5475
|
-
* though every caller here first validates the id/dir it derived `rel` from
|
|
5476
|
-
* ({@link assertSafeConceptId} / {@link assertSafeReservedDir}), this asserts the
|
|
5477
|
-
* REALIZED path still lands inside the bundle root before any `fs` call touches it, so
|
|
5478
|
-
* a future caller that skips the upstream guard cannot escape the bundle either.
|
|
5479
|
-
*/
|
|
5480
|
-
abs(rel) {
|
|
5481
|
-
const rootResolved = path2.resolve(this.root);
|
|
5482
|
-
const resolved = path2.resolve(rootResolved, rel);
|
|
5483
|
-
if (resolved !== rootResolved && !resolved.startsWith(rootResolved + path2.sep)) {
|
|
5484
|
-
throw new InvalidInputError(`Path '${rel}' resolves outside the bundle root.`);
|
|
5485
|
-
}
|
|
5486
|
-
return resolved;
|
|
5847
|
+
this.#root = path3.resolve(root);
|
|
5487
5848
|
}
|
|
5488
5849
|
async read(id) {
|
|
5489
5850
|
assertSafeConceptId(id);
|
|
5490
5851
|
const rel = pathFromConceptId(id);
|
|
5491
|
-
const
|
|
5852
|
+
const observed = await observeExact(nodeFilesystemIdentityPort, this.#root, rel, readBytes);
|
|
5853
|
+
if (observed.state === "absent") throw notFound(this.#root, rel);
|
|
5854
|
+
const raw = observed.value.toString("utf8");
|
|
5492
5855
|
const { frontmatter, body } = parseMarkdown(raw, rel);
|
|
5493
5856
|
return { doc: { id, frontmatter, body }, version: versionOfBytes(raw) };
|
|
5494
5857
|
}
|
|
@@ -5498,65 +5861,60 @@ var init_backend = __esm({
|
|
|
5498
5861
|
for (const id of ids) out.push(await this.read(id));
|
|
5499
5862
|
return out;
|
|
5500
5863
|
}
|
|
5501
|
-
/** Current version of the file at the already-resolved `absPath`, or `null` if absent. */
|
|
5502
|
-
async currentVersionAt(absPath) {
|
|
5503
|
-
try {
|
|
5504
|
-
return versionOfBytes(await fs2.readFile(absPath, "utf8"));
|
|
5505
|
-
} catch (err) {
|
|
5506
|
-
if (isAbsentFileError(err)) return null;
|
|
5507
|
-
throw err;
|
|
5508
|
-
}
|
|
5509
|
-
}
|
|
5510
5864
|
async write(id, doc2, options2 = {}) {
|
|
5511
5865
|
assertSafeConceptId(id);
|
|
5512
5866
|
const raw = stringifyDoc(doc2.frontmatter, doc2.body ?? "");
|
|
5513
|
-
const
|
|
5514
|
-
return
|
|
5867
|
+
const rel = pathFromConceptId(id);
|
|
5868
|
+
return mutateExact(nodeFilesystemIdentityPort, this.#root, rel, async (target) => {
|
|
5515
5869
|
if (options2.expectedVersion !== void 0) {
|
|
5516
|
-
const
|
|
5870
|
+
const bytes = await target.current();
|
|
5871
|
+
const current = bytes === null ? null : versionOfBytes(bytes.toString("utf8"));
|
|
5517
5872
|
if (current !== options2.expectedVersion) {
|
|
5518
5873
|
throw new VersionConflict(id, options2.expectedVersion, current);
|
|
5519
5874
|
}
|
|
5520
5875
|
}
|
|
5521
|
-
await
|
|
5876
|
+
await target.replace(Buffer.from(raw, "utf8"));
|
|
5522
5877
|
return versionOfBytes(raw);
|
|
5523
5878
|
});
|
|
5524
5879
|
}
|
|
5525
5880
|
async delete(id, options2 = {}) {
|
|
5526
5881
|
assertSafeConceptId(id);
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5882
|
+
return mutateExact(nodeFilesystemIdentityPort, this.#root, pathFromConceptId(id), async (target) => {
|
|
5883
|
+
const bytes = await target.current();
|
|
5884
|
+
if (bytes === null) return false;
|
|
5885
|
+
const current = versionOfBytes(bytes.toString("utf8"));
|
|
5531
5886
|
if (options2.expectedVersion !== void 0 && current !== options2.expectedVersion) {
|
|
5532
5887
|
throw new VersionConflict(id, options2.expectedVersion, current);
|
|
5533
5888
|
}
|
|
5534
|
-
await
|
|
5889
|
+
await target.remove();
|
|
5535
5890
|
return true;
|
|
5536
5891
|
});
|
|
5537
5892
|
}
|
|
5538
5893
|
async versions(id) {
|
|
5539
5894
|
assertSafeConceptId(id);
|
|
5540
|
-
const
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
|
|
5895
|
+
const rel = pathFromConceptId(id);
|
|
5896
|
+
const observed = await observeExact(nodeFilesystemIdentityPort, this.#root, rel, async (handle, target) => {
|
|
5897
|
+
try {
|
|
5898
|
+
const bytes = await nodeFilesystemIdentityPort.readAll(handle);
|
|
5899
|
+
const { mtime: mtime2 } = await nodeFilesystemIdentityPort.stat(target);
|
|
5900
|
+
return { raw: bytes.toString("utf8"), mtime: mtime2 };
|
|
5901
|
+
} catch {
|
|
5902
|
+
return null;
|
|
5903
|
+
}
|
|
5904
|
+
});
|
|
5905
|
+
if (observed.state === "absent") return [];
|
|
5906
|
+
const { raw, mtime } = observed.value;
|
|
5907
|
+
const { frontmatter } = parseMarkdown(raw, rel);
|
|
5550
5908
|
const actor = mutationActorFromFrontmatter(frontmatter) ?? defaultActor();
|
|
5551
5909
|
const timestamp = firstString(frontmatter.timestamp) ?? mtime.toISOString();
|
|
5552
5910
|
return [{ version: versionOfBytes(raw), actor, timestamp }];
|
|
5553
5911
|
}
|
|
5554
5912
|
async exists(id) {
|
|
5555
5913
|
assertSafeConceptId(id);
|
|
5556
|
-
return
|
|
5914
|
+
return (await probeExact(nodeFilesystemIdentityPort, this.#root, pathFromConceptId(id))).state === "exact";
|
|
5557
5915
|
}
|
|
5558
5916
|
async list(prefix) {
|
|
5559
|
-
const files = await
|
|
5917
|
+
const files = await walkFiles(this.#root, (name) => name.endsWith(".md"));
|
|
5560
5918
|
const ids = [];
|
|
5561
5919
|
for (const rel of files) {
|
|
5562
5920
|
if (isReservedFile(rel)) continue;
|
|
@@ -5575,80 +5933,69 @@ var init_backend = __esm({
|
|
|
5575
5933
|
}
|
|
5576
5934
|
async readReserved(dir, name) {
|
|
5577
5935
|
assertSafeReservedDir(dir);
|
|
5578
|
-
const
|
|
5579
|
-
if (
|
|
5580
|
-
const content3 =
|
|
5936
|
+
const observed = await observeExact(nodeFilesystemIdentityPort, this.#root, reservedPath(dir, name), readBytes);
|
|
5937
|
+
if (observed.state === "absent") return null;
|
|
5938
|
+
const content3 = observed.value.toString("utf8");
|
|
5581
5939
|
return { content: content3, version: versionOfBytes(content3) };
|
|
5582
5940
|
}
|
|
5583
5941
|
async writeReserved(dir, name, content3, options2 = {}) {
|
|
5584
5942
|
assertSafeReservedDir(dir);
|
|
5585
5943
|
const rel = reservedPath(dir, name);
|
|
5586
|
-
|
|
5587
|
-
return this.withLock(target, async () => {
|
|
5944
|
+
return mutateExact(nodeFilesystemIdentityPort, this.#root, rel, async (target) => {
|
|
5588
5945
|
if (options2.expectedVersion !== void 0) {
|
|
5589
|
-
const
|
|
5946
|
+
const bytes = await target.current();
|
|
5947
|
+
const current = bytes === null ? null : versionOfBytes(bytes.toString("utf8"));
|
|
5590
5948
|
if (current !== options2.expectedVersion) {
|
|
5591
5949
|
throw new VersionConflict(rel, options2.expectedVersion, current);
|
|
5592
5950
|
}
|
|
5593
5951
|
}
|
|
5594
|
-
await
|
|
5952
|
+
await target.replace(Buffer.from(content3, "utf8"));
|
|
5595
5953
|
return versionOfBytes(content3);
|
|
5596
5954
|
});
|
|
5597
5955
|
}
|
|
5598
5956
|
// ── blobs: opaque bytes + a content-type ──────────────────────────────────
|
|
5599
|
-
/** Current RAW-BYTES version of the blob at the already-resolved `absPath`, or `null` if absent. Reads with NO encoding — reusing the doc-shaped `currentVersionAt` would corrupt binary content via UTF-8 decoding (B1). */
|
|
5600
|
-
async currentBlobVersionAt(absPath) {
|
|
5601
|
-
try {
|
|
5602
|
-
return blobVersion(await fs2.readFile(absPath));
|
|
5603
|
-
} catch (err) {
|
|
5604
|
-
if (isAbsentFileError(err)) return null;
|
|
5605
|
-
throw err;
|
|
5606
|
-
}
|
|
5607
|
-
}
|
|
5608
5957
|
async readBlob(key) {
|
|
5609
5958
|
assertSafeBlobKey(key);
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
} catch (err) {
|
|
5614
|
-
if (isAbsentFileError(err)) return null;
|
|
5615
|
-
throw err;
|
|
5616
|
-
}
|
|
5959
|
+
const observed = await observeExact(nodeFilesystemIdentityPort, this.#root, key, readBytes);
|
|
5960
|
+
if (observed.state === "absent") return null;
|
|
5961
|
+
const bytes = observed.value;
|
|
5617
5962
|
return { bytes, contentType: resolveContentType(key), version: blobVersion(bytes) };
|
|
5618
5963
|
}
|
|
5619
5964
|
async writeBlob(key, bytes, _contentType, options2 = {}) {
|
|
5620
5965
|
assertSafeBlobKey(key);
|
|
5621
|
-
|
|
5622
|
-
return this.withLock(target, async () => {
|
|
5966
|
+
return mutateExact(nodeFilesystemIdentityPort, this.#root, key, async (target) => {
|
|
5623
5967
|
if (options2.expectedVersion !== void 0) {
|
|
5624
|
-
const
|
|
5968
|
+
const existing = await target.current();
|
|
5969
|
+
const current = existing === null ? null : blobVersion(existing);
|
|
5625
5970
|
if (current !== options2.expectedVersion) {
|
|
5626
5971
|
throw new VersionConflict(key, options2.expectedVersion, current);
|
|
5627
5972
|
}
|
|
5628
5973
|
}
|
|
5629
|
-
await
|
|
5974
|
+
await target.replace(bytes);
|
|
5630
5975
|
return blobVersion(bytes);
|
|
5631
5976
|
});
|
|
5632
5977
|
}
|
|
5633
5978
|
async deleteBlob(key, options2 = {}) {
|
|
5634
5979
|
assertSafeBlobKey(key);
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5980
|
+
return mutateExact(nodeFilesystemIdentityPort, this.#root, key, async (target) => {
|
|
5981
|
+
const existing = await target.current();
|
|
5982
|
+
if (existing === null) return false;
|
|
5983
|
+
const current = blobVersion(existing);
|
|
5639
5984
|
if (options2.expectedVersion !== void 0 && current !== options2.expectedVersion) {
|
|
5640
5985
|
throw new VersionConflict(key, options2.expectedVersion, current);
|
|
5641
5986
|
}
|
|
5642
|
-
await
|
|
5987
|
+
await target.remove();
|
|
5643
5988
|
return true;
|
|
5644
5989
|
});
|
|
5645
5990
|
}
|
|
5646
5991
|
async existsBlob(key) {
|
|
5647
5992
|
assertSafeBlobKey(key);
|
|
5648
|
-
|
|
5993
|
+
const observed = await probeExact(nodeFilesystemIdentityPort, this.#root, key);
|
|
5994
|
+
return observed.state === "exact" && observed.value.kind === "file";
|
|
5649
5995
|
}
|
|
5650
5996
|
async listBlobs(prefix) {
|
|
5651
|
-
const
|
|
5997
|
+
const files = await walkFiles(this.#root, (name) => !name.toLowerCase().endsWith(".md"));
|
|
5998
|
+
const keys = files.map(toPosix);
|
|
5652
5999
|
const filtered = prefix ? keys.filter((k2) => k2.startsWith(prefix)) : keys;
|
|
5653
6000
|
filtered.sort((a, b) => a.localeCompare(b));
|
|
5654
6001
|
return filtered;
|
|
@@ -5911,7 +6258,7 @@ var init_query_filter = __esm({
|
|
|
5911
6258
|
});
|
|
5912
6259
|
|
|
5913
6260
|
// ../core/src/bundle.ts
|
|
5914
|
-
import
|
|
6261
|
+
import path4 from "node:path";
|
|
5915
6262
|
function backendFor(bundle) {
|
|
5916
6263
|
return bundle.backend ?? new FilesystemBackend(bundle.root);
|
|
5917
6264
|
}
|
|
@@ -5932,10 +6279,10 @@ function resolveOkfAuthoringVersion(requested) {
|
|
|
5932
6279
|
}
|
|
5933
6280
|
async function initBundle(root, options2 = {}) {
|
|
5934
6281
|
const okfVersion = resolveOkfAuthoringVersion(options2.okfVersion);
|
|
5935
|
-
const resolved =
|
|
6282
|
+
const resolved = path4.resolve(root);
|
|
5936
6283
|
const backend = new FilesystemBackend(resolved);
|
|
5937
6284
|
if (options2.expectNew || await backend.readReserved("", "index.md") === null) {
|
|
5938
|
-
const name =
|
|
6285
|
+
const name = path4.basename(resolved);
|
|
5939
6286
|
const body = `${GENERATED_INDEX_MARKER}
|
|
5940
6287
|
# ${name}
|
|
5941
6288
|
|
|
@@ -6240,7 +6587,7 @@ var init_freshness = __esm({
|
|
|
6240
6587
|
function snapshot(value) {
|
|
6241
6588
|
return structuredClone(value);
|
|
6242
6589
|
}
|
|
6243
|
-
function
|
|
6590
|
+
function notFound2(id) {
|
|
6244
6591
|
const err = new Error(`no concept document '${id}'`);
|
|
6245
6592
|
err.code = "ENOENT";
|
|
6246
6593
|
return err;
|
|
@@ -6268,7 +6615,7 @@ var init_memory_backend = __esm({
|
|
|
6268
6615
|
async read(id) {
|
|
6269
6616
|
assertSafeConceptId(id);
|
|
6270
6617
|
const head = this.chains.get(id)?.[0];
|
|
6271
|
-
if (!head) throw
|
|
6618
|
+
if (!head) throw notFound2(id);
|
|
6272
6619
|
return { doc: snapshot(head.doc), version: head.version };
|
|
6273
6620
|
}
|
|
6274
6621
|
async readMany(ids) {
|
|
@@ -6387,7 +6734,7 @@ var init_memory_backend = __esm({
|
|
|
6387
6734
|
});
|
|
6388
6735
|
|
|
6389
6736
|
// ../core/src/remote-backend.ts
|
|
6390
|
-
function
|
|
6737
|
+
function notFound3(id) {
|
|
6391
6738
|
const err = new Error(`no concept document '${id}'`);
|
|
6392
6739
|
err.code = "ENOENT";
|
|
6393
6740
|
return err;
|
|
@@ -6510,7 +6857,7 @@ var init_remote_backend = __esm({
|
|
|
6510
6857
|
async read(id) {
|
|
6511
6858
|
assertSafeConceptId(id);
|
|
6512
6859
|
const res = await this.send(`/docs/${encodeId(id)}`, { method: "GET" });
|
|
6513
|
-
if (res.status === 404) throw
|
|
6860
|
+
if (res.status === 404) throw notFound3(id);
|
|
6514
6861
|
if (!res.ok) throw await this.toError(res, id);
|
|
6515
6862
|
const version2 = extractVersion(res, `GET /docs/${id}`);
|
|
6516
6863
|
const payload = await res.json();
|
|
@@ -6531,7 +6878,7 @@ var init_remote_backend = __esm({
|
|
|
6531
6878
|
missing2 = envelope.error.details?.missing ?? [];
|
|
6532
6879
|
} catch {
|
|
6533
6880
|
}
|
|
6534
|
-
throw
|
|
6881
|
+
throw notFound3(missing2[0] ?? ids[0]);
|
|
6535
6882
|
}
|
|
6536
6883
|
if (!res.ok) throw await this.toError(res, ids[0] ?? "");
|
|
6537
6884
|
const payload = await res.json();
|
|
@@ -6684,6 +7031,7 @@ var init_remote_backend = __esm({
|
|
|
6684
7031
|
// Content-type rides `Content-Type`; the version rides `X-Version`/`ETag` (extractVersion),
|
|
6685
7032
|
// exactly like docs.
|
|
6686
7033
|
async readBlob(key) {
|
|
7034
|
+
assertSafeBlobKey(key);
|
|
6687
7035
|
const res = await this.send(`/blobs/${encodeBlobKey(key)}`, { method: "GET" });
|
|
6688
7036
|
if (res.status === 404) return null;
|
|
6689
7037
|
if (!res.ok) throw await this.toError(res, key);
|
|
@@ -6693,6 +7041,7 @@ var init_remote_backend = __esm({
|
|
|
6693
7041
|
return { bytes, contentType, version: version2 };
|
|
6694
7042
|
}
|
|
6695
7043
|
async writeBlob(key, bytes, contentType, options2 = {}) {
|
|
7044
|
+
assertSafeBlobKey(key);
|
|
6696
7045
|
assertValidExpectedVersion(options2.expectedVersion);
|
|
6697
7046
|
const headers = {};
|
|
6698
7047
|
if (contentType) headers["content-type"] = contentType;
|
|
@@ -6710,6 +7059,7 @@ var init_remote_backend = __esm({
|
|
|
6710
7059
|
}
|
|
6711
7060
|
/** `DELETE /blobs/{key}`, mirroring `delete`'s `If-Match`/no-404/no-actor posture exactly. */
|
|
6712
7061
|
async deleteBlob(key, options2 = {}) {
|
|
7062
|
+
assertSafeBlobKey(key);
|
|
6713
7063
|
assertValidExpectedVersion(options2.expectedVersion);
|
|
6714
7064
|
const headers = {};
|
|
6715
7065
|
if (options2.expectedVersion !== void 0) headers["If-Match"] = options2.expectedVersion;
|
|
@@ -6719,6 +7069,7 @@ var init_remote_backend = __esm({
|
|
|
6719
7069
|
return payload.deleted;
|
|
6720
7070
|
}
|
|
6721
7071
|
async existsBlob(key) {
|
|
7072
|
+
assertSafeBlobKey(key);
|
|
6722
7073
|
const res = await this.send(`/blobs/${encodeBlobKey(key)}`, { method: "HEAD" });
|
|
6723
7074
|
if (res.status === 404) return false;
|
|
6724
7075
|
if (!res.ok) throw await this.toError(res, key);
|
|
@@ -6749,7 +7100,14 @@ var init_remote_backend = __esm({
|
|
|
6749
7100
|
async function versionedMutation(opts) {
|
|
6750
7101
|
const maxAttempts = opts.maxAttempts ?? CAS_MAX_ATTEMPTS;
|
|
6751
7102
|
for (let attempt = 0; ; attempt++) {
|
|
6752
|
-
|
|
7103
|
+
let fresh;
|
|
7104
|
+
try {
|
|
7105
|
+
fresh = await opts.read();
|
|
7106
|
+
} catch (err) {
|
|
7107
|
+
if (err instanceof ConcurrentReplacementError && attempt < maxAttempts - 1) continue;
|
|
7108
|
+
throw err;
|
|
7109
|
+
}
|
|
7110
|
+
const { state, version: version2 } = fresh;
|
|
6753
7111
|
const decision = await opts.decide(state, attempt);
|
|
6754
7112
|
if (decision.action === "done") {
|
|
6755
7113
|
return { result: decision.result, version: version2, wrote: false };
|
|
@@ -6769,6 +7127,7 @@ var init_mutation = __esm({
|
|
|
6769
7127
|
"use strict";
|
|
6770
7128
|
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
6771
7129
|
init_define_SUPERBEE_UPDATE_POLICY();
|
|
7130
|
+
init_errors();
|
|
6772
7131
|
init_versioning();
|
|
6773
7132
|
CAS_MAX_ATTEMPTS = 5;
|
|
6774
7133
|
}
|
|
@@ -6879,13 +7238,13 @@ function describeShape(value) {
|
|
|
6879
7238
|
if (typeof value === "object") return "an object";
|
|
6880
7239
|
return typeof value;
|
|
6881
7240
|
}
|
|
6882
|
-
function toStringArrayLenient(value,
|
|
7241
|
+
function toStringArrayLenient(value, path29, docId, warnings) {
|
|
6883
7242
|
if (!Array.isArray(value)) {
|
|
6884
7243
|
if (value !== void 0) {
|
|
6885
7244
|
warnings.push({
|
|
6886
7245
|
code: "KIND_CONVENTION_BAD_SHAPE",
|
|
6887
|
-
message: `kind convention '${docId}' has a non-list '${
|
|
6888
|
-
field:
|
|
7246
|
+
message: `kind convention '${docId}' has a non-list '${path29}' (${describeShape(value)}; expected a list of strings); ignoring it.`,
|
|
7247
|
+
field: path29,
|
|
6889
7248
|
severity: "warning"
|
|
6890
7249
|
});
|
|
6891
7250
|
}
|
|
@@ -6898,8 +7257,8 @@ function toStringArrayLenient(value, path28, docId, warnings) {
|
|
|
6898
7257
|
} else {
|
|
6899
7258
|
warnings.push({
|
|
6900
7259
|
code: "KIND_CONVENTION_BAD_MEMBER",
|
|
6901
|
-
message: `kind convention '${docId}' has a non-scalar member (${describeShape(v2)}) in '${
|
|
6902
|
-
field:
|
|
7260
|
+
message: `kind convention '${docId}' has a non-scalar member (${describeShape(v2)}) in '${path29}'; skipping it.`,
|
|
7261
|
+
field: path29,
|
|
6903
7262
|
severity: "warning"
|
|
6904
7263
|
});
|
|
6905
7264
|
}
|
|
@@ -7241,7 +7600,7 @@ function parseConventionDoc(doc2) {
|
|
|
7241
7600
|
});
|
|
7242
7601
|
}
|
|
7243
7602
|
}
|
|
7244
|
-
const
|
|
7603
|
+
const path29 = typeof fm.path === "string" && fm.path.trim() !== "" ? fm.path.trim() : void 0;
|
|
7245
7604
|
const freshnessHorizon = typeof fm.freshness_horizon === "string" && fm.freshness_horizon.trim() !== "" ? fm.freshness_horizon.trim() : void 0;
|
|
7246
7605
|
const browseCollapsed = fm.browse_collapsed === true ? true : void 0;
|
|
7247
7606
|
const kind2 = {
|
|
@@ -7251,7 +7610,7 @@ function parseConventionDoc(doc2) {
|
|
|
7251
7610
|
fields: { required: required2, optional: optional2, values, valueDescriptions, terminal, descriptions }
|
|
7252
7611
|
};
|
|
7253
7612
|
if (description !== void 0) kind2.description = description;
|
|
7254
|
-
if (
|
|
7613
|
+
if (path29 !== void 0) kind2.path = path29;
|
|
7255
7614
|
if (links !== void 0) kind2.links = links;
|
|
7256
7615
|
if (linkDescriptions !== void 0) kind2.linkDescriptions = linkDescriptions;
|
|
7257
7616
|
if (expectsInbound !== void 0) kind2.expectsInbound = expectsInbound;
|
|
@@ -8203,11 +8562,11 @@ import {
|
|
|
8203
8562
|
writeFileSync as writeFileSync2
|
|
8204
8563
|
} from "node:fs";
|
|
8205
8564
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
8206
|
-
import
|
|
8565
|
+
import path5 from "node:path";
|
|
8207
8566
|
function recognizedBundlePath(name, sourcePath) {
|
|
8208
8567
|
try {
|
|
8209
8568
|
const link3 = lstatSync2(sourcePath);
|
|
8210
|
-
if (!statSync2(sourcePath).isDirectory() || !statSync2(
|
|
8569
|
+
if (!statSync2(sourcePath).isDirectory() || !statSync2(path5.join(sourcePath, "index.md")).isFile()) return null;
|
|
8211
8570
|
return { name, sourcePath, realPath: realpathSync4(sourcePath), symlink: link3.isSymbolicLink() };
|
|
8212
8571
|
} catch {
|
|
8213
8572
|
return null;
|
|
@@ -8215,7 +8574,7 @@ function recognizedBundlePath(name, sourcePath) {
|
|
|
8215
8574
|
}
|
|
8216
8575
|
function bundleDirNameForProject(top) {
|
|
8217
8576
|
const matches = BUNDLE_DIRS.flatMap((name) => {
|
|
8218
|
-
const direct =
|
|
8577
|
+
const direct = path5.join(top, name);
|
|
8219
8578
|
return [recognizedBundlePath(name, direct), recognizedBundlePath(name, `${direct}.establish-backup`)].filter((match) => match !== null);
|
|
8220
8579
|
});
|
|
8221
8580
|
const byName = /* @__PURE__ */ new Map();
|
|
@@ -8231,7 +8590,7 @@ function bundleDirNameForProject(top) {
|
|
|
8231
8590
|
return [...aliases].sort((a, b) => Number(a.symlink) - Number(b.symlink))[0].name;
|
|
8232
8591
|
}
|
|
8233
8592
|
const sources = [...byName.values()].map((group) => group[0].sourcePath);
|
|
8234
|
-
const shown = sources.map((source) => `'${
|
|
8593
|
+
const shown = sources.map((source) => `'${path5.relative(top, source)}/'`).join(" and ");
|
|
8235
8594
|
throw new BoardGitError(
|
|
8236
8595
|
"CONFLICT",
|
|
8237
8596
|
`${shown} contain project bundles at ${top} \u2014 refusing to choose between two project bundles`,
|
|
@@ -8240,7 +8599,7 @@ function bundleDirNameForProject(top) {
|
|
|
8240
8599
|
path: top,
|
|
8241
8600
|
phase: "filesystem-bundle-selection",
|
|
8242
8601
|
state: "bundle-directory-conflict",
|
|
8243
|
-
directories: sources.map((source) =>
|
|
8602
|
+
directories: sources.map((source) => path5.relative(top, source))
|
|
8244
8603
|
},
|
|
8245
8604
|
help: "choose the project bundle to keep, then move the other directory outside the repository before retrying"
|
|
8246
8605
|
}
|
|
@@ -8318,10 +8677,10 @@ function identityFlags(dir, actor) {
|
|
|
8318
8677
|
return ["-c", `user.name=${name}`, "-c", `user.email=${slugifyActor(name)}@superbee.invalid`];
|
|
8319
8678
|
}
|
|
8320
8679
|
function hasEnclosingGitMarker(dir) {
|
|
8321
|
-
let current =
|
|
8680
|
+
let current = path5.resolve(dir);
|
|
8322
8681
|
for (; ; ) {
|
|
8323
|
-
if (existsSync(
|
|
8324
|
-
const parent =
|
|
8682
|
+
if (existsSync(path5.join(current, ".git"))) return true;
|
|
8683
|
+
const parent = path5.dirname(current);
|
|
8325
8684
|
if (parent === current) return false;
|
|
8326
8685
|
current = parent;
|
|
8327
8686
|
}
|
|
@@ -8348,7 +8707,7 @@ function repoTopLevel(dir) {
|
|
|
8348
8707
|
}
|
|
8349
8708
|
function worktreeGitPath(boardPath, relative2) {
|
|
8350
8709
|
const raw = mustGit(boardPath, ["rev-parse", "--git-path", relative2]).trim();
|
|
8351
|
-
return
|
|
8710
|
+
return path5.resolve(boardPath, raw);
|
|
8352
8711
|
}
|
|
8353
8712
|
function realOrSame(p2) {
|
|
8354
8713
|
try {
|
|
@@ -8362,7 +8721,7 @@ function gitCommonDir(dir) {
|
|
|
8362
8721
|
if (r2.status !== 0) return null;
|
|
8363
8722
|
const raw = r2.stdout.trim();
|
|
8364
8723
|
if (raw.length === 0) return null;
|
|
8365
|
-
return realOrSame(
|
|
8724
|
+
return realOrSame(path5.isAbsolute(raw) ? raw : path5.resolve(dir, raw));
|
|
8366
8725
|
}
|
|
8367
8726
|
function sameGitCommonDir(a, b) {
|
|
8368
8727
|
const aCommon = gitCommonDir(a);
|
|
@@ -8378,7 +8737,7 @@ function worktreeRootResolvesForOwner(boardPath, ownerTop) {
|
|
|
8378
8737
|
}
|
|
8379
8738
|
function rebaseWasFromBoardBranch(boardPath) {
|
|
8380
8739
|
for (const state of ["rebase-merge", "rebase-apply"]) {
|
|
8381
|
-
const headNamePath =
|
|
8740
|
+
const headNamePath = path5.join(worktreeGitPath(boardPath, state), "head-name");
|
|
8382
8741
|
if (!existsSync(headNamePath)) continue;
|
|
8383
8742
|
try {
|
|
8384
8743
|
if (readFileSync3(headNamePath, "utf8").trim() === `refs/heads/${BOARD_BRANCH}`) return true;
|
|
@@ -8396,13 +8755,13 @@ function repairedWorktreeIsBoard(boardPath, ownerTop) {
|
|
|
8396
8755
|
function isProvisioned(dir) {
|
|
8397
8756
|
const top = repoTopLevel(dir);
|
|
8398
8757
|
if (!top) return false;
|
|
8399
|
-
const boardPath =
|
|
8758
|
+
const boardPath = path5.join(top, bundleDirNameForProject(top));
|
|
8400
8759
|
if (!existsSync(boardPath) || !worktreeRootResolvesForOwner(boardPath, top)) return false;
|
|
8401
8760
|
const branch = runGit(boardPath, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
8402
8761
|
return branch.status === 0 && branch.stdout.trim() === BOARD_BRANCH;
|
|
8403
8762
|
}
|
|
8404
8763
|
function hasWorktreeSignature(dir) {
|
|
8405
|
-
const gitPath =
|
|
8764
|
+
const gitPath = path5.join(dir, ".git");
|
|
8406
8765
|
if (!existsSync(gitPath)) return false;
|
|
8407
8766
|
try {
|
|
8408
8767
|
return statSync2(gitPath).isFile();
|
|
@@ -8482,7 +8841,7 @@ function boardWindowGuidance(top, originConfigured = true, bundleDir = bundleDir
|
|
|
8482
8841
|
};
|
|
8483
8842
|
}
|
|
8484
8843
|
function preShareWindowError(top, boardPath, originConfigured = true) {
|
|
8485
|
-
const base =
|
|
8844
|
+
const base = path5.basename(boardPath);
|
|
8486
8845
|
const bundleDir = BUNDLE_DIRS.includes(base) ? base : bundleDirNameForProject(top);
|
|
8487
8846
|
const guidance = boardWindowGuidance(top, originConfigured, bundleDir);
|
|
8488
8847
|
const details = { path: boardPath, state: guidance.state };
|
|
@@ -8494,7 +8853,7 @@ function preShareWindowError(top, boardPath, originConfigured = true) {
|
|
|
8494
8853
|
return new BoardGitError("RUNTIME", guidance.message, { details, help: guidance.help });
|
|
8495
8854
|
}
|
|
8496
8855
|
function existingDirRefusal(reason, boardPath, top) {
|
|
8497
|
-
const bundleDir =
|
|
8856
|
+
const bundleDir = path5.basename(boardPath);
|
|
8498
8857
|
const messages = {
|
|
8499
8858
|
foreign: {
|
|
8500
8859
|
message: `a non-empty '${bundleDir}' directory already exists at ${boardPath} but is not the shared board checkout \u2014 move it aside, then re-run sync`,
|
|
@@ -8522,7 +8881,7 @@ function provisionBoardWorktree(dir, budget = {}) {
|
|
|
8522
8881
|
const top = repoTopLevel(dir);
|
|
8523
8882
|
if (!top) return { kind: "no_repo" };
|
|
8524
8883
|
const bundleDir = bundleDirNameForProject(top);
|
|
8525
|
-
const boardPath =
|
|
8884
|
+
const boardPath = path5.join(top, bundleDir);
|
|
8526
8885
|
const withIgnoreCoverage = (outcome) => {
|
|
8527
8886
|
if (!budget.ensureIgnore) return outcome;
|
|
8528
8887
|
const gitignore = ensureBoardGitignoreWorkingTree(top);
|
|
@@ -8765,7 +9124,7 @@ function snapshotFilesystemFiles(root) {
|
|
|
8765
9124
|
{ details: { nested_git_paths: [relPath] } }
|
|
8766
9125
|
);
|
|
8767
9126
|
}
|
|
8768
|
-
if (entry.isDirectory()) visit2(
|
|
9127
|
+
if (entry.isDirectory()) visit2(path5.join(dir, entry.name), relPath);
|
|
8769
9128
|
else if (entry.isFile() || entry.isSymbolicLink()) files.push(relPath);
|
|
8770
9129
|
else {
|
|
8771
9130
|
throw new BoardGitError(
|
|
@@ -8787,8 +9146,8 @@ function assertBundleBytesMatchCommit(top, bundlePath, commit) {
|
|
|
8787
9146
|
if (tab < 0) continue;
|
|
8788
9147
|
const [mode, type, oid] = row2.slice(0, tab).split(" ");
|
|
8789
9148
|
const relPath = row2.slice(tab + 1);
|
|
8790
|
-
const absolute =
|
|
8791
|
-
if (!absolute.startsWith(`${
|
|
9149
|
+
const absolute = path5.resolve(bundlePath, relPath);
|
|
9150
|
+
if (!absolute.startsWith(`${path5.resolve(bundlePath)}${path5.sep}`)) {
|
|
8792
9151
|
mismatches.push(relPath);
|
|
8793
9152
|
continue;
|
|
8794
9153
|
}
|
|
@@ -8828,8 +9187,8 @@ function assertBundleBytesMatchCommit(top, bundlePath, commit) {
|
|
|
8828
9187
|
function snapshotBundleCommit(top, bundlePath) {
|
|
8829
9188
|
const gitDir = mustGit(top, ["rev-parse", "--absolute-git-dir"]).trim();
|
|
8830
9189
|
const filesystemFiles = snapshotFilesystemFiles(bundlePath);
|
|
8831
|
-
const scratch = mkdtempSync(
|
|
8832
|
-
const indexFile =
|
|
9190
|
+
const scratch = mkdtempSync(path5.join(tmpdir2(), "aslite-establish-index-"));
|
|
9191
|
+
const indexFile = path5.join(scratch, "index");
|
|
8833
9192
|
const snapshotOptions = { gitDir, workTree: bundlePath, indexFile };
|
|
8834
9193
|
try {
|
|
8835
9194
|
mustGit(bundlePath, ["read-tree", "--empty"], snapshotOptions);
|
|
@@ -8920,8 +9279,8 @@ function fetchRebaseResolving(boardPath, exportDir) {
|
|
|
8920
9279
|
let bodyExportPath = null;
|
|
8921
9280
|
const isDoc = isConceptDocPath(relPath);
|
|
8922
9281
|
if (local.status === 0) {
|
|
8923
|
-
exportPath =
|
|
8924
|
-
mkdirSync2(
|
|
9282
|
+
exportPath = path5.join(exportDir, relPath);
|
|
9283
|
+
mkdirSync2(path5.dirname(exportPath), { recursive: true, mode: 448 });
|
|
8925
9284
|
writeFileSync2(exportPath, local.stdout, { mode: 384 });
|
|
8926
9285
|
if (isDoc) {
|
|
8927
9286
|
try {
|
|
@@ -9015,7 +9374,7 @@ function withIgnoreEntries(content3) {
|
|
|
9015
9374
|
return out;
|
|
9016
9375
|
}
|
|
9017
9376
|
function ensureBoardGitignoreWorkingTree(top) {
|
|
9018
|
-
const gitignorePath =
|
|
9377
|
+
const gitignorePath = path5.join(top, ".gitignore");
|
|
9019
9378
|
let content3 = "";
|
|
9020
9379
|
try {
|
|
9021
9380
|
content3 = readFileSync3(gitignorePath, "utf8");
|
|
@@ -9142,7 +9501,7 @@ var init_porcelain = __esm({
|
|
|
9142
9501
|
|
|
9143
9502
|
// ../board-git/src/flow.ts
|
|
9144
9503
|
import { existsSync as existsSync2, readFileSync as readFileSync4, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
9145
|
-
import
|
|
9504
|
+
import path6 from "node:path";
|
|
9146
9505
|
function refCommit(top, ref) {
|
|
9147
9506
|
const r2 = runGit(top, ["rev-parse", "--verify", "--quiet", ref]);
|
|
9148
9507
|
const value = r2.stdout.trim();
|
|
@@ -9164,7 +9523,7 @@ function resolveOriginRef(boardPath) {
|
|
|
9164
9523
|
function hasLocalOnlyBundle(dir) {
|
|
9165
9524
|
const top = repoTopLevel(dir);
|
|
9166
9525
|
if (!top) return false;
|
|
9167
|
-
return existsSync2(
|
|
9526
|
+
return existsSync2(path6.join(top, bundleDirNameForProject(top), "index.md"));
|
|
9168
9527
|
}
|
|
9169
9528
|
function committedBundleAtHead(top) {
|
|
9170
9529
|
const found = [];
|
|
@@ -9223,7 +9582,7 @@ function annotateLanded(boardPath, conflicts) {
|
|
|
9223
9582
|
}));
|
|
9224
9583
|
}
|
|
9225
9584
|
function markerPath(top, key) {
|
|
9226
|
-
return
|
|
9585
|
+
return path6.join(mustGit(top, ["rev-parse", "--absolute-git-dir"]).trim(), key);
|
|
9227
9586
|
}
|
|
9228
9587
|
function readGitDirMarker(top, key) {
|
|
9229
9588
|
try {
|
|
@@ -9317,7 +9676,7 @@ var init_flow = __esm({
|
|
|
9317
9676
|
});
|
|
9318
9677
|
|
|
9319
9678
|
// ../board-git/src/channel.ts
|
|
9320
|
-
import
|
|
9679
|
+
import path7 from "node:path";
|
|
9321
9680
|
function indeterminateTrackedReason(bundleDir) {
|
|
9322
9681
|
return `'${bundleDir}/' is committed on the current branch, but ${BOARD_REMOTE} could not be checked for a shared '${BOARD_BRANCH}' branch \u2014 refusing to classify: an existing shared board must never be shadowed by guessing in-tree`;
|
|
9323
9682
|
}
|
|
@@ -9348,7 +9707,7 @@ function probeRemoteBoardState(top, budget = {}) {
|
|
|
9348
9707
|
function ownerRegistersBoardWorktree(top, bundleDir) {
|
|
9349
9708
|
const r2 = runGit(top, ["worktree", "list", "--porcelain"]);
|
|
9350
9709
|
if (r2.status !== 0) return false;
|
|
9351
|
-
return r2.stdout.split("\n").some((l) => l.startsWith("worktree ") &&
|
|
9710
|
+
return r2.stdout.split("\n").some((l) => l.startsWith("worktree ") && path7.basename(l.slice("worktree ".length).trim()) === bundleDir);
|
|
9352
9711
|
}
|
|
9353
9712
|
function verifiedForeignBoardRoot(top) {
|
|
9354
9713
|
const folderTree = folderTreeAtHead(top);
|
|
@@ -9361,7 +9720,7 @@ function verifiedForeignBoardRoot(top) {
|
|
|
9361
9720
|
return shas.every((sha) => treeOf(top, sha) !== folderTree);
|
|
9362
9721
|
}
|
|
9363
9722
|
function dualBoardError(boardPath) {
|
|
9364
|
-
const bundleDir =
|
|
9723
|
+
const bundleDir = path7.basename(boardPath);
|
|
9365
9724
|
return new BoardGitError(
|
|
9366
9725
|
"CONFLICT",
|
|
9367
9726
|
`a shared '${BOARD_BRANCH}' branch exists on ${BOARD_REMOTE} AND '${bundleDir}' is committed on the current branch with content that never seeded that branch \u2014 two competing board locations; nothing is safe to adopt automatically`,
|
|
@@ -9376,7 +9735,7 @@ function detectBoardChannel(dir, options2 = {}) {
|
|
|
9376
9735
|
if (!top) return localOnlyChannel();
|
|
9377
9736
|
const committed = committedBundleAtHead(top);
|
|
9378
9737
|
const bundleDir = committed?.bundleDir ?? bundleDirNameForProject(top);
|
|
9379
|
-
const boardPath =
|
|
9738
|
+
const boardPath = path7.join(top, bundleDir);
|
|
9380
9739
|
if (hasWorktreeSignature(boardPath)) {
|
|
9381
9740
|
if (worktreeRootResolvesForOwner(boardPath, top)) return branchChannel();
|
|
9382
9741
|
if (!worktreeRootResolves(boardPath) && ownerRegistersBoardWorktree(top, bundleDir)) return branchChannel();
|
|
@@ -9472,7 +9831,7 @@ var init_diff = __esm({
|
|
|
9472
9831
|
|
|
9473
9832
|
// ../board-git/src/cursor.ts
|
|
9474
9833
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
9475
|
-
import { createHash as
|
|
9834
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
9476
9835
|
import { basename, join as join5, resolve } from "node:path";
|
|
9477
9836
|
function normalizeRemoteUrl(url2) {
|
|
9478
9837
|
let u2 = url2.trim().replace(/\/+$/, "");
|
|
@@ -9493,7 +9852,7 @@ ${resolve(src.checkoutRoot)}`;
|
|
|
9493
9852
|
${resolve(src.root)}`;
|
|
9494
9853
|
}
|
|
9495
9854
|
function keyDigest(key) {
|
|
9496
|
-
return
|
|
9855
|
+
return createHash5("sha256").update(key, "utf8").digest("hex").slice(0, 32);
|
|
9497
9856
|
}
|
|
9498
9857
|
function isRecord3(v2) {
|
|
9499
9858
|
return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
|
|
@@ -9729,7 +10088,7 @@ var init_cursor = __esm({
|
|
|
9729
10088
|
|
|
9730
10089
|
// ../board-git/src/engine.ts
|
|
9731
10090
|
import { existsSync as existsSync3, realpathSync as realpathSync5, statSync as statSync3 } from "node:fs";
|
|
9732
|
-
import
|
|
10091
|
+
import path8 from "node:path";
|
|
9733
10092
|
function realOrSame2(p2) {
|
|
9734
10093
|
try {
|
|
9735
10094
|
return realpathSync5(p2);
|
|
@@ -9742,23 +10101,23 @@ function isLinkedWorktree(p2) {
|
|
|
9742
10101
|
if (r2.status !== 0) return false;
|
|
9743
10102
|
const [gitDirRaw, commonDirRaw] = r2.stdout.trim().split("\n");
|
|
9744
10103
|
if (!gitDirRaw || !commonDirRaw) return false;
|
|
9745
|
-
const commonDir =
|
|
10104
|
+
const commonDir = path8.isAbsolute(commonDirRaw) ? commonDirRaw : path8.resolve(p2, commonDirRaw);
|
|
9746
10105
|
return realOrSame2(gitDirRaw) !== realOrSame2(commonDir);
|
|
9747
10106
|
}
|
|
9748
10107
|
function hasGitFileSignature(p2) {
|
|
9749
10108
|
try {
|
|
9750
|
-
return statSync3(
|
|
10109
|
+
return statSync3(path8.join(p2, ".git")).isFile();
|
|
9751
10110
|
} catch {
|
|
9752
10111
|
return false;
|
|
9753
10112
|
}
|
|
9754
10113
|
}
|
|
9755
10114
|
function retargetStaleBoardInteriorByPath(dir) {
|
|
9756
|
-
let cur =
|
|
10115
|
+
let cur = path8.resolve(dir);
|
|
9757
10116
|
for (; ; ) {
|
|
9758
|
-
if (BUNDLE_DIRS.includes(
|
|
9759
|
-
return
|
|
10117
|
+
if (BUNDLE_DIRS.includes(path8.basename(cur)) && hasGitFileSignature(cur)) {
|
|
10118
|
+
return path8.dirname(cur);
|
|
9760
10119
|
}
|
|
9761
|
-
const parent =
|
|
10120
|
+
const parent = path8.dirname(cur);
|
|
9762
10121
|
if (parent === cur) return null;
|
|
9763
10122
|
cur = parent;
|
|
9764
10123
|
}
|
|
@@ -9766,8 +10125,8 @@ function retargetStaleBoardInteriorByPath(dir) {
|
|
|
9766
10125
|
function retargetBoardInterior(dir) {
|
|
9767
10126
|
try {
|
|
9768
10127
|
const top = repoTopLevel(dir);
|
|
9769
|
-
if (top && BUNDLE_DIRS.includes(
|
|
9770
|
-
return
|
|
10128
|
+
if (top && BUNDLE_DIRS.includes(path8.basename(top)) && isLinkedWorktree(top)) {
|
|
10129
|
+
return path8.dirname(top);
|
|
9771
10130
|
}
|
|
9772
10131
|
} catch {
|
|
9773
10132
|
}
|
|
@@ -9777,7 +10136,7 @@ function healStaleRebaseBeforeProvisioning(dir) {
|
|
|
9777
10136
|
try {
|
|
9778
10137
|
const top = repoTopLevel(dir);
|
|
9779
10138
|
if (!top) return;
|
|
9780
|
-
const candidateBoardPath =
|
|
10139
|
+
const candidateBoardPath = path8.join(top, bundleDirNameForProject(top));
|
|
9781
10140
|
if (!existsSync3(candidateBoardPath)) return;
|
|
9782
10141
|
const boardTop = repoTopLevel(candidateBoardPath);
|
|
9783
10142
|
if (!boardTop || realOrSame2(boardTop) !== realOrSame2(candidateBoardPath)) return;
|
|
@@ -9829,7 +10188,7 @@ var init_engine = __esm({
|
|
|
9829
10188
|
});
|
|
9830
10189
|
|
|
9831
10190
|
// ../board-git/src/autopull.ts
|
|
9832
|
-
import
|
|
10191
|
+
import path9 from "node:path";
|
|
9833
10192
|
import { realpathSync as realpathSync6, statSync as statSync4 } from "node:fs";
|
|
9834
10193
|
function realOrSame3(p2) {
|
|
9835
10194
|
try {
|
|
@@ -9840,21 +10199,21 @@ function realOrSame3(p2) {
|
|
|
9840
10199
|
}
|
|
9841
10200
|
function hasGitFileSignature2(p2) {
|
|
9842
10201
|
try {
|
|
9843
|
-
return statSync4(
|
|
10202
|
+
return statSync4(path9.join(p2, ".git")).isFile();
|
|
9844
10203
|
} catch {
|
|
9845
10204
|
return false;
|
|
9846
10205
|
}
|
|
9847
10206
|
}
|
|
9848
10207
|
function findBoardCandidate(start) {
|
|
9849
|
-
let cur =
|
|
10208
|
+
let cur = path9.resolve(start);
|
|
9850
10209
|
for (; ; ) {
|
|
9851
|
-
if (BUNDLE_DIRS.includes(
|
|
9852
|
-
return { top:
|
|
10210
|
+
if (BUNDLE_DIRS.includes(path9.basename(cur)) && hasGitFileSignature2(cur)) {
|
|
10211
|
+
return { top: path9.dirname(cur), boardPath: cur };
|
|
9853
10212
|
}
|
|
9854
|
-
const candidates = BUNDLE_DIRS.map((name) =>
|
|
10213
|
+
const candidates = BUNDLE_DIRS.map((name) => path9.join(cur, name)).filter(hasGitFileSignature2);
|
|
9855
10214
|
if (candidates.length > 1) return null;
|
|
9856
10215
|
if (candidates[0]) return { top: cur, boardPath: candidates[0] };
|
|
9857
|
-
const parent =
|
|
10216
|
+
const parent = path9.dirname(cur);
|
|
9858
10217
|
if (parent === cur) return null;
|
|
9859
10218
|
cur = parent;
|
|
9860
10219
|
}
|
|
@@ -9898,7 +10257,7 @@ async function maybeAutoPull(deps, dir, opts = {}) {
|
|
|
9898
10257
|
if (!candidate) return "no-board";
|
|
9899
10258
|
const boardPath = candidate.boardPath;
|
|
9900
10259
|
if (opts.requireBoardBundle !== false) {
|
|
9901
|
-
const root = dir !== void 0 ?
|
|
10260
|
+
const root = dir !== void 0 ? path9.resolve(dir) : await deps.resolveBundleRoot(start);
|
|
9902
10261
|
if (!root || realOrSame3(root) !== realOrSame3(boardPath)) return "different-bundle";
|
|
9903
10262
|
}
|
|
9904
10263
|
const key = resolveBundleKey(boardPath);
|
|
@@ -9908,7 +10267,7 @@ async function maybeAutoPull(deps, dir, opts = {}) {
|
|
|
9908
10267
|
if (ageOk(state.cache?.updatedAt)) return "fresh";
|
|
9909
10268
|
if (ageOk(state.autoPullAttemptAt)) return "throttled";
|
|
9910
10269
|
const gitTop = repoTopLevel(candidate.top);
|
|
9911
|
-
if (!gitTop || realOrSame3(
|
|
10270
|
+
if (!gitTop || realOrSame3(path9.join(gitTop, path9.basename(boardPath))) !== realOrSame3(boardPath) || !isProvisioned(gitTop)) {
|
|
9912
10271
|
return "no-board";
|
|
9913
10272
|
}
|
|
9914
10273
|
await deps.store.recordAutoPullAttempt(key, now);
|
|
@@ -11300,26 +11659,26 @@ function applyReplacer(root, replacer) {
|
|
|
11300
11659
|
if (replacedRoot === void 0) return transformChildren(root, replacer, []);
|
|
11301
11660
|
return transformChildren(normalizeValue(replacedRoot), replacer, []);
|
|
11302
11661
|
}
|
|
11303
|
-
function transformChildren(value, replacer,
|
|
11304
|
-
if (isJsonObject(value)) return transformObject(value, replacer,
|
|
11305
|
-
if (isJsonArray(value)) return transformArray(value, replacer,
|
|
11662
|
+
function transformChildren(value, replacer, path29) {
|
|
11663
|
+
if (isJsonObject(value)) return transformObject(value, replacer, path29);
|
|
11664
|
+
if (isJsonArray(value)) return transformArray(value, replacer, path29);
|
|
11306
11665
|
return value;
|
|
11307
11666
|
}
|
|
11308
|
-
function transformObject(obj, replacer,
|
|
11667
|
+
function transformObject(obj, replacer, path29) {
|
|
11309
11668
|
const result3 = {};
|
|
11310
11669
|
for (const [key, value] of Object.entries(obj)) {
|
|
11311
|
-
const childPath = [...
|
|
11670
|
+
const childPath = [...path29, key];
|
|
11312
11671
|
const replacedValue = replacer(key, value, childPath);
|
|
11313
11672
|
if (replacedValue === void 0) continue;
|
|
11314
11673
|
result3[key] = transformChildren(normalizeValue(replacedValue), replacer, childPath);
|
|
11315
11674
|
}
|
|
11316
11675
|
return result3;
|
|
11317
11676
|
}
|
|
11318
|
-
function transformArray(arr, replacer,
|
|
11677
|
+
function transformArray(arr, replacer, path29) {
|
|
11319
11678
|
const result3 = [];
|
|
11320
11679
|
for (let i = 0; i < arr.length; i++) {
|
|
11321
11680
|
const value = arr[i];
|
|
11322
|
-
const childPath = [...
|
|
11681
|
+
const childPath = [...path29, i];
|
|
11323
11682
|
const replacedValue = replacer(String(i), value, childPath);
|
|
11324
11683
|
if (replacedValue === void 0) continue;
|
|
11325
11684
|
const normalizedValue = normalizeValue(replacedValue);
|
|
@@ -11364,11 +11723,11 @@ var init_dist = __esm({
|
|
|
11364
11723
|
|
|
11365
11724
|
// ../../node_modules/axi-sdk-js/dist/output.js
|
|
11366
11725
|
import { homedir as homedir6 } from "node:os";
|
|
11367
|
-
function collapseHomeDirectory2(
|
|
11368
|
-
if (!
|
|
11369
|
-
return
|
|
11726
|
+
function collapseHomeDirectory2(path29, homeDir = homedir6()) {
|
|
11727
|
+
if (!path29.startsWith(homeDir)) {
|
|
11728
|
+
return path29;
|
|
11370
11729
|
}
|
|
11371
|
-
return `~${
|
|
11730
|
+
return `~${path29.slice(homeDir.length)}`;
|
|
11372
11731
|
}
|
|
11373
11732
|
function homeHeaderOutput(options2) {
|
|
11374
11733
|
return {
|
|
@@ -11499,36 +11858,36 @@ function readNearestPackageJson(startPath, fs9 = nodeFs) {
|
|
|
11499
11858
|
}
|
|
11500
11859
|
function detectInstallMethod(options2) {
|
|
11501
11860
|
const env = options2.env ?? process.env;
|
|
11502
|
-
const
|
|
11503
|
-
if (
|
|
11861
|
+
const path29 = options2.entry.replaceAll("\\", "/");
|
|
11862
|
+
if (path29.includes("/_npx/") || /\/dlx-[^/]+\//.test(path29) || path29.includes("/pnpm/dlx/") || path29.includes("/bun/install/cache/")) {
|
|
11504
11863
|
return { kind: "npx" };
|
|
11505
11864
|
}
|
|
11506
|
-
const homebrewFormula = homebrewFormulaFromPath(
|
|
11865
|
+
const homebrewFormula = homebrewFormulaFromPath(path29, env);
|
|
11507
11866
|
if (homebrewFormula) {
|
|
11508
11867
|
return { kind: "homebrew", formula: homebrewFormula };
|
|
11509
11868
|
}
|
|
11510
11869
|
const pnpmHome = normalizePathRoot(env.PNPM_HOME);
|
|
11511
|
-
if (isPathInsideRoot(
|
|
11870
|
+
if (isPathInsideRoot(path29, pnpmHome) || isKnownPnpmGlobalStore(path29, env)) {
|
|
11512
11871
|
return { kind: "pnpm-global" };
|
|
11513
11872
|
}
|
|
11514
|
-
if (isKnownNpmGlobalInstall(
|
|
11873
|
+
if (isKnownNpmGlobalInstall(path29, env)) {
|
|
11515
11874
|
return { kind: "npm-global" };
|
|
11516
11875
|
}
|
|
11517
11876
|
return { kind: "unknown" };
|
|
11518
11877
|
}
|
|
11519
|
-
function normalizePathRoot(
|
|
11520
|
-
const normalized =
|
|
11878
|
+
function normalizePathRoot(path29) {
|
|
11879
|
+
const normalized = path29?.replaceAll("\\", "/").replace(/\/+$/, "");
|
|
11521
11880
|
return normalized && normalized.length > 0 ? normalized : void 0;
|
|
11522
11881
|
}
|
|
11523
|
-
function isPathInsideRoot(
|
|
11524
|
-
return root !== void 0 && (
|
|
11882
|
+
function isPathInsideRoot(path29, root) {
|
|
11883
|
+
return root !== void 0 && (path29 === root || path29.startsWith(`${root}/`));
|
|
11525
11884
|
}
|
|
11526
|
-
function homebrewFormulaFromPath(
|
|
11885
|
+
function homebrewFormulaFromPath(path29, env) {
|
|
11527
11886
|
for (const root of homebrewCellarRoots(env)) {
|
|
11528
|
-
if (!isPathInsideRoot(
|
|
11887
|
+
if (!isPathInsideRoot(path29, root)) {
|
|
11529
11888
|
continue;
|
|
11530
11889
|
}
|
|
11531
|
-
const relative2 =
|
|
11890
|
+
const relative2 = path29.slice(root.length).replace(/^\/+/, "");
|
|
11532
11891
|
const formula = relative2.split("/")[0];
|
|
11533
11892
|
if (formula) {
|
|
11534
11893
|
return formula;
|
|
@@ -11556,12 +11915,12 @@ function homebrewCellarRoots(env) {
|
|
|
11556
11915
|
}
|
|
11557
11916
|
return [...new Set(roots)];
|
|
11558
11917
|
}
|
|
11559
|
-
function isKnownPnpmGlobalStore(
|
|
11918
|
+
function isKnownPnpmGlobalStore(path29, env) {
|
|
11560
11919
|
return pnpmGlobalStoreRoots(env).some((root) => {
|
|
11561
|
-
if (!isPathInsideRoot(
|
|
11920
|
+
if (!isPathInsideRoot(path29, root)) {
|
|
11562
11921
|
return false;
|
|
11563
11922
|
}
|
|
11564
|
-
const relative2 =
|
|
11923
|
+
const relative2 = path29.slice(root.length).replace(/^\/+/, "");
|
|
11565
11924
|
return /^\d+\/\.pnpm\//.test(relative2);
|
|
11566
11925
|
});
|
|
11567
11926
|
}
|
|
@@ -11579,8 +11938,8 @@ function pnpmGlobalStoreRoots(env) {
|
|
|
11579
11938
|
}
|
|
11580
11939
|
return [...new Set(roots)];
|
|
11581
11940
|
}
|
|
11582
|
-
function isKnownNpmGlobalInstall(
|
|
11583
|
-
return npmGlobalNodeModulesRoots(env).some((root) => isPathInsideRoot(
|
|
11941
|
+
function isKnownNpmGlobalInstall(path29, env) {
|
|
11942
|
+
return npmGlobalNodeModulesRoots(env).some((root) => isPathInsideRoot(path29, root)) || isKnownVersionManagerNpmGlobal(path29, env);
|
|
11584
11943
|
}
|
|
11585
11944
|
function npmGlobalNodeModulesRoots(env) {
|
|
11586
11945
|
const roots = [
|
|
@@ -11606,8 +11965,8 @@ function npmGlobalNodeModulesRoots(env) {
|
|
|
11606
11965
|
}
|
|
11607
11966
|
return [...new Set(roots)];
|
|
11608
11967
|
}
|
|
11609
|
-
function isKnownVersionManagerNpmGlobal(
|
|
11610
|
-
return versionManagerNodeRoots(env).some((root) => isPathInsideRoot(
|
|
11968
|
+
function isKnownVersionManagerNpmGlobal(path29, env) {
|
|
11969
|
+
return versionManagerNodeRoots(env).some((root) => isPathInsideRoot(path29, root) && path29.includes("/lib/node_modules/"));
|
|
11611
11970
|
}
|
|
11612
11971
|
function versionManagerNodeRoots(env) {
|
|
11613
11972
|
const roots = [];
|
|
@@ -11841,7 +12200,7 @@ async function runUpdate(options2) {
|
|
|
11841
12200
|
const binName = binNameFromArgv(invokedAs);
|
|
11842
12201
|
const mode = parseUpdateArgs(options2.args, binName);
|
|
11843
12202
|
const platform = options2.platform ?? process.platform;
|
|
11844
|
-
const realpath2 = options2.realpath ?? ((
|
|
12203
|
+
const realpath2 = options2.realpath ?? ((path29) => realpathSync7(path29));
|
|
11845
12204
|
const entry = resolveEntry(invokedAs, realpath2);
|
|
11846
12205
|
const fs9 = options2.fs ?? nodeFs;
|
|
11847
12206
|
const fromPackageJson = entry ? readNearestPackageJson(entry, fs9) : {};
|
|
@@ -11926,7 +12285,7 @@ var init_update = __esm({
|
|
|
11926
12285
|
REGISTRY_FETCH_TIMEOUT_MS = 2e4;
|
|
11927
12286
|
nodeFs = {
|
|
11928
12287
|
existsSync: existsSync4,
|
|
11929
|
-
readFileSync: (
|
|
12288
|
+
readFileSync: (path29, encoding) => readFileSync5(path29, encoding)
|
|
11930
12289
|
};
|
|
11931
12290
|
RegistryNotFoundError = class extends Error {
|
|
11932
12291
|
};
|
|
@@ -12194,8 +12553,8 @@ function normalizeServer(raw) {
|
|
|
12194
12553
|
if (url2.protocol !== "http:" && url2.protocol !== "https:") {
|
|
12195
12554
|
throw new Error(`server URL must use http or https: ${raw}`);
|
|
12196
12555
|
}
|
|
12197
|
-
const
|
|
12198
|
-
return { base: url2.origin +
|
|
12556
|
+
const path29 = url2.pathname.replace(/\/+$/, "");
|
|
12557
|
+
return { base: url2.origin + path29, resource: url2.origin };
|
|
12199
12558
|
}
|
|
12200
12559
|
var init_config = __esm({
|
|
12201
12560
|
"src/config.ts"() {
|
|
@@ -12208,7 +12567,7 @@ var init_config = __esm({
|
|
|
12208
12567
|
// src/private-state-bundle-boundary.ts
|
|
12209
12568
|
import { lstatSync as lstatSync3, readlinkSync as readlinkSync2, realpathSync as realpathSync8, statSync as statSync5 } from "node:fs";
|
|
12210
12569
|
import { homedir as homedir7 } from "node:os";
|
|
12211
|
-
import
|
|
12570
|
+
import path10 from "node:path";
|
|
12212
12571
|
function code(error51) {
|
|
12213
12572
|
return error51?.code;
|
|
12214
12573
|
}
|
|
@@ -12235,7 +12594,7 @@ function danglingLinkTarget(cursor, seenLinks) {
|
|
|
12235
12594
|
throw new CliError("RUNTIME", "cannot resolve the private-state filesystem boundary");
|
|
12236
12595
|
}
|
|
12237
12596
|
seenLinks.add(cursor);
|
|
12238
|
-
return
|
|
12597
|
+
return path10.resolve(path10.dirname(cursor), readlinkSync2(cursor));
|
|
12239
12598
|
}
|
|
12240
12599
|
function realAnchor(anchorPath) {
|
|
12241
12600
|
try {
|
|
@@ -12253,7 +12612,7 @@ function anchorAt(lexicalAnchorPath, anchorStatus, missing2) {
|
|
|
12253
12612
|
const key = inodeKey(status2);
|
|
12254
12613
|
if (key === null) return { anchorKey: null, anchorChain: chain, missing: missing2, anchorPath };
|
|
12255
12614
|
chain.push(key);
|
|
12256
|
-
const parent =
|
|
12615
|
+
const parent = path10.dirname(current);
|
|
12257
12616
|
if (parent === current) break;
|
|
12258
12617
|
try {
|
|
12259
12618
|
status2 = statSync5(parent, { bigint: true });
|
|
@@ -12265,10 +12624,10 @@ function anchorAt(lexicalAnchorPath, anchorStatus, missing2) {
|
|
|
12265
12624
|
return { anchorKey: chain[0] ?? null, anchorChain: chain, missing: missing2, anchorPath };
|
|
12266
12625
|
}
|
|
12267
12626
|
function physicalCoordinate(candidate, seenLinks = /* @__PURE__ */ new Set()) {
|
|
12268
|
-
if (!
|
|
12627
|
+
if (!path10.isAbsolute(candidate)) {
|
|
12269
12628
|
throw new CliError("RUNTIME", "private state and bundle identities require absolute filesystem paths");
|
|
12270
12629
|
}
|
|
12271
|
-
let cursor =
|
|
12630
|
+
let cursor = path10.normalize(candidate);
|
|
12272
12631
|
const missing2 = [];
|
|
12273
12632
|
for (; ; ) {
|
|
12274
12633
|
try {
|
|
@@ -12278,12 +12637,12 @@ function physicalCoordinate(candidate, seenLinks = /* @__PURE__ */ new Set()) {
|
|
|
12278
12637
|
if (!absentComponent(error51)) throw runtimeFailure();
|
|
12279
12638
|
}
|
|
12280
12639
|
const hop = danglingLinkTarget(cursor, seenLinks);
|
|
12281
|
-
if (hop !== null) return physicalCoordinate(
|
|
12282
|
-
const parent =
|
|
12640
|
+
if (hop !== null) return physicalCoordinate(path10.resolve(hop, ...[...missing2].reverse()), seenLinks);
|
|
12641
|
+
const parent = path10.dirname(cursor);
|
|
12283
12642
|
if (parent === cursor) {
|
|
12284
12643
|
throw new CliError("RUNTIME", "cannot resolve the private-state filesystem boundary");
|
|
12285
12644
|
}
|
|
12286
|
-
missing2.push(
|
|
12645
|
+
missing2.push(path10.basename(cursor));
|
|
12287
12646
|
cursor = parent;
|
|
12288
12647
|
}
|
|
12289
12648
|
}
|
|
@@ -12291,7 +12650,7 @@ function fold(segment) {
|
|
|
12291
12650
|
return segment.normalize("NFC").toLowerCase();
|
|
12292
12651
|
}
|
|
12293
12652
|
function foldedSegments(coordinate) {
|
|
12294
|
-
return
|
|
12653
|
+
return path10.resolve(coordinate.anchorPath, ...coordinate.missing).split(path10.sep).filter(Boolean).map(fold);
|
|
12295
12654
|
}
|
|
12296
12655
|
function relateSegments(bundle, state) {
|
|
12297
12656
|
const shared = Math.min(bundle.length, state.length);
|
|
@@ -12302,8 +12661,8 @@ function relateSegments(bundle, state) {
|
|
|
12302
12661
|
return bundle.length < state.length ? "bundle-contains-state" : "bundle-inside-state";
|
|
12303
12662
|
}
|
|
12304
12663
|
function relateToPrivateState(candidate, stateRoot) {
|
|
12305
|
-
const bundle = physicalCoordinate(
|
|
12306
|
-
const state = physicalCoordinate(
|
|
12664
|
+
const bundle = physicalCoordinate(path10.resolve(candidate));
|
|
12665
|
+
const state = physicalCoordinate(path10.resolve(stateRoot));
|
|
12307
12666
|
if (bundle.anchorKey === null || state.anchorKey === null) {
|
|
12308
12667
|
return relateSegments(foldedSegments(bundle), foldedSegments(state));
|
|
12309
12668
|
}
|
|
@@ -12355,17 +12714,17 @@ function bundleBoundaryError(finding) {
|
|
|
12355
12714
|
);
|
|
12356
12715
|
}
|
|
12357
12716
|
function assertBundleOutsidePrivateState(bundleRoot, home2 = homedir7()) {
|
|
12358
|
-
const finding = classifyAgainstPrivateState(
|
|
12717
|
+
const finding = classifyAgainstPrivateState(path10.resolve(bundleRoot), home2);
|
|
12359
12718
|
if (finding.relation === "unrelated") return;
|
|
12360
12719
|
throw bundleBoundaryError(finding);
|
|
12361
12720
|
}
|
|
12362
12721
|
function assertSearchDirOutsidePrivateState(dir, home2 = homedir7()) {
|
|
12363
|
-
const finding = classifyAgainstPrivateState(
|
|
12722
|
+
const finding = classifyAgainstPrivateState(path10.resolve(dir), home2);
|
|
12364
12723
|
if (finding.relation !== "identical" && finding.relation !== "bundle-inside-state") return;
|
|
12365
12724
|
throw bundleBoundaryError(finding);
|
|
12366
12725
|
}
|
|
12367
12726
|
function assertPathOutsidePrivateState(target, home2 = homedir7()) {
|
|
12368
|
-
const finding = classifyAgainstPrivateState(
|
|
12727
|
+
const finding = classifyAgainstPrivateState(path10.resolve(target), home2);
|
|
12369
12728
|
if (finding.relation !== "identical" && finding.relation !== "bundle-inside-state") return;
|
|
12370
12729
|
throw new CliError(
|
|
12371
12730
|
"CONFLICT",
|
|
@@ -12387,7 +12746,7 @@ var init_private_state_bundle_boundary = __esm({
|
|
|
12387
12746
|
// src/bound-board-owner.ts
|
|
12388
12747
|
import { realpath } from "node:fs/promises";
|
|
12389
12748
|
import { realpathSync as realpathSync9 } from "node:fs";
|
|
12390
|
-
import
|
|
12749
|
+
import path11 from "node:path";
|
|
12391
12750
|
function failure(target, stage, message) {
|
|
12392
12751
|
return new CliError("CONFLICT", `project binding cannot be used as a board owner: ${message}`, {
|
|
12393
12752
|
details: {
|
|
@@ -12399,7 +12758,7 @@ function failure(target, stage, message) {
|
|
|
12399
12758
|
}
|
|
12400
12759
|
function canonicalGitPath(from, raw) {
|
|
12401
12760
|
if (!raw) return null;
|
|
12402
|
-
const candidate =
|
|
12761
|
+
const candidate = path11.isAbsolute(raw) ? raw : path11.resolve(from, raw);
|
|
12403
12762
|
try {
|
|
12404
12763
|
return realpathSync9(candidate);
|
|
12405
12764
|
} catch {
|
|
@@ -12411,9 +12770,9 @@ async function validateBoundBoardOwner(target) {
|
|
|
12411
12770
|
const bindingFile = target.bindingFile;
|
|
12412
12771
|
if (!bindingFile) throw failure(target, "binding", "the selected binding has no source path");
|
|
12413
12772
|
const bundleRoot = await realpath(target.canonicalRoot);
|
|
12414
|
-
const bundleDir =
|
|
12773
|
+
const bundleDir = path11.basename(bundleRoot);
|
|
12415
12774
|
if (!BUNDLE_DIRS.includes(bundleDir)) return void 0;
|
|
12416
|
-
const ownerRoot =
|
|
12775
|
+
const ownerRoot = path11.dirname(bundleRoot);
|
|
12417
12776
|
if (repoTopLevel(bundleRoot) !== bundleRoot || repoTopLevel(ownerRoot) !== ownerRoot) return void 0;
|
|
12418
12777
|
const candidateGit = runGit(bundleRoot, ["rev-parse", "--git-common-dir"]);
|
|
12419
12778
|
const ownerGit = runGit(ownerRoot, ["rev-parse", "--git-common-dir"]);
|
|
@@ -12462,7 +12821,7 @@ var init_bound_board_owner = __esm({
|
|
|
12462
12821
|
|
|
12463
12822
|
// src/bundle.ts
|
|
12464
12823
|
import { constants as constants3, promises as fs3 } from "node:fs";
|
|
12465
|
-
import
|
|
12824
|
+
import path12 from "node:path";
|
|
12466
12825
|
async function exists(p2) {
|
|
12467
12826
|
try {
|
|
12468
12827
|
await fs3.stat(p2);
|
|
@@ -12472,16 +12831,16 @@ async function exists(p2) {
|
|
|
12472
12831
|
}
|
|
12473
12832
|
}
|
|
12474
12833
|
function resolveTargetDir(dirFlag) {
|
|
12475
|
-
return
|
|
12834
|
+
return path12.resolve(dirFlag ?? process.cwd());
|
|
12476
12835
|
}
|
|
12477
12836
|
async function assertPlainInitTarget(dirFlag) {
|
|
12478
12837
|
const target = resolveTargetDir(dirFlag);
|
|
12479
12838
|
assertBundleOutsidePrivateState(target);
|
|
12480
|
-
const ownIndex = await exists(
|
|
12481
|
-
const base =
|
|
12839
|
+
const ownIndex = await exists(path12.join(target, "index.md"));
|
|
12840
|
+
const base = path12.basename(target);
|
|
12482
12841
|
if (BUNDLE_DIRS.includes(base)) {
|
|
12483
|
-
const selected = await conventionalBundleAt(
|
|
12484
|
-
if (selected &&
|
|
12842
|
+
const selected = await conventionalBundleAt(path12.dirname(target));
|
|
12843
|
+
if (selected && path12.resolve(selected) !== target) {
|
|
12485
12844
|
throw new CliError(
|
|
12486
12845
|
"CONFLICT",
|
|
12487
12846
|
`an existing project workspace ${selected} already serves this location \u2014 refusing to create a second conventional bundle`,
|
|
@@ -12512,20 +12871,20 @@ function conventionalBundleConflict(dir) {
|
|
|
12512
12871
|
async function conventionalBundleAt(dir) {
|
|
12513
12872
|
const found = [];
|
|
12514
12873
|
for (const name of BUNDLE_DIRS) {
|
|
12515
|
-
const candidate =
|
|
12516
|
-
if (await exists(
|
|
12874
|
+
const candidate = path12.join(dir, name);
|
|
12875
|
+
if (await exists(path12.join(candidate, "index.md"))) found.push(candidate);
|
|
12517
12876
|
}
|
|
12518
12877
|
if (found.length > 1) throw conventionalBundleConflict(dir);
|
|
12519
12878
|
return found[0] ?? null;
|
|
12520
12879
|
}
|
|
12521
12880
|
async function findBundleRoot(start) {
|
|
12522
12881
|
assertSearchDirOutsidePrivateState(start);
|
|
12523
|
-
let dir =
|
|
12882
|
+
let dir = path12.resolve(start);
|
|
12524
12883
|
while (true) {
|
|
12525
|
-
if (await exists(
|
|
12884
|
+
if (await exists(path12.join(dir, "index.md"))) return dir;
|
|
12526
12885
|
const conventional = await conventionalBundleAt(dir);
|
|
12527
12886
|
if (conventional) return conventional;
|
|
12528
|
-
const parent =
|
|
12887
|
+
const parent = path12.dirname(dir);
|
|
12529
12888
|
if (parent === dir) return null;
|
|
12530
12889
|
dir = parent;
|
|
12531
12890
|
}
|
|
@@ -12577,7 +12936,7 @@ function parseProjectBinding(file2, raw) {
|
|
|
12577
12936
|
{ help: `${cliInvocation()} <command> --remote ${remote}` }
|
|
12578
12937
|
);
|
|
12579
12938
|
}
|
|
12580
|
-
return { file: file2, target:
|
|
12939
|
+
return { file: file2, target: path12.resolve(path12.dirname(file2), value) };
|
|
12581
12940
|
}
|
|
12582
12941
|
async function readProjectBindingFile(file2) {
|
|
12583
12942
|
let handle;
|
|
@@ -12613,8 +12972,8 @@ async function readProjectBindingFile(file2) {
|
|
|
12613
12972
|
}
|
|
12614
12973
|
}
|
|
12615
12974
|
function projectBindingConflict(dir) {
|
|
12616
|
-
const preferred =
|
|
12617
|
-
const legacy =
|
|
12975
|
+
const preferred = path12.join(dir, SUPERBEE_PROJECT_BINDING_FILE_NAME);
|
|
12976
|
+
const legacy = path12.join(dir, PROJECT_BINDING_FILE_NAME);
|
|
12618
12977
|
return new CliError(
|
|
12619
12978
|
"USAGE",
|
|
12620
12979
|
`conflicting project bindings at ${dir}: found both ${preferred} and ${legacy}; remove one instead of relying on an ambiguous target`,
|
|
@@ -12637,7 +12996,7 @@ async function ordinaryBindingEntryExists(file2) {
|
|
|
12637
12996
|
async function ordinaryProjectBindingAtLevel(dir) {
|
|
12638
12997
|
const observed = await Promise.all(
|
|
12639
12998
|
PROJECT_BINDING_FILE_NAMES.map(async (name) => {
|
|
12640
|
-
const file2 =
|
|
12999
|
+
const file2 = path12.join(dir, name);
|
|
12641
13000
|
return { file: file2, present: await ordinaryBindingEntryExists(file2) };
|
|
12642
13001
|
})
|
|
12643
13002
|
);
|
|
@@ -12646,11 +13005,11 @@ async function ordinaryProjectBindingAtLevel(dir) {
|
|
|
12646
13005
|
return present[0]?.file ?? null;
|
|
12647
13006
|
}
|
|
12648
13007
|
async function resolveProjectBinding(startDir = process.cwd()) {
|
|
12649
|
-
let dir =
|
|
13008
|
+
let dir = path12.resolve(startDir);
|
|
12650
13009
|
for (; ; ) {
|
|
12651
13010
|
const file2 = await ordinaryProjectBindingAtLevel(dir);
|
|
12652
13011
|
if (file2) return parseProjectBinding(file2, await readProjectBindingFile(file2));
|
|
12653
|
-
const parent =
|
|
13012
|
+
const parent = path12.dirname(dir);
|
|
12654
13013
|
if (parent === dir) return null;
|
|
12655
13014
|
dir = parent;
|
|
12656
13015
|
}
|
|
@@ -12749,12 +13108,12 @@ function createOnlyUncertainty(phase, operation, p2, err, createdDirectories = [
|
|
|
12749
13108
|
);
|
|
12750
13109
|
}
|
|
12751
13110
|
function samePhysicalPath(a, b) {
|
|
12752
|
-
const left =
|
|
12753
|
-
const right =
|
|
13111
|
+
const left = path12.resolve(a);
|
|
13112
|
+
const right = path12.resolve(b);
|
|
12754
13113
|
return process.platform === "win32" ? left.toLowerCase() === right.toLowerCase() : left === right;
|
|
12755
13114
|
}
|
|
12756
13115
|
function createOnlyArbitrationLockKey(physicalTarget) {
|
|
12757
|
-
return
|
|
13116
|
+
return path12.parse(path12.resolve(physicalTarget)).root;
|
|
12758
13117
|
}
|
|
12759
13118
|
async function optionalLstat(io, p2, phase, operation, createdDirectories = []) {
|
|
12760
13119
|
try {
|
|
@@ -12785,9 +13144,9 @@ async function resolveCreateOnlyPhysicalTarget(logical, io, phase, createdDirect
|
|
|
12785
13144
|
});
|
|
12786
13145
|
}
|
|
12787
13146
|
if (code3 !== "ENOENT") createOnlyUncertainty(phase, "lstat", existingPrefix, err, createdDirectories);
|
|
12788
|
-
const parent =
|
|
13147
|
+
const parent = path12.dirname(existingPrefix);
|
|
12789
13148
|
if (parent === existingPrefix) createOnlyUncertainty(phase, "lstat", existingPrefix, err, createdDirectories);
|
|
12790
|
-
missingTail.unshift(
|
|
13149
|
+
missingTail.unshift(path12.basename(existingPrefix));
|
|
12791
13150
|
existingPrefix = parent;
|
|
12792
13151
|
}
|
|
12793
13152
|
}
|
|
@@ -12817,7 +13176,7 @@ async function resolveCreateOnlyPhysicalTarget(logical, io, phase, createdDirect
|
|
|
12817
13176
|
}
|
|
12818
13177
|
return {
|
|
12819
13178
|
logical,
|
|
12820
|
-
target:
|
|
13179
|
+
target: path12.join(physicalPrefix, ...missingTail),
|
|
12821
13180
|
physicalPrefix,
|
|
12822
13181
|
missingTail,
|
|
12823
13182
|
...targetStat ? { targetStat } : {}
|
|
@@ -12900,7 +13259,7 @@ async function existingBundleAt(io, candidate, phase, createdDirectories) {
|
|
|
12900
13259
|
if (!physicalInfo.isDirectory()) return null;
|
|
12901
13260
|
const own5 = await optionalLstat(
|
|
12902
13261
|
io,
|
|
12903
|
-
|
|
13262
|
+
path12.join(physicalCandidate, "index.md"),
|
|
12904
13263
|
phase,
|
|
12905
13264
|
"lstat-own-index",
|
|
12906
13265
|
createdDirectories
|
|
@@ -12911,7 +13270,7 @@ async function existingBundleAt(io, candidate, phase, createdDirectories) {
|
|
|
12911
13270
|
async function strictConventionalBundleAt(io, dir, phase, createdDirectories, operation) {
|
|
12912
13271
|
const found = [];
|
|
12913
13272
|
for (const name of BUNDLE_DIRS) {
|
|
12914
|
-
const candidate =
|
|
13273
|
+
const candidate = path12.join(dir, name);
|
|
12915
13274
|
const info = await optionalLstat(io, candidate, phase, `lstat-${operation}-directory`, createdDirectories);
|
|
12916
13275
|
if (!info) continue;
|
|
12917
13276
|
if (info.isSymbolicLink() || !info.isDirectory()) {
|
|
@@ -12923,7 +13282,7 @@ async function strictConventionalBundleAt(io, dir, phase, createdDirectories, op
|
|
|
12923
13282
|
createdDirectories
|
|
12924
13283
|
);
|
|
12925
13284
|
}
|
|
12926
|
-
if (await optionalLstat(io,
|
|
13285
|
+
if (await optionalLstat(io, path12.join(candidate, "index.md"), phase, `lstat-${operation}-index`, createdDirectories)) {
|
|
12927
13286
|
found.push(candidate);
|
|
12928
13287
|
}
|
|
12929
13288
|
}
|
|
@@ -12936,7 +13295,7 @@ async function strictProjectBinding(io, start, phase, createdDirectories) {
|
|
|
12936
13295
|
await assertObservedDirectory(io, dir, phase, createdDirectories);
|
|
12937
13296
|
const observed = await Promise.all(
|
|
12938
13297
|
PROJECT_BINDING_FILE_NAMES.map(async (name) => {
|
|
12939
|
-
const file2 =
|
|
13298
|
+
const file2 = path12.join(dir, name);
|
|
12940
13299
|
const info = await optionalLstat(
|
|
12941
13300
|
io,
|
|
12942
13301
|
file2,
|
|
@@ -12968,7 +13327,7 @@ async function strictProjectBinding(io, start, phase, createdDirectories) {
|
|
|
12968
13327
|
}
|
|
12969
13328
|
return parseProjectBinding(file2, raw);
|
|
12970
13329
|
}
|
|
12971
|
-
const parent =
|
|
13330
|
+
const parent = path12.dirname(dir);
|
|
12972
13331
|
if (parent === dir) return null;
|
|
12973
13332
|
dir = parent;
|
|
12974
13333
|
}
|
|
@@ -12977,7 +13336,7 @@ async function inspectCreateOnlyTarget(logical, io, phase, createdDirectories =
|
|
|
12977
13336
|
const resolved = await resolveCreateOnlyPhysicalTarget(logical, io, phase, createdDirectories);
|
|
12978
13337
|
const target = resolved.target;
|
|
12979
13338
|
if (resolved.missingTail.length === 0) {
|
|
12980
|
-
if (await optionalLstat(io,
|
|
13339
|
+
if (await optionalLstat(io, path12.join(target, "index.md"), phase, "lstat-own-index", createdDirectories)) {
|
|
12981
13340
|
createOnlyConflict(`create-only target ${target} is already an OKF bundle`, {
|
|
12982
13341
|
phase,
|
|
12983
13342
|
residual_created_directories: [...createdDirectories]
|
|
@@ -13003,11 +13362,11 @@ async function inspectCreateOnlyTarget(logical, io, phase, createdDirectories =
|
|
|
13003
13362
|
);
|
|
13004
13363
|
}
|
|
13005
13364
|
}
|
|
13006
|
-
const existingParent = resolved.missingTail.length > 0 ? resolved.physicalPrefix :
|
|
13365
|
+
const existingParent = resolved.missingTail.length > 0 ? resolved.physicalPrefix : path12.dirname(target);
|
|
13007
13366
|
let ancestor = existingParent;
|
|
13008
13367
|
for (; ; ) {
|
|
13009
13368
|
await assertObservedDirectory(io, ancestor, phase, createdDirectories);
|
|
13010
|
-
if (await optionalLstat(io,
|
|
13369
|
+
if (await optionalLstat(io, path12.join(ancestor, "index.md"), phase, "lstat-upward-own-index", createdDirectories)) {
|
|
13011
13370
|
createOnlyConflict(`create-only target ${target} would nest inside the existing bundle at ${ancestor}`, {
|
|
13012
13371
|
phase,
|
|
13013
13372
|
residual_created_directories: [...createdDirectories]
|
|
@@ -13020,7 +13379,7 @@ async function inspectCreateOnlyTarget(logical, io, phase, createdDirectories =
|
|
|
13020
13379
|
residual_created_directories: [...createdDirectories]
|
|
13021
13380
|
});
|
|
13022
13381
|
}
|
|
13023
|
-
const parent =
|
|
13382
|
+
const parent = path12.dirname(ancestor);
|
|
13024
13383
|
if (parent === ancestor) break;
|
|
13025
13384
|
ancestor = parent;
|
|
13026
13385
|
}
|
|
@@ -13042,7 +13401,7 @@ function createOnlyIo(deps) {
|
|
|
13042
13401
|
async function createMissingDirectories(resolution, io, createdDirectories) {
|
|
13043
13402
|
let current = resolution.physicalPrefix;
|
|
13044
13403
|
for (const segment of resolution.missingTail) {
|
|
13045
|
-
const next =
|
|
13404
|
+
const next = path12.join(current, segment);
|
|
13046
13405
|
try {
|
|
13047
13406
|
await io.mkdir(next);
|
|
13048
13407
|
createdDirectories.push(next);
|
|
@@ -13149,7 +13508,7 @@ function decorateCreateOnlyFailure(err, target, createdDirectories, publicationS
|
|
|
13149
13508
|
createOnlyConflict(`create-only target ${target} gained a bundle concurrently \u2014 another process created it first`, {
|
|
13150
13509
|
phase: "pre-publish",
|
|
13151
13510
|
operation: "write-index-expect-absent",
|
|
13152
|
-
path:
|
|
13511
|
+
path: path12.join(target, "index.md"),
|
|
13153
13512
|
residual_created_directories: [...createdDirectories],
|
|
13154
13513
|
publication_outcome: publicationState
|
|
13155
13514
|
});
|
|
@@ -13167,7 +13526,7 @@ function decorateCreateOnlyFailure(err, target, createdDirectories, publicationS
|
|
|
13167
13526
|
createOnlyUncertainty(
|
|
13168
13527
|
publicationState === "not-started" ? "directory-creation" : "pre-publish",
|
|
13169
13528
|
publicationState === "not-started" ? "create-only-critical-section" : "publish-index",
|
|
13170
|
-
publicationState === "not-started" ? err?.path ?? target : err?.path ??
|
|
13529
|
+
publicationState === "not-started" ? err?.path ?? target : err?.path ?? path12.join(target, "index.md"),
|
|
13171
13530
|
err,
|
|
13172
13531
|
createdDirectories,
|
|
13173
13532
|
{ publication_outcome: publicationState }
|
|
@@ -13175,7 +13534,7 @@ function decorateCreateOnlyFailure(err, target, createdDirectories, publicationS
|
|
|
13175
13534
|
}
|
|
13176
13535
|
async function withCreateOnlyTarget(dirFlag, publish, startDir = process.cwd(), deps = {}) {
|
|
13177
13536
|
const io = createOnlyIo(deps);
|
|
13178
|
-
const logical =
|
|
13537
|
+
const logical = path12.resolve(startDir, dirFlag ?? startDir);
|
|
13179
13538
|
try {
|
|
13180
13539
|
assertBundleOutsidePrivateState(logical);
|
|
13181
13540
|
} catch (error51) {
|
|
@@ -13260,9 +13619,9 @@ async function withCreateOnlyTarget(dirFlag, publish, startDir = process.cwd(),
|
|
|
13260
13619
|
}
|
|
13261
13620
|
async function resolveLocalBundleTarget(dirFlag, startDir = process.cwd()) {
|
|
13262
13621
|
if (dirFlag !== void 0) {
|
|
13263
|
-
const requested =
|
|
13622
|
+
const requested = path12.resolve(startDir, dirFlag);
|
|
13264
13623
|
assertBundleOutsidePrivateState(requested);
|
|
13265
|
-
const ownIndex = await exists(
|
|
13624
|
+
const ownIndex = await exists(path12.join(requested, "index.md"));
|
|
13266
13625
|
const conventional = ownIndex ? null : await conventionalBundleAt(requested);
|
|
13267
13626
|
const root = ownIndex ? requested : conventional ?? requested;
|
|
13268
13627
|
let canonicalRoot2;
|
|
@@ -13288,7 +13647,7 @@ async function resolveLocalBundleTarget(dirFlag, startDir = process.cwd()) {
|
|
|
13288
13647
|
}
|
|
13289
13648
|
const binding = await resolveProjectBinding(startDir);
|
|
13290
13649
|
if (binding) {
|
|
13291
|
-
assertBundleOutsidePrivateState(
|
|
13650
|
+
assertBundleOutsidePrivateState(path12.resolve(binding.target));
|
|
13292
13651
|
const canonicalRoot2 = await canonicalDirectoryRoot(
|
|
13293
13652
|
binding.target,
|
|
13294
13653
|
`no local bundle directory at ${binding.target} \u2014 from project binding ${binding.file}`,
|
|
@@ -13324,17 +13683,17 @@ function bindingPathConflict(target, message) {
|
|
|
13324
13683
|
});
|
|
13325
13684
|
}
|
|
13326
13685
|
function strictlyLexicalAncestor(ancestor, descendant) {
|
|
13327
|
-
const relative2 =
|
|
13328
|
-
return relative2 !== "" && relative2 !== ".." && !relative2.startsWith(`..${
|
|
13686
|
+
const relative2 = path12.relative(ancestor, descendant);
|
|
13687
|
+
return relative2 !== "" && relative2 !== ".." && !relative2.startsWith(`..${path12.sep}`) && !path12.isAbsolute(relative2);
|
|
13329
13688
|
}
|
|
13330
13689
|
function lexicalBindingAnchors(anchor) {
|
|
13331
13690
|
const anchors = [anchor];
|
|
13332
13691
|
if (process.platform !== "darwin") return anchors;
|
|
13333
13692
|
for (const [physical, lexical] of [
|
|
13334
|
-
[
|
|
13335
|
-
[
|
|
13693
|
+
[path12.join(path12.sep, "private", "var"), path12.join(path12.sep, "var")],
|
|
13694
|
+
[path12.join(path12.sep, "private", "tmp"), path12.join(path12.sep, "tmp")]
|
|
13336
13695
|
]) {
|
|
13337
|
-
if (anchor === physical || anchor.startsWith(`${physical}${
|
|
13696
|
+
if (anchor === physical || anchor.startsWith(`${physical}${path12.sep}`)) {
|
|
13338
13697
|
anchors.push(`${lexical}${anchor.slice(physical.length)}`);
|
|
13339
13698
|
}
|
|
13340
13699
|
}
|
|
@@ -13343,14 +13702,14 @@ function lexicalBindingAnchors(anchor) {
|
|
|
13343
13702
|
async function bindingRouteTraversesSymlink(target) {
|
|
13344
13703
|
if (target.selectedBy !== "project-binding") return false;
|
|
13345
13704
|
if (!target.bindingFile) throw bindingPathConflict(target, "the selected binding has no source path");
|
|
13346
|
-
const lexicalAnchor =
|
|
13705
|
+
const lexicalAnchor = path12.resolve(path12.dirname(target.bindingFile));
|
|
13347
13706
|
const lexicalAnchors = lexicalBindingAnchors(lexicalAnchor);
|
|
13348
|
-
const targetRoot =
|
|
13349
|
-
const targetParts = targetRoot.split(
|
|
13707
|
+
const targetRoot = path12.resolve(target.root);
|
|
13708
|
+
const targetParts = targetRoot.split(path12.sep).filter(Boolean);
|
|
13350
13709
|
let traversesBindingSymlink = false;
|
|
13351
|
-
let current =
|
|
13710
|
+
let current = path12.parse(targetRoot).root;
|
|
13352
13711
|
for (const segment of targetParts) {
|
|
13353
|
-
current =
|
|
13712
|
+
current = path12.join(current, segment);
|
|
13354
13713
|
let info;
|
|
13355
13714
|
try {
|
|
13356
13715
|
info = await fs3.lstat(current);
|
|
@@ -13371,7 +13730,7 @@ async function captureDirectoryIdentity(target) {
|
|
|
13371
13730
|
} catch {
|
|
13372
13731
|
throw bindingPathConflict(target, "the selected target is unavailable");
|
|
13373
13732
|
}
|
|
13374
|
-
assertBundleOutsidePrivateState(
|
|
13733
|
+
assertBundleOutsidePrivateState(path12.resolve(target.root));
|
|
13375
13734
|
assertBundleOutsidePrivateState(canonicalRoot);
|
|
13376
13735
|
if (canonicalRoot !== target.canonicalRoot) {
|
|
13377
13736
|
throw bindingPathConflict(target, "the selected target changed while its lexical path was validated");
|
|
@@ -13387,14 +13746,14 @@ async function captureDirectoryIdentity(target) {
|
|
|
13387
13746
|
}
|
|
13388
13747
|
async function hasOwnGitWorktreeSignature(root) {
|
|
13389
13748
|
try {
|
|
13390
|
-
await fs3.lstat(
|
|
13749
|
+
await fs3.lstat(path12.join(root, ".git"));
|
|
13391
13750
|
return true;
|
|
13392
13751
|
} catch {
|
|
13393
13752
|
return false;
|
|
13394
13753
|
}
|
|
13395
13754
|
}
|
|
13396
13755
|
async function assertSymlinkedTargetIsNotBoardShaped(target, identity) {
|
|
13397
|
-
if (!BUNDLE_DIRS.includes(
|
|
13756
|
+
if (!BUNDLE_DIRS.includes(path12.basename(identity.canonicalRoot))) return;
|
|
13398
13757
|
if (await hasOwnGitWorktreeSignature(identity.canonicalRoot)) {
|
|
13399
13758
|
throw bindingPathConflict(target, "the symlinked target has a conventional board-worktree signature");
|
|
13400
13759
|
}
|
|
@@ -13407,7 +13766,7 @@ async function assertResolvedLocalRouteIdentity(route) {
|
|
|
13407
13766
|
} catch {
|
|
13408
13767
|
throw bindingPathConflict(route.target, "the selected target is unavailable");
|
|
13409
13768
|
}
|
|
13410
|
-
assertBundleOutsidePrivateState(
|
|
13769
|
+
assertBundleOutsidePrivateState(path12.resolve(route.target.root));
|
|
13411
13770
|
assertBundleOutsidePrivateState(canonicalRoot);
|
|
13412
13771
|
if (canonicalRoot !== route.identity.canonicalRoot) {
|
|
13413
13772
|
throw bindingPathConflict(route.target, "the selected target changed after classification");
|
|
@@ -13450,7 +13809,7 @@ function boardAttributionForRoute(route) {
|
|
|
13450
13809
|
return route.readiness === "ready" ? { kind: "board", stateKey: route.owner.stateKey } : { kind: "none" };
|
|
13451
13810
|
}
|
|
13452
13811
|
if (route.kind === "bound-local") return { kind: "none" };
|
|
13453
|
-
if (!BUNDLE_DIRS.includes(
|
|
13812
|
+
if (!BUNDLE_DIRS.includes(path12.basename(route.bundle.root))) return { kind: "none" };
|
|
13454
13813
|
try {
|
|
13455
13814
|
return { kind: "board", stateKey: resolveBundleKey(route.bundle.root) };
|
|
13456
13815
|
} catch {
|
|
@@ -13519,8 +13878,8 @@ function exactPositionalArity(count) {
|
|
|
13519
13878
|
function pathFlags(...flags) {
|
|
13520
13879
|
return Object.freeze(flags.map((entry) => Object.freeze({ ...entry })));
|
|
13521
13880
|
}
|
|
13522
|
-
function firstWord(
|
|
13523
|
-
return
|
|
13881
|
+
function firstWord(path29) {
|
|
13882
|
+
return path29.split(" ", 1)[0];
|
|
13524
13883
|
}
|
|
13525
13884
|
function surfaceOf(surface, arity) {
|
|
13526
13885
|
const positionals = surface?.positionals ?? NO_PATH_POSITIONALS;
|
|
@@ -13531,14 +13890,14 @@ function surfaceOf(surface, arity) {
|
|
|
13531
13890
|
}
|
|
13532
13891
|
return { pathFlags: surface?.flags ?? NO_PATHS, pathPositionals: positionals };
|
|
13533
13892
|
}
|
|
13534
|
-
function publicLeaf(id,
|
|
13893
|
+
function publicLeaf(id, path29, arity, commandOrder, surface) {
|
|
13535
13894
|
if (commandOrder !== void 0 && (!Number.isSafeInteger(commandOrder) || commandOrder < 0)) {
|
|
13536
13895
|
throw new TypeError(`command order must be a non-negative safe integer; received ${commandOrder}`);
|
|
13537
13896
|
}
|
|
13538
13897
|
const mutable = {
|
|
13539
13898
|
id,
|
|
13540
|
-
path:
|
|
13541
|
-
command: firstWord(
|
|
13899
|
+
path: path29,
|
|
13900
|
+
command: firstWord(path29),
|
|
13542
13901
|
arity,
|
|
13543
13902
|
canonical: void 0,
|
|
13544
13903
|
exposure: "public",
|
|
@@ -13551,12 +13910,12 @@ function publicLeaf(id, path28, arity, commandOrder, surface) {
|
|
|
13551
13910
|
OWNED_CLI_LEAVES.add(mutable);
|
|
13552
13911
|
return Object.freeze(mutable);
|
|
13553
13912
|
}
|
|
13554
|
-
function publicAlias(id,
|
|
13913
|
+
function publicAlias(id, path29, canonical, commandOrder) {
|
|
13555
13914
|
if (canonical.exposure !== "public") throw new TypeError("a public alias must target a public leaf");
|
|
13556
13915
|
const mutable = {
|
|
13557
13916
|
id,
|
|
13558
|
-
path:
|
|
13559
|
-
command: firstWord(
|
|
13917
|
+
path: path29,
|
|
13918
|
+
command: firstWord(path29),
|
|
13560
13919
|
arity: canonical.arity,
|
|
13561
13920
|
canonical: canonical.canonical,
|
|
13562
13921
|
exposure: "public",
|
|
@@ -13571,11 +13930,11 @@ function publicAlias(id, path28, canonical, commandOrder) {
|
|
|
13571
13930
|
OWNED_CLI_LEAVES.add(mutable);
|
|
13572
13931
|
return Object.freeze(mutable);
|
|
13573
13932
|
}
|
|
13574
|
-
function hiddenLeaf(id,
|
|
13933
|
+
function hiddenLeaf(id, path29, arity, surface) {
|
|
13575
13934
|
const mutable = {
|
|
13576
13935
|
id,
|
|
13577
|
-
path:
|
|
13578
|
-
command: firstWord(
|
|
13936
|
+
path: path29,
|
|
13937
|
+
command: firstWord(path29),
|
|
13579
13938
|
arity,
|
|
13580
13939
|
canonical: void 0,
|
|
13581
13940
|
exposure: "hidden",
|
|
@@ -13956,22 +14315,22 @@ function boundedToken(token) {
|
|
|
13956
14315
|
}
|
|
13957
14316
|
function assertLeafArity(leaf, positionals) {
|
|
13958
14317
|
assertCliLeaf(leaf);
|
|
13959
|
-
const
|
|
14318
|
+
const path29 = leaf.canonical.path;
|
|
13960
14319
|
const count = leaf.arity.count;
|
|
13961
14320
|
const expected = count === 0 ? "no positional arguments" : `exactly ${count} positional${count === 1 ? "" : "s"}`;
|
|
13962
14321
|
const actual = positionals.length;
|
|
13963
14322
|
if (actual === count) return;
|
|
13964
14323
|
const firstUnexpected = boundedToken(positionals[count]);
|
|
13965
14324
|
const surplus = Math.max(0, actual - count);
|
|
13966
|
-
throw new CliError("USAGE", `${
|
|
14325
|
+
throw new CliError("USAGE", `${path29} expected ${expected}; received ${actual}`, {
|
|
13967
14326
|
details: {
|
|
13968
|
-
command:
|
|
14327
|
+
command: path29,
|
|
13969
14328
|
expected,
|
|
13970
14329
|
actual,
|
|
13971
14330
|
...surplus === 0 ? {} : { surplus },
|
|
13972
14331
|
...firstUnexpected === void 0 ? {} : { first_unexpected: firstUnexpected }
|
|
13973
14332
|
},
|
|
13974
|
-
help: `${cliInvocation()} ${
|
|
14333
|
+
help: `${cliInvocation()} ${path29} --help`
|
|
13975
14334
|
});
|
|
13976
14335
|
}
|
|
13977
14336
|
var init_positional_arity = __esm({
|
|
@@ -15187,13 +15546,13 @@ var init_recipe_parser = __esm({
|
|
|
15187
15546
|
|
|
15188
15547
|
// src/recipe-ref.ts
|
|
15189
15548
|
import os from "node:os";
|
|
15190
|
-
import
|
|
15549
|
+
import path13 from "node:path";
|
|
15191
15550
|
function looksLikeRecipePath(ref) {
|
|
15192
15551
|
return ref.includes("/") || ref.startsWith("~");
|
|
15193
15552
|
}
|
|
15194
15553
|
function expandRecipePath(ref) {
|
|
15195
15554
|
if (ref === "~") return os.homedir();
|
|
15196
|
-
if (ref.startsWith("~/")) return
|
|
15555
|
+
if (ref.startsWith("~/")) return path13.join(os.homedir(), ref.slice(2));
|
|
15197
15556
|
return ref;
|
|
15198
15557
|
}
|
|
15199
15558
|
var init_recipe_ref = __esm({
|
|
@@ -15315,15 +15674,15 @@ var init_recipe_source_builtin = __esm({
|
|
|
15315
15674
|
|
|
15316
15675
|
// src/recipe-source-filesystem.ts
|
|
15317
15676
|
import { promises as fs4 } from "node:fs";
|
|
15318
|
-
import
|
|
15677
|
+
import path14 from "node:path";
|
|
15319
15678
|
async function readRecipeDir(root) {
|
|
15320
15679
|
const files = [];
|
|
15321
15680
|
const rootReal = await fs4.realpath(root);
|
|
15322
|
-
const manifestPath =
|
|
15681
|
+
const manifestPath = path14.join(root, "recipe.md");
|
|
15323
15682
|
const manifestStat = await fs4.stat(manifestPath).catch(() => null);
|
|
15324
15683
|
if (manifestStat?.isFile()) {
|
|
15325
15684
|
const manifestReal = await fs4.realpath(manifestPath).catch(() => null);
|
|
15326
|
-
if (!manifestReal || manifestReal !== rootReal && !manifestReal.startsWith(rootReal +
|
|
15685
|
+
if (!manifestReal || manifestReal !== rootReal && !manifestReal.startsWith(rootReal + path14.sep)) {
|
|
15327
15686
|
throw new RecipeUnsafePathSignal("recipe.md");
|
|
15328
15687
|
}
|
|
15329
15688
|
const bytes = await fs4.readFile(manifestPath, "utf8");
|
|
@@ -15334,7 +15693,7 @@ async function readRecipeDir(root) {
|
|
|
15334
15693
|
return files;
|
|
15335
15694
|
}
|
|
15336
15695
|
}
|
|
15337
|
-
const conventionsRoot =
|
|
15696
|
+
const conventionsRoot = path14.join(root, "conventions");
|
|
15338
15697
|
const conventionsStat = await fs4.stat(conventionsRoot).catch(() => null);
|
|
15339
15698
|
if (conventionsStat?.isDirectory()) {
|
|
15340
15699
|
await walkConventions(conventionsRoot, "conventions", rootReal, files);
|
|
@@ -15344,7 +15703,7 @@ async function readRecipeDir(root) {
|
|
|
15344
15703
|
async function walkRecipeFiles(dir, relPrefix, rootReal, out, skip) {
|
|
15345
15704
|
const entries = await fs4.readdir(dir, { withFileTypes: true });
|
|
15346
15705
|
for (const entry of entries) {
|
|
15347
|
-
const abs =
|
|
15706
|
+
const abs = path14.join(dir, entry.name);
|
|
15348
15707
|
const rel = relPrefix ? `${relPrefix}/${entry.name}` : entry.name;
|
|
15349
15708
|
if (skip.has(rel)) continue;
|
|
15350
15709
|
if (entry.name.startsWith(".")) {
|
|
@@ -15356,7 +15715,7 @@ async function walkRecipeFiles(dir, relPrefix, rootReal, out, skip) {
|
|
|
15356
15715
|
}
|
|
15357
15716
|
if (!entry.isFile() && !entry.isSymbolicLink()) continue;
|
|
15358
15717
|
const real = await fs4.realpath(abs).catch(() => null);
|
|
15359
|
-
if (!real || real !== rootReal && !real.startsWith(rootReal +
|
|
15718
|
+
if (!real || real !== rootReal && !real.startsWith(rootReal + path14.sep)) {
|
|
15360
15719
|
throw new RecipeUnsafePathSignal(rel);
|
|
15361
15720
|
}
|
|
15362
15721
|
const stat4 = await fs4.stat(real).catch(() => null);
|
|
@@ -15367,7 +15726,7 @@ async function walkRecipeFiles(dir, relPrefix, rootReal, out, skip) {
|
|
|
15367
15726
|
async function walkConventions(dir, relPrefix, rootReal, out) {
|
|
15368
15727
|
const entries = await fs4.readdir(dir, { withFileTypes: true });
|
|
15369
15728
|
for (const entry of entries) {
|
|
15370
|
-
const abs =
|
|
15729
|
+
const abs = path14.join(dir, entry.name);
|
|
15371
15730
|
const rel = `${relPrefix}/${entry.name}`;
|
|
15372
15731
|
if (entry.isDirectory()) {
|
|
15373
15732
|
await walkConventions(abs, rel, rootReal, out);
|
|
@@ -15376,7 +15735,7 @@ async function walkConventions(dir, relPrefix, rootReal, out) {
|
|
|
15376
15735
|
if (!entry.isFile() && !entry.isSymbolicLink()) continue;
|
|
15377
15736
|
if (!rel.endsWith(".md")) continue;
|
|
15378
15737
|
const real = await fs4.realpath(abs).catch(() => null);
|
|
15379
|
-
if (!real || real !== rootReal && !real.startsWith(rootReal +
|
|
15738
|
+
if (!real || real !== rootReal && !real.startsWith(rootReal + path14.sep)) {
|
|
15380
15739
|
throw new RecipeUnsafePathSignal(rel);
|
|
15381
15740
|
}
|
|
15382
15741
|
out.push({ path: rel, bytes: await fs4.readFile(abs, "utf8") });
|
|
@@ -15388,7 +15747,7 @@ function filesRecipeSource() {
|
|
|
15388
15747
|
async resolve(ref) {
|
|
15389
15748
|
if (!looksLikeRecipePath(ref)) return null;
|
|
15390
15749
|
const expanded = expandRecipePath(ref);
|
|
15391
|
-
const real = await fs4.realpath(
|
|
15750
|
+
const real = await fs4.realpath(path14.resolve(expanded)).catch(() => null);
|
|
15392
15751
|
if (!real) {
|
|
15393
15752
|
return { ok: false, error: { code: "RECIPE_NOT_FOUND", message: `no recipe folder at '${ref}'` } };
|
|
15394
15753
|
}
|
|
@@ -15474,12 +15833,12 @@ var init_recipe_source = __esm({
|
|
|
15474
15833
|
// src/commands/init.ts
|
|
15475
15834
|
import { parseArgs } from "node:util";
|
|
15476
15835
|
import { existsSync as existsSync5 } from "node:fs";
|
|
15477
|
-
import
|
|
15836
|
+
import path15 from "node:path";
|
|
15478
15837
|
function insideGitRepo(dir) {
|
|
15479
|
-
let cur =
|
|
15838
|
+
let cur = path15.resolve(dir);
|
|
15480
15839
|
for (; ; ) {
|
|
15481
|
-
if (existsSync5(
|
|
15482
|
-
const parent =
|
|
15840
|
+
if (existsSync5(path15.join(cur, ".git"))) return true;
|
|
15841
|
+
const parent = path15.dirname(cur);
|
|
15483
15842
|
if (parent === cur) return false;
|
|
15484
15843
|
cur = parent;
|
|
15485
15844
|
}
|
|
@@ -16237,12 +16596,12 @@ var init_concept_id = __esm({
|
|
|
16237
16596
|
// src/external-file.ts
|
|
16238
16597
|
import { promises as fs5 } from "node:fs";
|
|
16239
16598
|
import { homedir as homedir9 } from "node:os";
|
|
16240
|
-
import
|
|
16599
|
+
import path16 from "node:path";
|
|
16241
16600
|
function isExportedBundleContent(resolved, home2) {
|
|
16242
16601
|
return relateToPrivateState(resolved, syncExportsRoot(home2)) === "bundle-inside-state";
|
|
16243
16602
|
}
|
|
16244
16603
|
function guardExternalRead(file2, home2 = homedir9()) {
|
|
16245
|
-
const resolved =
|
|
16604
|
+
const resolved = path16.resolve(file2);
|
|
16246
16605
|
if (isExportedBundleContent(resolved, home2)) return;
|
|
16247
16606
|
assertPathOutsidePrivateState(resolved, home2);
|
|
16248
16607
|
}
|
|
@@ -24295,7 +24654,7 @@ function tokenizeWwwAutolink(effects, ok4, nok) {
|
|
|
24295
24654
|
}
|
|
24296
24655
|
effects.enter("literalAutolink");
|
|
24297
24656
|
effects.enter("literalAutolinkWww");
|
|
24298
|
-
return effects.check(wwwPrefix, effects.attempt(domain, effects.attempt(
|
|
24657
|
+
return effects.check(wwwPrefix, effects.attempt(domain, effects.attempt(path17, wwwAfter), nok), nok)(code3);
|
|
24299
24658
|
}
|
|
24300
24659
|
function wwwAfter(code3) {
|
|
24301
24660
|
effects.exit("literalAutolinkWww");
|
|
@@ -24345,7 +24704,7 @@ function tokenizeProtocolAutolink(effects, ok4, nok) {
|
|
|
24345
24704
|
return nok(code3);
|
|
24346
24705
|
}
|
|
24347
24706
|
function afterProtocol(code3) {
|
|
24348
|
-
return code3 === null || asciiControl(code3) || markdownLineEndingOrSpace(code3) || unicodeWhitespace(code3) || unicodePunctuation(code3) ? nok(code3) : effects.attempt(domain, effects.attempt(
|
|
24707
|
+
return code3 === null || asciiControl(code3) || markdownLineEndingOrSpace(code3) || unicodeWhitespace(code3) || unicodePunctuation(code3) ? nok(code3) : effects.attempt(domain, effects.attempt(path17, protocolAfter), nok)(code3);
|
|
24349
24708
|
}
|
|
24350
24709
|
function protocolAfter(code3) {
|
|
24351
24710
|
effects.exit("literalAutolinkHttp");
|
|
@@ -24521,7 +24880,7 @@ function previousUnbalanced(events) {
|
|
|
24521
24880
|
}
|
|
24522
24881
|
return result3;
|
|
24523
24882
|
}
|
|
24524
|
-
var wwwPrefix, domain,
|
|
24883
|
+
var wwwPrefix, domain, path17, trail, emailDomainDotTrail, wwwAutolink, protocolAutolink, emailAutolink, text3, code2;
|
|
24525
24884
|
var init_syntax = __esm({
|
|
24526
24885
|
"../../node_modules/micromark-extension-gfm-autolink-literal/lib/syntax.js"() {
|
|
24527
24886
|
init_define_SUPERBEE_BUILD_IDENTITY();
|
|
@@ -24535,7 +24894,7 @@ var init_syntax = __esm({
|
|
|
24535
24894
|
tokenize: tokenizeDomain,
|
|
24536
24895
|
partial: true
|
|
24537
24896
|
};
|
|
24538
|
-
|
|
24897
|
+
path17 = {
|
|
24539
24898
|
tokenize: tokenizePath,
|
|
24540
24899
|
partial: true
|
|
24541
24900
|
};
|
|
@@ -26072,7 +26431,7 @@ function transformGfmAutolinkLiterals(tree) {
|
|
|
26072
26431
|
{ ignore: ["link", "linkReference"] }
|
|
26073
26432
|
);
|
|
26074
26433
|
}
|
|
26075
|
-
function findUrl(_2, protocol, domain3,
|
|
26434
|
+
function findUrl(_2, protocol, domain3, path29, match) {
|
|
26076
26435
|
let prefix = "";
|
|
26077
26436
|
if (!previous2(match)) {
|
|
26078
26437
|
return false;
|
|
@@ -26085,7 +26444,7 @@ function findUrl(_2, protocol, domain3, path28, match) {
|
|
|
26085
26444
|
if (!isCorrectDomain(domain3)) {
|
|
26086
26445
|
return false;
|
|
26087
26446
|
}
|
|
26088
|
-
const parts = splitUrl(domain3 +
|
|
26447
|
+
const parts = splitUrl(domain3 + path29);
|
|
26089
26448
|
if (!parts[0]) return false;
|
|
26090
26449
|
const result3 = {
|
|
26091
26450
|
type: "link",
|
|
@@ -54729,7 +55088,7 @@ var init_static = __esm({
|
|
|
54729
55088
|
// src/commands/doc/read.ts
|
|
54730
55089
|
import { parseArgs as parseArgs4 } from "node:util";
|
|
54731
55090
|
import { promises as fs6 } from "node:fs";
|
|
54732
|
-
import
|
|
55091
|
+
import path18 from "node:path";
|
|
54733
55092
|
async function docRead(argv2, deps) {
|
|
54734
55093
|
const stderr = deps.stderr ?? ((s) => void process.stderr.write(s));
|
|
54735
55094
|
const rawStdoutReserved = requestsStdoutByteChannel(argv2);
|
|
@@ -54822,7 +55181,7 @@ async function docReadInner(argv2, deps) {
|
|
|
54822
55181
|
const bodyOut = bodyOutValue.trim();
|
|
54823
55182
|
const streamMode2 = bodyOut === "-";
|
|
54824
55183
|
if (!streamMode2) {
|
|
54825
|
-
assertPathOutsidePrivateState(
|
|
55184
|
+
assertPathOutsidePrivateState(path18.resolve(bodyOut));
|
|
54826
55185
|
await assertSafeNonDocumentOutTarget(bundle, "--body-out", bodyOut, id, "body-only markdown");
|
|
54827
55186
|
}
|
|
54828
55187
|
const runToTarget2 = async () => {
|
|
@@ -54857,7 +55216,7 @@ async function docReadInner(argv2, deps) {
|
|
|
54857
55216
|
const renderedOut = renderedOutValue.trim();
|
|
54858
55217
|
const streamMode2 = renderedOut === "-";
|
|
54859
55218
|
if (!streamMode2) {
|
|
54860
|
-
assertPathOutsidePrivateState(
|
|
55219
|
+
assertPathOutsidePrivateState(path18.resolve(renderedOut));
|
|
54861
55220
|
await assertSafeNonDocumentOutTarget(bundle, "--rendered-out", renderedOut, id, "rendered HTML");
|
|
54862
55221
|
}
|
|
54863
55222
|
let parsed;
|
|
@@ -54943,7 +55302,7 @@ async function docReadInner(argv2, deps) {
|
|
|
54943
55302
|
return;
|
|
54944
55303
|
}
|
|
54945
55304
|
const streamMode = out === "-";
|
|
54946
|
-
if (!streamMode) assertPathOutsidePrivateState(
|
|
55305
|
+
if (!streamMode) assertPathOutsidePrivateState(path18.resolve(out));
|
|
54947
55306
|
const runToTarget = async () => {
|
|
54948
55307
|
let bytes;
|
|
54949
55308
|
let rel;
|
|
@@ -54960,7 +55319,7 @@ async function docReadInner(argv2, deps) {
|
|
|
54960
55319
|
try {
|
|
54961
55320
|
assertSafeConceptId(id);
|
|
54962
55321
|
rel = pathFromConceptId(id);
|
|
54963
|
-
bytes = await fs6.readFile(
|
|
55322
|
+
bytes = await fs6.readFile(path18.join(bundle.root, rel));
|
|
54964
55323
|
} catch (err) {
|
|
54965
55324
|
throw readErrorToCliError(err, id, values.remote);
|
|
54966
55325
|
}
|
|
@@ -54997,10 +55356,10 @@ function requestsStdoutByteChannel(argv2) {
|
|
|
54997
55356
|
}
|
|
54998
55357
|
async function assertSafeNonDocumentOutTarget(bundle, flag, outValue, id, payload) {
|
|
54999
55358
|
if (bundle.backend) return;
|
|
55000
|
-
const lexicalTarget =
|
|
55001
|
-
const rootReal = await fs6.realpath(
|
|
55359
|
+
const lexicalTarget = path18.resolve(outValue);
|
|
55360
|
+
const rootReal = await fs6.realpath(path18.resolve(bundle.root)).catch(() => path18.resolve(bundle.root));
|
|
55002
55361
|
const effectiveTarget = await effectiveOutputPath(lexicalTarget);
|
|
55003
|
-
const inside = (candidate, base) => candidate === base || candidate.startsWith(base +
|
|
55362
|
+
const inside = (candidate, base) => candidate === base || candidate.startsWith(base + path18.sep);
|
|
55004
55363
|
const unsafeLexical = inside(lexicalTarget, rootReal) && lexicalTarget.endsWith(".md");
|
|
55005
55364
|
const unsafeEffective = inside(effectiveTarget, rootReal) && effectiveTarget.endsWith(".md");
|
|
55006
55365
|
if (!unsafeLexical && !unsafeEffective) return;
|
|
@@ -55015,11 +55374,11 @@ async function effectiveOutputPath(absoluteTarget) {
|
|
|
55015
55374
|
const missingSuffix = [];
|
|
55016
55375
|
while (true) {
|
|
55017
55376
|
try {
|
|
55018
|
-
return
|
|
55377
|
+
return path18.join(await fs6.realpath(probe), ...missingSuffix);
|
|
55019
55378
|
} catch {
|
|
55020
|
-
const parent =
|
|
55379
|
+
const parent = path18.dirname(probe);
|
|
55021
55380
|
if (parent === probe) return absoluteTarget;
|
|
55022
|
-
missingSuffix.unshift(
|
|
55381
|
+
missingSuffix.unshift(path18.basename(probe));
|
|
55023
55382
|
probe = parent;
|
|
55024
55383
|
}
|
|
55025
55384
|
}
|
|
@@ -55047,9 +55406,9 @@ function formatFieldValue(value) {
|
|
|
55047
55406
|
}
|
|
55048
55407
|
function inBundlePollutionWarning(bundle, out) {
|
|
55049
55408
|
if (bundle.backend) return void 0;
|
|
55050
|
-
const resolvedOut =
|
|
55409
|
+
const resolvedOut = path18.resolve(out);
|
|
55051
55410
|
const root = bundle.root;
|
|
55052
|
-
const isInside = resolvedOut === root || resolvedOut.startsWith(root +
|
|
55411
|
+
const isInside = resolvedOut === root || resolvedOut.startsWith(root + path18.sep);
|
|
55053
55412
|
if (!isInside) return void 0;
|
|
55054
55413
|
if (isReservedFile(resolvedOut)) {
|
|
55055
55414
|
return `--out ${out} resolves to ${resolvedOut}, which is INSIDE this bundle (${root}) at a reserved OKF filename \u2014 the write will CLOBBER that reserved file (index.md/log.md is never re-parsed as a concept doc). Pass a path outside the bundle if that is not intended.`;
|
|
@@ -55339,6 +55698,81 @@ function deleteOptionsFromHeaders(req) {
|
|
|
55339
55698
|
function versionHeaders(version2) {
|
|
55340
55699
|
return { "X-Version": version2, ETag: `"${version2}"` };
|
|
55341
55700
|
}
|
|
55701
|
+
function matchWireResources(pathname) {
|
|
55702
|
+
if (pathname === "/v0/capabilities") return [{ resource: "capabilities" }];
|
|
55703
|
+
const match = BUNDLE_PATH_RE.exec(pathname);
|
|
55704
|
+
if (!match) return [];
|
|
55705
|
+
const rest = match[2] ?? "";
|
|
55706
|
+
if (rest === "docs") return [{ resource: "docs" }];
|
|
55707
|
+
if (rest === "docs:read-many") return [{ resource: "docs-read-many" }];
|
|
55708
|
+
if (rest.startsWith("docs/")) {
|
|
55709
|
+
const tail = rest.slice("docs/".length);
|
|
55710
|
+
return tail.endsWith("/versions") ? [
|
|
55711
|
+
{ resource: "doc-versions", value: tail.slice(0, -"/versions".length) },
|
|
55712
|
+
{ resource: "doc", value: tail }
|
|
55713
|
+
] : [{ resource: "doc", value: tail }];
|
|
55714
|
+
}
|
|
55715
|
+
if (rest.startsWith("reserved/")) {
|
|
55716
|
+
return [{ resource: "reserved", value: rest.slice("reserved/".length) }];
|
|
55717
|
+
}
|
|
55718
|
+
if (rest === "blobs") return [{ resource: "blobs" }];
|
|
55719
|
+
if (rest.startsWith("blobs/")) return [{ resource: "blob", value: rest.slice("blobs/".length) }];
|
|
55720
|
+
return [];
|
|
55721
|
+
}
|
|
55722
|
+
function resolveWireEndpoint(resources, method) {
|
|
55723
|
+
for (const match of resources) {
|
|
55724
|
+
const endpoint = WIRE_ENDPOINTS.find((row2) => row2.resource === match.resource && row2.method === method);
|
|
55725
|
+
if (endpoint) return { endpoint, match };
|
|
55726
|
+
}
|
|
55727
|
+
return void 0;
|
|
55728
|
+
}
|
|
55729
|
+
function unsupportedMethodResponse(method, match) {
|
|
55730
|
+
let label;
|
|
55731
|
+
switch (match.resource) {
|
|
55732
|
+
case "docs":
|
|
55733
|
+
label = "/docs";
|
|
55734
|
+
break;
|
|
55735
|
+
case "docs-read-many":
|
|
55736
|
+
label = "/docs:read-many";
|
|
55737
|
+
break;
|
|
55738
|
+
case "doc":
|
|
55739
|
+
case "doc-versions":
|
|
55740
|
+
label = "a doc route";
|
|
55741
|
+
break;
|
|
55742
|
+
case "reserved":
|
|
55743
|
+
label = "a reserved-file route";
|
|
55744
|
+
break;
|
|
55745
|
+
case "blobs":
|
|
55746
|
+
label = "/blobs";
|
|
55747
|
+
break;
|
|
55748
|
+
case "blob":
|
|
55749
|
+
label = "a blob route";
|
|
55750
|
+
break;
|
|
55751
|
+
case "capabilities":
|
|
55752
|
+
label = "/v0/capabilities";
|
|
55753
|
+
break;
|
|
55754
|
+
}
|
|
55755
|
+
return errorResponse(400, "USAGE", `unsupported method ${method} for ${label}`);
|
|
55756
|
+
}
|
|
55757
|
+
function registeredWireRouter(dispatch) {
|
|
55758
|
+
return async function handle(req) {
|
|
55759
|
+
let url2;
|
|
55760
|
+
try {
|
|
55761
|
+
url2 = new URL(req.url);
|
|
55762
|
+
} catch {
|
|
55763
|
+
return errorResponse(400, "USAGE", "invalid request URL");
|
|
55764
|
+
}
|
|
55765
|
+
const resources = matchWireResources(url2.pathname);
|
|
55766
|
+
if (resources.length === 0) return errorResponse(404, "NOT_FOUND", `no route for ${url2.pathname}`);
|
|
55767
|
+
const resolved = resolveWireEndpoint(resources, req.method);
|
|
55768
|
+
if (!resolved) return unsupportedMethodResponse(req.method, resources[0]);
|
|
55769
|
+
try {
|
|
55770
|
+
return await dispatch(req, { ...resolved, searchParams: url2.searchParams });
|
|
55771
|
+
} catch (err) {
|
|
55772
|
+
return errorFromCaught(err);
|
|
55773
|
+
}
|
|
55774
|
+
};
|
|
55775
|
+
}
|
|
55342
55776
|
function createRouter(bundle) {
|
|
55343
55777
|
return buildRouter(bundle.backend ?? new FilesystemBackend(bundle.root));
|
|
55344
55778
|
}
|
|
@@ -55430,15 +55864,15 @@ function buildRouter(backend) {
|
|
|
55430
55864
|
results: results.map((r2) => ({ id: r2.doc.id, frontmatter: r2.doc.frontmatter, body: r2.doc.body, version: r2.version }))
|
|
55431
55865
|
});
|
|
55432
55866
|
}
|
|
55433
|
-
async function handleList(
|
|
55434
|
-
const prefix =
|
|
55435
|
-
const type =
|
|
55436
|
-
const tags =
|
|
55437
|
-
const fields =
|
|
55438
|
-
const limitParam =
|
|
55867
|
+
async function handleList(searchParams) {
|
|
55868
|
+
const prefix = searchParams.get("prefix") ?? void 0;
|
|
55869
|
+
const type = searchParams.get("type") ?? void 0;
|
|
55870
|
+
const tags = searchParams.getAll("tag");
|
|
55871
|
+
const fields = searchParams.get("fields");
|
|
55872
|
+
const limitParam = searchParams.get("limit");
|
|
55439
55873
|
const parsedLimit = limitParam ? parseInt(limitParam, 10) : NaN;
|
|
55440
55874
|
const limit = Number.isFinite(parsedLimit) && parsedLimit > 0 ? parsedLimit : DEFAULT_LIST_LIMIT;
|
|
55441
|
-
const cursor =
|
|
55875
|
+
const cursor = searchParams.get("cursor") ?? void 0;
|
|
55442
55876
|
const heads = await queryHeads(bundle, { prefix, type, tags });
|
|
55443
55877
|
const count = heads.length;
|
|
55444
55878
|
let page = heads;
|
|
@@ -55519,12 +55953,12 @@ function buildRouter(backend) {
|
|
|
55519
55953
|
const deleted = await backend.deleteBlob(key, options2);
|
|
55520
55954
|
return jsonResponse(200, { deleted });
|
|
55521
55955
|
}
|
|
55522
|
-
async function handleListBlobs(
|
|
55523
|
-
const prefix =
|
|
55524
|
-
const limitParam =
|
|
55956
|
+
async function handleListBlobs(searchParams) {
|
|
55957
|
+
const prefix = searchParams.get("prefix") ?? void 0;
|
|
55958
|
+
const limitParam = searchParams.get("limit");
|
|
55525
55959
|
const parsedLimit = limitParam ? parseInt(limitParam, 10) : NaN;
|
|
55526
55960
|
const limit = Number.isFinite(parsedLimit) && parsedLimit > 0 ? parsedLimit : DEFAULT_LIST_LIMIT;
|
|
55527
|
-
const cursor =
|
|
55961
|
+
const cursor = searchParams.get("cursor") ?? void 0;
|
|
55528
55962
|
const keys = await backend.listBlobs(prefix);
|
|
55529
55963
|
const count = keys.length;
|
|
55530
55964
|
let page = keys;
|
|
@@ -55554,69 +55988,47 @@ function buildRouter(backend) {
|
|
|
55554
55988
|
blobs: caps.blobs
|
|
55555
55989
|
});
|
|
55556
55990
|
}
|
|
55557
|
-
return async
|
|
55558
|
-
|
|
55559
|
-
|
|
55560
|
-
|
|
55561
|
-
|
|
55562
|
-
|
|
55563
|
-
|
|
55564
|
-
|
|
55565
|
-
|
|
55566
|
-
|
|
55567
|
-
|
|
55568
|
-
|
|
55569
|
-
|
|
55570
|
-
|
|
55571
|
-
|
|
55572
|
-
|
|
55573
|
-
|
|
55574
|
-
|
|
55575
|
-
|
|
55576
|
-
|
|
55577
|
-
|
|
55578
|
-
}
|
|
55579
|
-
if (rest.startsWith("docs/")) {
|
|
55580
|
-
const tail = rest.slice("docs/".length);
|
|
55581
|
-
if (tail.endsWith("/versions") && req.method === "GET") {
|
|
55582
|
-
return await handleVersions(decodeId(tail.slice(0, -"/versions".length)));
|
|
55583
|
-
}
|
|
55584
|
-
const id = decodeId(tail);
|
|
55585
|
-
if (req.method === "GET") return await handleReadDoc(id);
|
|
55586
|
-
if (req.method === "PUT") return await handleWriteDoc(id, req);
|
|
55587
|
-
if (req.method === "HEAD") return await handleHeadDoc(id);
|
|
55588
|
-
if (req.method === "DELETE") return await handleDeleteDoc(id, req);
|
|
55589
|
-
return errorResponse(400, "USAGE", `unsupported method ${req.method} for a doc route`);
|
|
55590
|
-
}
|
|
55591
|
-
if (rest.startsWith("reserved/")) {
|
|
55592
|
-
const name = rest.slice("reserved/".length);
|
|
55991
|
+
return registeredWireRouter(async (req, { endpoint, match, searchParams }) => {
|
|
55992
|
+
switch (endpoint.id) {
|
|
55993
|
+
case "capabilities":
|
|
55994
|
+
return handleCapabilities();
|
|
55995
|
+
case "docs-list":
|
|
55996
|
+
return await handleList(searchParams);
|
|
55997
|
+
case "docs-read-many":
|
|
55998
|
+
return await handleReadMany(req);
|
|
55999
|
+
case "doc-versions":
|
|
56000
|
+
return await handleVersions(decodeId(match.value));
|
|
56001
|
+
case "doc-read":
|
|
56002
|
+
return await handleReadDoc(decodeId(match.value));
|
|
56003
|
+
case "doc-write":
|
|
56004
|
+
return await handleWriteDoc(decodeId(match.value), req);
|
|
56005
|
+
case "doc-head":
|
|
56006
|
+
return await handleHeadDoc(decodeId(match.value));
|
|
56007
|
+
case "doc-delete":
|
|
56008
|
+
return await handleDeleteDoc(decodeId(match.value), req);
|
|
56009
|
+
case "reserved-read":
|
|
56010
|
+
case "reserved-write": {
|
|
56011
|
+
const name = match.value;
|
|
55593
56012
|
if (name !== "index.md" && name !== "log.md") {
|
|
55594
56013
|
return errorResponse(400, "USAGE", `reserved file name must be index.md or log.md, got '${name}'`);
|
|
55595
56014
|
}
|
|
55596
|
-
const dir =
|
|
55597
|
-
|
|
55598
|
-
if (req.method === "PUT") return await handleWriteReserved(dir, name, req);
|
|
55599
|
-
return errorResponse(400, "USAGE", `unsupported method ${req.method} for a reserved-file route`);
|
|
55600
|
-
}
|
|
55601
|
-
if (rest === "blobs") {
|
|
55602
|
-
if (req.method === "GET") return await handleListBlobs(url2);
|
|
55603
|
-
return errorResponse(400, "USAGE", `unsupported method ${req.method} for /blobs`);
|
|
55604
|
-
}
|
|
55605
|
-
if (rest.startsWith("blobs/")) {
|
|
55606
|
-
const key = decodeBlobKey(rest.slice("blobs/".length));
|
|
55607
|
-
if (req.method === "GET") return await handleReadBlob(key);
|
|
55608
|
-
if (req.method === "PUT") return await handleWriteBlob(key, req);
|
|
55609
|
-
if (req.method === "HEAD") return await handleHeadBlob(key);
|
|
55610
|
-
if (req.method === "DELETE") return await handleDeleteBlob(key, req);
|
|
55611
|
-
return errorResponse(400, "USAGE", `unsupported method ${req.method} for a blob route`);
|
|
56015
|
+
const dir = searchParams.get("dir") ?? "";
|
|
56016
|
+
return endpoint.id === "reserved-read" ? await handleReadReserved(dir, name) : await handleWriteReserved(dir, name, req);
|
|
55612
56017
|
}
|
|
55613
|
-
|
|
55614
|
-
|
|
55615
|
-
|
|
56018
|
+
case "blobs-list":
|
|
56019
|
+
return await handleListBlobs(searchParams);
|
|
56020
|
+
case "blob-read":
|
|
56021
|
+
return await handleReadBlob(decodeBlobKey(match.value));
|
|
56022
|
+
case "blob-write":
|
|
56023
|
+
return await handleWriteBlob(decodeBlobKey(match.value), req);
|
|
56024
|
+
case "blob-head":
|
|
56025
|
+
return await handleHeadBlob(decodeBlobKey(match.value));
|
|
56026
|
+
case "blob-delete":
|
|
56027
|
+
return await handleDeleteBlob(decodeBlobKey(match.value), req);
|
|
55616
56028
|
}
|
|
55617
|
-
};
|
|
56029
|
+
});
|
|
55618
56030
|
}
|
|
55619
|
-
var DEFAULT_LIST_LIMIT, BUNDLE_PATH_RE;
|
|
56031
|
+
var DEFAULT_LIST_LIMIT, BUNDLE_PATH_RE, WIRE_ENDPOINTS;
|
|
55620
56032
|
var init_router = __esm({
|
|
55621
56033
|
"../server/src/router.ts"() {
|
|
55622
56034
|
"use strict";
|
|
@@ -55625,6 +56037,48 @@ var init_router = __esm({
|
|
|
55625
56037
|
init_src();
|
|
55626
56038
|
DEFAULT_LIST_LIMIT = 50;
|
|
55627
56039
|
BUNDLE_PATH_RE = /^\/v0\/bundles\/([^/]+)\/(.*)$/;
|
|
56040
|
+
WIRE_ENDPOINTS = [
|
|
56041
|
+
{ id: "capabilities", resource: "capabilities", method: "GET", path: "/v0/capabilities" },
|
|
56042
|
+
{ id: "docs-list", resource: "docs", method: "GET", path: "/v0/bundles/{bundle}/docs" },
|
|
56043
|
+
{
|
|
56044
|
+
id: "docs-read-many",
|
|
56045
|
+
resource: "docs-read-many",
|
|
56046
|
+
method: "POST",
|
|
56047
|
+
path: "/v0/bundles/{bundle}/docs:read-many"
|
|
56048
|
+
},
|
|
56049
|
+
{ id: "doc-read", resource: "doc", method: "GET", path: "/v0/bundles/{bundle}/docs/{id...}" },
|
|
56050
|
+
{ id: "doc-write", resource: "doc", method: "PUT", path: "/v0/bundles/{bundle}/docs/{id...}" },
|
|
56051
|
+
{ id: "doc-head", resource: "doc", method: "HEAD", path: "/v0/bundles/{bundle}/docs/{id...}" },
|
|
56052
|
+
{ id: "doc-delete", resource: "doc", method: "DELETE", path: "/v0/bundles/{bundle}/docs/{id...}" },
|
|
56053
|
+
{
|
|
56054
|
+
id: "doc-versions",
|
|
56055
|
+
resource: "doc-versions",
|
|
56056
|
+
method: "GET",
|
|
56057
|
+
path: "/v0/bundles/{bundle}/docs/{id...}/versions"
|
|
56058
|
+
},
|
|
56059
|
+
{
|
|
56060
|
+
id: "reserved-read",
|
|
56061
|
+
resource: "reserved",
|
|
56062
|
+
method: "GET",
|
|
56063
|
+
path: "/v0/bundles/{bundle}/reserved/{name}"
|
|
56064
|
+
},
|
|
56065
|
+
{
|
|
56066
|
+
id: "reserved-write",
|
|
56067
|
+
resource: "reserved",
|
|
56068
|
+
method: "PUT",
|
|
56069
|
+
path: "/v0/bundles/{bundle}/reserved/{name}"
|
|
56070
|
+
},
|
|
56071
|
+
{ id: "blobs-list", resource: "blobs", method: "GET", path: "/v0/bundles/{bundle}/blobs" },
|
|
56072
|
+
{ id: "blob-read", resource: "blob", method: "GET", path: "/v0/bundles/{bundle}/blobs/{key...}" },
|
|
56073
|
+
{ id: "blob-write", resource: "blob", method: "PUT", path: "/v0/bundles/{bundle}/blobs/{key...}" },
|
|
56074
|
+
{ id: "blob-head", resource: "blob", method: "HEAD", path: "/v0/bundles/{bundle}/blobs/{key...}" },
|
|
56075
|
+
{
|
|
56076
|
+
id: "blob-delete",
|
|
56077
|
+
resource: "blob",
|
|
56078
|
+
method: "DELETE",
|
|
56079
|
+
path: "/v0/bundles/{bundle}/blobs/{key...}"
|
|
56080
|
+
}
|
|
56081
|
+
];
|
|
55628
56082
|
}
|
|
55629
56083
|
});
|
|
55630
56084
|
|
|
@@ -58373,7 +58827,7 @@ var init_src6 = __esm({
|
|
|
58373
58827
|
});
|
|
58374
58828
|
|
|
58375
58829
|
// src/bundle-name.ts
|
|
58376
|
-
import
|
|
58830
|
+
import path19 from "node:path";
|
|
58377
58831
|
function nonEmptyString3(value) {
|
|
58378
58832
|
if (typeof value !== "string") return void 0;
|
|
58379
58833
|
const trimmed = value.trim();
|
|
@@ -58388,9 +58842,9 @@ async function deriveBundleDisplayName(bundle) {
|
|
|
58388
58842
|
}
|
|
58389
58843
|
} catch {
|
|
58390
58844
|
}
|
|
58391
|
-
const base =
|
|
58845
|
+
const base = path19.basename(bundle.root);
|
|
58392
58846
|
if (base === CONVENTIONAL_BUNDLE_DIR_NAME || base === LEGACY_CONVENTIONAL_BUNDLE_DIR_NAME) {
|
|
58393
|
-
const parent =
|
|
58847
|
+
const parent = path19.basename(path19.dirname(bundle.root));
|
|
58394
58848
|
if (parent) return { name: parent, source: "conventional-parent" };
|
|
58395
58849
|
}
|
|
58396
58850
|
return { name: base || FALLBACK_NAME, source: "root-basename" };
|
|
@@ -58443,15 +58897,15 @@ var init_assets2 = __esm({
|
|
|
58443
58897
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
58444
58898
|
import { open as open2, readFile as readFile3, stat as stat2, unlink as unlink2 } from "node:fs/promises";
|
|
58445
58899
|
import { homedir as homedir10 } from "node:os";
|
|
58446
|
-
import
|
|
58900
|
+
import path20 from "node:path";
|
|
58447
58901
|
function catalogDir(home2) {
|
|
58448
58902
|
return credentialsDir(home2);
|
|
58449
58903
|
}
|
|
58450
58904
|
function catalogPath(home2 = homedir10()) {
|
|
58451
|
-
return
|
|
58905
|
+
return path20.join(catalogDir(home2), CATALOG_FILE_NAME);
|
|
58452
58906
|
}
|
|
58453
58907
|
function catalogLockPath(home2 = homedir10()) {
|
|
58454
|
-
return
|
|
58908
|
+
return path20.join(catalogDir(home2), CATALOG_LOCK_FILE_NAME);
|
|
58455
58909
|
}
|
|
58456
58910
|
function isObject2(value) {
|
|
58457
58911
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -58491,7 +58945,7 @@ function validateEntry(value, file2, index2) {
|
|
|
58491
58945
|
if (value.locator.kind !== "local-path") {
|
|
58492
58946
|
throw invalidCatalog(file2, `entries[${index2}].locator.kind must be "local-path"`);
|
|
58493
58947
|
}
|
|
58494
|
-
if (typeof value.locator.path !== "string" || !
|
|
58948
|
+
if (typeof value.locator.path !== "string" || !path20.isAbsolute(value.locator.path) || path20.normalize(value.locator.path) !== value.locator.path) {
|
|
58495
58949
|
throw invalidCatalog(file2, `entries[${index2}].locator.path must be a normalized absolute path`);
|
|
58496
58950
|
}
|
|
58497
58951
|
return {
|
|
@@ -58668,7 +59122,7 @@ function generatedId(options2, existing) {
|
|
|
58668
59122
|
}
|
|
58669
59123
|
async function addCatalogEntry(label, canonicalPath, options2 = {}) {
|
|
58670
59124
|
assertCatalogLabel(label);
|
|
58671
|
-
if (!
|
|
59125
|
+
if (!path20.isAbsolute(canonicalPath)) throw new CliError("USAGE", "workspace catalog paths must be absolute");
|
|
58672
59126
|
const result3 = await mutateCatalog(async (current) => {
|
|
58673
59127
|
const target = await resolveLocalBundleTarget(canonicalPath);
|
|
58674
59128
|
if (target.canonicalRoot !== canonicalPath) {
|
|
@@ -58771,7 +59225,7 @@ var init_catalog2 = __esm({
|
|
|
58771
59225
|
});
|
|
58772
59226
|
|
|
58773
59227
|
// src/ui/sharing.ts
|
|
58774
|
-
import
|
|
59228
|
+
import path21 from "node:path";
|
|
58775
59229
|
import { realpathSync as realpathSync10 } from "node:fs";
|
|
58776
59230
|
function realOr(p2) {
|
|
58777
59231
|
try {
|
|
@@ -58810,13 +59264,13 @@ function classifySharing(bundleRoot, now = () => /* @__PURE__ */ new Date()) {
|
|
|
58810
59264
|
const asOf = now().toISOString();
|
|
58811
59265
|
try {
|
|
58812
59266
|
const root = realOr(bundleRoot);
|
|
58813
|
-
const repo = probeRepoTopLevel(
|
|
59267
|
+
const repo = probeRepoTopLevel(path21.dirname(root));
|
|
58814
59268
|
if (repo.kind === "not_repo") return { kind: "private", as_of: asOf };
|
|
58815
59269
|
if (repo.kind === "unavailable") return { kind: "unavailable", reason: repo.reason, as_of: asOf };
|
|
58816
59270
|
const top = repo.top;
|
|
58817
59271
|
const committed = committedBundleAtHead(top);
|
|
58818
59272
|
const bundleDir = committed?.bundleDir ?? bundleDirNameForProject(top);
|
|
58819
|
-
if (realOr(
|
|
59273
|
+
if (realOr(path21.join(top, bundleDir)) !== root) return { kind: "unscoped", as_of: asOf };
|
|
58820
59274
|
const evidence = localEvidence(top, committed !== null);
|
|
58821
59275
|
const branchMode = hasWorktreeSignature(root) && worktreeRootResolvesForOwner(root, top) || !evidence.tracked && localBranchExists(top, BOARD_BRANCH);
|
|
58822
59276
|
if (branchMode) {
|
|
@@ -58898,7 +59352,7 @@ var init_sharing = __esm({
|
|
|
58898
59352
|
});
|
|
58899
59353
|
|
|
58900
59354
|
// src/ui/view-authorizations.ts
|
|
58901
|
-
import { createHash as
|
|
59355
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
58902
59356
|
import { homedir as homedir11 } from "node:os";
|
|
58903
59357
|
import { join as join9 } from "node:path";
|
|
58904
59358
|
function stableRecord(bundle, subject) {
|
|
@@ -58948,12 +59402,12 @@ function assertMigratableViewAuthorization(name, raw) {
|
|
|
58948
59402
|
}
|
|
58949
59403
|
const canonical = JSON.stringify(value);
|
|
58950
59404
|
if (raw !== `${canonical}
|
|
58951
|
-
` || name !== `${
|
|
59405
|
+
` || name !== `${createHash6("sha256").update(canonical).digest("hex")}.json`) {
|
|
58952
59406
|
throw new Error("legacy View authorization does not match its immutable identity");
|
|
58953
59407
|
}
|
|
58954
59408
|
}
|
|
58955
59409
|
function fileName(bundle, subject) {
|
|
58956
|
-
return `${
|
|
59410
|
+
return `${createHash6("sha256").update(serialized(bundle, subject)).digest("hex")}.json`;
|
|
58957
59411
|
}
|
|
58958
59412
|
var STORE_DIR, LocalViewAuthorizationStore;
|
|
58959
59413
|
var init_view_authorizations = __esm({
|
|
@@ -59592,7 +60046,7 @@ Options:
|
|
|
59592
60046
|
// src/commands/pull.ts
|
|
59593
60047
|
import { parseArgs as parseArgs9 } from "node:util";
|
|
59594
60048
|
import { promises as fs7 } from "node:fs";
|
|
59595
|
-
import
|
|
60049
|
+
import path22 from "node:path";
|
|
59596
60050
|
function isDocRouteKey2(key) {
|
|
59597
60051
|
return key.toLowerCase().endsWith(".md");
|
|
59598
60052
|
}
|
|
@@ -59683,7 +60137,7 @@ async function pull(argv2, deps = {}) {
|
|
|
59683
60137
|
help: `${cliInvocation()} pull --doc-key ${key} --out <path>`
|
|
59684
60138
|
});
|
|
59685
60139
|
}
|
|
59686
|
-
if (out !== "-") assertPathOutsidePrivateState(
|
|
60140
|
+
if (out !== "-") assertPathOutsidePrivateState(path22.resolve(out));
|
|
59687
60141
|
const bundle = await openBundle(values.dir, await resolveRemoteFlag(values.remote, values.dir));
|
|
59688
60142
|
const mode = resolveMode(values);
|
|
59689
60143
|
const streamMode = out === "-";
|
|
@@ -63055,8 +63509,8 @@ var init_parseUtil = __esm({
|
|
|
63055
63509
|
init_errors5();
|
|
63056
63510
|
init_en();
|
|
63057
63511
|
makeIssue = (params) => {
|
|
63058
|
-
const { data, path:
|
|
63059
|
-
const fullPath = [...
|
|
63512
|
+
const { data, path: path29, errorMaps, issueData } = params;
|
|
63513
|
+
const fullPath = [...path29, ...issueData.path || []];
|
|
63060
63514
|
const fullIssue = {
|
|
63061
63515
|
...issueData,
|
|
63062
63516
|
path: fullPath
|
|
@@ -63342,11 +63796,11 @@ var init_types = __esm({
|
|
|
63342
63796
|
init_parseUtil();
|
|
63343
63797
|
init_util();
|
|
63344
63798
|
ParseInputLazyPath = class {
|
|
63345
|
-
constructor(parent, value,
|
|
63799
|
+
constructor(parent, value, path29, key) {
|
|
63346
63800
|
this._cachedPath = [];
|
|
63347
63801
|
this.parent = parent;
|
|
63348
63802
|
this.data = value;
|
|
63349
|
-
this._path =
|
|
63803
|
+
this._path = path29;
|
|
63350
63804
|
this._key = key;
|
|
63351
63805
|
}
|
|
63352
63806
|
get path() {
|
|
@@ -66852,10 +67306,10 @@ function mergeDefs(...defs) {
|
|
|
66852
67306
|
function cloneDef(schema) {
|
|
66853
67307
|
return mergeDefs(schema._zod.def);
|
|
66854
67308
|
}
|
|
66855
|
-
function getElementAtPath(obj,
|
|
66856
|
-
if (!
|
|
67309
|
+
function getElementAtPath(obj, path29) {
|
|
67310
|
+
if (!path29)
|
|
66857
67311
|
return obj;
|
|
66858
|
-
return
|
|
67312
|
+
return path29.reduce((acc, key) => acc?.[key], obj);
|
|
66859
67313
|
}
|
|
66860
67314
|
function promiseAllObject(promisesObj) {
|
|
66861
67315
|
const keys = Object.keys(promisesObj);
|
|
@@ -67183,11 +67637,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
67183
67637
|
}
|
|
67184
67638
|
return false;
|
|
67185
67639
|
}
|
|
67186
|
-
function prefixIssues(
|
|
67640
|
+
function prefixIssues(path29, issues) {
|
|
67187
67641
|
return issues.map((iss) => {
|
|
67188
67642
|
var _a3;
|
|
67189
67643
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
67190
|
-
iss.path.unshift(
|
|
67644
|
+
iss.path.unshift(path29);
|
|
67191
67645
|
return iss;
|
|
67192
67646
|
});
|
|
67193
67647
|
}
|
|
@@ -67406,16 +67860,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
67406
67860
|
}
|
|
67407
67861
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
67408
67862
|
const fieldErrors = { _errors: [] };
|
|
67409
|
-
const processError = (error52,
|
|
67863
|
+
const processError = (error52, path29 = []) => {
|
|
67410
67864
|
for (const issue2 of error52.issues) {
|
|
67411
67865
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
67412
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
67866
|
+
issue2.errors.map((issues) => processError({ issues }, [...path29, ...issue2.path]));
|
|
67413
67867
|
} else if (issue2.code === "invalid_key") {
|
|
67414
|
-
processError({ issues: issue2.issues }, [...
|
|
67868
|
+
processError({ issues: issue2.issues }, [...path29, ...issue2.path]);
|
|
67415
67869
|
} else if (issue2.code === "invalid_element") {
|
|
67416
|
-
processError({ issues: issue2.issues }, [...
|
|
67870
|
+
processError({ issues: issue2.issues }, [...path29, ...issue2.path]);
|
|
67417
67871
|
} else {
|
|
67418
|
-
const fullpath = [...
|
|
67872
|
+
const fullpath = [...path29, ...issue2.path];
|
|
67419
67873
|
if (fullpath.length === 0) {
|
|
67420
67874
|
fieldErrors._errors.push(mapper(issue2));
|
|
67421
67875
|
} else {
|
|
@@ -67442,17 +67896,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
67442
67896
|
}
|
|
67443
67897
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
67444
67898
|
const result3 = { errors: [] };
|
|
67445
|
-
const processError = (error52,
|
|
67899
|
+
const processError = (error52, path29 = []) => {
|
|
67446
67900
|
var _a3, _b;
|
|
67447
67901
|
for (const issue2 of error52.issues) {
|
|
67448
67902
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
67449
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
67903
|
+
issue2.errors.map((issues) => processError({ issues }, [...path29, ...issue2.path]));
|
|
67450
67904
|
} else if (issue2.code === "invalid_key") {
|
|
67451
|
-
processError({ issues: issue2.issues }, [...
|
|
67905
|
+
processError({ issues: issue2.issues }, [...path29, ...issue2.path]);
|
|
67452
67906
|
} else if (issue2.code === "invalid_element") {
|
|
67453
|
-
processError({ issues: issue2.issues }, [...
|
|
67907
|
+
processError({ issues: issue2.issues }, [...path29, ...issue2.path]);
|
|
67454
67908
|
} else {
|
|
67455
|
-
const fullpath = [...
|
|
67909
|
+
const fullpath = [...path29, ...issue2.path];
|
|
67456
67910
|
if (fullpath.length === 0) {
|
|
67457
67911
|
result3.errors.push(mapper(issue2));
|
|
67458
67912
|
continue;
|
|
@@ -67484,8 +67938,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
67484
67938
|
}
|
|
67485
67939
|
function toDotPath(_path) {
|
|
67486
67940
|
const segs = [];
|
|
67487
|
-
const
|
|
67488
|
-
for (const seg of
|
|
67941
|
+
const path29 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
67942
|
+
for (const seg of path29) {
|
|
67489
67943
|
if (typeof seg === "number")
|
|
67490
67944
|
segs.push(`[${seg}]`);
|
|
67491
67945
|
else if (typeof seg === "symbol")
|
|
@@ -81327,13 +81781,13 @@ function resolveRef(ref, ctx) {
|
|
|
81327
81781
|
if (!ref.startsWith("#")) {
|
|
81328
81782
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
81329
81783
|
}
|
|
81330
|
-
const
|
|
81331
|
-
if (
|
|
81784
|
+
const path29 = ref.slice(1).split("/").filter(Boolean);
|
|
81785
|
+
if (path29.length === 0) {
|
|
81332
81786
|
return ctx.rootSchema;
|
|
81333
81787
|
}
|
|
81334
81788
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
81335
|
-
if (
|
|
81336
|
-
const key =
|
|
81789
|
+
if (path29[0] === defsKey) {
|
|
81790
|
+
const key = path29[1];
|
|
81337
81791
|
if (!key || !ctx.defs[key]) {
|
|
81338
81792
|
throw new Error(`Reference not found: ${ref}`);
|
|
81339
81793
|
}
|
|
@@ -89904,8 +90358,8 @@ var require_utils2 = __commonJS({
|
|
|
89904
90358
|
}
|
|
89905
90359
|
return ind;
|
|
89906
90360
|
}
|
|
89907
|
-
function removeDotSegments(
|
|
89908
|
-
let input =
|
|
90361
|
+
function removeDotSegments(path29) {
|
|
90362
|
+
let input = path29;
|
|
89909
90363
|
const output = [];
|
|
89910
90364
|
let nextSlash = -1;
|
|
89911
90365
|
let len = 0;
|
|
@@ -90159,8 +90613,8 @@ var require_schemes = __commonJS({
|
|
|
90159
90613
|
wsComponent.secure = void 0;
|
|
90160
90614
|
}
|
|
90161
90615
|
if (wsComponent.resourceName) {
|
|
90162
|
-
const [
|
|
90163
|
-
wsComponent.path =
|
|
90616
|
+
const [path29, query2] = wsComponent.resourceName.split("?");
|
|
90617
|
+
wsComponent.path = path29 && path29 !== "/" ? path29 : void 0;
|
|
90164
90618
|
wsComponent.query = query2;
|
|
90165
90619
|
wsComponent.resourceName = void 0;
|
|
90166
90620
|
}
|
|
@@ -97566,12 +98020,12 @@ function parseTree(text4, errors = [], options2 = ParseOptions.DEFAULT) {
|
|
|
97566
98020
|
}
|
|
97567
98021
|
return result3;
|
|
97568
98022
|
}
|
|
97569
|
-
function findNodeAtLocation(root,
|
|
98023
|
+
function findNodeAtLocation(root, path29) {
|
|
97570
98024
|
if (!root) {
|
|
97571
98025
|
return void 0;
|
|
97572
98026
|
}
|
|
97573
98027
|
let node2 = root;
|
|
97574
|
-
for (let segment of
|
|
98028
|
+
for (let segment of path29) {
|
|
97575
98029
|
if (typeof segment === "string") {
|
|
97576
98030
|
if (node2.type !== "object" || !Array.isArray(node2.children)) {
|
|
97577
98031
|
return void 0;
|
|
@@ -97961,14 +98415,14 @@ var init_parser = __esm({
|
|
|
97961
98415
|
|
|
97962
98416
|
// ../../node_modules/jsonc-parser/lib/esm/impl/edit.js
|
|
97963
98417
|
function setProperty(text4, originalPath, value, options2) {
|
|
97964
|
-
const
|
|
98418
|
+
const path29 = originalPath.slice();
|
|
97965
98419
|
const errors = [];
|
|
97966
98420
|
const root = parseTree(text4, errors);
|
|
97967
98421
|
let parent = void 0;
|
|
97968
98422
|
let lastSegment = void 0;
|
|
97969
|
-
while (
|
|
97970
|
-
lastSegment =
|
|
97971
|
-
parent = findNodeAtLocation(root,
|
|
98423
|
+
while (path29.length > 0) {
|
|
98424
|
+
lastSegment = path29.pop();
|
|
98425
|
+
parent = findNodeAtLocation(root, path29);
|
|
97972
98426
|
if (parent === void 0 && value !== void 0) {
|
|
97973
98427
|
if (typeof lastSegment === "string") {
|
|
97974
98428
|
value = { [lastSegment]: value };
|
|
@@ -98113,8 +98567,8 @@ var init_edit = __esm({
|
|
|
98113
98567
|
});
|
|
98114
98568
|
|
|
98115
98569
|
// ../../node_modules/jsonc-parser/lib/esm/main.js
|
|
98116
|
-
function modify(text4,
|
|
98117
|
-
return setProperty(text4,
|
|
98570
|
+
function modify(text4, path29, value, options2) {
|
|
98571
|
+
return setProperty(text4, path29, value, options2);
|
|
98118
98572
|
}
|
|
98119
98573
|
function applyEdits(text4, edits) {
|
|
98120
98574
|
let sortedEdits = edits.slice(0).sort((a, b) => {
|
|
@@ -98598,8 +99052,8 @@ function environment(deps) {
|
|
|
98598
99052
|
}
|
|
98599
99053
|
function inspectMcpHost(target, deps = {}) {
|
|
98600
99054
|
const input = environment(deps);
|
|
98601
|
-
const
|
|
98602
|
-
if (!
|
|
99055
|
+
const path29 = resolveMcpTargetConfigPath(target.id, input);
|
|
99056
|
+
if (!path29) {
|
|
98603
99057
|
return {
|
|
98604
99058
|
host: target.id,
|
|
98605
99059
|
label: target.label,
|
|
@@ -98610,7 +99064,7 @@ function inspectMcpHost(target, deps = {}) {
|
|
|
98610
99064
|
};
|
|
98611
99065
|
}
|
|
98612
99066
|
const authority = deps.authority?.() ?? resolvePersistentInstallAuthority({ env: input.env, platform: input.platform });
|
|
98613
|
-
let reportedPath =
|
|
99067
|
+
let reportedPath = path29;
|
|
98614
99068
|
try {
|
|
98615
99069
|
let entries;
|
|
98616
99070
|
if (target.id === "codex") {
|
|
@@ -98625,7 +99079,7 @@ function inspectMcpHost(target, deps = {}) {
|
|
|
98625
99079
|
}));
|
|
98626
99080
|
} else {
|
|
98627
99081
|
const read = deps.readFile ?? ((candidate) => readFileSync6(candidate, "utf8"));
|
|
98628
|
-
const candidates = target.id === "opencode" ? openCodeConfigCandidates(input) : [
|
|
99082
|
+
const candidates = target.id === "opencode" ? openCodeConfigCandidates(input) : [path29];
|
|
98629
99083
|
const sources = [];
|
|
98630
99084
|
for (const candidate of candidates) {
|
|
98631
99085
|
try {
|
|
@@ -98759,26 +99213,26 @@ import { dirname as dirname4 } from "node:path";
|
|
|
98759
99213
|
function missing(error51) {
|
|
98760
99214
|
return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === "ENOENT";
|
|
98761
99215
|
}
|
|
98762
|
-
function resolveWriteDestination(
|
|
99216
|
+
function resolveWriteDestination(path29, followFinalSymlink) {
|
|
98763
99217
|
let isLink = false;
|
|
98764
99218
|
try {
|
|
98765
|
-
isLink = lstatSync4(
|
|
99219
|
+
isLink = lstatSync4(path29).isSymbolicLink();
|
|
98766
99220
|
} catch (error51) {
|
|
98767
|
-
if (missing(error51)) return
|
|
99221
|
+
if (missing(error51)) return path29;
|
|
98768
99222
|
throw error51;
|
|
98769
99223
|
}
|
|
98770
|
-
if (!isLink) return
|
|
99224
|
+
if (!isLink) return path29;
|
|
98771
99225
|
if (!followFinalSymlink) {
|
|
98772
|
-
throw new Error(`symlink at ${
|
|
99226
|
+
throw new Error(`symlink at ${path29} \u2014 refusing to replace a generated plugin through a link`);
|
|
98773
99227
|
}
|
|
98774
99228
|
try {
|
|
98775
|
-
return realpathSync12(
|
|
99229
|
+
return realpathSync12(path29);
|
|
98776
99230
|
} catch {
|
|
98777
|
-
throw new Error(`dangling symlink at ${
|
|
99231
|
+
throw new Error(`dangling symlink at ${path29} \u2014 refusing to write through it; fix or remove the link`);
|
|
98778
99232
|
}
|
|
98779
99233
|
}
|
|
98780
|
-
function capturePrivateConfigParent(
|
|
98781
|
-
let current = dirname4(
|
|
99234
|
+
function capturePrivateConfigParent(path29) {
|
|
99235
|
+
let current = dirname4(path29);
|
|
98782
99236
|
while (true) {
|
|
98783
99237
|
try {
|
|
98784
99238
|
return { path: current, destination: realpathSync12(current) };
|
|
@@ -98790,18 +99244,18 @@ function capturePrivateConfigParent(path28) {
|
|
|
98790
99244
|
}
|
|
98791
99245
|
}
|
|
98792
99246
|
}
|
|
98793
|
-
function atomicWriteFileSync(
|
|
98794
|
-
const destination = resolveWriteDestination(
|
|
99247
|
+
function atomicWriteFileSync(path29, content3, options2 = {}) {
|
|
99248
|
+
const destination = resolveWriteDestination(path29, options2.followFinalSymlink ?? true);
|
|
98795
99249
|
if (options2.expected) {
|
|
98796
99250
|
if (options2.expected.parent) {
|
|
98797
|
-
const currentParent = capturePrivateConfigParent(
|
|
99251
|
+
const currentParent = capturePrivateConfigParent(path29);
|
|
98798
99252
|
if (currentParent.path !== options2.expected.parent.path || currentParent.destination !== options2.expected.parent.destination) {
|
|
98799
99253
|
throw new Error("private configuration parent changed after inspection");
|
|
98800
99254
|
}
|
|
98801
99255
|
}
|
|
98802
99256
|
let currentDestination;
|
|
98803
99257
|
try {
|
|
98804
|
-
currentDestination = realpathSync12(
|
|
99258
|
+
currentDestination = realpathSync12(path29);
|
|
98805
99259
|
} catch (error51) {
|
|
98806
99260
|
if (!missing(error51)) throw error51;
|
|
98807
99261
|
currentDestination = null;
|
|
@@ -98870,7 +99324,7 @@ function defaultEnvironment() {
|
|
|
98870
99324
|
function isMissing(error51) {
|
|
98871
99325
|
return isRecord8(error51) && own4(error51, "code") === "ENOENT";
|
|
98872
99326
|
}
|
|
98873
|
-
function resolvedPath(
|
|
99327
|
+
function resolvedPath(path29, deps) {
|
|
98874
99328
|
const resolve2 = deps.realpath ?? ((candidate) => {
|
|
98875
99329
|
try {
|
|
98876
99330
|
return realpathSync13(candidate);
|
|
@@ -98879,11 +99333,11 @@ function resolvedPath(path28, deps) {
|
|
|
98879
99333
|
throw error51;
|
|
98880
99334
|
}
|
|
98881
99335
|
});
|
|
98882
|
-
return resolve2(
|
|
99336
|
+
return resolve2(path29);
|
|
98883
99337
|
}
|
|
98884
|
-
function readOptional(
|
|
99338
|
+
function readOptional(path29, read) {
|
|
98885
99339
|
try {
|
|
98886
|
-
return read(
|
|
99340
|
+
return read(path29);
|
|
98887
99341
|
} catch (error51) {
|
|
98888
99342
|
if (isMissing(error51)) return void 0;
|
|
98889
99343
|
throw error51;
|
|
@@ -98933,8 +99387,8 @@ function selectedSources(sources) {
|
|
|
98933
99387
|
}
|
|
98934
99388
|
function inspectTarget(target, deps) {
|
|
98935
99389
|
const input = deps.environment ?? defaultEnvironment();
|
|
98936
|
-
const
|
|
98937
|
-
if (!
|
|
99390
|
+
const path29 = resolveMcpTargetConfigPath(target.id, input);
|
|
99391
|
+
if (!path29) {
|
|
98938
99392
|
throw new McpRegistrationError(`no supported ${target.label} local-config path on ${input.platform}`, {
|
|
98939
99393
|
host: target.id
|
|
98940
99394
|
}, [target.docs_url], "usage");
|
|
@@ -98950,20 +99404,20 @@ function inspectTarget(target, deps) {
|
|
|
98950
99404
|
host: target.id
|
|
98951
99405
|
}, [target.docs_url], "runtime");
|
|
98952
99406
|
}
|
|
98953
|
-
return { entries, selected: selectMcpRegistration(entries), config: collapseHomeDirectory(
|
|
99407
|
+
return { entries, selected: selectMcpRegistration(entries), config: collapseHomeDirectory(path29) };
|
|
98954
99408
|
}
|
|
98955
99409
|
if (target.id !== "opencode") {
|
|
98956
|
-
const text4 = readOptional(
|
|
99410
|
+
const text4 = readOptional(path29, read);
|
|
98957
99411
|
const entries = text4 === void 0 ? [] : parseClaudeMcpEntries(text4, target.id);
|
|
98958
99412
|
return {
|
|
98959
99413
|
entries,
|
|
98960
99414
|
selected: selectMcpRegistration(entries),
|
|
98961
|
-
config: collapseHomeDirectory(
|
|
98962
|
-
sourcePath:
|
|
99415
|
+
config: collapseHomeDirectory(path29),
|
|
99416
|
+
sourcePath: path29,
|
|
98963
99417
|
sourceText: text4 ?? "{}\n",
|
|
98964
99418
|
sourceExists: text4 !== void 0,
|
|
98965
|
-
sourceDestination: text4 === void 0 ? null : resolvedPath(
|
|
98966
|
-
sourceParent: capturePrivateConfigParent(
|
|
99419
|
+
sourceDestination: text4 === void 0 ? null : resolvedPath(path29, deps) ?? null,
|
|
99420
|
+
sourceParent: capturePrivateConfigParent(path29)
|
|
98967
99421
|
};
|
|
98968
99422
|
}
|
|
98969
99423
|
if (input.env.OPENCODE_CONFIG_CONTENT?.trim()) {
|
|
@@ -99006,7 +99460,7 @@ function inspectTarget(target, deps) {
|
|
|
99006
99460
|
configs: standard.map((candidate) => collapseHomeDirectory(candidate.path))
|
|
99007
99461
|
});
|
|
99008
99462
|
}
|
|
99009
|
-
source = standard[0] ?? { path:
|
|
99463
|
+
source = standard[0] ?? { path: path29, text: "{}\n", entries: [], destination: null, exists: false };
|
|
99010
99464
|
}
|
|
99011
99465
|
}
|
|
99012
99466
|
const root = parseMcpConfigRoot(source.text);
|
|
@@ -99063,8 +99517,8 @@ function inspectForMutation(target, deps) {
|
|
|
99063
99517
|
}, [target.docs_url], "runtime");
|
|
99064
99518
|
}
|
|
99065
99519
|
}
|
|
99066
|
-
function editJsonc(text4,
|
|
99067
|
-
const edits = modify(text4, [...
|
|
99520
|
+
function editJsonc(text4, path29, value) {
|
|
99521
|
+
const edits = modify(text4, [...path29], value, {
|
|
99068
99522
|
formattingOptions: { insertSpaces: true, tabSize: 2, eol: "\n" }
|
|
99069
99523
|
});
|
|
99070
99524
|
const next = applyEdits(text4, edits);
|
|
@@ -99144,7 +99598,7 @@ function applyTarget(target, operation, desired, before, deps) {
|
|
|
99144
99598
|
if (!before.sourcePath || before.sourceText === void 0) {
|
|
99145
99599
|
throw new McpRegistrationError(`no writable ${target.label} configuration source was resolved`);
|
|
99146
99600
|
}
|
|
99147
|
-
let
|
|
99601
|
+
let path29;
|
|
99148
99602
|
let value;
|
|
99149
99603
|
if (target.id === "claude-desktop") {
|
|
99150
99604
|
const root = parseMcpConfigRoot(before.sourceText);
|
|
@@ -99152,14 +99606,14 @@ function applyTarget(target, operation, desired, before, deps) {
|
|
|
99152
99606
|
if (servers !== void 0 && !isRecord8(servers)) {
|
|
99153
99607
|
throw new McpRegistrationError("Claude Desktop mcpServers is not an object");
|
|
99154
99608
|
}
|
|
99155
|
-
|
|
99609
|
+
path29 = ["mcpServers", CURRENT_MCP_REGISTRATION];
|
|
99156
99610
|
value = operation === "install" ? { command: desired.command, args: desired.args } : void 0;
|
|
99157
99611
|
} else {
|
|
99158
|
-
|
|
99159
|
-
const v2 =
|
|
99612
|
+
path29 = before.openCodePath ?? ["mcp", CURRENT_MCP_REGISTRATION];
|
|
99613
|
+
const v2 = path29[1] === "servers";
|
|
99160
99614
|
value = operation === "install" ? v2 ? { type: "local", command: [desired.command, ...desired.args], disabled: false } : { type: "local", command: [desired.command, ...desired.args], enabled: true } : void 0;
|
|
99161
99615
|
}
|
|
99162
|
-
const next = editJsonc(before.sourceText,
|
|
99616
|
+
const next = editJsonc(before.sourceText, path29, value);
|
|
99163
99617
|
const write = deps.writeFile ?? ((candidate, content3) => atomicWriteFileSync(candidate, content3, {
|
|
99164
99618
|
expected: {
|
|
99165
99619
|
destination: before.sourceDestination ?? null,
|
|
@@ -100036,10 +100490,10 @@ function targetSets(bases, deps) {
|
|
|
100036
100490
|
const env = deps.env ?? process.env;
|
|
100037
100491
|
return [targetsForBase(cwd), globalHookTargets(home2, env)];
|
|
100038
100492
|
}
|
|
100039
|
-
function readSettings(
|
|
100040
|
-
if (!existsSync6(
|
|
100493
|
+
function readSettings(path29) {
|
|
100494
|
+
if (!existsSync6(path29)) return {};
|
|
100041
100495
|
try {
|
|
100042
|
-
return JSON.parse(readFileSync9(
|
|
100496
|
+
return JSON.parse(readFileSync9(path29, "utf8"));
|
|
100043
100497
|
} catch {
|
|
100044
100498
|
return {};
|
|
100045
100499
|
}
|
|
@@ -100047,11 +100501,11 @@ function readSettings(path28) {
|
|
|
100047
100501
|
function isPlainObject5(value) {
|
|
100048
100502
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
100049
100503
|
}
|
|
100050
|
-
function readSettingsForInstall(
|
|
100051
|
-
if (!existsSync6(
|
|
100504
|
+
function readSettingsForInstall(path29) {
|
|
100505
|
+
if (!existsSync6(path29)) return { ok: true, settings: {} };
|
|
100052
100506
|
let raw;
|
|
100053
100507
|
try {
|
|
100054
|
-
raw = readFileSync9(
|
|
100508
|
+
raw = readFileSync9(path29, "utf8");
|
|
100055
100509
|
} catch (err) {
|
|
100056
100510
|
return { ok: false, reason: `unreadable (${err instanceof Error ? err.message : String(err)})` };
|
|
100057
100511
|
}
|
|
@@ -100102,8 +100556,8 @@ function readSettingsForInstall(path28) {
|
|
|
100102
100556
|
}
|
|
100103
100557
|
return { ok: true, settings: parsed };
|
|
100104
100558
|
}
|
|
100105
|
-
function writeSettings(
|
|
100106
|
-
atomicWriteFileSync(
|
|
100559
|
+
function writeSettings(path29, settings) {
|
|
100560
|
+
atomicWriteFileSync(path29, `${JSON.stringify(settings, null, 2)}
|
|
100107
100561
|
`);
|
|
100108
100562
|
}
|
|
100109
100563
|
function buildOpenCodePluginTemplate(options2) {
|
|
@@ -100254,10 +100708,10 @@ function generatedConstant(source, name) {
|
|
|
100254
100708
|
return void 0;
|
|
100255
100709
|
}
|
|
100256
100710
|
}
|
|
100257
|
-
function readOpenCodeHookStatus(
|
|
100711
|
+
function readOpenCodeHookStatus(path29, expectedSource) {
|
|
100258
100712
|
let entry;
|
|
100259
100713
|
try {
|
|
100260
|
-
entry = lstatSync5(
|
|
100714
|
+
entry = lstatSync5(path29);
|
|
100261
100715
|
} catch {
|
|
100262
100716
|
return { installed: false, compatibility: { state: "absent", reason: "plugin file is absent" } };
|
|
100263
100717
|
}
|
|
@@ -100275,7 +100729,7 @@ function readOpenCodeHookStatus(path28, expectedSource) {
|
|
|
100275
100729
|
}
|
|
100276
100730
|
let source;
|
|
100277
100731
|
try {
|
|
100278
|
-
source = readFileSync9(
|
|
100732
|
+
source = readFileSync9(path29, "utf8");
|
|
100279
100733
|
} catch {
|
|
100280
100734
|
return { installed: false, compatibility: { state: "unmanaged", reason: "plugin file is unreadable" } };
|
|
100281
100735
|
}
|
|
@@ -100363,60 +100817,60 @@ function readOpenCodeTargetsStatus(targets, expectedSource) {
|
|
|
100363
100817
|
}
|
|
100364
100818
|
return canonical;
|
|
100365
100819
|
}
|
|
100366
|
-
function openCodeClaimPath(
|
|
100367
|
-
return `${
|
|
100820
|
+
function openCodeClaimPath(path29) {
|
|
100821
|
+
return `${path29}.claim-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
100368
100822
|
}
|
|
100369
|
-
function restoreOpenCodeClaim(claim,
|
|
100823
|
+
function restoreOpenCodeClaim(claim, path29) {
|
|
100370
100824
|
try {
|
|
100371
100825
|
const entry = lstatSync5(claim);
|
|
100372
|
-
if (entry.isSymbolicLink()) symlinkSync(readlinkSync3(claim),
|
|
100373
|
-
else if (entry.isFile()) linkSync3(claim,
|
|
100826
|
+
if (entry.isSymbolicLink()) symlinkSync(readlinkSync3(claim), path29);
|
|
100827
|
+
else if (entry.isFile()) linkSync3(claim, path29);
|
|
100374
100828
|
else throw new Error("claimed entry is not a regular file or symlink");
|
|
100375
100829
|
} catch (error51) {
|
|
100376
100830
|
throw new Error(`OpenCode plugin changed during migration; recovery copy retained at ${collapseHomeDirectory(claim)}`, { cause: error51 });
|
|
100377
100831
|
}
|
|
100378
100832
|
rmSync3(claim, { force: true });
|
|
100379
100833
|
}
|
|
100380
|
-
function claimOwnedOpenCodePlugin(
|
|
100381
|
-
const inspected = readOpenCodeHookStatus(
|
|
100834
|
+
function claimOwnedOpenCodePlugin(path29) {
|
|
100835
|
+
const inspected = readOpenCodeHookStatus(path29);
|
|
100382
100836
|
if (!inspected.installed) return void 0;
|
|
100383
|
-
const claim = openCodeClaimPath(
|
|
100837
|
+
const claim = openCodeClaimPath(path29);
|
|
100384
100838
|
try {
|
|
100385
|
-
renameSync5(
|
|
100839
|
+
renameSync5(path29, claim);
|
|
100386
100840
|
} catch (error51) {
|
|
100387
100841
|
throw new Error("OpenCode plugin changed after inspection; nothing was removed", { cause: error51 });
|
|
100388
100842
|
}
|
|
100389
100843
|
const claimed = readOpenCodeHookStatus(claim);
|
|
100390
100844
|
if (!claimed.installed) {
|
|
100391
|
-
restoreOpenCodeClaim(claim,
|
|
100845
|
+
restoreOpenCodeClaim(claim, path29);
|
|
100392
100846
|
throw new Error("OpenCode plugin changed after inspection; the changed bytes were preserved");
|
|
100393
100847
|
}
|
|
100394
100848
|
return claim;
|
|
100395
100849
|
}
|
|
100396
|
-
function removeOwnedOpenCodePlugin(
|
|
100397
|
-
const claim = claimOwnedOpenCodePlugin(
|
|
100850
|
+
function removeOwnedOpenCodePlugin(path29) {
|
|
100851
|
+
const claim = claimOwnedOpenCodePlugin(path29);
|
|
100398
100852
|
if (claim === void 0) return false;
|
|
100399
100853
|
rmSync3(claim, { force: true });
|
|
100400
100854
|
return true;
|
|
100401
100855
|
}
|
|
100402
|
-
function installOpenCodePlugin(
|
|
100403
|
-
const inspected = readOpenCodeHookStatus(
|
|
100856
|
+
function installOpenCodePlugin(path29, next) {
|
|
100857
|
+
const inspected = readOpenCodeHookStatus(path29, next);
|
|
100404
100858
|
if (inspected.compatibility.state === "unmanaged") {
|
|
100405
100859
|
throw new Error("refusing to overwrite unmanaged OpenCode plugin");
|
|
100406
100860
|
}
|
|
100407
100861
|
if (inspected.compatibility.state === "current") return false;
|
|
100408
|
-
const claim = inspected.installed ? claimOwnedOpenCodePlugin(
|
|
100862
|
+
const claim = inspected.installed ? claimOwnedOpenCodePlugin(path29) : void 0;
|
|
100409
100863
|
try {
|
|
100410
|
-
atomicWriteFileSync(
|
|
100864
|
+
atomicWriteFileSync(path29, next, {
|
|
100411
100865
|
followFinalSymlink: false,
|
|
100412
100866
|
expected: {
|
|
100413
100867
|
destination: null,
|
|
100414
100868
|
content: null,
|
|
100415
|
-
parent: capturePrivateConfigParent(
|
|
100869
|
+
parent: capturePrivateConfigParent(path29)
|
|
100416
100870
|
}
|
|
100417
100871
|
});
|
|
100418
100872
|
} catch (error51) {
|
|
100419
|
-
if (claim !== void 0) restoreOpenCodeClaim(claim,
|
|
100873
|
+
if (claim !== void 0) restoreOpenCodeClaim(claim, path29);
|
|
100420
100874
|
throw error51;
|
|
100421
100875
|
}
|
|
100422
100876
|
if (claim !== void 0) rmSync3(claim, { force: true });
|
|
@@ -100456,9 +100910,9 @@ function inspectHookStatus(scope, deps = {}) {
|
|
|
100456
100910
|
} catch {
|
|
100457
100911
|
expectedLaunch = void 0;
|
|
100458
100912
|
}
|
|
100459
|
-
const inspectSettingsTarget = (
|
|
100460
|
-
const status2 = readHookCompatibilityStatus(readSettings(
|
|
100461
|
-
const preflight = readSettingsForInstall(
|
|
100913
|
+
const inspectSettingsTarget = (path29) => {
|
|
100914
|
+
const status2 = readHookCompatibilityStatus(readSettings(path29));
|
|
100915
|
+
const preflight = readSettingsForInstall(path29);
|
|
100462
100916
|
if (!preflight.ok) {
|
|
100463
100917
|
return { ...status2, installSafe: false };
|
|
100464
100918
|
}
|
|
@@ -100673,19 +101127,19 @@ async function hook(argv2, deps = {}) {
|
|
|
100673
101127
|
}
|
|
100674
101128
|
let changed = false;
|
|
100675
101129
|
const notes = [];
|
|
100676
|
-
for (const
|
|
100677
|
-
const [updated, didChange] = computeHookUninstall(readSettings(
|
|
101130
|
+
for (const path29 of [targets.claudeSettings, targets.codexHooks]) {
|
|
101131
|
+
const [updated, didChange] = computeHookUninstall(readSettings(path29));
|
|
100678
101132
|
if (didChange) {
|
|
100679
|
-
writeSettings(
|
|
101133
|
+
writeSettings(path29, updated);
|
|
100680
101134
|
changed = true;
|
|
100681
101135
|
}
|
|
100682
101136
|
}
|
|
100683
|
-
for (const
|
|
100684
|
-
const openCodeStatus = readOpenCodeHookStatus(
|
|
101137
|
+
for (const path29 of [targets.opencodePlugin, targets.legacyOpencodePlugin]) {
|
|
101138
|
+
const openCodeStatus = readOpenCodeHookStatus(path29);
|
|
100685
101139
|
if (openCodeStatus.installed) {
|
|
100686
|
-
changed = removeOwnedOpenCodePlugin(
|
|
101140
|
+
changed = removeOwnedOpenCodePlugin(path29) || changed;
|
|
100687
101141
|
} else if (openCodeStatus.compatibility.state === "unmanaged") {
|
|
100688
|
-
notes.push(`preserved unmanaged OpenCode plugin: ${collapseHomeDirectory(
|
|
101142
|
+
notes.push(`preserved unmanaged OpenCode plugin: ${collapseHomeDirectory(path29)}`);
|
|
100689
101143
|
}
|
|
100690
101144
|
}
|
|
100691
101145
|
stdout(
|
|
@@ -100784,7 +101238,7 @@ var init_sync_cli = __esm({
|
|
|
100784
101238
|
});
|
|
100785
101239
|
|
|
100786
101240
|
// src/sync-outcomes.ts
|
|
100787
|
-
import
|
|
101241
|
+
import path23 from "node:path";
|
|
100788
101242
|
function upstreamHelp(inv) {
|
|
100789
101243
|
return `if a teammate already shares this project's board, make sure your \`origin\` remote points at the SAME repository they pushed the \`board\` branch to; if nobody has started sharing this project's board yet, run \`${inv} sync --establish\` to start \u2014 until then a local-only board is a supported mode: every local command keeps working, and nothing leaves this machine`;
|
|
100790
101244
|
}
|
|
@@ -100962,7 +101416,7 @@ var init_sync_outcomes = __esm({
|
|
|
100962
101416
|
// The in-tree board's write refusal + the viewer's no-comparison-basis refusal.
|
|
100963
101417
|
"in-tree.sync-refusal": row({
|
|
100964
101418
|
code: "USAGE",
|
|
100965
|
-
message: (p2) => syncInTreeRefusalMessage(p2.inv, p2.hasOrigin,
|
|
101419
|
+
message: (p2) => syncInTreeRefusalMessage(p2.inv, p2.hasOrigin, path23.basename(p2.boardPath)),
|
|
100966
101420
|
details: (p2) => ({ path: p2.boardPath, state: "in-tree" }),
|
|
100967
101421
|
help: (p2) => p2.hasOrigin ? `${p2.inv} sync --establish` : `git remote add ${BOARD_REMOTE} <url>`
|
|
100968
101422
|
}),
|
|
@@ -101422,7 +101876,7 @@ var init_establish_committed = __esm({
|
|
|
101422
101876
|
|
|
101423
101877
|
// src/commands/sync/establish.ts
|
|
101424
101878
|
import { existsSync as existsSync7, lstatSync as lstatSync6, readdirSync as readdirSync2, renameSync as renameSync6, rmSync as rmSync4 } from "node:fs";
|
|
101425
|
-
import
|
|
101879
|
+
import path24 from "node:path";
|
|
101426
101880
|
function establishNextSteps(inv) {
|
|
101427
101881
|
return [
|
|
101428
101882
|
`teammates just run '${inv} sync' \u2014 it provisions automatically`,
|
|
@@ -101430,7 +101884,7 @@ function establishNextSteps(inv) {
|
|
|
101430
101884
|
];
|
|
101431
101885
|
}
|
|
101432
101886
|
function assertPlainBundleShape(bundlePath, inv) {
|
|
101433
|
-
const bundleDir =
|
|
101887
|
+
const bundleDir = path24.basename(bundlePath);
|
|
101434
101888
|
const runInitHelp = `${inv} init --create-only --dir ${BUNDLE_DIR}`;
|
|
101435
101889
|
if (!existsSync7(bundlePath)) {
|
|
101436
101890
|
throw new CliError(
|
|
@@ -101446,7 +101900,7 @@ function assertPlainBundleShape(bundlePath, inv) {
|
|
|
101446
101900
|
`'${bundlePath}' must be a real, plain directory \u2014 symlinks and non-directories are never followed by establish`
|
|
101447
101901
|
);
|
|
101448
101902
|
}
|
|
101449
|
-
if (existsSync7(
|
|
101903
|
+
if (existsSync7(path24.join(bundlePath, ".git"))) {
|
|
101450
101904
|
throw new CliError(
|
|
101451
101905
|
"RUNTIME",
|
|
101452
101906
|
`'${bundlePath}' already contains its own '.git' \u2014 establish only operates on a plain bundle folder`
|
|
@@ -101457,7 +101911,7 @@ function assertPlainBundleShape(bundlePath, inv) {
|
|
|
101457
101911
|
help: runInitHelp
|
|
101458
101912
|
});
|
|
101459
101913
|
}
|
|
101460
|
-
const indexPath =
|
|
101914
|
+
const indexPath = path24.join(bundlePath, "index.md");
|
|
101461
101915
|
if (!existsSync7(indexPath)) {
|
|
101462
101916
|
throw new CliError(
|
|
101463
101917
|
"RUNTIME",
|
|
@@ -101471,7 +101925,7 @@ function assertPlainBundleShape(bundlePath, inv) {
|
|
|
101471
101925
|
}
|
|
101472
101926
|
}
|
|
101473
101927
|
function assertFreshSource(top, boardPath, inv) {
|
|
101474
|
-
const bundleDir =
|
|
101928
|
+
const bundleDir = path24.basename(boardPath);
|
|
101475
101929
|
assertPlainBundleShape(boardPath, inv);
|
|
101476
101930
|
if (folderPresentInCodeIndex(top)) {
|
|
101477
101931
|
throw new CliError(
|
|
@@ -101484,11 +101938,11 @@ function assertFreshSource(top, boardPath, inv) {
|
|
|
101484
101938
|
async function assertNotBoundElsewhere(top, boardPath) {
|
|
101485
101939
|
const binding = await resolveProjectBinding(top);
|
|
101486
101940
|
if (!binding) return;
|
|
101487
|
-
const boundIsConventional =
|
|
101941
|
+
const boundIsConventional = path24.resolve(binding.target) === boardPath;
|
|
101488
101942
|
if (boundIsConventional) return;
|
|
101489
101943
|
throw new CliError(
|
|
101490
101944
|
"RUNTIME",
|
|
101491
|
-
`a project binding (${binding.file}) points this project's bundle out of the git-sync tier (the selected conventional path is '${
|
|
101945
|
+
`a project binding (${binding.file}) points this project's bundle out of the git-sync tier (the selected conventional path is '${path24.basename(boardPath)}/')`,
|
|
101492
101946
|
{ help: `fix or remove ${binding.file} if you want to share this bundle over the board branch` }
|
|
101493
101947
|
);
|
|
101494
101948
|
}
|
|
@@ -101509,7 +101963,7 @@ function removeVerifiedBackup(top, backupPath, expectedCommit, inv) {
|
|
|
101509
101963
|
rmSync4(backupPath, { recursive: true, force: false });
|
|
101510
101964
|
}
|
|
101511
101965
|
function finishLocalConversion(top, sourcePath, publishedCommit, expectedTree, inv) {
|
|
101512
|
-
const boardPath =
|
|
101966
|
+
const boardPath = path24.join(top, bundleDirNameForProject(top));
|
|
101513
101967
|
const backupPath = `${boardPath}.establish-backup`;
|
|
101514
101968
|
const remoteCommit = refCommit(top, `refs/remotes/${BOARD_REF}`);
|
|
101515
101969
|
if (!remoteCommit || !isAncestor(top, publishedCommit, remoteCommit)) {
|
|
@@ -101597,7 +102051,7 @@ async function renderEstablished(top, conversion, snapshot2, inv, mode, stdout,
|
|
|
101597
102051
|
return { already: false };
|
|
101598
102052
|
}
|
|
101599
102053
|
function readGreenfieldState(top) {
|
|
101600
|
-
const boardPath =
|
|
102054
|
+
const boardPath = path24.join(top, bundleDirNameForProject(top));
|
|
101601
102055
|
return {
|
|
101602
102056
|
boardPath,
|
|
101603
102057
|
backupPath: `${boardPath}.establish-backup`,
|
|
@@ -101642,7 +102096,7 @@ async function publishLocalBoardBranch(top, boardPath, inv, mode, stdout, deps)
|
|
|
101642
102096
|
throw new CliError("RUNTIME", "the local board branch could not be provisioned for explicit establishment");
|
|
101643
102097
|
}
|
|
101644
102098
|
}
|
|
101645
|
-
const indexPath =
|
|
102099
|
+
const indexPath = path24.join(boardPath, "index.md");
|
|
101646
102100
|
if (!existsSync7(indexPath) || lstatSync6(indexPath).isSymbolicLink() || !lstatSync6(indexPath).isFile()) {
|
|
101647
102101
|
throw new CliError("RUNTIME", `the local '${BOARD_BRANCH}' worktree is not a valid bundle (root index.md missing)`);
|
|
101648
102102
|
}
|
|
@@ -101715,7 +102169,7 @@ async function establishBoard(dir, inv, mode, stdout, deps, opts = {}) {
|
|
|
101715
102169
|
}
|
|
101716
102170
|
const committed = committedBundleAtHead(top);
|
|
101717
102171
|
if (committed !== null) {
|
|
101718
|
-
assertBundleOutsidePrivateState(
|
|
102172
|
+
assertBundleOutsidePrivateState(path24.join(top, committed.bundleDir));
|
|
101719
102173
|
return establishCommitted(top, inv, mode, Boolean(opts.yes), committed, stdout);
|
|
101720
102174
|
}
|
|
101721
102175
|
fetchOriginRequired(top);
|
|
@@ -101956,7 +102410,7 @@ var init_converge = __esm({
|
|
|
101956
102410
|
|
|
101957
102411
|
// src/commands/sync/show-incoming.ts
|
|
101958
102412
|
import { promises as fs8 } from "node:fs";
|
|
101959
|
-
import
|
|
102413
|
+
import path25 from "node:path";
|
|
101960
102414
|
function showIncomingInTreeNoBasis(inv, reason, ref) {
|
|
101961
102415
|
return syncOutcomeError("in-tree.show-incoming.no-basis", { inv, reason, ref });
|
|
101962
102416
|
}
|
|
@@ -101979,7 +102433,7 @@ async function showIncoming(id, values, deps, route) {
|
|
|
101979
102433
|
const out = values.out?.trim();
|
|
101980
102434
|
const streamMode = out === "-";
|
|
101981
102435
|
const run = async () => {
|
|
101982
|
-
if (out && !streamMode) assertPathOutsidePrivateState(
|
|
102436
|
+
if (out && !streamMode) assertPathOutsidePrivateState(path25.resolve(out));
|
|
101983
102437
|
if (route?.kind === "bound-local") throw syncOutcomeError("show-incoming.no-upstream", { inv });
|
|
101984
102438
|
if (route?.kind === "bound-board" && route.readiness !== "ready") {
|
|
101985
102439
|
throw new CliError(
|
|
@@ -101987,7 +102441,7 @@ async function showIncoming(id, values, deps, route) {
|
|
|
101987
102441
|
"the selected private board has a board-origin rebase pending; --show-incoming cannot recover it"
|
|
101988
102442
|
);
|
|
101989
102443
|
}
|
|
101990
|
-
if (!route) assertSearchDirOutsidePrivateState(
|
|
102444
|
+
if (!route) assertSearchDirOutsidePrivateState(path25.resolve(values.dir ?? process.cwd()));
|
|
101991
102445
|
const dir = route?.kind === "bound-board" ? route.owner.bundleRoot : retargetBoardInterior(values.dir ?? process.cwd());
|
|
101992
102446
|
const top = repoTopLevel(dir);
|
|
101993
102447
|
if (!top) {
|
|
@@ -101997,7 +102451,7 @@ async function showIncoming(id, values, deps, route) {
|
|
|
101997
102451
|
{ details: { state: "no-repo" } }
|
|
101998
102452
|
);
|
|
101999
102453
|
}
|
|
102000
|
-
if (
|
|
102454
|
+
if (path25.isAbsolute(id) || id.split("/").some((seg) => seg === "..")) {
|
|
102001
102455
|
throw new CliError("USAGE", `--show-incoming needs a repo-relative doc id or path without '..' segments: ${id}`);
|
|
102002
102456
|
}
|
|
102003
102457
|
let readRef = `refs/remotes/${BOARD_REF}`;
|
|
@@ -102185,7 +102639,7 @@ var init_bound_board_recovery = __esm({
|
|
|
102185
102639
|
});
|
|
102186
102640
|
|
|
102187
102641
|
// src/commands/sync/orchestrate.ts
|
|
102188
|
-
import
|
|
102642
|
+
import path26 from "node:path";
|
|
102189
102643
|
import { parseArgs as parseArgs23 } from "node:util";
|
|
102190
102644
|
function syncLocalOnlyNote(inv) {
|
|
102191
102645
|
return `a supported mode: every local command works, and your board changes stay on this machine (sync committed nothing). To share the board with teammates, run \`${inv} sync --establish\` \u2014 it publishes the board as a 'board' branch on the repo's 'origin' remote (add one first if the repo has none); teammates then just run sync.`;
|
|
@@ -102204,7 +102658,7 @@ async function syncInTree(run) {
|
|
|
102204
102658
|
const top = repoTopLevel(run.dir);
|
|
102205
102659
|
if (!top) throw new CliError("RUNTIME", "not inside a git repository");
|
|
102206
102660
|
const bundleDir = committedBundleAtHead(top)?.bundleDir ?? bundleDirNameForProject(top);
|
|
102207
|
-
const boardPath =
|
|
102661
|
+
const boardPath = path26.join(top, bundleDir);
|
|
102208
102662
|
assertBundleOutsidePrivateState(boardPath);
|
|
102209
102663
|
if (!run.pullOnly) {
|
|
102210
102664
|
const hasOrigin = runGit(top, ["remote", "get-url", BOARD_REMOTE]).status === 0;
|
|
@@ -102311,7 +102765,7 @@ async function parseSyncInvocation(argv2, inv) {
|
|
|
102311
102765
|
}
|
|
102312
102766
|
limit = Number(raw);
|
|
102313
102767
|
}
|
|
102314
|
-
assertSearchDirOutsidePrivateState(
|
|
102768
|
+
assertSearchDirOutsidePrivateState(path26.resolve(values.dir ?? process.cwd()));
|
|
102315
102769
|
let route;
|
|
102316
102770
|
if (values.dir === void 0 && await resolveProjectBinding(process.cwd())) {
|
|
102317
102771
|
route = await resolveLocalBundleRoute(void 0);
|
|
@@ -102488,7 +102942,7 @@ async function syncCommand(argv2, deps = {}) {
|
|
|
102488
102942
|
const initialTop = repoTopLevel(run.dir);
|
|
102489
102943
|
if (initialTop) {
|
|
102490
102944
|
const initialBundleDir = committedBundleAtHead(initialTop)?.bundleDir ?? bundleDirNameForProject(initialTop);
|
|
102491
|
-
assertBundleOutsidePrivateState(
|
|
102945
|
+
assertBundleOutsidePrivateState(path26.join(initialTop, initialBundleDir));
|
|
102492
102946
|
}
|
|
102493
102947
|
let establishAlreadyNote;
|
|
102494
102948
|
if (dispatch.establish) {
|
|
@@ -102936,7 +103390,7 @@ var init_skill_compatibility = __esm({
|
|
|
102936
103390
|
});
|
|
102937
103391
|
|
|
102938
103392
|
// src/commands/skill.ts
|
|
102939
|
-
import { createHash as
|
|
103393
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
102940
103394
|
import { existsSync as existsSync8, lstatSync as lstatSync7, readFileSync as readFileSync11, readdirSync as readdirSync3, renameSync as renameSync7, rmSync as rmSync5, rmdirSync as rmdirSync3 } from "node:fs";
|
|
102941
103395
|
import { homedir as homedir16 } from "node:os";
|
|
102942
103396
|
import { dirname as dirname5, join as join15 } from "node:path";
|
|
@@ -102976,7 +103430,7 @@ function resolveSkillAssets(executable) {
|
|
|
102976
103430
|
const fileSha256 = Object.fromEntries(
|
|
102977
103431
|
files.map((relativePath) => [
|
|
102978
103432
|
relativePath,
|
|
102979
|
-
`sha256:${
|
|
103433
|
+
`sha256:${createHash7("sha256").update(readFileSync11(join15(root, relativePath))).digest("hex")}`
|
|
102980
103434
|
])
|
|
102981
103435
|
);
|
|
102982
103436
|
return {
|
|
@@ -103299,7 +103753,7 @@ function skillStatusForDir(dir, assets, installCommand = `${cliInvocation()} ski
|
|
|
103299
103753
|
const installed = readFileSync11(installedPath);
|
|
103300
103754
|
const shipped = readFileSync11(join15(assets.root, relativePath));
|
|
103301
103755
|
if (!installed.equals(shipped)) assetsMatch = false;
|
|
103302
|
-
if (manifest.kind === "v2" && manifest.file_sha256?.[relativePath] !== `sha256:${
|
|
103756
|
+
if (manifest.kind === "v2" && manifest.file_sha256?.[relativePath] !== `sha256:${createHash7("sha256").update(installed).digest("hex")}`) {
|
|
103303
103757
|
receiptDigestsMatch = false;
|
|
103304
103758
|
}
|
|
103305
103759
|
}
|
|
@@ -103679,7 +104133,7 @@ The former spelling --scope global remains accepted as an alias for --scope user
|
|
|
103679
104133
|
|
|
103680
104134
|
// src/commands/home.ts
|
|
103681
104135
|
import { parseArgs as parseArgs25 } from "node:util";
|
|
103682
|
-
import
|
|
104136
|
+
import path27 from "node:path";
|
|
103683
104137
|
function parseHomeArgs(argv2) {
|
|
103684
104138
|
return parseArgs25({ args: argv2, options: HOME_OPTIONS, allowPositionals: true });
|
|
103685
104139
|
}
|
|
@@ -103730,7 +104184,7 @@ async function defaultSummarizeBundle(dir, route) {
|
|
|
103730
104184
|
if (route) await assertResolvedLocalRouteIdentity(route);
|
|
103731
104185
|
} catch (err) {
|
|
103732
104186
|
if (err instanceof CliError && err.code === "NOT_FOUND") return null;
|
|
103733
|
-
const root = collapseHomeDirectory(
|
|
104187
|
+
const root = collapseHomeDirectory(path27.resolve(dir ?? process.cwd()));
|
|
103734
104188
|
if (err instanceof CliError && err.code === "CONFLICT") {
|
|
103735
104189
|
return { root, conflict: true, message: err.message };
|
|
103736
104190
|
}
|
|
@@ -103746,11 +104200,11 @@ async function defaultSummarizeBundle(dir, route) {
|
|
|
103746
104200
|
}
|
|
103747
104201
|
async function discoverSummarizeBundle(startDir) {
|
|
103748
104202
|
try {
|
|
103749
|
-
const root = await findBundleRoot(
|
|
104203
|
+
const root = await findBundleRoot(path27.resolve(startDir));
|
|
103750
104204
|
return root ? defaultSummarizeBundle(root) : null;
|
|
103751
104205
|
} catch (err) {
|
|
103752
104206
|
if (err instanceof CliError && err.code === "NOT_FOUND") return null;
|
|
103753
|
-
const root = collapseHomeDirectory(
|
|
104207
|
+
const root = collapseHomeDirectory(path27.resolve(startDir));
|
|
103754
104208
|
if (err instanceof CliError && err.code === "CONFLICT") {
|
|
103755
104209
|
return { root, conflict: true, message: err.message };
|
|
103756
104210
|
}
|
|
@@ -103846,7 +104300,7 @@ async function defaultLoadBoardStatus(dir, route) {
|
|
|
103846
104300
|
if (!top) return null;
|
|
103847
104301
|
const committed = committedBundleAtHead(top);
|
|
103848
104302
|
const bundleDir = committed?.bundleDir ?? bundleDirNameForProject(top);
|
|
103849
|
-
const boardPath =
|
|
104303
|
+
const boardPath = path27.join(top, bundleDir);
|
|
103850
104304
|
if (!isProvisioned(top)) {
|
|
103851
104305
|
const remoteRefExists = runGit(top, ["rev-parse", "--verify", "--quiet", `refs/remotes/${BOARD_REF}`]).status === 0;
|
|
103852
104306
|
const probed = remoteRefExists || runGit(top, ["rev-parse", "--verify", "--quiet", `refs/heads/${BOARD_BRANCH}`]).status === 0;
|
|
@@ -103980,7 +104434,7 @@ function buildHomeView(deps, summary, remote, binding, bindingError, board, hook
|
|
|
103980
104434
|
const target = ` --dir ${shellArg(binding.target)}`;
|
|
103981
104435
|
view2.getting_started = `project binding ${binding.file} -> ${binding.target} did not resolve to a bundle \u2014 run \`${deps.invocation()} init --recipe none${target}\` to recreate that bound bundle, or fix/remove the binding before browsing recipes`;
|
|
103982
104436
|
} else {
|
|
103983
|
-
const createTarget =
|
|
104437
|
+
const createTarget = path27.join(deps.targetDir ?? ".", CONVENTIONAL_BUNDLE_DIR_NAME);
|
|
103984
104438
|
const target = ` --dir ${shellArg(createTarget)}`;
|
|
103985
104439
|
view2.getting_started = `no OKF bundle found in this directory \u2014 run \`${deps.invocation()} init --create-only --recipe none${target}\` to create a blank bundle, or \`${deps.invocation()} recipes\` to compare available workspace setups; create your chosen setup here with \`${deps.invocation()} init --create-only --recipe <name>${target}\``;
|
|
103986
104440
|
}
|
|
@@ -104248,12 +104702,12 @@ ASLITE_NO_UPDATE_CHECK, NO_UPDATE_NOTIFIER, or CI.
|
|
|
104248
104702
|
|
|
104249
104703
|
// src/commands/session-start.ts
|
|
104250
104704
|
import { parseArgs as parseArgs26 } from "node:util";
|
|
104251
|
-
import
|
|
104705
|
+
import path28 from "node:path";
|
|
104252
104706
|
async function sessionStartPull(dir, budgetMs = SESSION_START_PULL_BUDGET_MS, now = Date.now) {
|
|
104253
104707
|
const deadline = now() + budgetMs;
|
|
104254
104708
|
const remaining = () => Math.max(0, deadline - now());
|
|
104255
104709
|
try {
|
|
104256
|
-
assertSearchDirOutsidePrivateState(
|
|
104710
|
+
assertSearchDirOutsidePrivateState(path28.resolve(dir ?? process.cwd()));
|
|
104257
104711
|
const route = dir === void 0 && await resolveProjectBinding(process.cwd()) ? await resolveLocalBundleRoute(void 0) : void 0;
|
|
104258
104712
|
if (route?.kind === "bound-board" && route.readiness !== "ready") return void 0;
|
|
104259
104713
|
const owner = route?.kind === "bound-board" ? route.owner : void 0;
|
|
@@ -104286,7 +104740,7 @@ async function sessionStartPull(dir, budgetMs = SESSION_START_PULL_BUDGET_MS, no
|
|
|
104286
104740
|
const top = repoTopLevel(startDir);
|
|
104287
104741
|
if (!top) return void 0;
|
|
104288
104742
|
const bundleDir = committedBundleAtHead(top)?.bundleDir ?? bundleDirNameForProject(top);
|
|
104289
|
-
const boardPath2 =
|
|
104743
|
+
const boardPath2 = path28.join(top, bundleDir);
|
|
104290
104744
|
const key2 = resolveBundleKey(boardPath2);
|
|
104291
104745
|
await defaultSyncStore.refreshMarker(key2);
|
|
104292
104746
|
if (remaining() < MIN_USEFUL_BUDGET_MS) return { offline: true, boardPath: boardPath2 };
|
|
@@ -104723,7 +105177,7 @@ function cappedPaths(dirs) {
|
|
|
104723
105177
|
return {
|
|
104724
105178
|
shown: Math.min(paths.length, PATH_LIMIT),
|
|
104725
105179
|
total: paths.length,
|
|
104726
|
-
rows: paths.slice(0, PATH_LIMIT).map((
|
|
105180
|
+
rows: paths.slice(0, PATH_LIMIT).map((path29) => ({ path: path29 }))
|
|
104727
105181
|
};
|
|
104728
105182
|
}
|
|
104729
105183
|
function dirsWith(targets, disposition) {
|
|
@@ -105690,7 +106144,7 @@ var init_setup_plan = __esm({
|
|
|
105690
106144
|
});
|
|
105691
106145
|
|
|
105692
106146
|
// src/user-state-migration.ts
|
|
105693
|
-
import { createHash as
|
|
106147
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
105694
106148
|
import {
|
|
105695
106149
|
chmod as chmod2,
|
|
105696
106150
|
lstat as lstat2,
|
|
@@ -105707,7 +106161,7 @@ function errno3(error51) {
|
|
|
105707
106161
|
return error51?.code;
|
|
105708
106162
|
}
|
|
105709
106163
|
function digest(bytes) {
|
|
105710
|
-
return
|
|
106164
|
+
return createHash8("sha256").update(bytes).digest("hex");
|
|
105711
106165
|
}
|
|
105712
106166
|
function isRecord10(value) {
|
|
105713
106167
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -105853,7 +106307,7 @@ async function ensureMigrationParent(home2) {
|
|
|
105853
106307
|
if (!(await stat3(parent)).isDirectory()) throw new Error("canonical state parent is unsafe");
|
|
105854
106308
|
}
|
|
105855
106309
|
function migrationTemporaryPath(root, relative2) {
|
|
105856
|
-
const digest2 =
|
|
106310
|
+
const digest2 = createHash8("sha256").update(relative2).digest("hex").slice(0, 24);
|
|
105857
106311
|
return join16(root, dirname6(relative2), `.migration-${digest2}.tmp`);
|
|
105858
106312
|
}
|
|
105859
106313
|
async function sweepOwnedStagingTemporaries(root, records) {
|
|
@@ -105905,10 +106359,10 @@ function journalBytes(records) {
|
|
|
105905
106359
|
`;
|
|
105906
106360
|
}
|
|
105907
106361
|
async function removeStaleJournal(root) {
|
|
105908
|
-
const
|
|
105909
|
-
const raw = await readPrivateStateFile(
|
|
106362
|
+
const path29 = join16(root, MIGRATION_JOURNAL_FILE_NAME);
|
|
106363
|
+
const raw = await readPrivateStateFile(path29, MAX_CATALOG_BYTES).catch(() => null);
|
|
105910
106364
|
if (raw === null || parseJournal(raw) === null) return;
|
|
105911
|
-
await unlink4(
|
|
106365
|
+
await unlink4(path29).catch(() => {
|
|
105912
106366
|
});
|
|
105913
106367
|
}
|
|
105914
106368
|
function parseJournal(raw) {
|