@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
|
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
|
|
25
25
|
// src/core/devpod-exec.ts
|
|
26
26
|
var import_node_child_process29 = require("child_process");
|
|
27
|
-
var
|
|
27
|
+
var import_node_crypto23 = require("crypto");
|
|
28
28
|
|
|
29
29
|
// src/core/devpod-environment.ts
|
|
30
30
|
var import_node_child_process3 = require("child_process");
|
|
@@ -4327,12 +4327,13 @@ function reliabilityFence(state) {
|
|
|
4327
4327
|
}
|
|
4328
4328
|
|
|
4329
4329
|
// src/core/reliability-operation-store.ts
|
|
4330
|
-
var
|
|
4330
|
+
var import_node_crypto9 = require("crypto");
|
|
4331
4331
|
var import_node_fs17 = __toESM(require("fs"));
|
|
4332
4332
|
var import_node_path21 = __toESM(require("path"));
|
|
4333
4333
|
var import_node_util4 = require("util");
|
|
4334
4334
|
|
|
4335
4335
|
// src/core/capacity-store.ts
|
|
4336
|
+
var import_node_crypto7 = require("crypto");
|
|
4336
4337
|
var import_node_fs15 = __toESM(require("fs"));
|
|
4337
4338
|
var import_node_path19 = __toESM(require("path"));
|
|
4338
4339
|
|
|
@@ -4393,11 +4394,13 @@ function evaluateCapacity(budgets, samples, charges, requested, nowMs, maxSample
|
|
|
4393
4394
|
// src/core/capacity-store.ts
|
|
4394
4395
|
var MAX_BYTES = 1048576;
|
|
4395
4396
|
var CapacityHistoryError = class extends Error {
|
|
4396
|
-
constructor(code) {
|
|
4397
|
+
constructor(code, cause = null, location = null) {
|
|
4397
4398
|
super(
|
|
4398
4399
|
code === "capacity-ledger-lost" ? "Capacity ledger history is lost; restore verified capacity-reservations.json." : "Capacity history cannot be proven; inspect the private lifecycle journals."
|
|
4399
4400
|
);
|
|
4400
4401
|
this.code = code;
|
|
4402
|
+
this.cause = cause;
|
|
4403
|
+
this.location = location;
|
|
4401
4404
|
this.name = "CapacityHistoryError";
|
|
4402
4405
|
}
|
|
4403
4406
|
};
|
|
@@ -4554,9 +4557,10 @@ var CapacityStore = class {
|
|
|
4554
4557
|
const buffer = Buffer.alloc(MAX_BYTES + 1);
|
|
4555
4558
|
const count = import_node_fs15.default.readSync(descriptor, buffer, 0, buffer.length, 0);
|
|
4556
4559
|
if (count > MAX_BYTES) throw new Error("Capacity reservation snapshot exceeds byte limit.");
|
|
4557
|
-
const
|
|
4560
|
+
const bytes2 = buffer.subarray(0, count);
|
|
4561
|
+
const value = JSON.parse(bytes2.toString("utf8"));
|
|
4558
4562
|
validate(value);
|
|
4559
|
-
this.ledgerGeneration =
|
|
4563
|
+
this.ledgerGeneration = this.generationIdentity(stat, bytes2);
|
|
4560
4564
|
if (value.revision < minimumRevision) return { kind: "stale", revision: value.revision };
|
|
4561
4565
|
this.observedLedger = true;
|
|
4562
4566
|
return { kind: "intact", revision: value.revision, snapshot: value };
|
|
@@ -4609,20 +4613,30 @@ var CapacityStore = class {
|
|
|
4609
4613
|
return snapshot;
|
|
4610
4614
|
}
|
|
4611
4615
|
commit(snapshot) {
|
|
4612
|
-
|
|
4616
|
+
const contents = serializeSnapshot(snapshot);
|
|
4617
|
+
this.write(this.file, contents);
|
|
4613
4618
|
this.observedLedger = true;
|
|
4614
|
-
this.rememberGeneration();
|
|
4619
|
+
this.rememberGeneration(contents);
|
|
4615
4620
|
this.establish();
|
|
4616
4621
|
}
|
|
4617
4622
|
/** Remember the published snapshot identity for the next generation fence. */
|
|
4618
|
-
rememberGeneration() {
|
|
4623
|
+
rememberGeneration(contents) {
|
|
4619
4624
|
try {
|
|
4620
4625
|
const stat = import_node_fs15.default.statSync(this.file);
|
|
4621
|
-
this.ledgerGeneration = stat.isFile() ?
|
|
4626
|
+
this.ledgerGeneration = stat.isFile() ? this.generationIdentity(stat, contents) : void 0;
|
|
4622
4627
|
} catch {
|
|
4623
4628
|
this.ledgerGeneration = void 0;
|
|
4624
4629
|
}
|
|
4625
4630
|
}
|
|
4631
|
+
/**
|
|
4632
|
+
* File identity plus content digest. Deleting and recreating the snapshot can
|
|
4633
|
+
* reuse its inode number, so the inode alone cannot fence a replacement that
|
|
4634
|
+
* reuses a revision number.
|
|
4635
|
+
*/
|
|
4636
|
+
generationIdentity(stat, contents) {
|
|
4637
|
+
const digest = (0, import_node_crypto7.createHash)("sha256").update(contents).digest("hex");
|
|
4638
|
+
return `${stat.dev}:${stat.ino}:${digest}`;
|
|
4639
|
+
}
|
|
4626
4640
|
/**
|
|
4627
4641
|
* Durable evidence that recorded history is gone, for a stop whose physical
|
|
4628
4642
|
* cessation is already proven. The caller holds that proof; this writes no
|
|
@@ -4871,7 +4885,7 @@ var CapacityStore = class {
|
|
|
4871
4885
|
};
|
|
4872
4886
|
|
|
4873
4887
|
// src/core/controller-store.ts
|
|
4874
|
-
var
|
|
4888
|
+
var import_node_crypto8 = require("crypto");
|
|
4875
4889
|
var import_node_fs16 = __toESM(require("fs"));
|
|
4876
4890
|
var import_node_path20 = __toESM(require("path"));
|
|
4877
4891
|
var CONTROLLER_SNAPSHOT_BYTES = 1048576;
|
|
@@ -5173,7 +5187,7 @@ var ControllerStore = class {
|
|
|
5173
5187
|
provenance(identity2) {
|
|
5174
5188
|
if (identity2.version !== 2) throw new Error("Controller binding provenance is unavailable.");
|
|
5175
5189
|
return {
|
|
5176
|
-
digest: (0,
|
|
5190
|
+
digest: (0, import_node_crypto8.createHash)("sha256").update(JSON.stringify(["devrouter-controller-binding-v1", identity2.store, identity2.key])).digest("hex"),
|
|
5177
5191
|
enrolledEpoch: identity2.enrolledEpoch
|
|
5178
5192
|
};
|
|
5179
5193
|
}
|
|
@@ -5197,7 +5211,7 @@ var ControllerStore = class {
|
|
|
5197
5211
|
if (!current || current.store !== captured.store || current.epoch !== captured.epoch || JSON.stringify(current.fingerprint) !== JSON.stringify(captured.fingerprint) || identity2?.version !== 2)
|
|
5198
5212
|
throw new Error("Controller binding incarnation changed.");
|
|
5199
5213
|
this.checkProvenance(current, identity2);
|
|
5200
|
-
return (0,
|
|
5214
|
+
return (0, import_node_crypto8.createHmac)("sha256", Buffer.from(identity2.key, "hex")).update(JSON.stringify({ owner, config })).digest("hex");
|
|
5201
5215
|
};
|
|
5202
5216
|
}
|
|
5203
5217
|
read() {
|
|
@@ -5250,7 +5264,7 @@ var ControllerStore = class {
|
|
|
5250
5264
|
const identity2 = existing?.version === 2 ? existing : {
|
|
5251
5265
|
version: 2,
|
|
5252
5266
|
store,
|
|
5253
|
-
key: (0,
|
|
5267
|
+
key: (0, import_node_crypto8.randomBytes)(32).toString("hex"),
|
|
5254
5268
|
enrolledEpoch: epoch
|
|
5255
5269
|
};
|
|
5256
5270
|
if (existing?.version !== 2)
|
|
@@ -5296,7 +5310,7 @@ var ControllerStore = class {
|
|
|
5296
5310
|
if (!previous) {
|
|
5297
5311
|
previous = {
|
|
5298
5312
|
version: 2,
|
|
5299
|
-
store: (0,
|
|
5313
|
+
store: (0, import_node_crypto8.randomUUID)(),
|
|
5300
5314
|
epoch: 0,
|
|
5301
5315
|
revision: 0,
|
|
5302
5316
|
parkingRevision: 0,
|
|
@@ -5347,7 +5361,7 @@ function retain(session, previous) {
|
|
|
5347
5361
|
|
|
5348
5362
|
// src/core/reliability-operation-store.ts
|
|
5349
5363
|
function installedCliVersion() {
|
|
5350
|
-
return true ? "0.1.
|
|
5364
|
+
return true ? "0.1.2" : "0.0.0-dev";
|
|
5351
5365
|
}
|
|
5352
5366
|
function compareCliVersions(left, right) {
|
|
5353
5367
|
const parts = (value) => value.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
@@ -5370,7 +5384,7 @@ function identityKey(identity2) {
|
|
|
5370
5384
|
if (!import_node_path21.default.isAbsolute(identity2.repoPath) || import_node_path21.default.resolve(identity2.repoPath) !== identity2.repoPath || identity2.repoPath.includes("\0") || identity2.workspace !== null && !isReliabilityId(identity2.workspace) || !["devpod", "devsy"].includes(identity2.provider)) {
|
|
5371
5385
|
throw new Error("Invalid reliability workspace identity.");
|
|
5372
5386
|
}
|
|
5373
|
-
return (0,
|
|
5387
|
+
return (0, import_node_crypto9.createHash)("sha256").update(identity2.repoPath).digest("hex");
|
|
5374
5388
|
}
|
|
5375
5389
|
function reliabilityOperationPath(identity2) {
|
|
5376
5390
|
return import_node_path21.default.join(DEVROUTER_HOME, "reliability", `${identityKey(identity2)}.json`);
|
|
@@ -5669,12 +5683,35 @@ function validate2(record5, identity2) {
|
|
|
5669
5683
|
}
|
|
5670
5684
|
}
|
|
5671
5685
|
}
|
|
5686
|
+
var ReliabilityJournalError = class extends Error {
|
|
5687
|
+
constructor(cause, location, message) {
|
|
5688
|
+
super(message);
|
|
5689
|
+
this.cause = cause;
|
|
5690
|
+
this.location = location;
|
|
5691
|
+
this.name = "ReliabilityJournalError";
|
|
5692
|
+
}
|
|
5693
|
+
};
|
|
5694
|
+
var MAX_REPORTED_ENTRY_NAME = 160;
|
|
5695
|
+
var JournalFileGuardError = class extends Error {
|
|
5696
|
+
constructor(message) {
|
|
5697
|
+
super(message);
|
|
5698
|
+
this.name = "JournalFileGuardError";
|
|
5699
|
+
}
|
|
5700
|
+
};
|
|
5701
|
+
function journalEntryLocation(name) {
|
|
5702
|
+
const printable = name.replace(/[^A-Za-z0-9._-]/g, "?");
|
|
5703
|
+
return printable.length > MAX_REPORTED_ENTRY_NAME ? `${printable.slice(0, MAX_REPORTED_ENTRY_NAME - 3)}...` : printable;
|
|
5704
|
+
}
|
|
5672
5705
|
function createLifecycleCapacityStore(directory = import_node_path21.default.join(DEVROUTER_HOME, "controller")) {
|
|
5673
5706
|
return new CapacityStore(directory, void 0, () => {
|
|
5674
5707
|
try {
|
|
5675
5708
|
return listUnsettledCapacityBindings().floor;
|
|
5676
|
-
} catch {
|
|
5677
|
-
throw new CapacityHistoryError("capacity-history-unprovable")
|
|
5709
|
+
} catch (error) {
|
|
5710
|
+
throw error instanceof ReliabilityJournalError ? new CapacityHistoryError("capacity-history-unprovable", error.cause, error.location) : new CapacityHistoryError(
|
|
5711
|
+
"capacity-history-unprovable",
|
|
5712
|
+
"journal-enumeration-failed",
|
|
5713
|
+
null
|
|
5714
|
+
);
|
|
5678
5715
|
}
|
|
5679
5716
|
});
|
|
5680
5717
|
}
|
|
@@ -5733,11 +5770,12 @@ function readBoundedPrivateJson(file, label) {
|
|
|
5733
5770
|
try {
|
|
5734
5771
|
const stat = import_node_fs17.default.fstatSync(descriptor);
|
|
5735
5772
|
if (!stat.isFile() || stat.uid !== process.getuid?.() || stat.size > MAX_RECORD_BYTES || (stat.mode & 63) !== 0) {
|
|
5736
|
-
throw new
|
|
5773
|
+
throw new JournalFileGuardError(`${label} is not a bounded private file.`);
|
|
5737
5774
|
}
|
|
5738
5775
|
const bytes2 = Buffer.alloc(MAX_RECORD_BYTES + 1);
|
|
5739
5776
|
const count = import_node_fs17.default.readSync(descriptor, bytes2, 0, bytes2.length, 0);
|
|
5740
|
-
if (count > MAX_RECORD_BYTES)
|
|
5777
|
+
if (count > MAX_RECORD_BYTES)
|
|
5778
|
+
throw new JournalFileGuardError(`${label} exceeds its byte limit.`);
|
|
5741
5779
|
return JSON.parse(bytes2.subarray(0, count).toString("utf8"));
|
|
5742
5780
|
} finally {
|
|
5743
5781
|
import_node_fs17.default.closeSync(descriptor);
|
|
@@ -5745,7 +5783,11 @@ function readBoundedPrivateJson(file, label) {
|
|
|
5745
5783
|
}
|
|
5746
5784
|
function assertReliabilityEnumerationTime(startedAtMs) {
|
|
5747
5785
|
if (performance.now() - startedAtMs > MAX_RELIABILITY_ENUMERATION_MS)
|
|
5748
|
-
throw new
|
|
5786
|
+
throw new ReliabilityJournalError(
|
|
5787
|
+
"journal-enumeration-timeout",
|
|
5788
|
+
null,
|
|
5789
|
+
"Reliability journal enumeration exceeded its time limit."
|
|
5790
|
+
);
|
|
5749
5791
|
}
|
|
5750
5792
|
function reliabilityDirectory() {
|
|
5751
5793
|
return import_node_path21.default.join(DEVROUTER_HOME, "reliability");
|
|
@@ -5766,22 +5808,56 @@ function listReliabilityOperations() {
|
|
|
5766
5808
|
stat = import_node_fs17.default.lstatSync(directory);
|
|
5767
5809
|
} catch (error) {
|
|
5768
5810
|
if (error.code === "ENOENT") return [];
|
|
5769
|
-
throw
|
|
5811
|
+
throw new ReliabilityJournalError(
|
|
5812
|
+
"journal-directory-unreadable",
|
|
5813
|
+
null,
|
|
5814
|
+
"Reliability journal directory could not be read."
|
|
5815
|
+
);
|
|
5770
5816
|
}
|
|
5771
5817
|
if (!stat.isDirectory() || stat.isSymbolicLink())
|
|
5772
|
-
throw new
|
|
5818
|
+
throw new ReliabilityJournalError(
|
|
5819
|
+
"journal-directory-unsafe",
|
|
5820
|
+
null,
|
|
5821
|
+
"Reliability journal directory is unsafe."
|
|
5822
|
+
);
|
|
5773
5823
|
if (stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0)
|
|
5774
|
-
throw new
|
|
5824
|
+
throw new ReliabilityJournalError(
|
|
5825
|
+
"journal-directory-unsafe",
|
|
5826
|
+
null,
|
|
5827
|
+
"Reliability journal directory is not private."
|
|
5828
|
+
);
|
|
5775
5829
|
const entries = [];
|
|
5776
|
-
|
|
5830
|
+
let handle;
|
|
5831
|
+
try {
|
|
5832
|
+
handle = import_node_fs17.default.opendirSync(directory);
|
|
5833
|
+
} catch {
|
|
5834
|
+
throw new ReliabilityJournalError(
|
|
5835
|
+
"journal-directory-unreadable",
|
|
5836
|
+
null,
|
|
5837
|
+
"Reliability journal directory could not be read."
|
|
5838
|
+
);
|
|
5839
|
+
}
|
|
5777
5840
|
try {
|
|
5778
5841
|
for (; ; ) {
|
|
5779
5842
|
assertReliabilityEnumerationTime(startedAtMs);
|
|
5780
|
-
|
|
5843
|
+
let entry;
|
|
5844
|
+
try {
|
|
5845
|
+
entry = handle.readSync();
|
|
5846
|
+
} catch {
|
|
5847
|
+
throw new ReliabilityJournalError(
|
|
5848
|
+
"journal-directory-unreadable",
|
|
5849
|
+
null,
|
|
5850
|
+
"Reliability journal directory could not be read."
|
|
5851
|
+
);
|
|
5852
|
+
}
|
|
5781
5853
|
if (!entry) break;
|
|
5782
5854
|
entries.push(entry);
|
|
5783
5855
|
if (entries.length > MAX_RELIABILITY_DIRECTORY_ENTRIES)
|
|
5784
|
-
throw new
|
|
5856
|
+
throw new ReliabilityJournalError(
|
|
5857
|
+
"journal-enumeration-limit",
|
|
5858
|
+
null,
|
|
5859
|
+
"Reliability journal directory exceeds its entry limit."
|
|
5860
|
+
);
|
|
5785
5861
|
}
|
|
5786
5862
|
} finally {
|
|
5787
5863
|
handle.closeSync();
|
|
@@ -5790,27 +5866,82 @@ function listReliabilityOperations() {
|
|
|
5790
5866
|
for (const entry of entries) {
|
|
5791
5867
|
assertReliabilityEnumerationTime(startedAtMs);
|
|
5792
5868
|
if (entry.isSymbolicLink())
|
|
5793
|
-
throw new
|
|
5869
|
+
throw new ReliabilityJournalError(
|
|
5870
|
+
"journal-entry-unsupported",
|
|
5871
|
+
journalEntryLocation(entry.name),
|
|
5872
|
+
"Reliability journal directory contains a symlink."
|
|
5873
|
+
);
|
|
5794
5874
|
if (!entry.isFile())
|
|
5795
|
-
throw new
|
|
5875
|
+
throw new ReliabilityJournalError(
|
|
5876
|
+
"journal-entry-unsupported",
|
|
5877
|
+
journalEntryLocation(entry.name),
|
|
5878
|
+
"Reliability journal directory contains an unsupported entry."
|
|
5879
|
+
);
|
|
5796
5880
|
if (RELIABILITY_LOCK_NAME_RE.test(entry.name) || RELIABILITY_ATOMIC_TEMP_NAME_RE.test(entry.name))
|
|
5797
5881
|
continue;
|
|
5798
5882
|
const match = RELIABILITY_JOURNAL_NAME_RE.exec(entry.name);
|
|
5799
|
-
if (!match)
|
|
5883
|
+
if (!match)
|
|
5884
|
+
throw new ReliabilityJournalError(
|
|
5885
|
+
"journal-entry-unsupported",
|
|
5886
|
+
journalEntryLocation(entry.name),
|
|
5887
|
+
"Reliability journal directory contains an unsupported entry."
|
|
5888
|
+
);
|
|
5800
5889
|
journals.push({ name: entry.name, key: match[1] });
|
|
5801
5890
|
}
|
|
5802
5891
|
if (journals.length > MAX_RELIABILITY_JOURNALS)
|
|
5803
|
-
throw new
|
|
5892
|
+
throw new ReliabilityJournalError(
|
|
5893
|
+
"journal-enumeration-limit",
|
|
5894
|
+
null,
|
|
5895
|
+
"Reliability journal directory exceeds its journal limit."
|
|
5896
|
+
);
|
|
5804
5897
|
journals.sort((left, right) => left.name.localeCompare(right.name));
|
|
5805
5898
|
const records = [];
|
|
5806
5899
|
for (const journal of journals) {
|
|
5807
5900
|
assertReliabilityEnumerationTime(startedAtMs);
|
|
5808
5901
|
const file = import_node_path21.default.join(directory, journal.name);
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5902
|
+
let raw;
|
|
5903
|
+
try {
|
|
5904
|
+
raw = readBoundedPrivateJson(file, "Reliability journal");
|
|
5905
|
+
} catch (error) {
|
|
5906
|
+
const fsCode = error?.code;
|
|
5907
|
+
const cause = error instanceof JournalFileGuardError ? "journal-entry-unsafe" : error instanceof SyntaxError || !fsCode ? "journal-invalid" : "journal-unreadable";
|
|
5908
|
+
throw new ReliabilityJournalError(
|
|
5909
|
+
cause,
|
|
5910
|
+
journalEntryLocation(journal.name),
|
|
5911
|
+
error instanceof JournalFileGuardError ? error.message : cause === "journal-invalid" ? "Reliability journal entry is invalid." : "Reliability journal entry could not be read."
|
|
5912
|
+
);
|
|
5913
|
+
}
|
|
5914
|
+
if (raw === void 0)
|
|
5915
|
+
throw new ReliabilityJournalError(
|
|
5916
|
+
"journal-unstable",
|
|
5917
|
+
journalEntryLocation(journal.name),
|
|
5918
|
+
"Reliability journal disappeared during enumeration."
|
|
5919
|
+
);
|
|
5920
|
+
let identity2;
|
|
5921
|
+
let record5;
|
|
5922
|
+
try {
|
|
5923
|
+
identity2 = journalIdentity(raw);
|
|
5924
|
+
if (identityKey(identity2) !== journal.key)
|
|
5925
|
+
throw new ReliabilityJournalError(
|
|
5926
|
+
"journal-identity-mismatch",
|
|
5927
|
+
journalEntryLocation(journal.name),
|
|
5928
|
+
"Reliability journal filename does not match its identity."
|
|
5929
|
+
);
|
|
5930
|
+
record5 = readReliabilityOperation(identity2);
|
|
5931
|
+
} catch (error) {
|
|
5932
|
+
if (error instanceof ReliabilityJournalError) throw error;
|
|
5933
|
+
throw new ReliabilityJournalError(
|
|
5934
|
+
"journal-invalid",
|
|
5935
|
+
journalEntryLocation(journal.name),
|
|
5936
|
+
"Reliability journal entry is invalid."
|
|
5937
|
+
);
|
|
5938
|
+
}
|
|
5939
|
+
if (!record5)
|
|
5940
|
+
throw new ReliabilityJournalError(
|
|
5941
|
+
"journal-unstable",
|
|
5942
|
+
journalEntryLocation(journal.name),
|
|
5943
|
+
"Reliability journal disappeared during enumeration."
|
|
5944
|
+
);
|
|
5814
5945
|
records.push(record5);
|
|
5815
5946
|
assertReliabilityEnumerationTime(startedAtMs);
|
|
5816
5947
|
}
|
|
@@ -5886,7 +6017,7 @@ function clearStartupWitness(identity2, fence) {
|
|
|
5886
6017
|
}
|
|
5887
6018
|
|
|
5888
6019
|
// src/core/repo-config.ts
|
|
5889
|
-
var
|
|
6020
|
+
var import_node_crypto10 = require("crypto");
|
|
5890
6021
|
var import_node_fs18 = __toESM(require("fs"));
|
|
5891
6022
|
var import_node_path22 = __toESM(require("path"));
|
|
5892
6023
|
var import_yaml3 = __toESM(require("yaml"));
|
|
@@ -7163,7 +7294,7 @@ function loadRepoConfig(repoPath, read2 = (file) => import_node_fs18.default.rea
|
|
|
7163
7294
|
const config = parseConfig(parsed ?? {}, configPath);
|
|
7164
7295
|
const requiredVersion = config.devrouter?.version;
|
|
7165
7296
|
if (requiredVersion && !hasWarnedVersionMismatch) {
|
|
7166
|
-
const cliVersion = true ? "0.1.
|
|
7297
|
+
const cliVersion = true ? "0.1.2" : "0.0.0-dev";
|
|
7167
7298
|
if (cliVersion !== "0.0.0-dev" && compareSemver2(requiredVersion, cliVersion) > 0) {
|
|
7168
7299
|
hasWarnedVersionMismatch = true;
|
|
7169
7300
|
process.stderr.write(
|
|
@@ -7342,7 +7473,7 @@ async function ensureNetwork(name) {
|
|
|
7342
7473
|
|
|
7343
7474
|
// src/core/tls.ts
|
|
7344
7475
|
var import_node_child_process13 = require("child_process");
|
|
7345
|
-
var
|
|
7476
|
+
var import_node_crypto11 = require("crypto");
|
|
7346
7477
|
var import_node_fs19 = __toESM(require("fs"));
|
|
7347
7478
|
var import_node_path23 = __toESM(require("path"));
|
|
7348
7479
|
var DEFAULT_TLS_CERT_HOSTS = ["localhost", "*.localhost"];
|
|
@@ -7412,7 +7543,7 @@ function parseDnsHostsFromSubjectAltName(subjectAltName) {
|
|
|
7412
7543
|
return normalizeUniqueHosts(names);
|
|
7413
7544
|
}
|
|
7414
7545
|
function parseCertificateDnsHosts(pem) {
|
|
7415
|
-
const certificate = new
|
|
7546
|
+
const certificate = new import_node_crypto11.X509Certificate(pem);
|
|
7416
7547
|
const subjectAltName = certificate.subjectAltName ?? "";
|
|
7417
7548
|
if (subjectAltName.length === 0) {
|
|
7418
7549
|
return [];
|
|
@@ -8478,12 +8609,12 @@ function networkProviderEnvironment(binding, source) {
|
|
|
8478
8609
|
}
|
|
8479
8610
|
|
|
8480
8611
|
// src/core/network-claim-lookup.ts
|
|
8481
|
-
var
|
|
8612
|
+
var import_node_crypto13 = require("crypto");
|
|
8482
8613
|
var import_node_fs24 = __toESM(require("fs"));
|
|
8483
8614
|
var import_node_path28 = __toESM(require("path"));
|
|
8484
8615
|
|
|
8485
8616
|
// src/core/network-claims.ts
|
|
8486
|
-
var
|
|
8617
|
+
var import_node_crypto12 = require("crypto");
|
|
8487
8618
|
var import_node_fs23 = __toESM(require("fs"));
|
|
8488
8619
|
var import_node_path27 = __toESM(require("path"));
|
|
8489
8620
|
|
|
@@ -9673,7 +9804,7 @@ function assertDirectory(directory) {
|
|
|
9673
9804
|
}
|
|
9674
9805
|
}
|
|
9675
9806
|
function hashKey(value) {
|
|
9676
|
-
return (0,
|
|
9807
|
+
return (0, import_node_crypto12.createHash)("sha256").update(value).digest("hex");
|
|
9677
9808
|
}
|
|
9678
9809
|
function cloneFence(fence) {
|
|
9679
9810
|
return { ...fence };
|
|
@@ -9701,7 +9832,7 @@ function claimError(code, message) {
|
|
|
9701
9832
|
function networkOwnerKey(repoPath) {
|
|
9702
9833
|
if (!import_node_path28.default.isAbsolute(repoPath) || import_node_path28.default.resolve(repoPath) !== repoPath)
|
|
9703
9834
|
throw new Error("Invalid network owner path.");
|
|
9704
|
-
return (0,
|
|
9835
|
+
return (0, import_node_crypto13.createHash)("sha256").update(repoPath).digest("hex");
|
|
9705
9836
|
}
|
|
9706
9837
|
function findOwnedNetworkClaim(repoPath, root = NETWORK_CLAIMS_ROOT) {
|
|
9707
9838
|
let names;
|
|
@@ -9741,7 +9872,7 @@ function findOwnedNetworkClaim(repoPath, root = NETWORK_CLAIMS_ROOT) {
|
|
|
9741
9872
|
} finally {
|
|
9742
9873
|
import_node_fs24.default.closeSync(descriptor);
|
|
9743
9874
|
}
|
|
9744
|
-
if (typeof value.daemonId !== "string" || `${(0,
|
|
9875
|
+
if (typeof value.daemonId !== "string" || `${(0, import_node_crypto13.createHash)("sha256").update(value.daemonId).digest("hex")}.json` !== file)
|
|
9745
9876
|
throw new Error("Retained network daemon identity is invalid.");
|
|
9746
9877
|
const claim2 = readNetworkClaim({
|
|
9747
9878
|
daemonId: value.daemonId,
|
|
@@ -9758,7 +9889,7 @@ function findOwnedNetworkClaim(repoPath, root = NETWORK_CLAIMS_ROOT) {
|
|
|
9758
9889
|
|
|
9759
9890
|
// src/core/network-provider-inspect.ts
|
|
9760
9891
|
var import_node_child_process15 = require("child_process");
|
|
9761
|
-
var
|
|
9892
|
+
var import_node_crypto14 = require("crypto");
|
|
9762
9893
|
function object2(value) {
|
|
9763
9894
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
9764
9895
|
throw new Error("Invalid provider evidence.");
|
|
@@ -9778,7 +9909,7 @@ function qualifyNetworkProviderDefinition(value, provider) {
|
|
|
9778
9909
|
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 !== "") {
|
|
9779
9910
|
throw new Error("Docker provider definition is not qualified for network allocation.");
|
|
9780
9911
|
}
|
|
9781
|
-
return (0,
|
|
9912
|
+
return (0, import_node_crypto14.createHash)("sha256").update(JSON.stringify({ name: definition.name, agent, options, exec })).digest("hex");
|
|
9782
9913
|
}
|
|
9783
9914
|
function read(provider, args) {
|
|
9784
9915
|
const result = (0, import_node_child_process15.spawnSync)(provider, args, {
|
|
@@ -10161,7 +10292,7 @@ var ExecutionOutcomeError = class extends Error {
|
|
|
10161
10292
|
};
|
|
10162
10293
|
|
|
10163
10294
|
// src/core/reliability-lifecycle.ts
|
|
10164
|
-
var
|
|
10295
|
+
var import_node_crypto22 = require("crypto");
|
|
10165
10296
|
var import_node_path40 = __toESM(require("path"));
|
|
10166
10297
|
var import_node_util7 = require("util");
|
|
10167
10298
|
|
|
@@ -10170,7 +10301,7 @@ var import_node_fs26 = __toESM(require("fs"));
|
|
|
10170
10301
|
var import_node_path30 = __toESM(require("path"));
|
|
10171
10302
|
|
|
10172
10303
|
// src/core/controller-client.ts
|
|
10173
|
-
var
|
|
10304
|
+
var import_node_crypto15 = require("crypto");
|
|
10174
10305
|
var import_node_fs27 = __toESM(require("fs"));
|
|
10175
10306
|
var import_node_net2 = __toESM(require("net"));
|
|
10176
10307
|
var import_node_path32 = __toESM(require("path"));
|
|
@@ -10185,7 +10316,7 @@ var CONTROLLER_PROFILE_RE = new RegExp(
|
|
|
10185
10316
|
);
|
|
10186
10317
|
|
|
10187
10318
|
// src/core/controller-monitor.ts
|
|
10188
|
-
var
|
|
10319
|
+
var import_node_crypto16 = require("crypto");
|
|
10189
10320
|
var import_node_util6 = require("util");
|
|
10190
10321
|
|
|
10191
10322
|
// src/core/reliability-output.ts
|
|
@@ -10974,7 +11105,7 @@ function stepReliability(state, event, nowMs) {
|
|
|
10974
11105
|
|
|
10975
11106
|
// src/core/reliability-worker.ts
|
|
10976
11107
|
var import_node_child_process17 = require("child_process");
|
|
10977
|
-
var
|
|
11108
|
+
var import_node_crypto17 = require("crypto");
|
|
10978
11109
|
var import_node_fs28 = __toESM(require("fs"));
|
|
10979
11110
|
var import_node_path33 = __toESM(require("path"));
|
|
10980
11111
|
|
|
@@ -11742,7 +11873,7 @@ async function runManagedHostPreparation(repoPath, config) {
|
|
|
11742
11873
|
|
|
11743
11874
|
// src/core/managed-post-start.ts
|
|
11744
11875
|
var import_node_child_process22 = require("child_process");
|
|
11745
|
-
var
|
|
11876
|
+
var import_node_crypto18 = require("crypto");
|
|
11746
11877
|
var import_node_fs31 = __toESM(require("fs"));
|
|
11747
11878
|
var import_node_path36 = __toESM(require("path"));
|
|
11748
11879
|
var MANAGED_MARKER = "devrouter:managed devcontainer";
|
|
@@ -11799,7 +11930,7 @@ function readRegularFile(filePath) {
|
|
|
11799
11930
|
return readRegularFileBytes(filePath)?.toString("utf-8");
|
|
11800
11931
|
}
|
|
11801
11932
|
function adapterFingerprint(adapter) {
|
|
11802
|
-
return (0,
|
|
11933
|
+
return (0, import_node_crypto18.createHash)("sha256").update(adapter).digest("hex");
|
|
11803
11934
|
}
|
|
11804
11935
|
function resolveProcessHelperPath() {
|
|
11805
11936
|
const candidates = [
|
|
@@ -11952,24 +12083,45 @@ function runManagedProcessAction(options) {
|
|
|
11952
12083
|
}
|
|
11953
12084
|
|
|
11954
12085
|
// src/core/managed-runtime-status.ts
|
|
12086
|
+
function recoveryPath(repoPath) {
|
|
12087
|
+
if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(repoPath)) return repoPath;
|
|
12088
|
+
return `'${repoPath.replaceAll("'", "'\\''")}'`;
|
|
12089
|
+
}
|
|
11955
12090
|
function reliabilityRecovery(reason2, repoPath) {
|
|
12091
|
+
const checkout = recoveryPath(repoPath);
|
|
11956
12092
|
switch (reason2) {
|
|
11957
12093
|
case "stop-incomplete":
|
|
11958
12094
|
case "operation-unknown":
|
|
11959
|
-
return [`Run: devrouter stop ${
|
|
12095
|
+
return [`Run: devrouter stop ${checkout}`, `Run: devrouter ensure ${checkout} --repair`];
|
|
12096
|
+
case "start-refused":
|
|
12097
|
+
return [
|
|
12098
|
+
`Run: devrouter doctor --repo ${checkout} to read the refused fixed host-port claim and its holder`,
|
|
12099
|
+
`Stop the holding workspace or change this repository's own published binding, then run: devrouter ensure ${checkout}`
|
|
12100
|
+
];
|
|
11960
12101
|
case "unadmittable":
|
|
11961
12102
|
return [
|
|
11962
|
-
`Run: devrouter stop ${
|
|
11963
|
-
`Lower the requested capacity in .devrouter.yml, then run: devrouter ensure ${
|
|
12103
|
+
`Run: devrouter stop ${checkout}`,
|
|
12104
|
+
`Lower the requested capacity in .devrouter.yml, then run: devrouter ensure ${checkout}`
|
|
11964
12105
|
];
|
|
11965
12106
|
case "capacity-parked":
|
|
11966
|
-
return [
|
|
12107
|
+
return [
|
|
12108
|
+
"Parked for host capacity: the enrolled foreground controller resumes this checkout after its pressure dwell and live-consumer checks pass.",
|
|
12109
|
+
`Inspect the parked intent with: devrouter status --repo ${checkout} --json`,
|
|
12110
|
+
`'devrouter ensure' refuses while the journal stays parked; release the intent instead with: devrouter stop ${checkout}`
|
|
12111
|
+
];
|
|
11967
12112
|
case "capacity-waiting":
|
|
11968
|
-
return [`Run: devrouter ensure ${
|
|
12113
|
+
return [`Run: devrouter ensure ${checkout} (still queued until capacity frees up)`];
|
|
11969
12114
|
default:
|
|
11970
12115
|
return [];
|
|
11971
12116
|
}
|
|
11972
12117
|
}
|
|
12118
|
+
function refusedManagedStart(result) {
|
|
12119
|
+
if (result?.ok !== true) return false;
|
|
12120
|
+
const value = result.value;
|
|
12121
|
+
if (typeof value !== "object" || value === null) return false;
|
|
12122
|
+
const conflicts = value.hostPortConflicts;
|
|
12123
|
+
return Array.isArray(conflicts) && conflicts.length > 0;
|
|
12124
|
+
}
|
|
11973
12125
|
function readReliabilityStatus(options) {
|
|
11974
12126
|
let provider;
|
|
11975
12127
|
try {
|
|
@@ -11989,7 +12141,7 @@ function readReliabilityStatus(options) {
|
|
|
11989
12141
|
return void 0;
|
|
11990
12142
|
}
|
|
11991
12143
|
if (!record5) return void 0;
|
|
11992
|
-
const reason2 = reliabilityAttention(record5.state);
|
|
12144
|
+
const reason2 = reliabilityAttention(record5.state) ?? (record5.state.desired === "running" && refusedManagedStart(record5.result) ? "start-refused" : void 0);
|
|
11993
12145
|
return {
|
|
11994
12146
|
desired: record5.state.desired,
|
|
11995
12147
|
phase: record5.state.phase,
|
|
@@ -12707,10 +12859,10 @@ function inspectLegacyNetworkCapacity(input) {
|
|
|
12707
12859
|
}
|
|
12708
12860
|
|
|
12709
12861
|
// src/core/network-managed.ts
|
|
12710
|
-
var
|
|
12862
|
+
var import_node_crypto21 = require("crypto");
|
|
12711
12863
|
|
|
12712
12864
|
// src/core/network-compose.ts
|
|
12713
|
-
var
|
|
12865
|
+
var import_node_crypto19 = require("crypto");
|
|
12714
12866
|
var SAFE_ENDPOINT_UPPER_BOUND_SEMANTICS = "full-lifecycle-demand";
|
|
12715
12867
|
function isRecord5(value) {
|
|
12716
12868
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -13516,12 +13668,12 @@ function stableValue(value) {
|
|
|
13516
13668
|
}
|
|
13517
13669
|
function fingerprintComposeNetworkModel(input) {
|
|
13518
13670
|
const projection = normalizedFingerprintProjection(input);
|
|
13519
|
-
return (0,
|
|
13671
|
+
return (0, import_node_crypto19.createHash)("sha256").update(stableValue(projection), "utf8").digest("hex");
|
|
13520
13672
|
}
|
|
13521
13673
|
|
|
13522
13674
|
// src/core/network-compose-files.ts
|
|
13523
13675
|
var import_node_child_process25 = require("child_process");
|
|
13524
|
-
var
|
|
13676
|
+
var import_node_crypto20 = require("crypto");
|
|
13525
13677
|
var import_node_fs33 = __toESM(require("fs"));
|
|
13526
13678
|
var import_node_path38 = __toESM(require("path"));
|
|
13527
13679
|
var import_yaml4 = __toESM(require("yaml"));
|
|
@@ -13622,7 +13774,7 @@ ${JSON.stringify(extended.config, null, 2)}
|
|
|
13622
13774
|
...plan,
|
|
13623
13775
|
contents,
|
|
13624
13776
|
composeFiles: [...plan.composeFiles, overlayPath],
|
|
13625
|
-
effectiveConfigSha256: (0,
|
|
13777
|
+
effectiveConfigSha256: (0, import_node_crypto20.createHash)("sha256").update(contents).digest("hex")
|
|
13626
13778
|
};
|
|
13627
13779
|
return {
|
|
13628
13780
|
plan: result,
|
|
@@ -13940,7 +14092,7 @@ function createManagedNetworkSession(input) {
|
|
|
13940
14092
|
"Insufficient endpoint headroom; request an allowed larger network before first allocation."
|
|
13941
14093
|
);
|
|
13942
14094
|
const authority = readNetworkOperationAuthority(identity2);
|
|
13943
|
-
const fingerprint = (0,
|
|
14095
|
+
const fingerprint = (0, import_node_crypto21.createHash)("sha256").update(input.plan().sourceConfigSha256).update(fingerprintComposeNetworkModel(model)).digest("hex");
|
|
13944
14096
|
if (!saved) {
|
|
13945
14097
|
if (policy.status !== "valid")
|
|
13946
14098
|
throw new Error("New network allocation requires valid machine policy.");
|
|
@@ -16267,7 +16419,7 @@ async function devpodExecOutcome(repoPath, command) {
|
|
|
16267
16419
|
}
|
|
16268
16420
|
assertRunningDevpod(devpod.id, repoPath);
|
|
16269
16421
|
const workspaceDirectory = resolveWorkspaceDirectory(repoPath);
|
|
16270
|
-
const statusMarker = `__DEVROUTER_EXIT_${(0,
|
|
16422
|
+
const statusMarker = `__DEVROUTER_EXIT_${(0, import_node_crypto23.randomUUID)()}__:`;
|
|
16271
16423
|
const statusMarkerBytes = Buffer.from(statusMarker, "ascii");
|
|
16272
16424
|
const literalCommand = command.map(quotePosixArg).join(" ");
|
|
16273
16425
|
const wrappedCommand = `${literalCommand}; __devrouter_status=$?; printf '${statusMarker}%s\\n' "$__devrouter_status" >&2; exit 0`;
|