orkestrator 2.34.4-beta → 2.35.0-beta
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/README.md +12 -0
- package/bin/orkestrator-launcher.js +42 -3
- package/dist/client.js +1852 -146
- package/dist/main.js +216258 -201848
- package/package.json +4 -4
- package/resources/acp-bridge/dist/index.js +22797 -0
- package/resources/claude-bridge/dist/index.js +837 -433
- package/resources/codex-bridge/dist/index.js +744 -119
- package/resources/cursor-bridge/dist/index.js +36885 -0
- package/resources/cursor-bridge/runtime/bun.lock +40 -0
- package/resources/cursor-bridge/runtime/install.json +4 -0
- package/resources/cursor-bridge/runtime/package.json +11 -0
- package/resources/cursor-bridge/runtime/patches/@cursor%2Fsdk@1.2.0.patch +19 -0
- package/resources/pi-bridge/dist/index.js +36084 -0
- package/resources/pi-bridge/runtime/bun.lock +259 -0
- package/resources/pi-bridge/runtime/install.json +4 -0
- package/resources/pi-bridge/runtime/package.json +10 -0
package/dist/client.js
CHANGED
|
@@ -147,13 +147,16 @@ __export(exports_standalone_service, {
|
|
|
147
147
|
STANDALONE_MAX_BOOT_ATTEMPTS: () => STANDALONE_MAX_BOOT_ATTEMPTS,
|
|
148
148
|
STANDALONE_PACKAGE: () => STANDALONE_PACKAGE,
|
|
149
149
|
activateRelease: () => activateRelease,
|
|
150
|
+
effectiveServiceArguments: () => effectiveServiceArguments,
|
|
150
151
|
installLauncher: () => installLauncher,
|
|
151
152
|
installRelease: () => installRelease,
|
|
152
153
|
isNewerVersion: () => isNewerVersion,
|
|
153
154
|
linkedVersion: () => linkedVersion,
|
|
155
|
+
nextRollbackTarget: () => nextRollbackTarget,
|
|
154
156
|
readLauncherState: () => readLauncherState,
|
|
155
157
|
readReleaseManifest: () => readReleaseManifest,
|
|
156
158
|
readServiceConfig: () => readServiceConfig,
|
|
159
|
+
readStartupFailure: () => readStartupFailure,
|
|
157
160
|
readText: () => readText,
|
|
158
161
|
releaseDirectory: () => releaseDirectory,
|
|
159
162
|
releaseEntry: () => releaseEntry,
|
|
@@ -202,9 +205,31 @@ function readServiceConfig(layout) {
|
|
|
202
205
|
bun: value.bun,
|
|
203
206
|
bunVersion: typeof value.bunVersion === "string" ? value.bunVersion : "",
|
|
204
207
|
args: value.args.filter((arg) => typeof arg === "string"),
|
|
208
|
+
...typeof value.rollbackTarget?.version === "string" && Array.isArray(value.rollbackTarget.args) ? {
|
|
209
|
+
rollbackTarget: {
|
|
210
|
+
version: value.rollbackTarget.version,
|
|
211
|
+
args: value.rollbackTarget.args.filter((arg) => typeof arg === "string")
|
|
212
|
+
}
|
|
213
|
+
} : {},
|
|
214
|
+
...typeof value.installGeneration === "string" ? { installGeneration: value.installGeneration } : {},
|
|
205
215
|
installedAt: typeof value.installedAt === "string" ? value.installedAt : ""
|
|
206
216
|
};
|
|
207
217
|
}
|
|
218
|
+
function nextRollbackTarget(layout, config, before, version) {
|
|
219
|
+
if (!config || !before)
|
|
220
|
+
return;
|
|
221
|
+
const target = config.rollbackTarget;
|
|
222
|
+
if (before === version)
|
|
223
|
+
return target?.version === version ? undefined : target;
|
|
224
|
+
return {
|
|
225
|
+
version: before,
|
|
226
|
+
args: effectiveServiceArguments(config, before, linkedVersion(layout.previous))
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function effectiveServiceArguments(config, current, previous) {
|
|
230
|
+
const target = config?.rollbackTarget;
|
|
231
|
+
return target && target.version === current && previous === current ? target.args : config?.args ?? [];
|
|
232
|
+
}
|
|
208
233
|
async function writeServiceConfig(layout, config) {
|
|
209
234
|
await mkdir(layout.root, { recursive: true });
|
|
210
235
|
await writeAtomically(layout.serviceFile, `${JSON.stringify(config, null, 2)}
|
|
@@ -213,13 +238,30 @@ async function writeServiceConfig(layout, config) {
|
|
|
213
238
|
function readLauncherState(layout) {
|
|
214
239
|
const value = readJson(layout.stateFile);
|
|
215
240
|
const rollback = value?.rollback;
|
|
241
|
+
const bootFailure = value?.bootFailure;
|
|
216
242
|
return {
|
|
217
243
|
version: 1,
|
|
244
|
+
...typeof value?.installGeneration === "string" ? { installGeneration: value.installGeneration } : {},
|
|
218
245
|
lastReadyVersion: typeof value?.lastReadyVersion === "string" ? value.lastReadyVersion : null,
|
|
219
246
|
bootAttempts: value?.bootAttempts && typeof value.bootAttempts === "object" ? value.bootAttempts : {},
|
|
220
|
-
rollback: rollback && typeof rollback.failedVersion === "string" && typeof rollback.restoredVersion === "string" && typeof rollback.at === "string" ? rollback : null
|
|
247
|
+
rollback: rollback && typeof rollback.failedVersion === "string" && typeof rollback.restoredVersion === "string" && typeof rollback.at === "string" ? rollback : null,
|
|
248
|
+
bootFailure: bootFailure && typeof bootFailure.version === "string" && typeof bootFailure.exits === "number" && typeof bootFailure.at === "string" ? bootFailure : null
|
|
221
249
|
};
|
|
222
250
|
}
|
|
251
|
+
function readStartupFailure(layout, version, sinceMs, installGeneration) {
|
|
252
|
+
const state = readLauncherState(layout);
|
|
253
|
+
const rollback = state.rollback;
|
|
254
|
+
if (rollback?.failedVersion === version && (installGeneration === undefined || rollback.installGeneration === installGeneration) && Date.parse(rollback.at) >= sinceMs) {
|
|
255
|
+
return { restoredVersion: rollback.restoredVersion };
|
|
256
|
+
}
|
|
257
|
+
const failure = state.bootFailure;
|
|
258
|
+
if (failure?.version !== version || installGeneration !== undefined && failure.installGeneration !== installGeneration || failure.exits < STANDALONE_MAX_BOOT_ATTEMPTS || Date.parse(failure.at) < sinceMs) {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
const previous = linkedVersion(layout.previous);
|
|
262
|
+
const rollbackComing = previous && previous !== version && state.lastReadyVersion !== version;
|
|
263
|
+
return rollbackComing ? null : { restoredVersion: null };
|
|
264
|
+
}
|
|
223
265
|
async function writeAtomically(file, contents) {
|
|
224
266
|
const temporary = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
225
267
|
await writeFile(temporary, contents, { mode: 384 });
|
|
@@ -3457,7 +3499,7 @@ var require_crc32 = __commonJS(function(exports, module) {
|
|
|
3457
3499
|
});
|
|
3458
3500
|
|
|
3459
3501
|
// ../../node_modules/.bun/yauzl@3.4.0/node_modules/yauzl/index.js
|
|
3460
|
-
function
|
|
3502
|
+
function open2(path, options2, callback) {
|
|
3461
3503
|
if (typeof options2 === "function") {
|
|
3462
3504
|
callback = options2;
|
|
3463
3505
|
options2 = null;
|
|
@@ -3773,7 +3815,7 @@ var init_yauzl = __esm(() => {
|
|
|
3773
3815
|
PassThrough = __require("stream").PassThrough;
|
|
3774
3816
|
Writable = __require("stream").Writable;
|
|
3775
3817
|
crc32 = typeof zlib.crc32 === "function" ? zlib.crc32 : require_crc32();
|
|
3776
|
-
$open =
|
|
3818
|
+
$open = open2;
|
|
3777
3819
|
$validateFileName = validateFileName;
|
|
3778
3820
|
util.inherits(ZipFile, EventEmitter);
|
|
3779
3821
|
ZipFile.prototype.close = function() {
|
|
@@ -4391,10 +4433,10 @@ function pinnedToolchainArtifacts(platform = process.platform, architecture = pr
|
|
|
4391
4433
|
var PINNED_TOOLCHAIN_VERSIONS, PINNED_SUPPORT_TOOL_VERSIONS, PINNED_TOOL_VERSIONS, GITHUB_RELEASE_HOSTS, NPM_REGISTRY_HOSTS, GROK_DOWNLOAD_HOSTS, CODEX_RELEASE_BASE, PI_RELEASE_BASE, GH_RELEASE_BASE, OPENCODE_RELEASE_BASE, CODEX_CODE_MODE_HOST_FILE_NAME = "codex-code-mode-host", PINNED_TOOLCHAIN_ARTIFACTS;
|
|
4392
4434
|
var init_manifest = __esm(() => {
|
|
4393
4435
|
PINNED_TOOLCHAIN_VERSIONS = {
|
|
4394
|
-
claude: "2.1.
|
|
4395
|
-
codex: "0.
|
|
4396
|
-
grok: "1.0.
|
|
4397
|
-
opencode: "1.19.
|
|
4436
|
+
claude: "2.1.314",
|
|
4437
|
+
codex: "0.166.0",
|
|
4438
|
+
grok: "1.0.70",
|
|
4439
|
+
opencode: "1.19.5",
|
|
4398
4440
|
pi: "1.4.0"
|
|
4399
4441
|
};
|
|
4400
4442
|
PINNED_SUPPORT_TOOL_VERSIONS = {
|
|
@@ -4425,23 +4467,23 @@ var init_manifest = __esm(() => {
|
|
|
4425
4467
|
format: "tar.gz",
|
|
4426
4468
|
url: `${CODEX_RELEASE_BASE}/codex-aarch64-apple-darwin.tar.gz`,
|
|
4427
4469
|
entryPath: "codex-aarch64-apple-darwin",
|
|
4428
|
-
size:
|
|
4429
|
-
sha256: "
|
|
4470
|
+
size: 107610108,
|
|
4471
|
+
sha256: "c48824462fc57681eafb0925d97b11b589010475613904f570b42fea53e240d5",
|
|
4430
4472
|
allowedHosts: GITHUB_RELEASE_HOSTS
|
|
4431
4473
|
},
|
|
4432
4474
|
companions: [
|
|
4433
4475
|
codexCodeModeHost("aarch64-apple-darwin", {
|
|
4434
|
-
size:
|
|
4435
|
-
sha256: "
|
|
4476
|
+
size: 24769716,
|
|
4477
|
+
sha256: "7abd50fe5f033495a7b693c45fb82dc57093a18f1c4ba3e8043577de46c5c7c5"
|
|
4436
4478
|
}, {
|
|
4437
|
-
size:
|
|
4438
|
-
sha256: "
|
|
4479
|
+
size: 69182864,
|
|
4480
|
+
sha256: "fd37051bfdce0b65cf22a7077e265720a7bd6709d5e400dcbc26197f3041400a"
|
|
4439
4481
|
})
|
|
4440
4482
|
],
|
|
4441
4483
|
executable: {
|
|
4442
4484
|
fileName: "codex",
|
|
4443
|
-
size:
|
|
4444
|
-
sha256: "
|
|
4485
|
+
size: 268972064,
|
|
4486
|
+
sha256: "39acf979729dd290f9a24ee38b2914e036c91b65952872e28ae2a6b88a7db7c1"
|
|
4445
4487
|
}
|
|
4446
4488
|
},
|
|
4447
4489
|
{
|
|
@@ -4453,23 +4495,23 @@ var init_manifest = __esm(() => {
|
|
|
4453
4495
|
format: "tar.gz",
|
|
4454
4496
|
url: `${CODEX_RELEASE_BASE}/codex-x86_64-apple-darwin.tar.gz`,
|
|
4455
4497
|
entryPath: "codex-x86_64-apple-darwin",
|
|
4456
|
-
size:
|
|
4457
|
-
sha256: "
|
|
4498
|
+
size: 117027024,
|
|
4499
|
+
sha256: "db0c38713c36199b12e7c8d1629386c35a4ce8f99e1c9ce72f1725a74df67b57",
|
|
4458
4500
|
allowedHosts: GITHUB_RELEASE_HOSTS
|
|
4459
4501
|
},
|
|
4460
4502
|
companions: [
|
|
4461
4503
|
codexCodeModeHost("x86_64-apple-darwin", {
|
|
4462
|
-
size:
|
|
4463
|
-
sha256: "
|
|
4504
|
+
size: 26748407,
|
|
4505
|
+
sha256: "b35c775d5e5f8d60d05e0de7154e5bbbf320b6d0e28a3237d42cc8a742ccaf65"
|
|
4464
4506
|
}, {
|
|
4465
|
-
size:
|
|
4466
|
-
sha256: "
|
|
4507
|
+
size: 73183424,
|
|
4508
|
+
sha256: "9d96de017ecec30ec3f8689f489584151c167c255a787dc6e297b6edc9ebe08c"
|
|
4467
4509
|
})
|
|
4468
4510
|
],
|
|
4469
4511
|
executable: {
|
|
4470
4512
|
fileName: "codex",
|
|
4471
|
-
size:
|
|
4472
|
-
sha256: "
|
|
4513
|
+
size: 289445104,
|
|
4514
|
+
sha256: "1361e18268866b7f9f5e8703fabcea0a2a990a439eedcce03940abb4ba9eaaeb"
|
|
4473
4515
|
}
|
|
4474
4516
|
},
|
|
4475
4517
|
{
|
|
@@ -4481,23 +4523,23 @@ var init_manifest = __esm(() => {
|
|
|
4481
4523
|
format: "tar.gz",
|
|
4482
4524
|
url: `${CODEX_RELEASE_BASE}/codex-aarch64-unknown-linux-musl.tar.gz`,
|
|
4483
4525
|
entryPath: "codex-aarch64-unknown-linux-musl",
|
|
4484
|
-
size:
|
|
4485
|
-
sha256: "
|
|
4526
|
+
size: 113382496,
|
|
4527
|
+
sha256: "94eb707605ec2646b2e05b7edf7c4e7b3ccf02b16237c34ae9beb8cfb7f810a9",
|
|
4486
4528
|
allowedHosts: GITHUB_RELEASE_HOSTS
|
|
4487
4529
|
},
|
|
4488
4530
|
companions: [
|
|
4489
4531
|
codexCodeModeHost("aarch64-unknown-linux-musl", {
|
|
4490
|
-
size:
|
|
4491
|
-
sha256: "
|
|
4532
|
+
size: 27023046,
|
|
4533
|
+
sha256: "ac98d1f878e353a16cba711fd47bfef2f6c814109bdd819ee2b6b6d6a19701e7"
|
|
4492
4534
|
}, {
|
|
4493
|
-
size:
|
|
4494
|
-
sha256: "
|
|
4535
|
+
size: 70838624,
|
|
4536
|
+
sha256: "587436a943a59c18cabdbe83f07800d237b60ddd2e0f54d05b23d8b37a0b36f4"
|
|
4495
4537
|
})
|
|
4496
4538
|
],
|
|
4497
4539
|
executable: {
|
|
4498
4540
|
fileName: "codex",
|
|
4499
|
-
size:
|
|
4500
|
-
sha256: "
|
|
4541
|
+
size: 277549176,
|
|
4542
|
+
sha256: "f2e6c980c937e734644bed1b4a9a018d3e63a0ccbe71aafc85c86a8c6e4b462a"
|
|
4501
4543
|
}
|
|
4502
4544
|
},
|
|
4503
4545
|
{
|
|
@@ -4509,23 +4551,23 @@ var init_manifest = __esm(() => {
|
|
|
4509
4551
|
format: "tar.gz",
|
|
4510
4552
|
url: `${CODEX_RELEASE_BASE}/codex-x86_64-unknown-linux-musl.tar.gz`,
|
|
4511
4553
|
entryPath: "codex-x86_64-unknown-linux-musl",
|
|
4512
|
-
size:
|
|
4513
|
-
sha256: "
|
|
4554
|
+
size: 121764138,
|
|
4555
|
+
sha256: "a0bf572d2f93f056c6712a6da348e96078dc84f3885fd7be67807ef389cb3978",
|
|
4514
4556
|
allowedHosts: GITHUB_RELEASE_HOSTS
|
|
4515
4557
|
},
|
|
4516
4558
|
companions: [
|
|
4517
4559
|
codexCodeModeHost("x86_64-unknown-linux-musl", {
|
|
4518
|
-
size:
|
|
4519
|
-
sha256: "
|
|
4560
|
+
size: 28565521,
|
|
4561
|
+
sha256: "7588334fd47bc4003d970b70dfd4d1e4578491b1e9baa72976a4c2d7e97590da"
|
|
4520
4562
|
}, {
|
|
4521
|
-
size:
|
|
4522
|
-
sha256: "
|
|
4563
|
+
size: 77997328,
|
|
4564
|
+
sha256: "657f4e902726e05867c937b583049d5997e057f8cd0ab40450633c9c9ef8d630"
|
|
4523
4565
|
})
|
|
4524
4566
|
],
|
|
4525
4567
|
executable: {
|
|
4526
4568
|
fileName: "codex",
|
|
4527
|
-
size:
|
|
4528
|
-
sha256: "
|
|
4569
|
+
size: 319346888,
|
|
4570
|
+
sha256: "b8a11fedf24b2dfb59a70c9e52b030f9a508dcd49cd2dd0d41956f4c785156b8"
|
|
4529
4571
|
}
|
|
4530
4572
|
},
|
|
4531
4573
|
{
|
|
@@ -4537,14 +4579,14 @@ var init_manifest = __esm(() => {
|
|
|
4537
4579
|
format: "zip",
|
|
4538
4580
|
url: `${OPENCODE_RELEASE_BASE}/opencode-darwin-arm64.zip`,
|
|
4539
4581
|
entryPath: "opencode",
|
|
4540
|
-
size:
|
|
4541
|
-
sha256: "
|
|
4582
|
+
size: 64278924,
|
|
4583
|
+
sha256: "c1c9e62521192192ef4c3ed1355ada2144055bddb61682217e997b03c55203c1",
|
|
4542
4584
|
allowedHosts: GITHUB_RELEASE_HOSTS
|
|
4543
4585
|
},
|
|
4544
4586
|
executable: {
|
|
4545
4587
|
fileName: "opencode",
|
|
4546
|
-
size:
|
|
4547
|
-
sha256: "
|
|
4588
|
+
size: 180672544,
|
|
4589
|
+
sha256: "feaafead8cd563af0c2dcb386b0757e4355e327ebb6bd1aaad5440fe2f83596c",
|
|
4548
4590
|
repairInvalidMacSignature: true
|
|
4549
4591
|
}
|
|
4550
4592
|
},
|
|
@@ -4557,14 +4599,14 @@ var init_manifest = __esm(() => {
|
|
|
4557
4599
|
format: "zip",
|
|
4558
4600
|
url: `${OPENCODE_RELEASE_BASE}/opencode-darwin-x64.zip`,
|
|
4559
4601
|
entryPath: "opencode",
|
|
4560
|
-
size:
|
|
4561
|
-
sha256: "
|
|
4602
|
+
size: 69100888,
|
|
4603
|
+
sha256: "b0212efa6db347187225a17fa3a31c6b261bf4c9f1589a290b0ca902d720d250",
|
|
4562
4604
|
allowedHosts: GITHUB_RELEASE_HOSTS
|
|
4563
4605
|
},
|
|
4564
4606
|
executable: {
|
|
4565
4607
|
fileName: "opencode",
|
|
4566
|
-
size:
|
|
4567
|
-
sha256: "
|
|
4608
|
+
size: 193954400,
|
|
4609
|
+
sha256: "4b15c8aab1844936e9e1d1327213355d94c820de8c7084fad88d3812a067d3d0",
|
|
4568
4610
|
repairInvalidMacSignature: true
|
|
4569
4611
|
}
|
|
4570
4612
|
},
|
|
@@ -4577,14 +4619,14 @@ var init_manifest = __esm(() => {
|
|
|
4577
4619
|
format: "tar.gz",
|
|
4578
4620
|
url: `${OPENCODE_RELEASE_BASE}/opencode-linux-arm64.tar.gz`,
|
|
4579
4621
|
entryPath: "opencode",
|
|
4580
|
-
size:
|
|
4581
|
-
sha256: "
|
|
4622
|
+
size: 78513091,
|
|
4623
|
+
sha256: "fae5be262d693b7c5e562856cc473e59e741772936db0c0600ac0d5ed5bd088b",
|
|
4582
4624
|
allowedHosts: GITHUB_RELEASE_HOSTS
|
|
4583
4625
|
},
|
|
4584
4626
|
executable: {
|
|
4585
4627
|
fileName: "opencode",
|
|
4586
|
-
size:
|
|
4587
|
-
sha256: "
|
|
4628
|
+
size: 211209208,
|
|
4629
|
+
sha256: "dab85b46f4ea4813da5367997f99a60aab64a2118d58ebf552980e792747436c"
|
|
4588
4630
|
}
|
|
4589
4631
|
},
|
|
4590
4632
|
{
|
|
@@ -4596,14 +4638,14 @@ var init_manifest = __esm(() => {
|
|
|
4596
4638
|
format: "tar.gz",
|
|
4597
4639
|
url: `${OPENCODE_RELEASE_BASE}/opencode-linux-x64.tar.gz`,
|
|
4598
4640
|
entryPath: "opencode",
|
|
4599
|
-
size:
|
|
4600
|
-
sha256: "
|
|
4641
|
+
size: 79651896,
|
|
4642
|
+
sha256: "588310a336fa3b9df36b3f0225b26f679d453efaad0cf3d66c3651ef3ec1647a",
|
|
4601
4643
|
allowedHosts: GITHUB_RELEASE_HOSTS
|
|
4602
4644
|
},
|
|
4603
4645
|
executable: {
|
|
4604
4646
|
fileName: "opencode",
|
|
4605
|
-
size:
|
|
4606
|
-
sha256: "
|
|
4647
|
+
size: 214386864,
|
|
4648
|
+
sha256: "7df4e4136301f16589b0f30bf91a61380fca5f8ef22dd36570f5ebe1d4ec802c"
|
|
4607
4649
|
}
|
|
4608
4650
|
},
|
|
4609
4651
|
{
|
|
@@ -4615,14 +4657,14 @@ var init_manifest = __esm(() => {
|
|
|
4615
4657
|
format: "tar.gz",
|
|
4616
4658
|
url: claudeArchiveUrl("darwin-arm64"),
|
|
4617
4659
|
entryPath: "package/claude",
|
|
4618
|
-
size:
|
|
4619
|
-
sha256: "
|
|
4660
|
+
size: 124539940,
|
|
4661
|
+
sha256: "e4524422963f1c79a4894b5ecb70e123cc45a3dd3a0915f312f6135f70aa570c",
|
|
4620
4662
|
allowedHosts: NPM_REGISTRY_HOSTS
|
|
4621
4663
|
},
|
|
4622
4664
|
executable: {
|
|
4623
4665
|
fileName: "claude",
|
|
4624
|
-
size:
|
|
4625
|
-
sha256: "
|
|
4666
|
+
size: 278848096,
|
|
4667
|
+
sha256: "21d6e7b9a6f07b4cfcb7df13760b3b72aa25e084e13a5354413382987ba832ed"
|
|
4626
4668
|
}
|
|
4627
4669
|
},
|
|
4628
4670
|
{
|
|
@@ -4634,14 +4676,14 @@ var init_manifest = __esm(() => {
|
|
|
4634
4676
|
format: "tar.gz",
|
|
4635
4677
|
url: claudeArchiveUrl("darwin-x64"),
|
|
4636
4678
|
entryPath: "package/claude",
|
|
4637
|
-
size:
|
|
4638
|
-
sha256: "
|
|
4679
|
+
size: 129924753,
|
|
4680
|
+
sha256: "f0041d107ad1a613e82fa4d8149e44390c975c3488ca34812fa27ccc9a92b8d6",
|
|
4639
4681
|
allowedHosts: NPM_REGISTRY_HOSTS
|
|
4640
4682
|
},
|
|
4641
4683
|
executable: {
|
|
4642
4684
|
fileName: "claude",
|
|
4643
|
-
size:
|
|
4644
|
-
sha256: "
|
|
4685
|
+
size: 290710016,
|
|
4686
|
+
sha256: "404779a308a358ecec8b25c8bccf0ce79a94cf261d12cb74065518d189c174f8"
|
|
4645
4687
|
}
|
|
4646
4688
|
},
|
|
4647
4689
|
{
|
|
@@ -4653,14 +4695,14 @@ var init_manifest = __esm(() => {
|
|
|
4653
4695
|
format: "tar.gz",
|
|
4654
4696
|
url: claudeArchiveUrl("linux-arm64"),
|
|
4655
4697
|
entryPath: "package/claude",
|
|
4656
|
-
size:
|
|
4657
|
-
sha256: "
|
|
4698
|
+
size: 136687968,
|
|
4699
|
+
sha256: "5a8087f6b0df5796326bb8e58c6e89637c58f28a16aea45434a7e914e854b0dc",
|
|
4658
4700
|
allowedHosts: NPM_REGISTRY_HOSTS
|
|
4659
4701
|
},
|
|
4660
4702
|
executable: {
|
|
4661
4703
|
fileName: "claude",
|
|
4662
|
-
size:
|
|
4663
|
-
sha256: "
|
|
4704
|
+
size: 297067016,
|
|
4705
|
+
sha256: "a66c0a8f5d0c87a439953d797985192bbcbaefbce2e0d7b2eaa8df30ef0f3ef2"
|
|
4664
4706
|
}
|
|
4665
4707
|
},
|
|
4666
4708
|
{
|
|
@@ -4672,14 +4714,14 @@ var init_manifest = __esm(() => {
|
|
|
4672
4714
|
format: "tar.gz",
|
|
4673
4715
|
url: claudeArchiveUrl("linux-x64"),
|
|
4674
4716
|
entryPath: "package/claude",
|
|
4675
|
-
size:
|
|
4676
|
-
sha256: "
|
|
4717
|
+
size: 137217467,
|
|
4718
|
+
sha256: "c6b690e52ba2d038c4c8d2566b2ec35acef4995c4321f7d57fa464a7088c2b78",
|
|
4677
4719
|
allowedHosts: NPM_REGISTRY_HOSTS
|
|
4678
4720
|
},
|
|
4679
4721
|
executable: {
|
|
4680
4722
|
fileName: "claude",
|
|
4681
|
-
size:
|
|
4682
|
-
sha256: "
|
|
4723
|
+
size: 298229464,
|
|
4724
|
+
sha256: "4487042b4c4f5d88d4568f68ae98aae0b1ffae58864cf57fb868641bc5f84594"
|
|
4683
4725
|
}
|
|
4684
4726
|
},
|
|
4685
4727
|
{
|
|
@@ -4691,14 +4733,14 @@ var init_manifest = __esm(() => {
|
|
|
4691
4733
|
format: "raw",
|
|
4692
4734
|
url: `https://storage.googleapis.com/grok-build-public-artifacts/cli/grok-${PINNED_TOOLCHAIN_VERSIONS.grok}-macos-aarch64`,
|
|
4693
4735
|
entryPath: "",
|
|
4694
|
-
size:
|
|
4695
|
-
sha256: "
|
|
4736
|
+
size: 179063008,
|
|
4737
|
+
sha256: "5c8a688251bf61e35370b828b6a353b0a20fcc3f64000de8a91d426039f29cec",
|
|
4696
4738
|
allowedHosts: GROK_DOWNLOAD_HOSTS
|
|
4697
4739
|
},
|
|
4698
4740
|
executable: {
|
|
4699
4741
|
fileName: "grok",
|
|
4700
|
-
size:
|
|
4701
|
-
sha256: "
|
|
4742
|
+
size: 179063008,
|
|
4743
|
+
sha256: "5c8a688251bf61e35370b828b6a353b0a20fcc3f64000de8a91d426039f29cec"
|
|
4702
4744
|
}
|
|
4703
4745
|
},
|
|
4704
4746
|
{
|
|
@@ -4710,14 +4752,14 @@ var init_manifest = __esm(() => {
|
|
|
4710
4752
|
format: "raw",
|
|
4711
4753
|
url: `https://storage.googleapis.com/grok-build-public-artifacts/cli/grok-${PINNED_TOOLCHAIN_VERSIONS.grok}-macos-x86_64`,
|
|
4712
4754
|
entryPath: "",
|
|
4713
|
-
size:
|
|
4714
|
-
sha256: "
|
|
4755
|
+
size: 193578304,
|
|
4756
|
+
sha256: "d9ecd462f1f3c3b40a7a131944987ee7ed1c38069b7009cc4107398ab767f484",
|
|
4715
4757
|
allowedHosts: GROK_DOWNLOAD_HOSTS
|
|
4716
4758
|
},
|
|
4717
4759
|
executable: {
|
|
4718
4760
|
fileName: "grok",
|
|
4719
|
-
size:
|
|
4720
|
-
sha256: "
|
|
4761
|
+
size: 193578304,
|
|
4762
|
+
sha256: "d9ecd462f1f3c3b40a7a131944987ee7ed1c38069b7009cc4107398ab767f484"
|
|
4721
4763
|
}
|
|
4722
4764
|
},
|
|
4723
4765
|
{
|
|
@@ -4729,14 +4771,14 @@ var init_manifest = __esm(() => {
|
|
|
4729
4771
|
format: "raw",
|
|
4730
4772
|
url: `https://storage.googleapis.com/grok-build-public-artifacts/cli/grok-${PINNED_TOOLCHAIN_VERSIONS.grok}-linux-aarch64`,
|
|
4731
4773
|
entryPath: "",
|
|
4732
|
-
size:
|
|
4733
|
-
sha256: "
|
|
4774
|
+
size: 166639048,
|
|
4775
|
+
sha256: "3aa36883574b263088e5addffe241f55430e8daaee1a0c4934b02180007a9761",
|
|
4734
4776
|
allowedHosts: GROK_DOWNLOAD_HOSTS
|
|
4735
4777
|
},
|
|
4736
4778
|
executable: {
|
|
4737
4779
|
fileName: "grok",
|
|
4738
|
-
size:
|
|
4739
|
-
sha256: "
|
|
4780
|
+
size: 166639048,
|
|
4781
|
+
sha256: "3aa36883574b263088e5addffe241f55430e8daaee1a0c4934b02180007a9761"
|
|
4740
4782
|
}
|
|
4741
4783
|
},
|
|
4742
4784
|
{
|
|
@@ -4748,14 +4790,14 @@ var init_manifest = __esm(() => {
|
|
|
4748
4790
|
format: "raw",
|
|
4749
4791
|
url: `https://storage.googleapis.com/grok-build-public-artifacts/cli/grok-${PINNED_TOOLCHAIN_VERSIONS.grok}-linux-x86_64`,
|
|
4750
4792
|
entryPath: "",
|
|
4751
|
-
size:
|
|
4752
|
-
sha256: "
|
|
4793
|
+
size: 195700192,
|
|
4794
|
+
sha256: "22d281c5964c5444147328096ba2a221f3f0874c6858e27c825656a80f6e58e9",
|
|
4753
4795
|
allowedHosts: GROK_DOWNLOAD_HOSTS
|
|
4754
4796
|
},
|
|
4755
4797
|
executable: {
|
|
4756
4798
|
fileName: "grok",
|
|
4757
|
-
size:
|
|
4758
|
-
sha256: "
|
|
4799
|
+
size: 195700192,
|
|
4800
|
+
sha256: "22d281c5964c5444147328096ba2a221f3f0874c6858e27c825656a80f6e58e9"
|
|
4759
4801
|
}
|
|
4760
4802
|
},
|
|
4761
4803
|
{
|
|
@@ -4893,7 +4935,7 @@ var init_manifest = __esm(() => {
|
|
|
4893
4935
|
|
|
4894
4936
|
// ../toolchain/src/manager.ts
|
|
4895
4937
|
import { spawn } from "child_process";
|
|
4896
|
-
import { createHash as createHash4, randomUUID as
|
|
4938
|
+
import { createHash as createHash4, randomUUID as randomUUID5 } from "crypto";
|
|
4897
4939
|
import { createReadStream, createWriteStream } from "fs";
|
|
4898
4940
|
import {
|
|
4899
4941
|
chmod,
|
|
@@ -4901,13 +4943,13 @@ import {
|
|
|
4901
4943
|
lstat,
|
|
4902
4944
|
mkdir as mkdir3,
|
|
4903
4945
|
mkdtemp as mkdtemp2,
|
|
4904
|
-
open as
|
|
4946
|
+
open as open3,
|
|
4905
4947
|
readFile as readFile2,
|
|
4906
4948
|
readdir as readdir3,
|
|
4907
4949
|
readlink,
|
|
4908
4950
|
rename as rename2,
|
|
4909
4951
|
rm as rm3,
|
|
4910
|
-
stat as
|
|
4952
|
+
stat as stat3,
|
|
4911
4953
|
symlink as symlink2,
|
|
4912
4954
|
utimes
|
|
4913
4955
|
} from "fs/promises";
|
|
@@ -5214,7 +5256,7 @@ async function acquireInstallLock(rootDir, onProgress, timings, openLockFile, ow
|
|
|
5214
5256
|
let announcedWait = false;
|
|
5215
5257
|
while (Date.now() - startedAt < timings.lockWaitTimeoutMs) {
|
|
5216
5258
|
const owner = {
|
|
5217
|
-
token:
|
|
5259
|
+
token: randomUUID5(),
|
|
5218
5260
|
pid: process.pid,
|
|
5219
5261
|
createdAt: new Date().toISOString()
|
|
5220
5262
|
};
|
|
@@ -5260,7 +5302,7 @@ async function acquireInstallLock(rootDir, onProgress, timings, openLockFile, ow
|
|
|
5260
5302
|
continue;
|
|
5261
5303
|
}
|
|
5262
5304
|
}
|
|
5263
|
-
const lockStat = await
|
|
5305
|
+
const lockStat = await stat3(lockPath).catch(() => null);
|
|
5264
5306
|
if (!observedOwner && lockStat && Date.now() - lockStat.mtimeMs > timings.lockStaleAfterMs) {
|
|
5265
5307
|
const currentOwner = await readInstallLockOwner(lockPath);
|
|
5266
5308
|
if (!currentOwner) {
|
|
@@ -5307,7 +5349,7 @@ async function downloadArchive(label, archive, archivePath, fetchImpl, onBytes,
|
|
|
5307
5349
|
if (contentLength !== null && Number(contentLength) !== archive.size) {
|
|
5308
5350
|
throw new Error(`${label} archive size header did not match the pinned manifest`);
|
|
5309
5351
|
}
|
|
5310
|
-
handle = await
|
|
5352
|
+
handle = await open3(archivePath, "wx", 384);
|
|
5311
5353
|
const reader = response.body.getReader();
|
|
5312
5354
|
const hash = createHash4("sha256");
|
|
5313
5355
|
let received = 0;
|
|
@@ -5583,7 +5625,7 @@ async function repairInvalidMacSignature(executablePath, artifact, timeoutMs, sp
|
|
|
5583
5625
|
await runCodesign(["--sign", "-", "--force", executablePath], `${artifact.name} could not be ad-hoc signed after source verification`, timeoutMs, spawnProcess);
|
|
5584
5626
|
}
|
|
5585
5627
|
async function prepareRepairableExecutable(sourcePath, executablePath, artifact, skipExecutableProbeForTests, processTimeoutMs, spawnProcess) {
|
|
5586
|
-
const temporaryPath = path17.join(path17.dirname(executablePath), `.repair-${artifact.executable.fileName}-${
|
|
5628
|
+
const temporaryPath = path17.join(path17.dirname(executablePath), `.repair-${artifact.executable.fileName}-${randomUUID5()}.tmp`);
|
|
5587
5629
|
try {
|
|
5588
5630
|
await copyFile2(sourcePath, temporaryPath);
|
|
5589
5631
|
await chmod(temporaryPath, 448);
|
|
@@ -5743,7 +5785,7 @@ async function acquireVersionLease(rootDir, artifact, openLeaseFile) {
|
|
|
5743
5785
|
return;
|
|
5744
5786
|
processVersionLeases.delete(leaseKey);
|
|
5745
5787
|
const owner = {
|
|
5746
|
-
token:
|
|
5788
|
+
token: randomUUID5(),
|
|
5747
5789
|
pid: process.pid,
|
|
5748
5790
|
createdAt: new Date().toISOString()
|
|
5749
5791
|
};
|
|
@@ -5799,7 +5841,7 @@ async function pruneSupersededVersions(rootDir, artifacts, retainSupersededMs, o
|
|
|
5799
5841
|
await Promise.all(entries.filter((entry) => entry.isDirectory() && !keep.has(entry.name)).map(async (entry) => {
|
|
5800
5842
|
const versionDir = path17.join(toolDir, entry.name);
|
|
5801
5843
|
try {
|
|
5802
|
-
if ((await
|
|
5844
|
+
if ((await stat3(versionDir)).mtimeMs > staleBefore)
|
|
5803
5845
|
return;
|
|
5804
5846
|
if (await versionHasLiveLease(rootDir, name, entry.name, ownerProcessExists))
|
|
5805
5847
|
return;
|
|
@@ -5855,7 +5897,7 @@ async function activateExecutables(rootDir, artifacts) {
|
|
|
5855
5897
|
const executables = {};
|
|
5856
5898
|
const activate = async (linkName, target) => {
|
|
5857
5899
|
const activePath = path17.join(binDir, linkName);
|
|
5858
|
-
const temporaryLink = path17.join(binDir, `.${linkName}-${
|
|
5900
|
+
const temporaryLink = path17.join(binDir, `.${linkName}-${randomUUID5()}.tmp`);
|
|
5859
5901
|
const existingTarget = await readlink(activePath).catch(() => null);
|
|
5860
5902
|
if (existingTarget !== target) {
|
|
5861
5903
|
await symlink2(target, temporaryLink, "file");
|
|
@@ -5921,7 +5963,7 @@ async function ensurePinnedToolchains(options2) {
|
|
|
5921
5963
|
phase: "waiting",
|
|
5922
5964
|
completedTools: 0,
|
|
5923
5965
|
message
|
|
5924
|
-
}), timings, options2.openLockFileForTests ??
|
|
5966
|
+
}), timings, options2.openLockFileForTests ?? open3, ownerProcessExists);
|
|
5925
5967
|
try {
|
|
5926
5968
|
await cleanStagingDirectories(rootDir);
|
|
5927
5969
|
const statuses = await Promise.all(artifacts.map((artifact) => installationStatus(rootDir, artifact)));
|
|
@@ -5995,7 +6037,7 @@ async function ensurePinnedToolchains(options2) {
|
|
|
5995
6037
|
const result = await activateExecutables(rootDir, artifacts);
|
|
5996
6038
|
await Promise.all(artifacts.map((artifact) => touchArtifactDirectory(rootDir, artifact)));
|
|
5997
6039
|
if (!options2.skipVersionLeaseForTests) {
|
|
5998
|
-
await Promise.all(artifacts.map((artifact) => acquireVersionLease(rootDir, artifact, options2.openLeaseFileForTests ??
|
|
6040
|
+
await Promise.all(artifacts.map((artifact) => acquireVersionLease(rootDir, artifact, options2.openLeaseFileForTests ?? open3)));
|
|
5999
6041
|
}
|
|
6000
6042
|
await options2.onActivated?.(result);
|
|
6001
6043
|
await pruneSupersededVersions(rootDir, artifacts, timings.retainSupersededMs, ownerProcessExists, options2.removeSupersededVersionForTests ?? rm3);
|
|
@@ -6072,7 +6114,7 @@ var init_platform_selection = __esm(() => {
|
|
|
6072
6114
|
});
|
|
6073
6115
|
|
|
6074
6116
|
// ../toolchain/src/install.ts
|
|
6075
|
-
import { randomUUID as
|
|
6117
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
6076
6118
|
import { lstat as lstat2, mkdir as mkdir4, readdir as readdir4, readlink as readlink2, rename as rename3, rm as rm4, symlink as symlink3 } from "fs/promises";
|
|
6077
6119
|
import path19 from "path";
|
|
6078
6120
|
async function resolveToolchainSelection(options2) {
|
|
@@ -6150,7 +6192,7 @@ async function pointCurrentAt(rootDir, binDir) {
|
|
|
6150
6192
|
}
|
|
6151
6193
|
if (existing && await readlink2(link) === target)
|
|
6152
6194
|
return link;
|
|
6153
|
-
const temporary = path19.join(binRoot, `.${CURRENT_TOOLCHAIN_LINK}-${
|
|
6195
|
+
const temporary = path19.join(binRoot, `.${CURRENT_TOOLCHAIN_LINK}-${randomUUID6()}.tmp`);
|
|
6154
6196
|
await symlink3(target, temporary, "dir");
|
|
6155
6197
|
try {
|
|
6156
6198
|
await rename3(temporary, link);
|
|
@@ -6443,7 +6485,7 @@ var PUBLIC_ACTIONS = {
|
|
|
6443
6485
|
effects: [],
|
|
6444
6486
|
observation: "immediate",
|
|
6445
6487
|
milestone: "A",
|
|
6446
|
-
summary: "List native-agent sessions of one environment without reading transcripts."
|
|
6488
|
+
summary: "List native-agent sessions of one environment or Coordinator conversation without reading transcripts."
|
|
6447
6489
|
},
|
|
6448
6490
|
"session.get": {
|
|
6449
6491
|
version: 1,
|
|
@@ -6488,10 +6530,10 @@ var PUBLIC_ACTIONS = {
|
|
|
6488
6530
|
"session.stop": {
|
|
6489
6531
|
version: 1,
|
|
6490
6532
|
mutation: true,
|
|
6491
|
-
effects: ["provider-session"],
|
|
6533
|
+
effects: ["metadata", "provider-session", "filesystem", "process"],
|
|
6492
6534
|
observation: "receipt",
|
|
6493
6535
|
milestone: "C",
|
|
6494
|
-
summary: "Stop the current turn
|
|
6536
|
+
summary: "Stop the current turn and pause its goal, optionally bound to an expected run."
|
|
6495
6537
|
},
|
|
6496
6538
|
"session.steer": {
|
|
6497
6539
|
version: 1,
|
|
@@ -6565,6 +6607,46 @@ var PUBLIC_ACTIONS = {
|
|
|
6565
6607
|
milestone: "C",
|
|
6566
6608
|
summary: "Pause or resume one pending interaction's countdown where its deadline is enforced."
|
|
6567
6609
|
},
|
|
6610
|
+
"session.goal.set": {
|
|
6611
|
+
version: 1,
|
|
6612
|
+
mutation: true,
|
|
6613
|
+
effects: ["provider-session", "filesystem", "process"],
|
|
6614
|
+
observation: "receipt",
|
|
6615
|
+
milestone: "D",
|
|
6616
|
+
summary: "Give one agent tab a durable objective: the backend sends turns until a check proves it, the agent needs a person, or a limit stops it."
|
|
6617
|
+
},
|
|
6618
|
+
"session.goal.get": {
|
|
6619
|
+
version: 1,
|
|
6620
|
+
mutation: false,
|
|
6621
|
+
effects: [],
|
|
6622
|
+
observation: "immediate",
|
|
6623
|
+
milestone: "D",
|
|
6624
|
+
summary: "Read one session's goal and its recent history, without starting anything; check output on request."
|
|
6625
|
+
},
|
|
6626
|
+
"session.goal.pause": {
|
|
6627
|
+
version: 1,
|
|
6628
|
+
mutation: true,
|
|
6629
|
+
effects: ["metadata", "provider-session", "filesystem", "process"],
|
|
6630
|
+
observation: "receipt",
|
|
6631
|
+
milestone: "D",
|
|
6632
|
+
summary: "Pause a running goal; no further turn starts until it is resumed."
|
|
6633
|
+
},
|
|
6634
|
+
"session.goal.resume": {
|
|
6635
|
+
version: 1,
|
|
6636
|
+
mutation: true,
|
|
6637
|
+
effects: ["provider-session", "filesystem", "process"],
|
|
6638
|
+
observation: "receipt",
|
|
6639
|
+
milestone: "D",
|
|
6640
|
+
summary: "Resume a stopped goal, optionally with a higher iteration cap or token budget."
|
|
6641
|
+
},
|
|
6642
|
+
"session.goal.clear": {
|
|
6643
|
+
version: 1,
|
|
6644
|
+
mutation: true,
|
|
6645
|
+
effects: ["metadata", "provider-session", "filesystem", "process"],
|
|
6646
|
+
observation: "receipt",
|
|
6647
|
+
milestone: "D",
|
|
6648
|
+
summary: "Remove a session's goal in any status; it stays readable in the goal history."
|
|
6649
|
+
},
|
|
6568
6650
|
"session.transcript": {
|
|
6569
6651
|
version: 1,
|
|
6570
6652
|
mutation: false,
|
|
@@ -6733,6 +6815,158 @@ var PUBLIC_ACTIONS = {
|
|
|
6733
6815
|
milestone: "D",
|
|
6734
6816
|
summary: "Start the Resolve Conflicts agent session in an environment (the Resolve tab): merge the target branch, resolve and validate conflicts, commit and push."
|
|
6735
6817
|
},
|
|
6818
|
+
"pr.get": {
|
|
6819
|
+
version: 1,
|
|
6820
|
+
mutation: false,
|
|
6821
|
+
effects: [],
|
|
6822
|
+
observation: "immediate",
|
|
6823
|
+
milestone: "D",
|
|
6824
|
+
summary: "Read the pull request attached to an environment's branch: attachment, URL, state, draft, base and head branches, head SHA, mergeability, checks, reviewers, labels and conversation comments."
|
|
6825
|
+
},
|
|
6826
|
+
"pr.list": {
|
|
6827
|
+
version: 1,
|
|
6828
|
+
mutation: false,
|
|
6829
|
+
effects: [],
|
|
6830
|
+
observation: "immediate",
|
|
6831
|
+
milestone: "D",
|
|
6832
|
+
summary: "List a project's pull requests from GitHub, by filter and search text."
|
|
6833
|
+
},
|
|
6834
|
+
"pr.timeline": {
|
|
6835
|
+
version: 1,
|
|
6836
|
+
mutation: false,
|
|
6837
|
+
effects: [],
|
|
6838
|
+
observation: "immediate",
|
|
6839
|
+
milestone: "D",
|
|
6840
|
+
summary: "Read the timeline of an environment's pull request: commits, comments, reviews and events, oldest first."
|
|
6841
|
+
},
|
|
6842
|
+
"pr.files": {
|
|
6843
|
+
version: 1,
|
|
6844
|
+
mutation: false,
|
|
6845
|
+
effects: [],
|
|
6846
|
+
observation: "immediate",
|
|
6847
|
+
milestone: "D",
|
|
6848
|
+
summary: "Read the changed files and review threads of an environment's pull request; with path, that file's diff hunks."
|
|
6849
|
+
},
|
|
6850
|
+
"pr.options": {
|
|
6851
|
+
version: 1,
|
|
6852
|
+
mutation: false,
|
|
6853
|
+
effects: [],
|
|
6854
|
+
observation: "immediate",
|
|
6855
|
+
milestone: "D",
|
|
6856
|
+
summary: "Read the labels and assignable users of the repository of an environment's pull request, for pr.label and pr.reviewers."
|
|
6857
|
+
},
|
|
6858
|
+
"pr.merge": {
|
|
6859
|
+
version: 1,
|
|
6860
|
+
mutation: true,
|
|
6861
|
+
effects: ["external-repository", "filesystem", "process"],
|
|
6862
|
+
observation: "receipt",
|
|
6863
|
+
milestone: "D",
|
|
6864
|
+
summary: "Merge an environment's pull request into its target branch (the Merge button, squash by default): a draft is marked ready first and the head branch is deleted unless deleteBranch is false. With cleanup, the Merge and Cleanup button: also delete the environment and its worktree once the merge is confirmed."
|
|
6865
|
+
},
|
|
6866
|
+
"pr.close": {
|
|
6867
|
+
version: 1,
|
|
6868
|
+
mutation: true,
|
|
6869
|
+
effects: ["external-repository"],
|
|
6870
|
+
observation: "receipt",
|
|
6871
|
+
milestone: "D",
|
|
6872
|
+
summary: "Close an environment's pull request without merging; pr.reopen undoes it."
|
|
6873
|
+
},
|
|
6874
|
+
"pr.reopen": {
|
|
6875
|
+
version: 1,
|
|
6876
|
+
mutation: true,
|
|
6877
|
+
effects: ["external-repository"],
|
|
6878
|
+
observation: "receipt",
|
|
6879
|
+
milestone: "D",
|
|
6880
|
+
summary: "Reopen an environment's closed pull request."
|
|
6881
|
+
},
|
|
6882
|
+
"pr.ready": {
|
|
6883
|
+
version: 1,
|
|
6884
|
+
mutation: true,
|
|
6885
|
+
effects: ["external-repository"],
|
|
6886
|
+
observation: "receipt",
|
|
6887
|
+
milestone: "D",
|
|
6888
|
+
summary: "Mark an environment's draft pull request ready for review."
|
|
6889
|
+
},
|
|
6890
|
+
"pr.draft": {
|
|
6891
|
+
version: 1,
|
|
6892
|
+
mutation: true,
|
|
6893
|
+
effects: ["external-repository"],
|
|
6894
|
+
observation: "receipt",
|
|
6895
|
+
milestone: "D",
|
|
6896
|
+
summary: "Convert an environment's pull request back to a draft."
|
|
6897
|
+
},
|
|
6898
|
+
"pr.comment": {
|
|
6899
|
+
version: 1,
|
|
6900
|
+
mutation: true,
|
|
6901
|
+
effects: ["external-repository"],
|
|
6902
|
+
observation: "receipt",
|
|
6903
|
+
milestone: "D",
|
|
6904
|
+
summary: "Add a conversation comment to an environment's pull request."
|
|
6905
|
+
},
|
|
6906
|
+
"pr.comment.edit": {
|
|
6907
|
+
version: 1,
|
|
6908
|
+
mutation: true,
|
|
6909
|
+
effects: ["external-repository"],
|
|
6910
|
+
observation: "receipt",
|
|
6911
|
+
milestone: "D",
|
|
6912
|
+
summary: "Edit a conversation comment on an environment's pull request; the GitHub user must be allowed to edit it."
|
|
6913
|
+
},
|
|
6914
|
+
"pr.review": {
|
|
6915
|
+
version: 1,
|
|
6916
|
+
mutation: true,
|
|
6917
|
+
effects: ["external-repository"],
|
|
6918
|
+
observation: "receipt",
|
|
6919
|
+
milestone: "D",
|
|
6920
|
+
summary: "Submit a review of an environment's pull request: approve, request changes or comment, with optional inline comments."
|
|
6921
|
+
},
|
|
6922
|
+
"pr.review.comment": {
|
|
6923
|
+
version: 1,
|
|
6924
|
+
mutation: true,
|
|
6925
|
+
effects: ["external-repository"],
|
|
6926
|
+
observation: "receipt",
|
|
6927
|
+
milestone: "D",
|
|
6928
|
+
summary: "Add one inline review comment to a line of an environment's pull request."
|
|
6929
|
+
},
|
|
6930
|
+
"pr.thread.reply": {
|
|
6931
|
+
version: 1,
|
|
6932
|
+
mutation: true,
|
|
6933
|
+
effects: ["external-repository"],
|
|
6934
|
+
observation: "receipt",
|
|
6935
|
+
milestone: "D",
|
|
6936
|
+
summary: "Reply to a review thread on an environment's pull request (threadId from pr.files)."
|
|
6937
|
+
},
|
|
6938
|
+
"pr.thread.resolve": {
|
|
6939
|
+
version: 1,
|
|
6940
|
+
mutation: true,
|
|
6941
|
+
effects: ["external-repository"],
|
|
6942
|
+
observation: "receipt",
|
|
6943
|
+
milestone: "D",
|
|
6944
|
+
summary: "Resolve or unresolve a review thread on an environment's pull request (threadId from pr.files)."
|
|
6945
|
+
},
|
|
6946
|
+
"pr.file.viewed": {
|
|
6947
|
+
version: 1,
|
|
6948
|
+
mutation: true,
|
|
6949
|
+
effects: ["external-repository"],
|
|
6950
|
+
observation: "receipt",
|
|
6951
|
+
milestone: "D",
|
|
6952
|
+
summary: "Mark a changed file of an environment's pull request as viewed or not viewed for the GitHub user."
|
|
6953
|
+
},
|
|
6954
|
+
"pr.reviewers": {
|
|
6955
|
+
version: 1,
|
|
6956
|
+
mutation: true,
|
|
6957
|
+
effects: ["external-repository"],
|
|
6958
|
+
observation: "receipt",
|
|
6959
|
+
milestone: "D",
|
|
6960
|
+
summary: "Request or remove reviewers on an environment's pull request."
|
|
6961
|
+
},
|
|
6962
|
+
"pr.label": {
|
|
6963
|
+
version: 1,
|
|
6964
|
+
mutation: true,
|
|
6965
|
+
effects: ["external-repository"],
|
|
6966
|
+
observation: "receipt",
|
|
6967
|
+
milestone: "D",
|
|
6968
|
+
summary: "Add or remove one label on an environment's pull request."
|
|
6969
|
+
},
|
|
6736
6970
|
"attention.list": {
|
|
6737
6971
|
version: 1,
|
|
6738
6972
|
mutation: false,
|
|
@@ -7003,7 +7237,12 @@ var PUBLIC_EXIT = Object.freeze({
|
|
|
7003
7237
|
deadline: 5,
|
|
7004
7238
|
interactionRequired: 6,
|
|
7005
7239
|
unknownDispatch: 7,
|
|
7006
|
-
conflict: 8
|
|
7240
|
+
conflict: 8,
|
|
7241
|
+
goalClaimed: 10,
|
|
7242
|
+
goalBlocked: 11,
|
|
7243
|
+
goalLimited: 12,
|
|
7244
|
+
goalPaused: 13,
|
|
7245
|
+
goalGone: 14
|
|
7007
7246
|
});
|
|
7008
7247
|
var PUBLIC_SIGNAL_EXIT = Object.freeze({ SIGINT: 130, SIGTERM: 143 });
|
|
7009
7248
|
var PUBLIC_ERROR_EXIT = {
|
|
@@ -7055,7 +7294,12 @@ var PUBLIC_ERROR_EXIT = {
|
|
|
7055
7294
|
"session-idle": PUBLIC_EXIT.conflict,
|
|
7056
7295
|
"interaction-stale": PUBLIC_EXIT.conflict,
|
|
7057
7296
|
"dispatch-parked": PUBLIC_EXIT.conflict,
|
|
7058
|
-
"node-unsupported": PUBLIC_EXIT.conflict
|
|
7297
|
+
"node-unsupported": PUBLIC_EXIT.conflict,
|
|
7298
|
+
"goal-claimed": PUBLIC_EXIT.goalClaimed,
|
|
7299
|
+
"goal-blocked": PUBLIC_EXIT.goalBlocked,
|
|
7300
|
+
"goal-limited": PUBLIC_EXIT.goalLimited,
|
|
7301
|
+
"goal-paused": PUBLIC_EXIT.goalPaused,
|
|
7302
|
+
"goal-gone": PUBLIC_EXIT.goalGone
|
|
7059
7303
|
};
|
|
7060
7304
|
function isPublicErrorCode(value) {
|
|
7061
7305
|
return typeof value === "string" && Object.hasOwn(PUBLIC_ERROR_EXIT, value);
|
|
@@ -7550,7 +7794,7 @@ function splitFlag(token) {
|
|
|
7550
7794
|
}
|
|
7551
7795
|
|
|
7552
7796
|
// src/client/fix.ts
|
|
7553
|
-
import { existsSync as existsSync3, realpathSync as
|
|
7797
|
+
import { existsSync as existsSync3, realpathSync as realpathSync3 } from "fs";
|
|
7554
7798
|
import { mkdtemp, readdir as readdir2, rmdir } from "fs/promises";
|
|
7555
7799
|
import os4 from "os";
|
|
7556
7800
|
import path6 from "path";
|
|
@@ -7562,16 +7806,19 @@ var COORDINATOR_CONTROL_TOOL_NAMES = Object.freeze([
|
|
|
7562
7806
|
"add_ticket_comment",
|
|
7563
7807
|
"address_multi_review",
|
|
7564
7808
|
"adopt_workflow",
|
|
7809
|
+
"answer_worker_question",
|
|
7565
7810
|
"cancel_build_pipeline",
|
|
7566
7811
|
"cancel_graph_run",
|
|
7567
7812
|
"cancel_multi_review",
|
|
7568
7813
|
"cancel_schedule",
|
|
7814
|
+
"clear_worker_goal",
|
|
7569
7815
|
"compare_project_files",
|
|
7570
7816
|
"create_pr",
|
|
7571
7817
|
"create_schedule",
|
|
7572
7818
|
"create_ticket",
|
|
7573
7819
|
"custom_fix_multi_review",
|
|
7574
7820
|
"edit_worker_tab",
|
|
7821
|
+
"fork_worker",
|
|
7575
7822
|
"get_build_pipeline",
|
|
7576
7823
|
"get_environment",
|
|
7577
7824
|
"get_feature_plan",
|
|
@@ -7584,6 +7831,9 @@ var COORDINATOR_CONTROL_TOOL_NAMES = Object.freeze([
|
|
|
7584
7831
|
"get_tab_state",
|
|
7585
7832
|
"get_tab_transcript",
|
|
7586
7833
|
"get_ticket",
|
|
7834
|
+
"get_usage_limits",
|
|
7835
|
+
"get_worker_changes",
|
|
7836
|
+
"get_worker_goal",
|
|
7587
7837
|
"launch_environment",
|
|
7588
7838
|
"launch_feature_plan",
|
|
7589
7839
|
"launch_graph",
|
|
@@ -7598,14 +7848,18 @@ var COORDINATOR_CONTROL_TOOL_NAMES = Object.freeze([
|
|
|
7598
7848
|
"list_node_environments",
|
|
7599
7849
|
"list_nodes",
|
|
7600
7850
|
"list_projects",
|
|
7851
|
+
"list_provider_accounts",
|
|
7601
7852
|
"list_schedules",
|
|
7602
7853
|
"list_tabs",
|
|
7603
7854
|
"list_tickets",
|
|
7855
|
+
"list_worker_commands",
|
|
7604
7856
|
"list_workflows",
|
|
7605
7857
|
"open_multi_review",
|
|
7606
7858
|
"open_multi_review_fix",
|
|
7607
7859
|
"open_worker_browser",
|
|
7608
7860
|
"pause_build_pipeline",
|
|
7861
|
+
"pause_schedule",
|
|
7862
|
+
"pause_worker_goal",
|
|
7609
7863
|
"propose_agents_md_update",
|
|
7610
7864
|
"read_messages",
|
|
7611
7865
|
"read_node_environment",
|
|
@@ -7614,18 +7868,26 @@ var COORDINATOR_CONTROL_TOOL_NAMES = Object.freeze([
|
|
|
7614
7868
|
"request_project_file_update",
|
|
7615
7869
|
"request_project_on_node",
|
|
7616
7870
|
"request_root_changes",
|
|
7871
|
+
"resolve_conflicts",
|
|
7617
7872
|
"resume_build_pipeline",
|
|
7873
|
+
"resume_schedule",
|
|
7874
|
+
"run_worker_command",
|
|
7618
7875
|
"send_message",
|
|
7619
7876
|
"send_node_message",
|
|
7620
7877
|
"send_prompt_to_node_tab",
|
|
7621
7878
|
"send_prompt_to_tab",
|
|
7879
|
+
"set_worker_goal",
|
|
7622
7880
|
"start_build_pipeline",
|
|
7623
7881
|
"start_environment",
|
|
7624
7882
|
"start_multi_review",
|
|
7625
7883
|
"start_node_environment",
|
|
7626
7884
|
"stop_environment",
|
|
7627
7885
|
"stop_node_environment",
|
|
7886
|
+
"stop_worker_turn",
|
|
7887
|
+
"switch_provider_account",
|
|
7888
|
+
"set_account_auto_switch",
|
|
7628
7889
|
"transfer_files",
|
|
7890
|
+
"update_schedule",
|
|
7629
7891
|
"update_ticket"
|
|
7630
7892
|
]);
|
|
7631
7893
|
|
|
@@ -8066,12 +8328,13 @@ async function writePrivateFile(file, contents) {
|
|
|
8066
8328
|
}
|
|
8067
8329
|
|
|
8068
8330
|
// ../../apps/backend/src/data-dir.ts
|
|
8331
|
+
import { realpathSync as realpathSync2 } from "fs";
|
|
8069
8332
|
import os3 from "os";
|
|
8070
8333
|
import path5 from "path";
|
|
8071
8334
|
// ../../apps/backend/package.json
|
|
8072
8335
|
var package_default = {
|
|
8073
8336
|
name: "@orkestrator/backend",
|
|
8074
|
-
version: "2.
|
|
8337
|
+
version: "2.35.0-beta",
|
|
8075
8338
|
private: true,
|
|
8076
8339
|
type: "module",
|
|
8077
8340
|
exports: {
|
|
@@ -8091,7 +8354,7 @@ var package_default = {
|
|
|
8091
8354
|
dependencies: {
|
|
8092
8355
|
"@modelcontextprotocol/node": "2.1.1",
|
|
8093
8356
|
"@modelcontextprotocol/server": "2.3.1",
|
|
8094
|
-
"@opencode-ai/sdk": "1.19.
|
|
8357
|
+
"@opencode-ai/sdk": "1.19.5",
|
|
8095
8358
|
"@orkestrator/protocol": "workspace:*",
|
|
8096
8359
|
"@orkestrator/toolchain": "workspace:*",
|
|
8097
8360
|
"@xterm/addon-serialize": "0.14.0",
|
|
@@ -8191,6 +8454,16 @@ function defaultDataDir(platform = process.platform, env = process.env, home = o
|
|
|
8191
8454
|
return path5.join(home, "Library", "Application Support", APP_SLUG);
|
|
8192
8455
|
return path5.join(env.XDG_CONFIG_HOME ?? path5.join(home, ".config"), APP_SLUG);
|
|
8193
8456
|
}
|
|
8457
|
+
function isDefaultDataDir(dataDir, platform = process.platform, env = process.env, home = os3.homedir()) {
|
|
8458
|
+
const canonical = (value) => {
|
|
8459
|
+
try {
|
|
8460
|
+
return realpathSync2(value);
|
|
8461
|
+
} catch {
|
|
8462
|
+
return path5.resolve(value);
|
|
8463
|
+
}
|
|
8464
|
+
};
|
|
8465
|
+
return canonical(dataDir) === canonical(defaultDataDir(platform, env, home));
|
|
8466
|
+
}
|
|
8194
8467
|
|
|
8195
8468
|
// src/client/fix.ts
|
|
8196
8469
|
var FIX_ISSUE_REPOSITORY = BUG_REPORT_ISSUE_REPOSITORY;
|
|
@@ -8292,10 +8565,10 @@ function resolveFixAgent(name, options2) {
|
|
|
8292
8565
|
if (onPath) {
|
|
8293
8566
|
let isManaged = false;
|
|
8294
8567
|
try {
|
|
8295
|
-
const root =
|
|
8296
|
-
const target =
|
|
8568
|
+
const root = realpathSync3(toolchainRootDir(options2.dataDir));
|
|
8569
|
+
const target = realpathSync3(onPath);
|
|
8297
8570
|
const relative = path6.relative(root, target);
|
|
8298
|
-
isManaged = !relative.startsWith(`..${path6.sep}`) && relative !== ".." && !path6.isAbsolute(relative) || existsSync3(managed) && target ===
|
|
8571
|
+
isManaged = !relative.startsWith(`..${path6.sep}`) && relative !== ".." && !path6.isAbsolute(relative) || existsSync3(managed) && target === realpathSync3(managed);
|
|
8299
8572
|
} catch {}
|
|
8300
8573
|
return { agent, executable: onPath, source: isManaged ? "managed" : "path" };
|
|
8301
8574
|
}
|
|
@@ -8305,13 +8578,13 @@ function resolveFixAgent(name, options2) {
|
|
|
8305
8578
|
}
|
|
8306
8579
|
async function diagnosticConnection(dataDir, env) {
|
|
8307
8580
|
try {
|
|
8308
|
-
const descriptor =
|
|
8581
|
+
const descriptor = realpathSync3(path6.join(dataDir, "backend-instance.json"));
|
|
8309
8582
|
const config = await new CliConfigStore(defaultCliConfigDir(env)).read();
|
|
8310
8583
|
for (const [name, connection] of Object.entries(config.connections)) {
|
|
8311
8584
|
if (connection.kind !== "descriptor")
|
|
8312
8585
|
continue;
|
|
8313
8586
|
try {
|
|
8314
|
-
if (
|
|
8587
|
+
if (realpathSync3(connection.descriptorPath) === descriptor)
|
|
8315
8588
|
return name;
|
|
8316
8589
|
} catch {}
|
|
8317
8590
|
}
|
|
@@ -8538,6 +8811,63 @@ async function observe(check, options2) {
|
|
|
8538
8811
|
}
|
|
8539
8812
|
}
|
|
8540
8813
|
|
|
8814
|
+
// ../protocol/src/native-agent-goal.ts
|
|
8815
|
+
init_agent_platforms();
|
|
8816
|
+
function goalIsRunning(status) {
|
|
8817
|
+
return status === "active" || status === "checking" || status === "verifying";
|
|
8818
|
+
}
|
|
8819
|
+
var NATIVE_AGENT_GOAL_LIMITS = Object.freeze({
|
|
8820
|
+
objectiveMaxChars: 4000,
|
|
8821
|
+
checkMaxBytes: 4 * 1024,
|
|
8822
|
+
reportMessageMaxBytes: 2 * 1024,
|
|
8823
|
+
checkOutputMaxBytes: 8 * 1024,
|
|
8824
|
+
statusDetailMaxBytes: 1024,
|
|
8825
|
+
maxIterationsDefault: 20,
|
|
8826
|
+
maxIterationsLimit: 100,
|
|
8827
|
+
noProgressLimit: 3,
|
|
8828
|
+
checkTimeoutDefaultMs: 10 * 60000,
|
|
8829
|
+
checkTimeoutMaxMs: 30 * 60000,
|
|
8830
|
+
verifierModelMaxChars: 200,
|
|
8831
|
+
verifierTimeoutDefaultMs: 30 * 60000,
|
|
8832
|
+
verdictSummaryMaxBytes: 2 * 1024,
|
|
8833
|
+
verdictReasonsMax: 16,
|
|
8834
|
+
verdictReasonMaxBytes: 512,
|
|
8835
|
+
historyLimit: 5
|
|
8836
|
+
});
|
|
8837
|
+
var AGENT_GOAL_TOOL_NAMES = Object.freeze(["report_goal"]);
|
|
8838
|
+
var GOAL_QUALIFIED_PLATFORMS = Object.freeze([
|
|
8839
|
+
"claude",
|
|
8840
|
+
"codex",
|
|
8841
|
+
"opencode",
|
|
8842
|
+
"cursor",
|
|
8843
|
+
"grok",
|
|
8844
|
+
"pi"
|
|
8845
|
+
]);
|
|
8846
|
+
var GOAL_TOKEN_BUDGET_PLATFORMS = Object.freeze([
|
|
8847
|
+
"claude",
|
|
8848
|
+
"codex",
|
|
8849
|
+
"opencode",
|
|
8850
|
+
"cursor",
|
|
8851
|
+
"grok",
|
|
8852
|
+
"pi"
|
|
8853
|
+
]);
|
|
8854
|
+
function parseVerifierFlag(text) {
|
|
8855
|
+
const colon = text.indexOf(":");
|
|
8856
|
+
const agent = colon < 0 ? text : text.slice(0, colon);
|
|
8857
|
+
const model = colon < 0 ? undefined : text.slice(colon + 1);
|
|
8858
|
+
if (!isAgentPlatform(agent)) {
|
|
8859
|
+
return { error: "--verifier takes an agent, optionally with a model: --verifier codex:o3." };
|
|
8860
|
+
}
|
|
8861
|
+
if (model === undefined)
|
|
8862
|
+
return { agent };
|
|
8863
|
+
if (!model || model.length > NATIVE_AGENT_GOAL_LIMITS.verifierModelMaxChars) {
|
|
8864
|
+
return {
|
|
8865
|
+
error: `The verifier's model name must be 1 to ${NATIVE_AGENT_GOAL_LIMITS.verifierModelMaxChars} characters.`
|
|
8866
|
+
};
|
|
8867
|
+
}
|
|
8868
|
+
return { agent, model };
|
|
8869
|
+
}
|
|
8870
|
+
|
|
8541
8871
|
// ../protocol/src/public-api-wait.ts
|
|
8542
8872
|
function isTerminalPublicReceipt(receipt) {
|
|
8543
8873
|
return !["admitted", "running", "unknown"].includes(receipt.state);
|
|
@@ -8592,6 +8922,34 @@ function terminalReceiptErrorCode(receipt) {
|
|
|
8592
8922
|
return "run-unknown";
|
|
8593
8923
|
return receipt.error?.code ?? "operation-failed";
|
|
8594
8924
|
}
|
|
8925
|
+
var GOAL_END_CODES = {
|
|
8926
|
+
claimed: "goal-claimed",
|
|
8927
|
+
blocked: "goal-blocked",
|
|
8928
|
+
limited: "goal-limited",
|
|
8929
|
+
paused: "goal-paused"
|
|
8930
|
+
};
|
|
8931
|
+
function classifyGoalForWait(read, goalId, options2 = {}) {
|
|
8932
|
+
const current = read.goal?.goalId === goalId ? read.goal : null;
|
|
8933
|
+
if (!current) {
|
|
8934
|
+
const past = read.history.findLast((goal) => goal.goalId === goalId);
|
|
8935
|
+
if (past?.status === "complete")
|
|
8936
|
+
return { kind: "complete", goal: past };
|
|
8937
|
+
if (past?.status === "claimed")
|
|
8938
|
+
return { kind: "stopped", code: "goal-claimed", goal: past };
|
|
8939
|
+
return past ? { kind: "gone", goal: past } : { kind: "gone" };
|
|
8940
|
+
}
|
|
8941
|
+
if (goalIsRunning(current.status)) {
|
|
8942
|
+
const needsAnswer = read.activity === "waiting" || (read.pendingInteractionCount ?? 0) > 0;
|
|
8943
|
+
return needsAnswer && !options2.continueOnInteraction ? { kind: "interaction", goal: current } : { kind: "pending", goal: current };
|
|
8944
|
+
}
|
|
8945
|
+
if (current.status === "complete")
|
|
8946
|
+
return { kind: "complete", goal: current };
|
|
8947
|
+
return {
|
|
8948
|
+
kind: "stopped",
|
|
8949
|
+
code: GOAL_END_CODES[current.status],
|
|
8950
|
+
goal: current
|
|
8951
|
+
};
|
|
8952
|
+
}
|
|
8595
8953
|
|
|
8596
8954
|
// src/client/commands/common.ts
|
|
8597
8955
|
var REQUEST_ID_OPTION = {
|
|
@@ -8766,6 +9124,15 @@ async function waitForOperation(context, session, initial, timeoutMs, options2 =
|
|
|
8766
9124
|
}
|
|
8767
9125
|
async function waitForEnvironment(context, session, environmentId, condition, receipt, timeoutMs) {
|
|
8768
9126
|
let latestReceipt = receipt;
|
|
9127
|
+
const deadline = Date.now() + timeoutMs;
|
|
9128
|
+
const remaining = () => {
|
|
9129
|
+
if (context.signal?.aborted)
|
|
9130
|
+
throw new ObservationStopped("signal", signalName(context.signal));
|
|
9131
|
+
const budget = deadline - Date.now();
|
|
9132
|
+
if (budget <= 0)
|
|
9133
|
+
throw new ObservationStopped("deadline");
|
|
9134
|
+
return budget;
|
|
9135
|
+
};
|
|
8769
9136
|
const conditionMet = (environment) => {
|
|
8770
9137
|
if (condition === "deleted")
|
|
8771
9138
|
return environment === null;
|
|
@@ -8779,8 +9146,10 @@ async function waitForEnvironment(context, session, environmentId, condition, re
|
|
|
8779
9146
|
};
|
|
8780
9147
|
try {
|
|
8781
9148
|
return await observe(async () => {
|
|
9149
|
+
remaining();
|
|
8782
9150
|
if (latestReceipt && !isTerminalReceipt(latestReceipt)) {
|
|
8783
|
-
latestReceipt = await readOperation(session, latestReceipt.operationId);
|
|
9151
|
+
latestReceipt = await readOperation(session, latestReceipt.operationId, remaining());
|
|
9152
|
+
remaining();
|
|
8784
9153
|
}
|
|
8785
9154
|
if (latestReceipt && isTerminalReceipt(latestReceipt)) {
|
|
8786
9155
|
const failure = receiptFailure(latestReceipt);
|
|
@@ -8789,15 +9158,15 @@ async function waitForEnvironment(context, session, environmentId, condition, re
|
|
|
8789
9158
|
}
|
|
8790
9159
|
let environment;
|
|
8791
9160
|
try {
|
|
8792
|
-
|
|
8793
|
-
|
|
8794
|
-
});
|
|
9161
|
+
const snapshot = await session.readWithReceipt("environment.get", { environmentId }, remaining());
|
|
9162
|
+
environment = snapshot.result;
|
|
8795
9163
|
} catch (error) {
|
|
8796
9164
|
if (error instanceof CliError && error.code === "not-found")
|
|
8797
9165
|
environment = null;
|
|
8798
9166
|
else
|
|
8799
9167
|
throw error;
|
|
8800
9168
|
}
|
|
9169
|
+
remaining();
|
|
8801
9170
|
if (condition !== "deleted" && !environment) {
|
|
8802
9171
|
throw new CliError("not-found", "The environment no longer exists", latestReceipt ? { receipt: latestReceipt } : {});
|
|
8803
9172
|
}
|
|
@@ -8816,8 +9185,9 @@ async function waitForEnvironment(context, session, environmentId, condition, re
|
|
|
8816
9185
|
return { done: false };
|
|
8817
9186
|
}, { timeoutMs, signal: context.signal });
|
|
8818
9187
|
} catch (error) {
|
|
8819
|
-
|
|
8820
|
-
|
|
9188
|
+
const stopped = context.signal?.aborted ? new ObservationStopped("signal", signalName(context.signal)) : Date.now() >= deadline && error instanceof CliError && error.code === "connection-failed" ? new ObservationStopped("deadline") : error;
|
|
9189
|
+
if (stopped instanceof ObservationStopped) {
|
|
9190
|
+
throw stoppedError(stopped, latestReceipt?.action ?? "environment.get", latestReceipt, `the environment (${condition})`);
|
|
8821
9191
|
}
|
|
8822
9192
|
throw error;
|
|
8823
9193
|
}
|
|
@@ -9862,6 +10232,7 @@ var PROJECTION_FIELD_SET = new Set([
|
|
|
9862
10232
|
"queue",
|
|
9863
10233
|
"asyncQuestionResponses",
|
|
9864
10234
|
"contextUsage",
|
|
10235
|
+
"goal",
|
|
9865
10236
|
"rateLimits",
|
|
9866
10237
|
"runtime",
|
|
9867
10238
|
"runtimeHealthAuthoritative",
|
|
@@ -9886,6 +10257,7 @@ var OPTIONAL_PROJECTION_FIELD_SET = new Set([
|
|
|
9886
10257
|
"queue",
|
|
9887
10258
|
"asyncQuestionResponses",
|
|
9888
10259
|
"contextUsage",
|
|
10260
|
+
"goal",
|
|
9889
10261
|
"rateLimits",
|
|
9890
10262
|
"runtime",
|
|
9891
10263
|
"runtimeHealthAuthoritative",
|
|
@@ -9910,6 +10282,35 @@ var REVIEWER_STATUSES = new Set([
|
|
|
9910
10282
|
"cancelled"
|
|
9911
10283
|
]);
|
|
9912
10284
|
|
|
10285
|
+
// ../protocol/src/build-pipeline-key-information.ts
|
|
10286
|
+
var KEY_INFORMATION_LIMITS = Object.freeze({
|
|
10287
|
+
proseLength: 4000,
|
|
10288
|
+
itemLength: 600,
|
|
10289
|
+
listItems: 30,
|
|
10290
|
+
decisions: 12,
|
|
10291
|
+
decisionLength: 400,
|
|
10292
|
+
options: 6,
|
|
10293
|
+
optionLength: 300,
|
|
10294
|
+
prosCons: 6,
|
|
10295
|
+
rationaleLength: 1000,
|
|
10296
|
+
tests: 40,
|
|
10297
|
+
testNameLength: 400,
|
|
10298
|
+
issues: 60,
|
|
10299
|
+
issueLength: 400,
|
|
10300
|
+
severityLength: 40,
|
|
10301
|
+
resolutionLength: 1000,
|
|
10302
|
+
verifications: 20,
|
|
10303
|
+
summaryLength: 2000,
|
|
10304
|
+
checks: 30,
|
|
10305
|
+
checkLength: 400,
|
|
10306
|
+
updates: 30,
|
|
10307
|
+
maxRound: 1000
|
|
10308
|
+
});
|
|
10309
|
+
var KEY_INFORMATION_TOOL_NAMES = Object.freeze([
|
|
10310
|
+
"get_key_information",
|
|
10311
|
+
"update_key_information"
|
|
10312
|
+
]);
|
|
10313
|
+
|
|
9913
10314
|
// ../protocol/src/ticket-sections.ts
|
|
9914
10315
|
var ACCEPTANCE_CRITERION_STATUSES = ["passed", "failed", "not-checked"];
|
|
9915
10316
|
var TICKET_SECTION_DEFINITIONS = [
|
|
@@ -10079,6 +10480,11 @@ var VERIFICATION_VERDICT_SCHEMA = Object.freeze({
|
|
|
10079
10480
|
properties: VERIFICATION_VERDICT_PROPERTIES
|
|
10080
10481
|
});
|
|
10081
10482
|
var MAX_BUILD_PIPELINE_ITERATIONS = 10;
|
|
10483
|
+
var SETUP_BUILD_PHASES = new Set([
|
|
10484
|
+
"creating-environment",
|
|
10485
|
+
"starting-environment",
|
|
10486
|
+
"waiting-for-setup"
|
|
10487
|
+
]);
|
|
10082
10488
|
var BUILD_PHASES = new Set([
|
|
10083
10489
|
"creating-environment",
|
|
10084
10490
|
"starting-environment",
|
|
@@ -10114,6 +10520,15 @@ var FAILURE_KINDS = new Set([
|
|
|
10114
10520
|
var INTERACTION_PAYLOAD_ENCODER = new TextEncoder;
|
|
10115
10521
|
var INTERACTION_PROVIDERS = new Set(AGENT_INTERACTION_PROVIDERS);
|
|
10116
10522
|
var INTERACTION_KINDS = new Set(AGENT_INTERACTION_KINDS);
|
|
10523
|
+
var VALIDATION_RESULT_STATUSES = new Set([
|
|
10524
|
+
"pending",
|
|
10525
|
+
"queued",
|
|
10526
|
+
"running",
|
|
10527
|
+
"passed",
|
|
10528
|
+
"failed",
|
|
10529
|
+
"skipped",
|
|
10530
|
+
"incomplete"
|
|
10531
|
+
]);
|
|
10117
10532
|
|
|
10118
10533
|
// ../protocol/src/public-api-inputs-build.ts
|
|
10119
10534
|
init_agent_platforms();
|
|
@@ -10401,7 +10816,11 @@ function sessionLines(session) {
|
|
|
10401
10816
|
["activity", session.activity],
|
|
10402
10817
|
["latest request", session.latestRequestId],
|
|
10403
10818
|
["pending interactions", session.pendingInteractionCount],
|
|
10404
|
-
["recoverable dispatch", session.recoverableDispatch]
|
|
10819
|
+
["recoverable dispatch", session.recoverableDispatch],
|
|
10820
|
+
[
|
|
10821
|
+
"goal",
|
|
10822
|
+
session.goal ? `${session.goal.status} (${session.goal.iterations}/${session.goal.maxIterations})` : undefined
|
|
10823
|
+
]
|
|
10405
10824
|
]);
|
|
10406
10825
|
}
|
|
10407
10826
|
function receiptLines(receipt) {
|
|
@@ -15001,6 +15420,15 @@ function parseEndpoints(value) {
|
|
|
15001
15420
|
return { role: entry.role, url: entry.url };
|
|
15002
15421
|
});
|
|
15003
15422
|
}
|
|
15423
|
+
function parseControlMcp(value) {
|
|
15424
|
+
if (!isRecord3(value) || typeof value.running !== "boolean" || value.url !== undefined && !isHttpUrl(value.url)) {
|
|
15425
|
+
throw new Error("Backend instance descriptor field is invalid: controlMcp");
|
|
15426
|
+
}
|
|
15427
|
+
return {
|
|
15428
|
+
running: value.running,
|
|
15429
|
+
...value.url !== undefined ? { url: value.url } : {}
|
|
15430
|
+
};
|
|
15431
|
+
}
|
|
15004
15432
|
function parseBackendInstanceDescriptor(value) {
|
|
15005
15433
|
if (!isRecord3(value))
|
|
15006
15434
|
throw new Error("Backend instance descriptor must be an object");
|
|
@@ -15023,6 +15451,7 @@ function parseBackendInstanceDescriptor(value) {
|
|
|
15023
15451
|
throw new Error("Backend instance descriptor field is invalid: browserUrl");
|
|
15024
15452
|
}
|
|
15025
15453
|
const endpoints = value.endpoints === undefined ? undefined : parseEndpoints(value.endpoints);
|
|
15454
|
+
const controlMcp = value.controlMcp === undefined ? undefined : parseControlMcp(value.controlMcp);
|
|
15026
15455
|
if (!Number.isSafeInteger(value.publicApiSchemaVersion) || value.publicApiSchemaVersion < 1) {
|
|
15027
15456
|
throw new Error("Backend instance descriptor field is invalid: publicApiSchemaVersion");
|
|
15028
15457
|
}
|
|
@@ -15041,6 +15470,7 @@ function parseBackendInstanceDescriptor(value) {
|
|
|
15041
15470
|
url: value.url,
|
|
15042
15471
|
...value.browserUrl !== undefined ? { browserUrl: value.browserUrl } : {},
|
|
15043
15472
|
...endpoints !== undefined ? { endpoints } : {},
|
|
15473
|
+
...controlMcp !== undefined ? { controlMcp } : {},
|
|
15044
15474
|
authFile,
|
|
15045
15475
|
dataDir,
|
|
15046
15476
|
appVersion: text("appVersion", 64),
|
|
@@ -16277,17 +16707,24 @@ function waitOption(conditions) {
|
|
|
16277
16707
|
description: `Observe until the environment is ${conditions.join(" or ")} (bounded by --timeout).`
|
|
16278
16708
|
};
|
|
16279
16709
|
}
|
|
16710
|
+
function remainingBudget(budget, recoveryDeadline) {
|
|
16711
|
+
return recoveryDeadline === undefined ? budget : Math.max(0, recoveryDeadline - Date.now());
|
|
16712
|
+
}
|
|
16280
16713
|
async function lifecycle(context, parsed, action, conditions, extraInput = {}) {
|
|
16281
16714
|
const environmentId = String(parsed.positionals.environment);
|
|
16282
16715
|
const wait = parsed.options.wait === undefined ? undefined : oneOf(parsed.options.wait, conditions, "--wait");
|
|
16283
16716
|
if (parsed.options.timeout !== undefined && wait === undefined) {
|
|
16284
16717
|
throw new CliError("invalid-input", "--timeout needs --wait");
|
|
16285
16718
|
}
|
|
16286
|
-
const
|
|
16719
|
+
const input = { environmentId, ...extraInput };
|
|
16720
|
+
const budget = parsed.options.timeout ?? DEFAULT_WAIT_MS;
|
|
16721
|
+
const submitted = wait ? await submitForWait(context, action, input, parsed.options, budget) : await submit(context, action, input, parsed.options);
|
|
16722
|
+
const { session, receipt, warnings } = submitted;
|
|
16723
|
+
const result = submitted.result ?? receipt?.result;
|
|
16287
16724
|
let finalReceipt = receipt;
|
|
16288
16725
|
let environment;
|
|
16289
16726
|
if (wait) {
|
|
16290
|
-
const waited = await waitForEnvironment(context, session, environmentId, wait, receipt,
|
|
16727
|
+
const waited = await waitForEnvironment(context, session, environmentId, wait, receipt, remainingBudget(budget, "deadline" in submitted ? submitted.deadline : undefined));
|
|
16291
16728
|
finalReceipt = waited.receipt ?? finalReceipt;
|
|
16292
16729
|
environment = waited.environment;
|
|
16293
16730
|
}
|
|
@@ -16713,14 +17150,18 @@ var environmentCommands = [
|
|
|
16713
17150
|
if (options2["exit-code"] === true && options2.wait !== true) {
|
|
16714
17151
|
throw new CliError("invalid-input", "--exit-code needs --wait");
|
|
16715
17152
|
}
|
|
16716
|
-
const
|
|
17153
|
+
const input = {
|
|
16717
17154
|
environmentId: parsed.positionals.environment,
|
|
16718
17155
|
argv,
|
|
16719
17156
|
...options2.cwd !== undefined ? { cwd: options2.cwd } : {},
|
|
16720
17157
|
...Object.keys(env).length > 0 ? { env } : {},
|
|
16721
17158
|
...stdinBase64 !== undefined ? { stdinBase64 } : {},
|
|
16722
17159
|
...options2["exec-timeout"] !== undefined ? { timeoutMs: options2["exec-timeout"] } : {}
|
|
16723
|
-
}
|
|
17160
|
+
};
|
|
17161
|
+
const budget = options2.timeout ?? DEFAULT_WAIT_MS;
|
|
17162
|
+
const submitted = options2.wait === true ? await submitForWait(context, "environment.exec", input, options2, budget) : await submit(context, "environment.exec", input, options2);
|
|
17163
|
+
const { session, receipt, warnings } = submitted;
|
|
17164
|
+
const result = submitted.result ?? receipt?.result;
|
|
16724
17165
|
if (!receipt)
|
|
16725
17166
|
throw new CliError("response-invalid", "environment.exec returned no receipt");
|
|
16726
17167
|
if (options2.wait !== true) {
|
|
@@ -16734,7 +17175,7 @@ var environmentCommands = [
|
|
|
16734
17175
|
human: receiptLines(receipt)
|
|
16735
17176
|
};
|
|
16736
17177
|
}
|
|
16737
|
-
const final = await waitForOperation(context, session, receipt,
|
|
17178
|
+
const final = await waitForOperation(context, session, receipt, remainingBudget(budget, "deadline" in submitted ? submitted.deadline : undefined));
|
|
16738
17179
|
const human = [];
|
|
16739
17180
|
if (context.global.output === "human") {
|
|
16740
17181
|
for (const stream of ["stdout", "stderr"]) {
|
|
@@ -17120,7 +17561,11 @@ var SCHEDULED_JOB_LIMITS = Object.freeze({
|
|
|
17120
17561
|
busyRetryDelayMs: 30000,
|
|
17121
17562
|
fireStaleMs: 90000,
|
|
17122
17563
|
fireHeartbeatMs: 20000,
|
|
17123
|
-
maxFireAttempts: 3
|
|
17564
|
+
maxFireAttempts: 3,
|
|
17565
|
+
maxSelfTimerDelayMs: 7 * 24 * 60 * 60000,
|
|
17566
|
+
maxPendingSelfTimers: 20,
|
|
17567
|
+
selfTimerGrantWindowMs: 2 * 60 * 60000,
|
|
17568
|
+
userInstructionMaxChars: 500
|
|
17124
17569
|
});
|
|
17125
17570
|
function describeScheduleTrigger(trigger, timeZone) {
|
|
17126
17571
|
switch (trigger.kind) {
|
|
@@ -17701,12 +18146,19 @@ var mailCommands = [
|
|
|
17701
18146
|
];
|
|
17702
18147
|
|
|
17703
18148
|
// src/client/commands/service.ts
|
|
17704
|
-
import {
|
|
18149
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
18150
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
17705
18151
|
import { existsSync as existsSync6 } from "fs";
|
|
17706
|
-
import { mkdir as mkdir2, rm as rm2, writeFile as writeFile2 } from "fs/promises";
|
|
18152
|
+
import { mkdir as mkdir2, rm as rm2, stat as stat2, writeFile as writeFile2 } from "fs/promises";
|
|
18153
|
+
import { createServer } from "net";
|
|
17707
18154
|
import path16 from "path";
|
|
17708
18155
|
|
|
18156
|
+
// ../../apps/backend/src/fixed-ports.ts
|
|
18157
|
+
var DEFAULT_GATEWAY_PORT = 34121;
|
|
18158
|
+
var DEFAULT_CONTROL_MCP_PORT = 34122;
|
|
18159
|
+
|
|
17709
18160
|
// src/client/service-connection.ts
|
|
18161
|
+
import { open } from "fs/promises";
|
|
17710
18162
|
import path13 from "path";
|
|
17711
18163
|
async function currentDescriptorGeneration(dataDir) {
|
|
17712
18164
|
try {
|
|
@@ -17715,20 +18167,49 @@ async function currentDescriptorGeneration(dataDir) {
|
|
|
17715
18167
|
return null;
|
|
17716
18168
|
}
|
|
17717
18169
|
}
|
|
18170
|
+
var LOG_EXCERPT_LINES = 20;
|
|
18171
|
+
var LOG_EXCERPT_MAX_LINE = 500;
|
|
18172
|
+
var LOG_EXCERPT_MAX_BYTES = 256 * 1024;
|
|
18173
|
+
async function startupLogExcerpt(logFile, offset, version) {
|
|
18174
|
+
let text;
|
|
18175
|
+
try {
|
|
18176
|
+
const file = await open(logFile);
|
|
18177
|
+
try {
|
|
18178
|
+
const { size } = await file.stat();
|
|
18179
|
+
const start = Math.max(offset, size - LOG_EXCERPT_MAX_BYTES);
|
|
18180
|
+
const buffer = Buffer.alloc(Math.max(size - start, 0));
|
|
18181
|
+
await file.read(buffer, 0, buffer.length, start);
|
|
18182
|
+
text = buffer.toString("utf8");
|
|
18183
|
+
} finally {
|
|
18184
|
+
await file.close();
|
|
18185
|
+
}
|
|
18186
|
+
} catch {
|
|
18187
|
+
return [];
|
|
18188
|
+
}
|
|
18189
|
+
const lines = text.split(`
|
|
18190
|
+
`);
|
|
18191
|
+
const exit = lines.findLastIndex((line) => line.includes(` ${version} exited (`));
|
|
18192
|
+
const rollback = lines.findIndex((line) => line.includes(` ${version} did not start after `) && line.includes("; rolling back to "));
|
|
18193
|
+
const nextStart = lines.findIndex((line) => /^\[launcher\] \S+ starting /.test(line) && !line.endsWith(` starting ${version}`));
|
|
18194
|
+
const end = exit >= 0 ? exit : Math.min(...[rollback, nextStart, lines.length].filter((index) => index >= 0));
|
|
18195
|
+
return lines.slice(0, end).filter((line) => line.trim() !== "").slice(-LOG_EXCERPT_LINES).map((line) => line.slice(0, LOG_EXCERPT_MAX_LINE));
|
|
18196
|
+
}
|
|
17718
18197
|
async function awaitServiceConnection(dataDir, previousGeneration, options2) {
|
|
17719
18198
|
const file = path13.join(dataDir, BACKEND_INSTANCE_DESCRIPTOR_FILE);
|
|
17720
18199
|
try {
|
|
17721
18200
|
const descriptor = await observe(async () => {
|
|
17722
18201
|
try {
|
|
17723
18202
|
const value = await readDescriptor(file);
|
|
17724
|
-
const fresh = value.generation !== previousGeneration && path13.resolve(value.dataDir) === path13.resolve(dataDir) && processIsAlive(value.pid);
|
|
17725
|
-
|
|
17726
|
-
|
|
17727
|
-
|
|
17728
|
-
|
|
18203
|
+
const fresh = value.generation !== previousGeneration && path13.resolve(value.dataDir) === path13.resolve(dataDir) && (options2.expectedVersion === undefined || value.appVersion === options2.expectedVersion) && processIsAlive(value.pid);
|
|
18204
|
+
if (fresh)
|
|
18205
|
+
return { done: true, value };
|
|
18206
|
+
} catch {}
|
|
18207
|
+
await options2.assertStarting?.();
|
|
18208
|
+
return { done: false };
|
|
17729
18209
|
}, options2);
|
|
17730
18210
|
const connection = {
|
|
17731
18211
|
browserUrl: descriptor.browserUrl ?? (isLoopbackHost(new URL(descriptor.url).hostname) || descriptor.endpoints?.some((endpoint) => endpoint.url === descriptor.url) ? null : descriptor.url),
|
|
18212
|
+
clientUrls: (descriptor.endpoints ?? []).filter((endpoint) => endpoint.role === "client").map((endpoint) => endpoint.url),
|
|
17732
18213
|
authFile: descriptor.authFile,
|
|
17733
18214
|
token: null
|
|
17734
18215
|
};
|
|
@@ -17752,6 +18233,7 @@ async function awaitServiceConnection(dataDir, previousGeneration, options2) {
|
|
|
17752
18233
|
}
|
|
17753
18234
|
|
|
17754
18235
|
// src/client/service-setup.ts
|
|
18236
|
+
import { spawnSync } from "child_process";
|
|
17755
18237
|
import { existsSync as existsSync4 } from "fs";
|
|
17756
18238
|
import os6 from "os";
|
|
17757
18239
|
var HOSTED_WEB_ORIGINS = "https://orkestrator.dev,https://www.orkestrator.dev";
|
|
@@ -17764,7 +18246,24 @@ var systemSetupProbe = {
|
|
|
17764
18246
|
return MACOS_TAILSCALE_APP_CLI;
|
|
17765
18247
|
}
|
|
17766
18248
|
return typeof Bun === "undefined" ? null : Bun.which("tailscale");
|
|
17767
|
-
}
|
|
18249
|
+
},
|
|
18250
|
+
tailscaleOperatorNeeded: (cli) => {
|
|
18251
|
+
if (process.platform !== "linux")
|
|
18252
|
+
return null;
|
|
18253
|
+
const user = os6.userInfo();
|
|
18254
|
+
if (user.uid === 0)
|
|
18255
|
+
return null;
|
|
18256
|
+
const prefs = spawnSync(cli, ["debug", "prefs"], { encoding: "utf8", timeout: 1e4 });
|
|
18257
|
+
if (prefs.status !== 0)
|
|
18258
|
+
return null;
|
|
18259
|
+
try {
|
|
18260
|
+
const { OperatorUser } = JSON.parse(prefs.stdout);
|
|
18261
|
+
return OperatorUser === user.username ? null : user.username;
|
|
18262
|
+
} catch {
|
|
18263
|
+
return null;
|
|
18264
|
+
}
|
|
18265
|
+
},
|
|
18266
|
+
grantTailscaleOperator: (cli, user) => spawnSync("sudo", [cli, "set", `--operator=${user}`], { stdio: "inherit" }).status === 0
|
|
17768
18267
|
};
|
|
17769
18268
|
function isTailscaleIPv4(address) {
|
|
17770
18269
|
const [first, second] = address.split(".").map(Number);
|
|
@@ -17808,9 +18307,44 @@ async function confirm(io, prompt, fallback) {
|
|
|
17808
18307
|
`);
|
|
17809
18308
|
}
|
|
17810
18309
|
}
|
|
18310
|
+
async function askGatewayPort(io) {
|
|
18311
|
+
io.stderr(`
|
|
18312
|
+
This is not the default data directory, so ports ${DEFAULT_GATEWAY_PORT} and ${DEFAULT_CONTROL_MCP_PORT} stay with the main install. Without a port of its own, this backend takes a free one that changes on each start.
|
|
18313
|
+
`);
|
|
18314
|
+
for (;; ) {
|
|
18315
|
+
const answer = await ask(io, "Gateway port for a stable address (empty for a free one): ");
|
|
18316
|
+
if (answer === "")
|
|
18317
|
+
return null;
|
|
18318
|
+
const port = Number(answer);
|
|
18319
|
+
if (/^\d+$/.test(answer) && port >= 1 && port <= 65535 && port !== DEFAULT_GATEWAY_PORT && port !== DEFAULT_CONTROL_MCP_PORT) {
|
|
18320
|
+
return String(port);
|
|
18321
|
+
}
|
|
18322
|
+
io.stderr(`Enter a port from 1 to 65535, other than ${DEFAULT_GATEWAY_PORT} and ${DEFAULT_CONTROL_MCP_PORT}.
|
|
18323
|
+
`);
|
|
18324
|
+
}
|
|
18325
|
+
}
|
|
17811
18326
|
function quote(arg) {
|
|
17812
18327
|
return /^[\w@%+=:,./-]+$/.test(arg) ? arg : `'${arg.replaceAll("'", `'\\''`)}'`;
|
|
17813
18328
|
}
|
|
18329
|
+
function operatorMessage(cli, user) {
|
|
18330
|
+
return [
|
|
18331
|
+
`
|
|
18332
|
+
Tailscale only lets root or its operator configure Serve, and ${user} is neither.`,
|
|
18333
|
+
"The backend cannot start with --tailscale-serve until this has been run once:",
|
|
18334
|
+
` sudo ${quote(cli)} set --operator=${quote(user)}
|
|
18335
|
+
`
|
|
18336
|
+
].join(`
|
|
18337
|
+
`);
|
|
18338
|
+
}
|
|
18339
|
+
function warnIfTailscaleOperatorNeeded(io, serveArgs, probe = systemSetupProbe) {
|
|
18340
|
+
if (!serveArgs.includes("--tailscale-serve"))
|
|
18341
|
+
return;
|
|
18342
|
+
const binFlag = serveArgs.indexOf("--tailscale-bin");
|
|
18343
|
+
const cli = (binFlag >= 0 ? serveArgs[binFlag + 1] : undefined) ?? io.env.ORKESTRATOR_TAILSCALE_BIN ?? probe.findTailscaleCli();
|
|
18344
|
+
const user = cli ? probe.tailscaleOperatorNeeded(cli) : null;
|
|
18345
|
+
if (cli && user)
|
|
18346
|
+
io.stderr(operatorMessage(cli, user));
|
|
18347
|
+
}
|
|
17814
18348
|
async function askServeArguments(io, options2) {
|
|
17815
18349
|
const source = io;
|
|
17816
18350
|
io = {
|
|
@@ -17843,16 +18377,30 @@ async function askServeArguments(io, options2) {
|
|
|
17843
18377
|
This machine has no Tailscale address yet. Connect Tailscale before the service starts, or it will not serve.
|
|
17844
18378
|
`);
|
|
17845
18379
|
}
|
|
18380
|
+
if (access === "tailnet" && options2.secondBackend) {
|
|
18381
|
+
const port = await askGatewayPort(io);
|
|
18382
|
+
if (port)
|
|
18383
|
+
args.push("--port", port);
|
|
18384
|
+
}
|
|
17846
18385
|
if (access === "serve") {
|
|
17847
18386
|
args.push("--tailscale-serve");
|
|
17848
|
-
|
|
18387
|
+
let cli = probe.findTailscaleCli();
|
|
18388
|
+
if (!cli) {
|
|
17849
18389
|
io.stderr(`
|
|
17850
18390
|
The Tailscale CLI was not found, and Tailscale Serve needs it.
|
|
17851
18391
|
`);
|
|
17852
|
-
|
|
18392
|
+
cli = await ask(io, "Path to the tailscale executable (empty to keep `tailscale`): ");
|
|
17853
18393
|
if (cli !== "")
|
|
17854
18394
|
args.push("--tailscale-bin", cli);
|
|
17855
18395
|
}
|
|
18396
|
+
const operator = cli ? probe.tailscaleOperatorNeeded(cli) : null;
|
|
18397
|
+
if (cli && operator) {
|
|
18398
|
+
io.stderr(operatorMessage(cli, operator));
|
|
18399
|
+
const granted = !options2.dryRun && await confirm(io, "Run it now with sudo?", true) && probe.grantTailscaleOperator(cli, operator);
|
|
18400
|
+
if (!granted && !options2.dryRun)
|
|
18401
|
+
io.stderr(`Continuing without it.
|
|
18402
|
+
`);
|
|
18403
|
+
}
|
|
17856
18404
|
if (await confirm(io, `
|
|
17857
18405
|
Allow the hosted web client at orkestrator.dev?`, true)) {
|
|
17858
18406
|
args.push("--allowed-origins", HOSTED_WEB_ORIGINS);
|
|
@@ -17934,6 +18482,8 @@ ${args}
|
|
|
17934
18482
|
}
|
|
17935
18483
|
const name = `orkestrator-backend${tag}.service`;
|
|
17936
18484
|
const configHome = options2.env.XDG_CONFIG_HOME ?? path14.join(home, ".config");
|
|
18485
|
+
const xdgEnvironment = options2.env.XDG_CONFIG_HOME === undefined ? "" : `Environment=${systemdWord(`XDG_CONFIG_HOME=${options2.env.XDG_CONFIG_HOME}`)}
|
|
18486
|
+
`;
|
|
17937
18487
|
return {
|
|
17938
18488
|
manager: "systemd",
|
|
17939
18489
|
name,
|
|
@@ -17947,7 +18497,7 @@ Type=simple
|
|
|
17947
18497
|
ExecStart=${[options2.bun, options2.launcher, options2.dataDir].map(systemdWord).join(" ")}
|
|
17948
18498
|
Environment=${systemdWord(`PATH=${pathValue}`)}
|
|
17949
18499
|
Environment=NODE_ENV=production
|
|
17950
|
-
Restart=always
|
|
18500
|
+
${xdgEnvironment}Restart=always
|
|
17951
18501
|
RestartSec=10
|
|
17952
18502
|
StandardOutput=append:${options2.logFile}
|
|
17953
18503
|
StandardError=append:${options2.logFile}
|
|
@@ -18032,8 +18582,43 @@ function unitFor(context, dataDir, bun) {
|
|
|
18032
18582
|
};
|
|
18033
18583
|
});
|
|
18034
18584
|
}
|
|
18585
|
+
async function startupFailedError(version, failure, logFile, logOffset) {
|
|
18586
|
+
const excerpt = await startupLogExcerpt(logFile, logOffset, version);
|
|
18587
|
+
return new CliError("operation-failed", [
|
|
18588
|
+
failure.restoredVersion ? `orkestrator@${version} did not start, so the service went back to ${failure.restoredVersion}.` : `orkestrator@${version} did not start, and the service keeps retrying it.`,
|
|
18589
|
+
...excerpt.length > 0 ? ["", ...excerpt, ""] : [],
|
|
18590
|
+
`Fix the cause, then run this command again. Full log: ${logFile}`
|
|
18591
|
+
].join(`
|
|
18592
|
+
`), { retryable: true });
|
|
18593
|
+
}
|
|
18594
|
+
async function freeServicePort(allocate = probeServicePort) {
|
|
18595
|
+
for (let attempt = 0;attempt < 32; attempt += 1) {
|
|
18596
|
+
const port = await allocate();
|
|
18597
|
+
if (validServicePort(String(port)))
|
|
18598
|
+
return String(port);
|
|
18599
|
+
}
|
|
18600
|
+
throw new Error("Unable to allocate an unreserved service port");
|
|
18601
|
+
}
|
|
18602
|
+
function validServicePort(value) {
|
|
18603
|
+
const port = Number(value);
|
|
18604
|
+
return value !== undefined && String(port) === value && Number.isInteger(port) && port > 0 && port <= 65535 && port !== DEFAULT_GATEWAY_PORT && port !== DEFAULT_CONTROL_MCP_PORT ? value : undefined;
|
|
18605
|
+
}
|
|
18606
|
+
async function probeServicePort() {
|
|
18607
|
+
return new Promise((resolve, reject) => {
|
|
18608
|
+
const probe = createServer();
|
|
18609
|
+
probe.once("error", reject);
|
|
18610
|
+
probe.listen(0, "127.0.0.1", () => {
|
|
18611
|
+
const address = probe.address();
|
|
18612
|
+
probe.close(() => resolve(typeof address === "object" && address ? address.port : 0));
|
|
18613
|
+
});
|
|
18614
|
+
});
|
|
18615
|
+
}
|
|
18616
|
+
function portArgument(args) {
|
|
18617
|
+
const index = args?.indexOf("--port") ?? -1;
|
|
18618
|
+
return index >= 0 ? args?.[index + 1] : undefined;
|
|
18619
|
+
}
|
|
18035
18620
|
function runManager(argv, allowFailure = false) {
|
|
18036
|
-
const result =
|
|
18621
|
+
const result = spawnSync2(argv[0], argv.slice(1), { encoding: "utf8", timeout: 60000 });
|
|
18037
18622
|
const ok = result.status === 0;
|
|
18038
18623
|
if (!ok && !allowFailure) {
|
|
18039
18624
|
throw new CliError("operation-failed", `${argv.join(" ")} failed: ${(result.stderr || result.stdout || "").trim().slice(0, 300)}`);
|
|
@@ -18055,10 +18640,19 @@ var serviceCommands = [
|
|
|
18055
18640
|
"With none, in a terminal, it asks how clients will connect (Tailscale Serve, the",
|
|
18056
18641
|
"tailnet address or SSH) and prints the equivalent command; --yes skips the questions.",
|
|
18057
18642
|
"The Bun running this command is the Bun the service uses; reinstall to change it.",
|
|
18643
|
+
"",
|
|
18644
|
+
"Only the default data directory's backend uses the fixed gateway port. With another",
|
|
18645
|
+
"--data-dir and no `--port`, the backend takes a free port that changes on each start,",
|
|
18646
|
+
"so pass `-- --port PORT` for a stable address. --tailscale-serve gets a free port",
|
|
18647
|
+
"chosen once, here, with strict binding so it cannot move to a fallback port.",
|
|
18058
18648
|
"On Linux, run `loginctl enable-linger $USER` so the service runs without a login.",
|
|
18059
18649
|
"",
|
|
18060
18650
|
"Once the service is running, the address it serves and its gateway token are printed.",
|
|
18061
|
-
"The token is shown only in this terminal: never in --output json or the service log."
|
|
18651
|
+
"The token is shown only in this terminal: never in --output json or the service log.",
|
|
18652
|
+
"If the release cannot start, the command fails with what the service logged.",
|
|
18653
|
+
"",
|
|
18654
|
+
"On Linux, --tailscale-serve needs `sudo tailscale set --operator=$USER` once; the",
|
|
18655
|
+
"questions offer to run it, and a scripted install warns when it is missing."
|
|
18062
18656
|
].join(`
|
|
18063
18657
|
`),
|
|
18064
18658
|
positionals: [],
|
|
@@ -18115,13 +18709,30 @@ var serviceCommands = [
|
|
|
18115
18709
|
if (readyWaitMs > PUBLIC_API_LIMITS.waitMaxMs) {
|
|
18116
18710
|
throw new CliError("invalid-input", "--timeout may be at most 24h");
|
|
18117
18711
|
}
|
|
18118
|
-
const
|
|
18712
|
+
const secondBackend = !isDefaultDataDir(dataDir, process.platform, context.io.env);
|
|
18713
|
+
const requestedArgs = interactive ? await askServeArguments(context.io, {
|
|
18119
18714
|
installCommand: installCommandLine(parsed),
|
|
18120
|
-
signal: context.signal
|
|
18715
|
+
signal: context.signal,
|
|
18716
|
+
dryRun: parsed.options["dry-run"] === true,
|
|
18717
|
+
secondBackend
|
|
18121
18718
|
}) : parsed.rest;
|
|
18719
|
+
if (!interactive)
|
|
18720
|
+
warnIfTailscaleOperatorNeeded(context.io, requestedArgs);
|
|
18122
18721
|
const bun = process.execPath;
|
|
18123
18722
|
const bunVersion = typeof Bun === "undefined" ? "" : Bun.version;
|
|
18124
18723
|
const { service, layout, unit } = await unitFor(context, dataDir, bun);
|
|
18724
|
+
const pinsPort = secondBackend && requestedArgs.includes("--tailscale-serve") && !requestedArgs.includes("--port");
|
|
18725
|
+
const serveArgs = pinsPort && parsed.options["dry-run"] !== true ? [
|
|
18726
|
+
...requestedArgs,
|
|
18727
|
+
"--port",
|
|
18728
|
+
validServicePort(portArgument(service.readServiceConfig(layout)?.args)) ?? await freeServicePort(),
|
|
18729
|
+
"--strict-gateway-port"
|
|
18730
|
+
] : requestedArgs;
|
|
18731
|
+
const portNote = pinsPort ? [
|
|
18732
|
+
"This is not the default data directory, so its gateway keeps a free port chosen at install instead of the fixed one."
|
|
18733
|
+
] : secondBackend && !requestedArgs.includes("--port") ? [
|
|
18734
|
+
"This is not the default data directory, so its gateway takes a free port that changes on each start. For a stable address, reinstall with `-- --port PORT`."
|
|
18735
|
+
] : [];
|
|
18125
18736
|
const summary = {
|
|
18126
18737
|
dataDir,
|
|
18127
18738
|
version,
|
|
@@ -18143,6 +18754,7 @@ var serviceCommands = [
|
|
|
18143
18754
|
["unit", `${unit.manager} ${unit.name} \u2192 ${unit.file}`],
|
|
18144
18755
|
["serve arguments", serveArgs.join(" ") || "(none)"]
|
|
18145
18756
|
]),
|
|
18757
|
+
...portNote,
|
|
18146
18758
|
"",
|
|
18147
18759
|
"Dry run: nothing was installed."
|
|
18148
18760
|
]
|
|
@@ -18158,13 +18770,17 @@ var serviceCommands = [
|
|
|
18158
18770
|
throw new CliError("operation-failed", `Could not install orkestrator@${version}: ${error instanceof Error ? error.message : String(error)}`, { retryable: true });
|
|
18159
18771
|
}
|
|
18160
18772
|
await service.installLauncher(layout, releaseDir);
|
|
18773
|
+
const rollbackTarget = service.nextRollbackTarget(layout, service.readServiceConfig(layout), service.linkedVersion(layout.current), version);
|
|
18161
18774
|
await service.activateRelease(layout, version);
|
|
18775
|
+
const installGeneration = randomUUID4();
|
|
18162
18776
|
await service.writeServiceConfig(layout, {
|
|
18777
|
+
installGeneration,
|
|
18163
18778
|
version: 1,
|
|
18164
18779
|
dataDir,
|
|
18165
18780
|
bun,
|
|
18166
18781
|
bunVersion,
|
|
18167
18782
|
args: serveArgs,
|
|
18783
|
+
...rollbackTarget ? { rollbackTarget } : {},
|
|
18168
18784
|
installedAt: new Date().toISOString()
|
|
18169
18785
|
});
|
|
18170
18786
|
await mkdir2(layout.logs, { recursive: true });
|
|
@@ -18175,6 +18791,8 @@ var serviceCommands = [
|
|
|
18175
18791
|
let connection = null;
|
|
18176
18792
|
if (started) {
|
|
18177
18793
|
const previousGeneration = await currentDescriptorGeneration(dataDir);
|
|
18794
|
+
const loadedAt = Date.now();
|
|
18795
|
+
const logOffset = await stat2(logFile).then((file) => file.size, () => 0);
|
|
18178
18796
|
const commands = serviceManagerCommands(unit);
|
|
18179
18797
|
commands.load.forEach((argv, index) => runManager(argv, unit.manager === "launchd" && index === 0));
|
|
18180
18798
|
if (readyWaitMs > 0) {
|
|
@@ -18182,7 +18800,13 @@ var serviceCommands = [
|
|
|
18182
18800
|
`);
|
|
18183
18801
|
connection = await awaitServiceConnection(dataDir, previousGeneration, {
|
|
18184
18802
|
timeoutMs: readyWaitMs,
|
|
18185
|
-
signal: context.signal
|
|
18803
|
+
signal: context.signal,
|
|
18804
|
+
expectedVersion: version,
|
|
18805
|
+
assertStarting: async () => {
|
|
18806
|
+
const failure = service.readStartupFailure(layout, version, loadedAt, installGeneration);
|
|
18807
|
+
if (failure)
|
|
18808
|
+
throw await startupFailedError(version, failure, logFile, logOffset);
|
|
18809
|
+
}
|
|
18186
18810
|
});
|
|
18187
18811
|
}
|
|
18188
18812
|
}
|
|
@@ -18193,6 +18817,7 @@ var serviceCommands = [
|
|
|
18193
18817
|
started,
|
|
18194
18818
|
ready: connection !== null,
|
|
18195
18819
|
browserUrl: connection?.browserUrl ?? null,
|
|
18820
|
+
clientUrls: connection?.clientUrls ?? [],
|
|
18196
18821
|
authFile: connection?.authFile ?? null,
|
|
18197
18822
|
...connection?.credentialError ? { credentialError: connection.credentialError } : {},
|
|
18198
18823
|
...summary
|
|
@@ -18209,6 +18834,7 @@ var serviceCommands = [
|
|
|
18209
18834
|
"",
|
|
18210
18835
|
...keyValues([
|
|
18211
18836
|
["address", connection.browserUrl ?? "(no browser listener; see the log)"],
|
|
18837
|
+
...connection.clientUrls.length > 0 ? [["local listeners", connection.clientUrls.join(", ")]] : [],
|
|
18212
18838
|
["auth file", connection.authFile],
|
|
18213
18839
|
...context.io.stdoutIsTty && context.global.output === "human" && connection.token ? [["token", connection.token]] : []
|
|
18214
18840
|
]),
|
|
@@ -18217,6 +18843,7 @@ var serviceCommands = [
|
|
|
18217
18843
|
"",
|
|
18218
18844
|
`The backend has not reported ready yet. Follow ${logFile}; its address and token file are logged there.`
|
|
18219
18845
|
] : [],
|
|
18846
|
+
...portNote,
|
|
18220
18847
|
...unit.manager === "systemd" ? ["Run `loginctl enable-linger $USER` so it keeps running after you log out."] : []
|
|
18221
18848
|
]
|
|
18222
18849
|
};
|
|
@@ -18269,15 +18896,17 @@ var serviceCommands = [
|
|
|
18269
18896
|
const state = service.readLauncherState(layout);
|
|
18270
18897
|
const installed = existsSync6(unit.file);
|
|
18271
18898
|
const running = installed ? runManager(serviceManagerCommands(unit).status, true).ok : false;
|
|
18899
|
+
const current = service.linkedVersion(layout.current);
|
|
18900
|
+
const previous = service.linkedVersion(layout.previous);
|
|
18272
18901
|
const result = {
|
|
18273
18902
|
dataDir,
|
|
18274
18903
|
installed,
|
|
18275
18904
|
running,
|
|
18276
18905
|
unit: { manager: unit.manager, name: unit.name, file: unit.file },
|
|
18277
|
-
current
|
|
18278
|
-
previous
|
|
18906
|
+
current,
|
|
18907
|
+
previous,
|
|
18279
18908
|
bun: config?.bun ?? null,
|
|
18280
|
-
args: config
|
|
18909
|
+
args: service.effectiveServiceArguments(config, current, previous),
|
|
18281
18910
|
lastReadyVersion: state.lastReadyVersion,
|
|
18282
18911
|
rollback: state.rollback
|
|
18283
18912
|
};
|
|
@@ -18850,6 +19479,345 @@ var runCommands = [
|
|
|
18850
19479
|
}
|
|
18851
19480
|
];
|
|
18852
19481
|
|
|
19482
|
+
// src/client/commands/session-goal.ts
|
|
19483
|
+
var WAIT_OPTIONS2 = [
|
|
19484
|
+
{
|
|
19485
|
+
name: "wait",
|
|
19486
|
+
kind: "boolean",
|
|
19487
|
+
description: "Observe the goal until it stops. Exit 0 for complete, 10 claimed, 11 blocked, 12 limited, 13 paused, 14 cleared or replaced."
|
|
19488
|
+
},
|
|
19489
|
+
TIMEOUT_OPTION,
|
|
19490
|
+
{
|
|
19491
|
+
name: "continue-on-interaction",
|
|
19492
|
+
kind: "boolean",
|
|
19493
|
+
description: "While waiting, keep waiting when a turn needs an answer (another client may answer)."
|
|
19494
|
+
}
|
|
19495
|
+
];
|
|
19496
|
+
var LIMIT_OPTIONS = [
|
|
19497
|
+
{
|
|
19498
|
+
name: "max-iterations",
|
|
19499
|
+
kind: "integer",
|
|
19500
|
+
valueName: "N",
|
|
19501
|
+
description: `Turns the backend may send, at most ${NATIVE_AGENT_GOAL_LIMITS.maxIterationsLimit}.`
|
|
19502
|
+
},
|
|
19503
|
+
{
|
|
19504
|
+
name: "budget",
|
|
19505
|
+
kind: "integer",
|
|
19506
|
+
valueName: "TOKENS",
|
|
19507
|
+
description: "Tokens the goal may spend; refused where the provider reports no usage."
|
|
19508
|
+
}
|
|
19509
|
+
];
|
|
19510
|
+
var LIMIT_FIELDS = { budget: "tokenBudget" };
|
|
19511
|
+
function limitsInput(options2) {
|
|
19512
|
+
return {
|
|
19513
|
+
...options2["max-iterations"] !== undefined ? { maxIterations: options2["max-iterations"] } : {},
|
|
19514
|
+
...options2.budget !== undefined ? { tokenBudget: options2.budget } : {}
|
|
19515
|
+
};
|
|
19516
|
+
}
|
|
19517
|
+
function goalLines(read) {
|
|
19518
|
+
const goal = read.goal;
|
|
19519
|
+
if (!goal)
|
|
19520
|
+
return ["no goal"];
|
|
19521
|
+
return keyValues([
|
|
19522
|
+
["goal", goal.goalId],
|
|
19523
|
+
["status", goal.status],
|
|
19524
|
+
["reason", read.description],
|
|
19525
|
+
["iterations", `${goal.iterations}/${goal.maxIterations}`],
|
|
19526
|
+
[
|
|
19527
|
+
"tokens",
|
|
19528
|
+
goal.tokenBudget !== undefined ? `${goal.tokensUsed ?? 0}/${goal.tokenBudget}` : undefined
|
|
19529
|
+
],
|
|
19530
|
+
["check", goal.check],
|
|
19531
|
+
[
|
|
19532
|
+
"verifier",
|
|
19533
|
+
goal.verifier ? `${goal.verifier.agent}${goal.verifier.model ? `:${goal.verifier.model}` : ""}` : undefined
|
|
19534
|
+
],
|
|
19535
|
+
["last check", goal.lastCheck ? goal.lastCheck.passed ? "passed" : "failed" : undefined],
|
|
19536
|
+
["objective", goal.objective]
|
|
19537
|
+
]);
|
|
19538
|
+
}
|
|
19539
|
+
function goalDetails(sessionId, goal) {
|
|
19540
|
+
return {
|
|
19541
|
+
sessionId,
|
|
19542
|
+
goalId: goal.goalId,
|
|
19543
|
+
status: goal.status,
|
|
19544
|
+
...goal.statusReason ? { statusReason: goal.statusReason } : {},
|
|
19545
|
+
iterations: goal.iterations,
|
|
19546
|
+
maxIterations: goal.maxIterations
|
|
19547
|
+
};
|
|
19548
|
+
}
|
|
19549
|
+
var STOPPED_MESSAGES = {
|
|
19550
|
+
"goal-claimed": "The agent says the goal is done, and nothing verified it",
|
|
19551
|
+
"goal-blocked": "The goal is blocked: the agent says it needs a person",
|
|
19552
|
+
"goal-limited": "The goal reached its iteration cap or token budget",
|
|
19553
|
+
"goal-paused": "The goal is paused"
|
|
19554
|
+
};
|
|
19555
|
+
async function waitForGoal(context, session, sessionId, goalId, timeoutMs, options2) {
|
|
19556
|
+
let latest;
|
|
19557
|
+
const receiptOption = options2.receipt ? { receipt: options2.receipt } : {};
|
|
19558
|
+
try {
|
|
19559
|
+
return await observe(async () => {
|
|
19560
|
+
const read = await session.read("session.goal.get", {
|
|
19561
|
+
sessionId,
|
|
19562
|
+
...options2.includeCheckOutput ? { includeCheckOutput: true } : {}
|
|
19563
|
+
});
|
|
19564
|
+
const verdict = classifyGoalForWait(read, goalId, {
|
|
19565
|
+
continueOnInteraction: options2.continueOnInteraction
|
|
19566
|
+
});
|
|
19567
|
+
if (verdict.kind === "pending") {
|
|
19568
|
+
latest = verdict.goal;
|
|
19569
|
+
return { done: false };
|
|
19570
|
+
}
|
|
19571
|
+
if (verdict.kind === "complete")
|
|
19572
|
+
return {
|
|
19573
|
+
done: true,
|
|
19574
|
+
value: {
|
|
19575
|
+
...read,
|
|
19576
|
+
goal: verdict.goal,
|
|
19577
|
+
description: "Complete",
|
|
19578
|
+
...read.goal?.goalId !== goalId ? { checkOutput: undefined } : {}
|
|
19579
|
+
}
|
|
19580
|
+
};
|
|
19581
|
+
if (verdict.kind === "interaction") {
|
|
19582
|
+
throw new CliError("interaction-required", "The goal's turn is waiting for an answer to a pending interaction", {
|
|
19583
|
+
...receiptOption,
|
|
19584
|
+
details: {
|
|
19585
|
+
...goalDetails(sessionId, verdict.goal),
|
|
19586
|
+
pendingInteractionCount: read.pendingInteractionCount
|
|
19587
|
+
}
|
|
19588
|
+
});
|
|
19589
|
+
}
|
|
19590
|
+
if (verdict.kind === "gone") {
|
|
19591
|
+
throw new CliError("goal-gone", "The goal was cleared or replaced before it ended", {
|
|
19592
|
+
...receiptOption,
|
|
19593
|
+
details: {
|
|
19594
|
+
sessionId,
|
|
19595
|
+
goalId,
|
|
19596
|
+
...verdict.goal ? { status: verdict.goal.status } : {}
|
|
19597
|
+
}
|
|
19598
|
+
});
|
|
19599
|
+
}
|
|
19600
|
+
throw new CliError(verdict.code, STOPPED_MESSAGES[verdict.code], {
|
|
19601
|
+
...receiptOption,
|
|
19602
|
+
details: goalDetails(sessionId, verdict.goal)
|
|
19603
|
+
});
|
|
19604
|
+
}, { timeoutMs, signal: context.signal });
|
|
19605
|
+
} catch (error) {
|
|
19606
|
+
if (!(error instanceof ObservationStopped))
|
|
19607
|
+
throw error;
|
|
19608
|
+
const details = { sessionId, goalId, ...latest ? goalDetails(sessionId, latest) : {} };
|
|
19609
|
+
if (error.reason === "signal") {
|
|
19610
|
+
throw new CliError("observation-interrupted", "Stopped observing the goal; it continues in the backend", { ...receiptOption, details: { ...details, signal: signalName(context.signal) } });
|
|
19611
|
+
}
|
|
19612
|
+
throw new CliError("deadline-exceeded", "Timed out observing the goal; it continues in the backend. `session goal get --wait` observes it again", { ...receiptOption, details });
|
|
19613
|
+
}
|
|
19614
|
+
}
|
|
19615
|
+
function waitOutcome(base, read) {
|
|
19616
|
+
return {
|
|
19617
|
+
...base,
|
|
19618
|
+
result: read,
|
|
19619
|
+
human: goalLines(read),
|
|
19620
|
+
ids: read.goal ? [read.goal.goalId] : []
|
|
19621
|
+
};
|
|
19622
|
+
}
|
|
19623
|
+
async function runLoopMutation(context, parsed, action, input) {
|
|
19624
|
+
const options2 = parsed.options;
|
|
19625
|
+
const sessionId = parsed.positionals.session;
|
|
19626
|
+
validateWaitOptions(options2);
|
|
19627
|
+
if (options2.wait !== true) {
|
|
19628
|
+
const { session, result, receipt, warnings } = await submit(context, action, input, options2);
|
|
19629
|
+
return {
|
|
19630
|
+
action,
|
|
19631
|
+
result,
|
|
19632
|
+
receipt,
|
|
19633
|
+
warnings,
|
|
19634
|
+
connection: session.identity,
|
|
19635
|
+
ids: result.goal ? [result.goal.goalId] : [],
|
|
19636
|
+
human: result.goal ? keyValues([
|
|
19637
|
+
["goal", result.goal.goalId],
|
|
19638
|
+
["status", result.goal.status],
|
|
19639
|
+
["iterations", `${result.goal.iterations}/${result.goal.maxIterations}`]
|
|
19640
|
+
]) : receipt ? receiptLines(receipt) : []
|
|
19641
|
+
};
|
|
19642
|
+
}
|
|
19643
|
+
const budget = options2.timeout ?? DEFAULT_WAIT_MS;
|
|
19644
|
+
const started = Date.now();
|
|
19645
|
+
const submitted = await submitForWait(context, action, input, options2, budget);
|
|
19646
|
+
const { session, warnings } = submitted;
|
|
19647
|
+
let receipt = submitted.receipt;
|
|
19648
|
+
let mutation = submitted.result;
|
|
19649
|
+
if (!mutation && receipt) {
|
|
19650
|
+
receipt = await waitForOperation(context, session, receipt, budget - (Date.now() - started));
|
|
19651
|
+
const failure = receiptFailure(receipt);
|
|
19652
|
+
if (failure)
|
|
19653
|
+
throw failure;
|
|
19654
|
+
mutation = receipt.result;
|
|
19655
|
+
}
|
|
19656
|
+
const goalId = mutation?.goal?.goalId;
|
|
19657
|
+
if (!goalId)
|
|
19658
|
+
throw new CliError("response-invalid", `${action} returned no goal`);
|
|
19659
|
+
const read = await waitForGoal(context, session, sessionId, goalId, Math.max(0, budget - (Date.now() - started)), {
|
|
19660
|
+
continueOnInteraction: options2["continue-on-interaction"] === true,
|
|
19661
|
+
...receipt ? { receipt } : {}
|
|
19662
|
+
});
|
|
19663
|
+
return waitOutcome({ action, result: read, receipt, warnings, connection: session.identity }, read);
|
|
19664
|
+
}
|
|
19665
|
+
var sessionGoalCommands = [
|
|
19666
|
+
{
|
|
19667
|
+
path: ["session", "goal", "set"],
|
|
19668
|
+
action: "session.goal.set",
|
|
19669
|
+
summary: "Give a session a goal: the backend sends turns until a check proves it or it stops.",
|
|
19670
|
+
description: "Pass the objective with --objective, --objective-file or --objective-stdin. Without --check or --verifier, a done report ends the goal as claimed: nothing verified it, and --wait exits 10. A session holds one goal, and a running goal is refused (exit 8) until it is cleared. A goal never changes the permission mode, so an approval still parks a turn (--wait exits 6).",
|
|
19671
|
+
positionals: [{ name: "session", required: true }],
|
|
19672
|
+
options: [
|
|
19673
|
+
{
|
|
19674
|
+
name: "objective-file",
|
|
19675
|
+
kind: "string",
|
|
19676
|
+
valueName: "PATH",
|
|
19677
|
+
description: "Read the objective from a local file."
|
|
19678
|
+
},
|
|
19679
|
+
{ name: "objective-stdin", kind: "boolean", description: "Read the objective from stdin." },
|
|
19680
|
+
{ name: "objective", kind: "string", valueName: "TEXT", description: "Inline objective." },
|
|
19681
|
+
{
|
|
19682
|
+
name: "check",
|
|
19683
|
+
kind: "string",
|
|
19684
|
+
valueName: "COMMAND",
|
|
19685
|
+
description: "One-line shell command run in the workspace on a done report; exit 0 completes the goal."
|
|
19686
|
+
},
|
|
19687
|
+
{
|
|
19688
|
+
name: "verifier",
|
|
19689
|
+
kind: "string",
|
|
19690
|
+
valueName: "AGENT[:MODEL]",
|
|
19691
|
+
description: "A fresh read-only session on that agent judges the work on a done report; with --check, both must pass."
|
|
19692
|
+
},
|
|
19693
|
+
...LIMIT_OPTIONS,
|
|
19694
|
+
...WAIT_OPTIONS2,
|
|
19695
|
+
REQUEST_ID_OPTION
|
|
19696
|
+
],
|
|
19697
|
+
inputFields: { ...LIMIT_FIELDS, "objective-file": "objective", "objective-stdin": "objective" },
|
|
19698
|
+
idOutput: "goal ID",
|
|
19699
|
+
examples: [
|
|
19700
|
+
'orkestrator session goal set ses_\u2026 --objective "Make the tests pass" --check "bun test" --max-iterations 10 --wait --timeout 2h'
|
|
19701
|
+
],
|
|
19702
|
+
async run(context, parsed) {
|
|
19703
|
+
const options2 = parsed.options;
|
|
19704
|
+
validateWaitOptions(options2);
|
|
19705
|
+
const verifier = options2.verifier === undefined ? undefined : parseVerifierFlag(String(options2.verifier));
|
|
19706
|
+
if (verifier && "error" in verifier)
|
|
19707
|
+
throw new CliError("invalid-input", verifier.error);
|
|
19708
|
+
const objective = await readTextSource(context.io, {
|
|
19709
|
+
file: options2["objective-file"],
|
|
19710
|
+
stdin: options2["objective-stdin"],
|
|
19711
|
+
inline: options2.objective,
|
|
19712
|
+
label: "Objective",
|
|
19713
|
+
maxBytes: NATIVE_AGENT_GOAL_LIMITS.objectiveMaxChars * 4,
|
|
19714
|
+
names: {
|
|
19715
|
+
file: "--objective-file",
|
|
19716
|
+
stdin: "--objective-stdin",
|
|
19717
|
+
inline: "--objective"
|
|
19718
|
+
},
|
|
19719
|
+
required: true
|
|
19720
|
+
});
|
|
19721
|
+
return runLoopMutation(context, parsed, "session.goal.set", {
|
|
19722
|
+
sessionId: parsed.positionals.session,
|
|
19723
|
+
objective,
|
|
19724
|
+
...options2.check !== undefined ? { check: options2.check } : {},
|
|
19725
|
+
...verifier ? { verifier } : {},
|
|
19726
|
+
...limitsInput(options2)
|
|
19727
|
+
});
|
|
19728
|
+
}
|
|
19729
|
+
},
|
|
19730
|
+
{
|
|
19731
|
+
path: ["session", "goal", "get"],
|
|
19732
|
+
action: "session.goal.get",
|
|
19733
|
+
summary: "Show a session's goal: status, iterations, limits and the last check.",
|
|
19734
|
+
description: "Reads the session record and starts nothing. With no goal the result's goal is null and the exit is 0, unless --wait is given, which exits 14. --wait observes the goal the session holds now, so it picks up a goal after an earlier --wait timed out.",
|
|
19735
|
+
positionals: [{ name: "session", required: true }],
|
|
19736
|
+
options: [
|
|
19737
|
+
{
|
|
19738
|
+
name: "check-output",
|
|
19739
|
+
kind: "boolean",
|
|
19740
|
+
description: "Include the last check's output tail. It is untrusted command output."
|
|
19741
|
+
},
|
|
19742
|
+
...WAIT_OPTIONS2
|
|
19743
|
+
],
|
|
19744
|
+
inputFields: { "check-output": "includeCheckOutput" },
|
|
19745
|
+
idOutput: "goal ID",
|
|
19746
|
+
async run(context, parsed) {
|
|
19747
|
+
const options2 = parsed.options;
|
|
19748
|
+
validateWaitOptions(options2);
|
|
19749
|
+
const sessionId = parsed.positionals.session;
|
|
19750
|
+
const session = await context.session();
|
|
19751
|
+
const first = await session.read("session.goal.get", {
|
|
19752
|
+
sessionId,
|
|
19753
|
+
...options2["check-output"] === true ? { includeCheckOutput: true } : {}
|
|
19754
|
+
});
|
|
19755
|
+
const base = { action: "session.goal.get", connection: session.identity };
|
|
19756
|
+
if (options2.wait !== true)
|
|
19757
|
+
return waitOutcome({ ...base, result: first }, first);
|
|
19758
|
+
const goalId = first.goal?.goalId;
|
|
19759
|
+
if (!goalId) {
|
|
19760
|
+
throw new CliError("goal-gone", "The session has no goal to wait for", {
|
|
19761
|
+
details: { sessionId }
|
|
19762
|
+
});
|
|
19763
|
+
}
|
|
19764
|
+
const read = await waitForGoal(context, session, sessionId, goalId, options2.timeout ?? DEFAULT_WAIT_MS, {
|
|
19765
|
+
continueOnInteraction: options2["continue-on-interaction"] === true,
|
|
19766
|
+
includeCheckOutput: options2["check-output"] === true
|
|
19767
|
+
});
|
|
19768
|
+
return waitOutcome({ ...base, result: read }, read);
|
|
19769
|
+
}
|
|
19770
|
+
},
|
|
19771
|
+
{
|
|
19772
|
+
path: ["session", "goal", "pause"],
|
|
19773
|
+
action: "session.goal.pause",
|
|
19774
|
+
summary: "Pause a running goal; no further turn starts until it is resumed.",
|
|
19775
|
+
description: "A turn already running finishes. Use `session stop` to stop it too. Refused (exit 8) when no goal is running.",
|
|
19776
|
+
positionals: [{ name: "session", required: true }],
|
|
19777
|
+
options: [REQUEST_ID_OPTION],
|
|
19778
|
+
idOutput: "goal ID",
|
|
19779
|
+
run: (context, parsed) => runGoalControl(context, parsed, "session.goal.pause")
|
|
19780
|
+
},
|
|
19781
|
+
{
|
|
19782
|
+
path: ["session", "goal", "resume"],
|
|
19783
|
+
action: "session.goal.resume",
|
|
19784
|
+
summary: "Resume a stopped goal, optionally with a higher limit.",
|
|
19785
|
+
description: "A goal stopped by its limit needs a higher --max-iterations or --budget. An ended goal (claimed, complete) cannot resume; set a new one. Refused with exit 8.",
|
|
19786
|
+
positionals: [{ name: "session", required: true }],
|
|
19787
|
+
options: [...LIMIT_OPTIONS, ...WAIT_OPTIONS2, REQUEST_ID_OPTION],
|
|
19788
|
+
inputFields: LIMIT_FIELDS,
|
|
19789
|
+
idOutput: "goal ID",
|
|
19790
|
+
run: (context, parsed) => runLoopMutation(context, parsed, "session.goal.resume", {
|
|
19791
|
+
sessionId: parsed.positionals.session,
|
|
19792
|
+
...limitsInput(parsed.options)
|
|
19793
|
+
})
|
|
19794
|
+
},
|
|
19795
|
+
{
|
|
19796
|
+
path: ["session", "goal", "clear"],
|
|
19797
|
+
action: "session.goal.clear",
|
|
19798
|
+
summary: "Remove a session's goal, in any status.",
|
|
19799
|
+
description: "What the agent did stays, and the goal stays readable in the goal history. A session with no goal stays that way and exits 0.",
|
|
19800
|
+
positionals: [{ name: "session", required: true }],
|
|
19801
|
+
options: [REQUEST_ID_OPTION],
|
|
19802
|
+
idOutput: "goal ID",
|
|
19803
|
+
run: (context, parsed) => runGoalControl(context, parsed, "session.goal.clear")
|
|
19804
|
+
}
|
|
19805
|
+
];
|
|
19806
|
+
async function runGoalControl(context, parsed, action) {
|
|
19807
|
+
const { session, result, receipt, warnings } = await submit(context, action, { sessionId: parsed.positionals.session }, parsed.options);
|
|
19808
|
+
return {
|
|
19809
|
+
action,
|
|
19810
|
+
result,
|
|
19811
|
+
receipt,
|
|
19812
|
+
warnings,
|
|
19813
|
+
connection: session.identity,
|
|
19814
|
+
ids: result.goal ? [result.goal.goalId] : [],
|
|
19815
|
+
human: action === "session.goal.clear" ? [result.cleared ? "cleared" : "no goal"] : [
|
|
19816
|
+
`paused${result.goal ? ` at ${result.goal.iterations}/${result.goal.maxIterations}` : ""}`
|
|
19817
|
+
]
|
|
19818
|
+
};
|
|
19819
|
+
}
|
|
19820
|
+
|
|
18853
19821
|
// src/client/commands/ticket.ts
|
|
18854
19822
|
var STATUSES = ["backlog", "in-progress", "review", "done"];
|
|
18855
19823
|
var KINDS3 = ["feature", "work-brief"];
|
|
@@ -19267,6 +20235,742 @@ var toolchainCommands = [
|
|
|
19267
20235
|
}
|
|
19268
20236
|
];
|
|
19269
20237
|
|
|
20238
|
+
// ../protocol/src/public-api-inputs-pr.ts
|
|
20239
|
+
var PUBLIC_PR_BODY_MAX_CHARS = 65536;
|
|
20240
|
+
var PUBLIC_PR_REVIEW_COMMENTS_MAX = 200;
|
|
20241
|
+
var PUBLIC_PR_REVIEWERS_MAX = 100;
|
|
20242
|
+
var PUBLIC_PR_MERGE_METHODS = Object.freeze(["squash", "merge", "rebase"]);
|
|
20243
|
+
var PUBLIC_PR_LIST_FILTERS = Object.freeze([
|
|
20244
|
+
"open",
|
|
20245
|
+
"mine",
|
|
20246
|
+
"review-requested",
|
|
20247
|
+
"closed"
|
|
20248
|
+
]);
|
|
20249
|
+
var PUBLIC_PR_REVIEW_EVENTS = Object.freeze([
|
|
20250
|
+
"APPROVE",
|
|
20251
|
+
"REQUEST_CHANGES",
|
|
20252
|
+
"COMMENT"
|
|
20253
|
+
]);
|
|
20254
|
+
var PUBLIC_PR_SIDES = Object.freeze(["LEFT", "RIGHT"]);
|
|
20255
|
+
function schema4(properties, required = []) {
|
|
20256
|
+
return { type: "object", properties, required, additionalProperties: false };
|
|
20257
|
+
}
|
|
20258
|
+
var environmentId = {
|
|
20259
|
+
type: "string",
|
|
20260
|
+
minLength: 1,
|
|
20261
|
+
maxLength: PUBLIC_API_LIMITS.idMaxChars,
|
|
20262
|
+
description: "Environment ID, from environment.list. Its attached pull request is the target."
|
|
20263
|
+
};
|
|
20264
|
+
var projectId = {
|
|
20265
|
+
type: "string",
|
|
20266
|
+
minLength: 1,
|
|
20267
|
+
maxLength: PUBLIC_API_LIMITS.idMaxChars,
|
|
20268
|
+
description: "Project ID, from project.list."
|
|
20269
|
+
};
|
|
20270
|
+
var body = {
|
|
20271
|
+
type: "string",
|
|
20272
|
+
minLength: 1,
|
|
20273
|
+
maxLength: PUBLIC_PR_BODY_MAX_CHARS,
|
|
20274
|
+
description: "Markdown text, posted as the GitHub user configured in Settings."
|
|
20275
|
+
};
|
|
20276
|
+
var filePath = {
|
|
20277
|
+
type: "string",
|
|
20278
|
+
minLength: 1,
|
|
20279
|
+
maxLength: PUBLIC_API_LIMITS.pathMaxChars,
|
|
20280
|
+
description: "Repository-relative path of a changed file, from pr.files."
|
|
20281
|
+
};
|
|
20282
|
+
var threadId = {
|
|
20283
|
+
type: "string",
|
|
20284
|
+
minLength: 1,
|
|
20285
|
+
maxLength: PUBLIC_API_LIMITS.idMaxChars,
|
|
20286
|
+
description: "Review thread ID, from pr.files."
|
|
20287
|
+
};
|
|
20288
|
+
var commitSha = {
|
|
20289
|
+
type: "string",
|
|
20290
|
+
minLength: 40,
|
|
20291
|
+
maxLength: 40
|
|
20292
|
+
};
|
|
20293
|
+
var line = {
|
|
20294
|
+
type: "integer",
|
|
20295
|
+
minimum: 1,
|
|
20296
|
+
description: "Line in the new file (RIGHT) or the old file (LEFT)."
|
|
20297
|
+
};
|
|
20298
|
+
var side = {
|
|
20299
|
+
type: "string",
|
|
20300
|
+
enum: PUBLIC_PR_SIDES,
|
|
20301
|
+
description: "RIGHT: the new file. LEFT: the old file."
|
|
20302
|
+
};
|
|
20303
|
+
var startLine = {
|
|
20304
|
+
type: "integer",
|
|
20305
|
+
minimum: 1,
|
|
20306
|
+
description: "First line of a multi-line comment; below line."
|
|
20307
|
+
};
|
|
20308
|
+
var reviewerList = {
|
|
20309
|
+
type: "array",
|
|
20310
|
+
maxItems: PUBLIC_PR_REVIEWERS_MAX,
|
|
20311
|
+
items: { type: "string", minLength: 1, maxLength: PUBLIC_API_LIMITS.nameMaxChars }
|
|
20312
|
+
};
|
|
20313
|
+
var environmentOnly = schema4({ environmentId }, ["environmentId"]);
|
|
20314
|
+
var environmentExamples = [{ environmentId: "env-1" }];
|
|
20315
|
+
var PR_ACTION_INPUTS = Object.freeze({
|
|
20316
|
+
"pr.get": {
|
|
20317
|
+
capability: "sessions.read",
|
|
20318
|
+
confirmation: "never",
|
|
20319
|
+
input: environmentOnly,
|
|
20320
|
+
examples: environmentExamples
|
|
20321
|
+
},
|
|
20322
|
+
"pr.list": {
|
|
20323
|
+
capability: "sessions.read",
|
|
20324
|
+
confirmation: "never",
|
|
20325
|
+
input: schema4({
|
|
20326
|
+
projectId,
|
|
20327
|
+
filter: {
|
|
20328
|
+
type: "string",
|
|
20329
|
+
enum: PUBLIC_PR_LIST_FILTERS,
|
|
20330
|
+
description: "Which pull requests (default open)."
|
|
20331
|
+
},
|
|
20332
|
+
query: {
|
|
20333
|
+
type: "string",
|
|
20334
|
+
minLength: 1,
|
|
20335
|
+
maxLength: 256,
|
|
20336
|
+
description: "Search text, as in the pull request list's search box."
|
|
20337
|
+
}
|
|
20338
|
+
}, ["projectId"]),
|
|
20339
|
+
examples: [{ projectId: "project-1" }, { projectId: "project-1", filter: "closed" }]
|
|
20340
|
+
},
|
|
20341
|
+
"pr.timeline": {
|
|
20342
|
+
capability: "sessions.read",
|
|
20343
|
+
confirmation: "never",
|
|
20344
|
+
input: environmentOnly,
|
|
20345
|
+
examples: environmentExamples
|
|
20346
|
+
},
|
|
20347
|
+
"pr.files": {
|
|
20348
|
+
capability: "sessions.read",
|
|
20349
|
+
confirmation: "never",
|
|
20350
|
+
input: schema4({
|
|
20351
|
+
environmentId,
|
|
20352
|
+
path: {
|
|
20353
|
+
...filePath,
|
|
20354
|
+
description: "Return only this file, with its diff hunks. Omitted: every file without hunks, to keep the result small."
|
|
20355
|
+
}
|
|
20356
|
+
}, ["environmentId"]),
|
|
20357
|
+
examples: [{ environmentId: "env-1" }, { environmentId: "env-1", path: "src/index.ts" }]
|
|
20358
|
+
},
|
|
20359
|
+
"pr.options": {
|
|
20360
|
+
capability: "sessions.read",
|
|
20361
|
+
confirmation: "never",
|
|
20362
|
+
input: environmentOnly,
|
|
20363
|
+
examples: environmentExamples
|
|
20364
|
+
},
|
|
20365
|
+
"pr.merge": {
|
|
20366
|
+
capability: "environments.destructive",
|
|
20367
|
+
confirmation: "always",
|
|
20368
|
+
input: schema4({
|
|
20369
|
+
environmentId,
|
|
20370
|
+
method: {
|
|
20371
|
+
type: "string",
|
|
20372
|
+
enum: PUBLIC_PR_MERGE_METHODS,
|
|
20373
|
+
description: "How to merge (default squash, as on the Merge button)."
|
|
20374
|
+
},
|
|
20375
|
+
deleteBranch: {
|
|
20376
|
+
type: "boolean",
|
|
20377
|
+
description: "Delete the head branch after merging (default true). A project's home checkout keeps its branch."
|
|
20378
|
+
},
|
|
20379
|
+
cleanup: {
|
|
20380
|
+
type: "boolean",
|
|
20381
|
+
description: "Merge and Cleanup: delete this environment and its worktree once the merge is confirmed. Cannot be combined with deleteBranch false."
|
|
20382
|
+
},
|
|
20383
|
+
expectedPrUrl: {
|
|
20384
|
+
type: "string",
|
|
20385
|
+
description: "Refuse if the attached PR or the explicit cleanup/branch effects changed since confirmation."
|
|
20386
|
+
},
|
|
20387
|
+
expectedHeadSha: {
|
|
20388
|
+
...commitSha,
|
|
20389
|
+
description: "headSha from pr.get. The merge is refused if the branch has moved since, so what merges is what was read."
|
|
20390
|
+
}
|
|
20391
|
+
}, ["environmentId"]),
|
|
20392
|
+
examples: [
|
|
20393
|
+
{ environmentId: "env-1" },
|
|
20394
|
+
{ environmentId: "env-1", method: "rebase", deleteBranch: false },
|
|
20395
|
+
{ environmentId: "env-1", cleanup: true },
|
|
20396
|
+
{ environmentId: "env-1", expectedHeadSha: "0123456789abcdef0123456789abcdef01234567" }
|
|
20397
|
+
]
|
|
20398
|
+
},
|
|
20399
|
+
"pr.close": {
|
|
20400
|
+
capability: "sessions.control",
|
|
20401
|
+
confirmation: "always",
|
|
20402
|
+
input: environmentOnly,
|
|
20403
|
+
examples: environmentExamples
|
|
20404
|
+
},
|
|
20405
|
+
"pr.reopen": {
|
|
20406
|
+
capability: "sessions.control",
|
|
20407
|
+
confirmation: "voice",
|
|
20408
|
+
input: environmentOnly,
|
|
20409
|
+
examples: environmentExamples
|
|
20410
|
+
},
|
|
20411
|
+
"pr.ready": {
|
|
20412
|
+
capability: "sessions.control",
|
|
20413
|
+
confirmation: "voice",
|
|
20414
|
+
input: environmentOnly,
|
|
20415
|
+
examples: environmentExamples
|
|
20416
|
+
},
|
|
20417
|
+
"pr.draft": {
|
|
20418
|
+
capability: "sessions.control",
|
|
20419
|
+
confirmation: "voice",
|
|
20420
|
+
input: environmentOnly,
|
|
20421
|
+
examples: environmentExamples
|
|
20422
|
+
},
|
|
20423
|
+
"pr.comment": {
|
|
20424
|
+
capability: "sessions.control",
|
|
20425
|
+
confirmation: "voice",
|
|
20426
|
+
input: schema4({ environmentId, body }, ["environmentId", "body"]),
|
|
20427
|
+
examples: [{ environmentId: "env-1", body: "Merging once CI is green." }]
|
|
20428
|
+
},
|
|
20429
|
+
"pr.comment.edit": {
|
|
20430
|
+
capability: "sessions.control",
|
|
20431
|
+
confirmation: "voice",
|
|
20432
|
+
input: schema4({
|
|
20433
|
+
environmentId,
|
|
20434
|
+
commentId: {
|
|
20435
|
+
type: "integer",
|
|
20436
|
+
minimum: 1,
|
|
20437
|
+
description: "Comment ID, from pr.get or a pr.comment result."
|
|
20438
|
+
},
|
|
20439
|
+
body
|
|
20440
|
+
}, ["environmentId", "commentId", "body"]),
|
|
20441
|
+
examples: [{ environmentId: "env-1", commentId: 123, body: "Merged after the fix." }]
|
|
20442
|
+
},
|
|
20443
|
+
"pr.review": {
|
|
20444
|
+
capability: "sessions.control",
|
|
20445
|
+
confirmation: "always",
|
|
20446
|
+
input: schema4({
|
|
20447
|
+
environmentId,
|
|
20448
|
+
event: {
|
|
20449
|
+
type: "string",
|
|
20450
|
+
enum: PUBLIC_PR_REVIEW_EVENTS,
|
|
20451
|
+
description: "The verdict. REQUEST_CHANGES needs body; COMMENT needs body or comments. GitHub refuses approving your own pull request."
|
|
20452
|
+
},
|
|
20453
|
+
body: { ...body, description: "Review summary." },
|
|
20454
|
+
commitId: {
|
|
20455
|
+
...commitSha,
|
|
20456
|
+
description: "The commit reviewed (headSha from pr.get). Omitted: the current head."
|
|
20457
|
+
},
|
|
20458
|
+
comments: {
|
|
20459
|
+
type: "array",
|
|
20460
|
+
maxItems: PUBLIC_PR_REVIEW_COMMENTS_MAX,
|
|
20461
|
+
description: "Inline comments submitted with the review.",
|
|
20462
|
+
items: {
|
|
20463
|
+
type: "object",
|
|
20464
|
+
properties: { path: filePath, line, side, startLine, body },
|
|
20465
|
+
required: ["path", "line", "side", "body"],
|
|
20466
|
+
additionalProperties: false
|
|
20467
|
+
}
|
|
20468
|
+
}
|
|
20469
|
+
}, ["environmentId", "event"]),
|
|
20470
|
+
examples: [
|
|
20471
|
+
{ environmentId: "env-1", event: "APPROVE" },
|
|
20472
|
+
{
|
|
20473
|
+
environmentId: "env-1",
|
|
20474
|
+
event: "COMMENT",
|
|
20475
|
+
comments: [{ path: "src/index.ts", line: 12, side: "RIGHT", body: "Is this bounded?" }]
|
|
20476
|
+
}
|
|
20477
|
+
]
|
|
20478
|
+
},
|
|
20479
|
+
"pr.review.comment": {
|
|
20480
|
+
capability: "sessions.control",
|
|
20481
|
+
confirmation: "voice",
|
|
20482
|
+
input: schema4({
|
|
20483
|
+
environmentId,
|
|
20484
|
+
path: filePath,
|
|
20485
|
+
line,
|
|
20486
|
+
side,
|
|
20487
|
+
startLine,
|
|
20488
|
+
body,
|
|
20489
|
+
commitId: {
|
|
20490
|
+
...commitSha,
|
|
20491
|
+
description: "The commit commented on. Omitted: the pull request's current head."
|
|
20492
|
+
}
|
|
20493
|
+
}, ["environmentId", "path", "line", "side", "body"]),
|
|
20494
|
+
examples: [
|
|
20495
|
+
{ environmentId: "env-1", path: "src/index.ts", line: 12, side: "RIGHT", body: "Why?" }
|
|
20496
|
+
]
|
|
20497
|
+
},
|
|
20498
|
+
"pr.thread.reply": {
|
|
20499
|
+
capability: "sessions.control",
|
|
20500
|
+
confirmation: "voice",
|
|
20501
|
+
input: schema4({ environmentId, threadId, body }, ["environmentId", "threadId", "body"]),
|
|
20502
|
+
examples: [{ environmentId: "env-1", threadId: "PRRT_1", body: "Fixed." }]
|
|
20503
|
+
},
|
|
20504
|
+
"pr.thread.resolve": {
|
|
20505
|
+
capability: "sessions.control",
|
|
20506
|
+
confirmation: "voice",
|
|
20507
|
+
input: schema4({
|
|
20508
|
+
environmentId,
|
|
20509
|
+
threadId,
|
|
20510
|
+
resolved: { type: "boolean", description: "False to unresolve (default true)." }
|
|
20511
|
+
}, ["environmentId", "threadId"]),
|
|
20512
|
+
examples: [
|
|
20513
|
+
{ environmentId: "env-1", threadId: "PRRT_1" },
|
|
20514
|
+
{ environmentId: "env-1", threadId: "PRRT_1", resolved: false }
|
|
20515
|
+
]
|
|
20516
|
+
},
|
|
20517
|
+
"pr.file.viewed": {
|
|
20518
|
+
capability: "sessions.control",
|
|
20519
|
+
confirmation: "never",
|
|
20520
|
+
input: schema4({
|
|
20521
|
+
environmentId,
|
|
20522
|
+
path: filePath,
|
|
20523
|
+
viewed: { type: "boolean", description: "False to clear it (default true)." }
|
|
20524
|
+
}, ["environmentId", "path"]),
|
|
20525
|
+
examples: [{ environmentId: "env-1", path: "src/index.ts" }]
|
|
20526
|
+
},
|
|
20527
|
+
"pr.reviewers": {
|
|
20528
|
+
capability: "sessions.control",
|
|
20529
|
+
confirmation: "voice",
|
|
20530
|
+
input: schema4({
|
|
20531
|
+
environmentId,
|
|
20532
|
+
add: {
|
|
20533
|
+
...reviewerList,
|
|
20534
|
+
description: "Logins or org/team-slug entries to request a review from."
|
|
20535
|
+
},
|
|
20536
|
+
remove: {
|
|
20537
|
+
...reviewerList,
|
|
20538
|
+
description: "Logins or org/team-slug entries whose request to remove."
|
|
20539
|
+
}
|
|
20540
|
+
}, ["environmentId"]),
|
|
20541
|
+
examples: [{ environmentId: "env-1", add: ["octocat"] }]
|
|
20542
|
+
},
|
|
20543
|
+
"pr.label": {
|
|
20544
|
+
capability: "sessions.control",
|
|
20545
|
+
confirmation: "voice",
|
|
20546
|
+
input: schema4({
|
|
20547
|
+
environmentId,
|
|
20548
|
+
name: {
|
|
20549
|
+
type: "string",
|
|
20550
|
+
minLength: 1,
|
|
20551
|
+
maxLength: 100,
|
|
20552
|
+
description: "Label name, from pr.options."
|
|
20553
|
+
},
|
|
20554
|
+
present: { type: "boolean", description: "False to remove the label (default true)." }
|
|
20555
|
+
}, ["environmentId", "name"]),
|
|
20556
|
+
examples: [{ environmentId: "env-1", name: "bug" }]
|
|
20557
|
+
}
|
|
20558
|
+
});
|
|
20559
|
+
|
|
20560
|
+
// src/client/commands/pull-requests.ts
|
|
20561
|
+
var ENVIRONMENT = { name: "environment", required: true, description: "Its pull request." };
|
|
20562
|
+
var YES_OPTION = {
|
|
20563
|
+
name: "yes",
|
|
20564
|
+
kind: "boolean",
|
|
20565
|
+
description: "Confirm this change on GitHub. Required."
|
|
20566
|
+
};
|
|
20567
|
+
var BODY_OPTIONS = [
|
|
20568
|
+
{ name: "body", kind: "string", valueName: "TEXT", description: "Inline Markdown text." },
|
|
20569
|
+
{
|
|
20570
|
+
name: "body-file",
|
|
20571
|
+
kind: "string",
|
|
20572
|
+
valueName: "PATH",
|
|
20573
|
+
description: "Read the text from a local file."
|
|
20574
|
+
}
|
|
20575
|
+
];
|
|
20576
|
+
var INLINE_OPTIONS = [
|
|
20577
|
+
{ name: "path", kind: "string", valueName: "PATH", description: "Changed file." },
|
|
20578
|
+
{ name: "line", kind: "string", valueName: "N", description: "Line of the comment." },
|
|
20579
|
+
{ name: "side", kind: "string", valueName: "SIDE", description: "RIGHT (new) or LEFT (old)." },
|
|
20580
|
+
{ name: "start-line", kind: "string", valueName: "N", description: "First line of a range." }
|
|
20581
|
+
];
|
|
20582
|
+
function requireYes(parsed, what) {
|
|
20583
|
+
if (parsed.options.yes !== true) {
|
|
20584
|
+
throw new CliError("invalid-input", `${what}; pass --yes to confirm`);
|
|
20585
|
+
}
|
|
20586
|
+
}
|
|
20587
|
+
function requiredOption(parsed, name) {
|
|
20588
|
+
const value = stringOption(parsed.options, name);
|
|
20589
|
+
if (!value)
|
|
20590
|
+
throw new CliError("invalid-input", `--${name} is required`);
|
|
20591
|
+
return value;
|
|
20592
|
+
}
|
|
20593
|
+
function integerOption(parsed, name) {
|
|
20594
|
+
const value = stringOption(parsed.options, name);
|
|
20595
|
+
if (value === undefined)
|
|
20596
|
+
return;
|
|
20597
|
+
const number = Number(value);
|
|
20598
|
+
if (!Number.isSafeInteger(number) || number < 1) {
|
|
20599
|
+
throw new CliError("invalid-input", `--${name} must be a positive integer`);
|
|
20600
|
+
}
|
|
20601
|
+
return number;
|
|
20602
|
+
}
|
|
20603
|
+
function requiredInteger(parsed, name) {
|
|
20604
|
+
const number = integerOption(parsed, name);
|
|
20605
|
+
if (number === undefined)
|
|
20606
|
+
throw new CliError("invalid-input", `--${name} is required`);
|
|
20607
|
+
return number;
|
|
20608
|
+
}
|
|
20609
|
+
async function bodyText(context, parsed, required) {
|
|
20610
|
+
const body = await readTextSource(context.io, {
|
|
20611
|
+
file: parsed.options["body-file"],
|
|
20612
|
+
inline: parsed.options.body,
|
|
20613
|
+
label: "Body",
|
|
20614
|
+
maxBytes: PUBLIC_PR_BODY_MAX_CHARS * 4,
|
|
20615
|
+
names: { file: "--body-file", stdin: "", inline: "--body" },
|
|
20616
|
+
required
|
|
20617
|
+
});
|
|
20618
|
+
if (body !== undefined && body.length > PUBLIC_PR_BODY_MAX_CHARS) {
|
|
20619
|
+
throw new CliError("input-too-large", `Body is longer than ${PUBLIC_PR_BODY_MAX_CHARS} characters`);
|
|
20620
|
+
}
|
|
20621
|
+
return body;
|
|
20622
|
+
}
|
|
20623
|
+
function repeatedList(value) {
|
|
20624
|
+
return typeof value === "string" ? value.split(",").map((entry) => entry.trim()).filter(Boolean) : [];
|
|
20625
|
+
}
|
|
20626
|
+
function changeHuman(result) {
|
|
20627
|
+
return keyValues(Object.entries(result).filter(([key, value]) => key !== "environmentId" && typeof value !== "object"));
|
|
20628
|
+
}
|
|
20629
|
+
function change(name, action, summary, options2, input, extras = {}) {
|
|
20630
|
+
return {
|
|
20631
|
+
path: ["pr", name],
|
|
20632
|
+
action,
|
|
20633
|
+
summary,
|
|
20634
|
+
positionals: [ENVIRONMENT],
|
|
20635
|
+
options: [...options2, REQUEST_ID_OPTION],
|
|
20636
|
+
idOutput: "pull request URL",
|
|
20637
|
+
async run(context, parsed) {
|
|
20638
|
+
const environmentId = parsed.positionals.environment;
|
|
20639
|
+
const { session, result, receipt, warnings } = await submit(context, action, { environmentId, ...await input(context, parsed) }, parsed.options);
|
|
20640
|
+
return {
|
|
20641
|
+
action,
|
|
20642
|
+
result,
|
|
20643
|
+
receipt,
|
|
20644
|
+
warnings,
|
|
20645
|
+
connection: session.identity,
|
|
20646
|
+
ids: typeof result.url === "string" ? [result.url] : [],
|
|
20647
|
+
human: changeHuman(result)
|
|
20648
|
+
};
|
|
20649
|
+
},
|
|
20650
|
+
...extras
|
|
20651
|
+
};
|
|
20652
|
+
}
|
|
20653
|
+
function read(name, action, summary, options2, input, human) {
|
|
20654
|
+
return {
|
|
20655
|
+
path: ["pr", name],
|
|
20656
|
+
action,
|
|
20657
|
+
summary,
|
|
20658
|
+
positionals: [ENVIRONMENT],
|
|
20659
|
+
options: options2,
|
|
20660
|
+
async run(context, parsed) {
|
|
20661
|
+
const session = await context.session();
|
|
20662
|
+
const result = await session.read(action, {
|
|
20663
|
+
environmentId: parsed.positionals.environment,
|
|
20664
|
+
...input(parsed)
|
|
20665
|
+
});
|
|
20666
|
+
return { action, result, connection: session.identity, human: human(result) };
|
|
20667
|
+
}
|
|
20668
|
+
};
|
|
20669
|
+
}
|
|
20670
|
+
function pullRequestLines(result) {
|
|
20671
|
+
const pullRequest = result.pullRequest;
|
|
20672
|
+
if (!pullRequest) {
|
|
20673
|
+
return keyValues([
|
|
20674
|
+
["attachment", result.attachment],
|
|
20675
|
+
["url", result.url],
|
|
20676
|
+
["error", result.error]
|
|
20677
|
+
]);
|
|
20678
|
+
}
|
|
20679
|
+
return keyValues([
|
|
20680
|
+
["attachment", result.attachment],
|
|
20681
|
+
["number", pullRequest.number],
|
|
20682
|
+
["title", pullRequest.title],
|
|
20683
|
+
["url", pullRequest.htmlUrl],
|
|
20684
|
+
["state", pullRequest.isDraft ? `${pullRequest.state} (draft)` : pullRequest.state],
|
|
20685
|
+
["branch", `${pullRequest.headRef} into ${pullRequest.baseRef}`],
|
|
20686
|
+
["head", pullRequest.headSha],
|
|
20687
|
+
["mergeability", pullRequest.mergeability],
|
|
20688
|
+
["checks", pullRequest.checksState]
|
|
20689
|
+
]);
|
|
20690
|
+
}
|
|
20691
|
+
function timelineLines(result) {
|
|
20692
|
+
const items = result.items;
|
|
20693
|
+
const lines = items.flatMap((item) => {
|
|
20694
|
+
if (item.kind === "comment") {
|
|
20695
|
+
return [
|
|
20696
|
+
`comment \xB7 ${item.comment.author?.login ?? "unknown"} \xB7 ${item.comment.createdAt}`,
|
|
20697
|
+
item.comment.body
|
|
20698
|
+
];
|
|
20699
|
+
}
|
|
20700
|
+
if (item.kind === "event") {
|
|
20701
|
+
return [
|
|
20702
|
+
`event \xB7 ${item.actor?.login ?? "unknown"} \xB7 ${item.createdAt}`,
|
|
20703
|
+
`${item.event}${item.detail ? `: ${item.detail}` : ""}`
|
|
20704
|
+
];
|
|
20705
|
+
}
|
|
20706
|
+
return [
|
|
20707
|
+
`${item.kind} \xB7 ${item.author?.login ?? (item.kind === "commit" ? item.authorName : undefined) ?? "unknown"} \xB7 ${item.createdAt}`,
|
|
20708
|
+
item.kind === "commit" ? `${item.sha} ${item.message}` : `${item.state}${item.body ? `: ${item.body}` : ""}`
|
|
20709
|
+
];
|
|
20710
|
+
});
|
|
20711
|
+
if (!items.length)
|
|
20712
|
+
lines.push("No timeline entries.");
|
|
20713
|
+
if (result.truncated)
|
|
20714
|
+
lines.push("Timeline truncated; more entries are available on GitHub.");
|
|
20715
|
+
return lines;
|
|
20716
|
+
}
|
|
20717
|
+
function fileLines(result) {
|
|
20718
|
+
const lines = keyValues([
|
|
20719
|
+
["number", result.number],
|
|
20720
|
+
["head", result.headSha]
|
|
20721
|
+
]);
|
|
20722
|
+
if (Array.isArray(result.files)) {
|
|
20723
|
+
lines.push(...table(["FILE", "STATUS", "+", "-"], result.files.map((file) => [
|
|
20724
|
+
file.path,
|
|
20725
|
+
file.status,
|
|
20726
|
+
String(file.additions),
|
|
20727
|
+
String(file.deletions)
|
|
20728
|
+
])));
|
|
20729
|
+
} else {
|
|
20730
|
+
const file = result.file;
|
|
20731
|
+
lines.push(`${file.path} (${file.status}, +${file.additions} -${file.deletions})`);
|
|
20732
|
+
if (!file.patchAvailable)
|
|
20733
|
+
lines.push("Patch unavailable; view this file on GitHub.");
|
|
20734
|
+
else
|
|
20735
|
+
for (const hunk of file.hunks) {
|
|
20736
|
+
lines.push(hunk.header, ...hunk.lines.map((line) => `${line.type === "add" ? "+" : line.type === "remove" ? "-" : line.type === "no-newline" ? "\\" : " "}${line.text}`));
|
|
20737
|
+
}
|
|
20738
|
+
}
|
|
20739
|
+
for (const thread of result.threads ?? []) {
|
|
20740
|
+
lines.push(`Thread ${thread.id} \xB7 ${thread.path}:${thread.line ?? "outdated"} \xB7 ${thread.isResolved ? "resolved" : "unresolved"}${thread.isOutdated ? " \xB7 outdated" : ""}`);
|
|
20741
|
+
for (const comment of thread.comments)
|
|
20742
|
+
lines.push(`${comment.author?.login ?? "unknown"} \xB7 ${comment.createdAt}: ${comment.body}`);
|
|
20743
|
+
if (thread.commentsTruncated)
|
|
20744
|
+
lines.push("Thread comments truncated; see GitHub for more.");
|
|
20745
|
+
}
|
|
20746
|
+
if (result.truncated)
|
|
20747
|
+
lines.push("File list truncated; more files are available on GitHub.");
|
|
20748
|
+
return lines;
|
|
20749
|
+
}
|
|
20750
|
+
async function reviewComments(context, parsed) {
|
|
20751
|
+
const file = parsed.options["comments-file"];
|
|
20752
|
+
if (file === undefined)
|
|
20753
|
+
return;
|
|
20754
|
+
const text = await readTextSource(context.io, {
|
|
20755
|
+
file,
|
|
20756
|
+
label: "Review comments",
|
|
20757
|
+
maxBytes: PUBLIC_PR_BODY_MAX_CHARS * 4,
|
|
20758
|
+
names: { file: "--comments-file", stdin: "" },
|
|
20759
|
+
required: true
|
|
20760
|
+
});
|
|
20761
|
+
let comments;
|
|
20762
|
+
try {
|
|
20763
|
+
comments = JSON.parse(text);
|
|
20764
|
+
} catch {
|
|
20765
|
+
throw new CliError("invalid-input", "--comments-file must contain a JSON array of inline comments");
|
|
20766
|
+
}
|
|
20767
|
+
if (!Array.isArray(comments) || comments.length > PUBLIC_PR_REVIEW_COMMENTS_MAX)
|
|
20768
|
+
throw new CliError("invalid-input", `--comments-file must contain at most ${PUBLIC_PR_REVIEW_COMMENTS_MAX} inline comments in a JSON array`);
|
|
20769
|
+
return comments;
|
|
20770
|
+
}
|
|
20771
|
+
var pullRequestCommands = [
|
|
20772
|
+
read("get", "pr.get", "Read the pull request attached to an environment's branch.", [], () => ({}), pullRequestLines),
|
|
20773
|
+
{
|
|
20774
|
+
path: ["pr", "list"],
|
|
20775
|
+
action: "pr.list",
|
|
20776
|
+
summary: "List a project's pull requests from GitHub.",
|
|
20777
|
+
positionals: [{ name: "project", required: true }],
|
|
20778
|
+
options: [
|
|
20779
|
+
{
|
|
20780
|
+
name: "filter",
|
|
20781
|
+
kind: "string",
|
|
20782
|
+
valueName: "FILTER",
|
|
20783
|
+
description: "open (default), mine, review-requested or closed."
|
|
20784
|
+
},
|
|
20785
|
+
{ name: "query", kind: "string", valueName: "TEXT", description: "Search text." }
|
|
20786
|
+
],
|
|
20787
|
+
idOutput: "pull request URLs",
|
|
20788
|
+
async run(context, parsed) {
|
|
20789
|
+
const session = await context.session();
|
|
20790
|
+
const filter = stringOption(parsed.options, "filter");
|
|
20791
|
+
const query = stringOption(parsed.options, "query");
|
|
20792
|
+
const result = await session.read("pr.list", {
|
|
20793
|
+
projectId: parsed.positionals.project,
|
|
20794
|
+
...filter !== undefined ? { filter: oneOf(filter, PUBLIC_PR_LIST_FILTERS, "--filter") } : {},
|
|
20795
|
+
...query !== undefined ? { query } : {}
|
|
20796
|
+
});
|
|
20797
|
+
return {
|
|
20798
|
+
action: "pr.list",
|
|
20799
|
+
result,
|
|
20800
|
+
connection: session.identity,
|
|
20801
|
+
ids: result.pullRequests.map((pullRequest) => pullRequest.htmlUrl),
|
|
20802
|
+
human: table(["NUMBER", "STATE", "TITLE"], result.pullRequests.map((pullRequest) => [
|
|
20803
|
+
String(pullRequest.number),
|
|
20804
|
+
pullRequest.state,
|
|
20805
|
+
pullRequest.title
|
|
20806
|
+
]))
|
|
20807
|
+
};
|
|
20808
|
+
}
|
|
20809
|
+
},
|
|
20810
|
+
read("timeline", "pr.timeline", "Read a pull request's commits, comments, reviews and events.", [], () => ({}), timelineLines),
|
|
20811
|
+
read("files", "pr.files", "Read a pull request's changed files and review threads; with --path, one file's diff.", [
|
|
20812
|
+
{
|
|
20813
|
+
name: "path",
|
|
20814
|
+
kind: "string",
|
|
20815
|
+
valueName: "PATH",
|
|
20816
|
+
description: "Only this file, with hunks."
|
|
20817
|
+
}
|
|
20818
|
+
], (parsed) => {
|
|
20819
|
+
const path = stringOption(parsed.options, "path");
|
|
20820
|
+
return path !== undefined ? { path } : {};
|
|
20821
|
+
}, fileLines),
|
|
20822
|
+
read("options", "pr.options", "Read the repository's labels and assignable users.", [], () => ({}), (result) => keyValues([
|
|
20823
|
+
[
|
|
20824
|
+
"labels",
|
|
20825
|
+
result.labels.map((label) => label.name).join(", ")
|
|
20826
|
+
],
|
|
20827
|
+
[
|
|
20828
|
+
"assignable users",
|
|
20829
|
+
result.assignableUsers.map((user) => user.login).join(", ")
|
|
20830
|
+
]
|
|
20831
|
+
])),
|
|
20832
|
+
change("merge", "pr.merge", "Merge the environment's pull request into its target branch (squash by default).", [
|
|
20833
|
+
{
|
|
20834
|
+
name: "method",
|
|
20835
|
+
kind: "string",
|
|
20836
|
+
valueName: "METHOD",
|
|
20837
|
+
description: "squash (default), merge or rebase."
|
|
20838
|
+
},
|
|
20839
|
+
{ name: "keep-branch", kind: "boolean", description: "Keep the head branch." },
|
|
20840
|
+
{
|
|
20841
|
+
name: "cleanup",
|
|
20842
|
+
kind: "boolean",
|
|
20843
|
+
description: "Merge and Cleanup: also delete the environment once merged."
|
|
20844
|
+
},
|
|
20845
|
+
{
|
|
20846
|
+
name: "expected-head-sha",
|
|
20847
|
+
kind: "string",
|
|
20848
|
+
valueName: "SHA",
|
|
20849
|
+
description: "Refuse if the branch has moved from this commit."
|
|
20850
|
+
},
|
|
20851
|
+
YES_OPTION
|
|
20852
|
+
], (_context, parsed) => {
|
|
20853
|
+
requireYes(parsed, "Merging cannot be undone");
|
|
20854
|
+
const method = stringOption(parsed.options, "method");
|
|
20855
|
+
const expectedHeadSha = stringOption(parsed.options, "expected-head-sha");
|
|
20856
|
+
return {
|
|
20857
|
+
...method !== undefined ? { method: oneOf(method, PUBLIC_PR_MERGE_METHODS, "--method") } : {},
|
|
20858
|
+
...parsed.options["keep-branch"] === true ? { deleteBranch: false } : {},
|
|
20859
|
+
...parsed.options.cleanup === true ? { cleanup: true } : {},
|
|
20860
|
+
...expectedHeadSha !== undefined ? { expectedHeadSha } : {}
|
|
20861
|
+
};
|
|
20862
|
+
}, { inputFields: { "keep-branch": "deleteBranch", yes: null } }),
|
|
20863
|
+
change("close", "pr.close", "Close the environment's pull request without merging.", [YES_OPTION], (_context, parsed) => {
|
|
20864
|
+
requireYes(parsed, "This closes the pull request");
|
|
20865
|
+
return {};
|
|
20866
|
+
}, { inputFields: { yes: null } }),
|
|
20867
|
+
change("reopen", "pr.reopen", "Reopen the environment's closed pull request.", [], () => ({})),
|
|
20868
|
+
change("ready", "pr.ready", "Mark the environment's draft pull request ready.", [], () => ({})),
|
|
20869
|
+
change("draft", "pr.draft", "Convert the environment's pull request to a draft.", [], () => ({})),
|
|
20870
|
+
change("comment", "pr.comment", "Add a conversation comment to the environment's pull request.", BODY_OPTIONS, async (context, parsed) => ({ body: await bodyText(context, parsed, true) }), { inputFields: { "body-file": "body" } }),
|
|
20871
|
+
change("comment-edit", "pr.comment.edit", "Edit a conversation comment on the environment's pull request.", [
|
|
20872
|
+
{ name: "comment-id", kind: "string", valueName: "ID", description: "From pr get." },
|
|
20873
|
+
...BODY_OPTIONS
|
|
20874
|
+
], async (context, parsed) => ({
|
|
20875
|
+
commentId: requiredInteger(parsed, "comment-id"),
|
|
20876
|
+
body: await bodyText(context, parsed, true)
|
|
20877
|
+
}), { inputFields: { "body-file": "body" } }),
|
|
20878
|
+
change("review", "pr.review", "Submit a review: approve, request changes or comment.", [
|
|
20879
|
+
{
|
|
20880
|
+
name: "event",
|
|
20881
|
+
kind: "string",
|
|
20882
|
+
valueName: "EVENT",
|
|
20883
|
+
description: "APPROVE, REQUEST_CHANGES or COMMENT."
|
|
20884
|
+
},
|
|
20885
|
+
...BODY_OPTIONS,
|
|
20886
|
+
{ name: "commit-id", kind: "string", valueName: "SHA", description: "The commit reviewed." },
|
|
20887
|
+
{
|
|
20888
|
+
name: "comments-file",
|
|
20889
|
+
kind: "string",
|
|
20890
|
+
valueName: "PATH",
|
|
20891
|
+
description: "JSON array of inline comments (path, line, side, body and optional startLine)."
|
|
20892
|
+
},
|
|
20893
|
+
YES_OPTION
|
|
20894
|
+
], async (context, parsed) => {
|
|
20895
|
+
requireYes(parsed, "This submits a review as your GitHub user");
|
|
20896
|
+
const body = await bodyText(context, parsed, false);
|
|
20897
|
+
const commitId = stringOption(parsed.options, "commit-id");
|
|
20898
|
+
const comments = await reviewComments(context, parsed);
|
|
20899
|
+
return {
|
|
20900
|
+
...comments !== undefined ? { comments } : {},
|
|
20901
|
+
event: oneOf(parsed.options.event, PUBLIC_PR_REVIEW_EVENTS, "--event"),
|
|
20902
|
+
...body !== undefined ? { body } : {},
|
|
20903
|
+
...commitId !== undefined ? { commitId } : {}
|
|
20904
|
+
};
|
|
20905
|
+
}, { inputFields: { "body-file": "body", "comments-file": "comments", yes: null } }),
|
|
20906
|
+
change("review-comment", "pr.review.comment", "Add one inline review comment to the environment's pull request.", [
|
|
20907
|
+
...INLINE_OPTIONS,
|
|
20908
|
+
...BODY_OPTIONS,
|
|
20909
|
+
{
|
|
20910
|
+
name: "commit-id",
|
|
20911
|
+
kind: "string",
|
|
20912
|
+
valueName: "SHA",
|
|
20913
|
+
description: "Omitted: the current head."
|
|
20914
|
+
}
|
|
20915
|
+
], async (context, parsed) => {
|
|
20916
|
+
const startLine = integerOption(parsed, "start-line");
|
|
20917
|
+
const commitId = stringOption(parsed.options, "commit-id");
|
|
20918
|
+
return {
|
|
20919
|
+
path: requiredOption(parsed, "path"),
|
|
20920
|
+
line: requiredInteger(parsed, "line"),
|
|
20921
|
+
side: oneOf(parsed.options.side, PUBLIC_PR_SIDES, "--side"),
|
|
20922
|
+
...startLine !== undefined ? { startLine } : {},
|
|
20923
|
+
body: await bodyText(context, parsed, true),
|
|
20924
|
+
...commitId !== undefined ? { commitId } : {}
|
|
20925
|
+
};
|
|
20926
|
+
}, { inputFields: { "body-file": "body" } }),
|
|
20927
|
+
change("thread-reply", "pr.thread.reply", "Reply to a review thread on the environment's pull request.", [
|
|
20928
|
+
{ name: "thread-id", kind: "string", valueName: "ID", description: "From pr files." },
|
|
20929
|
+
...BODY_OPTIONS
|
|
20930
|
+
], async (context, parsed) => ({
|
|
20931
|
+
threadId: requiredOption(parsed, "thread-id"),
|
|
20932
|
+
body: await bodyText(context, parsed, true)
|
|
20933
|
+
}), { inputFields: { "body-file": "body" } }),
|
|
20934
|
+
change("thread-resolve", "pr.thread.resolve", "Resolve a review thread on the environment's pull request.", [
|
|
20935
|
+
{ name: "thread-id", kind: "string", valueName: "ID", description: "From pr files." },
|
|
20936
|
+
{ name: "unresolve", kind: "boolean", description: "Unresolve it instead." }
|
|
20937
|
+
], (_context, parsed) => ({
|
|
20938
|
+
threadId: requiredOption(parsed, "thread-id"),
|
|
20939
|
+
...parsed.options.unresolve === true ? { resolved: false } : {}
|
|
20940
|
+
}), { inputFields: { unresolve: "resolved" } }),
|
|
20941
|
+
change("file-viewed", "pr.file.viewed", "Mark a changed file as viewed on the environment's pull request.", [
|
|
20942
|
+
{ name: "path", kind: "string", valueName: "PATH", description: "Changed file." },
|
|
20943
|
+
{ name: "unviewed", kind: "boolean", description: "Clear it instead." }
|
|
20944
|
+
], (_context, parsed) => ({
|
|
20945
|
+
path: requiredOption(parsed, "path"),
|
|
20946
|
+
...parsed.options.unviewed === true ? { viewed: false } : {}
|
|
20947
|
+
}), { inputFields: { unviewed: "viewed" } }),
|
|
20948
|
+
change("reviewers", "pr.reviewers", "Request or remove reviewers on the environment's pull request.", [
|
|
20949
|
+
{
|
|
20950
|
+
name: "add",
|
|
20951
|
+
kind: "string",
|
|
20952
|
+
valueName: "LIST",
|
|
20953
|
+
description: "Comma-separated logins or org/team-slugs."
|
|
20954
|
+
},
|
|
20955
|
+
{
|
|
20956
|
+
name: "remove",
|
|
20957
|
+
kind: "string",
|
|
20958
|
+
valueName: "LIST",
|
|
20959
|
+
description: "Comma-separated logins or org/team-slugs."
|
|
20960
|
+
}
|
|
20961
|
+
], (_context, parsed) => ({
|
|
20962
|
+
add: repeatedList(parsed.options.add),
|
|
20963
|
+
remove: repeatedList(parsed.options.remove)
|
|
20964
|
+
})),
|
|
20965
|
+
change("label", "pr.label", "Add or remove one label on the environment's pull request.", [
|
|
20966
|
+
{ name: "name", kind: "string", valueName: "LABEL", description: "Label name." },
|
|
20967
|
+
{ name: "remove", kind: "boolean", description: "Remove it instead." }
|
|
20968
|
+
], (_context, parsed) => ({
|
|
20969
|
+
name: requiredOption(parsed, "name"),
|
|
20970
|
+
...parsed.options.remove === true ? { present: false } : {}
|
|
20971
|
+
}), { inputFields: { remove: "present" } })
|
|
20972
|
+
];
|
|
20973
|
+
|
|
19270
20974
|
// src/client/help.ts
|
|
19271
20975
|
var GROUP_SUMMARIES = {
|
|
19272
20976
|
connection: "Select and verify the backend this client talks to.",
|
|
@@ -19628,8 +21332,10 @@ var CLIENT_COMMANDS = [
|
|
|
19628
21332
|
...projectCommands,
|
|
19629
21333
|
...environmentCommands,
|
|
19630
21334
|
...sessionCommands,
|
|
21335
|
+
...sessionGoalCommands,
|
|
19631
21336
|
...changesCommands,
|
|
19632
21337
|
...workflowCommands,
|
|
21338
|
+
...pullRequestCommands,
|
|
19633
21339
|
...buildCommands,
|
|
19634
21340
|
...graphCommands,
|
|
19635
21341
|
...attentionCommands,
|