@parall/daemon 1.44.0 → 1.45.0
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/bundle/manifest.json +9 -9
- package/bundle/parall-claude-agent.js +336 -92
- package/bundle/parall-codex-agent.js +964 -1342
- package/bundle/parall-daemon.js +866 -311
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +229 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/runtime-bin-resolver.d.ts +7 -1
- package/dist/runtime-bin-resolver.d.ts.map +1 -1
- package/dist/runtime-bin-resolver.js +57 -22
- package/dist/runtimes.d.ts +15 -4
- package/dist/runtimes.d.ts.map +1 -1
- package/dist/runtimes.js +60 -5
- package/dist/supervisor.d.ts.map +1 -1
- package/dist/supervisor.js +4 -1
- package/dist/win-lifecycle.d.ts +96 -0
- package/dist/win-lifecycle.d.ts.map +1 -0
- package/dist/win-lifecycle.js +229 -0
- package/dist/win-service.d.ts +119 -0
- package/dist/win-service.d.ts.map +1 -0
- package/dist/win-service.js +226 -0
- package/package.json +6 -6
|
@@ -17718,9 +17718,9 @@ var require_getMachineId_linux = __commonJS({
|
|
|
17718
17718
|
var api_1 = (init_esm(), __toCommonJS(esm_exports));
|
|
17719
17719
|
async function getMachineId() {
|
|
17720
17720
|
const paths = ["/etc/machine-id", "/var/lib/dbus/machine-id"];
|
|
17721
|
-
for (const
|
|
17721
|
+
for (const path12 of paths) {
|
|
17722
17722
|
try {
|
|
17723
|
-
const result = await fs_1.promises.readFile(
|
|
17723
|
+
const result = await fs_1.promises.readFile(path12, { encoding: "utf8" });
|
|
17724
17724
|
return result.trim();
|
|
17725
17725
|
} catch (e) {
|
|
17726
17726
|
api_1.diag.debug(`error reading machine id: ${e}`);
|
|
@@ -21123,7 +21123,7 @@ function appendRootPathToUrlIfNeeded(url) {
|
|
|
21123
21123
|
return void 0;
|
|
21124
21124
|
}
|
|
21125
21125
|
}
|
|
21126
|
-
function appendResourcePathToUrl(url,
|
|
21126
|
+
function appendResourcePathToUrl(url, path12) {
|
|
21127
21127
|
try {
|
|
21128
21128
|
new URL(url);
|
|
21129
21129
|
} catch (_a) {
|
|
@@ -21133,11 +21133,11 @@ function appendResourcePathToUrl(url, path11) {
|
|
|
21133
21133
|
if (!url.endsWith("/")) {
|
|
21134
21134
|
url = url + "/";
|
|
21135
21135
|
}
|
|
21136
|
-
url +=
|
|
21136
|
+
url += path12;
|
|
21137
21137
|
try {
|
|
21138
21138
|
new URL(url);
|
|
21139
21139
|
} catch (_b) {
|
|
21140
|
-
diag2.warn("Configuration: Provided URL appended with '" +
|
|
21140
|
+
diag2.warn("Configuration: Provided URL appended with '" + path12 + "' is not a valid URL, using 'undefined' instead of '" + url + "'");
|
|
21141
21141
|
return void 0;
|
|
21142
21142
|
}
|
|
21143
21143
|
return url;
|
|
@@ -24050,7 +24050,7 @@ var require_parse = __commonJS({
|
|
|
24050
24050
|
"ts/node_modules/.pnpm/semver@7.7.4/node_modules/semver/functions/parse.js"(exports2, module2) {
|
|
24051
24051
|
"use strict";
|
|
24052
24052
|
var SemVer = require_semver();
|
|
24053
|
-
var
|
|
24053
|
+
var parse = (version, options, throwErrors = false) => {
|
|
24054
24054
|
if (version instanceof SemVer) {
|
|
24055
24055
|
return version;
|
|
24056
24056
|
}
|
|
@@ -24063,7 +24063,7 @@ var require_parse = __commonJS({
|
|
|
24063
24063
|
throw er;
|
|
24064
24064
|
}
|
|
24065
24065
|
};
|
|
24066
|
-
module2.exports =
|
|
24066
|
+
module2.exports = parse;
|
|
24067
24067
|
}
|
|
24068
24068
|
});
|
|
24069
24069
|
|
|
@@ -24071,9 +24071,9 @@ var require_parse = __commonJS({
|
|
|
24071
24071
|
var require_valid = __commonJS({
|
|
24072
24072
|
"ts/node_modules/.pnpm/semver@7.7.4/node_modules/semver/functions/valid.js"(exports2, module2) {
|
|
24073
24073
|
"use strict";
|
|
24074
|
-
var
|
|
24074
|
+
var parse = require_parse();
|
|
24075
24075
|
var valid = (version, options) => {
|
|
24076
|
-
const v =
|
|
24076
|
+
const v = parse(version, options);
|
|
24077
24077
|
return v ? v.version : null;
|
|
24078
24078
|
};
|
|
24079
24079
|
module2.exports = valid;
|
|
@@ -24084,9 +24084,9 @@ var require_valid = __commonJS({
|
|
|
24084
24084
|
var require_clean = __commonJS({
|
|
24085
24085
|
"ts/node_modules/.pnpm/semver@7.7.4/node_modules/semver/functions/clean.js"(exports2, module2) {
|
|
24086
24086
|
"use strict";
|
|
24087
|
-
var
|
|
24087
|
+
var parse = require_parse();
|
|
24088
24088
|
var clean = (version, options) => {
|
|
24089
|
-
const s =
|
|
24089
|
+
const s = parse(version.trim().replace(/^[=v]+/, ""), options);
|
|
24090
24090
|
return s ? s.version : null;
|
|
24091
24091
|
};
|
|
24092
24092
|
module2.exports = clean;
|
|
@@ -24121,10 +24121,10 @@ var require_inc = __commonJS({
|
|
|
24121
24121
|
var require_diff = __commonJS({
|
|
24122
24122
|
"ts/node_modules/.pnpm/semver@7.7.4/node_modules/semver/functions/diff.js"(exports2, module2) {
|
|
24123
24123
|
"use strict";
|
|
24124
|
-
var
|
|
24124
|
+
var parse = require_parse();
|
|
24125
24125
|
var diff = (version1, version2) => {
|
|
24126
|
-
const v1 =
|
|
24127
|
-
const v2 =
|
|
24126
|
+
const v1 = parse(version1, null, true);
|
|
24127
|
+
const v2 = parse(version2, null, true);
|
|
24128
24128
|
const comparison = v1.compare(v2);
|
|
24129
24129
|
if (comparison === 0) {
|
|
24130
24130
|
return null;
|
|
@@ -24195,9 +24195,9 @@ var require_patch = __commonJS({
|
|
|
24195
24195
|
var require_prerelease = __commonJS({
|
|
24196
24196
|
"ts/node_modules/.pnpm/semver@7.7.4/node_modules/semver/functions/prerelease.js"(exports2, module2) {
|
|
24197
24197
|
"use strict";
|
|
24198
|
-
var
|
|
24198
|
+
var parse = require_parse();
|
|
24199
24199
|
var prerelease = (version, options) => {
|
|
24200
|
-
const parsed =
|
|
24200
|
+
const parsed = parse(version, options);
|
|
24201
24201
|
return parsed && parsed.prerelease.length ? parsed.prerelease : null;
|
|
24202
24202
|
};
|
|
24203
24203
|
module2.exports = prerelease;
|
|
@@ -24383,7 +24383,7 @@ var require_coerce = __commonJS({
|
|
|
24383
24383
|
"ts/node_modules/.pnpm/semver@7.7.4/node_modules/semver/functions/coerce.js"(exports2, module2) {
|
|
24384
24384
|
"use strict";
|
|
24385
24385
|
var SemVer = require_semver();
|
|
24386
|
-
var
|
|
24386
|
+
var parse = require_parse();
|
|
24387
24387
|
var { safeRe: re2, t } = require_re();
|
|
24388
24388
|
var coerce = (version, options) => {
|
|
24389
24389
|
if (version instanceof SemVer) {
|
|
@@ -24418,7 +24418,7 @@ var require_coerce = __commonJS({
|
|
|
24418
24418
|
const patch = match[4] || "0";
|
|
24419
24419
|
const prerelease = options.includePrerelease && match[5] ? `-${match[5]}` : "";
|
|
24420
24420
|
const build = options.includePrerelease && match[6] ? `+${match[6]}` : "";
|
|
24421
|
-
return
|
|
24421
|
+
return parse(`${major2}.${minor}.${patch}${prerelease}${build}`, options);
|
|
24422
24422
|
};
|
|
24423
24423
|
module2.exports = coerce;
|
|
24424
24424
|
}
|
|
@@ -25435,7 +25435,7 @@ var require_semver2 = __commonJS({
|
|
|
25435
25435
|
var constants2 = require_constants3();
|
|
25436
25436
|
var SemVer = require_semver();
|
|
25437
25437
|
var identifiers = require_identifiers();
|
|
25438
|
-
var
|
|
25438
|
+
var parse = require_parse();
|
|
25439
25439
|
var valid = require_valid();
|
|
25440
25440
|
var clean = require_clean();
|
|
25441
25441
|
var inc = require_inc();
|
|
@@ -25473,7 +25473,7 @@ var require_semver2 = __commonJS({
|
|
|
25473
25473
|
var simplifyRange = require_simplify();
|
|
25474
25474
|
var subset = require_subset();
|
|
25475
25475
|
module2.exports = {
|
|
25476
|
-
parse
|
|
25476
|
+
parse,
|
|
25477
25477
|
valid,
|
|
25478
25478
|
clean,
|
|
25479
25479
|
inc,
|
|
@@ -26487,9 +26487,6 @@ function laneContextFilePath(contextDir, targetUri, threadRootId) {
|
|
|
26487
26487
|
return path.join(contextDir, `${laneKeyForTarget(targetUri, threadRootId)}.json`);
|
|
26488
26488
|
}
|
|
26489
26489
|
|
|
26490
|
-
// ts/agent-core/dist/lane-ledger.js
|
|
26491
|
-
import * as fs from "node:fs";
|
|
26492
|
-
|
|
26493
26490
|
// ts/sdk/dist/types.js
|
|
26494
26491
|
var MENTION_ALL_USER_ID = "all";
|
|
26495
26492
|
|
|
@@ -26965,7 +26962,7 @@ var ParallClient = class _ParallClient {
|
|
|
26965
26962
|
return apiError;
|
|
26966
26963
|
}
|
|
26967
26964
|
/** Build headers common to all requests (auth, swimlane). */
|
|
26968
|
-
buildHeaders(
|
|
26965
|
+
buildHeaders(path12, extra) {
|
|
26969
26966
|
const headers = {
|
|
26970
26967
|
"Content-Type": "application/json",
|
|
26971
26968
|
...extra
|
|
@@ -26976,7 +26973,7 @@ var ParallClient = class _ParallClient {
|
|
|
26976
26973
|
if (this.swimlaneName) {
|
|
26977
26974
|
headers["X-Prll-Swimlane"] = this.swimlaneName;
|
|
26978
26975
|
}
|
|
26979
|
-
if (
|
|
26976
|
+
if (path12.startsWith(API_BASE)) {
|
|
26980
26977
|
const overrides = this.getFeatureFlagOverrides?.();
|
|
26981
26978
|
if (overrides)
|
|
26982
26979
|
headers["X-Prll-FF-Override"] = overrides;
|
|
@@ -26999,8 +26996,8 @@ var ParallClient = class _ParallClient {
|
|
|
26999
26996
|
* is authoritative, so wiki vs api routing can't drift from how a caller
|
|
27000
26997
|
* happens to invoke the client.
|
|
27001
26998
|
*/
|
|
27002
|
-
baseUrlFor(
|
|
27003
|
-
return
|
|
26999
|
+
baseUrlFor(path12) {
|
|
27000
|
+
return path12.startsWith(WIKI_BASE) ? this.wikiBaseUrl : this.baseUrl;
|
|
27004
27001
|
}
|
|
27005
27002
|
setToken(token) {
|
|
27006
27003
|
this.token = token;
|
|
@@ -27027,10 +27024,10 @@ var ParallClient = class _ParallClient {
|
|
|
27027
27024
|
* REFRESH_THRESHOLD_S, refresh it **before** sending the request.
|
|
27028
27025
|
* No-op when the token is still fresh, missing, or un-parseable.
|
|
27029
27026
|
*/
|
|
27030
|
-
async ensureFreshToken(
|
|
27027
|
+
async ensureFreshToken(path12) {
|
|
27031
27028
|
if (!this.token || !this.getRefreshToken)
|
|
27032
27029
|
return;
|
|
27033
|
-
const pathSuffix =
|
|
27030
|
+
const pathSuffix = path12.replace(/^\/api\/v1/, "");
|
|
27034
27031
|
if (_ParallClient.AUTH_PATHS.has(pathSuffix))
|
|
27035
27032
|
return;
|
|
27036
27033
|
const exp = _ParallClient.decodeJwtExp(this.token);
|
|
@@ -27062,11 +27059,11 @@ var ParallClient = class _ParallClient {
|
|
|
27062
27059
|
this.refreshPromise = null;
|
|
27063
27060
|
}
|
|
27064
27061
|
}
|
|
27065
|
-
async request(method,
|
|
27062
|
+
async request(method, path12, body, query, retried = false, opts) {
|
|
27066
27063
|
if (!retried) {
|
|
27067
|
-
await this.ensureFreshToken(
|
|
27064
|
+
await this.ensureFreshToken(path12);
|
|
27068
27065
|
}
|
|
27069
|
-
let url = `${this.baseUrlFor(
|
|
27066
|
+
let url = `${this.baseUrlFor(path12)}${path12}`;
|
|
27070
27067
|
if (query) {
|
|
27071
27068
|
const params = new URLSearchParams();
|
|
27072
27069
|
for (const [key, value] of Object.entries(query)) {
|
|
@@ -27078,7 +27075,7 @@ var ParallClient = class _ParallClient {
|
|
|
27078
27075
|
if (qs)
|
|
27079
27076
|
url += `?${qs}`;
|
|
27080
27077
|
}
|
|
27081
|
-
const headers = this.buildHeaders(
|
|
27078
|
+
const headers = this.buildHeaders(path12);
|
|
27082
27079
|
const timeoutSignal = AbortSignal.timeout(opts?.timeoutMs ?? 15e3);
|
|
27083
27080
|
const signal = opts?.signal ? AbortSignal.any([opts.signal, timeoutSignal]) : timeoutSignal;
|
|
27084
27081
|
let res;
|
|
@@ -27096,12 +27093,12 @@ var ParallClient = class _ParallClient {
|
|
|
27096
27093
|
throw _ParallClient.normalizeFetchError(err);
|
|
27097
27094
|
}
|
|
27098
27095
|
if (res.status === 401) {
|
|
27099
|
-
const pathSuffix =
|
|
27096
|
+
const pathSuffix = path12.replace(/^\/api\/v1/, "");
|
|
27100
27097
|
const isAuthPath = _ParallClient.AUTH_PATHS.has(pathSuffix);
|
|
27101
27098
|
if (!retried && !isAuthPath && this.getRefreshToken) {
|
|
27102
27099
|
const refreshed = await this.tryRefresh();
|
|
27103
27100
|
if (refreshed) {
|
|
27104
|
-
return this.request(method,
|
|
27101
|
+
return this.request(method, path12, body, query, true, opts);
|
|
27105
27102
|
}
|
|
27106
27103
|
}
|
|
27107
27104
|
if (this.onTokenExpired && !isAuthPath) {
|
|
@@ -27131,15 +27128,15 @@ var ParallClient = class _ParallClient {
|
|
|
27131
27128
|
* hit the 100 MiB cap, so a longer 5-minute timeout is used so a
|
|
27132
27129
|
* 50 MiB blob on a slow connection doesn't get chopped at 15 s.
|
|
27133
27130
|
*/
|
|
27134
|
-
async multipartRequest(method,
|
|
27131
|
+
async multipartRequest(method, path12, body, retried = false) {
|
|
27135
27132
|
if (!retried) {
|
|
27136
|
-
await this.ensureFreshToken(
|
|
27133
|
+
await this.ensureFreshToken(path12);
|
|
27137
27134
|
}
|
|
27138
|
-
const { "Content-Type": _drop, ...headers } = this.buildHeaders(
|
|
27135
|
+
const { "Content-Type": _drop, ...headers } = this.buildHeaders(path12);
|
|
27139
27136
|
void _drop;
|
|
27140
27137
|
let res;
|
|
27141
27138
|
try {
|
|
27142
|
-
res = await fetch(`${this.baseUrlFor(
|
|
27139
|
+
res = await fetch(`${this.baseUrlFor(path12)}${path12}`, {
|
|
27143
27140
|
method,
|
|
27144
27141
|
headers,
|
|
27145
27142
|
body,
|
|
@@ -27149,12 +27146,12 @@ var ParallClient = class _ParallClient {
|
|
|
27149
27146
|
throw _ParallClient.normalizeFetchError(err);
|
|
27150
27147
|
}
|
|
27151
27148
|
if (res.status === 401) {
|
|
27152
|
-
const pathSuffix =
|
|
27149
|
+
const pathSuffix = path12.replace(/^\/api\/v1/, "");
|
|
27153
27150
|
const isAuthPath = _ParallClient.AUTH_PATHS.has(pathSuffix);
|
|
27154
27151
|
if (!retried && !isAuthPath && this.getRefreshToken) {
|
|
27155
27152
|
const refreshed = await this.tryRefresh();
|
|
27156
27153
|
if (refreshed) {
|
|
27157
|
-
return this.multipartRequest(method,
|
|
27154
|
+
return this.multipartRequest(method, path12, body, true);
|
|
27158
27155
|
}
|
|
27159
27156
|
}
|
|
27160
27157
|
if (this.onTokenExpired && !isAuthPath) {
|
|
@@ -27858,8 +27855,8 @@ var ParallClient = class _ParallClient {
|
|
|
27858
27855
|
async requestMachineUpdate(orgId, machineId, mandatory = false) {
|
|
27859
27856
|
await this.request("POST", ENDPOINTS.MACHINE_REQUEST_UPDATE(orgId, machineId), { mandatory });
|
|
27860
27857
|
}
|
|
27861
|
-
async browseMachineFilesystem(orgId, machineId,
|
|
27862
|
-
return this.request("POST", ENDPOINTS.MACHINE_BROWSE(orgId, machineId), { path:
|
|
27858
|
+
async browseMachineFilesystem(orgId, machineId, path12) {
|
|
27859
|
+
return this.request("POST", ENDPOINTS.MACHINE_BROWSE(orgId, machineId), { path: path12 }, void 0, false, { timeoutMs: 15e3 });
|
|
27863
27860
|
}
|
|
27864
27861
|
/** Create a new machine key. Returns the raw key string (shown once) + metadata. */
|
|
27865
27862
|
async createMachineKey(orgId, machineId, name) {
|
|
@@ -28431,8 +28428,8 @@ var ParallClient = class _ParallClient {
|
|
|
28431
28428
|
async deleteWikiRestriction(orgId, wikiId, restrictionId) {
|
|
28432
28429
|
await this.request("DELETE", ENDPOINTS.WIKI_RESTRICTION(orgId, wikiId, restrictionId));
|
|
28433
28430
|
}
|
|
28434
|
-
async getWikiAccessStatus(orgId, wikiId,
|
|
28435
|
-
return this.request("GET", ENDPOINTS.WIKI_ACCESS_STATUS(orgId, wikiId), void 0,
|
|
28431
|
+
async getWikiAccessStatus(orgId, wikiId, path12) {
|
|
28432
|
+
return this.request("GET", ENDPOINTS.WIKI_ACCESS_STATUS(orgId, wikiId), void 0, path12 ? { path: path12 } : void 0);
|
|
28436
28433
|
}
|
|
28437
28434
|
async createWikiAccessRequest(orgId, wikiId, data) {
|
|
28438
28435
|
await this.request("POST", ENDPOINTS.WIKI_ACCESS_REQUESTS(orgId, wikiId), data);
|
|
@@ -28441,14 +28438,14 @@ var ParallClient = class _ParallClient {
|
|
|
28441
28438
|
async getWikiCommits(orgId, wikiId, params) {
|
|
28442
28439
|
return this.request("GET", ENDPOINTS.WIKI_COMMITS(orgId, wikiId), void 0, params);
|
|
28443
28440
|
}
|
|
28444
|
-
async getWikiFileCommits(orgId, wikiId,
|
|
28441
|
+
async getWikiFileCommits(orgId, wikiId, path12, params) {
|
|
28445
28442
|
return this.request("GET", ENDPOINTS.WIKI_FILE_COMMITS(orgId, wikiId), void 0, {
|
|
28446
|
-
path:
|
|
28443
|
+
path: path12,
|
|
28447
28444
|
...params
|
|
28448
28445
|
});
|
|
28449
28446
|
}
|
|
28450
|
-
async getWikiBlame(orgId, wikiId,
|
|
28451
|
-
return this.request("GET", ENDPOINTS.WIKI_BLAME(orgId, wikiId), void 0, { path:
|
|
28447
|
+
async getWikiBlame(orgId, wikiId, path12, ref) {
|
|
28448
|
+
return this.request("GET", ENDPOINTS.WIKI_BLAME(orgId, wikiId), void 0, { path: path12, ref });
|
|
28452
28449
|
}
|
|
28453
28450
|
// ---- Wiki Operations (audit log) ----
|
|
28454
28451
|
async getWikiOperations(orgId, wikiId, params) {
|
|
@@ -29101,6 +29098,7 @@ var ParallWs = class {
|
|
|
29101
29098
|
};
|
|
29102
29099
|
|
|
29103
29100
|
// ts/agent-core/dist/lane-ledger.js
|
|
29101
|
+
import * as fs from "node:fs";
|
|
29104
29102
|
var LedgerUnsupportedError = class extends Error {
|
|
29105
29103
|
};
|
|
29106
29104
|
function isStaleLane(err) {
|
|
@@ -29384,6 +29382,20 @@ var LaneLedger = class {
|
|
|
29384
29382
|
this.lanes.set(lane.laneKey, lane);
|
|
29385
29383
|
return lane;
|
|
29386
29384
|
}
|
|
29385
|
+
/**
|
|
29386
|
+
* Drop a lane's local record without any server call — for a typed lane
|
|
29387
|
+
* whose member the by-id complete just resolved (the server dropped the
|
|
29388
|
+
* vacated lane row in the same transaction). Calling completeIfIdle
|
|
29389
|
+
* instead would fire a lane-form Complete at a lane that no longer exists
|
|
29390
|
+
* and burn an RPC on the guaranteed STALE_LANE answer.
|
|
29391
|
+
*/
|
|
29392
|
+
dropLocal(laneKey) {
|
|
29393
|
+
const lane = this.lanes.get(laneKey);
|
|
29394
|
+
if (!lane)
|
|
29395
|
+
return;
|
|
29396
|
+
this.lanes.delete(laneKey);
|
|
29397
|
+
this.removeLaneContext(lane);
|
|
29398
|
+
}
|
|
29387
29399
|
/**
|
|
29388
29400
|
* Remove the per-lane context file (and its CLI sidecar) when the lane
|
|
29389
29401
|
* ends. A leftover file would make a later cross-context send to the same
|
|
@@ -29463,10 +29475,104 @@ async function dispatchLaneGroup(host, opts) {
|
|
|
29463
29475
|
await ledger.completeIfIdle(lane.laneKey, pendingInjections || opts.hasMoreLocal());
|
|
29464
29476
|
return "dispatched";
|
|
29465
29477
|
}
|
|
29478
|
+
function typedLedgerEventIds(host, events) {
|
|
29479
|
+
if (!host.laneLedger || host.ledgerDisabled)
|
|
29480
|
+
return null;
|
|
29481
|
+
const ids = [];
|
|
29482
|
+
for (const ev of events) {
|
|
29483
|
+
if (!ev.dispatchEventId || host.usesLaneLedger(ev))
|
|
29484
|
+
return null;
|
|
29485
|
+
ids.push(ev.dispatchEventId);
|
|
29486
|
+
}
|
|
29487
|
+
return ids.length > 0 ? ids : null;
|
|
29488
|
+
}
|
|
29489
|
+
function isByIDCompleteUnsupported(err) {
|
|
29490
|
+
return err instanceof ApiError && err.status === 400;
|
|
29491
|
+
}
|
|
29492
|
+
async function resolveDispatchByID(host, dispatchEventId, lane) {
|
|
29493
|
+
try {
|
|
29494
|
+
await host.opts.client.completeDispatch(host.opts.config.org_id, {
|
|
29495
|
+
dispatch_event_id: dispatchEventId,
|
|
29496
|
+
...lane ? { lane } : {},
|
|
29497
|
+
turn_outcome: "ok"
|
|
29498
|
+
});
|
|
29499
|
+
return "ok";
|
|
29500
|
+
} catch (err) {
|
|
29501
|
+
if (err instanceof ApiError && err.status === 409)
|
|
29502
|
+
return "stale";
|
|
29503
|
+
if (isByIDCompleteUnsupported(err))
|
|
29504
|
+
return "unsupported";
|
|
29505
|
+
host.opts.log?.warn(`by-id complete failed for ${dispatchEventId} \u2014 leaving for re-drive: ${String(err)}`);
|
|
29506
|
+
return "failed";
|
|
29507
|
+
}
|
|
29508
|
+
}
|
|
29509
|
+
function clearTypedDedupeForEvent(host, event) {
|
|
29510
|
+
const sourceId = event.ackSourceId;
|
|
29511
|
+
if (!sourceId)
|
|
29512
|
+
return;
|
|
29513
|
+
switch (event.ackSourceType) {
|
|
29514
|
+
case "task_activity": {
|
|
29515
|
+
const prefix = `${event.targetId}:`;
|
|
29516
|
+
for (const key of host.dispatchedTasks) {
|
|
29517
|
+
if (key.startsWith(prefix))
|
|
29518
|
+
host.dispatchedTasks.delete(key);
|
|
29519
|
+
}
|
|
29520
|
+
break;
|
|
29521
|
+
}
|
|
29522
|
+
case "comment":
|
|
29523
|
+
host.dispatchedTasks.delete(`comment:${sourceId}`);
|
|
29524
|
+
break;
|
|
29525
|
+
case "schedule_run":
|
|
29526
|
+
host.dispatchedTasks.delete(`schedule_run:${sourceId}`);
|
|
29527
|
+
break;
|
|
29528
|
+
case "external_trigger_run":
|
|
29529
|
+
host.dispatchedTasks.delete(`external_trigger_run:${sourceId}`);
|
|
29530
|
+
break;
|
|
29531
|
+
case "channel_message":
|
|
29532
|
+
host.dispatchedMessages.delete(`channel_message:${sourceId}`);
|
|
29533
|
+
break;
|
|
29534
|
+
case "approval":
|
|
29535
|
+
host.dispatchedTasks.delete(`approval:${sourceId}`);
|
|
29536
|
+
break;
|
|
29537
|
+
}
|
|
29538
|
+
}
|
|
29539
|
+
async function settleDrainedTypedGroup(host, events, ids, turnErrored) {
|
|
29540
|
+
if (turnErrored) {
|
|
29541
|
+
host.opts.log?.info(`buffered typed turn for ${events[events.length - 1]?.messageId} surfaced a runtime error \u2014 leaving for re-drive`);
|
|
29542
|
+
for (const event of events)
|
|
29543
|
+
clearTypedDedupeForEvent(host, event);
|
|
29544
|
+
return;
|
|
29545
|
+
}
|
|
29546
|
+
const legacyAckFrom = async (start) => {
|
|
29547
|
+
for (const [j, id] of ids.slice(start).entries()) {
|
|
29548
|
+
try {
|
|
29549
|
+
await host.opts.client.ackDispatchByID(host.opts.config.org_id, id);
|
|
29550
|
+
} catch {
|
|
29551
|
+
clearTypedDedupeForEvent(host, events[start + j]);
|
|
29552
|
+
}
|
|
29553
|
+
}
|
|
29554
|
+
};
|
|
29555
|
+
if (host.typedByIdCompleteUnsupported) {
|
|
29556
|
+
await legacyAckFrom(0);
|
|
29557
|
+
return;
|
|
29558
|
+
}
|
|
29559
|
+
for (const [i, id] of ids.entries()) {
|
|
29560
|
+
const outcome = await resolveDispatchByID(host, id);
|
|
29561
|
+
if (outcome === "unsupported") {
|
|
29562
|
+
host.typedByIdCompleteUnsupported = true;
|
|
29563
|
+
host.opts.log?.warn("server predates the by-id dispatch complete \u2014 falling back to legacy typed acks");
|
|
29564
|
+
await legacyAckFrom(i);
|
|
29565
|
+
return;
|
|
29566
|
+
}
|
|
29567
|
+
if (outcome !== "ok") {
|
|
29568
|
+
clearTypedDedupeForEvent(host, events[i]);
|
|
29569
|
+
}
|
|
29570
|
+
}
|
|
29571
|
+
}
|
|
29466
29572
|
var TYPED_BACKOFF_BASE_MS = 2e3;
|
|
29467
29573
|
var TYPED_BACKOFF_CAP_MS = 5 * 6e4;
|
|
29468
29574
|
var TYPED_BACKOFF_MAP_CAP = 512;
|
|
29469
|
-
async function consumeTypedDispatch(host, ref, run,
|
|
29575
|
+
async function consumeTypedDispatch(host, ref, run, hooks) {
|
|
29470
29576
|
const backoffKey = ref.dispatchEventId ?? `${ref.sourceType}:${ref.sourceId}`;
|
|
29471
29577
|
const armed = host.typedRedriveBackoff.get(backoffKey);
|
|
29472
29578
|
if (armed) {
|
|
@@ -29482,8 +29588,8 @@ async function consumeTypedDispatch(host, ref, run, ack) {
|
|
|
29482
29588
|
return;
|
|
29483
29589
|
}
|
|
29484
29590
|
const settleAck = (ackResult) => ackResult !== false;
|
|
29485
|
-
const settle = (
|
|
29486
|
-
if (
|
|
29591
|
+
const settle = (resolved2) => {
|
|
29592
|
+
if (resolved2) {
|
|
29487
29593
|
host.typedRedriveBackoff.delete(backoffKey);
|
|
29488
29594
|
return;
|
|
29489
29595
|
}
|
|
@@ -29497,13 +29603,13 @@ async function consumeTypedDispatch(host, ref, run, ack) {
|
|
|
29497
29603
|
host.typedRedriveBackoff.set(backoffKey, { failures, until: Date.now() + backoffMs });
|
|
29498
29604
|
};
|
|
29499
29605
|
const runLegacy = async () => {
|
|
29500
|
-
let
|
|
29606
|
+
let acked = false;
|
|
29501
29607
|
try {
|
|
29502
29608
|
if (await run(ref.dispatchEventId)) {
|
|
29503
|
-
|
|
29609
|
+
acked = settleAck(await hooks.legacyAck(ref.dispatchEventId));
|
|
29504
29610
|
}
|
|
29505
29611
|
} finally {
|
|
29506
|
-
settle(
|
|
29612
|
+
settle(acked);
|
|
29507
29613
|
}
|
|
29508
29614
|
};
|
|
29509
29615
|
if (!host.laneLedger || host.ledgerDisabled) {
|
|
@@ -29525,15 +29631,39 @@ async function consumeTypedDispatch(host, ref, run, ack) {
|
|
|
29525
29631
|
host.opts.log?.info(`typed dispatch ${ref.dispatchEventId ?? `${ref.sourceType}:${ref.sourceId}`} not claimable (held elsewhere or already resolved) \u2014 skipping`);
|
|
29526
29632
|
return;
|
|
29527
29633
|
}
|
|
29528
|
-
let
|
|
29634
|
+
let resolved = false;
|
|
29635
|
+
let viaLegacyAck = false;
|
|
29529
29636
|
try {
|
|
29530
29637
|
if (await run(lane.typedDispatchEventId)) {
|
|
29531
|
-
|
|
29638
|
+
if (host.typedByIdCompleteUnsupported || !lane.typedDispatchEventId) {
|
|
29639
|
+
viaLegacyAck = true;
|
|
29640
|
+
resolved = settleAck(await hooks.legacyAck(lane.typedDispatchEventId));
|
|
29641
|
+
} else {
|
|
29642
|
+
const outcome = await resolveDispatchByID(host, lane.typedDispatchEventId, lane.lane);
|
|
29643
|
+
if (outcome === "unsupported") {
|
|
29644
|
+
host.typedByIdCompleteUnsupported = true;
|
|
29645
|
+
host.opts.log?.warn("server predates the by-id dispatch complete \u2014 falling back to the legacy typed ack");
|
|
29646
|
+
viaLegacyAck = true;
|
|
29647
|
+
resolved = settleAck(await hooks.legacyAck(lane.typedDispatchEventId));
|
|
29648
|
+
} else if (outcome === "stale") {
|
|
29649
|
+
hooks.clearDedupe?.();
|
|
29650
|
+
resolved = true;
|
|
29651
|
+
} else {
|
|
29652
|
+
resolved = outcome === "ok";
|
|
29653
|
+
if (!resolved) {
|
|
29654
|
+
hooks.clearDedupe?.();
|
|
29655
|
+
}
|
|
29656
|
+
}
|
|
29657
|
+
}
|
|
29532
29658
|
}
|
|
29533
29659
|
} finally {
|
|
29534
|
-
settle(
|
|
29535
|
-
|
|
29536
|
-
|
|
29660
|
+
settle(resolved);
|
|
29661
|
+
if (resolved && !viaLegacyAck) {
|
|
29662
|
+
host.laneLedger.dropLocal(lane.laneKey);
|
|
29663
|
+
} else {
|
|
29664
|
+
await host.laneLedger.completeIfIdle(lane.laneKey, false).catch(() => {
|
|
29665
|
+
});
|
|
29666
|
+
}
|
|
29537
29667
|
}
|
|
29538
29668
|
}
|
|
29539
29669
|
async function consumeMessageWorkItem(host, item) {
|
|
@@ -29542,6 +29672,16 @@ async function consumeMessageWorkItem(host, item) {
|
|
|
29542
29672
|
if (!host.tryClaimMessage(item.source_id))
|
|
29543
29673
|
return;
|
|
29544
29674
|
const ackItem = () => {
|
|
29675
|
+
if (host.laneLedger && !host.ledgerDisabled && !host.typedByIdCompleteUnsupported) {
|
|
29676
|
+
void resolveDispatchByID(host, item.id).then((outcome) => {
|
|
29677
|
+
if (outcome === "unsupported") {
|
|
29678
|
+
host.typedByIdCompleteUnsupported = true;
|
|
29679
|
+
host.opts.client.ackDispatchByID(host.opts.config.org_id, item.id).catch(() => {
|
|
29680
|
+
});
|
|
29681
|
+
}
|
|
29682
|
+
});
|
|
29683
|
+
return;
|
|
29684
|
+
}
|
|
29545
29685
|
host.opts.client.ackDispatchByID(host.opts.config.org_id, item.id).catch(() => {
|
|
29546
29686
|
});
|
|
29547
29687
|
};
|
|
@@ -30721,20 +30861,23 @@ var ParallAgentGateway = class {
|
|
|
30721
30861
|
if (data.status !== "todo" && data.status !== "in_progress")
|
|
30722
30862
|
return;
|
|
30723
30863
|
try {
|
|
30724
|
-
await this.consumeTypedDispatch(data.dispatch_event_id ? { dispatchEventId: data.dispatch_event_id } : { sourceType: "task_activity", sourceId: data.id }, (dispatchEventId) => this.handleTaskAssignment(data, data.id, dispatchEventId),
|
|
30725
|
-
|
|
30726
|
-
|
|
30864
|
+
await this.consumeTypedDispatch(data.dispatch_event_id ? { dispatchEventId: data.dispatch_event_id } : { sourceType: "task_activity", sourceId: data.id }, (dispatchEventId) => this.handleTaskAssignment(data, data.id, dispatchEventId), {
|
|
30865
|
+
legacyAck: (dispatchEventId) => {
|
|
30866
|
+
if (dispatchEventId) {
|
|
30867
|
+
return this.ackDispatchEvent(dispatchEventId, () => {
|
|
30868
|
+
this.dispatchedTasks.delete(`${data.id}:${data.updated_at}`);
|
|
30869
|
+
});
|
|
30870
|
+
}
|
|
30871
|
+
return this.opts.client.ackDispatch(this.opts.config.org_id, {
|
|
30872
|
+
source_type: "task_activity",
|
|
30873
|
+
source_id: data.id
|
|
30874
|
+
}).then(() => true, (err) => {
|
|
30727
30875
|
this.dispatchedTasks.delete(`${data.id}:${data.updated_at}`);
|
|
30876
|
+
this.opts.log?.warn(`dispatch ack failed for task ${data.id}, releasing for re-drive: ${String(err)}`);
|
|
30877
|
+
return false;
|
|
30728
30878
|
});
|
|
30729
|
-
}
|
|
30730
|
-
|
|
30731
|
-
source_type: "task_activity",
|
|
30732
|
-
source_id: data.id
|
|
30733
|
-
}).then(() => true, (err) => {
|
|
30734
|
-
this.dispatchedTasks.delete(`${data.id}:${data.updated_at}`);
|
|
30735
|
-
this.opts.log?.warn(`dispatch ack failed for task ${data.id}, releasing for re-drive: ${String(err)}`);
|
|
30736
|
-
return false;
|
|
30737
|
-
});
|
|
30879
|
+
},
|
|
30880
|
+
clearDedupe: () => this.dispatchedTasks.delete(`${data.id}:${data.updated_at}`)
|
|
30738
30881
|
});
|
|
30739
30882
|
} catch (err) {
|
|
30740
30883
|
this.opts.log?.error(`task dispatch failed for ${data.id}: ${String(err)}`);
|
|
@@ -30753,7 +30896,10 @@ var ParallAgentGateway = class {
|
|
|
30753
30896
|
if (!data.source_id || !data.task_id)
|
|
30754
30897
|
return;
|
|
30755
30898
|
try {
|
|
30756
|
-
await this.consumeTypedDispatch({ dispatchEventId: data.id }, () => this.handleTaskComment(data.source_id, data.task_id ?? "", data.actor_id, data.delivery_reason
|
|
30899
|
+
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.handleTaskComment(data.source_id, data.task_id ?? "", data.actor_id, data.delivery_reason, dispatchEventId), {
|
|
30900
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
30901
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data)
|
|
30902
|
+
});
|
|
30757
30903
|
} catch (err) {
|
|
30758
30904
|
this.opts.log?.error(`task comment dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
30759
30905
|
}
|
|
@@ -30761,7 +30907,10 @@ var ParallAgentGateway = class {
|
|
|
30761
30907
|
if (!data.source_id)
|
|
30762
30908
|
return;
|
|
30763
30909
|
try {
|
|
30764
|
-
await this.consumeTypedDispatch({ dispatchEventId: data.id }, () => this.handleWikiComment(data.source_id, data.actor_id, data.delivery_reason
|
|
30910
|
+
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.handleWikiComment(data.source_id, data.actor_id, data.delivery_reason, dispatchEventId), {
|
|
30911
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
30912
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data)
|
|
30913
|
+
});
|
|
30765
30914
|
} catch (err) {
|
|
30766
30915
|
this.opts.log?.error(`wiki comment dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
30767
30916
|
}
|
|
@@ -30772,7 +30921,10 @@ var ParallAgentGateway = class {
|
|
|
30772
30921
|
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.handleTaskDispatch(data.task_id ?? "", data.source_id ?? data.task_id ?? "", {
|
|
30773
30922
|
allowCreator: true,
|
|
30774
30923
|
dispatchEventId
|
|
30775
|
-
}),
|
|
30924
|
+
}), {
|
|
30925
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
30926
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data)
|
|
30927
|
+
});
|
|
30776
30928
|
} catch (err) {
|
|
30777
30929
|
this.opts.log?.error(`task update dispatch failed for ${data.task_id}: ${String(err)}`);
|
|
30778
30930
|
}
|
|
@@ -30780,7 +30932,10 @@ var ParallAgentGateway = class {
|
|
|
30780
30932
|
if (!data.source_id)
|
|
30781
30933
|
return;
|
|
30782
30934
|
try {
|
|
30783
|
-
await this.consumeTypedDispatch({ dispatchEventId: data.id }, () => this.fetchAndHandleScheduleFire(data.source_id, data.actor_id
|
|
30935
|
+
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.fetchAndHandleScheduleFire(data.source_id, data.actor_id, dispatchEventId), {
|
|
30936
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
30937
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data)
|
|
30938
|
+
});
|
|
30784
30939
|
} catch (err) {
|
|
30785
30940
|
this.opts.log?.error(`schedule fire dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
30786
30941
|
}
|
|
@@ -30788,7 +30943,10 @@ var ParallAgentGateway = class {
|
|
|
30788
30943
|
if (!data.source_id)
|
|
30789
30944
|
return;
|
|
30790
30945
|
try {
|
|
30791
|
-
await this.consumeTypedDispatch({ dispatchEventId: data.id }, () => this.fetchAndHandleExternalTriggerRun(data.source_id
|
|
30946
|
+
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.fetchAndHandleExternalTriggerRun(data.source_id, dispatchEventId), {
|
|
30947
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
30948
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data)
|
|
30949
|
+
});
|
|
30792
30950
|
} catch (err) {
|
|
30793
30951
|
this.opts.log?.error(`external trigger dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
30794
30952
|
}
|
|
@@ -30796,7 +30954,10 @@ var ParallAgentGateway = class {
|
|
|
30796
30954
|
if (!data.source_id)
|
|
30797
30955
|
return;
|
|
30798
30956
|
try {
|
|
30799
|
-
await this.consumeTypedDispatch({ dispatchEventId: data.id }, () => this.fetchAndHandleChannelMessage(data.source_id
|
|
30957
|
+
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.fetchAndHandleChannelMessage(data.source_id, dispatchEventId), {
|
|
30958
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
30959
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data)
|
|
30960
|
+
});
|
|
30800
30961
|
} catch (err) {
|
|
30801
30962
|
this.opts.log?.error(`channel message dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
30802
30963
|
}
|
|
@@ -30804,7 +30965,10 @@ var ParallAgentGateway = class {
|
|
|
30804
30965
|
if (!data.source_id)
|
|
30805
30966
|
return;
|
|
30806
30967
|
try {
|
|
30807
|
-
await this.consumeTypedDispatch({ dispatchEventId: data.id }, () => this.fetchAndHandleApprovalDecided(data.source_id, data.actor_id, data.chat_id ?? null
|
|
30968
|
+
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.fetchAndHandleApprovalDecided(data.source_id, data.actor_id, data.chat_id ?? null, dispatchEventId), {
|
|
30969
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
30970
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data)
|
|
30971
|
+
});
|
|
30808
30972
|
} catch (err) {
|
|
30809
30973
|
this.opts.log?.error(`approval decided dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
30810
30974
|
}
|
|
@@ -30887,6 +31051,20 @@ var ParallAgentGateway = class {
|
|
|
30887
31051
|
source_id: sourceId
|
|
30888
31052
|
});
|
|
30889
31053
|
}
|
|
31054
|
+
/**
|
|
31055
|
+
* Sticky: the server answered a by-id complete with 400 (predates the
|
|
31056
|
+
* form). Typed resolution falls back to the legacy ack for the rest of
|
|
31057
|
+
* the process lifetime.
|
|
31058
|
+
*/
|
|
31059
|
+
typedByIdCompleteUnsupported = false;
|
|
31060
|
+
// Typed-face ledger helpers live in gateway-lane-flow.ts; thin delegates
|
|
31061
|
+
// keep the site code and tests on the class surface.
|
|
31062
|
+
typedLedgerEventIds(events) {
|
|
31063
|
+
return typedLedgerEventIds(this.laneFlowHost(), events);
|
|
31064
|
+
}
|
|
31065
|
+
resolveDispatchByID(dispatchEventId, lane) {
|
|
31066
|
+
return resolveDispatchByID(this.laneFlowHost(), dispatchEventId, lane);
|
|
31067
|
+
}
|
|
30890
31068
|
/** True when this event's lifecycle is owned by the dispatch lane ledger. */
|
|
30891
31069
|
usesLaneLedger(event) {
|
|
30892
31070
|
return this.laneLedger != null && !this.ledgerDisabled && this.laneLedger.handles(event);
|
|
@@ -30917,15 +31095,16 @@ var ParallAgentGateway = class {
|
|
|
30917
31095
|
dispatchLaneGroup(opts) {
|
|
30918
31096
|
return dispatchLaneGroup(this.laneFlowHost(), opts);
|
|
30919
31097
|
}
|
|
30920
|
-
consumeTypedDispatch(ref, run,
|
|
30921
|
-
return consumeTypedDispatch(this.laneFlowHost(), ref, run,
|
|
31098
|
+
consumeTypedDispatch(ref, run, hooks) {
|
|
31099
|
+
return consumeTypedDispatch(this.laneFlowHost(), ref, run, hooks);
|
|
30922
31100
|
}
|
|
30923
|
-
//
|
|
30924
|
-
//
|
|
30925
|
-
//
|
|
30926
|
-
//
|
|
30927
|
-
//
|
|
30928
|
-
//
|
|
31101
|
+
// Legacy administrative ack (ledger-disabled fallback only). Typed
|
|
31102
|
+
// completion must wait until the ack has either committed or failed.
|
|
31103
|
+
// Errors stay best-effort: a failed ack leaves the row received, so
|
|
31104
|
+
// Complete releases and re-drives it safely. The boolean outcome feeds the
|
|
31105
|
+
// typed-consume backoff — an ack that failed must count as a failed
|
|
31106
|
+
// consume, or an ack outage would clear the backoff entry and let the
|
|
31107
|
+
// release re-drive spin at wire speed.
|
|
30929
31108
|
ackDispatchEvent(dispatchEventId, onFailure) {
|
|
30930
31109
|
return this.opts.client.ackDispatchByID(this.opts.config.org_id, dispatchEventId).then(() => true, (err) => {
|
|
30931
31110
|
onFailure?.();
|
|
@@ -30933,6 +31112,9 @@ var ParallAgentGateway = class {
|
|
|
30933
31112
|
return false;
|
|
30934
31113
|
});
|
|
30935
31114
|
}
|
|
31115
|
+
// PARITY: this switch and gateway-lane-flow's clearTypedDedupeForEvent must
|
|
31116
|
+
// handle the same typed source families — extend BOTH when adding a typed
|
|
31117
|
+
// event type (same dedupe entries, keyed from different event shapes).
|
|
30936
31118
|
clearTypedDispatchDedupe(item) {
|
|
30937
31119
|
switch (item.event_type) {
|
|
30938
31120
|
case "task_assign":
|
|
@@ -31506,6 +31688,12 @@ var ParallAgentGateway = class {
|
|
|
31506
31688
|
dispatched = outcome === "dispatched";
|
|
31507
31689
|
} else {
|
|
31508
31690
|
dispatched = await this.runDispatch(last, fork.fork.sessionKey, buildForkScopePrefix(last) + buildEventBody(last), earlier, batchText);
|
|
31691
|
+
if (dispatched && this.typedLedgerEventIds(events) && this.consumeTurnError(fork.fork.sessionKey)) {
|
|
31692
|
+
this.opts.log?.info(`typed fork turn for ${last.messageId} surfaced a runtime error \u2014 releasing for retry`);
|
|
31693
|
+
for (const item of items)
|
|
31694
|
+
item.resolve(false);
|
|
31695
|
+
continue;
|
|
31696
|
+
}
|
|
31509
31697
|
}
|
|
31510
31698
|
if (!dispatched) {
|
|
31511
31699
|
for (const item of items) {
|
|
@@ -31655,13 +31843,16 @@ var ParallAgentGateway = class {
|
|
|
31655
31843
|
}
|
|
31656
31844
|
continue;
|
|
31657
31845
|
}
|
|
31658
|
-
|
|
31659
|
-
|
|
31660
|
-
|
|
31661
|
-
|
|
31662
|
-
|
|
31663
|
-
|
|
31664
|
-
|
|
31846
|
+
const typedRefs = this.typedLedgerEventIds(events);
|
|
31847
|
+
if (!typedRefs) {
|
|
31848
|
+
try {
|
|
31849
|
+
await this.emitDispatchReceived(event);
|
|
31850
|
+
} catch (err) {
|
|
31851
|
+
this.opts.log?.warn?.(`mark-received failed for buffered dispatch, leaving unacked for retry: ${String(err)}`);
|
|
31852
|
+
this.dispatchState.mainBuffer.unshift(...events);
|
|
31853
|
+
this.dispatchState.pendingForkResults.unshift(...pendingFork);
|
|
31854
|
+
break;
|
|
31855
|
+
}
|
|
31665
31856
|
}
|
|
31666
31857
|
const dispatched = await this.runDispatch(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event), earlier);
|
|
31667
31858
|
if (!dispatched) {
|
|
@@ -31669,6 +31860,10 @@ var ParallAgentGateway = class {
|
|
|
31669
31860
|
this.dispatchState.pendingForkResults.unshift(...pendingFork);
|
|
31670
31861
|
break;
|
|
31671
31862
|
}
|
|
31863
|
+
if (typedRefs) {
|
|
31864
|
+
await settleDrainedTypedGroup(this.laneFlowHost(), events, typedRefs, this.consumeTurnError(this.opts.runtimeKey));
|
|
31865
|
+
continue;
|
|
31866
|
+
}
|
|
31672
31867
|
for (const bufferedEvent of events) {
|
|
31673
31868
|
const sourceType = bufferedEvent.ackSourceType ?? (bufferedEvent.type === "task" ? "task_activity" : "message");
|
|
31674
31869
|
const sourceId = bufferedEvent.ackSourceId ?? bufferedEvent.messageId;
|
|
@@ -31728,20 +31923,27 @@ var ParallAgentGateway = class {
|
|
|
31728
31923
|
}
|
|
31729
31924
|
return outcome === "dispatched";
|
|
31730
31925
|
}
|
|
31731
|
-
|
|
31732
|
-
|
|
31733
|
-
|
|
31734
|
-
|
|
31735
|
-
|
|
31736
|
-
|
|
31737
|
-
|
|
31738
|
-
|
|
31739
|
-
|
|
31740
|
-
|
|
31926
|
+
const typedRefs = this.typedLedgerEventIds([event]);
|
|
31927
|
+
if (!typedRefs) {
|
|
31928
|
+
try {
|
|
31929
|
+
await this.emitDispatchReceived(event);
|
|
31930
|
+
} catch (err) {
|
|
31931
|
+
this.opts.log?.warn?.(`mark-received failed, leaving unacked for retry: ${String(err)}`);
|
|
31932
|
+
this.dispatchState.mainDispatching = false;
|
|
31933
|
+
this.dispatchState.mainCurrentTargetId = void 0;
|
|
31934
|
+
this.mainCurrentGroupKey = void 0;
|
|
31935
|
+
this.dispatchState.mainPreDispatchBranchPoint = void 0;
|
|
31936
|
+
this.dispatchState.pendingForkResults.unshift(...pendingFork);
|
|
31937
|
+
return false;
|
|
31938
|
+
}
|
|
31741
31939
|
}
|
|
31742
31940
|
let dispatched = false;
|
|
31743
31941
|
try {
|
|
31744
31942
|
dispatched = await this.runDispatch(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event));
|
|
31943
|
+
if (dispatched && typedRefs && this.consumeTurnError(this.opts.runtimeKey)) {
|
|
31944
|
+
this.opts.log?.info(`typed dispatch turn for ${event.messageId} surfaced a runtime error \u2014 releasing for retry`);
|
|
31945
|
+
dispatched = false;
|
|
31946
|
+
}
|
|
31745
31947
|
if (!dispatched) {
|
|
31746
31948
|
this.dispatchState.pendingForkResults.unshift(...pendingFork);
|
|
31747
31949
|
}
|
|
@@ -31783,7 +31985,7 @@ var ParallAgentGateway = class {
|
|
|
31783
31985
|
this.dispatchState.mainBuffer.push(event);
|
|
31784
31986
|
return false;
|
|
31785
31987
|
}
|
|
31786
|
-
if (!this.usesLaneLedger(event)) {
|
|
31988
|
+
if (!this.usesLaneLedger(event) && !this.typedLedgerEventIds([event])) {
|
|
31787
31989
|
try {
|
|
31788
31990
|
await this.emitDispatchReceived(event);
|
|
31789
31991
|
} catch (err) {
|
|
@@ -31964,7 +32166,10 @@ var ParallAgentGateway = class {
|
|
|
31964
32166
|
return;
|
|
31965
32167
|
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.handleTaskDispatch(item.task_id ?? "", item.source_id ?? item.task_id ?? "", {
|
|
31966
32168
|
dispatchEventId
|
|
31967
|
-
}),
|
|
32169
|
+
}), {
|
|
32170
|
+
legacyAck: (dispatchEventId) => this.ackDispatchEvent(dispatchEventId ?? item.id, () => this.clearTypedDispatchDedupe(item)),
|
|
32171
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(item)
|
|
32172
|
+
});
|
|
31968
32173
|
}
|
|
31969
32174
|
consumeMessageWorkItem(item) {
|
|
31970
32175
|
return consumeMessageWorkItem(this.laneFlowHost(), item);
|
|
@@ -32025,7 +32230,7 @@ var ParallAgentGateway = class {
|
|
|
32025
32230
|
}
|
|
32026
32231
|
return this.handleTaskAssignment(task, ackSourceId, opts.dispatchEventId);
|
|
32027
32232
|
}
|
|
32028
|
-
async handleTaskComment(commentId, taskId, actorId, deliveryReason) {
|
|
32233
|
+
async handleTaskComment(commentId, taskId, actorId, deliveryReason, dispatchEventId) {
|
|
32029
32234
|
if (this.shuttingDown)
|
|
32030
32235
|
return false;
|
|
32031
32236
|
const dedupeKey = `comment:${commentId}`;
|
|
@@ -32081,7 +32286,8 @@ var ParallAgentGateway = class {
|
|
|
32081
32286
|
body: parts.join("\n"),
|
|
32082
32287
|
deliveryReason: deliveryReason ?? void 0,
|
|
32083
32288
|
ackSourceType: "comment",
|
|
32084
|
-
ackSourceId: commentId
|
|
32289
|
+
ackSourceId: commentId,
|
|
32290
|
+
dispatchEventId
|
|
32085
32291
|
};
|
|
32086
32292
|
let dispatched;
|
|
32087
32293
|
try {
|
|
@@ -32095,7 +32301,7 @@ var ParallAgentGateway = class {
|
|
|
32095
32301
|
}
|
|
32096
32302
|
return dispatched;
|
|
32097
32303
|
}
|
|
32098
|
-
async handleWikiComment(commentId, actorId, deliveryReason) {
|
|
32304
|
+
async handleWikiComment(commentId, actorId, deliveryReason, dispatchEventId) {
|
|
32099
32305
|
if (this.shuttingDown)
|
|
32100
32306
|
return false;
|
|
32101
32307
|
const dedupeKey = `comment:${commentId}`;
|
|
@@ -32141,7 +32347,8 @@ var ParallAgentGateway = class {
|
|
|
32141
32347
|
deliveryReason: deliveryReason ?? void 0,
|
|
32142
32348
|
replyTargetUri: comment.target_uri,
|
|
32143
32349
|
ackSourceType: "comment",
|
|
32144
|
-
ackSourceId: commentId
|
|
32350
|
+
ackSourceId: commentId,
|
|
32351
|
+
dispatchEventId
|
|
32145
32352
|
};
|
|
32146
32353
|
let dispatched;
|
|
32147
32354
|
try {
|
|
@@ -32163,7 +32370,7 @@ var ParallAgentGateway = class {
|
|
|
32163
32370
|
* access to already-delivered run snapshots, and the runtime must not crash
|
|
32164
32371
|
* or retry forever in that case.
|
|
32165
32372
|
*/
|
|
32166
|
-
async fetchAndHandleScheduleFire(runId, actorId) {
|
|
32373
|
+
async fetchAndHandleScheduleFire(runId, actorId, dispatchEventId) {
|
|
32167
32374
|
let run = null;
|
|
32168
32375
|
try {
|
|
32169
32376
|
run = await this.opts.client.getScheduleRun(this.opts.config.org_id, runId);
|
|
@@ -32178,9 +32385,9 @@ var ParallAgentGateway = class {
|
|
|
32178
32385
|
}
|
|
32179
32386
|
if (!run)
|
|
32180
32387
|
return true;
|
|
32181
|
-
return this.handleScheduleFire(run, actorId);
|
|
32388
|
+
return this.handleScheduleFire(run, actorId, dispatchEventId);
|
|
32182
32389
|
}
|
|
32183
|
-
async handleScheduleFire(run, actorId) {
|
|
32390
|
+
async handleScheduleFire(run, actorId, dispatchEventId) {
|
|
32184
32391
|
if (this.shuttingDown)
|
|
32185
32392
|
return false;
|
|
32186
32393
|
const dedupeKey = `schedule_run:${run.id}`;
|
|
@@ -32203,7 +32410,8 @@ var ParallAgentGateway = class {
|
|
|
32203
32410
|
scheduledFireAt: run.scheduled_fire_at,
|
|
32204
32411
|
attachedUri: run.fired_attached_uri ?? void 0,
|
|
32205
32412
|
ackSourceType: "schedule_run",
|
|
32206
|
-
ackSourceId: run.id
|
|
32413
|
+
ackSourceId: run.id,
|
|
32414
|
+
dispatchEventId
|
|
32207
32415
|
};
|
|
32208
32416
|
let dispatched;
|
|
32209
32417
|
try {
|
|
@@ -32217,7 +32425,7 @@ var ParallAgentGateway = class {
|
|
|
32217
32425
|
}
|
|
32218
32426
|
return dispatched;
|
|
32219
32427
|
}
|
|
32220
|
-
async fetchAndHandleExternalTriggerRun(runId) {
|
|
32428
|
+
async fetchAndHandleExternalTriggerRun(runId, dispatchEventId) {
|
|
32221
32429
|
let run = null;
|
|
32222
32430
|
try {
|
|
32223
32431
|
run = await this.opts.client.getExternalTriggerRun(this.opts.config.org_id, runId);
|
|
@@ -32232,14 +32440,14 @@ var ParallAgentGateway = class {
|
|
|
32232
32440
|
}
|
|
32233
32441
|
if (!run)
|
|
32234
32442
|
return true;
|
|
32235
|
-
return this.handleExternalTriggerRun(run);
|
|
32443
|
+
return this.handleExternalTriggerRun(run, dispatchEventId);
|
|
32236
32444
|
}
|
|
32237
32445
|
// fetchAndHandleChannelMessage resolves a channel_message dispatch to its
|
|
32238
32446
|
// durable ChannelMessage + conversation and hands it to the inbound
|
|
32239
32447
|
// pipeline. targetId = the ChannelConversation id, so per-conversation
|
|
32240
32448
|
// multi-turn continuity rides the same per-target session mechanics as
|
|
32241
32449
|
// chats. Design: docs/engineering-design/external-im-channel-design.md.
|
|
32242
|
-
async fetchAndHandleChannelMessage(messageId) {
|
|
32450
|
+
async fetchAndHandleChannelMessage(messageId, dispatchEventId) {
|
|
32243
32451
|
if (this.shuttingDown)
|
|
32244
32452
|
return false;
|
|
32245
32453
|
const claimKey = `channel_message:${messageId}`;
|
|
@@ -32292,7 +32500,8 @@ var ParallAgentGateway = class {
|
|
|
32292
32500
|
channelExternalMessageId: msg.external_message_id,
|
|
32293
32501
|
channelCliCapable: cliCapable,
|
|
32294
32502
|
ackSourceType: "channel_message",
|
|
32295
|
-
ackSourceId: msg.id
|
|
32503
|
+
ackSourceId: msg.id,
|
|
32504
|
+
dispatchEventId
|
|
32296
32505
|
};
|
|
32297
32506
|
let dispatched;
|
|
32298
32507
|
try {
|
|
@@ -32306,7 +32515,7 @@ var ParallAgentGateway = class {
|
|
|
32306
32515
|
}
|
|
32307
32516
|
return dispatched;
|
|
32308
32517
|
}
|
|
32309
|
-
async handleExternalTriggerRun(run) {
|
|
32518
|
+
async handleExternalTriggerRun(run, dispatchEventId) {
|
|
32310
32519
|
if (this.shuttingDown)
|
|
32311
32520
|
return false;
|
|
32312
32521
|
const dedupeKey = `external_trigger_run:${run.id}`;
|
|
@@ -32331,7 +32540,8 @@ var ParallAgentGateway = class {
|
|
|
32331
32540
|
externalIngressEventType: run.ingress_event_type || void 0,
|
|
32332
32541
|
attachedUri,
|
|
32333
32542
|
ackSourceType: "external_trigger_run",
|
|
32334
|
-
ackSourceId: run.id
|
|
32543
|
+
ackSourceId: run.id,
|
|
32544
|
+
dispatchEventId
|
|
32335
32545
|
};
|
|
32336
32546
|
let dispatched;
|
|
32337
32547
|
try {
|
|
@@ -32345,7 +32555,7 @@ var ParallAgentGateway = class {
|
|
|
32345
32555
|
}
|
|
32346
32556
|
return dispatched;
|
|
32347
32557
|
}
|
|
32348
|
-
async fetchAndHandleApprovalDecided(approvalId, actorId, chatId) {
|
|
32558
|
+
async fetchAndHandleApprovalDecided(approvalId, actorId, chatId, dispatchEventId) {
|
|
32349
32559
|
let approval = null;
|
|
32350
32560
|
try {
|
|
32351
32561
|
approval = await this.opts.client.getApproval(approvalId);
|
|
@@ -32376,7 +32586,12 @@ var ParallAgentGateway = class {
|
|
|
32376
32586
|
senderId: actorId ?? approval.decided_by ?? "system",
|
|
32377
32587
|
senderName: "approver",
|
|
32378
32588
|
messageId: approval.id,
|
|
32379
|
-
body
|
|
32589
|
+
body,
|
|
32590
|
+
// The WorkItem's real source pair. Without it the legacy fallback
|
|
32591
|
+
// guessed ('message', approval_id) — a pair no row matches.
|
|
32592
|
+
ackSourceType: "approval",
|
|
32593
|
+
ackSourceId: approval.id,
|
|
32594
|
+
dispatchEventId
|
|
32380
32595
|
};
|
|
32381
32596
|
let dispatched;
|
|
32382
32597
|
try {
|
|
@@ -32423,7 +32638,17 @@ var ParallAgentGateway = class {
|
|
|
32423
32638
|
break;
|
|
32424
32639
|
if (overflowMode && processed >= CATCHUP_MAX) {
|
|
32425
32640
|
try {
|
|
32426
|
-
|
|
32641
|
+
if (this.laneLedger && !this.ledgerDisabled && !this.typedByIdCompleteUnsupported) {
|
|
32642
|
+
const outcome = await this.resolveDispatchByID(item.id);
|
|
32643
|
+
if (outcome === "unsupported") {
|
|
32644
|
+
this.typedByIdCompleteUnsupported = true;
|
|
32645
|
+
await this.opts.client.ackDispatchByID(this.opts.config.org_id, item.id);
|
|
32646
|
+
} else if (outcome === "failed") {
|
|
32647
|
+
throw new Error("by-id complete failed");
|
|
32648
|
+
}
|
|
32649
|
+
} else {
|
|
32650
|
+
await this.opts.client.ackDispatchByID(this.opts.config.org_id, item.id);
|
|
32651
|
+
}
|
|
32427
32652
|
skipped++;
|
|
32428
32653
|
const key = item.event_type;
|
|
32429
32654
|
skippedByType.set(key, (skippedByType.get(key) ?? 0) + 1);
|
|
@@ -32434,12 +32659,15 @@ var ParallAgentGateway = class {
|
|
|
32434
32659
|
}
|
|
32435
32660
|
processed++;
|
|
32436
32661
|
try {
|
|
32437
|
-
const
|
|
32662
|
+
const typedHooks = {
|
|
32663
|
+
legacyAck: () => this.ackDispatchEvent(item.id, () => this.clearTypedDispatchDedupe(item)),
|
|
32664
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(item)
|
|
32665
|
+
};
|
|
32438
32666
|
if (item.event_type === "task_assign" && item.task_id) {
|
|
32439
32667
|
try {
|
|
32440
32668
|
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.handleTaskDispatch(item.task_id ?? "", item.source_id ?? item.task_id ?? "", {
|
|
32441
32669
|
dispatchEventId
|
|
32442
|
-
}),
|
|
32670
|
+
}), typedHooks);
|
|
32443
32671
|
} catch (err) {
|
|
32444
32672
|
this.opts.log?.warn(`catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
|
|
32445
32673
|
continue;
|
|
@@ -32449,23 +32677,23 @@ var ParallAgentGateway = class {
|
|
|
32449
32677
|
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.handleTaskDispatch(item.task_id ?? "", item.source_id ?? item.task_id ?? "", {
|
|
32450
32678
|
allowCreator: true,
|
|
32451
32679
|
dispatchEventId
|
|
32452
|
-
}),
|
|
32680
|
+
}), typedHooks);
|
|
32453
32681
|
} catch (err) {
|
|
32454
32682
|
this.opts.log?.warn(`catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
|
|
32455
32683
|
continue;
|
|
32456
32684
|
}
|
|
32457
32685
|
} else if (item.event_type === "task_comment" && item.source_id && item.task_id) {
|
|
32458
|
-
await this.consumeTypedDispatch({ dispatchEventId: item.id }, () => this.handleTaskComment(item.source_id, item.task_id ?? "", item.actor_id, item.delivery_reason),
|
|
32686
|
+
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.handleTaskComment(item.source_id, item.task_id ?? "", item.actor_id, item.delivery_reason, dispatchEventId), typedHooks);
|
|
32459
32687
|
} else if (item.event_type === "wiki_comment" && item.source_id) {
|
|
32460
|
-
await this.consumeTypedDispatch({ dispatchEventId: item.id }, () => this.handleWikiComment(item.source_id, item.actor_id, item.delivery_reason),
|
|
32688
|
+
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.handleWikiComment(item.source_id, item.actor_id, item.delivery_reason, dispatchEventId), typedHooks);
|
|
32461
32689
|
} else if (item.event_type === "schedule.fire" && item.source_id) {
|
|
32462
|
-
await this.consumeTypedDispatch({ dispatchEventId: item.id }, () => this.fetchAndHandleScheduleFire(item.source_id, item.actor_id),
|
|
32690
|
+
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.fetchAndHandleScheduleFire(item.source_id, item.actor_id, dispatchEventId), typedHooks);
|
|
32463
32691
|
} else if (item.event_type === "external_trigger" && item.source_id) {
|
|
32464
|
-
await this.consumeTypedDispatch({ dispatchEventId: item.id }, () => this.fetchAndHandleExternalTriggerRun(item.source_id),
|
|
32692
|
+
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.fetchAndHandleExternalTriggerRun(item.source_id, dispatchEventId), typedHooks);
|
|
32465
32693
|
} else if (item.event_type === "channel_message" && item.source_id) {
|
|
32466
|
-
await this.consumeTypedDispatch({ dispatchEventId: item.id }, () => this.fetchAndHandleChannelMessage(item.source_id),
|
|
32694
|
+
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.fetchAndHandleChannelMessage(item.source_id, dispatchEventId), typedHooks);
|
|
32467
32695
|
} else if (item.event_type === "approval_decided" && item.source_id) {
|
|
32468
|
-
await this.consumeTypedDispatch({ dispatchEventId: item.id }, () => this.fetchAndHandleApprovalDecided(item.source_id, item.actor_id, item.chat_id ?? null),
|
|
32696
|
+
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.fetchAndHandleApprovalDecided(item.source_id, item.actor_id, item.chat_id ?? null, dispatchEventId), typedHooks);
|
|
32469
32697
|
} else if (item.event_type === "message" && item.source_id && item.chat_id) {
|
|
32470
32698
|
await this.consumeMessageWorkItem({
|
|
32471
32699
|
id: item.id,
|
|
@@ -33163,16 +33391,32 @@ parall tasks list --assignee-id prll://usr_xxx # first page only (default 20)
|
|
|
33163
33391
|
parall tasks subtasks prll://tsk_xxx # children of a single parent task
|
|
33164
33392
|
|
|
33165
33393
|
# Create a task (add --parent-id to make it a SUBTASK of another task)
|
|
33166
|
-
parall tasks create --title "Task title" [--assignee-id prll://usr_xxx] [--parent-id prll://tsk_xxx] [--project-id prll://prj_xxx]
|
|
33394
|
+
parall tasks create --title "Task title" [--assignee-id prll://usr_xxx] [--parent-id prll://tsk_xxx] [--project-id prll://prj_xxx] [--due-date 2026-08-01]
|
|
33395
|
+
|
|
33396
|
+
# Update task status \u2014 add --placement end so the task lands at the end of
|
|
33397
|
+
# its NEW status column (a bare --status keeps the old column's sort_order)
|
|
33398
|
+
parall tasks update prll://tsk_xxx --status in_progress --placement end
|
|
33399
|
+
parall tasks update prll://tsk_xxx --status done --placement end
|
|
33167
33400
|
|
|
33168
|
-
#
|
|
33169
|
-
parall tasks update prll://tsk_xxx --
|
|
33170
|
-
parall tasks update prll://tsk_xxx --
|
|
33401
|
+
# Due date \u2014 a plain YYYY-MM-DD date (no timestamps); "none" clears it
|
|
33402
|
+
parall tasks update prll://tsk_xxx --due-date 2026-08-01
|
|
33403
|
+
parall tasks update prll://tsk_xxx --due-date none
|
|
33404
|
+
|
|
33405
|
+
# Move a task to the end of its status column
|
|
33406
|
+
parall tasks update prll://tsk_xxx --placement end
|
|
33171
33407
|
|
|
33172
33408
|
# Add a comment
|
|
33173
33409
|
parall tasks comments add prll://tsk_xxx --body "Progress update..."
|
|
33174
33410
|
\`\`\`
|
|
33175
33411
|
|
|
33412
|
+
Ordering: to append a task to the end of a status column, always use
|
|
33413
|
+
\`--placement end\` \u2014 the server resolves the position atomically. This
|
|
33414
|
+
includes status changes: a bare \`--status\` keeps the task's old
|
|
33415
|
+
\`sort_order\`, which may collide inside the new column. Do NOT compute a
|
|
33416
|
+
\`sort_order\` value yourself from listed tasks (your view may be stale or
|
|
33417
|
+
partial). \`--sort-order\` is only for pinpoint insertion between two cards
|
|
33418
|
+
you just listed, and it cannot be combined with \`--placement\`.
|
|
33419
|
+
|
|
33176
33420
|
Subtasks are just tasks with a parent: create one with \`tasks create --parent-id\`,
|
|
33177
33421
|
re-parent with \`tasks update --parent-id\`, list a parent's children with
|
|
33178
33422
|
\`tasks subtasks\`. \`tasks list\` without \`--parent-id\` already returns both
|
|
@@ -33207,7 +33451,7 @@ watcher.
|
|
|
33207
33451
|
When you receive \`[Event: task.assigned]\`:
|
|
33208
33452
|
|
|
33209
33453
|
1. Acknowledge with a comment: \`tasks comments add prll://tsk_xxx --body "On it"\`
|
|
33210
|
-
2. Update status: \`tasks update prll://tsk_xxx --status in_progress\`
|
|
33454
|
+
2. Update status: \`tasks update prll://tsk_xxx --status in_progress --placement end\`
|
|
33211
33455
|
3. Do the work
|
|
33212
33456
|
4. Report results in a comment. If a gate remains \u2014 review, merge, deploy,
|
|
33213
33457
|
requester acceptance \u2014 set \`in_review\` and name the gate; set \`done\`
|
|
@@ -33453,7 +33697,7 @@ parall schedules create \\
|
|
|
33453
33697
|
--run-at <FUTURE_RFC3339_TIME>
|
|
33454
33698
|
\`\`\`
|
|
33455
33699
|
|
|
33456
|
-
\`--target-ids\` is who receives the fire (usually yourself when you're self-scheduling; another agent or human when delegating). \`--attached-to-uri\` optionally anchors the schedule to a task / chat / project / wiki page \u2014 when that resource is archived or deleted, the schedule auto-cancels (\`
|
|
33700
|
+
\`--target-ids\` is who receives the fire (usually yourself when you're self-scheduling; another agent or human when delegating). \`--attached-to-uri\` optionally anchors the schedule to a task / chat / project / wiki page \u2014 when that resource is archived or deleted, the schedule auto-cancels (\`status_reason=attached_gone\`). A schedule whose agent targets all sit on a terminated machine is auto-paused by the platform (\`status_reason=attendee_unreachable\`) instead of firing into a void; resuming a recurring schedule while the machine is still terminated just pauses it again on the next slot (a one-shot resumed past its catch-up window instead follows the normal missed semantics and completes).
|
|
33457
33701
|
|
|
33458
33702
|
### Reminders for someone else
|
|
33459
33703
|
|
|
@@ -33769,9 +34013,8 @@ function stepIdFilePathForSession(stateDir, sessionKey) {
|
|
|
33769
34013
|
}
|
|
33770
34014
|
|
|
33771
34015
|
// ts/codex-agent/dist/dispatch.js
|
|
33772
|
-
import {
|
|
34016
|
+
import { spawn } from "node:child_process";
|
|
33773
34017
|
import { randomUUID } from "node:crypto";
|
|
33774
|
-
import * as fs7 from "node:fs";
|
|
33775
34018
|
import * as path8 from "node:path";
|
|
33776
34019
|
|
|
33777
34020
|
// ts/agent-core/dist/internal/attachment-input.js
|
|
@@ -34346,125 +34589,333 @@ function parseContentLength(value) {
|
|
|
34346
34589
|
return n;
|
|
34347
34590
|
}
|
|
34348
34591
|
|
|
34349
|
-
// ts/codex-agent/dist/
|
|
34350
|
-
|
|
34351
|
-
|
|
34352
|
-
|
|
34353
|
-
|
|
34354
|
-
|
|
34355
|
-
|
|
34356
|
-
|
|
34357
|
-
|
|
34358
|
-
|
|
34359
|
-
|
|
34360
|
-
|
|
34361
|
-
|
|
34362
|
-
|
|
34363
|
-
|
|
34364
|
-
break;
|
|
34365
|
-
case "item/started": {
|
|
34366
|
-
const item = p.item;
|
|
34367
|
-
if (!item || typeof item.type !== "string")
|
|
34368
|
-
break;
|
|
34369
|
-
events.push(...this.mapItem(item, "started"));
|
|
34370
|
-
break;
|
|
34371
|
-
}
|
|
34372
|
-
case "item/completed": {
|
|
34373
|
-
const item = p.item;
|
|
34374
|
-
if (!item || typeof item.type !== "string")
|
|
34375
|
-
break;
|
|
34376
|
-
events.push(...this.mapItem(item, "completed"));
|
|
34377
|
-
break;
|
|
34378
|
-
}
|
|
34379
|
-
case "turn/completed": {
|
|
34380
|
-
const turn = p.turn;
|
|
34381
|
-
const status = turn ? asString(turn.status) : void 0;
|
|
34382
|
-
const error = turn?.error;
|
|
34383
|
-
if (status === "failed") {
|
|
34384
|
-
const message = asString(error?.message) ?? "Codex turn failed";
|
|
34385
|
-
events.push({ type: "error", message });
|
|
34386
|
-
}
|
|
34387
|
-
break;
|
|
34388
|
-
}
|
|
34389
|
-
case "error": {
|
|
34390
|
-
const message = asString(p.message) ?? "Codex error";
|
|
34391
|
-
events.push({ type: "error", message });
|
|
34392
|
-
break;
|
|
34393
|
-
}
|
|
34394
|
-
}
|
|
34395
|
-
return events;
|
|
34592
|
+
// ts/codex-agent/dist/app-server-process.js
|
|
34593
|
+
import { execSync as execSync2 } from "node:child_process";
|
|
34594
|
+
import * as fs7 from "node:fs";
|
|
34595
|
+
var IS_WIN32 = process.platform === "win32";
|
|
34596
|
+
function quoteWin32Arg(arg) {
|
|
34597
|
+
if (!/[\s"&|^<>()]/.test(arg))
|
|
34598
|
+
return arg;
|
|
34599
|
+
return `"${arg.replace(/"/g, '""')}"`;
|
|
34600
|
+
}
|
|
34601
|
+
function killWin32Tree(pid) {
|
|
34602
|
+
try {
|
|
34603
|
+
execSync2(`taskkill /T /F /PID ${pid}`, { windowsHide: true, stdio: "ignore" });
|
|
34604
|
+
return true;
|
|
34605
|
+
} catch {
|
|
34606
|
+
return false;
|
|
34396
34607
|
}
|
|
34397
|
-
|
|
34398
|
-
|
|
34399
|
-
|
|
34400
|
-
|
|
34401
|
-
|
|
34402
|
-
|
|
34403
|
-
|
|
34404
|
-
|
|
34405
|
-
|
|
34406
|
-
|
|
34407
|
-
|
|
34408
|
-
|
|
34409
|
-
|
|
34410
|
-
|
|
34411
|
-
|
|
34412
|
-
|
|
34413
|
-
|
|
34414
|
-
|
|
34415
|
-
|
|
34416
|
-
|
|
34417
|
-
|
|
34418
|
-
|
|
34419
|
-
|
|
34420
|
-
|
|
34421
|
-
|
|
34422
|
-
|
|
34423
|
-
|
|
34424
|
-
|
|
34425
|
-
|
|
34426
|
-
|
|
34427
|
-
|
|
34428
|
-
|
|
34429
|
-
|
|
34430
|
-
|
|
34431
|
-
|
|
34432
|
-
|
|
34433
|
-
|
|
34434
|
-
|
|
34435
|
-
|
|
34436
|
-
|
|
34437
|
-
|
|
34438
|
-
|
|
34439
|
-
|
|
34440
|
-
|
|
34441
|
-
|
|
34442
|
-
|
|
34443
|
-
|
|
34444
|
-
|
|
34445
|
-
|
|
34446
|
-
|
|
34447
|
-
|
|
34448
|
-
|
|
34449
|
-
|
|
34450
|
-
|
|
34451
|
-
|
|
34452
|
-
|
|
34453
|
-
|
|
34454
|
-
|
|
34455
|
-
|
|
34456
|
-
|
|
34457
|
-
|
|
34458
|
-
|
|
34459
|
-
|
|
34460
|
-
|
|
34461
|
-
|
|
34462
|
-
|
|
34463
|
-
|
|
34464
|
-
|
|
34465
|
-
|
|
34466
|
-
|
|
34467
|
-
|
|
34608
|
+
}
|
|
34609
|
+
function ensureGitRepo(workingDirectory) {
|
|
34610
|
+
fs7.mkdirSync(workingDirectory, { recursive: true });
|
|
34611
|
+
try {
|
|
34612
|
+
execSync2("git rev-parse --is-inside-work-tree", { cwd: workingDirectory, stdio: "pipe" });
|
|
34613
|
+
ensureLocalAttachmentGitExclude(workingDirectory);
|
|
34614
|
+
return;
|
|
34615
|
+
} catch {
|
|
34616
|
+
}
|
|
34617
|
+
const env = {
|
|
34618
|
+
...process.env,
|
|
34619
|
+
GIT_AUTHOR_NAME: "parall-codex-agent",
|
|
34620
|
+
GIT_AUTHOR_EMAIL: "agent@parall.local",
|
|
34621
|
+
GIT_COMMITTER_NAME: "parall-codex-agent",
|
|
34622
|
+
GIT_COMMITTER_EMAIL: "agent@parall.local"
|
|
34623
|
+
};
|
|
34624
|
+
try {
|
|
34625
|
+
execSync2("git init", { cwd: workingDirectory, stdio: "pipe", env });
|
|
34626
|
+
execSync2("git commit --allow-empty -m init", { cwd: workingDirectory, stdio: "pipe", env });
|
|
34627
|
+
ensureLocalAttachmentGitExclude(workingDirectory);
|
|
34628
|
+
} catch {
|
|
34629
|
+
}
|
|
34630
|
+
}
|
|
34631
|
+
|
|
34632
|
+
// ts/codex-agent/dist/app-server-protocol.js
|
|
34633
|
+
function buildTurnInput(body, images) {
|
|
34634
|
+
return [
|
|
34635
|
+
{ type: "text", text: body },
|
|
34636
|
+
...images.map((image) => ({ type: "localImage", path: image.localPath }))
|
|
34637
|
+
];
|
|
34638
|
+
}
|
|
34639
|
+
function extractThreadId(result) {
|
|
34640
|
+
if (!result || typeof result !== "object")
|
|
34641
|
+
return void 0;
|
|
34642
|
+
const r = result;
|
|
34643
|
+
if (typeof r.threadId === "string")
|
|
34644
|
+
return r.threadId;
|
|
34645
|
+
const thread = r.thread;
|
|
34646
|
+
if (thread && typeof thread.id === "string")
|
|
34647
|
+
return thread.id;
|
|
34648
|
+
return void 0;
|
|
34649
|
+
}
|
|
34650
|
+
function extractTurnId(result) {
|
|
34651
|
+
if (!result || typeof result !== "object")
|
|
34652
|
+
return void 0;
|
|
34653
|
+
const r = result;
|
|
34654
|
+
if (typeof r.turnId === "string")
|
|
34655
|
+
return r.turnId;
|
|
34656
|
+
const turn = r.turn;
|
|
34657
|
+
if (turn && typeof turn.id === "string")
|
|
34658
|
+
return turn.id;
|
|
34659
|
+
return void 0;
|
|
34660
|
+
}
|
|
34661
|
+
function extractThreadIdFromNotification(params) {
|
|
34662
|
+
if (!params || typeof params !== "object")
|
|
34663
|
+
return void 0;
|
|
34664
|
+
const p = params;
|
|
34665
|
+
if (typeof p.threadId === "string")
|
|
34666
|
+
return p.threadId;
|
|
34667
|
+
const thread = p.thread;
|
|
34668
|
+
if (thread && typeof thread.id === "string")
|
|
34669
|
+
return thread.id;
|
|
34670
|
+
const meta = p._meta ?? p.meta;
|
|
34671
|
+
if (meta && typeof meta.threadId === "string")
|
|
34672
|
+
return meta.threadId;
|
|
34673
|
+
return void 0;
|
|
34674
|
+
}
|
|
34675
|
+
|
|
34676
|
+
// ts/codex-agent/dist/jsonrpc-client.js
|
|
34677
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 12e4;
|
|
34678
|
+
var JsonRpcStdioClient = class {
|
|
34679
|
+
proc;
|
|
34680
|
+
requestTimeoutMs;
|
|
34681
|
+
killProcess;
|
|
34682
|
+
nextId = 1;
|
|
34683
|
+
pending = /* @__PURE__ */ new Map();
|
|
34684
|
+
buffer = "";
|
|
34685
|
+
onNotification = null;
|
|
34686
|
+
disposed = false;
|
|
34687
|
+
constructor(proc, requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS, killProcess) {
|
|
34688
|
+
this.proc = proc;
|
|
34689
|
+
this.requestTimeoutMs = requestTimeoutMs;
|
|
34690
|
+
this.killProcess = killProcess;
|
|
34691
|
+
proc.stdout.setEncoding("utf8");
|
|
34692
|
+
proc.stdout.on("data", (chunk) => this.ingest(chunk));
|
|
34693
|
+
proc.once("close", () => this.dispose(new Error("app-server subprocess closed")));
|
|
34694
|
+
proc.once("error", (err) => this.dispose(err));
|
|
34695
|
+
proc.stdin.on("error", (err) => this.killUnhealthy(err));
|
|
34696
|
+
}
|
|
34697
|
+
setNotificationHandler(handler) {
|
|
34698
|
+
this.onNotification = handler;
|
|
34699
|
+
}
|
|
34700
|
+
sendRequest(method, params) {
|
|
34701
|
+
if (this.disposed) {
|
|
34702
|
+
return Promise.reject(new Error("JSON-RPC client disposed"));
|
|
34703
|
+
}
|
|
34704
|
+
const id = this.nextId++;
|
|
34705
|
+
const request3 = { jsonrpc: "2.0", id, method, params };
|
|
34706
|
+
const promise = new Promise((resolve4, reject) => {
|
|
34707
|
+
const timer = setTimeout(() => {
|
|
34708
|
+
const pending = this.pending.get(id);
|
|
34709
|
+
if (!pending)
|
|
34710
|
+
return;
|
|
34711
|
+
this.pending.delete(id);
|
|
34712
|
+
reject(new Error(`JSON-RPC request "${method}" timed out after ${this.requestTimeoutMs}ms`));
|
|
34713
|
+
this.killUnhealthy(new Error(`request "${method}" timed out; subprocess assumed hung`));
|
|
34714
|
+
}, this.requestTimeoutMs);
|
|
34715
|
+
this.pending.set(id, { resolve: resolve4, reject, timer });
|
|
34716
|
+
});
|
|
34717
|
+
this.writeFrame(request3);
|
|
34718
|
+
return promise;
|
|
34719
|
+
}
|
|
34720
|
+
sendNotification(method, params) {
|
|
34721
|
+
if (this.disposed)
|
|
34722
|
+
return;
|
|
34723
|
+
const notification = { jsonrpc: "2.0", method, params };
|
|
34724
|
+
this.writeFrame(notification);
|
|
34725
|
+
}
|
|
34726
|
+
isDisposed() {
|
|
34727
|
+
return this.disposed;
|
|
34728
|
+
}
|
|
34729
|
+
dispose(err) {
|
|
34730
|
+
if (this.disposed)
|
|
34731
|
+
return;
|
|
34732
|
+
this.disposed = true;
|
|
34733
|
+
for (const pending of this.pending.values()) {
|
|
34734
|
+
clearTimeout(pending.timer);
|
|
34735
|
+
pending.reject(err);
|
|
34736
|
+
}
|
|
34737
|
+
this.pending.clear();
|
|
34738
|
+
}
|
|
34739
|
+
writeFrame(message) {
|
|
34740
|
+
try {
|
|
34741
|
+
this.proc.stdin.write(`${JSON.stringify(message)}
|
|
34742
|
+
`);
|
|
34743
|
+
} catch (err) {
|
|
34744
|
+
this.killUnhealthy(err instanceof Error ? err : new Error(String(err)));
|
|
34745
|
+
}
|
|
34746
|
+
}
|
|
34747
|
+
killUnhealthy(err) {
|
|
34748
|
+
this.dispose(err);
|
|
34749
|
+
if (this.proc.exitCode === null && this.proc.signalCode === null) {
|
|
34750
|
+
if (this.killProcess) {
|
|
34751
|
+
this.killProcess(this.proc);
|
|
34752
|
+
} else {
|
|
34753
|
+
this.proc.kill("SIGTERM");
|
|
34754
|
+
}
|
|
34755
|
+
}
|
|
34756
|
+
}
|
|
34757
|
+
ingest(chunk) {
|
|
34758
|
+
this.buffer += chunk;
|
|
34759
|
+
let newlineIndex = this.buffer.indexOf("\n");
|
|
34760
|
+
while (newlineIndex >= 0) {
|
|
34761
|
+
const line = this.buffer.slice(0, newlineIndex).trim();
|
|
34762
|
+
this.buffer = this.buffer.slice(newlineIndex + 1);
|
|
34763
|
+
if (line)
|
|
34764
|
+
this.handleLine(line);
|
|
34765
|
+
newlineIndex = this.buffer.indexOf("\n");
|
|
34766
|
+
}
|
|
34767
|
+
}
|
|
34768
|
+
handleLine(line) {
|
|
34769
|
+
let message;
|
|
34770
|
+
try {
|
|
34771
|
+
message = JSON.parse(line);
|
|
34772
|
+
} catch {
|
|
34773
|
+
return;
|
|
34774
|
+
}
|
|
34775
|
+
if (isResponse(message)) {
|
|
34776
|
+
const pending = this.pending.get(message.id);
|
|
34777
|
+
if (!pending)
|
|
34778
|
+
return;
|
|
34779
|
+
this.pending.delete(message.id);
|
|
34780
|
+
clearTimeout(pending.timer);
|
|
34781
|
+
if (message.error) {
|
|
34782
|
+
pending.reject(new Error(message.error.message || "JSON-RPC error"));
|
|
34783
|
+
} else {
|
|
34784
|
+
pending.resolve(message.result);
|
|
34785
|
+
}
|
|
34786
|
+
return;
|
|
34787
|
+
}
|
|
34788
|
+
if (isNotification(message)) {
|
|
34789
|
+
this.onNotification?.(message.method, message.params);
|
|
34790
|
+
}
|
|
34791
|
+
}
|
|
34792
|
+
};
|
|
34793
|
+
function isResponse(m) {
|
|
34794
|
+
return !!m && typeof m === "object" && "id" in m && ("result" in m || "error" in m);
|
|
34795
|
+
}
|
|
34796
|
+
function isNotification(m) {
|
|
34797
|
+
return !!m && typeof m === "object" && "method" in m && !("id" in m);
|
|
34798
|
+
}
|
|
34799
|
+
|
|
34800
|
+
// ts/codex-agent/dist/event-mapping.js
|
|
34801
|
+
var EventMapper = class {
|
|
34802
|
+
toolCallStart = /* @__PURE__ */ new Map();
|
|
34803
|
+
/**
|
|
34804
|
+
* Map a single server notification to zero or more RuntimeEvents.
|
|
34805
|
+
* Return `null` for notifications that have no chat surface.
|
|
34806
|
+
*/
|
|
34807
|
+
map(method, params) {
|
|
34808
|
+
const events = [];
|
|
34809
|
+
const p = params ?? {};
|
|
34810
|
+
switch (method) {
|
|
34811
|
+
// Streaming deltas are intentionally dropped — see the class comment.
|
|
34812
|
+
case "item/agentMessage/delta":
|
|
34813
|
+
case "item/reasoning/textDelta":
|
|
34814
|
+
case "item/reasoning/summaryTextDelta":
|
|
34815
|
+
break;
|
|
34816
|
+
case "item/started": {
|
|
34817
|
+
const item = p.item;
|
|
34818
|
+
if (!item || typeof item.type !== "string")
|
|
34819
|
+
break;
|
|
34820
|
+
events.push(...this.mapItem(item, "started"));
|
|
34821
|
+
break;
|
|
34822
|
+
}
|
|
34823
|
+
case "item/completed": {
|
|
34824
|
+
const item = p.item;
|
|
34825
|
+
if (!item || typeof item.type !== "string")
|
|
34826
|
+
break;
|
|
34827
|
+
events.push(...this.mapItem(item, "completed"));
|
|
34828
|
+
break;
|
|
34829
|
+
}
|
|
34830
|
+
case "turn/completed": {
|
|
34831
|
+
const turn = p.turn;
|
|
34832
|
+
const status = turn ? asString(turn.status) : void 0;
|
|
34833
|
+
const error = turn?.error;
|
|
34834
|
+
if (status === "failed") {
|
|
34835
|
+
const message = asString(error?.message) ?? "Codex turn failed";
|
|
34836
|
+
events.push({ type: "error", message });
|
|
34837
|
+
}
|
|
34838
|
+
break;
|
|
34839
|
+
}
|
|
34840
|
+
case "error": {
|
|
34841
|
+
const message = asString(p.message) ?? "Codex error";
|
|
34842
|
+
events.push({ type: "error", message });
|
|
34843
|
+
break;
|
|
34844
|
+
}
|
|
34845
|
+
}
|
|
34846
|
+
return events;
|
|
34847
|
+
}
|
|
34848
|
+
mapItem(item, phase) {
|
|
34849
|
+
const type = asString(item.type);
|
|
34850
|
+
const id = asString(item.id);
|
|
34851
|
+
const now = Date.now();
|
|
34852
|
+
if (type === "agentMessage") {
|
|
34853
|
+
if (phase !== "completed")
|
|
34854
|
+
return [];
|
|
34855
|
+
const text = asString(item.text);
|
|
34856
|
+
if (!text)
|
|
34857
|
+
return [];
|
|
34858
|
+
return [{ type: "text", text, project: false }];
|
|
34859
|
+
}
|
|
34860
|
+
if (type === "reasoning") {
|
|
34861
|
+
if (phase !== "completed")
|
|
34862
|
+
return [];
|
|
34863
|
+
const text = joinReasoningText(item);
|
|
34864
|
+
if (!text)
|
|
34865
|
+
return [];
|
|
34866
|
+
return [{ type: "thinking", text }];
|
|
34867
|
+
}
|
|
34868
|
+
if (type === "commandExecution") {
|
|
34869
|
+
const command = formatCommand(item.command);
|
|
34870
|
+
const callId = id ?? `shell-${now}`;
|
|
34871
|
+
if (phase === "started") {
|
|
34872
|
+
this.toolCallStart.set(callId, now);
|
|
34873
|
+
return [
|
|
34874
|
+
{
|
|
34875
|
+
type: "tool_call",
|
|
34876
|
+
callId,
|
|
34877
|
+
toolName: "shell",
|
|
34878
|
+
input: { command, cwd: asString(item.cwd) },
|
|
34879
|
+
startedAt: new Date(now).toISOString()
|
|
34880
|
+
}
|
|
34881
|
+
];
|
|
34882
|
+
}
|
|
34883
|
+
const durationMs = this.resolveDuration(callId, now, item.durationMs);
|
|
34884
|
+
const output = asString(item.aggregatedOutput) ?? joinStreams(item.stdout, item.stderr);
|
|
34885
|
+
const exitCode = typeof item.exitCode === "number" ? item.exitCode : void 0;
|
|
34886
|
+
const status = asString(item.status);
|
|
34887
|
+
const failed = exitCode !== void 0 && exitCode !== 0 || status === "failed" || status === "declined";
|
|
34888
|
+
return [
|
|
34889
|
+
{
|
|
34890
|
+
type: "tool_result",
|
|
34891
|
+
callId,
|
|
34892
|
+
toolName: "shell",
|
|
34893
|
+
output,
|
|
34894
|
+
...failed ? { error: output || `shell ${status ?? "exited"} (code=${exitCode ?? "?"})` } : {},
|
|
34895
|
+
...durationMs !== void 0 ? { durationMs } : {}
|
|
34896
|
+
}
|
|
34897
|
+
];
|
|
34898
|
+
}
|
|
34899
|
+
if (type === "mcpToolCall") {
|
|
34900
|
+
const server = asString(item.server);
|
|
34901
|
+
const tool = asString(item.tool);
|
|
34902
|
+
const toolName = server && tool ? `${server}:${tool}` : tool ?? server ?? "mcp";
|
|
34903
|
+
const callId = id ?? `mcp-${now}`;
|
|
34904
|
+
if (phase === "started") {
|
|
34905
|
+
this.toolCallStart.set(callId, now);
|
|
34906
|
+
return [
|
|
34907
|
+
{
|
|
34908
|
+
type: "tool_call",
|
|
34909
|
+
callId,
|
|
34910
|
+
toolName,
|
|
34911
|
+
input: item.arguments ?? {},
|
|
34912
|
+
startedAt: new Date(now).toISOString()
|
|
34913
|
+
}
|
|
34914
|
+
];
|
|
34915
|
+
}
|
|
34916
|
+
const durationMs = this.resolveDuration(callId, now, item.durationMs);
|
|
34917
|
+
const result = item.result;
|
|
34918
|
+
const output = result == null ? "" : typeof result === "string" ? result : JSON.stringify(result);
|
|
34468
34919
|
const success = item.isSuccess !== false;
|
|
34469
34920
|
return [
|
|
34470
34921
|
{
|
|
@@ -34577,145 +35028,43 @@ function formatCommand(command) {
|
|
|
34577
35028
|
return "";
|
|
34578
35029
|
}
|
|
34579
35030
|
|
|
34580
|
-
// ts/codex-agent/dist/
|
|
34581
|
-
var
|
|
34582
|
-
|
|
34583
|
-
|
|
34584
|
-
|
|
34585
|
-
|
|
34586
|
-
|
|
34587
|
-
|
|
34588
|
-
buffer = "";
|
|
34589
|
-
onNotification = null;
|
|
34590
|
-
disposed = false;
|
|
34591
|
-
constructor(proc, requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS, killProcess) {
|
|
34592
|
-
this.proc = proc;
|
|
34593
|
-
this.requestTimeoutMs = requestTimeoutMs;
|
|
34594
|
-
this.killProcess = killProcess;
|
|
34595
|
-
proc.stdout.setEncoding("utf8");
|
|
34596
|
-
proc.stdout.on("data", (chunk) => this.ingest(chunk));
|
|
34597
|
-
proc.once("close", () => this.dispose(new Error("app-server subprocess closed")));
|
|
34598
|
-
proc.once("error", (err) => this.dispose(err));
|
|
34599
|
-
proc.stdin.on("error", (err) => this.killUnhealthy(err));
|
|
34600
|
-
}
|
|
34601
|
-
setNotificationHandler(handler) {
|
|
34602
|
-
this.onNotification = handler;
|
|
34603
|
-
}
|
|
34604
|
-
sendRequest(method, params) {
|
|
34605
|
-
if (this.disposed) {
|
|
34606
|
-
return Promise.reject(new Error("JSON-RPC client disposed"));
|
|
34607
|
-
}
|
|
34608
|
-
const id = this.nextId++;
|
|
34609
|
-
const request3 = { jsonrpc: "2.0", id, method, params };
|
|
34610
|
-
const promise = new Promise((resolve4, reject) => {
|
|
34611
|
-
const timer = setTimeout(() => {
|
|
34612
|
-
const pending = this.pending.get(id);
|
|
34613
|
-
if (!pending)
|
|
34614
|
-
return;
|
|
34615
|
-
this.pending.delete(id);
|
|
34616
|
-
reject(new Error(`JSON-RPC request "${method}" timed out after ${this.requestTimeoutMs}ms`));
|
|
34617
|
-
this.killUnhealthy(new Error(`request "${method}" timed out; subprocess assumed hung`));
|
|
34618
|
-
}, this.requestTimeoutMs);
|
|
34619
|
-
this.pending.set(id, { resolve: resolve4, reject, timer });
|
|
34620
|
-
});
|
|
34621
|
-
this.writeFrame(request3);
|
|
34622
|
-
return promise;
|
|
34623
|
-
}
|
|
34624
|
-
sendNotification(method, params) {
|
|
34625
|
-
if (this.disposed)
|
|
35031
|
+
// ts/codex-agent/dist/turn-sink.js
|
|
35032
|
+
var TurnSink = class {
|
|
35033
|
+
mapper = new EventMapper();
|
|
35034
|
+
queue = [];
|
|
35035
|
+
resolver = null;
|
|
35036
|
+
closed = false;
|
|
35037
|
+
push(envelope) {
|
|
35038
|
+
if (this.closed)
|
|
34626
35039
|
return;
|
|
34627
|
-
|
|
34628
|
-
|
|
34629
|
-
|
|
34630
|
-
|
|
34631
|
-
return this.disposed;
|
|
34632
|
-
}
|
|
34633
|
-
dispose(err) {
|
|
34634
|
-
if (this.disposed)
|
|
35040
|
+
if (this.resolver) {
|
|
35041
|
+
const r = this.resolver;
|
|
35042
|
+
this.resolver = null;
|
|
35043
|
+
r(envelope);
|
|
34635
35044
|
return;
|
|
34636
|
-
this.disposed = true;
|
|
34637
|
-
for (const pending of this.pending.values()) {
|
|
34638
|
-
clearTimeout(pending.timer);
|
|
34639
|
-
pending.reject(err);
|
|
34640
|
-
}
|
|
34641
|
-
this.pending.clear();
|
|
34642
|
-
}
|
|
34643
|
-
writeFrame(message) {
|
|
34644
|
-
try {
|
|
34645
|
-
this.proc.stdin.write(`${JSON.stringify(message)}
|
|
34646
|
-
`);
|
|
34647
|
-
} catch (err) {
|
|
34648
|
-
this.killUnhealthy(err instanceof Error ? err : new Error(String(err)));
|
|
34649
|
-
}
|
|
34650
|
-
}
|
|
34651
|
-
killUnhealthy(err) {
|
|
34652
|
-
this.dispose(err);
|
|
34653
|
-
if (this.proc.exitCode === null && this.proc.signalCode === null) {
|
|
34654
|
-
if (this.killProcess) {
|
|
34655
|
-
this.killProcess(this.proc);
|
|
34656
|
-
} else {
|
|
34657
|
-
this.proc.kill("SIGTERM");
|
|
34658
|
-
}
|
|
34659
35045
|
}
|
|
35046
|
+
this.queue.push(envelope);
|
|
34660
35047
|
}
|
|
34661
|
-
|
|
34662
|
-
this.
|
|
34663
|
-
|
|
34664
|
-
|
|
34665
|
-
|
|
34666
|
-
|
|
34667
|
-
if (line)
|
|
34668
|
-
this.handleLine(line);
|
|
34669
|
-
newlineIndex = this.buffer.indexOf("\n");
|
|
35048
|
+
next() {
|
|
35049
|
+
const pending = this.queue.shift();
|
|
35050
|
+
if (pending)
|
|
35051
|
+
return Promise.resolve(pending);
|
|
35052
|
+
if (this.closed) {
|
|
35053
|
+
return Promise.resolve({ kind: "turn_end" });
|
|
34670
35054
|
}
|
|
35055
|
+
return new Promise((resolve4) => {
|
|
35056
|
+
this.resolver = resolve4;
|
|
35057
|
+
});
|
|
34671
35058
|
}
|
|
34672
|
-
|
|
34673
|
-
|
|
34674
|
-
|
|
34675
|
-
|
|
34676
|
-
|
|
34677
|
-
return;
|
|
34678
|
-
}
|
|
34679
|
-
if (isResponse(message)) {
|
|
34680
|
-
const pending = this.pending.get(message.id);
|
|
34681
|
-
if (!pending)
|
|
34682
|
-
return;
|
|
34683
|
-
this.pending.delete(message.id);
|
|
34684
|
-
clearTimeout(pending.timer);
|
|
34685
|
-
if (message.error) {
|
|
34686
|
-
pending.reject(new Error(message.error.message || "JSON-RPC error"));
|
|
34687
|
-
} else {
|
|
34688
|
-
pending.resolve(message.result);
|
|
34689
|
-
}
|
|
34690
|
-
return;
|
|
34691
|
-
}
|
|
34692
|
-
if (isNotification(message)) {
|
|
34693
|
-
this.onNotification?.(message.method, message.params);
|
|
34694
|
-
}
|
|
35059
|
+
close() {
|
|
35060
|
+
this.closed = true;
|
|
35061
|
+
const r = this.resolver;
|
|
35062
|
+
this.resolver = null;
|
|
35063
|
+
r?.({ kind: "turn_end" });
|
|
34695
35064
|
}
|
|
34696
35065
|
};
|
|
34697
|
-
function isResponse(m) {
|
|
34698
|
-
return !!m && typeof m === "object" && "id" in m && ("result" in m || "error" in m);
|
|
34699
|
-
}
|
|
34700
|
-
function isNotification(m) {
|
|
34701
|
-
return !!m && typeof m === "object" && "method" in m && !("id" in m);
|
|
34702
|
-
}
|
|
34703
35066
|
|
|
34704
35067
|
// ts/codex-agent/dist/dispatch.js
|
|
34705
|
-
var IS_WIN32 = process.platform === "win32";
|
|
34706
|
-
function quoteWin32Arg(arg) {
|
|
34707
|
-
if (!/[\s"&|^<>()]/.test(arg))
|
|
34708
|
-
return arg;
|
|
34709
|
-
return `"${arg.replace(/"/g, '""')}"`;
|
|
34710
|
-
}
|
|
34711
|
-
function killWin32Tree(pid) {
|
|
34712
|
-
try {
|
|
34713
|
-
execSync2(`taskkill /T /F /PID ${pid}`, { windowsHide: true, stdio: "ignore" });
|
|
34714
|
-
return true;
|
|
34715
|
-
} catch {
|
|
34716
|
-
return false;
|
|
34717
|
-
}
|
|
34718
|
-
}
|
|
34719
35068
|
var CodexAppServerAdapter = class {
|
|
34720
35069
|
opts;
|
|
34721
35070
|
client = null;
|
|
@@ -34752,6 +35101,8 @@ var CodexAppServerAdapter = class {
|
|
|
34752
35101
|
this.opts.model = config.model ?? void 0;
|
|
34753
35102
|
if (config.reasoningEffort !== void 0)
|
|
34754
35103
|
this.opts.reasoningEffort = config.reasoningEffort ?? void 0;
|
|
35104
|
+
if (config.developerInstructions !== void 0)
|
|
35105
|
+
this.opts.developerInstructions = config.developerInstructions ?? void 0;
|
|
34755
35106
|
}
|
|
34756
35107
|
async enqueueDuringDispatch(sessionKey, body) {
|
|
34757
35108
|
const client = this.client;
|
|
@@ -34996,6 +35347,9 @@ var CodexAppServerAdapter = class {
|
|
|
34996
35347
|
if (this.opts.useParallProvider) {
|
|
34997
35348
|
forkParams.modelProvider = "parall";
|
|
34998
35349
|
}
|
|
35350
|
+
if (this.opts.developerInstructions) {
|
|
35351
|
+
forkParams.developerInstructions = this.opts.developerInstructions;
|
|
35352
|
+
}
|
|
34999
35353
|
if (this.opts.model)
|
|
35000
35354
|
forkParams.model = this.opts.model;
|
|
35001
35355
|
if (this.opts.reasoningEffort) {
|
|
@@ -35021,11 +35375,14 @@ var CodexAppServerAdapter = class {
|
|
|
35021
35375
|
return null;
|
|
35022
35376
|
}
|
|
35023
35377
|
/**
|
|
35024
|
-
* Lazily restart the app-server before the NEXT turn
|
|
35025
|
-
*
|
|
35026
|
-
*
|
|
35027
|
-
*
|
|
35028
|
-
*
|
|
35378
|
+
* Lazily restart the app-server before the NEXT turn, so a subprocess that
|
|
35379
|
+
* has been running since before a capability change starts clean. Deferred
|
|
35380
|
+
* to the next dispatch with no active turns — never kills an in-flight turn;
|
|
35381
|
+
* thread state survives via thread/resume.
|
|
35382
|
+
*
|
|
35383
|
+
* A restart does NOT re-instruct an already-persisted thread — see the
|
|
35384
|
+
* `developerInstructions` option doc. The capability shim dir on PATH is what
|
|
35385
|
+
* makes a grant/revocation effective immediately.
|
|
35029
35386
|
*/
|
|
35030
35387
|
requestProcessRestart() {
|
|
35031
35388
|
this.restartRequested = true;
|
|
@@ -35035,7 +35392,7 @@ var CodexAppServerAdapter = class {
|
|
|
35035
35392
|
if (!this.restartRequested || this.activeTurns.size > 0)
|
|
35036
35393
|
return;
|
|
35037
35394
|
this.restartRequested = false;
|
|
35038
|
-
(log2 ?? this.opts.log)?.info?.("restarting codex app-server
|
|
35395
|
+
(log2 ?? this.opts.log)?.info?.("restarting codex app-server after a capability change (new threads pick up the refreshed developerInstructions; an already-persisted thread keeps its own)");
|
|
35039
35396
|
await this.stop();
|
|
35040
35397
|
}
|
|
35041
35398
|
async stop() {
|
|
@@ -35174,6 +35531,9 @@ var CodexAppServerAdapter = class {
|
|
|
35174
35531
|
commonParams.modelProvider = "parall";
|
|
35175
35532
|
}
|
|
35176
35533
|
commonParams.sandbox = normalizeSandbox(this.opts.sandbox);
|
|
35534
|
+
if (this.opts.developerInstructions) {
|
|
35535
|
+
commonParams.developerInstructions = this.opts.developerInstructions;
|
|
35536
|
+
}
|
|
35177
35537
|
if (this.opts.model)
|
|
35178
35538
|
commonParams.model = this.opts.model;
|
|
35179
35539
|
if (this.opts.reasoningEffort) {
|
|
@@ -35196,119 +35556,21 @@ var CodexAppServerAdapter = class {
|
|
|
35196
35556
|
for (const sink2 of this.activeTurns.values()) {
|
|
35197
35557
|
sink2.push({ kind: "error", message: String(msg) });
|
|
35198
35558
|
}
|
|
35199
|
-
}
|
|
35200
|
-
return;
|
|
35201
|
-
}
|
|
35202
|
-
const sink = this.activeTurns.get(threadId);
|
|
35203
|
-
if (!sink)
|
|
35204
|
-
return;
|
|
35205
|
-
for (const event of sink.mapper.map(method, params)) {
|
|
35206
|
-
sink.push({ kind: "runtime", event });
|
|
35207
|
-
}
|
|
35208
|
-
if (method === "turn/completed") {
|
|
35209
|
-
this.activeTurnIds.delete(threadId);
|
|
35210
|
-
sink.push({ kind: "turn_end", threadId });
|
|
35211
|
-
}
|
|
35212
|
-
}
|
|
35213
|
-
};
|
|
35214
|
-
var TurnSink = class {
|
|
35215
|
-
mapper = new EventMapper();
|
|
35216
|
-
queue = [];
|
|
35217
|
-
resolver = null;
|
|
35218
|
-
closed = false;
|
|
35219
|
-
push(envelope) {
|
|
35220
|
-
if (this.closed)
|
|
35221
|
-
return;
|
|
35222
|
-
if (this.resolver) {
|
|
35223
|
-
const r = this.resolver;
|
|
35224
|
-
this.resolver = null;
|
|
35225
|
-
r(envelope);
|
|
35226
|
-
return;
|
|
35227
|
-
}
|
|
35228
|
-
this.queue.push(envelope);
|
|
35229
|
-
}
|
|
35230
|
-
next() {
|
|
35231
|
-
const pending = this.queue.shift();
|
|
35232
|
-
if (pending)
|
|
35233
|
-
return Promise.resolve(pending);
|
|
35234
|
-
if (this.closed) {
|
|
35235
|
-
return Promise.resolve({ kind: "turn_end" });
|
|
35236
|
-
}
|
|
35237
|
-
return new Promise((resolve4) => {
|
|
35238
|
-
this.resolver = resolve4;
|
|
35239
|
-
});
|
|
35240
|
-
}
|
|
35241
|
-
close() {
|
|
35242
|
-
this.closed = true;
|
|
35243
|
-
const r = this.resolver;
|
|
35244
|
-
this.resolver = null;
|
|
35245
|
-
r?.({ kind: "turn_end" });
|
|
35246
|
-
}
|
|
35247
|
-
};
|
|
35248
|
-
function ensureGitRepo(workingDirectory) {
|
|
35249
|
-
fs7.mkdirSync(workingDirectory, { recursive: true });
|
|
35250
|
-
try {
|
|
35251
|
-
execSync2("git rev-parse --is-inside-work-tree", { cwd: workingDirectory, stdio: "pipe" });
|
|
35252
|
-
ensureLocalAttachmentGitExclude(workingDirectory);
|
|
35253
|
-
return;
|
|
35254
|
-
} catch {
|
|
35255
|
-
}
|
|
35256
|
-
const env = {
|
|
35257
|
-
...process.env,
|
|
35258
|
-
GIT_AUTHOR_NAME: "parall-codex-agent",
|
|
35259
|
-
GIT_AUTHOR_EMAIL: "agent@parall.local",
|
|
35260
|
-
GIT_COMMITTER_NAME: "parall-codex-agent",
|
|
35261
|
-
GIT_COMMITTER_EMAIL: "agent@parall.local"
|
|
35262
|
-
};
|
|
35263
|
-
try {
|
|
35264
|
-
execSync2("git init", { cwd: workingDirectory, stdio: "pipe", env });
|
|
35265
|
-
execSync2("git commit --allow-empty -m init", { cwd: workingDirectory, stdio: "pipe", env });
|
|
35266
|
-
ensureLocalAttachmentGitExclude(workingDirectory);
|
|
35267
|
-
} catch {
|
|
35559
|
+
}
|
|
35560
|
+
return;
|
|
35561
|
+
}
|
|
35562
|
+
const sink = this.activeTurns.get(threadId);
|
|
35563
|
+
if (!sink)
|
|
35564
|
+
return;
|
|
35565
|
+
for (const event of sink.mapper.map(method, params)) {
|
|
35566
|
+
sink.push({ kind: "runtime", event });
|
|
35567
|
+
}
|
|
35568
|
+
if (method === "turn/completed") {
|
|
35569
|
+
this.activeTurnIds.delete(threadId);
|
|
35570
|
+
sink.push({ kind: "turn_end", threadId });
|
|
35571
|
+
}
|
|
35268
35572
|
}
|
|
35269
|
-
}
|
|
35270
|
-
function buildTurnInput(body, images) {
|
|
35271
|
-
return [
|
|
35272
|
-
{ type: "text", text: body },
|
|
35273
|
-
...images.map((image) => ({ type: "localImage", path: image.localPath }))
|
|
35274
|
-
];
|
|
35275
|
-
}
|
|
35276
|
-
function extractThreadId(result) {
|
|
35277
|
-
if (!result || typeof result !== "object")
|
|
35278
|
-
return void 0;
|
|
35279
|
-
const r = result;
|
|
35280
|
-
if (typeof r.threadId === "string")
|
|
35281
|
-
return r.threadId;
|
|
35282
|
-
const thread = r.thread;
|
|
35283
|
-
if (thread && typeof thread.id === "string")
|
|
35284
|
-
return thread.id;
|
|
35285
|
-
return void 0;
|
|
35286
|
-
}
|
|
35287
|
-
function extractTurnId(result) {
|
|
35288
|
-
if (!result || typeof result !== "object")
|
|
35289
|
-
return void 0;
|
|
35290
|
-
const r = result;
|
|
35291
|
-
if (typeof r.turnId === "string")
|
|
35292
|
-
return r.turnId;
|
|
35293
|
-
const turn = r.turn;
|
|
35294
|
-
if (turn && typeof turn.id === "string")
|
|
35295
|
-
return turn.id;
|
|
35296
|
-
return void 0;
|
|
35297
|
-
}
|
|
35298
|
-
function extractThreadIdFromNotification(params) {
|
|
35299
|
-
if (!params || typeof params !== "object")
|
|
35300
|
-
return void 0;
|
|
35301
|
-
const p = params;
|
|
35302
|
-
if (typeof p.threadId === "string")
|
|
35303
|
-
return p.threadId;
|
|
35304
|
-
const thread = p.thread;
|
|
35305
|
-
if (thread && typeof thread.id === "string")
|
|
35306
|
-
return thread.id;
|
|
35307
|
-
const meta = p._meta ?? p.meta;
|
|
35308
|
-
if (meta && typeof meta.threadId === "string")
|
|
35309
|
-
return meta.threadId;
|
|
35310
|
-
return void 0;
|
|
35311
|
-
}
|
|
35573
|
+
};
|
|
35312
35574
|
function errToString(err) {
|
|
35313
35575
|
if (err instanceof Error)
|
|
35314
35576
|
return err.message;
|
|
@@ -35385,697 +35647,123 @@ var CodexSessionManager = class {
|
|
|
35385
35647
|
};
|
|
35386
35648
|
|
|
35387
35649
|
// ts/codex-agent/dist/workspace.js
|
|
35650
|
+
import * as fs10 from "node:fs";
|
|
35651
|
+
import * as path11 from "node:path";
|
|
35652
|
+
|
|
35653
|
+
// ts/codex-agent/dist/legacy-workspace-config-migration.js
|
|
35388
35654
|
import * as fs9 from "node:fs";
|
|
35389
35655
|
import * as path10 from "node:path";
|
|
35390
|
-
|
|
35391
|
-
|
|
35392
|
-
function
|
|
35393
|
-
|
|
35394
|
-
return [lines.length, lines.pop().length + 1];
|
|
35395
|
-
}
|
|
35396
|
-
function makeCodeBlock(string, line, column) {
|
|
35397
|
-
let lines = string.split(/\r\n|\n|\r/g);
|
|
35398
|
-
let codeblock = "";
|
|
35399
|
-
let numberLen = (Math.log10(line + 1) | 0) + 1;
|
|
35400
|
-
for (let i = line - 1; i <= line + 1; i++) {
|
|
35401
|
-
let l = lines[i - 1];
|
|
35402
|
-
if (!l)
|
|
35403
|
-
continue;
|
|
35404
|
-
codeblock += i.toString().padEnd(numberLen, " ");
|
|
35405
|
-
codeblock += ": ";
|
|
35406
|
-
codeblock += l;
|
|
35407
|
-
codeblock += "\n";
|
|
35408
|
-
if (i === line) {
|
|
35409
|
-
codeblock += " ".repeat(numberLen + column + 2);
|
|
35410
|
-
codeblock += "^\n";
|
|
35411
|
-
}
|
|
35412
|
-
}
|
|
35413
|
-
return codeblock;
|
|
35414
|
-
}
|
|
35415
|
-
var TomlError = class extends Error {
|
|
35416
|
-
line;
|
|
35417
|
-
column;
|
|
35418
|
-
codeblock;
|
|
35419
|
-
constructor(message, options) {
|
|
35420
|
-
const [line, column] = getLineColFromPtr(options.toml, options.ptr);
|
|
35421
|
-
const codeblock = makeCodeBlock(options.toml, line, column);
|
|
35422
|
-
super(`Invalid TOML document: ${message}
|
|
35423
|
-
|
|
35424
|
-
${codeblock}`, options);
|
|
35425
|
-
this.line = line;
|
|
35426
|
-
this.column = column;
|
|
35427
|
-
this.codeblock = codeblock;
|
|
35428
|
-
}
|
|
35429
|
-
};
|
|
35430
|
-
|
|
35431
|
-
// ts/node_modules/.pnpm/smol-toml@1.6.1/node_modules/smol-toml/dist/util.js
|
|
35432
|
-
function isEscaped(str, ptr) {
|
|
35433
|
-
let i = 0;
|
|
35434
|
-
while (str[ptr - ++i] === "\\")
|
|
35435
|
-
;
|
|
35436
|
-
return --i && i % 2;
|
|
35437
|
-
}
|
|
35438
|
-
function indexOfNewline(str, start = 0, end = str.length) {
|
|
35439
|
-
let idx = str.indexOf("\n", start);
|
|
35440
|
-
if (str[idx - 1] === "\r")
|
|
35441
|
-
idx--;
|
|
35442
|
-
return idx <= end ? idx : -1;
|
|
35443
|
-
}
|
|
35444
|
-
function skipComment(str, ptr) {
|
|
35445
|
-
for (let i = ptr; i < str.length; i++) {
|
|
35446
|
-
let c = str[i];
|
|
35447
|
-
if (c === "\n")
|
|
35448
|
-
return i;
|
|
35449
|
-
if (c === "\r" && str[i + 1] === "\n")
|
|
35450
|
-
return i + 1;
|
|
35451
|
-
if (c < " " && c !== " " || c === "\x7F") {
|
|
35452
|
-
throw new TomlError("control characters are not allowed in comments", {
|
|
35453
|
-
toml: str,
|
|
35454
|
-
ptr
|
|
35455
|
-
});
|
|
35456
|
-
}
|
|
35457
|
-
}
|
|
35458
|
-
return str.length;
|
|
35656
|
+
var LEGACY_CONFIG_RELPATH = [".codex", "config.toml"];
|
|
35657
|
+
var MIGRATION_SENTINEL_RELPATH = [".parall", "legacy-workspace-config-migration.v1"];
|
|
35658
|
+
function legacyWorkspaceConfigPath(workspaceDir) {
|
|
35659
|
+
return path10.join(workspaceDir, ...LEGACY_CONFIG_RELPATH);
|
|
35459
35660
|
}
|
|
35460
|
-
function
|
|
35461
|
-
|
|
35462
|
-
while (1) {
|
|
35463
|
-
while ((c = str[ptr]) === " " || c === " " || !banNewLines && (c === "\n" || c === "\r" && str[ptr + 1] === "\n"))
|
|
35464
|
-
ptr++;
|
|
35465
|
-
if (banComments || c !== "#")
|
|
35466
|
-
break;
|
|
35467
|
-
ptr = skipComment(str, ptr);
|
|
35468
|
-
}
|
|
35469
|
-
return ptr;
|
|
35661
|
+
function migrationSentinelPath(workspaceDir) {
|
|
35662
|
+
return path10.join(workspaceDir, ...MIGRATION_SENTINEL_RELPATH);
|
|
35470
35663
|
}
|
|
35471
|
-
function
|
|
35472
|
-
|
|
35473
|
-
|
|
35474
|
-
|
|
35475
|
-
|
|
35476
|
-
for (let i = ptr; i < str.length; i++) {
|
|
35477
|
-
let c = str[i];
|
|
35478
|
-
if (c === "#") {
|
|
35479
|
-
i = indexOfNewline(str, i);
|
|
35480
|
-
} else if (c === sep2) {
|
|
35481
|
-
return i + 1;
|
|
35482
|
-
} else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
|
|
35483
|
-
return i;
|
|
35484
|
-
}
|
|
35485
|
-
}
|
|
35486
|
-
throw new TomlError("cannot find end of structure", {
|
|
35487
|
-
toml: str,
|
|
35488
|
-
ptr
|
|
35489
|
-
});
|
|
35664
|
+
function legacyWorkspaceConfigToml(prompt) {
|
|
35665
|
+
return `developer_instructions = """
|
|
35666
|
+
${prompt.replace(/\\/g, "\\\\").replace(/"""/g, '\\"""')}
|
|
35667
|
+
"""
|
|
35668
|
+
`;
|
|
35490
35669
|
}
|
|
35491
|
-
function
|
|
35492
|
-
|
|
35493
|
-
|
|
35494
|
-
|
|
35495
|
-
|
|
35496
|
-
|
|
35497
|
-
|
|
35498
|
-
|
|
35499
|
-
|
|
35500
|
-
|
|
35501
|
-
|
|
35502
|
-
|
|
35503
|
-
|
|
35504
|
-
|
|
35505
|
-
}
|
|
35506
|
-
|
|
35507
|
-
|
|
35670
|
+
function classifyLegacyWorkspaceConfig(facts) {
|
|
35671
|
+
const { entry, rawContent, proof } = facts;
|
|
35672
|
+
if (!entry)
|
|
35673
|
+
return { action: "none" };
|
|
35674
|
+
if (!entry.isPlainFile)
|
|
35675
|
+
return { action: "preserve", reason: "not-a-plain-file" };
|
|
35676
|
+
if (entry.hardLinks !== 1)
|
|
35677
|
+
return { action: "preserve", reason: "extra-hard-links" };
|
|
35678
|
+
if (proof.kind === "absent")
|
|
35679
|
+
return { action: "preserve", reason: "no-authorship-proof" };
|
|
35680
|
+
if (proof.kind === "unreadable") {
|
|
35681
|
+
return { action: "preserve", reason: "authorship-proof-unreadable" };
|
|
35682
|
+
}
|
|
35683
|
+
if (rawContent === null)
|
|
35684
|
+
return { action: "preserve", reason: "config-unreadable" };
|
|
35685
|
+
if (rawContent !== legacyWorkspaceConfigToml(proof.prompt)) {
|
|
35686
|
+
return { action: "preserve", reason: "content-mismatch" };
|
|
35687
|
+
}
|
|
35688
|
+
return { action: "remove" };
|
|
35508
35689
|
}
|
|
35509
|
-
|
|
35510
|
-
|
|
35511
|
-
|
|
35512
|
-
|
|
35513
|
-
|
|
35514
|
-
|
|
35515
|
-
|
|
35516
|
-
constructor(date) {
|
|
35517
|
-
let hasDate = true;
|
|
35518
|
-
let hasTime = true;
|
|
35519
|
-
let offset = "Z";
|
|
35520
|
-
if (typeof date === "string") {
|
|
35521
|
-
let match = date.match(DATE_TIME_RE);
|
|
35522
|
-
if (match) {
|
|
35523
|
-
if (!match[1]) {
|
|
35524
|
-
hasDate = false;
|
|
35525
|
-
date = `0000-01-01T${date}`;
|
|
35526
|
-
}
|
|
35527
|
-
hasTime = !!match[2];
|
|
35528
|
-
hasTime && date[10] === " " && (date = date.replace(" ", "T"));
|
|
35529
|
-
if (match[2] && +match[2] > 23) {
|
|
35530
|
-
date = "";
|
|
35531
|
-
} else {
|
|
35532
|
-
offset = match[3] || null;
|
|
35533
|
-
date = date.toUpperCase();
|
|
35534
|
-
if (!offset && hasTime)
|
|
35535
|
-
date += "Z";
|
|
35536
|
-
}
|
|
35537
|
-
} else {
|
|
35538
|
-
date = "";
|
|
35539
|
-
}
|
|
35540
|
-
}
|
|
35541
|
-
super(date);
|
|
35542
|
-
if (!isNaN(this.getTime())) {
|
|
35543
|
-
this.#hasDate = hasDate;
|
|
35544
|
-
this.#hasTime = hasTime;
|
|
35545
|
-
this.#offset = offset;
|
|
35546
|
-
}
|
|
35547
|
-
}
|
|
35548
|
-
isDateTime() {
|
|
35549
|
-
return this.#hasDate && this.#hasTime;
|
|
35550
|
-
}
|
|
35551
|
-
isLocal() {
|
|
35552
|
-
return !this.#hasDate || !this.#hasTime || !this.#offset;
|
|
35553
|
-
}
|
|
35554
|
-
isDate() {
|
|
35555
|
-
return this.#hasDate && !this.#hasTime;
|
|
35556
|
-
}
|
|
35557
|
-
isTime() {
|
|
35558
|
-
return this.#hasTime && !this.#hasDate;
|
|
35559
|
-
}
|
|
35560
|
-
isValid() {
|
|
35561
|
-
return this.#hasDate || this.#hasTime;
|
|
35562
|
-
}
|
|
35563
|
-
toISOString() {
|
|
35564
|
-
let iso = super.toISOString();
|
|
35565
|
-
if (this.isDate())
|
|
35566
|
-
return iso.slice(0, 10);
|
|
35567
|
-
if (this.isTime())
|
|
35568
|
-
return iso.slice(11, 23);
|
|
35569
|
-
if (this.#offset === null)
|
|
35570
|
-
return iso.slice(0, -1);
|
|
35571
|
-
if (this.#offset === "Z")
|
|
35572
|
-
return iso;
|
|
35573
|
-
let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6);
|
|
35574
|
-
offset = this.#offset[0] === "-" ? offset : -offset;
|
|
35575
|
-
let offsetDate = new Date(this.getTime() - offset * 6e4);
|
|
35576
|
-
return offsetDate.toISOString().slice(0, -1) + this.#offset;
|
|
35577
|
-
}
|
|
35578
|
-
static wrapAsOffsetDateTime(jsDate, offset = "Z") {
|
|
35579
|
-
let date = new _TomlDate(jsDate);
|
|
35580
|
-
date.#offset = offset;
|
|
35581
|
-
return date;
|
|
35582
|
-
}
|
|
35583
|
-
static wrapAsLocalDateTime(jsDate) {
|
|
35584
|
-
let date = new _TomlDate(jsDate);
|
|
35585
|
-
date.#offset = null;
|
|
35586
|
-
return date;
|
|
35587
|
-
}
|
|
35588
|
-
static wrapAsLocalDate(jsDate) {
|
|
35589
|
-
let date = new _TomlDate(jsDate);
|
|
35590
|
-
date.#hasTime = false;
|
|
35591
|
-
date.#offset = null;
|
|
35592
|
-
return date;
|
|
35593
|
-
}
|
|
35594
|
-
static wrapAsLocalTime(jsDate) {
|
|
35595
|
-
let date = new _TomlDate(jsDate);
|
|
35596
|
-
date.#hasDate = false;
|
|
35597
|
-
date.#offset = null;
|
|
35598
|
-
return date;
|
|
35599
|
-
}
|
|
35690
|
+
var PRESERVE_DETAIL = {
|
|
35691
|
+
"not-a-plain-file": "it is a symlink or directory, not a plain file the bridge could have written",
|
|
35692
|
+
"extra-hard-links": "the file has more than one hard link, so another path shares this inode",
|
|
35693
|
+
"no-authorship-proof": "this workspace has no .parall/system-prompt.md from a previous boot, so nothing here can be proven ours",
|
|
35694
|
+
"authorship-proof-unreadable": "the .parall/system-prompt.md authorship proof exists but could not be read, so ownership cannot be evaluated",
|
|
35695
|
+
"config-unreadable": "its own bytes could not be read, so authorship cannot be proven",
|
|
35696
|
+
"content-mismatch": "its bytes are not what the retired bridge would have written"
|
|
35600
35697
|
};
|
|
35698
|
+
var SENTINEL_BODY = `Parall codex bridge \u2014 one-shot workspace migration record (v1)
|
|
35601
35699
|
|
|
35602
|
-
|
|
35603
|
-
|
|
35604
|
-
|
|
35605
|
-
var LEADING_ZERO = /^[+-]?0[0-9_]/;
|
|
35606
|
-
var ESCAPE_REGEX = /^[0-9a-f]{2,8}$/i;
|
|
35607
|
-
var ESC_MAP = {
|
|
35608
|
-
b: "\b",
|
|
35609
|
-
t: " ",
|
|
35610
|
-
n: "\n",
|
|
35611
|
-
f: "\f",
|
|
35612
|
-
r: "\r",
|
|
35613
|
-
e: "\x1B",
|
|
35614
|
-
'"': '"',
|
|
35615
|
-
"\\": "\\"
|
|
35616
|
-
};
|
|
35617
|
-
function parseString(str, ptr = 0, endPtr = str.length) {
|
|
35618
|
-
let isLiteral = str[ptr] === "'";
|
|
35619
|
-
let isMultiline = str[ptr++] === str[ptr] && str[ptr] === str[ptr + 1];
|
|
35620
|
-
if (isMultiline) {
|
|
35621
|
-
endPtr -= 2;
|
|
35622
|
-
if (str[ptr += 2] === "\r")
|
|
35623
|
-
ptr++;
|
|
35624
|
-
if (str[ptr] === "\n")
|
|
35625
|
-
ptr++;
|
|
35626
|
-
}
|
|
35627
|
-
let tmp = 0;
|
|
35628
|
-
let isEscape;
|
|
35629
|
-
let parsed = "";
|
|
35630
|
-
let sliceStart = ptr;
|
|
35631
|
-
while (ptr < endPtr - 1) {
|
|
35632
|
-
let c = str[ptr++];
|
|
35633
|
-
if (c === "\n" || c === "\r" && str[ptr] === "\n") {
|
|
35634
|
-
if (!isMultiline) {
|
|
35635
|
-
throw new TomlError("newlines are not allowed in strings", {
|
|
35636
|
-
toml: str,
|
|
35637
|
-
ptr: ptr - 1
|
|
35638
|
-
});
|
|
35639
|
-
}
|
|
35640
|
-
} else if (c < " " && c !== " " || c === "\x7F") {
|
|
35641
|
-
throw new TomlError("control characters are not allowed in strings", {
|
|
35642
|
-
toml: str,
|
|
35643
|
-
ptr: ptr - 1
|
|
35644
|
-
});
|
|
35645
|
-
}
|
|
35646
|
-
if (isEscape) {
|
|
35647
|
-
isEscape = false;
|
|
35648
|
-
if (c === "x" || c === "u" || c === "U") {
|
|
35649
|
-
let code = str.slice(ptr, ptr += c === "x" ? 2 : c === "u" ? 4 : 8);
|
|
35650
|
-
if (!ESCAPE_REGEX.test(code)) {
|
|
35651
|
-
throw new TomlError("invalid unicode escape", {
|
|
35652
|
-
toml: str,
|
|
35653
|
-
ptr: tmp
|
|
35654
|
-
});
|
|
35655
|
-
}
|
|
35656
|
-
try {
|
|
35657
|
-
parsed += String.fromCodePoint(parseInt(code, 16));
|
|
35658
|
-
} catch {
|
|
35659
|
-
throw new TomlError("invalid unicode escape", {
|
|
35660
|
-
toml: str,
|
|
35661
|
-
ptr: tmp
|
|
35662
|
-
});
|
|
35663
|
-
}
|
|
35664
|
-
} else if (isMultiline && (c === "\n" || c === " " || c === " " || c === "\r")) {
|
|
35665
|
-
ptr = skipVoid(str, ptr - 1, true);
|
|
35666
|
-
if (str[ptr] !== "\n" && str[ptr] !== "\r") {
|
|
35667
|
-
throw new TomlError("invalid escape: only line-ending whitespace may be escaped", {
|
|
35668
|
-
toml: str,
|
|
35669
|
-
ptr: tmp
|
|
35670
|
-
});
|
|
35671
|
-
}
|
|
35672
|
-
ptr = skipVoid(str, ptr);
|
|
35673
|
-
} else if (c in ESC_MAP) {
|
|
35674
|
-
parsed += ESC_MAP[c];
|
|
35675
|
-
} else {
|
|
35676
|
-
throw new TomlError("unrecognized escape sequence", {
|
|
35677
|
-
toml: str,
|
|
35678
|
-
ptr: tmp
|
|
35679
|
-
});
|
|
35680
|
-
}
|
|
35681
|
-
sliceStart = ptr;
|
|
35682
|
-
} else if (!isLiteral && c === "\\") {
|
|
35683
|
-
tmp = ptr - 1;
|
|
35684
|
-
isEscape = true;
|
|
35685
|
-
parsed += str.slice(sliceStart, tmp);
|
|
35686
|
-
}
|
|
35687
|
-
}
|
|
35688
|
-
return parsed + str.slice(sliceStart, endPtr - 1);
|
|
35689
|
-
}
|
|
35690
|
-
function parseValue(value, toml, ptr, integersAsBigInt) {
|
|
35691
|
-
if (value === "true")
|
|
35692
|
-
return true;
|
|
35693
|
-
if (value === "false")
|
|
35694
|
-
return false;
|
|
35695
|
-
if (value === "-inf")
|
|
35696
|
-
return -Infinity;
|
|
35697
|
-
if (value === "inf" || value === "+inf")
|
|
35698
|
-
return Infinity;
|
|
35699
|
-
if (value === "nan" || value === "+nan" || value === "-nan")
|
|
35700
|
-
return NaN;
|
|
35701
|
-
if (value === "-0")
|
|
35702
|
-
return integersAsBigInt ? 0n : 0;
|
|
35703
|
-
let isInt = INT_REGEX.test(value);
|
|
35704
|
-
if (isInt || FLOAT_REGEX.test(value)) {
|
|
35705
|
-
if (LEADING_ZERO.test(value)) {
|
|
35706
|
-
throw new TomlError("leading zeroes are not allowed", {
|
|
35707
|
-
toml,
|
|
35708
|
-
ptr
|
|
35709
|
-
});
|
|
35710
|
-
}
|
|
35711
|
-
value = value.replace(/_/g, "");
|
|
35712
|
-
let numeric = +value;
|
|
35713
|
-
if (isNaN(numeric)) {
|
|
35714
|
-
throw new TomlError("invalid number", {
|
|
35715
|
-
toml,
|
|
35716
|
-
ptr
|
|
35717
|
-
});
|
|
35718
|
-
}
|
|
35719
|
-
if (isInt) {
|
|
35720
|
-
if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) {
|
|
35721
|
-
throw new TomlError("integer value cannot be represented losslessly", {
|
|
35722
|
-
toml,
|
|
35723
|
-
ptr
|
|
35724
|
-
});
|
|
35725
|
-
}
|
|
35726
|
-
if (isInt || integersAsBigInt === true)
|
|
35727
|
-
numeric = BigInt(value);
|
|
35728
|
-
}
|
|
35729
|
-
return numeric;
|
|
35730
|
-
}
|
|
35731
|
-
const date = new TomlDate(value);
|
|
35732
|
-
if (!date.isValid()) {
|
|
35733
|
-
throw new TomlError("invalid value", {
|
|
35734
|
-
toml,
|
|
35735
|
-
ptr
|
|
35736
|
-
});
|
|
35737
|
-
}
|
|
35738
|
-
return date;
|
|
35739
|
-
}
|
|
35700
|
+
The legacy workspace-config cleanup has been CLAIMED for this workspace. Only the
|
|
35701
|
+
boot that created this file was allowed to remove a bridge-authored
|
|
35702
|
+
.codex/config.toml, and only under a byte-exact authorship proof.
|
|
35740
35703
|
|
|
35741
|
-
|
|
35742
|
-
|
|
35743
|
-
|
|
35744
|
-
|
|
35745
|
-
|
|
35746
|
-
skipComment(str, commentIdx);
|
|
35747
|
-
value = value.slice(0, commentIdx);
|
|
35748
|
-
}
|
|
35749
|
-
return [value.trimEnd(), commentIdx];
|
|
35750
|
-
}
|
|
35751
|
-
function extractValue(str, ptr, end, depth, integersAsBigInt) {
|
|
35752
|
-
if (depth === 0) {
|
|
35753
|
-
throw new TomlError("document contains excessively nested structures. aborting.", {
|
|
35754
|
-
toml: str,
|
|
35755
|
-
ptr
|
|
35756
|
-
});
|
|
35757
|
-
}
|
|
35758
|
-
let c = str[ptr];
|
|
35759
|
-
if (c === "[" || c === "{") {
|
|
35760
|
-
let [value, endPtr2] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt);
|
|
35761
|
-
if (end) {
|
|
35762
|
-
endPtr2 = skipVoid(str, endPtr2);
|
|
35763
|
-
if (str[endPtr2] === ",")
|
|
35764
|
-
endPtr2++;
|
|
35765
|
-
else if (str[endPtr2] !== end) {
|
|
35766
|
-
throw new TomlError("expected comma or end of structure", {
|
|
35767
|
-
toml: str,
|
|
35768
|
-
ptr: endPtr2
|
|
35769
|
-
});
|
|
35770
|
-
}
|
|
35771
|
-
}
|
|
35772
|
-
return [value, endPtr2];
|
|
35773
|
-
}
|
|
35774
|
-
let endPtr;
|
|
35775
|
-
if (c === '"' || c === "'") {
|
|
35776
|
-
endPtr = getStringEnd(str, ptr);
|
|
35777
|
-
let parsed = parseString(str, ptr, endPtr);
|
|
35778
|
-
if (end) {
|
|
35779
|
-
endPtr = skipVoid(str, endPtr);
|
|
35780
|
-
if (str[endPtr] && str[endPtr] !== "," && str[endPtr] !== end && str[endPtr] !== "\n" && str[endPtr] !== "\r") {
|
|
35781
|
-
throw new TomlError("unexpected character encountered", {
|
|
35782
|
-
toml: str,
|
|
35783
|
-
ptr: endPtr
|
|
35784
|
-
});
|
|
35785
|
-
}
|
|
35786
|
-
endPtr += +(str[endPtr] === ",");
|
|
35787
|
-
}
|
|
35788
|
-
return [parsed, endPtr];
|
|
35789
|
-
}
|
|
35790
|
-
endPtr = skipUntil(str, ptr, ",", end);
|
|
35791
|
-
let slice = sliceAndTrimEndOf(str, ptr, endPtr - +(str[endPtr - 1] === ","));
|
|
35792
|
-
if (!slice[0]) {
|
|
35793
|
-
throw new TomlError("incomplete key-value declaration: no value specified", {
|
|
35794
|
-
toml: str,
|
|
35795
|
-
ptr
|
|
35796
|
-
});
|
|
35797
|
-
}
|
|
35798
|
-
if (end && slice[1] > -1) {
|
|
35799
|
-
endPtr = skipVoid(str, ptr + slice[1]);
|
|
35800
|
-
endPtr += +(str[endPtr] === ",");
|
|
35801
|
-
}
|
|
35802
|
-
return [
|
|
35803
|
-
parseValue(slice[0], str, ptr, integersAsBigInt),
|
|
35804
|
-
endPtr
|
|
35805
|
-
];
|
|
35806
|
-
}
|
|
35704
|
+
While this file exists the bridge will NEVER auto-remove .codex/config.toml again.
|
|
35705
|
+
Deleting this file does not safely re-arm the migration: the evidence it relied on
|
|
35706
|
+
(.parall/system-prompt.md as written by a pre-protocol-delivery bridge) has since
|
|
35707
|
+
been overwritten by this bridge, so a re-run could mistake a prompt it wrote itself
|
|
35708
|
+
for legacy evidence and delete a file that is not ours.
|
|
35807
35709
|
|
|
35808
|
-
|
|
35809
|
-
|
|
35810
|
-
function
|
|
35811
|
-
|
|
35812
|
-
|
|
35813
|
-
|
|
35814
|
-
|
|
35815
|
-
|
|
35816
|
-
|
|
35817
|
-
|
|
35818
|
-
|
|
35819
|
-
|
|
35820
|
-
do {
|
|
35821
|
-
let c = str[ptr = ++dot];
|
|
35822
|
-
if (c !== " " && c !== " ") {
|
|
35823
|
-
if (c === '"' || c === "'") {
|
|
35824
|
-
if (c === str[ptr + 1] && c === str[ptr + 2]) {
|
|
35825
|
-
throw new TomlError("multiline strings are not allowed in keys", {
|
|
35826
|
-
toml: str,
|
|
35827
|
-
ptr
|
|
35828
|
-
});
|
|
35829
|
-
}
|
|
35830
|
-
let eos = getStringEnd(str, ptr);
|
|
35831
|
-
if (eos < 0) {
|
|
35832
|
-
throw new TomlError("unfinished string encountered", {
|
|
35833
|
-
toml: str,
|
|
35834
|
-
ptr
|
|
35835
|
-
});
|
|
35836
|
-
}
|
|
35837
|
-
dot = str.indexOf(".", eos);
|
|
35838
|
-
let strEnd = str.slice(eos, dot < 0 || dot > endPtr ? endPtr : dot);
|
|
35839
|
-
let newLine = indexOfNewline(strEnd);
|
|
35840
|
-
if (newLine > -1) {
|
|
35841
|
-
throw new TomlError("newlines are not allowed in keys", {
|
|
35842
|
-
toml: str,
|
|
35843
|
-
ptr: ptr + dot + newLine
|
|
35844
|
-
});
|
|
35845
|
-
}
|
|
35846
|
-
if (strEnd.trimStart()) {
|
|
35847
|
-
throw new TomlError("found extra tokens after the string part", {
|
|
35848
|
-
toml: str,
|
|
35849
|
-
ptr: eos
|
|
35850
|
-
});
|
|
35851
|
-
}
|
|
35852
|
-
if (endPtr < eos) {
|
|
35853
|
-
endPtr = str.indexOf(end, eos);
|
|
35854
|
-
if (endPtr < 0) {
|
|
35855
|
-
throw new TomlError("incomplete key-value: cannot find end of key", {
|
|
35856
|
-
toml: str,
|
|
35857
|
-
ptr
|
|
35858
|
-
});
|
|
35859
|
-
}
|
|
35860
|
-
}
|
|
35861
|
-
parsed.push(parseString(str, ptr, eos));
|
|
35862
|
-
} else {
|
|
35863
|
-
dot = str.indexOf(".", ptr);
|
|
35864
|
-
let part = str.slice(ptr, dot < 0 || dot > endPtr ? endPtr : dot);
|
|
35865
|
-
if (!KEY_PART_RE.test(part)) {
|
|
35866
|
-
throw new TomlError("only letter, numbers, dashes and underscores are allowed in keys", {
|
|
35867
|
-
toml: str,
|
|
35868
|
-
ptr
|
|
35869
|
-
});
|
|
35870
|
-
}
|
|
35871
|
-
parsed.push(part.trimEnd());
|
|
35872
|
-
}
|
|
35873
|
-
}
|
|
35874
|
-
} while (dot + 1 && dot < endPtr);
|
|
35875
|
-
return [parsed, skipVoid(str, endPtr + 1, true, true)];
|
|
35876
|
-
}
|
|
35877
|
-
function parseInlineTable(str, ptr, depth, integersAsBigInt) {
|
|
35878
|
-
let res = {};
|
|
35879
|
-
let seen = /* @__PURE__ */ new Set();
|
|
35880
|
-
let c;
|
|
35881
|
-
ptr++;
|
|
35882
|
-
while ((c = str[ptr++]) !== "}" && c) {
|
|
35883
|
-
if (c === ",") {
|
|
35884
|
-
throw new TomlError("expected value, found comma", {
|
|
35885
|
-
toml: str,
|
|
35886
|
-
ptr: ptr - 1
|
|
35887
|
-
});
|
|
35888
|
-
} else if (c === "#")
|
|
35889
|
-
ptr = skipComment(str, ptr);
|
|
35890
|
-
else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
|
|
35891
|
-
let k;
|
|
35892
|
-
let t = res;
|
|
35893
|
-
let hasOwn = false;
|
|
35894
|
-
let [key, keyEndPtr] = parseKey(str, ptr - 1);
|
|
35895
|
-
for (let i = 0; i < key.length; i++) {
|
|
35896
|
-
if (i)
|
|
35897
|
-
t = hasOwn ? t[k] : t[k] = {};
|
|
35898
|
-
k = key[i];
|
|
35899
|
-
if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) {
|
|
35900
|
-
throw new TomlError("trying to redefine an already defined value", {
|
|
35901
|
-
toml: str,
|
|
35902
|
-
ptr
|
|
35903
|
-
});
|
|
35904
|
-
}
|
|
35905
|
-
if (!hasOwn && k === "__proto__") {
|
|
35906
|
-
Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
|
|
35907
|
-
}
|
|
35908
|
-
}
|
|
35909
|
-
if (hasOwn) {
|
|
35910
|
-
throw new TomlError("trying to redefine an already defined value", {
|
|
35911
|
-
toml: str,
|
|
35912
|
-
ptr
|
|
35913
|
-
});
|
|
35914
|
-
}
|
|
35915
|
-
let [value, valueEndPtr] = extractValue(str, keyEndPtr, "}", depth - 1, integersAsBigInt);
|
|
35916
|
-
seen.add(value);
|
|
35917
|
-
t[k] = value;
|
|
35918
|
-
ptr = valueEndPtr;
|
|
35919
|
-
}
|
|
35920
|
-
}
|
|
35921
|
-
if (!c) {
|
|
35922
|
-
throw new TomlError("unfinished table encountered", {
|
|
35923
|
-
toml: str,
|
|
35924
|
-
ptr
|
|
35925
|
-
});
|
|
35710
|
+
If a stale .codex/config.toml is still present, remove it by hand.
|
|
35711
|
+
`;
|
|
35712
|
+
function claimLegacyWorkspaceConfigMigration(workspaceDir) {
|
|
35713
|
+
const sentinel = migrationSentinelPath(workspaceDir);
|
|
35714
|
+
fs9.mkdirSync(path10.dirname(sentinel), { recursive: true });
|
|
35715
|
+
try {
|
|
35716
|
+
fs9.writeFileSync(sentinel, SENTINEL_BODY, { flag: "wx" });
|
|
35717
|
+
return "claimed";
|
|
35718
|
+
} catch (err) {
|
|
35719
|
+
if (err.code === "EEXIST")
|
|
35720
|
+
return "already-claimed";
|
|
35721
|
+
throw err;
|
|
35926
35722
|
}
|
|
35927
|
-
return [res, ptr];
|
|
35928
35723
|
}
|
|
35929
|
-
function
|
|
35930
|
-
|
|
35931
|
-
|
|
35932
|
-
|
|
35933
|
-
while ((c = str[ptr++]) !== "]" && c) {
|
|
35934
|
-
if (c === ",") {
|
|
35935
|
-
throw new TomlError("expected value, found comma", {
|
|
35936
|
-
toml: str,
|
|
35937
|
-
ptr: ptr - 1
|
|
35938
|
-
});
|
|
35939
|
-
} else if (c === "#")
|
|
35940
|
-
ptr = skipComment(str, ptr);
|
|
35941
|
-
else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
|
|
35942
|
-
let e = extractValue(str, ptr - 1, "]", depth - 1, integersAsBigInt);
|
|
35943
|
-
res.push(e[0]);
|
|
35944
|
-
ptr = e[1];
|
|
35945
|
-
}
|
|
35946
|
-
}
|
|
35947
|
-
if (!c) {
|
|
35948
|
-
throw new TomlError("unfinished array encountered", {
|
|
35949
|
-
toml: str,
|
|
35950
|
-
ptr
|
|
35951
|
-
});
|
|
35952
|
-
}
|
|
35953
|
-
return [res, ptr];
|
|
35724
|
+
function runLegacyWorkspaceConfigMigration(workspaceDir, readProof, log2) {
|
|
35725
|
+
if (claimLegacyWorkspaceConfigMigration(workspaceDir) === "already-claimed")
|
|
35726
|
+
return;
|
|
35727
|
+
cleanupLegacyWorkspaceConfig(workspaceDir, readProof(), log2);
|
|
35954
35728
|
}
|
|
35955
|
-
|
|
35956
|
-
|
|
35957
|
-
|
|
35958
|
-
|
|
35959
|
-
|
|
35960
|
-
|
|
35961
|
-
|
|
35962
|
-
|
|
35963
|
-
for (let i = 0; i < key.length; i++) {
|
|
35964
|
-
if (i) {
|
|
35965
|
-
t = hasOwn ? t[k] : t[k] = {};
|
|
35966
|
-
m = (state = m[k]).c;
|
|
35967
|
-
if (type === 0 && (state.t === 1 || state.t === 2)) {
|
|
35968
|
-
return null;
|
|
35969
|
-
}
|
|
35970
|
-
if (state.t === 2) {
|
|
35971
|
-
let l = t.length - 1;
|
|
35972
|
-
t = t[l];
|
|
35973
|
-
m = m[l].c;
|
|
35974
|
-
}
|
|
35975
|
-
}
|
|
35976
|
-
k = key[i];
|
|
35977
|
-
if ((hasOwn = Object.hasOwn(t, k)) && m[k]?.t === 0 && m[k]?.d) {
|
|
35978
|
-
return null;
|
|
35979
|
-
}
|
|
35980
|
-
if (!hasOwn) {
|
|
35981
|
-
if (k === "__proto__") {
|
|
35982
|
-
Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
|
|
35983
|
-
Object.defineProperty(m, k, { enumerable: true, configurable: true, writable: true });
|
|
35984
|
-
}
|
|
35985
|
-
m[k] = {
|
|
35986
|
-
t: i < key.length - 1 && type === 2 ? 3 : type,
|
|
35987
|
-
d: false,
|
|
35988
|
-
i: 0,
|
|
35989
|
-
c: {}
|
|
35990
|
-
};
|
|
35729
|
+
function cleanupLegacyWorkspaceConfig(workspaceDir, proof, log2) {
|
|
35730
|
+
const configPath = legacyWorkspaceConfigPath(workspaceDir);
|
|
35731
|
+
let entry;
|
|
35732
|
+
try {
|
|
35733
|
+
entry = fs9.lstatSync(configPath);
|
|
35734
|
+
} catch (err) {
|
|
35735
|
+
if (err.code !== "ENOENT") {
|
|
35736
|
+
log2?.warn(`could not inspect legacy workspace codex config ${configPath}: ${String(err)}`);
|
|
35991
35737
|
}
|
|
35738
|
+
return;
|
|
35992
35739
|
}
|
|
35993
|
-
|
|
35994
|
-
|
|
35995
|
-
|
|
35996
|
-
|
|
35997
|
-
|
|
35998
|
-
|
|
35999
|
-
|
|
36000
|
-
t[k] = [];
|
|
35740
|
+
const isPlainFile = entry.isFile();
|
|
35741
|
+
let rawContent = null;
|
|
35742
|
+
if (isPlainFile) {
|
|
35743
|
+
try {
|
|
35744
|
+
rawContent = fs9.readFileSync(configPath, "utf8");
|
|
35745
|
+
} catch (err) {
|
|
35746
|
+
log2?.warn(`could not read legacy workspace codex config ${configPath}: ${String(err)}`);
|
|
36001
35747
|
}
|
|
36002
|
-
t[k].push(t = {});
|
|
36003
|
-
state.c[state.i++] = state = { t: 1, d: false, i: 0, c: {} };
|
|
36004
|
-
}
|
|
36005
|
-
if (state.d) {
|
|
36006
|
-
return null;
|
|
36007
|
-
}
|
|
36008
|
-
state.d = true;
|
|
36009
|
-
if (type === 1) {
|
|
36010
|
-
t = hasOwn ? t[k] : t[k] = {};
|
|
36011
|
-
} else if (type === 0 && hasOwn) {
|
|
36012
|
-
return null;
|
|
36013
35748
|
}
|
|
36014
|
-
|
|
36015
|
-
}
|
|
36016
|
-
|
|
36017
|
-
|
|
36018
|
-
|
|
36019
|
-
|
|
36020
|
-
|
|
36021
|
-
|
|
36022
|
-
|
|
36023
|
-
|
|
36024
|
-
|
|
36025
|
-
if (
|
|
36026
|
-
|
|
36027
|
-
|
|
36028
|
-
toml,
|
|
36029
|
-
ptr: k[1] - 1
|
|
36030
|
-
});
|
|
36031
|
-
}
|
|
36032
|
-
k[1]++;
|
|
36033
|
-
}
|
|
36034
|
-
let p = peekTable(
|
|
36035
|
-
k[0],
|
|
36036
|
-
res,
|
|
36037
|
-
meta,
|
|
36038
|
-
isTableArray ? 2 : 1
|
|
36039
|
-
/* Type.EXPLICIT */
|
|
36040
|
-
);
|
|
36041
|
-
if (!p) {
|
|
36042
|
-
throw new TomlError("trying to redefine an already defined table or value", {
|
|
36043
|
-
toml,
|
|
36044
|
-
ptr
|
|
36045
|
-
});
|
|
36046
|
-
}
|
|
36047
|
-
m = p[2];
|
|
36048
|
-
tbl = p[1];
|
|
36049
|
-
ptr = k[1];
|
|
36050
|
-
} else {
|
|
36051
|
-
let k = parseKey(toml, ptr);
|
|
36052
|
-
let p = peekTable(
|
|
36053
|
-
k[0],
|
|
36054
|
-
tbl,
|
|
36055
|
-
m,
|
|
36056
|
-
0
|
|
36057
|
-
/* Type.DOTTED */
|
|
36058
|
-
);
|
|
36059
|
-
if (!p) {
|
|
36060
|
-
throw new TomlError("trying to redefine an already defined table or value", {
|
|
36061
|
-
toml,
|
|
36062
|
-
ptr
|
|
36063
|
-
});
|
|
36064
|
-
}
|
|
36065
|
-
let v = extractValue(toml, k[1], void 0, maxDepth, integersAsBigInt);
|
|
36066
|
-
p[1][p[0]] = v[0];
|
|
36067
|
-
ptr = v[1];
|
|
36068
|
-
}
|
|
36069
|
-
ptr = skipVoid(toml, ptr, true);
|
|
36070
|
-
if (toml[ptr] && toml[ptr] !== "\n" && toml[ptr] !== "\r") {
|
|
36071
|
-
throw new TomlError("each key-value declaration must be followed by an end-of-line", {
|
|
36072
|
-
toml,
|
|
36073
|
-
ptr
|
|
36074
|
-
});
|
|
35749
|
+
const verdict = classifyLegacyWorkspaceConfig({
|
|
35750
|
+
entry: { isPlainFile, hardLinks: entry.nlink },
|
|
35751
|
+
rawContent,
|
|
35752
|
+
proof
|
|
35753
|
+
});
|
|
35754
|
+
if (verdict.action === "none")
|
|
35755
|
+
return;
|
|
35756
|
+
if (verdict.action === "remove") {
|
|
35757
|
+
try {
|
|
35758
|
+
fs9.unlinkSync(configPath);
|
|
35759
|
+
} catch (err) {
|
|
35760
|
+
if (err.code === "ENOENT")
|
|
35761
|
+
return;
|
|
35762
|
+
log2?.warn(`could not remove legacy workspace codex config ${configPath}: ${String(err)}`);
|
|
36075
35763
|
}
|
|
36076
|
-
|
|
35764
|
+
return;
|
|
36077
35765
|
}
|
|
36078
|
-
|
|
35766
|
+
log2?.warn(`leaving ${configPath} in place \u2014 ${PRESERVE_DETAIL[verdict.reason]}, so it is not provably the retired bridge's own artifact. Codex loads it for trusted workspaces IN ADDITION to the platform instructions; remove it manually if it is a stale artifact.`);
|
|
36079
35767
|
}
|
|
36080
35768
|
|
|
36081
35769
|
// ts/codex-agent/dist/workspace.js
|
|
@@ -36089,16 +35777,16 @@ function sleepSync(ms) {
|
|
|
36089
35777
|
Atomics.wait(SLEEP_SIGNAL, 0, 0, ms);
|
|
36090
35778
|
}
|
|
36091
35779
|
function withConfigLock(codexHome, log2, fn) {
|
|
36092
|
-
const queueDir =
|
|
35780
|
+
const queueDir = path11.join(codexHome, "config.toml.lock.d");
|
|
36093
35781
|
let ticketName = bakeryEnqueue(queueDir);
|
|
36094
|
-
let ticketPath = ticketName ?
|
|
35782
|
+
let ticketPath = ticketName ? path11.join(queueDir, ticketName) : "";
|
|
36095
35783
|
let acquired = false;
|
|
36096
35784
|
let heldPath = "";
|
|
36097
35785
|
const deadline = Date.now() + CONFIG_LOCK_TIMINGS.waitMs;
|
|
36098
35786
|
while (ticketName && Date.now() < deadline) {
|
|
36099
35787
|
let names;
|
|
36100
35788
|
try {
|
|
36101
|
-
names =
|
|
35789
|
+
names = fs10.readdirSync(queueDir).sort();
|
|
36102
35790
|
} catch {
|
|
36103
35791
|
break;
|
|
36104
35792
|
}
|
|
@@ -36106,7 +35794,7 @@ function withConfigLock(codexHome, log2, fn) {
|
|
|
36106
35794
|
ticketName = bakeryEnqueue(queueDir);
|
|
36107
35795
|
if (!ticketName)
|
|
36108
35796
|
break;
|
|
36109
|
-
ticketPath =
|
|
35797
|
+
ticketPath = path11.join(queueDir, ticketName);
|
|
36110
35798
|
continue;
|
|
36111
35799
|
}
|
|
36112
35800
|
const now = Date.now();
|
|
@@ -36114,12 +35802,12 @@ function withConfigLock(codexHome, log2, fn) {
|
|
|
36114
35802
|
let blocked = false;
|
|
36115
35803
|
let head;
|
|
36116
35804
|
for (const name of names) {
|
|
36117
|
-
const entryPath =
|
|
35805
|
+
const entryPath = path11.join(queueDir, name);
|
|
36118
35806
|
if (name.startsWith("held-")) {
|
|
36119
35807
|
const enteredAt = Number.parseInt(name.slice(5, 20), 10);
|
|
36120
35808
|
if (Number.isFinite(enteredAt) && now - enteredAt > CONFIG_LOCK_TIMINGS.staleMs) {
|
|
36121
35809
|
try {
|
|
36122
|
-
|
|
35810
|
+
fs10.unlinkSync(entryPath);
|
|
36123
35811
|
} catch {
|
|
36124
35812
|
}
|
|
36125
35813
|
rescan = true;
|
|
@@ -36130,14 +35818,14 @@ function withConfigLock(codexHome, log2, fn) {
|
|
|
36130
35818
|
}
|
|
36131
35819
|
let mtimeMs;
|
|
36132
35820
|
try {
|
|
36133
|
-
mtimeMs =
|
|
35821
|
+
mtimeMs = fs10.statSync(entryPath).mtimeMs;
|
|
36134
35822
|
} catch {
|
|
36135
35823
|
rescan = true;
|
|
36136
35824
|
break;
|
|
36137
35825
|
}
|
|
36138
35826
|
if (now - mtimeMs > CONFIG_LOCK_TIMINGS.staleMs) {
|
|
36139
35827
|
try {
|
|
36140
|
-
|
|
35828
|
+
fs10.unlinkSync(entryPath);
|
|
36141
35829
|
} catch {
|
|
36142
35830
|
}
|
|
36143
35831
|
rescan = true;
|
|
@@ -36157,9 +35845,9 @@ function withConfigLock(codexHome, log2, fn) {
|
|
|
36157
35845
|
if (!blocked && head === ticketName) {
|
|
36158
35846
|
CONFIG_LOCK_TEST_HOOKS.beforeTicketEntry?.();
|
|
36159
35847
|
const heldName = `held-${String(Date.now()).padStart(15, "0")}-${ticketName.slice(2)}`;
|
|
36160
|
-
const candidateHeldPath =
|
|
35848
|
+
const candidateHeldPath = path11.join(queueDir, heldName);
|
|
36161
35849
|
try {
|
|
36162
|
-
|
|
35850
|
+
fs10.renameSync(ticketPath, candidateHeldPath);
|
|
36163
35851
|
} catch {
|
|
36164
35852
|
continue;
|
|
36165
35853
|
}
|
|
@@ -36169,7 +35857,7 @@ function withConfigLock(codexHome, log2, fn) {
|
|
|
36169
35857
|
}
|
|
36170
35858
|
try {
|
|
36171
35859
|
const t = /* @__PURE__ */ new Date();
|
|
36172
|
-
|
|
35860
|
+
fs10.utimesSync(ticketPath, t, t);
|
|
36173
35861
|
} catch {
|
|
36174
35862
|
}
|
|
36175
35863
|
sleepSync(CONFIG_LOCK_TIMINGS.retryMs);
|
|
@@ -36178,7 +35866,7 @@ function withConfigLock(codexHome, log2, fn) {
|
|
|
36178
35866
|
log2?.warn(`could not acquire ${queueDir}; writing config.toml without lock`);
|
|
36179
35867
|
if (ticketName) {
|
|
36180
35868
|
try {
|
|
36181
|
-
|
|
35869
|
+
fs10.unlinkSync(ticketPath);
|
|
36182
35870
|
} catch {
|
|
36183
35871
|
}
|
|
36184
35872
|
}
|
|
@@ -36188,7 +35876,7 @@ function withConfigLock(codexHome, log2, fn) {
|
|
|
36188
35876
|
} finally {
|
|
36189
35877
|
if (acquired) {
|
|
36190
35878
|
try {
|
|
36191
|
-
|
|
35879
|
+
fs10.unlinkSync(heldPath);
|
|
36192
35880
|
} catch {
|
|
36193
35881
|
}
|
|
36194
35882
|
}
|
|
@@ -36198,17 +35886,17 @@ var CONFIG_LOCK_TEST_HOOKS = {};
|
|
|
36198
35886
|
function bakeryEnqueue(queueDir) {
|
|
36199
35887
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
36200
35888
|
const token = `${process.pid}-${Math.random().toString(36).slice(2, 10)}`;
|
|
36201
|
-
const markerPath =
|
|
35889
|
+
const markerPath = path11.join(queueDir, `choosing-${token}`);
|
|
36202
35890
|
try {
|
|
36203
|
-
|
|
35891
|
+
fs10.mkdirSync(queueDir, { recursive: true });
|
|
36204
35892
|
CONFIG_LOCK_TEST_HOOKS.beforeChoosingMarker?.();
|
|
36205
|
-
|
|
35893
|
+
fs10.writeFileSync(markerPath, "", { flag: "wx" });
|
|
36206
35894
|
} catch {
|
|
36207
35895
|
return null;
|
|
36208
35896
|
}
|
|
36209
35897
|
try {
|
|
36210
35898
|
let maxSeq = 0;
|
|
36211
|
-
for (const name of
|
|
35899
|
+
for (const name of fs10.readdirSync(queueDir)) {
|
|
36212
35900
|
if (!name.startsWith("t-"))
|
|
36213
35901
|
continue;
|
|
36214
35902
|
const seq = Number.parseInt(name.slice(2, 12), 10);
|
|
@@ -36216,18 +35904,18 @@ function bakeryEnqueue(queueDir) {
|
|
|
36216
35904
|
maxSeq = seq;
|
|
36217
35905
|
}
|
|
36218
35906
|
const ticketName = `t-${String(maxSeq + 1).padStart(10, "0")}-${token}`;
|
|
36219
|
-
const ticketPath =
|
|
35907
|
+
const ticketPath = path11.join(queueDir, ticketName);
|
|
36220
35908
|
CONFIG_LOCK_TEST_HOOKS.beforeTicketPublish?.();
|
|
36221
|
-
|
|
35909
|
+
fs10.renameSync(markerPath, ticketPath);
|
|
36222
35910
|
try {
|
|
36223
35911
|
const t = /* @__PURE__ */ new Date();
|
|
36224
|
-
|
|
35912
|
+
fs10.utimesSync(ticketPath, t, t);
|
|
36225
35913
|
} catch {
|
|
36226
35914
|
}
|
|
36227
35915
|
return ticketName;
|
|
36228
35916
|
} catch (err) {
|
|
36229
35917
|
try {
|
|
36230
|
-
|
|
35918
|
+
fs10.unlinkSync(markerPath);
|
|
36231
35919
|
} catch {
|
|
36232
35920
|
}
|
|
36233
35921
|
if (err.code === "ENOENT")
|
|
@@ -36241,21 +35929,21 @@ function writeConfigAtomic(filePath, content) {
|
|
|
36241
35929
|
const realPath = resolveWriteTarget(filePath);
|
|
36242
35930
|
let mode;
|
|
36243
35931
|
try {
|
|
36244
|
-
mode =
|
|
35932
|
+
mode = fs10.statSync(realPath).mode & 511;
|
|
36245
35933
|
} catch {
|
|
36246
35934
|
}
|
|
36247
35935
|
const tmpPath = `${realPath}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
|
|
36248
35936
|
let tmpCreated = false;
|
|
36249
35937
|
try {
|
|
36250
|
-
|
|
35938
|
+
fs10.writeFileSync(tmpPath, content, { encoding: "utf8", mode: 384, flag: "wx" });
|
|
36251
35939
|
tmpCreated = true;
|
|
36252
35940
|
if (mode !== void 0)
|
|
36253
|
-
|
|
36254
|
-
|
|
35941
|
+
fs10.chmodSync(tmpPath, mode);
|
|
35942
|
+
fs10.renameSync(tmpPath, realPath);
|
|
36255
35943
|
} catch (err) {
|
|
36256
35944
|
if (tmpCreated || err.code !== "EEXIST") {
|
|
36257
35945
|
try {
|
|
36258
|
-
|
|
35946
|
+
fs10.unlinkSync(tmpPath);
|
|
36259
35947
|
} catch {
|
|
36260
35948
|
}
|
|
36261
35949
|
}
|
|
@@ -36264,13 +35952,13 @@ function writeConfigAtomic(filePath, content) {
|
|
|
36264
35952
|
}
|
|
36265
35953
|
function resolveWriteTarget(filePath) {
|
|
36266
35954
|
try {
|
|
36267
|
-
return
|
|
35955
|
+
return fs10.realpathSync(filePath);
|
|
36268
35956
|
} catch (err) {
|
|
36269
35957
|
if (err.code !== "ENOENT")
|
|
36270
35958
|
throw err;
|
|
36271
35959
|
}
|
|
36272
35960
|
const seen = /* @__PURE__ */ new Set();
|
|
36273
|
-
let p =
|
|
35961
|
+
let p = path11.resolve(filePath);
|
|
36274
35962
|
for (let depth = 0; depth < 40; depth++) {
|
|
36275
35963
|
if (seen.has(p)) {
|
|
36276
35964
|
throw new Error(`symlink cycle at ${p} while resolving ${filePath}`);
|
|
@@ -36278,87 +35966,17 @@ function resolveWriteTarget(filePath) {
|
|
|
36278
35966
|
seen.add(p);
|
|
36279
35967
|
let link;
|
|
36280
35968
|
try {
|
|
36281
|
-
link =
|
|
35969
|
+
link = fs10.readlinkSync(p);
|
|
36282
35970
|
} catch (err) {
|
|
36283
35971
|
const code = err.code;
|
|
36284
35972
|
if (code === "ENOENT" || code === "EINVAL")
|
|
36285
35973
|
return p;
|
|
36286
35974
|
throw err;
|
|
36287
35975
|
}
|
|
36288
|
-
p =
|
|
35976
|
+
p = path11.resolve(path11.dirname(p), link);
|
|
36289
35977
|
}
|
|
36290
35978
|
throw new Error(`symlink chain deeper than 40 while resolving ${filePath}`);
|
|
36291
35979
|
}
|
|
36292
|
-
function ensureWorkspaceTrusted(codexHome, workspaceDir, log2) {
|
|
36293
|
-
withConfigLock(codexHome, log2, () => ensureWorkspaceTrustedLocked(codexHome, workspaceDir, log2));
|
|
36294
|
-
}
|
|
36295
|
-
function ensureWorkspaceTrustedLocked(codexHome, workspaceDir, log2) {
|
|
36296
|
-
const configPath = path10.join(codexHome, "config.toml");
|
|
36297
|
-
const normalizedPath = path10.resolve(workspaceDir);
|
|
36298
|
-
try {
|
|
36299
|
-
let content = "";
|
|
36300
|
-
try {
|
|
36301
|
-
content = fs9.readFileSync(configPath, "utf8");
|
|
36302
|
-
} catch (err) {
|
|
36303
|
-
if (err.code !== "ENOENT")
|
|
36304
|
-
throw err;
|
|
36305
|
-
}
|
|
36306
|
-
let parsed;
|
|
36307
|
-
if (content) {
|
|
36308
|
-
try {
|
|
36309
|
-
parsed = parse(content);
|
|
36310
|
-
} catch {
|
|
36311
|
-
log2?.warn(`Codex config.toml is not valid TOML; skipping trust write for ${normalizedPath}`);
|
|
36312
|
-
return;
|
|
36313
|
-
}
|
|
36314
|
-
}
|
|
36315
|
-
const projects = parsed?.projects;
|
|
36316
|
-
const existingTrust = projects?.[normalizedPath]?.trust_level;
|
|
36317
|
-
if (existingTrust === "trusted")
|
|
36318
|
-
return;
|
|
36319
|
-
if (existingTrust !== void 0) {
|
|
36320
|
-
log2?.warn(`Codex config marks ${normalizedPath} as trust_level=${JSON.stringify(existingTrust)}; respecting the explicit decision \u2014 project-level developer_instructions will not load for this workspace`);
|
|
36321
|
-
return;
|
|
36322
|
-
}
|
|
36323
|
-
const escapedPath = normalizedPath.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
36324
|
-
const sectionHeader = `[projects."${escapedPath}"]`;
|
|
36325
|
-
const trustLine = 'trust_level = "trusted"';
|
|
36326
|
-
const headerIdx = content.indexOf(sectionHeader);
|
|
36327
|
-
if (headerIdx !== -1) {
|
|
36328
|
-
const headerLineEnd = content.indexOf("\n", headerIdx);
|
|
36329
|
-
if (headerLineEnd === -1) {
|
|
36330
|
-
content = `${content}
|
|
36331
|
-
${trustLine}
|
|
36332
|
-
`;
|
|
36333
|
-
} else {
|
|
36334
|
-
const afterHeader = headerLineEnd + 1;
|
|
36335
|
-
const sectionEnd = findSectionEnd(content, afterHeader);
|
|
36336
|
-
const sectionBody = content.substring(afterHeader, sectionEnd);
|
|
36337
|
-
const trustMatch = sectionBody.match(/^[ \t]*trust_level[ \t]*=.*$/m);
|
|
36338
|
-
if (trustMatch) {
|
|
36339
|
-
const matchStart = afterHeader + trustMatch.index;
|
|
36340
|
-
const matchEnd = matchStart + trustMatch[0].length;
|
|
36341
|
-
content = content.substring(0, matchStart) + trustLine + content.substring(matchEnd);
|
|
36342
|
-
} else {
|
|
36343
|
-
content = content.substring(0, afterHeader) + trustLine + "\n" + content.substring(afterHeader);
|
|
36344
|
-
}
|
|
36345
|
-
}
|
|
36346
|
-
writeConfigAtomic(configPath, content);
|
|
36347
|
-
} else if (projects?.[normalizedPath] !== void 0) {
|
|
36348
|
-
log2?.warn(`Codex config.toml has non-canonical header for ${normalizedPath}; skipping trust write`);
|
|
36349
|
-
} else if (projects && !content.includes("[projects.")) {
|
|
36350
|
-
log2?.warn(`Codex config.toml uses inline table for projects; skipping trust write for ${normalizedPath}`);
|
|
36351
|
-
} else {
|
|
36352
|
-
fs9.mkdirSync(codexHome, { recursive: true });
|
|
36353
|
-
fs9.appendFileSync(configPath, `
|
|
36354
|
-
${sectionHeader}
|
|
36355
|
-
${trustLine}
|
|
36356
|
-
`, "utf8");
|
|
36357
|
-
}
|
|
36358
|
-
} catch (err) {
|
|
36359
|
-
log2?.warn(`failed to write Codex project trust for ${normalizedPath}: ${String(err)}`);
|
|
36360
|
-
}
|
|
36361
|
-
}
|
|
36362
35980
|
function isParallProxyMode(env = process.env) {
|
|
36363
35981
|
const baseUrl = env.OPENAI_BASE_URL?.trim()?.replace(/\/+$/, "");
|
|
36364
35982
|
const apiUrl = env.PRLL_API_URL?.trim()?.replace(/\/+$/, "");
|
|
@@ -36366,16 +35984,50 @@ function isParallProxyMode(env = process.env) {
|
|
|
36366
35984
|
return false;
|
|
36367
35985
|
return baseUrl === apiUrl || baseUrl.startsWith(`${apiUrl}/`);
|
|
36368
35986
|
}
|
|
36369
|
-
function
|
|
36370
|
-
|
|
35987
|
+
function tomlBasicString(value) {
|
|
35988
|
+
let out = "";
|
|
35989
|
+
for (const ch of value) {
|
|
35990
|
+
const code = ch.codePointAt(0) ?? 0;
|
|
35991
|
+
if (ch === "\\")
|
|
35992
|
+
out += "\\\\";
|
|
35993
|
+
else if (ch === '"')
|
|
35994
|
+
out += '\\"';
|
|
35995
|
+
else if (ch === "\b")
|
|
35996
|
+
out += "\\b";
|
|
35997
|
+
else if (ch === " ")
|
|
35998
|
+
out += "\\t";
|
|
35999
|
+
else if (ch === "\n")
|
|
36000
|
+
out += "\\n";
|
|
36001
|
+
else if (ch === "\f")
|
|
36002
|
+
out += "\\f";
|
|
36003
|
+
else if (ch === "\r")
|
|
36004
|
+
out += "\\r";
|
|
36005
|
+
else if (code < 32 || code === 127)
|
|
36006
|
+
out += `\\u${code.toString(16).padStart(4, "0")}`;
|
|
36007
|
+
else
|
|
36008
|
+
out += ch;
|
|
36009
|
+
}
|
|
36010
|
+
return `"${out}"`;
|
|
36011
|
+
}
|
|
36012
|
+
function parallAuthLines(opts) {
|
|
36013
|
+
const platform = opts?.platform ?? process.platform;
|
|
36014
|
+
if (platform !== "win32") {
|
|
36015
|
+
return ['command = "printenv"', 'args = ["OPENAI_API_KEY"]'];
|
|
36016
|
+
}
|
|
36017
|
+
const nodeBin = opts?.nodeBin ?? process.execPath;
|
|
36018
|
+
const script = "const v=process.env.OPENAI_API_KEY;if(v===undefined)process.exit(1);process.stdout.write(v)";
|
|
36019
|
+
return [`command = ${tomlBasicString(nodeBin)}`, `args = ["-e", ${tomlBasicString(script)}]`];
|
|
36020
|
+
}
|
|
36021
|
+
function ensureParallProvider(codexHome, apiUrl, log2, opts) {
|
|
36022
|
+
withConfigLock(codexHome, log2, () => ensureParallProviderLocked(codexHome, apiUrl, opts));
|
|
36371
36023
|
}
|
|
36372
|
-
function ensureParallProviderLocked(codexHome, apiUrl) {
|
|
36373
|
-
const configPath =
|
|
36024
|
+
function ensureParallProviderLocked(codexHome, apiUrl, opts) {
|
|
36025
|
+
const configPath = path11.join(codexHome, "config.toml");
|
|
36374
36026
|
const baseUrl = apiUrl.replace(/\/$/, "") + "/api/llm/v1";
|
|
36375
36027
|
try {
|
|
36376
36028
|
let content = "";
|
|
36377
36029
|
try {
|
|
36378
|
-
content =
|
|
36030
|
+
content = fs10.readFileSync(configPath, "utf8");
|
|
36379
36031
|
} catch (err) {
|
|
36380
36032
|
if (err.code !== "ENOENT")
|
|
36381
36033
|
throw err;
|
|
@@ -36385,14 +36037,13 @@ function ensureParallProviderLocked(codexHome, apiUrl) {
|
|
|
36385
36037
|
const providerBlock = [
|
|
36386
36038
|
sectionHeader,
|
|
36387
36039
|
'name = "Parall Proxy"',
|
|
36388
|
-
`base_url =
|
|
36040
|
+
`base_url = ${tomlBasicString(baseUrl)}`,
|
|
36389
36041
|
'wire_api = "responses"',
|
|
36390
36042
|
"supports_websockets = false",
|
|
36391
36043
|
"requires_openai_auth = false",
|
|
36392
36044
|
"",
|
|
36393
36045
|
authHeader,
|
|
36394
|
-
|
|
36395
|
-
'args = ["OPENAI_API_KEY"]'
|
|
36046
|
+
...parallAuthLines(opts)
|
|
36396
36047
|
].join("\n");
|
|
36397
36048
|
const headerIdx = content.indexOf(sectionHeader);
|
|
36398
36049
|
if (headerIdx !== -1) {
|
|
@@ -36406,7 +36057,7 @@ function ensureParallProviderLocked(codexHome, apiUrl) {
|
|
|
36406
36057
|
} else {
|
|
36407
36058
|
content = content.trimEnd() + "\n\n" + providerBlock + "\n";
|
|
36408
36059
|
}
|
|
36409
|
-
|
|
36060
|
+
fs10.mkdirSync(codexHome, { recursive: true });
|
|
36410
36061
|
writeConfigAtomic(configPath, content);
|
|
36411
36062
|
} catch (err) {
|
|
36412
36063
|
throw new Error(`failed to write Parall provider config: ${String(err)}`);
|
|
@@ -36416,6 +36067,9 @@ function findSectionEnd(content, fromIndex) {
|
|
|
36416
36067
|
const nextHeader = content.indexOf("\n[", fromIndex);
|
|
36417
36068
|
return nextHeader === -1 ? content.length : nextHeader;
|
|
36418
36069
|
}
|
|
36070
|
+
function systemPromptCopyPath(workspaceDir) {
|
|
36071
|
+
return path11.join(workspaceDir, ".parall", "system-prompt.md");
|
|
36072
|
+
}
|
|
36419
36073
|
function writeCodexSystemPrompt(workspaceDir, agentIdentity, capabilityFragments) {
|
|
36420
36074
|
const parts = [
|
|
36421
36075
|
buildIdentity(agentIdentity),
|
|
@@ -36428,21 +36082,27 @@ function writeCodexSystemPrompt(workspaceDir, agentIdentity, capabilityFragments
|
|
|
36428
36082
|
}
|
|
36429
36083
|
parts.push(buildSkillReferences(workspaceDir));
|
|
36430
36084
|
const systemPrompt = parts.join("\n\n");
|
|
36431
|
-
|
|
36432
|
-
|
|
36433
|
-
|
|
36434
|
-
const codexConfigDir = path10.join(workspaceDir, ".codex");
|
|
36435
|
-
fs9.mkdirSync(codexConfigDir, { recursive: true });
|
|
36436
|
-
const toml = `developer_instructions = """
|
|
36437
|
-
${systemPrompt.replace(/\\/g, "\\\\").replace(/"""/g, '\\"""')}
|
|
36438
|
-
"""
|
|
36439
|
-
`;
|
|
36440
|
-
fs9.writeFileSync(path10.join(codexConfigDir, "config.toml"), toml, "utf8");
|
|
36085
|
+
fs10.mkdirSync(path11.join(workspaceDir, ".parall"), { recursive: true });
|
|
36086
|
+
fs10.writeFileSync(systemPromptCopyPath(workspaceDir), systemPrompt, "utf8");
|
|
36087
|
+
return systemPrompt;
|
|
36441
36088
|
}
|
|
36442
36089
|
function ensureCodexWorkspace(workspaceDir, log2, agentIdentity, capabilityFragments) {
|
|
36443
|
-
|
|
36444
|
-
|
|
36445
|
-
|
|
36090
|
+
fs10.mkdirSync(workspaceDir, { recursive: true });
|
|
36091
|
+
runLegacyWorkspaceConfigMigration(workspaceDir, () => readAuthorshipProof(workspaceDir, log2), log2);
|
|
36092
|
+
const systemPrompt = writeCodexSystemPrompt(workspaceDir, agentIdentity, capabilityFragments);
|
|
36093
|
+
writeSkillFiles(path11.join(workspaceDir, ".parall", "skills"));
|
|
36094
|
+
return systemPrompt;
|
|
36095
|
+
}
|
|
36096
|
+
function readAuthorshipProof(workspaceDir, log2) {
|
|
36097
|
+
const proofPath = systemPromptCopyPath(workspaceDir);
|
|
36098
|
+
try {
|
|
36099
|
+
return { kind: "present", prompt: fs10.readFileSync(proofPath, "utf8") };
|
|
36100
|
+
} catch (err) {
|
|
36101
|
+
if (err.code === "ENOENT")
|
|
36102
|
+
return { kind: "absent" };
|
|
36103
|
+
log2?.warn(`could not read the authorship proof ${proofPath}: ${String(err)}`);
|
|
36104
|
+
return { kind: "unreadable" };
|
|
36105
|
+
}
|
|
36446
36106
|
}
|
|
36447
36107
|
|
|
36448
36108
|
// ts/codex-agent/dist/index.js
|
|
@@ -36490,7 +36150,6 @@ async function main() {
|
|
|
36490
36150
|
const agentUserId = me.id;
|
|
36491
36151
|
const agentLog = childLogger(activeLog, agentUserId);
|
|
36492
36152
|
activeLog = agentLog;
|
|
36493
|
-
ensureWorkspaceTrusted(config.codexHome, config.workspaceDir, agentLog);
|
|
36494
36153
|
const useParallProvider = isParallProxyMode();
|
|
36495
36154
|
if (useParallProvider) {
|
|
36496
36155
|
ensureParallProvider(config.codexHome, config.apiUrl, agentLog);
|
|
@@ -36524,7 +36183,7 @@ async function main() {
|
|
|
36524
36183
|
};
|
|
36525
36184
|
const bootCapabilityFragments = applyChannelCapabilities();
|
|
36526
36185
|
let lastCapabilityFragments = bootCapabilityFragments.join("\n\n");
|
|
36527
|
-
ensureCodexWorkspace(config.workspaceDir, agentLog, agentIdentity, bootCapabilityFragments);
|
|
36186
|
+
const developerInstructions = ensureCodexWorkspace(config.workspaceDir, agentLog, agentIdentity, bootCapabilityFragments);
|
|
36528
36187
|
const platformModelOverride = deriveModelIsPin(platformDefaults, me.agent_profile);
|
|
36529
36188
|
const resolvedModel = resolveRuntimeModel(platformModelOverride, platformDefaults.model, config.model);
|
|
36530
36189
|
const resolvedEffort = platformDefaults.thinkingEffort ?? config.reasoningEffort;
|
|
@@ -36545,7 +36204,8 @@ async function main() {
|
|
|
36545
36204
|
contextFilePath: mainContextFilePath,
|
|
36546
36205
|
contextDirPath: dispatchContextDirPath(config.stateDir),
|
|
36547
36206
|
useParallProvider,
|
|
36548
|
-
capabilityBinDir: capabilityBinDir(config.stateDir)
|
|
36207
|
+
capabilityBinDir: capabilityBinDir(config.stateDir),
|
|
36208
|
+
developerInstructions
|
|
36549
36209
|
});
|
|
36550
36210
|
const refreshPlatformConfig = async () => {
|
|
36551
36211
|
const updated = await configMgr.fetch();
|
|
@@ -36566,7 +36226,8 @@ async function main() {
|
|
|
36566
36226
|
const joinedFragments = fragments.join("\n\n");
|
|
36567
36227
|
let promptWritten = true;
|
|
36568
36228
|
try {
|
|
36569
|
-
writeCodexSystemPrompt(config.workspaceDir, agentIdentity, fragments);
|
|
36229
|
+
const refreshedPrompt = writeCodexSystemPrompt(config.workspaceDir, agentIdentity, fragments);
|
|
36230
|
+
adapter.updateConfig({ developerInstructions: refreshedPrompt });
|
|
36570
36231
|
} catch (err) {
|
|
36571
36232
|
promptWritten = false;
|
|
36572
36233
|
agentLog.warn(`system prompt refresh write failed (retrying next refresh): ${String(err)}`);
|
|
@@ -36636,42 +36297,3 @@ main().catch((err) => {
|
|
|
36636
36297
|
activeLog.error(`fatal: ${String(err)}`);
|
|
36637
36298
|
process.exitCode = 1;
|
|
36638
36299
|
});
|
|
36639
|
-
/*! Bundled license information:
|
|
36640
|
-
|
|
36641
|
-
smol-toml/dist/error.js:
|
|
36642
|
-
smol-toml/dist/util.js:
|
|
36643
|
-
smol-toml/dist/date.js:
|
|
36644
|
-
smol-toml/dist/primitive.js:
|
|
36645
|
-
smol-toml/dist/extract.js:
|
|
36646
|
-
smol-toml/dist/struct.js:
|
|
36647
|
-
smol-toml/dist/parse.js:
|
|
36648
|
-
smol-toml/dist/stringify.js:
|
|
36649
|
-
smol-toml/dist/index.js:
|
|
36650
|
-
(*!
|
|
36651
|
-
* Copyright (c) Squirrel Chat et al., All rights reserved.
|
|
36652
|
-
* SPDX-License-Identifier: BSD-3-Clause
|
|
36653
|
-
*
|
|
36654
|
-
* Redistribution and use in source and binary forms, with or without
|
|
36655
|
-
* modification, are permitted provided that the following conditions are met:
|
|
36656
|
-
*
|
|
36657
|
-
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
36658
|
-
* list of conditions and the following disclaimer.
|
|
36659
|
-
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
36660
|
-
* this list of conditions and the following disclaimer in the
|
|
36661
|
-
* documentation and/or other materials provided with the distribution.
|
|
36662
|
-
* 3. Neither the name of the copyright holder nor the names of its contributors
|
|
36663
|
-
* may be used to endorse or promote products derived from this software without
|
|
36664
|
-
* specific prior written permission.
|
|
36665
|
-
*
|
|
36666
|
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
36667
|
-
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
36668
|
-
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
36669
|
-
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
36670
|
-
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
36671
|
-
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
36672
|
-
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
36673
|
-
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
36674
|
-
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
36675
|
-
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
36676
|
-
*)
|
|
36677
|
-
*/
|