@devrouter/cli 0.1.0 → 0.1.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/devrouter-lifecycle-worker.js +218 -66
- package/dist/devrouter.js +417 -142
- package/package.json +3 -1
- package/upgrade-prompts/0.1.1.md +48 -0
- package/upgrade-prompts/0.1.2.md +57 -0
package/dist/devrouter.js
CHANGED
|
@@ -4275,7 +4275,7 @@ function loadRepoConfig(repoPath, read2 = (file) => import_node_fs7.default.read
|
|
|
4275
4275
|
const config = parseConfig(parsed ?? {}, configPath);
|
|
4276
4276
|
const requiredVersion = config.devrouter?.version;
|
|
4277
4277
|
if (requiredVersion && !hasWarnedVersionMismatch) {
|
|
4278
|
-
const cliVersion = true ? "0.1.
|
|
4278
|
+
const cliVersion = true ? "0.1.2" : "0.0.0-dev";
|
|
4279
4279
|
if (cliVersion !== "0.0.0-dev" && compareSemver(requiredVersion, cliVersion) > 0) {
|
|
4280
4280
|
hasWarnedVersionMismatch = true;
|
|
4281
4281
|
process.stderr.write(
|
|
@@ -5263,10 +5263,11 @@ function serializeSnapshot(snapshot) {
|
|
|
5263
5263
|
throw new Error("Capacity reservation snapshot exceeds byte limit.");
|
|
5264
5264
|
return contents;
|
|
5265
5265
|
}
|
|
5266
|
-
var import_node_fs9, import_node_path11, MAX_BYTES2, CapacityHistoryError, CapacitySnapshotChangedError, CapacityStore;
|
|
5266
|
+
var import_node_crypto6, import_node_fs9, import_node_path11, MAX_BYTES2, CapacityHistoryError, CapacitySnapshotChangedError, CapacityStore;
|
|
5267
5267
|
var init_capacity_store = __esm({
|
|
5268
5268
|
"src/core/capacity-store.ts"() {
|
|
5269
5269
|
"use strict";
|
|
5270
|
+
import_node_crypto6 = require("crypto");
|
|
5270
5271
|
import_node_fs9 = __toESM(require("fs"));
|
|
5271
5272
|
import_node_path11 = __toESM(require("path"));
|
|
5272
5273
|
init_atomic_file();
|
|
@@ -5274,11 +5275,13 @@ var init_capacity_store = __esm({
|
|
|
5274
5275
|
init_file_lock();
|
|
5275
5276
|
MAX_BYTES2 = 1048576;
|
|
5276
5277
|
CapacityHistoryError = class extends Error {
|
|
5277
|
-
constructor(code) {
|
|
5278
|
+
constructor(code, cause = null, location = null) {
|
|
5278
5279
|
super(
|
|
5279
5280
|
code === "capacity-ledger-lost" ? "Capacity ledger history is lost; restore verified capacity-reservations.json." : "Capacity history cannot be proven; inspect the private lifecycle journals."
|
|
5280
5281
|
);
|
|
5281
5282
|
this.code = code;
|
|
5283
|
+
this.cause = cause;
|
|
5284
|
+
this.location = location;
|
|
5282
5285
|
this.name = "CapacityHistoryError";
|
|
5283
5286
|
}
|
|
5284
5287
|
};
|
|
@@ -5351,9 +5354,10 @@ var init_capacity_store = __esm({
|
|
|
5351
5354
|
const buffer = Buffer.alloc(MAX_BYTES2 + 1);
|
|
5352
5355
|
const count = import_node_fs9.default.readSync(descriptor, buffer, 0, buffer.length, 0);
|
|
5353
5356
|
if (count > MAX_BYTES2) throw new Error("Capacity reservation snapshot exceeds byte limit.");
|
|
5354
|
-
const
|
|
5357
|
+
const bytes2 = buffer.subarray(0, count);
|
|
5358
|
+
const value = JSON.parse(bytes2.toString("utf8"));
|
|
5355
5359
|
validate(value);
|
|
5356
|
-
this.ledgerGeneration =
|
|
5360
|
+
this.ledgerGeneration = this.generationIdentity(stat, bytes2);
|
|
5357
5361
|
if (value.revision < minimumRevision) return { kind: "stale", revision: value.revision };
|
|
5358
5362
|
this.observedLedger = true;
|
|
5359
5363
|
return { kind: "intact", revision: value.revision, snapshot: value };
|
|
@@ -5406,20 +5410,30 @@ var init_capacity_store = __esm({
|
|
|
5406
5410
|
return snapshot;
|
|
5407
5411
|
}
|
|
5408
5412
|
commit(snapshot) {
|
|
5409
|
-
|
|
5413
|
+
const contents = serializeSnapshot(snapshot);
|
|
5414
|
+
this.write(this.file, contents);
|
|
5410
5415
|
this.observedLedger = true;
|
|
5411
|
-
this.rememberGeneration();
|
|
5416
|
+
this.rememberGeneration(contents);
|
|
5412
5417
|
this.establish();
|
|
5413
5418
|
}
|
|
5414
5419
|
/** Remember the published snapshot identity for the next generation fence. */
|
|
5415
|
-
rememberGeneration() {
|
|
5420
|
+
rememberGeneration(contents) {
|
|
5416
5421
|
try {
|
|
5417
5422
|
const stat = import_node_fs9.default.statSync(this.file);
|
|
5418
|
-
this.ledgerGeneration = stat.isFile() ?
|
|
5423
|
+
this.ledgerGeneration = stat.isFile() ? this.generationIdentity(stat, contents) : void 0;
|
|
5419
5424
|
} catch {
|
|
5420
5425
|
this.ledgerGeneration = void 0;
|
|
5421
5426
|
}
|
|
5422
5427
|
}
|
|
5428
|
+
/**
|
|
5429
|
+
* File identity plus content digest. Deleting and recreating the snapshot can
|
|
5430
|
+
* reuse its inode number, so the inode alone cannot fence a replacement that
|
|
5431
|
+
* reuses a revision number.
|
|
5432
|
+
*/
|
|
5433
|
+
generationIdentity(stat, contents) {
|
|
5434
|
+
const digest3 = (0, import_node_crypto6.createHash)("sha256").update(contents).digest("hex");
|
|
5435
|
+
return `${stat.dev}:${stat.ino}:${digest3}`;
|
|
5436
|
+
}
|
|
5423
5437
|
/**
|
|
5424
5438
|
* Durable evidence that recorded history is gone, for a stop whose physical
|
|
5425
5439
|
* cessation is already proven. The caller holds that proof; this writes no
|
|
@@ -5898,11 +5912,11 @@ function retain(session, previous) {
|
|
|
5898
5912
|
environment: { ...environment }
|
|
5899
5913
|
};
|
|
5900
5914
|
}
|
|
5901
|
-
var
|
|
5915
|
+
var import_node_crypto7, import_node_fs10, import_node_path12, CONTROLLER_SNAPSHOT_BYTES, EVENT_KINDS, LEGACY_EVENT_KINDS, PROJECTION_STATUSES, ControllerStore;
|
|
5902
5916
|
var init_controller_store = __esm({
|
|
5903
5917
|
"src/core/controller-store.ts"() {
|
|
5904
5918
|
"use strict";
|
|
5905
|
-
|
|
5919
|
+
import_node_crypto7 = require("crypto");
|
|
5906
5920
|
import_node_fs10 = __toESM(require("fs"));
|
|
5907
5921
|
import_node_path12 = __toESM(require("path"));
|
|
5908
5922
|
init_atomic_file();
|
|
@@ -5993,7 +6007,7 @@ var init_controller_store = __esm({
|
|
|
5993
6007
|
provenance(identity2) {
|
|
5994
6008
|
if (identity2.version !== 2) throw new Error("Controller binding provenance is unavailable.");
|
|
5995
6009
|
return {
|
|
5996
|
-
digest: (0,
|
|
6010
|
+
digest: (0, import_node_crypto7.createHash)("sha256").update(JSON.stringify(["devrouter-controller-binding-v1", identity2.store, identity2.key])).digest("hex"),
|
|
5997
6011
|
enrolledEpoch: identity2.enrolledEpoch
|
|
5998
6012
|
};
|
|
5999
6013
|
}
|
|
@@ -6017,7 +6031,7 @@ var init_controller_store = __esm({
|
|
|
6017
6031
|
if (!current || current.store !== captured.store || current.epoch !== captured.epoch || JSON.stringify(current.fingerprint) !== JSON.stringify(captured.fingerprint) || identity2?.version !== 2)
|
|
6018
6032
|
throw new Error("Controller binding incarnation changed.");
|
|
6019
6033
|
this.checkProvenance(current, identity2);
|
|
6020
|
-
return (0,
|
|
6034
|
+
return (0, import_node_crypto7.createHmac)("sha256", Buffer.from(identity2.key, "hex")).update(JSON.stringify({ owner, config })).digest("hex");
|
|
6021
6035
|
};
|
|
6022
6036
|
}
|
|
6023
6037
|
read() {
|
|
@@ -6070,7 +6084,7 @@ var init_controller_store = __esm({
|
|
|
6070
6084
|
const identity2 = existing?.version === 2 ? existing : {
|
|
6071
6085
|
version: 2,
|
|
6072
6086
|
store,
|
|
6073
|
-
key: (0,
|
|
6087
|
+
key: (0, import_node_crypto7.randomBytes)(32).toString("hex"),
|
|
6074
6088
|
enrolledEpoch: epoch
|
|
6075
6089
|
};
|
|
6076
6090
|
if (existing?.version !== 2)
|
|
@@ -6116,7 +6130,7 @@ var init_controller_store = __esm({
|
|
|
6116
6130
|
if (!previous) {
|
|
6117
6131
|
previous = {
|
|
6118
6132
|
version: 2,
|
|
6119
|
-
store: (0,
|
|
6133
|
+
store: (0, import_node_crypto7.randomUUID)(),
|
|
6120
6134
|
epoch: 0,
|
|
6121
6135
|
revision: 0,
|
|
6122
6136
|
parkingRevision: 0,
|
|
@@ -6259,7 +6273,7 @@ var init_reliability_contract = __esm({
|
|
|
6259
6273
|
|
|
6260
6274
|
// src/core/reliability-operation-store.ts
|
|
6261
6275
|
function installedCliVersion() {
|
|
6262
|
-
return true ? "0.1.
|
|
6276
|
+
return true ? "0.1.2" : "0.0.0-dev";
|
|
6263
6277
|
}
|
|
6264
6278
|
function compareCliVersions(left, right) {
|
|
6265
6279
|
const parts = (value) => value.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
@@ -6275,7 +6289,7 @@ function identityKey(identity2) {
|
|
|
6275
6289
|
if (!import_node_path13.default.isAbsolute(identity2.repoPath) || import_node_path13.default.resolve(identity2.repoPath) !== identity2.repoPath || identity2.repoPath.includes("\0") || identity2.workspace !== null && !isReliabilityId(identity2.workspace) || !["devpod", "devsy"].includes(identity2.provider)) {
|
|
6276
6290
|
throw new Error("Invalid reliability workspace identity.");
|
|
6277
6291
|
}
|
|
6278
|
-
return (0,
|
|
6292
|
+
return (0, import_node_crypto8.createHash)("sha256").update(identity2.repoPath).digest("hex");
|
|
6279
6293
|
}
|
|
6280
6294
|
function reliabilityOperationPath(identity2) {
|
|
6281
6295
|
return import_node_path13.default.join(DEVROUTER_HOME, "reliability", `${identityKey(identity2)}.json`);
|
|
@@ -6574,12 +6588,20 @@ function validate2(record5, identity2) {
|
|
|
6574
6588
|
}
|
|
6575
6589
|
}
|
|
6576
6590
|
}
|
|
6591
|
+
function journalEntryLocation(name) {
|
|
6592
|
+
const printable = name.replace(/[^A-Za-z0-9._-]/g, "?");
|
|
6593
|
+
return printable.length > MAX_REPORTED_ENTRY_NAME ? `${printable.slice(0, MAX_REPORTED_ENTRY_NAME - 3)}...` : printable;
|
|
6594
|
+
}
|
|
6577
6595
|
function createLifecycleCapacityStore(directory = import_node_path13.default.join(DEVROUTER_HOME, "controller")) {
|
|
6578
6596
|
return new CapacityStore(directory, void 0, () => {
|
|
6579
6597
|
try {
|
|
6580
6598
|
return listUnsettledCapacityBindings().floor;
|
|
6581
|
-
} catch {
|
|
6582
|
-
throw new CapacityHistoryError("capacity-history-unprovable")
|
|
6599
|
+
} catch (error) {
|
|
6600
|
+
throw error instanceof ReliabilityJournalError ? new CapacityHistoryError("capacity-history-unprovable", error.cause, error.location) : new CapacityHistoryError(
|
|
6601
|
+
"capacity-history-unprovable",
|
|
6602
|
+
"journal-enumeration-failed",
|
|
6603
|
+
null
|
|
6604
|
+
);
|
|
6583
6605
|
}
|
|
6584
6606
|
});
|
|
6585
6607
|
}
|
|
@@ -6638,11 +6660,12 @@ function readBoundedPrivateJson(file, label2) {
|
|
|
6638
6660
|
try {
|
|
6639
6661
|
const stat = import_node_fs11.default.fstatSync(descriptor);
|
|
6640
6662
|
if (!stat.isFile() || stat.uid !== process.getuid?.() || stat.size > MAX_RECORD_BYTES || (stat.mode & 63) !== 0) {
|
|
6641
|
-
throw new
|
|
6663
|
+
throw new JournalFileGuardError(`${label2} is not a bounded private file.`);
|
|
6642
6664
|
}
|
|
6643
6665
|
const bytes2 = Buffer.alloc(MAX_RECORD_BYTES + 1);
|
|
6644
6666
|
const count = import_node_fs11.default.readSync(descriptor, bytes2, 0, bytes2.length, 0);
|
|
6645
|
-
if (count > MAX_RECORD_BYTES)
|
|
6667
|
+
if (count > MAX_RECORD_BYTES)
|
|
6668
|
+
throw new JournalFileGuardError(`${label2} exceeds its byte limit.`);
|
|
6646
6669
|
return JSON.parse(bytes2.subarray(0, count).toString("utf8"));
|
|
6647
6670
|
} finally {
|
|
6648
6671
|
import_node_fs11.default.closeSync(descriptor);
|
|
@@ -6650,7 +6673,11 @@ function readBoundedPrivateJson(file, label2) {
|
|
|
6650
6673
|
}
|
|
6651
6674
|
function assertReliabilityEnumerationTime(startedAtMs) {
|
|
6652
6675
|
if (performance.now() - startedAtMs > MAX_RELIABILITY_ENUMERATION_MS)
|
|
6653
|
-
throw new
|
|
6676
|
+
throw new ReliabilityJournalError(
|
|
6677
|
+
"journal-enumeration-timeout",
|
|
6678
|
+
null,
|
|
6679
|
+
"Reliability journal enumeration exceeded its time limit."
|
|
6680
|
+
);
|
|
6654
6681
|
}
|
|
6655
6682
|
function reliabilityDirectory() {
|
|
6656
6683
|
return import_node_path13.default.join(DEVROUTER_HOME, "reliability");
|
|
@@ -6671,22 +6698,56 @@ function listReliabilityOperations() {
|
|
|
6671
6698
|
stat = import_node_fs11.default.lstatSync(directory);
|
|
6672
6699
|
} catch (error) {
|
|
6673
6700
|
if (error.code === "ENOENT") return [];
|
|
6674
|
-
throw
|
|
6701
|
+
throw new ReliabilityJournalError(
|
|
6702
|
+
"journal-directory-unreadable",
|
|
6703
|
+
null,
|
|
6704
|
+
"Reliability journal directory could not be read."
|
|
6705
|
+
);
|
|
6675
6706
|
}
|
|
6676
6707
|
if (!stat.isDirectory() || stat.isSymbolicLink())
|
|
6677
|
-
throw new
|
|
6708
|
+
throw new ReliabilityJournalError(
|
|
6709
|
+
"journal-directory-unsafe",
|
|
6710
|
+
null,
|
|
6711
|
+
"Reliability journal directory is unsafe."
|
|
6712
|
+
);
|
|
6678
6713
|
if (stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0)
|
|
6679
|
-
throw new
|
|
6714
|
+
throw new ReliabilityJournalError(
|
|
6715
|
+
"journal-directory-unsafe",
|
|
6716
|
+
null,
|
|
6717
|
+
"Reliability journal directory is not private."
|
|
6718
|
+
);
|
|
6680
6719
|
const entries = [];
|
|
6681
|
-
|
|
6720
|
+
let handle;
|
|
6721
|
+
try {
|
|
6722
|
+
handle = import_node_fs11.default.opendirSync(directory);
|
|
6723
|
+
} catch {
|
|
6724
|
+
throw new ReliabilityJournalError(
|
|
6725
|
+
"journal-directory-unreadable",
|
|
6726
|
+
null,
|
|
6727
|
+
"Reliability journal directory could not be read."
|
|
6728
|
+
);
|
|
6729
|
+
}
|
|
6682
6730
|
try {
|
|
6683
6731
|
for (; ; ) {
|
|
6684
6732
|
assertReliabilityEnumerationTime(startedAtMs);
|
|
6685
|
-
|
|
6733
|
+
let entry;
|
|
6734
|
+
try {
|
|
6735
|
+
entry = handle.readSync();
|
|
6736
|
+
} catch {
|
|
6737
|
+
throw new ReliabilityJournalError(
|
|
6738
|
+
"journal-directory-unreadable",
|
|
6739
|
+
null,
|
|
6740
|
+
"Reliability journal directory could not be read."
|
|
6741
|
+
);
|
|
6742
|
+
}
|
|
6686
6743
|
if (!entry) break;
|
|
6687
6744
|
entries.push(entry);
|
|
6688
6745
|
if (entries.length > MAX_RELIABILITY_DIRECTORY_ENTRIES)
|
|
6689
|
-
throw new
|
|
6746
|
+
throw new ReliabilityJournalError(
|
|
6747
|
+
"journal-enumeration-limit",
|
|
6748
|
+
null,
|
|
6749
|
+
"Reliability journal directory exceeds its entry limit."
|
|
6750
|
+
);
|
|
6690
6751
|
}
|
|
6691
6752
|
} finally {
|
|
6692
6753
|
handle.closeSync();
|
|
@@ -6695,27 +6756,82 @@ function listReliabilityOperations() {
|
|
|
6695
6756
|
for (const entry of entries) {
|
|
6696
6757
|
assertReliabilityEnumerationTime(startedAtMs);
|
|
6697
6758
|
if (entry.isSymbolicLink())
|
|
6698
|
-
throw new
|
|
6759
|
+
throw new ReliabilityJournalError(
|
|
6760
|
+
"journal-entry-unsupported",
|
|
6761
|
+
journalEntryLocation(entry.name),
|
|
6762
|
+
"Reliability journal directory contains a symlink."
|
|
6763
|
+
);
|
|
6699
6764
|
if (!entry.isFile())
|
|
6700
|
-
throw new
|
|
6765
|
+
throw new ReliabilityJournalError(
|
|
6766
|
+
"journal-entry-unsupported",
|
|
6767
|
+
journalEntryLocation(entry.name),
|
|
6768
|
+
"Reliability journal directory contains an unsupported entry."
|
|
6769
|
+
);
|
|
6701
6770
|
if (RELIABILITY_LOCK_NAME_RE.test(entry.name) || RELIABILITY_ATOMIC_TEMP_NAME_RE.test(entry.name))
|
|
6702
6771
|
continue;
|
|
6703
6772
|
const match = RELIABILITY_JOURNAL_NAME_RE.exec(entry.name);
|
|
6704
|
-
if (!match)
|
|
6773
|
+
if (!match)
|
|
6774
|
+
throw new ReliabilityJournalError(
|
|
6775
|
+
"journal-entry-unsupported",
|
|
6776
|
+
journalEntryLocation(entry.name),
|
|
6777
|
+
"Reliability journal directory contains an unsupported entry."
|
|
6778
|
+
);
|
|
6705
6779
|
journals.push({ name: entry.name, key: match[1] });
|
|
6706
6780
|
}
|
|
6707
6781
|
if (journals.length > MAX_RELIABILITY_JOURNALS)
|
|
6708
|
-
throw new
|
|
6782
|
+
throw new ReliabilityJournalError(
|
|
6783
|
+
"journal-enumeration-limit",
|
|
6784
|
+
null,
|
|
6785
|
+
"Reliability journal directory exceeds its journal limit."
|
|
6786
|
+
);
|
|
6709
6787
|
journals.sort((left, right) => left.name.localeCompare(right.name));
|
|
6710
6788
|
const records = [];
|
|
6711
6789
|
for (const journal of journals) {
|
|
6712
6790
|
assertReliabilityEnumerationTime(startedAtMs);
|
|
6713
6791
|
const file = import_node_path13.default.join(directory, journal.name);
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6792
|
+
let raw;
|
|
6793
|
+
try {
|
|
6794
|
+
raw = readBoundedPrivateJson(file, "Reliability journal");
|
|
6795
|
+
} catch (error) {
|
|
6796
|
+
const fsCode = error?.code;
|
|
6797
|
+
const cause = error instanceof JournalFileGuardError ? "journal-entry-unsafe" : error instanceof SyntaxError || !fsCode ? "journal-invalid" : "journal-unreadable";
|
|
6798
|
+
throw new ReliabilityJournalError(
|
|
6799
|
+
cause,
|
|
6800
|
+
journalEntryLocation(journal.name),
|
|
6801
|
+
error instanceof JournalFileGuardError ? error.message : cause === "journal-invalid" ? "Reliability journal entry is invalid." : "Reliability journal entry could not be read."
|
|
6802
|
+
);
|
|
6803
|
+
}
|
|
6804
|
+
if (raw === void 0)
|
|
6805
|
+
throw new ReliabilityJournalError(
|
|
6806
|
+
"journal-unstable",
|
|
6807
|
+
journalEntryLocation(journal.name),
|
|
6808
|
+
"Reliability journal disappeared during enumeration."
|
|
6809
|
+
);
|
|
6810
|
+
let identity2;
|
|
6811
|
+
let record5;
|
|
6812
|
+
try {
|
|
6813
|
+
identity2 = journalIdentity(raw);
|
|
6814
|
+
if (identityKey(identity2) !== journal.key)
|
|
6815
|
+
throw new ReliabilityJournalError(
|
|
6816
|
+
"journal-identity-mismatch",
|
|
6817
|
+
journalEntryLocation(journal.name),
|
|
6818
|
+
"Reliability journal filename does not match its identity."
|
|
6819
|
+
);
|
|
6820
|
+
record5 = readReliabilityOperation(identity2);
|
|
6821
|
+
} catch (error) {
|
|
6822
|
+
if (error instanceof ReliabilityJournalError) throw error;
|
|
6823
|
+
throw new ReliabilityJournalError(
|
|
6824
|
+
"journal-invalid",
|
|
6825
|
+
journalEntryLocation(journal.name),
|
|
6826
|
+
"Reliability journal entry is invalid."
|
|
6827
|
+
);
|
|
6828
|
+
}
|
|
6829
|
+
if (!record5)
|
|
6830
|
+
throw new ReliabilityJournalError(
|
|
6831
|
+
"journal-unstable",
|
|
6832
|
+
journalEntryLocation(journal.name),
|
|
6833
|
+
"Reliability journal disappeared during enumeration."
|
|
6834
|
+
);
|
|
6719
6835
|
records.push(record5);
|
|
6720
6836
|
assertReliabilityEnumerationTime(startedAtMs);
|
|
6721
6837
|
}
|
|
@@ -6872,11 +6988,11 @@ function setReliabilityHumanPin(identity2, expectedJournalRevision, expectedProt
|
|
|
6872
6988
|
};
|
|
6873
6989
|
});
|
|
6874
6990
|
}
|
|
6875
|
-
var
|
|
6991
|
+
var import_node_crypto8, import_node_fs11, import_node_path13, import_node_util3, MAX_RECORD_BYTES, MAX_RELIABILITY_JOURNALS, MAX_RELIABILITY_DIRECTORY_ENTRIES, MAX_RELIABILITY_ENUMERATION_MS, RELIABILITY_JOURNAL_NAME_RE, RELIABILITY_LOCK_NAME_RE, RELIABILITY_ATOMIC_TEMP_NAME_RE, ReliabilityJournalError, MAX_REPORTED_ENTRY_NAME, JournalFileGuardError;
|
|
6876
6992
|
var init_reliability_operation_store = __esm({
|
|
6877
6993
|
"src/core/reliability-operation-store.ts"() {
|
|
6878
6994
|
"use strict";
|
|
6879
|
-
|
|
6995
|
+
import_node_crypto8 = require("crypto");
|
|
6880
6996
|
import_node_fs11 = __toESM(require("fs"));
|
|
6881
6997
|
import_node_path13 = __toESM(require("path"));
|
|
6882
6998
|
import_node_util3 = require("util");
|
|
@@ -6893,6 +7009,21 @@ var init_reliability_operation_store = __esm({
|
|
|
6893
7009
|
RELIABILITY_JOURNAL_NAME_RE = /^([0-9a-f]{64})\.json$/;
|
|
6894
7010
|
RELIABILITY_LOCK_NAME_RE = /^[0-9a-f]{64}\.json\.lock(?:\.[0-9]+\.[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\.candidate(?:\.stale)?|\.queue\.[0-9]+\.[0-9]+\.[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}(?:\.candidate)?)?$/;
|
|
6895
7011
|
RELIABILITY_ATOMIC_TEMP_NAME_RE = /^\.[0-9a-f]{64}\.json\.[0-9]+\.[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\.tmp$/;
|
|
7012
|
+
ReliabilityJournalError = class extends Error {
|
|
7013
|
+
constructor(cause, location, message) {
|
|
7014
|
+
super(message);
|
|
7015
|
+
this.cause = cause;
|
|
7016
|
+
this.location = location;
|
|
7017
|
+
this.name = "ReliabilityJournalError";
|
|
7018
|
+
}
|
|
7019
|
+
};
|
|
7020
|
+
MAX_REPORTED_ENTRY_NAME = 160;
|
|
7021
|
+
JournalFileGuardError = class extends Error {
|
|
7022
|
+
constructor(message) {
|
|
7023
|
+
super(message);
|
|
7024
|
+
this.name = "JournalFileGuardError";
|
|
7025
|
+
}
|
|
7026
|
+
};
|
|
6896
7027
|
}
|
|
6897
7028
|
});
|
|
6898
7029
|
|
|
@@ -7258,7 +7389,7 @@ var init_managed_stop_baseline = __esm({
|
|
|
7258
7389
|
|
|
7259
7390
|
// src/core/managed-runtime-state.ts
|
|
7260
7391
|
function stateKey(repoPath, workspace) {
|
|
7261
|
-
return (0,
|
|
7392
|
+
return (0, import_node_crypto9.createHash)("sha256").update(`${repoPath}\0${workspace ?? ""}`, "utf-8").digest("hex");
|
|
7262
7393
|
}
|
|
7263
7394
|
function managedRuntimeStatePath(repoPath, workspace) {
|
|
7264
7395
|
return import_node_path17.default.join(DEVROUTER_HOME, "managed-runtime", `${stateKey(repoPath, workspace)}.json`);
|
|
@@ -7337,11 +7468,11 @@ function readManagedRuntimeState(repoPath, workspace, read2 = (file) => import_n
|
|
|
7337
7468
|
}
|
|
7338
7469
|
return validateState(parsed, repoPath, workspace);
|
|
7339
7470
|
}
|
|
7340
|
-
var
|
|
7471
|
+
var import_node_crypto9, import_node_fs13, import_node_path17;
|
|
7341
7472
|
var init_managed_runtime_state = __esm({
|
|
7342
7473
|
"src/core/managed-runtime-state.ts"() {
|
|
7343
7474
|
"use strict";
|
|
7344
|
-
|
|
7475
|
+
import_node_crypto9 = require("crypto");
|
|
7345
7476
|
import_node_fs13 = __toESM(require("fs"));
|
|
7346
7477
|
import_node_path17 = __toESM(require("path"));
|
|
7347
7478
|
init_atomic_file();
|
|
@@ -8416,7 +8547,7 @@ async function observeControllerBinding(directory, input2) {
|
|
|
8416
8547
|
};
|
|
8417
8548
|
}
|
|
8418
8549
|
async function controllerRequest(directory, input2, emit, timeoutMs) {
|
|
8419
|
-
const request2 = parseControllerRequest({ ...input2, version: 1, id: (0,
|
|
8550
|
+
const request2 = parseControllerRequest({ ...input2, version: 1, id: (0, import_node_crypto10.randomUUID)() });
|
|
8420
8551
|
const socketPath = import_node_path20.default.join(directory, "control.sock");
|
|
8421
8552
|
const stat = import_node_fs14.default.lstatSync(socketPath);
|
|
8422
8553
|
if (!stat.isSocket() || stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0)
|
|
@@ -8426,7 +8557,7 @@ async function controllerRequest(directory, input2, emit, timeoutMs) {
|
|
|
8426
8557
|
let buffer = Buffer.alloc(0);
|
|
8427
8558
|
let handshake = false;
|
|
8428
8559
|
let completed = false;
|
|
8429
|
-
const handshakeId = (0,
|
|
8560
|
+
const handshakeId = (0, import_node_crypto10.randomUUID)();
|
|
8430
8561
|
const timeout = request2.method === "watch" || request2.method === "operation-watch" ? Math.min(request2.timeout + 5, 2147483) * 1e3 : 5e3;
|
|
8431
8562
|
const timer = setTimeout(
|
|
8432
8563
|
() => {
|
|
@@ -8492,11 +8623,11 @@ async function controllerRequest(directory, input2, emit, timeoutMs) {
|
|
|
8492
8623
|
});
|
|
8493
8624
|
});
|
|
8494
8625
|
}
|
|
8495
|
-
var
|
|
8626
|
+
var import_node_crypto10, import_node_fs14, import_node_net, import_node_path20, CONTROLLER_OPERATION_WATCH_SECONDS, CONTROLLER_OPERATION_DEFAULT_WAIT_SECONDS, CONTROLLER_OPERATION_MAX_WAIT_SECONDS, CONTROLLER_ID_RE2, ControllerResponseDeadlineError, ControllerOperationSubmissionError;
|
|
8496
8627
|
var init_controller_client = __esm({
|
|
8497
8628
|
"src/core/controller-client.ts"() {
|
|
8498
8629
|
"use strict";
|
|
8499
|
-
|
|
8630
|
+
import_node_crypto10 = require("crypto");
|
|
8500
8631
|
import_node_fs14 = __toESM(require("fs"));
|
|
8501
8632
|
import_node_net = __toESM(require("net"));
|
|
8502
8633
|
import_node_path20 = __toESM(require("path"));
|
|
@@ -8632,11 +8763,11 @@ var init_reliability_output = __esm({
|
|
|
8632
8763
|
|
|
8633
8764
|
// src/core/controller-monitor.ts
|
|
8634
8765
|
function controllerCapability(selector) {
|
|
8635
|
-
return selector === "runtime" ? "runtime" : `app-${(0,
|
|
8766
|
+
return selector === "runtime" ? "runtime" : `app-${(0, import_node_crypto11.createHash)("sha256").update(selector).digest("hex")}`;
|
|
8636
8767
|
}
|
|
8637
8768
|
function sessionConsumerId(input2) {
|
|
8638
8769
|
const { store, epoch, session, generation } = input2;
|
|
8639
|
-
return `session-${(0,
|
|
8770
|
+
return `session-${(0, import_node_crypto11.createHash)("sha256").update(JSON.stringify([store, epoch, session, generation])).digest("hex")}`;
|
|
8640
8771
|
}
|
|
8641
8772
|
function environmentIdentity(environment) {
|
|
8642
8773
|
return {
|
|
@@ -8657,11 +8788,11 @@ function parkingConsumers(consumers) {
|
|
|
8657
8788
|
consentRevision
|
|
8658
8789
|
})).sort((a, b) => a.id.localeCompare(b.id));
|
|
8659
8790
|
}
|
|
8660
|
-
var
|
|
8791
|
+
var import_node_crypto11, import_node_util7, ControllerObservationBindingChanged, UNFINISHED_PARK_SCAN_MS, ControllerMonitor;
|
|
8661
8792
|
var init_controller_monitor = __esm({
|
|
8662
8793
|
"src/core/controller-monitor.ts"() {
|
|
8663
8794
|
"use strict";
|
|
8664
|
-
|
|
8795
|
+
import_node_crypto11 = require("crypto");
|
|
8665
8796
|
import_node_util7 = require("util");
|
|
8666
8797
|
init_reliability_operation_store();
|
|
8667
8798
|
init_reliability_output();
|
|
@@ -8935,7 +9066,7 @@ var init_controller_monitor = __esm({
|
|
|
8935
9066
|
const projections = /* @__PURE__ */ new Map();
|
|
8936
9067
|
for (const consumer of consumers) {
|
|
8937
9068
|
const transient = structuredClone(journal.state);
|
|
8938
|
-
const consumerId = `observer-${(0,
|
|
9069
|
+
const consumerId = `observer-${(0, import_node_crypto11.createHash)("sha256").update(consumer.id).digest("hex")}`;
|
|
8939
9070
|
transient.consumers = [
|
|
8940
9071
|
{
|
|
8941
9072
|
id: consumerId,
|
|
@@ -9353,7 +9484,7 @@ function writeManifestRecord(cacheRoot, manifest) {
|
|
|
9353
9484
|
import_node_fs16.default.mkdirSync(directory, { recursive: true, mode: 448 });
|
|
9354
9485
|
const temporary = import_node_path22.default.join(
|
|
9355
9486
|
directory,
|
|
9356
|
-
`.${DEVSY_AGENT_MANIFEST_FILE}.${process.pid}.${(0,
|
|
9487
|
+
`.${DEVSY_AGENT_MANIFEST_FILE}.${process.pid}.${(0, import_node_crypto12.randomUUID)()}.tmp`
|
|
9357
9488
|
);
|
|
9358
9489
|
const record5 = {
|
|
9359
9490
|
version: 1,
|
|
@@ -9451,7 +9582,7 @@ function managedBinaryPath(cacheRoot, devsyVersion, asset) {
|
|
|
9451
9582
|
return import_node_path22.default.join(cacheRoot, `v${devsyVersion}`, asset.name);
|
|
9452
9583
|
}
|
|
9453
9584
|
function hashOpenFile(file) {
|
|
9454
|
-
const digest3 = (0,
|
|
9585
|
+
const digest3 = (0, import_node_crypto12.createHash)("sha256");
|
|
9455
9586
|
const buffer = Buffer.allocUnsafe(1024 * 1024);
|
|
9456
9587
|
let position = 0;
|
|
9457
9588
|
for (; ; ) {
|
|
@@ -9647,7 +9778,7 @@ async function downloadAndPublish(asset, binaryPath, fetcher, githubCliDownloade
|
|
|
9647
9778
|
import_node_fs16.default.mkdirSync(directory, { recursive: true, mode: 448 });
|
|
9648
9779
|
const temporaryPath = import_node_path22.default.join(
|
|
9649
9780
|
directory,
|
|
9650
|
-
`.${import_node_path22.default.basename(binaryPath)}.${process.pid}.${(0,
|
|
9781
|
+
`.${import_node_path22.default.basename(binaryPath)}.${process.pid}.${(0, import_node_crypto12.randomUUID)()}.tmp`
|
|
9651
9782
|
);
|
|
9652
9783
|
let handle;
|
|
9653
9784
|
try {
|
|
@@ -9659,7 +9790,7 @@ async function downloadAndPublish(asset, binaryPath, fetcher, githubCliDownloade
|
|
|
9659
9790
|
directFailure = error;
|
|
9660
9791
|
}
|
|
9661
9792
|
handle = await import_node_fs16.default.promises.open(temporaryPath, "wx", 384);
|
|
9662
|
-
const digest3 = (0,
|
|
9793
|
+
const digest3 = (0, import_node_crypto12.createHash)("sha256");
|
|
9663
9794
|
let size = 0;
|
|
9664
9795
|
const writeChunk = async (chunk) => {
|
|
9665
9796
|
size += chunk.byteLength;
|
|
@@ -9795,12 +9926,12 @@ async function prepareDevsyAgent(options = {}) {
|
|
|
9795
9926
|
return { ...preparedFromInspection(published), changed: true, transport };
|
|
9796
9927
|
});
|
|
9797
9928
|
}
|
|
9798
|
-
var import_node_child_process7,
|
|
9929
|
+
var import_node_child_process7, import_node_crypto12, import_node_fs16, import_node_path22, PINNED_DEVSY_AGENT_VERSION, SUPPORTED_DEVSY_MIN_VERSION, SUPPORTED_DEVSY_MAX_VERSION, SUPPORTED_DEVSY_RANGE, DEVSY_AGENT_SETUP_COMMAND, DEVSY_RELEASE_TAG_PREFIX, DEVSY_RELEASE_METADATA_BASE_URL, DEVSY_AGENT_ASSETS, DevsyAgentReadinessError, DEVSY_AGENT_CACHE_LOCK, DEVSY_AGENT_LOCK_WAIT_MS, DEVSY_AGENT_MANIFEST_FILE, DEVSY_AGENT_ASSET_NAMES, GITHUB_CLI_STDERR_TAIL_BYTES;
|
|
9799
9930
|
var init_devsy_agent = __esm({
|
|
9800
9931
|
"src/core/devsy-agent.ts"() {
|
|
9801
9932
|
"use strict";
|
|
9802
9933
|
import_node_child_process7 = require("child_process");
|
|
9803
|
-
|
|
9934
|
+
import_node_crypto12 = require("crypto");
|
|
9804
9935
|
import_node_fs16 = __toESM(require("fs"));
|
|
9805
9936
|
import_node_path22 = __toESM(require("path"));
|
|
9806
9937
|
init_file_lock();
|
|
@@ -10037,7 +10168,7 @@ function isWildcard(values) {
|
|
|
10037
10168
|
return values?.length === 1 && values[0] === "*";
|
|
10038
10169
|
}
|
|
10039
10170
|
function sha256(contents) {
|
|
10040
|
-
return (0,
|
|
10171
|
+
return (0, import_node_crypto13.createHash)("sha256").update(contents, "utf-8").digest("hex");
|
|
10041
10172
|
}
|
|
10042
10173
|
function safeComposeProject(value) {
|
|
10043
10174
|
if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(value)) {
|
|
@@ -10260,12 +10391,12 @@ function stopExactManagedService(containerId, service, options) {
|
|
|
10260
10391
|
throw new Error(`Could not stop exact managed service '${service}' (${containerId}).`);
|
|
10261
10392
|
}
|
|
10262
10393
|
}
|
|
10263
|
-
var import_node_child_process8,
|
|
10394
|
+
var import_node_child_process8, import_node_crypto13, import_node_fs18, import_node_path25, import_yaml3, MANAGED_DEVCONTAINER_PATH, MANAGED_DEVCONTAINER_MARKER, COMPOSE_HASH_TIMEOUT_MS;
|
|
10264
10395
|
var init_devcontainer_profile = __esm({
|
|
10265
10396
|
"src/core/devcontainer-profile.ts"() {
|
|
10266
10397
|
"use strict";
|
|
10267
10398
|
import_node_child_process8 = require("child_process");
|
|
10268
|
-
|
|
10399
|
+
import_node_crypto13 = require("crypto");
|
|
10269
10400
|
import_node_fs18 = __toESM(require("fs"));
|
|
10270
10401
|
import_node_path25 = __toESM(require("path"));
|
|
10271
10402
|
import_yaml3 = __toESM(require("yaml"));
|
|
@@ -11751,7 +11882,7 @@ function parseDnsHostsFromSubjectAltName(subjectAltName) {
|
|
|
11751
11882
|
return normalizeUniqueHosts(names);
|
|
11752
11883
|
}
|
|
11753
11884
|
function parseCertificateDnsHosts(pem) {
|
|
11754
|
-
const certificate = new
|
|
11885
|
+
const certificate = new import_node_crypto14.X509Certificate(pem);
|
|
11755
11886
|
const subjectAltName = certificate.subjectAltName ?? "";
|
|
11756
11887
|
if (subjectAltName.length === 0) {
|
|
11757
11888
|
return [];
|
|
@@ -11951,12 +12082,12 @@ Run: ${tlsSetupCommand(options.repoPath)}`
|
|
|
11951
12082
|
);
|
|
11952
12083
|
}
|
|
11953
12084
|
}
|
|
11954
|
-
var import_node_child_process14,
|
|
12085
|
+
var import_node_child_process14, import_node_crypto14, import_node_fs23, import_node_path31, DEFAULT_TLS_CERT_HOSTS, TLS_CERTIFICATE_LOCK_FILE, TLS_CERTIFICATE_LOCK_WAIT_MS, TLS_CERTIFICATE_WRITE_ATTEMPTS;
|
|
11955
12086
|
var init_tls = __esm({
|
|
11956
12087
|
"src/core/tls.ts"() {
|
|
11957
12088
|
"use strict";
|
|
11958
12089
|
import_node_child_process14 = require("child_process");
|
|
11959
|
-
|
|
12090
|
+
import_node_crypto14 = require("crypto");
|
|
11960
12091
|
import_node_fs23 = __toESM(require("fs"));
|
|
11961
12092
|
import_node_path31 = __toESM(require("path"));
|
|
11962
12093
|
init_docker();
|
|
@@ -13515,7 +13646,7 @@ function validateRoot(root) {
|
|
|
13515
13646
|
return resolved;
|
|
13516
13647
|
}
|
|
13517
13648
|
function hashKey(value) {
|
|
13518
|
-
return (0,
|
|
13649
|
+
return (0, import_node_crypto15.createHash)("sha256").update(value).digest("hex");
|
|
13519
13650
|
}
|
|
13520
13651
|
function cloneFence(fence) {
|
|
13521
13652
|
return { ...fence };
|
|
@@ -13538,11 +13669,11 @@ function isErrno2(error, code) {
|
|
|
13538
13669
|
function claimError(code, message) {
|
|
13539
13670
|
return new NetworkClaimError(code, message);
|
|
13540
13671
|
}
|
|
13541
|
-
var
|
|
13672
|
+
var import_node_crypto15, import_node_fs27, import_node_path35, NETWORK_CLAIMS_VERSION, NETWORK_CLAIMS_ROOT, NETWORK_CLAIMS_MAX_RECORDS, NETWORK_CLAIMS_MAX_FILE_BYTES, NetworkClaimError, CLAIM_CORE_KEYS, CLAIM_KEYS, FENCE_KEYS, DOCUMENT_KEYS, MAX_CLAIM_TEXT, MAX_ENDPOINT_TEXT;
|
|
13542
13673
|
var init_network_claims = __esm({
|
|
13543
13674
|
"src/core/network-claims.ts"() {
|
|
13544
13675
|
"use strict";
|
|
13545
|
-
|
|
13676
|
+
import_node_crypto15 = require("crypto");
|
|
13546
13677
|
import_node_fs27 = __toESM(require("fs"));
|
|
13547
13678
|
import_node_path35 = __toESM(require("path"));
|
|
13548
13679
|
init_atomic_file();
|
|
@@ -13595,7 +13726,7 @@ var init_network_claims = __esm({
|
|
|
13595
13726
|
function networkOwnerKey(repoPath) {
|
|
13596
13727
|
if (!import_node_path36.default.isAbsolute(repoPath) || import_node_path36.default.resolve(repoPath) !== repoPath)
|
|
13597
13728
|
throw new Error("Invalid network owner path.");
|
|
13598
|
-
return (0,
|
|
13729
|
+
return (0, import_node_crypto16.createHash)("sha256").update(repoPath).digest("hex");
|
|
13599
13730
|
}
|
|
13600
13731
|
function findOwnedNetworkClaim(repoPath, root = NETWORK_CLAIMS_ROOT) {
|
|
13601
13732
|
let names;
|
|
@@ -13635,7 +13766,7 @@ function findOwnedNetworkClaim(repoPath, root = NETWORK_CLAIMS_ROOT) {
|
|
|
13635
13766
|
} finally {
|
|
13636
13767
|
import_node_fs28.default.closeSync(descriptor);
|
|
13637
13768
|
}
|
|
13638
|
-
if (typeof value.daemonId !== "string" || `${(0,
|
|
13769
|
+
if (typeof value.daemonId !== "string" || `${(0, import_node_crypto16.createHash)("sha256").update(value.daemonId).digest("hex")}.json` !== file)
|
|
13639
13770
|
throw new Error("Retained network daemon identity is invalid.");
|
|
13640
13771
|
const claim2 = readNetworkClaim({
|
|
13641
13772
|
daemonId: value.daemonId,
|
|
@@ -13649,11 +13780,11 @@ function findOwnedNetworkClaim(repoPath, root = NETWORK_CLAIMS_ROOT) {
|
|
|
13649
13780
|
}
|
|
13650
13781
|
return found;
|
|
13651
13782
|
}
|
|
13652
|
-
var
|
|
13783
|
+
var import_node_crypto16, import_node_fs28, import_node_path36;
|
|
13653
13784
|
var init_network_claim_lookup = __esm({
|
|
13654
13785
|
"src/core/network-claim-lookup.ts"() {
|
|
13655
13786
|
"use strict";
|
|
13656
|
-
|
|
13787
|
+
import_node_crypto16 = require("crypto");
|
|
13657
13788
|
import_node_fs28 = __toESM(require("fs"));
|
|
13658
13789
|
import_node_path36 = __toESM(require("path"));
|
|
13659
13790
|
init_network_claims();
|
|
@@ -13680,7 +13811,7 @@ function qualifyNetworkProviderDefinition(value, provider) {
|
|
|
13680
13811
|
if (definition.name !== "docker" || ![true, "true"].includes(agent.local) || agent.driver !== void 0 && agent.driver !== "docker" && agent.driver !== "" || docker.path !== "${DOCKER_PATH}" || docker.builder !== "${DOCKER_BUILDER}" || ![false, "false"].includes(docker.install) || (provider === "devsy" ? docker.elevation !== "${DOCKER_ELEVATION}" : docker.elevation !== void 0 && docker.elevation !== "") || env.DOCKER_HOST !== "${DOCKER_HOST}" || Object.keys(env).some((key) => key !== "DOCKER_HOST") || host.global !== true || dockerPath.default !== "docker" || actualCommand.length !== 1 || typeof actualCommand[0] !== "string" || actualCommand[0].trim() !== command || Object.keys(exec).some((key) => key !== "command") || agent.path !== void 0 && agent.path !== "" || agent.downloadURL !== void 0 && agent.downloadURL !== "") {
|
|
13681
13812
|
throw new Error("Docker provider definition is not qualified for network allocation.");
|
|
13682
13813
|
}
|
|
13683
|
-
return (0,
|
|
13814
|
+
return (0, import_node_crypto17.createHash)("sha256").update(JSON.stringify({ name: definition.name, agent, options, exec })).digest("hex");
|
|
13684
13815
|
}
|
|
13685
13816
|
function read(provider, args) {
|
|
13686
13817
|
const result = (0, import_node_child_process16.spawnSync)(provider, args, {
|
|
@@ -13772,12 +13903,12 @@ function inspectNetworkProviderBinding(input2) {
|
|
|
13772
13903
|
);
|
|
13773
13904
|
}
|
|
13774
13905
|
}
|
|
13775
|
-
var import_node_child_process16,
|
|
13906
|
+
var import_node_child_process16, import_node_crypto17;
|
|
13776
13907
|
var init_network_provider_inspect = __esm({
|
|
13777
13908
|
"src/core/network-provider-inspect.ts"() {
|
|
13778
13909
|
"use strict";
|
|
13779
13910
|
import_node_child_process16 = require("child_process");
|
|
13780
|
-
|
|
13911
|
+
import_node_crypto17 = require("crypto");
|
|
13781
13912
|
init_devpod_environment();
|
|
13782
13913
|
init_devsy_agent();
|
|
13783
13914
|
}
|
|
@@ -15095,14 +15226,14 @@ async function runLifecycleWorker(request2, supervision, beforeAdmission) {
|
|
|
15095
15226
|
}
|
|
15096
15227
|
}
|
|
15097
15228
|
function newLifecycleIds() {
|
|
15098
|
-
return { requestId: (0,
|
|
15229
|
+
return { requestId: (0, import_node_crypto18.randomUUID)(), operationId: (0, import_node_crypto18.randomUUID)(), workerId: (0, import_node_crypto18.randomUUID)() };
|
|
15099
15230
|
}
|
|
15100
|
-
var import_node_child_process18,
|
|
15231
|
+
var import_node_child_process18, import_node_crypto18, import_node_fs30, import_node_path38, OUTPUT_BUFFER_LIMIT, DEFAULT_OUTPUT_PAGE_BYTES, LifecycleOutput, LifecycleWorkerAdmissionBusyError;
|
|
15101
15232
|
var init_reliability_worker = __esm({
|
|
15102
15233
|
"src/core/reliability-worker.ts"() {
|
|
15103
15234
|
"use strict";
|
|
15104
15235
|
import_node_child_process18 = require("child_process");
|
|
15105
|
-
|
|
15236
|
+
import_node_crypto18 = require("crypto");
|
|
15106
15237
|
import_node_fs30 = __toESM(require("fs"));
|
|
15107
15238
|
import_node_path38 = __toESM(require("path"));
|
|
15108
15239
|
init_file_lock();
|
|
@@ -15790,7 +15921,7 @@ function readRegularFile(filePath) {
|
|
|
15790
15921
|
return readRegularFileBytes(filePath)?.toString("utf-8");
|
|
15791
15922
|
}
|
|
15792
15923
|
function adapterFingerprint(adapter) {
|
|
15793
|
-
return (0,
|
|
15924
|
+
return (0, import_node_crypto19.createHash)("sha256").update(adapter).digest("hex");
|
|
15794
15925
|
}
|
|
15795
15926
|
function resolveManagedPostStartPlan(repoPath) {
|
|
15796
15927
|
const adapterPath = import_node_path41.default.join(repoPath, MANAGED_ADAPTER_PATH);
|
|
@@ -15880,12 +16011,12 @@ function runManagedProcessAction(options) {
|
|
|
15880
16011
|
}
|
|
15881
16012
|
return "drifted";
|
|
15882
16013
|
}
|
|
15883
|
-
var import_node_child_process23,
|
|
16014
|
+
var import_node_child_process23, import_node_crypto19, import_node_fs33, import_node_path41, MANAGED_MARKER, MANAGED_ADAPTER_PATH, RUNTIME_HELPER_PATH;
|
|
15884
16015
|
var init_managed_post_start = __esm({
|
|
15885
16016
|
"src/core/managed-post-start.ts"() {
|
|
15886
16017
|
"use strict";
|
|
15887
16018
|
import_node_child_process23 = require("child_process");
|
|
15888
|
-
|
|
16019
|
+
import_node_crypto19 = require("crypto");
|
|
15889
16020
|
import_node_fs33 = __toESM(require("fs"));
|
|
15890
16021
|
import_node_path41 = __toESM(require("path"));
|
|
15891
16022
|
init_devcontainer_config();
|
|
@@ -15897,24 +16028,45 @@ var init_managed_post_start = __esm({
|
|
|
15897
16028
|
});
|
|
15898
16029
|
|
|
15899
16030
|
// src/core/managed-runtime-status.ts
|
|
16031
|
+
function recoveryPath(repoPath) {
|
|
16032
|
+
if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(repoPath)) return repoPath;
|
|
16033
|
+
return `'${repoPath.replaceAll("'", "'\\''")}'`;
|
|
16034
|
+
}
|
|
15900
16035
|
function reliabilityRecovery(reason, repoPath) {
|
|
16036
|
+
const checkout = recoveryPath(repoPath);
|
|
15901
16037
|
switch (reason) {
|
|
15902
16038
|
case "stop-incomplete":
|
|
15903
16039
|
case "operation-unknown":
|
|
15904
|
-
return [`Run: devrouter stop ${
|
|
16040
|
+
return [`Run: devrouter stop ${checkout}`, `Run: devrouter ensure ${checkout} --repair`];
|
|
16041
|
+
case "start-refused":
|
|
16042
|
+
return [
|
|
16043
|
+
`Run: devrouter doctor --repo ${checkout} to read the refused fixed host-port claim and its holder`,
|
|
16044
|
+
`Stop the holding workspace or change this repository's own published binding, then run: devrouter ensure ${checkout}`
|
|
16045
|
+
];
|
|
15905
16046
|
case "unadmittable":
|
|
15906
16047
|
return [
|
|
15907
|
-
`Run: devrouter stop ${
|
|
15908
|
-
`Lower the requested capacity in .devrouter.yml, then run: devrouter ensure ${
|
|
16048
|
+
`Run: devrouter stop ${checkout}`,
|
|
16049
|
+
`Lower the requested capacity in .devrouter.yml, then run: devrouter ensure ${checkout}`
|
|
15909
16050
|
];
|
|
15910
16051
|
case "capacity-parked":
|
|
15911
|
-
return [
|
|
16052
|
+
return [
|
|
16053
|
+
"Parked for host capacity: the enrolled foreground controller resumes this checkout after its pressure dwell and live-consumer checks pass.",
|
|
16054
|
+
`Inspect the parked intent with: devrouter status --repo ${checkout} --json`,
|
|
16055
|
+
`'devrouter ensure' refuses while the journal stays parked; release the intent instead with: devrouter stop ${checkout}`
|
|
16056
|
+
];
|
|
15912
16057
|
case "capacity-waiting":
|
|
15913
|
-
return [`Run: devrouter ensure ${
|
|
16058
|
+
return [`Run: devrouter ensure ${checkout} (still queued until capacity frees up)`];
|
|
15914
16059
|
default:
|
|
15915
16060
|
return [];
|
|
15916
16061
|
}
|
|
15917
16062
|
}
|
|
16063
|
+
function refusedManagedStart(result) {
|
|
16064
|
+
if (result?.ok !== true) return false;
|
|
16065
|
+
const value = result.value;
|
|
16066
|
+
if (typeof value !== "object" || value === null) return false;
|
|
16067
|
+
const conflicts = value.hostPortConflicts;
|
|
16068
|
+
return Array.isArray(conflicts) && conflicts.length > 0;
|
|
16069
|
+
}
|
|
15918
16070
|
function readReliabilityStatus(options) {
|
|
15919
16071
|
let provider;
|
|
15920
16072
|
try {
|
|
@@ -15934,7 +16086,7 @@ function readReliabilityStatus(options) {
|
|
|
15934
16086
|
return void 0;
|
|
15935
16087
|
}
|
|
15936
16088
|
if (!record5) return void 0;
|
|
15937
|
-
const reason = reliabilityAttention(record5.state);
|
|
16089
|
+
const reason = reliabilityAttention(record5.state) ?? (record5.state.desired === "running" && refusedManagedStart(record5.result) ? "start-refused" : void 0);
|
|
15938
16090
|
return {
|
|
15939
16091
|
desired: record5.state.desired,
|
|
15940
16092
|
phase: record5.state.phase,
|
|
@@ -17007,11 +17159,13 @@ function networkCapacityCheck(report) {
|
|
|
17007
17159
|
(pool) => pool.candidates.some((candidate) => candidate.overlappingNetworkIds.length === 0)
|
|
17008
17160
|
);
|
|
17009
17161
|
const managedDetails = managed ? ` Managed policy: ${managed.policy.status}; /${managed.policy.requestedPrefixLength} capacity: ${managed.configuredPolicyCapacity.status}; claims: ${managed.claims.reserved} reserved, ${managed.claims.attached} attached, ${managed.claims.uncertain} uncertain.` : "";
|
|
17162
|
+
const blockers = report.allocation.blockers.slice(0, 4).map((blocker) => blocker.slice(0, 120));
|
|
17163
|
+
const blockerDetails = blockers.length > 0 ? ` Missing evidence: ${blockers.join("; ")}.` : "";
|
|
17010
17164
|
return {
|
|
17011
17165
|
id: "global.network-capacity",
|
|
17012
17166
|
level: legacyAvailable ? "ok" : "warn",
|
|
17013
17167
|
summary: exhausted ? "Docker default address pools are exhausted for new networks." : legacyAvailable ? "Docker default pools have unoccupied capacity; managed allocation is not configured." : "Network allocation readiness requires complete route and capacity evidence.",
|
|
17014
|
-
details: `${report.pools.length} pool(s); ${retained} network(s) have no active endpoints but retain container references. Allocation readiness: ${report.allocation.status}.${managedDetails}`,
|
|
17168
|
+
details: `${report.pools.length} pool(s); ${retained} network(s) have no active endpoints but retain container references. Allocation readiness: ${report.allocation.status}.${blockerDetails}${managedDetails}`,
|
|
17015
17169
|
suggestion: exhausted ? "Existing network reuse can continue. Review operator-approved route-safe pools or exact ownership-aware recovery. Stop and worktree removal do not release subnets; do not prune automatically." : "Review complete Docker, LAN, VPN and guest route evidence before allocating a new subnet. Unknown evidence does not authorize cleanup."
|
|
17016
17170
|
};
|
|
17017
17171
|
}
|
|
@@ -17029,21 +17183,21 @@ var init_network_diagnostics = __esm({
|
|
|
17029
17183
|
});
|
|
17030
17184
|
|
|
17031
17185
|
// src/core/network-compose.ts
|
|
17032
|
-
var
|
|
17186
|
+
var import_node_crypto20;
|
|
17033
17187
|
var init_network_compose = __esm({
|
|
17034
17188
|
"src/core/network-compose.ts"() {
|
|
17035
17189
|
"use strict";
|
|
17036
|
-
|
|
17190
|
+
import_node_crypto20 = require("crypto");
|
|
17037
17191
|
}
|
|
17038
17192
|
});
|
|
17039
17193
|
|
|
17040
17194
|
// src/core/network-compose-files.ts
|
|
17041
|
-
var import_node_child_process26,
|
|
17195
|
+
var import_node_child_process26, import_node_crypto21, import_node_fs35, import_node_path43, import_yaml4, MAX_BYTES3;
|
|
17042
17196
|
var init_network_compose_files = __esm({
|
|
17043
17197
|
"src/core/network-compose-files.ts"() {
|
|
17044
17198
|
"use strict";
|
|
17045
17199
|
import_node_child_process26 = require("child_process");
|
|
17046
|
-
|
|
17200
|
+
import_node_crypto21 = require("crypto");
|
|
17047
17201
|
import_node_fs35 = __toESM(require("fs"));
|
|
17048
17202
|
import_node_path43 = __toESM(require("path"));
|
|
17049
17203
|
import_yaml4 = __toESM(require("yaml"));
|
|
@@ -17075,11 +17229,11 @@ var init_network_lifecycle = __esm({
|
|
|
17075
17229
|
});
|
|
17076
17230
|
|
|
17077
17231
|
// src/core/network-managed.ts
|
|
17078
|
-
var
|
|
17232
|
+
var import_node_crypto22;
|
|
17079
17233
|
var init_network_managed = __esm({
|
|
17080
17234
|
"src/core/network-managed.ts"() {
|
|
17081
17235
|
"use strict";
|
|
17082
|
-
|
|
17236
|
+
import_node_crypto22 = require("crypto");
|
|
17083
17237
|
init_devpod_environment();
|
|
17084
17238
|
init_network_capacity();
|
|
17085
17239
|
init_network_claim_lookup();
|
|
@@ -17835,7 +17989,7 @@ async function superviseThroughController(input2) {
|
|
|
17835
17989
|
try {
|
|
17836
17990
|
const bind = () => observeControllerBinding(directory, {
|
|
17837
17991
|
path: input2.repoPath,
|
|
17838
|
-
session: (0,
|
|
17992
|
+
session: (0, import_node_crypto23.randomUUID)(),
|
|
17839
17993
|
profile: input2.profile ?? "full",
|
|
17840
17994
|
// The protocol requires at least one readiness selector, and every
|
|
17841
17995
|
// supervised operation depends on runtime readiness; "runtime" is the
|
|
@@ -17986,11 +18140,11 @@ function bindLifecycleCapacity(request2, binding, directory = import_node_path45
|
|
|
17986
18140
|
stepRecord(record5, { ...request2.fence, type: "admission", result: "admitted" });
|
|
17987
18141
|
});
|
|
17988
18142
|
}
|
|
17989
|
-
var
|
|
18143
|
+
var import_node_crypto23, import_node_path45, import_node_util11, activeWorker, lockHeld, BUSY_LIFECYCLE_WAIT_MS, BUSY_LIFECYCLE_POLL_MS, CAPACITY_CLIENT_WAIT_MS, BUSY_LIFECYCLE_PROGRESS_MS;
|
|
17990
18144
|
var init_reliability_lifecycle = __esm({
|
|
17991
18145
|
"src/core/reliability-lifecycle.ts"() {
|
|
17992
18146
|
"use strict";
|
|
17993
|
-
|
|
18147
|
+
import_node_crypto23 = require("crypto");
|
|
17994
18148
|
import_node_path45 = __toESM(require("path"));
|
|
17995
18149
|
import_node_util11 = require("util");
|
|
17996
18150
|
init_capacity_accounting();
|
|
@@ -18626,7 +18780,7 @@ function createCapacityController(options) {
|
|
|
18626
18780
|
controller,
|
|
18627
18781
|
policyRevision: policy.revision
|
|
18628
18782
|
});
|
|
18629
|
-
const payloadKey = (0,
|
|
18783
|
+
const payloadKey = (0, import_node_crypto24.randomBytes)(32);
|
|
18630
18784
|
const acceptedPayloads = /* @__PURE__ */ new Map();
|
|
18631
18785
|
const settlePreparations = () => {
|
|
18632
18786
|
if (lifetime.signal.aborted) return;
|
|
@@ -18790,7 +18944,7 @@ function createCapacityController(options) {
|
|
|
18790
18944
|
{
|
|
18791
18945
|
...charge,
|
|
18792
18946
|
operationId: prepared.operationId,
|
|
18793
|
-
reservationId: (0,
|
|
18947
|
+
reservationId: (0, import_node_crypto24.randomUUID)(),
|
|
18794
18948
|
policyRevision: target.current.revision
|
|
18795
18949
|
},
|
|
18796
18950
|
{
|
|
@@ -18893,7 +19047,7 @@ function createCapacityController(options) {
|
|
|
18893
19047
|
throw error;
|
|
18894
19048
|
}
|
|
18895
19049
|
}
|
|
18896
|
-
const signature = (0,
|
|
19050
|
+
const signature = (0, import_node_crypto24.createHmac)("sha256", payloadKey).update(
|
|
18897
19051
|
JSON.stringify({
|
|
18898
19052
|
repoPath: identity2.repoPath,
|
|
18899
19053
|
profile: environment.profile,
|
|
@@ -18913,7 +19067,7 @@ function createCapacityController(options) {
|
|
|
18913
19067
|
{
|
|
18914
19068
|
...charge,
|
|
18915
19069
|
operationId: prepared.operationId,
|
|
18916
|
-
reservationId: (0,
|
|
19070
|
+
reservationId: (0, import_node_crypto24.randomUUID)(),
|
|
18917
19071
|
policyRevision: current.revision
|
|
18918
19072
|
},
|
|
18919
19073
|
{ estimates: resolved.estimates, enrollment: resolved.enrollment, pool }
|
|
@@ -19048,7 +19202,7 @@ function createCapacityController(options) {
|
|
|
19048
19202
|
// the budget module then falls back to the conservative wall duration.
|
|
19049
19203
|
activeElapsedMs: null,
|
|
19050
19204
|
profile: environment.profile,
|
|
19051
|
-
incidentId: `incident-${(0,
|
|
19205
|
+
incidentId: `incident-${(0, import_node_crypto24.randomUUID)()}`
|
|
19052
19206
|
});
|
|
19053
19207
|
} catch {
|
|
19054
19208
|
return;
|
|
@@ -19066,7 +19220,7 @@ function createCapacityController(options) {
|
|
|
19066
19220
|
{
|
|
19067
19221
|
...charge,
|
|
19068
19222
|
operationId: prepared.operationId,
|
|
19069
|
-
reservationId: (0,
|
|
19223
|
+
reservationId: (0, import_node_crypto24.randomUUID)(),
|
|
19070
19224
|
policyRevision: current.revision
|
|
19071
19225
|
},
|
|
19072
19226
|
{ estimates: resolved.estimates, enrollment: resolved.enrollment, pool }
|
|
@@ -19086,11 +19240,11 @@ function createCapacityController(options) {
|
|
|
19086
19240
|
}
|
|
19087
19241
|
};
|
|
19088
19242
|
}
|
|
19089
|
-
var
|
|
19243
|
+
var import_node_crypto24, import_node_path46, import_node_util13;
|
|
19090
19244
|
var init_capacity_controller = __esm({
|
|
19091
19245
|
"src/core/capacity-controller.ts"() {
|
|
19092
19246
|
"use strict";
|
|
19093
|
-
|
|
19247
|
+
import_node_crypto24 = require("crypto");
|
|
19094
19248
|
import_node_path46 = __toESM(require("path"));
|
|
19095
19249
|
import_node_util13 = require("util");
|
|
19096
19250
|
init_capacity_accounting();
|
|
@@ -19187,7 +19341,7 @@ printf '%s %s %s\n' "$pid" "$birth" "$fingerprint"
|
|
|
19187
19341
|
|
|
19188
19342
|
// src/core/controller-observation.ts
|
|
19189
19343
|
function digest2(value) {
|
|
19190
|
-
return (0,
|
|
19344
|
+
return (0, import_node_crypto25.createHash)("sha256").update(JSON.stringify(value)).digest("hex");
|
|
19191
19345
|
}
|
|
19192
19346
|
function readRoutes() {
|
|
19193
19347
|
return readHostRouteStateReadOnly((file) => readControllerEvidence(file, 1048576));
|
|
@@ -19271,7 +19425,7 @@ function createControllerObservationCollector(resolve, fingerprint) {
|
|
|
19271
19425
|
() => persisted.contents[3]
|
|
19272
19426
|
);
|
|
19273
19427
|
const source = parseDevcontainerConfig(persisted.contents[4], sourcePath);
|
|
19274
|
-
if (!state || state.devpodId !== environment.providerId || state.profile !== environment.profile || typeof source.service !== "string" || !source.service || (0,
|
|
19428
|
+
if (!state || state.devpodId !== environment.providerId || state.profile !== environment.profile || typeof source.service !== "string" || !source.service || (0, import_node_crypto25.createHash)("sha256").update(persisted.contents[4]).digest("hex") !== state.sourceConfigSha256 || (0, import_node_crypto25.createHash)("sha256").update(persisted.contents[5]).digest("hex") !== state.effectiveConfigSha256)
|
|
19275
19429
|
throw new ControllerObservationBindingChanged("Observation retained configuration changed.");
|
|
19276
19430
|
const identity2 = {
|
|
19277
19431
|
repoPath: environment.repoPath,
|
|
@@ -19446,11 +19600,11 @@ function createControllerObservationCollector(resolve, fingerprint) {
|
|
|
19446
19600
|
};
|
|
19447
19601
|
};
|
|
19448
19602
|
}
|
|
19449
|
-
var
|
|
19603
|
+
var import_node_crypto25, import_node_path47, OBSERVATION_INSPECT_TEMPLATE;
|
|
19450
19604
|
var init_controller_observation = __esm({
|
|
19451
19605
|
"src/core/controller-observation.ts"() {
|
|
19452
19606
|
"use strict";
|
|
19453
|
-
|
|
19607
|
+
import_node_crypto25 = require("crypto");
|
|
19454
19608
|
import_node_path47 = __toESM(require("path"));
|
|
19455
19609
|
init_controller_binding();
|
|
19456
19610
|
init_controller_monitor();
|
|
@@ -19475,11 +19629,11 @@ var init_controller_observation = __esm({
|
|
|
19475
19629
|
});
|
|
19476
19630
|
|
|
19477
19631
|
// src/core/controller-sessions.ts
|
|
19478
|
-
var
|
|
19632
|
+
var import_node_crypto26, import_node_util14, ControllerSessions;
|
|
19479
19633
|
var init_controller_sessions = __esm({
|
|
19480
19634
|
"src/core/controller-sessions.ts"() {
|
|
19481
19635
|
"use strict";
|
|
19482
|
-
|
|
19636
|
+
import_node_crypto26 = require("crypto");
|
|
19483
19637
|
import_node_util14 = require("util");
|
|
19484
19638
|
ControllerSessions = class {
|
|
19485
19639
|
constructor(store) {
|
|
@@ -19651,7 +19805,7 @@ var init_controller_sessions = __esm({
|
|
|
19651
19805
|
const session = {
|
|
19652
19806
|
id: id5,
|
|
19653
19807
|
environmentId: environment.id,
|
|
19654
|
-
generation: (0,
|
|
19808
|
+
generation: (0, import_node_crypto26.randomUUID)(),
|
|
19655
19809
|
requirements: required,
|
|
19656
19810
|
renewedAtMs: wall,
|
|
19657
19811
|
parkingConsent: "protected",
|
|
@@ -19678,7 +19832,7 @@ var init_controller_sessions = __esm({
|
|
|
19678
19832
|
const session = {
|
|
19679
19833
|
id: previous.session,
|
|
19680
19834
|
environmentId: environment.id,
|
|
19681
|
-
generation: (0,
|
|
19835
|
+
generation: (0, import_node_crypto26.randomUUID)(),
|
|
19682
19836
|
requirements: required,
|
|
19683
19837
|
renewedAtMs: wall,
|
|
19684
19838
|
parkingConsent: "protected",
|
|
@@ -21024,7 +21178,7 @@ Run several worktrees of one repo in parallel without host/route collisions. A *
|
|
|
21024
21178
|
- **TLS**: namespaced hosts (\`web.<ws>.localhost\`) are not covered by the \`*.localhost\` wildcard; devrouter auto-extends the mkcert cert SANs for active hosts when TLS is enabled.
|
|
21025
21179
|
- **devcontainer integration**: managed scaffolds list the base compose file, then \`\${localEnv:DEVCONTAINER_COMPOSE_OVERLAY:docker-compose.default.yml}\`; custom repositories may keep another default overlay. Selecting \`.devcontainer/docker-compose.devrouter.yml\` for linked worktrees must pass \`WORKSPACE\` and \`DEVROUTER_WORKSPACE\` across the combined base/overlay config and bind-mount \`\${DEVROUTER_GIT_COMMON_DIR}\` to the same absolute app-container path. The app exposes \`\${WORKSPACE}-app\`; the proxy uses \`upstream: \${WORKSPACE}-app:<port>\`.
|
|
21026
21180
|
- **Lifecycle**: after one-time \`setup\`, use \`ensure .\` for both primary and linked checkouts; never branch manually on checkout kind or use live verify as startup. \`stop .\` is non-destructive; \`stop . --delete\` is explicit exact-owner cleanup without worktree removal; and \`exec . -- <command...>\` runs one-shot commands only in the exact running workspace runtime (DevPod or Devsy). Never substitute raw \`devpod up\`, \`stop\`, \`delete\`, or the Devsy equivalents: they bypass devrouter's machine-global ownership lock, which serializes provider mutations in a fair arrival-order queue and lets contenders wait up to thirty minutes with throttled stderr progress before failing with the queue position or holder PID and true durations. Runtime selection is path-aware: \`DEVROUTER_WORKSPACE_RUNTIME=devpod|devsy\` forces one runtime, an exact-path registry owner wins next, then the machine preference from \`devrouter setup --workspace-runtime\`, then installed-CLI auto-detection. \`workspace up\` creates linked worktrees; destructive worktree removal and GC remain ledger-scoped. Dirty or locked full down fails before side effects. For Devsy, run \`devrouter setup --yes --workspace-runtime devsy\` once per installed Devsy release, rerunning it after a Devsy update, so Devrouter acquires and verifies the official Linux agent in its own machine cache. Devrouter supports Devsy releases in the range >=1.16.2 <2.0.0 and refuses a release whose published asset has no SHA-256 digest. \`doctor\` reports \`ready\`, \`missing\`, \`stale\`, or \`invalid\` without network access, and \`ensure\` fails before the provider queue when readiness is not \`ready\`. An explicit \`DEVSY_AGENT_BINARY\` remains authoritative and must match the official asset for the installed release.
|
|
21027
|
-
- **Interrupted lifecycle**: ensure reconciles an interrupted or never-dispatched ensure after positive worker drainage and automatically repairs retained degraded runtimes. Unknown arbitrary exec is never replayed; explicit stop reconciles that uncertainty. Preserve journals and retained configuration when evidence is unavailable. This does not provide OOM prevention or capacity-managed automatic recovery.
|
|
21181
|
+
- **Interrupted lifecycle**: ensure reconciles an interrupted or never-dispatched ensure after positive worker drainage and automatically repairs retained degraded runtimes. Unknown arbitrary exec is never replayed; explicit stop reconciles that uncertainty. A start refused before any provider mutation \u2014 a fixed published host port already held by a running container \u2014 stays visible in \`status\` as a \`start-refused\` attention reason naming the read-only \`doctor\` check and the consumer-side fix; an explicit \`stop\` releases the intent and the reason, and a later admitted ensure clears it. Preserve journals and retained configuration when evidence is unavailable. This does not provide OOM prevention or capacity-managed automatic recovery.
|
|
21028
21182
|
- **Managed process identity**: \`ensure\` executes an exact captured adapter snapshot. Default reuse includes command argv, workspace, and adapter SHA-256. Set \`DEVROUTER_PROCESS_FINGERPRINT_ENV\` only to comma-separated non-secret environment names whose values affect runtime identity; secret-like names are rejected and raw values are never persisted.
|
|
21029
21183
|
- **Route state**: the versioned Traefik dynamic file is authoritative for both metadata and rendering. JSON is a compatibility mirror; valid headerless generations migrate automatically, while corrupt canonical metadata fails closed.
|
|
21030
21184
|
- **Cleanup**: \`workspace cleanup --repo . --inactive-for 30d --json\` is a report-only, no-\`--yes\` report for managed linked workspaces. It joins ownership (\`present|missing|locked|conflict\`), workspace runtime registration, runtime state (\`running|stopped|busy|not-found|absent|unknown\`), checkout, route, advisory activity, and integration evidence without mutating the workspace runtime, routes, ownership, Git, Docker, applications, worktrees, or branches. Local DevPod/Devsy list/status checks always run; \`--check-merged\` alone enables read-only origin and matching GitHub/GitLab checks. Treat \`not-found\` as stale runtime after Docker pruning; busy, unavailable, or conflicting evidence suppresses destructive suggestions. Explicit \`gc\`/\`down\` can remove exact stale registration only after expected-ID \`NotFound\` proof and ownership revalidation. GC never removes Git worktrees, branches, or prune state. Git has no worktree-removal hook.
|
|
@@ -21122,26 +21276,30 @@ checkout's environment is mid-transition. Wire \`devrouter harness gate\` as a
|
|
|
21122
21276
|
{
|
|
21123
21277
|
"hooks": {
|
|
21124
21278
|
"PreToolUse": [
|
|
21125
|
-
{ "matcher": "
|
|
21279
|
+
{ "matcher": ".*", "hooks": [
|
|
21126
21280
|
{ "type": "command", "command": "devrouter harness gate", "timeout": 90 }
|
|
21127
21281
|
] }
|
|
21128
21282
|
]
|
|
21129
21283
|
}
|
|
21130
21284
|
}
|
|
21131
21285
|
|
|
21132
|
-
The Codex CLI reads the same hook from \`$CODEX_HOME/hooks.json
|
|
21133
|
-
tool is named \`exec_command\`:
|
|
21286
|
+
The Codex CLI reads the same hook from \`$CODEX_HOME/hooks.json\`:
|
|
21134
21287
|
|
|
21135
21288
|
{
|
|
21136
21289
|
"hooks": {
|
|
21137
21290
|
"PreToolUse": [
|
|
21138
|
-
{ "matcher": "
|
|
21291
|
+
{ "matcher": ".*", "hooks": [
|
|
21139
21292
|
{ "type": "command", "command": "devrouter harness gate", "timeout": 180 }
|
|
21140
21293
|
] }
|
|
21141
21294
|
]
|
|
21142
21295
|
}
|
|
21143
21296
|
}
|
|
21144
21297
|
|
|
21298
|
+
\`.*\` matches every tool, including the shell, file-editing and MCP tools a model
|
|
21299
|
+
can point at the environment. The gate answers a settled checkout immediately, so
|
|
21300
|
+
the price is one short-lived process per gated call; narrow the matcher when that
|
|
21301
|
+
price matters more than covering every tool.
|
|
21302
|
+
|
|
21145
21303
|
The gate identifies the requesting harness from its payload and answers in that
|
|
21146
21304
|
harness's accepted shape: a refusal is a \`deny\` in both, while an allowed call is
|
|
21147
21305
|
\`permissionDecision: allow\` for Claude Code and Codex receives a bare completion
|
|
@@ -21299,7 +21457,7 @@ function buildOnboardingPrompt(options = {}) {
|
|
|
21299
21457
|
"- if kind=app and runtime=proxy:",
|
|
21300
21458
|
" - HTTP-only optional readiness: { path: /api/health, statuses: [200], contentType: application/json }; statuses default to [200], explicit lists allow unique 2xx/4xx codes, never redirects. Paths stay on the configured host with no query, fragment, percent escapes, backslash or dot segments. Media types match their case-insensitive base type.",
|
|
21301
21459
|
" - Declared application readiness failures return applicationReadiness.status=application-error and a nonzero ensure exit, while retaining tooling and routes for application fixes; do not reset caches or recreate the provider. Absent readiness means legacy route liveness, not full application readiness.",
|
|
21302
|
-
" - A configured FIXED published host binding already held by a running container refuses managed ensure before any provider start (hostPortConflicts in --json, nonzero exit) naming the port, holder container, compose project, and owning workspace when attributable. Ephemeral host::container bindings are exempt. Never rewrite consumer ports to resolve a conflict: stop the holding workspace or use the consumer's own override, then ensure again. Unverifiable evidence also refuses.",
|
|
21460
|
+
" - A configured FIXED published host binding already held by a running container refuses managed ensure before any provider start (hostPortConflicts in --json, nonzero exit) naming the port, holder container, compose project, and owning workspace when attributable. Ephemeral host::container bindings are exempt. Never rewrite consumer ports to resolve a conflict: stop the holding workspace or use the consumer's own override, then ensure again. The refused start stays visible in `devrouter status` as a `start-refused` attention reason that names the read-only `doctor` check and the consumer-side fix; an explicit `stop` releases the intent and the reason, and a later admitted ensure clears it. Unverifiable evidence also refuses.",
|
|
21303
21461
|
' - upstream: "host:port" (an already-running port, e.g. a devcontainer published on 127.0.0.1:3000, or a container reachable by name on a shared Docker network such as `derivatives-db:5432`)',
|
|
21304
21462
|
` - upstream may use the \`${WORKSPACE_PLACEHOLDER}\` placeholder (e.g. \`${WORKSPACE_PLACEHOLDER}-app:3000\`) to target a per-workspace devcontainer alias; it is substituted with the resolved workspace token at runtime and re-validated. Do NOT put \`${WORKSPACE_PLACEHOLDER}\` in \`host\` (rejected) \u2014 the host is auto-namespaced.`,
|
|
21305
21463
|
" - managed `devrouter ensure` requires every HTTP/TCP proxy upstream to begin with the exact resolved workspace/project alias prefix before it mutates DevPod or routes",
|
|
@@ -23193,7 +23351,7 @@ function probeInstalledCliVersion(executable) {
|
|
|
23193
23351
|
}
|
|
23194
23352
|
function buildCliPathCheck(options = {}) {
|
|
23195
23353
|
const id5 = "global.cli-path";
|
|
23196
|
-
const runningVersion = options.runningVersion ?? (true ? "0.1.
|
|
23354
|
+
const runningVersion = options.runningVersion ?? (true ? "0.1.2" : "0.0.0-dev");
|
|
23197
23355
|
if (runningVersion === "0.0.0-dev") {
|
|
23198
23356
|
return {
|
|
23199
23357
|
id: id5,
|
|
@@ -23859,6 +24017,17 @@ function collectNextSteps(checks, statusNextSteps) {
|
|
|
23859
24017
|
}
|
|
23860
24018
|
return Array.from(steps.values());
|
|
23861
24019
|
}
|
|
24020
|
+
function capacityHistoryDetails(error) {
|
|
24021
|
+
if (!(error instanceof CapacityHistoryError)) return "capacity-history-unprovable";
|
|
24022
|
+
const parts = [error.code];
|
|
24023
|
+
if (error.cause) parts.push(error.cause);
|
|
24024
|
+
if (error.location) parts.push(`at ${error.location}`);
|
|
24025
|
+
return parts.join("; ");
|
|
24026
|
+
}
|
|
24027
|
+
function capacityHistorySuggestion(error) {
|
|
24028
|
+
const cause = error instanceof CapacityHistoryError ? error.cause : null;
|
|
24029
|
+
return (cause ? CAPACITY_RECOVERY_BY_CAUSE[cause] : void 0) ?? "Preserve ledger and lifecycle records; restore verified history before retrying admission.";
|
|
24030
|
+
}
|
|
23862
24031
|
async function buildDoctorReport(options = {}) {
|
|
23863
24032
|
const checks = [];
|
|
23864
24033
|
const fileLayout = getRouterFileLayout();
|
|
@@ -23904,8 +24073,8 @@ async function buildDoctorReport(options = {}) {
|
|
|
23904
24073
|
id: "global.capacity-ledger",
|
|
23905
24074
|
level: "error",
|
|
23906
24075
|
summary: "Capacity ledger history is unavailable for safe admission.",
|
|
23907
|
-
details: error
|
|
23908
|
-
suggestion: absent ? "Preserve ledger and lifecycle records; with every enrolled environment stopped, run: devrouter capacity reconcile --yes" :
|
|
24076
|
+
details: capacityHistoryDetails(error),
|
|
24077
|
+
suggestion: absent ? "Preserve ledger and lifecycle records; with every enrolled environment stopped, run: devrouter capacity reconcile --yes" : capacityHistorySuggestion(error)
|
|
23909
24078
|
});
|
|
23910
24079
|
}
|
|
23911
24080
|
let statusNextSteps = [];
|
|
@@ -24041,7 +24210,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
24041
24210
|
suggestion: `Remedy ${expansionNotice.remedy.code}: set a named default profile other than '${expansionNotice.profile}'${remedyCandidates}.`
|
|
24042
24211
|
});
|
|
24043
24212
|
}
|
|
24044
|
-
const cliVersion = true ? "0.1.
|
|
24213
|
+
const cliVersion = true ? "0.1.2" : "0.0.0-dev";
|
|
24045
24214
|
const configVersion = config.devrouter?.version;
|
|
24046
24215
|
const installedKnown = cliVersion !== "0.0.0-dev";
|
|
24047
24216
|
const versionComparison = installedKnown && configVersion ? compareSemver(configVersion, cliVersion) : void 0;
|
|
@@ -24267,7 +24436,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
24267
24436
|
nextSteps
|
|
24268
24437
|
};
|
|
24269
24438
|
}
|
|
24270
|
-
var import_node_fs44, import_node_path56, import_yaml6, POSTGRES_DEFAULTS;
|
|
24439
|
+
var import_node_fs44, import_node_path56, import_yaml6, POSTGRES_DEFAULTS, CAPACITY_RECOVERY_BY_CAUSE;
|
|
24271
24440
|
var init_doctor = __esm({
|
|
24272
24441
|
"src/core/doctor.ts"() {
|
|
24273
24442
|
"use strict";
|
|
@@ -24296,6 +24465,14 @@ var init_doctor = __esm({
|
|
|
24296
24465
|
POSTGRES_PASSWORD: "prisma",
|
|
24297
24466
|
POSTGRES_DB: "prisma"
|
|
24298
24467
|
};
|
|
24468
|
+
CAPACITY_RECOVERY_BY_CAUSE = {
|
|
24469
|
+
"journal-entry-unsupported": "Move the named unrecognised entry out of the private reliability journal directory, preserving its contents; it blocks every capacity read while it stays there.",
|
|
24470
|
+
"journal-directory-unsafe": "Restore private ownership and mode 0700 on the reliability journal directory, then retry.",
|
|
24471
|
+
"journal-directory-unreadable": "Restore read access to the reliability journal directory, then retry.",
|
|
24472
|
+
"journal-invalid": "Preserve the named journal entry and restore verified history before retrying admission.",
|
|
24473
|
+
"journal-unreadable": "Preserve the named journal entry and restore verified history before retrying admission.",
|
|
24474
|
+
"journal-entry-unsafe": "Restore private ownership, mode 0600 and a bounded size on the named journal entry, then retry."
|
|
24475
|
+
};
|
|
24299
24476
|
}
|
|
24300
24477
|
});
|
|
24301
24478
|
|
|
@@ -24904,7 +25081,7 @@ var init_status2 = __esm({
|
|
|
24904
25081
|
|
|
24905
25082
|
// src/core/harness-continuation.ts
|
|
24906
25083
|
function harnessContinuationPath(repoRoot) {
|
|
24907
|
-
const key = (0,
|
|
25084
|
+
const key = (0, import_node_crypto27.createHash)("sha256").update(comparableWorkspacePath(repoRoot)).digest("hex");
|
|
24908
25085
|
return import_node_path57.default.join(DEVROUTER_HOME, "harness", `${key}.json`);
|
|
24909
25086
|
}
|
|
24910
25087
|
function counter4(value) {
|
|
@@ -25002,11 +25179,11 @@ function settleHarnessContinuation(repoRoot, toolUseId, settlement) {
|
|
|
25002
25179
|
} catch {
|
|
25003
25180
|
}
|
|
25004
25181
|
}
|
|
25005
|
-
var
|
|
25182
|
+
var import_node_crypto27, import_node_fs45, import_node_path57, HARNESS_CONTINUATION_MAX_ENTRIES, HARNESS_CONTINUATION_TTL_MS, HARNESS_CONTINUATION_LOCK_WAIT_MS, MAX_LEDGER_BYTES, MAX_TOOL_USE_ID_LENGTH, MAX_PHASE_LENGTH;
|
|
25006
25183
|
var init_harness_continuation = __esm({
|
|
25007
25184
|
"src/core/harness-continuation.ts"() {
|
|
25008
25185
|
"use strict";
|
|
25009
|
-
|
|
25186
|
+
import_node_crypto27 = require("crypto");
|
|
25010
25187
|
import_node_fs45 = __toESM(require("fs"));
|
|
25011
25188
|
import_node_path57 = __toESM(require("path"));
|
|
25012
25189
|
init_atomic_file();
|
|
@@ -25073,17 +25250,20 @@ async function waitForHarnessGate(options) {
|
|
|
25073
25250
|
options.onObservation?.(observation, now() - started);
|
|
25074
25251
|
if (!isTransitionalHarnessPhase(observation.phase)) {
|
|
25075
25252
|
const waitedMs2 = now() - started;
|
|
25253
|
+
let reason = deferred ? "settled-after-wait" : "settled";
|
|
25254
|
+
if (observation.phase === "unknown") reason = "evidence-unavailable";
|
|
25076
25255
|
return {
|
|
25077
25256
|
version: 1,
|
|
25078
25257
|
decision: deferred ? "deferred-allow" : "allow",
|
|
25079
|
-
reason
|
|
25258
|
+
reason,
|
|
25080
25259
|
waitedMs: waitedMs2,
|
|
25081
25260
|
observations,
|
|
25082
25261
|
observedPhase: observation.phase
|
|
25083
25262
|
};
|
|
25084
25263
|
}
|
|
25085
25264
|
const waitedMs = now() - started;
|
|
25086
|
-
|
|
25265
|
+
const remainingMs = budget - waitedMs;
|
|
25266
|
+
if (remainingMs <= 0) {
|
|
25087
25267
|
return {
|
|
25088
25268
|
version: 1,
|
|
25089
25269
|
decision: "refuse",
|
|
@@ -25108,7 +25288,7 @@ async function waitForHarnessGate(options) {
|
|
|
25108
25288
|
}
|
|
25109
25289
|
}
|
|
25110
25290
|
deferred = true;
|
|
25111
|
-
await sleep3(Math.min(interval,
|
|
25291
|
+
await sleep3(Math.min(interval, remainingMs));
|
|
25112
25292
|
}
|
|
25113
25293
|
}
|
|
25114
25294
|
function parseHarnessGateBudget(value) {
|
|
@@ -25150,6 +25330,91 @@ __export(harness_exports, {
|
|
|
25150
25330
|
detectHarnessHook: () => detectHarnessHook,
|
|
25151
25331
|
runHarnessCommand: () => runHarnessCommand
|
|
25152
25332
|
});
|
|
25333
|
+
function commandSegments(command) {
|
|
25334
|
+
const segments = [];
|
|
25335
|
+
let current = "";
|
|
25336
|
+
let quote;
|
|
25337
|
+
for (const char of command) {
|
|
25338
|
+
if (quote) {
|
|
25339
|
+
current += char;
|
|
25340
|
+
if (char === quote) quote = void 0;
|
|
25341
|
+
continue;
|
|
25342
|
+
}
|
|
25343
|
+
if (char === "'" || char === '"') {
|
|
25344
|
+
quote = char;
|
|
25345
|
+
current += char;
|
|
25346
|
+
continue;
|
|
25347
|
+
}
|
|
25348
|
+
if (char === ";" || char === "\n" || char === "&" || char === "|" || char === "(" || char === ")") {
|
|
25349
|
+
segments.push(current);
|
|
25350
|
+
current = "";
|
|
25351
|
+
continue;
|
|
25352
|
+
}
|
|
25353
|
+
current += char;
|
|
25354
|
+
}
|
|
25355
|
+
segments.push(current);
|
|
25356
|
+
return segments;
|
|
25357
|
+
}
|
|
25358
|
+
function segmentWords(segment, limit) {
|
|
25359
|
+
const words = [];
|
|
25360
|
+
let current = "";
|
|
25361
|
+
let quote;
|
|
25362
|
+
const flush = () => {
|
|
25363
|
+
if (current) words.push(current);
|
|
25364
|
+
current = "";
|
|
25365
|
+
};
|
|
25366
|
+
for (const char of segment) {
|
|
25367
|
+
if (quote) {
|
|
25368
|
+
if (char === quote) {
|
|
25369
|
+
quote = void 0;
|
|
25370
|
+
continue;
|
|
25371
|
+
}
|
|
25372
|
+
current += char;
|
|
25373
|
+
continue;
|
|
25374
|
+
}
|
|
25375
|
+
if (char === "'" || char === '"') {
|
|
25376
|
+
quote = char;
|
|
25377
|
+
continue;
|
|
25378
|
+
}
|
|
25379
|
+
if (char === " " || char === " ") {
|
|
25380
|
+
flush();
|
|
25381
|
+
if (words.length >= limit) return words;
|
|
25382
|
+
continue;
|
|
25383
|
+
}
|
|
25384
|
+
current += char;
|
|
25385
|
+
}
|
|
25386
|
+
flush();
|
|
25387
|
+
return words;
|
|
25388
|
+
}
|
|
25389
|
+
function executableName(word) {
|
|
25390
|
+
return word.slice(word.lastIndexOf("/") + 1);
|
|
25391
|
+
}
|
|
25392
|
+
function commandWord(segment) {
|
|
25393
|
+
const words = segmentWords(segment, COMMAND_WORD_LIMIT);
|
|
25394
|
+
let index = 0;
|
|
25395
|
+
for (; ; ) {
|
|
25396
|
+
const word = words[index];
|
|
25397
|
+
if (word === void 0) return void 0;
|
|
25398
|
+
if (word === "env" || /^[A-Za-z_][A-Za-z0-9_]*=/u.test(word)) {
|
|
25399
|
+
index += 1;
|
|
25400
|
+
continue;
|
|
25401
|
+
}
|
|
25402
|
+
break;
|
|
25403
|
+
}
|
|
25404
|
+
const launcher = words[index];
|
|
25405
|
+
if (launcher !== void 0 && LAUNCHER_WORDS.has(executableName(launcher))) {
|
|
25406
|
+
index += 1;
|
|
25407
|
+
const subcommand = words[index];
|
|
25408
|
+
if (subcommand !== void 0 && LAUNCHER_SUBCOMMANDS.has(subcommand)) index += 1;
|
|
25409
|
+
}
|
|
25410
|
+
return words[index];
|
|
25411
|
+
}
|
|
25412
|
+
function isDevrouterLifecycleCommand(command) {
|
|
25413
|
+
return commandSegments(command).some((segment) => {
|
|
25414
|
+
const word = commandWord(segment);
|
|
25415
|
+
return word !== void 0 && DEVROUTER_EXECUTABLES.has(executableName(word));
|
|
25416
|
+
});
|
|
25417
|
+
}
|
|
25153
25418
|
function detectHarnessHook(payload) {
|
|
25154
25419
|
const turnId = payload.turn_id;
|
|
25155
25420
|
return typeof turnId === "string" && turnId.length > 0 ? "codex" : "claude";
|
|
@@ -25196,11 +25461,19 @@ function permitReason(decision) {
|
|
|
25196
25461
|
}
|
|
25197
25462
|
return `devrouter: this tool call's wait was cancelled${age}; the harness may have run it. Verify whether it ran before issuing a new call.`;
|
|
25198
25463
|
}
|
|
25199
|
-
switch (decision.
|
|
25200
|
-
case "
|
|
25464
|
+
switch (decision.reason) {
|
|
25465
|
+
case "budget-exhausted":
|
|
25201
25466
|
return `devrouter: the managed environment is still ${decision.observedPhase} after waiting ${seconds}s. Do not retry automatically; run 'devrouter status .' and continue once it settles.`;
|
|
25202
|
-
case "
|
|
25467
|
+
case "settled-after-wait":
|
|
25203
25468
|
return `devrouter: environment settled after ${seconds}s; the tool may run now.`;
|
|
25469
|
+
case "devrouter-command":
|
|
25470
|
+
return "devrouter: lifecycle command; the gate left it to the lifecycle engine and did not observe the environment.";
|
|
25471
|
+
case "unmanaged-checkout":
|
|
25472
|
+
return "devrouter: no managed checkout was found for this call; the gate did not observe environment state.";
|
|
25473
|
+
case "hook-payload-invalid":
|
|
25474
|
+
return "devrouter: the hook payload was unreadable; the gate did not observe environment state.";
|
|
25475
|
+
case "evidence-unavailable":
|
|
25476
|
+
return "devrouter: lifecycle evidence was unavailable; the gate observed no settled phase and the tool proceeds.";
|
|
25204
25477
|
default:
|
|
25205
25478
|
return "devrouter: environment settled.";
|
|
25206
25479
|
}
|
|
@@ -25268,10 +25541,9 @@ async function runHarnessCommand(method, options, repoPath, dependencies = {}) {
|
|
|
25268
25541
|
return;
|
|
25269
25542
|
}
|
|
25270
25543
|
kind = detectHarnessHook(payload);
|
|
25271
|
-
const toolName = typeof payload.tool_name === "string" ? payload.tool_name : "";
|
|
25272
25544
|
const toolInput = isRecord7(payload.tool_input) ? payload.tool_input : {};
|
|
25273
|
-
const command = typeof toolInput.command === "string" ? toolInput.command : "";
|
|
25274
|
-
if (
|
|
25545
|
+
const command = typeof toolInput.command === "string" ? toolInput.command : typeof toolInput.cmd === "string" ? toolInput.cmd : "";
|
|
25546
|
+
if (isDevrouterLifecycleCommand(command)) {
|
|
25275
25547
|
const decision2 = gateDecision("allow", "devrouter-command");
|
|
25276
25548
|
process.stdout.write(
|
|
25277
25549
|
json ? `${JSON.stringify(decision2)}
|
|
@@ -25293,7 +25565,7 @@ async function runHarnessCommand(method, options, repoPath, dependencies = {}) {
|
|
|
25293
25565
|
}
|
|
25294
25566
|
const budgetMs = parseHarnessGateBudget(options.waitBudgetMs);
|
|
25295
25567
|
const toolUseId = typeof payload.tool_use_id === "string" && payload.tool_use_id.length > 0 && payload.tool_use_id.length <= MAX_TOOL_USE_ID_LENGTH2 ? payload.tool_use_id : void 0;
|
|
25296
|
-
const payloadSha256 = (0,
|
|
25568
|
+
const payloadSha256 = (0, import_node_crypto28.createHash)("sha256").update(JSON.stringify(toolInput)).digest("hex");
|
|
25297
25569
|
const claim2 = dependencies.claim ?? ((root, input2) => {
|
|
25298
25570
|
const outcome = claimHarnessContinuation(root, input2);
|
|
25299
25571
|
if (outcome.kind === "claimed") {
|
|
@@ -25401,17 +25673,20 @@ async function runHarnessCommand(method, options, repoPath, dependencies = {}) {
|
|
|
25401
25673
|
`
|
|
25402
25674
|
);
|
|
25403
25675
|
}
|
|
25404
|
-
var
|
|
25676
|
+
var import_node_crypto28, MAX_HOOK_PAYLOAD_BYTES, STDIN_TIMEOUT_MS, MAX_TOOL_USE_ID_LENGTH2, DEVROUTER_EXECUTABLES, LAUNCHER_WORDS, LAUNCHER_SUBCOMMANDS, COMMAND_WORD_LIMIT;
|
|
25405
25677
|
var init_harness = __esm({
|
|
25406
25678
|
"src/commands/harness.ts"() {
|
|
25407
25679
|
"use strict";
|
|
25408
|
-
|
|
25680
|
+
import_node_crypto28 = require("crypto");
|
|
25409
25681
|
init_harness_continuation();
|
|
25410
25682
|
init_harness_gate();
|
|
25411
25683
|
MAX_HOOK_PAYLOAD_BYTES = 256 * 1024;
|
|
25412
25684
|
STDIN_TIMEOUT_MS = 5e3;
|
|
25413
25685
|
MAX_TOOL_USE_ID_LENGTH2 = 256;
|
|
25414
|
-
|
|
25686
|
+
DEVROUTER_EXECUTABLES = /* @__PURE__ */ new Set(["devrouter", "devrouter-process"]);
|
|
25687
|
+
LAUNCHER_WORDS = /* @__PURE__ */ new Set(["npx", "pnpm", "npm", "yarn"]);
|
|
25688
|
+
LAUNCHER_SUBCOMMANDS = /* @__PURE__ */ new Set(["exec", "dlx"]);
|
|
25689
|
+
COMMAND_WORD_LIMIT = 8;
|
|
25415
25690
|
}
|
|
25416
25691
|
});
|
|
25417
25692
|
|
|
@@ -27526,7 +27801,7 @@ function sanitizeRouterId(value) {
|
|
|
27526
27801
|
return value.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
27527
27802
|
}
|
|
27528
27803
|
function repoHash(repoPath) {
|
|
27529
|
-
return (0,
|
|
27804
|
+
return (0, import_node_crypto29.createHash)("sha1").update(import_node_path64.default.resolve(repoPath)).digest("hex").slice(0, 12);
|
|
27530
27805
|
}
|
|
27531
27806
|
function asDockerApp(app) {
|
|
27532
27807
|
return app.runtime === "docker";
|
|
@@ -27729,12 +28004,12 @@ function queryMappedPort(repoPath, composeFiles2, overlayPath, service, internal
|
|
|
27729
28004
|
const port = Number(match[1]);
|
|
27730
28005
|
return Number.isInteger(port) && port > 0 ? port : void 0;
|
|
27731
28006
|
}
|
|
27732
|
-
var import_node_child_process33,
|
|
28007
|
+
var import_node_child_process33, import_node_crypto29, import_node_fs51, import_node_path64, import_yaml9;
|
|
27733
28008
|
var init_docker_run = __esm({
|
|
27734
28009
|
"src/core/docker-run.ts"() {
|
|
27735
28010
|
"use strict";
|
|
27736
28011
|
import_node_child_process33 = require("child_process");
|
|
27737
|
-
|
|
28012
|
+
import_node_crypto29 = require("crypto");
|
|
27738
28013
|
import_node_fs51 = __toESM(require("fs"));
|
|
27739
28014
|
import_node_path64 = __toESM(require("path"));
|
|
27740
28015
|
import_yaml9 = __toESM(require("yaml"));
|
|
@@ -30021,7 +30296,7 @@ var init_version = __esm({
|
|
|
30021
30296
|
|
|
30022
30297
|
// src/cli.ts
|
|
30023
30298
|
var import_commander = require("commander");
|
|
30024
|
-
var CLI_VERSION = true ? "0.1.
|
|
30299
|
+
var CLI_VERSION = true ? "0.1.2" : "0.0.0-dev";
|
|
30025
30300
|
var VERSION_FLAGS = /* @__PURE__ */ new Set(["-V", "--version"]);
|
|
30026
30301
|
function withErrorHandling(action2) {
|
|
30027
30302
|
return async (...args) => {
|