@wrongstack/core 0.299.0 → 0.300.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/dist/coordination/director.d.ts +8 -0
- package/dist/coordination/fleet-manager.d.ts +48 -3
- package/dist/coordination/ifleet-manager.d.ts +2 -0
- package/dist/coordination/index.js +120 -20
- package/dist/coordination/multi-agent-coordinator.d.ts +1 -0
- package/dist/core/fallback-model.d.ts +48 -0
- package/dist/core/index.d.ts +3 -2
- package/dist/core/index.js +226 -26
- package/dist/core/instruction-template.d.ts +80 -0
- package/dist/core/system-prompt-blocks.d.ts +10 -1
- package/dist/core/system-prompt-builder.d.ts +35 -1
- package/dist/defaults/index.js +238 -99
- package/dist/execution/autonomy-brain.d.ts +7 -0
- package/dist/execution/council-brain.d.ts +11 -0
- package/dist/execution/council-orchestrator.d.ts +23 -4
- package/dist/execution/council-prompts.d.ts +12 -1
- package/dist/execution/index.js +355 -138
- package/dist/fleet-notifier.d.ts +9 -2
- package/dist/hooks/index.js +8 -4
- package/dist/hq/index.js +18 -4
- package/dist/hq/protocol/fleet.d.ts +20 -0
- package/dist/hq/protocol.js +10 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1512 -707
- package/dist/kernel/events/brain-events.d.ts +9 -0
- package/dist/kernel/events/provider-events.d.ts +42 -1
- package/dist/models/index.js +1 -1
- package/dist/plugin/api.d.ts +6 -0
- package/dist/plugin/config.d.ts +55 -0
- package/dist/plugin/index.d.ts +1 -1
- package/dist/plugin/index.js +134 -21
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.js +157 -42
- package/dist/security/permission-helpers.d.ts +23 -6
- package/dist/security/permission-policy.d.ts +16 -0
- package/dist/security/totp.d.ts +14 -0
- package/dist/storage/director-state.d.ts +7 -0
- package/dist/storage/index.js +33 -8
- package/dist/tools/fallback-system-config-view-tool.d.ts +1 -1
- package/dist/tools/index.js +388 -102
- package/dist/types/council.d.ts +11 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/multi-agent.d.ts +10 -0
- package/dist/types/one-shot-llm.d.ts +9 -0
- package/dist/types/plugin.d.ts +28 -0
- package/dist/worktree/index.js +4 -4
- package/instructions/system-lite.md +81 -3
- package/instructions/system-pro.md +275 -90
- package/instructions/system.md +228 -81
- package/package.json +3 -3
package/dist/defaults/index.js
CHANGED
|
@@ -295,7 +295,7 @@ var InMemoryAgentBridge = class {
|
|
|
295
295
|
});
|
|
296
296
|
}
|
|
297
297
|
this.inflightGuards.add(correlationId);
|
|
298
|
-
return new Promise((
|
|
298
|
+
return new Promise((resolve19, reject) => {
|
|
299
299
|
const timer = setTimeout(() => {
|
|
300
300
|
this.inflightGuards.delete(correlationId);
|
|
301
301
|
this.pendingRequests.delete(correlationId);
|
|
@@ -314,7 +314,7 @@ var InMemoryAgentBridge = class {
|
|
|
314
314
|
return;
|
|
315
315
|
}
|
|
316
316
|
this.pendingRequests.set(correlationId, {
|
|
317
|
-
resolve:
|
|
317
|
+
resolve: resolve19,
|
|
318
318
|
reject,
|
|
319
319
|
timer
|
|
320
320
|
});
|
|
@@ -663,13 +663,13 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
663
663
|
if (!bus?.hasListenerFor("budget.threshold_reached")) {
|
|
664
664
|
return Promise.resolve("stop");
|
|
665
665
|
}
|
|
666
|
-
return new Promise((
|
|
666
|
+
return new Promise((resolve19) => {
|
|
667
667
|
let resolved = false;
|
|
668
668
|
const respond = (d) => {
|
|
669
669
|
if (resolved) return;
|
|
670
670
|
resolved = true;
|
|
671
671
|
clearTimeout(fallback);
|
|
672
|
-
|
|
672
|
+
resolve19(d);
|
|
673
673
|
};
|
|
674
674
|
const fallback = setTimeout(() => respond("stop"), _SubagentBudget.DECISION_TIMEOUT_MS);
|
|
675
675
|
const sessionId = this.currentSessionId();
|
|
@@ -5306,7 +5306,7 @@ function createDelegateTool(opts) {
|
|
|
5306
5306
|
};
|
|
5307
5307
|
}
|
|
5308
5308
|
async function awaitDelegateAttempt(director, subagentId, taskId, timeoutMs, abortSignal) {
|
|
5309
|
-
return new Promise((
|
|
5309
|
+
return new Promise((resolve19) => {
|
|
5310
5310
|
let settled = false;
|
|
5311
5311
|
let timer;
|
|
5312
5312
|
let offAbort = () => {
|
|
@@ -5319,7 +5319,7 @@ async function awaitDelegateAttempt(director, subagentId, taskId, timeoutMs, abo
|
|
|
5319
5319
|
offIter();
|
|
5320
5320
|
offProgress();
|
|
5321
5321
|
offAbort();
|
|
5322
|
-
|
|
5322
|
+
resolve19(value);
|
|
5323
5323
|
};
|
|
5324
5324
|
const arm = () => {
|
|
5325
5325
|
if (timer) clearTimeout(timer);
|
|
@@ -5661,6 +5661,21 @@ var DirectorStateCheckpoint = class {
|
|
|
5661
5661
|
resume(snapshot) {
|
|
5662
5662
|
this.snapshot = snapshot;
|
|
5663
5663
|
}
|
|
5664
|
+
/**
|
|
5665
|
+
* After resume, pin the live spawn ceiling from the current profile/flag
|
|
5666
|
+
* while preserving `spawnCount` (cumulative used budget). Checkpoint
|
|
5667
|
+
* metadata previously stored a historical `maxSpawns` that can diverge
|
|
5668
|
+
* from the live runtime ceiling — operators need the live value to win.
|
|
5669
|
+
*/
|
|
5670
|
+
applyLiveMaxSpawns(maxSpawns) {
|
|
5671
|
+
if (this.snapshot.maxSpawns === maxSpawns) return;
|
|
5672
|
+
this.snapshot = {
|
|
5673
|
+
...this.snapshot,
|
|
5674
|
+
maxSpawns
|
|
5675
|
+
};
|
|
5676
|
+
this.bumpUpdatedAt();
|
|
5677
|
+
this.schedule();
|
|
5678
|
+
}
|
|
5664
5679
|
current() {
|
|
5665
5680
|
return this.snapshot;
|
|
5666
5681
|
}
|
|
@@ -7173,10 +7188,10 @@ var DirectorTaskRegistry = class _DirectorTaskRegistry {
|
|
|
7173
7188
|
pending: taskIds.filter((id) => !done.has(id))
|
|
7174
7189
|
});
|
|
7175
7190
|
}
|
|
7176
|
-
return new Promise((
|
|
7191
|
+
return new Promise((resolve19) => {
|
|
7177
7192
|
const entry = {
|
|
7178
7193
|
ids: new Set(taskIds),
|
|
7179
|
-
resolve: (result) =>
|
|
7194
|
+
resolve: (result) => resolve19({
|
|
7180
7195
|
completed: [result],
|
|
7181
7196
|
pending: taskIds.filter((id) => id !== result.taskId)
|
|
7182
7197
|
})
|
|
@@ -7184,7 +7199,7 @@ var DirectorTaskRegistry = class _DirectorTaskRegistry {
|
|
|
7184
7199
|
if (opts?.timeoutMs !== void 0) {
|
|
7185
7200
|
entry.timer = setTimeout(() => {
|
|
7186
7201
|
this.anyWaiters.delete(entry);
|
|
7187
|
-
|
|
7202
|
+
resolve19({ completed: [], pending: [...taskIds], timedOut: true });
|
|
7188
7203
|
}, opts.timeoutMs);
|
|
7189
7204
|
}
|
|
7190
7205
|
this.anyWaiters.add(entry);
|
|
@@ -7302,11 +7317,11 @@ ${JSON.stringify(result.result, null, 2)}
|
|
|
7302
7317
|
this.makeStoppedResult(taskId, "director", `Unknown task id "${taskId}" \u2014 never assigned`)
|
|
7303
7318
|
);
|
|
7304
7319
|
}
|
|
7305
|
-
let
|
|
7320
|
+
let resolve19;
|
|
7306
7321
|
const promise = new Promise((done) => {
|
|
7307
|
-
|
|
7322
|
+
resolve19 = done;
|
|
7308
7323
|
});
|
|
7309
|
-
this.taskWaiters.set(taskId, { promise, resolve:
|
|
7324
|
+
this.taskWaiters.set(taskId, { promise, resolve: resolve19 });
|
|
7310
7325
|
return promise;
|
|
7311
7326
|
}
|
|
7312
7327
|
recordAssignment(task) {
|
|
@@ -11060,7 +11075,7 @@ async function spawn(host, config, priceLookup) {
|
|
|
11060
11075
|
if (host.spawnDepth >= maxSpawnDepth) {
|
|
11061
11076
|
throw new FleetSpawnBudgetError("max_spawn_depth", maxSpawnDepth, host.spawnDepth);
|
|
11062
11077
|
}
|
|
11063
|
-
if (host.spawnCount >= host.maxSpawns) {
|
|
11078
|
+
if (host.spawnCount >= host.maxSpawns && !config.spawnBudgetExempt) {
|
|
11064
11079
|
throw new FleetSpawnBudgetError("max_spawns", host.maxSpawns, host.spawnCount + 1);
|
|
11065
11080
|
}
|
|
11066
11081
|
if (host.maxFleetCostUsd < Number.POSITIVE_INFINITY) {
|
|
@@ -11111,7 +11126,9 @@ async function spawn(host, config, priceLookup) {
|
|
|
11111
11126
|
...Number.isFinite(budget?.remainingSpawns ?? host.maxSpawns - host.spawnCount) ? {
|
|
11112
11127
|
remainingSpawns: Math.max(
|
|
11113
11128
|
0,
|
|
11114
|
-
|
|
11129
|
+
// Exempt spawns don't consume leader budget, so the reported
|
|
11130
|
+
// headroom is not decremented for them.
|
|
11131
|
+
(budget?.remainingSpawns ?? host.maxSpawns - host.spawnCount) - (config.spawnBudgetExempt ? 0 : 1)
|
|
11115
11132
|
)
|
|
11116
11133
|
} : {},
|
|
11117
11134
|
...Number.isFinite(maxFleetTokens) ? { maxTokens: maxFleetTokens } : {},
|
|
@@ -11124,7 +11141,9 @@ async function spawn(host, config, priceLookup) {
|
|
|
11124
11141
|
if (host.fleetManager) {
|
|
11125
11142
|
host.fleetManager.recordSpawn(result.subagentId, config, priceLookup);
|
|
11126
11143
|
} else {
|
|
11127
|
-
|
|
11144
|
+
if (!config.spawnBudgetExempt) {
|
|
11145
|
+
host.spawnCount += 1;
|
|
11146
|
+
}
|
|
11128
11147
|
host.subagentMeta.set(result.subagentId, {
|
|
11129
11148
|
provider: config.provider,
|
|
11130
11149
|
model: config.model
|
|
@@ -11476,12 +11495,12 @@ async function executeSubagentWithTimeout({
|
|
|
11476
11495
|
}
|
|
11477
11496
|
return new Promise((resolveDecision) => {
|
|
11478
11497
|
let settled = false;
|
|
11479
|
-
const
|
|
11498
|
+
const resolve19 = (d) => {
|
|
11480
11499
|
if (settled) return;
|
|
11481
11500
|
settled = true;
|
|
11482
11501
|
resolveDecision(d);
|
|
11483
11502
|
};
|
|
11484
|
-
const fallback = setTimeout(() =>
|
|
11503
|
+
const fallback = setTimeout(() => resolve19("stop"), DECISION_TIMEOUT_MS);
|
|
11485
11504
|
const sessionId = currentSessionId();
|
|
11486
11505
|
budget._events?.emit("budget.threshold_reached", {
|
|
11487
11506
|
...sessionId ? { sessionId } : {},
|
|
@@ -11491,11 +11510,11 @@ async function executeSubagentWithTimeout({
|
|
|
11491
11510
|
timeoutMs: DECISION_TIMEOUT_MS,
|
|
11492
11511
|
extend: (extra) => {
|
|
11493
11512
|
clearTimeout(fallback);
|
|
11494
|
-
queueMicrotask(() =>
|
|
11513
|
+
queueMicrotask(() => resolve19({ extend: extra }));
|
|
11495
11514
|
},
|
|
11496
11515
|
deny: () => {
|
|
11497
11516
|
clearTimeout(fallback);
|
|
11498
|
-
|
|
11517
|
+
resolve19("stop");
|
|
11499
11518
|
}
|
|
11500
11519
|
});
|
|
11501
11520
|
});
|
|
@@ -11882,7 +11901,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
11882
11901
|
taskIds.map((id) => {
|
|
11883
11902
|
const cached = this.completedResults.find((r) => r.taskId === id);
|
|
11884
11903
|
if (cached) return cached;
|
|
11885
|
-
return new Promise((
|
|
11904
|
+
return new Promise((resolve19, reject) => {
|
|
11886
11905
|
const timeout = setTimeout(() => {
|
|
11887
11906
|
this.off("task.completed", handler);
|
|
11888
11907
|
reject(new Error(`awaitTasks timed out waiting for task "${id}"`));
|
|
@@ -11891,7 +11910,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
11891
11910
|
if (result.taskId === id) {
|
|
11892
11911
|
clearTimeout(timeout);
|
|
11893
11912
|
this.off("task.completed", handler);
|
|
11894
|
-
|
|
11913
|
+
resolve19(result);
|
|
11895
11914
|
}
|
|
11896
11915
|
};
|
|
11897
11916
|
this.on("task.completed", handler);
|
|
@@ -11916,13 +11935,13 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
11916
11935
|
const done = new Set(completed.map((r) => r.taskId));
|
|
11917
11936
|
return { completed, pending: taskIds.filter((id) => !done.has(id)) };
|
|
11918
11937
|
}
|
|
11919
|
-
return new Promise((
|
|
11938
|
+
return new Promise((resolve19) => {
|
|
11920
11939
|
let timer;
|
|
11921
11940
|
const handler = ({ result }) => {
|
|
11922
11941
|
if (!ids.has(result.taskId)) return;
|
|
11923
11942
|
if (timer) clearTimeout(timer);
|
|
11924
11943
|
this.off("task.completed", handler);
|
|
11925
|
-
|
|
11944
|
+
resolve19({
|
|
11926
11945
|
completed: [result],
|
|
11927
11946
|
pending: taskIds.filter((id) => id !== result.taskId)
|
|
11928
11947
|
});
|
|
@@ -11930,7 +11949,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
11930
11949
|
if (opts?.timeoutMs !== void 0) {
|
|
11931
11950
|
timer = setTimeout(() => {
|
|
11932
11951
|
this.off("task.completed", handler);
|
|
11933
|
-
|
|
11952
|
+
resolve19({ completed: [], pending: [...taskIds], timedOut: true });
|
|
11934
11953
|
}, opts.timeoutMs);
|
|
11935
11954
|
}
|
|
11936
11955
|
this.on("task.completed", handler);
|
|
@@ -12049,8 +12068,17 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
12049
12068
|
durationMs: 0
|
|
12050
12069
|
};
|
|
12051
12070
|
this.completedResults.push(synthetic);
|
|
12071
|
+
this.trimCompletedResults();
|
|
12052
12072
|
this.emit("task.completed", { task, result: synthetic });
|
|
12053
12073
|
}
|
|
12074
|
+
trimCompletedResults() {
|
|
12075
|
+
if (this.completedResults.length > _DefaultMultiAgentCoordinator.MAX_COMPLETED_RESULTS) {
|
|
12076
|
+
this.completedResults.splice(
|
|
12077
|
+
0,
|
|
12078
|
+
this.completedResults.length - _DefaultMultiAgentCoordinator.MAX_COMPLETED_RESULTS
|
|
12079
|
+
);
|
|
12080
|
+
}
|
|
12081
|
+
}
|
|
12054
12082
|
async runDispatched(subagentId, task) {
|
|
12055
12083
|
const subagent = this.subagents.get(subagentId);
|
|
12056
12084
|
if (!subagent) return;
|
|
@@ -12184,12 +12212,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
12184
12212
|
}
|
|
12185
12213
|
recordCompletion(result) {
|
|
12186
12214
|
this.completedResults.push(result);
|
|
12187
|
-
|
|
12188
|
-
this.completedResults.splice(
|
|
12189
|
-
0,
|
|
12190
|
-
this.completedResults.length - _DefaultMultiAgentCoordinator.MAX_COMPLETED_RESULTS
|
|
12191
|
-
);
|
|
12192
|
-
}
|
|
12215
|
+
this.trimCompletedResults();
|
|
12193
12216
|
this.totalIterations += result.iterations;
|
|
12194
12217
|
if (this.inFlight > 0) {
|
|
12195
12218
|
this.inFlight--;
|
|
@@ -13607,10 +13630,10 @@ function validateAgainstSchema(value, schema) {
|
|
|
13607
13630
|
return { ok: errors.length === 0, errors };
|
|
13608
13631
|
}
|
|
13609
13632
|
var MAX_SCHEMA_DEPTH = 64;
|
|
13610
|
-
function walk(value, schema,
|
|
13633
|
+
function walk(value, schema, path42, errors, depth) {
|
|
13611
13634
|
if (depth > MAX_SCHEMA_DEPTH) {
|
|
13612
13635
|
errors.push({
|
|
13613
|
-
path:
|
|
13636
|
+
path: path42 || "<root>",
|
|
13614
13637
|
message: `schema nesting exceeds maximum depth (${MAX_SCHEMA_DEPTH})`
|
|
13615
13638
|
});
|
|
13616
13639
|
return;
|
|
@@ -13618,7 +13641,7 @@ function walk(value, schema, path40, errors, depth) {
|
|
|
13618
13641
|
if (schema.enum !== void 0) {
|
|
13619
13642
|
if (!enumIncludes(schema.enum, value)) {
|
|
13620
13643
|
errors.push({
|
|
13621
|
-
path:
|
|
13644
|
+
path: path42 || "<root>",
|
|
13622
13645
|
message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`
|
|
13623
13646
|
});
|
|
13624
13647
|
return;
|
|
@@ -13627,7 +13650,7 @@ function walk(value, schema, path40, errors, depth) {
|
|
|
13627
13650
|
if (typeof schema.type === "string") {
|
|
13628
13651
|
if (!checkType(value, schema.type)) {
|
|
13629
13652
|
errors.push({
|
|
13630
|
-
path:
|
|
13653
|
+
path: path42 || "<root>",
|
|
13631
13654
|
message: `expected ${schema.type}, got ${describeType(value)} (${previewValue(value)})`
|
|
13632
13655
|
});
|
|
13633
13656
|
return;
|
|
@@ -13639,7 +13662,7 @@ function walk(value, schema, path40, errors, depth) {
|
|
|
13639
13662
|
if (!(req in obj)) {
|
|
13640
13663
|
const expected = schema.properties?.[req]?.type;
|
|
13641
13664
|
errors.push({
|
|
13642
|
-
path: joinPath(
|
|
13665
|
+
path: joinPath(path42, req),
|
|
13643
13666
|
message: `required property missing${typeof expected === "string" ? ` (expected ${expected})` : ""}`
|
|
13644
13667
|
});
|
|
13645
13668
|
}
|
|
@@ -13647,14 +13670,14 @@ function walk(value, schema, path40, errors, depth) {
|
|
|
13647
13670
|
if (schema.properties) {
|
|
13648
13671
|
for (const [key, subSchema] of Object.entries(schema.properties)) {
|
|
13649
13672
|
if (key in obj) {
|
|
13650
|
-
walk(obj[key], subSchema, joinPath(
|
|
13673
|
+
walk(obj[key], subSchema, joinPath(path42, key), errors, depth + 1);
|
|
13651
13674
|
}
|
|
13652
13675
|
}
|
|
13653
13676
|
}
|
|
13654
13677
|
}
|
|
13655
13678
|
if (schema.type === "array" && Array.isArray(value) && schema.items) {
|
|
13656
13679
|
for (let i = 0; i < value.length; i++) {
|
|
13657
|
-
walk(value[i], schema.items, `${
|
|
13680
|
+
walk(value[i], schema.items, `${path42}[${i}]`, errors, depth + 1);
|
|
13658
13681
|
}
|
|
13659
13682
|
}
|
|
13660
13683
|
}
|
|
@@ -13950,7 +13973,7 @@ function invalid(sessionId) {
|
|
|
13950
13973
|
|
|
13951
13974
|
// src/utils/sleep.ts
|
|
13952
13975
|
function sleep(ms) {
|
|
13953
|
-
return new Promise((
|
|
13976
|
+
return new Promise((resolve19) => setTimeout(resolve19, ms));
|
|
13954
13977
|
}
|
|
13955
13978
|
|
|
13956
13979
|
// src/utils/slug.ts
|
|
@@ -16221,7 +16244,7 @@ var SessionCheckpointCas = class {
|
|
|
16221
16244
|
}
|
|
16222
16245
|
};
|
|
16223
16246
|
function defaultRunGit(args, cwd) {
|
|
16224
|
-
return new Promise((
|
|
16247
|
+
return new Promise((resolve19) => {
|
|
16225
16248
|
const stdoutChunks = [];
|
|
16226
16249
|
const stderrChunks = [];
|
|
16227
16250
|
let stdoutBytes = 0;
|
|
@@ -16264,8 +16287,8 @@ function defaultRunGit(args, cwd) {
|
|
|
16264
16287
|
stdoutTruncated,
|
|
16265
16288
|
stderrTruncated
|
|
16266
16289
|
});
|
|
16267
|
-
child.on("error", (err) =>
|
|
16268
|
-
child.on("close", (code) =>
|
|
16290
|
+
child.on("error", (err) => resolve19(result(1, err.message)));
|
|
16291
|
+
child.on("close", (code) => resolve19(result(code ?? 1)));
|
|
16269
16292
|
});
|
|
16270
16293
|
}
|
|
16271
16294
|
|
|
@@ -18905,6 +18928,7 @@ var Director = class _Director {
|
|
|
18905
18928
|
}
|
|
18906
18929
|
setCheckpointState(snapshot) {
|
|
18907
18930
|
setCheckpointState(this.checkpointHost(), snapshot);
|
|
18931
|
+
this.applyResumeBudget(snapshot);
|
|
18908
18932
|
}
|
|
18909
18933
|
async readSession(subagentId, tail) {
|
|
18910
18934
|
return readDirectorSubagentSession({
|
|
@@ -18956,6 +18980,22 @@ var Director = class _Director {
|
|
|
18956
18980
|
}
|
|
18957
18981
|
resumeFromCheckpoint(snapshot) {
|
|
18958
18982
|
resumeFromCheckpoint(this.checkpointHost(), snapshot);
|
|
18983
|
+
this.applyResumeBudget(snapshot);
|
|
18984
|
+
}
|
|
18985
|
+
/**
|
|
18986
|
+
* After re-attaching checkpoint metadata, pin the live maxSpawns ceiling
|
|
18987
|
+
* (profile/flag/env wins over historical checkpoint metadata). The
|
|
18988
|
+
* historical cumulative spawn counter is deliberately NOT restored — the
|
|
18989
|
+
* lifetime budget is scoped to this director run, so a restarted session
|
|
18990
|
+
* resumes with a fresh budget rather than a possibly-exhausted counter.
|
|
18991
|
+
*/
|
|
18992
|
+
applyResumeBudget(snapshot) {
|
|
18993
|
+
if (this.fleetManager) {
|
|
18994
|
+
this.fleetManager.restoreFromCheckpoint(snapshot);
|
|
18995
|
+
}
|
|
18996
|
+
this.stateCheckpoint?.applyLiveMaxSpawns(
|
|
18997
|
+
Number.isFinite(this.maxSpawns) ? this.maxSpawns : void 0
|
|
18998
|
+
);
|
|
18959
18999
|
}
|
|
18960
19000
|
};
|
|
18961
19001
|
|
|
@@ -21623,12 +21663,12 @@ function verifyFiles(tokens, files) {
|
|
|
21623
21663
|
const violations = [];
|
|
21624
21664
|
let onPalette = 0;
|
|
21625
21665
|
let offPalette = 0;
|
|
21626
|
-
for (const { path:
|
|
21666
|
+
for (const { path: path42, text } of files) {
|
|
21627
21667
|
const lines = text.split("\n");
|
|
21628
21668
|
lines.forEach((lineText, i) => {
|
|
21629
21669
|
const lineNo = i + 1;
|
|
21630
21670
|
const flag = (snippet, reason, axis = "color") => {
|
|
21631
|
-
violations.push({ file:
|
|
21671
|
+
violations.push({ file: path42, line: lineNo, snippet: snippet.slice(0, 80), reason, axis });
|
|
21632
21672
|
};
|
|
21633
21673
|
for (const re of [HEX_RE, FUNC_COLOR_RE]) {
|
|
21634
21674
|
re.lastIndex = 0;
|
|
@@ -22311,9 +22351,9 @@ function buildRecoveryStrategies(opts) {
|
|
|
22311
22351
|
const delayMs = err.body?.retryAfterMs ?? 5e3;
|
|
22312
22352
|
const delay = Math.min(6e4, Math.max(1e3, delayMs));
|
|
22313
22353
|
if (ctx?.signal) {
|
|
22314
|
-
await new Promise((
|
|
22354
|
+
await new Promise((resolve19) => {
|
|
22315
22355
|
if (ctx.signal.aborted) {
|
|
22316
|
-
|
|
22356
|
+
resolve19();
|
|
22317
22357
|
return;
|
|
22318
22358
|
}
|
|
22319
22359
|
let settled = false;
|
|
@@ -22324,7 +22364,7 @@ function buildRecoveryStrategies(opts) {
|
|
|
22324
22364
|
settled = true;
|
|
22325
22365
|
if (timer !== void 0) clearTimeout(timer);
|
|
22326
22366
|
ctx.signal.removeEventListener("abort", onAbort);
|
|
22327
|
-
|
|
22367
|
+
resolve19();
|
|
22328
22368
|
};
|
|
22329
22369
|
timer = setTimeout(finish, delay);
|
|
22330
22370
|
ctx.signal.addEventListener("abort", onAbort, { once: true });
|
|
@@ -24517,8 +24557,8 @@ async function streamProviderToResponse(provider, req, signal, ctx, events, logg
|
|
|
24517
24557
|
});
|
|
24518
24558
|
await Promise.race([
|
|
24519
24559
|
drainPromise,
|
|
24520
|
-
new Promise((
|
|
24521
|
-
drainTimer = setTimeout(
|
|
24560
|
+
new Promise((resolve19) => {
|
|
24561
|
+
drainTimer = setTimeout(resolve19, STREAM_DRAIN_TIMEOUT_MS);
|
|
24522
24562
|
})
|
|
24523
24563
|
]);
|
|
24524
24564
|
} finally {
|
|
@@ -24869,7 +24909,7 @@ async function runProviderWithRetry(opts) {
|
|
|
24869
24909
|
description,
|
|
24870
24910
|
...providerErrorBody ? { errorBody: providerErrorBody } : {}
|
|
24871
24911
|
});
|
|
24872
|
-
await new Promise((
|
|
24912
|
+
await new Promise((resolve19, reject) => {
|
|
24873
24913
|
let settled = false;
|
|
24874
24914
|
const cleanup = () => {
|
|
24875
24915
|
clearTimeout(t);
|
|
@@ -24885,7 +24925,7 @@ async function runProviderWithRetry(opts) {
|
|
|
24885
24925
|
if (settled) return;
|
|
24886
24926
|
settled = true;
|
|
24887
24927
|
cleanup();
|
|
24888
|
-
|
|
24928
|
+
resolve19();
|
|
24889
24929
|
}, delay);
|
|
24890
24930
|
if (signal.aborted) {
|
|
24891
24931
|
onAbort();
|
|
@@ -27147,18 +27187,18 @@ ${errorDetails}`,
|
|
|
27147
27187
|
if (this.opts.confirmAwaiter) {
|
|
27148
27188
|
const awaiter = this.opts.confirmAwaiter;
|
|
27149
27189
|
const choice = await new Promise(
|
|
27150
|
-
(
|
|
27190
|
+
(resolve19, reject) => {
|
|
27151
27191
|
const signal = ctx.signal;
|
|
27152
|
-
const onAbort = () =>
|
|
27192
|
+
const onAbort = () => resolve19("abort");
|
|
27153
27193
|
if (signal.aborted) {
|
|
27154
|
-
|
|
27194
|
+
resolve19("abort");
|
|
27155
27195
|
return;
|
|
27156
27196
|
}
|
|
27157
27197
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
27158
27198
|
awaiter(tool, use.input, use.id, suggestedPattern).then(
|
|
27159
27199
|
(c) => {
|
|
27160
27200
|
signal.removeEventListener("abort", onAbort);
|
|
27161
|
-
|
|
27201
|
+
resolve19(c);
|
|
27162
27202
|
},
|
|
27163
27203
|
(e) => {
|
|
27164
27204
|
signal.removeEventListener("abort", onAbort);
|
|
@@ -27496,7 +27536,7 @@ ${post.additionalContext}`;
|
|
|
27496
27536
|
toolPromise.catch(() => {
|
|
27497
27537
|
});
|
|
27498
27538
|
try {
|
|
27499
|
-
output = await new Promise((
|
|
27539
|
+
output = await new Promise((resolve19, reject) => {
|
|
27500
27540
|
const onAbort = () => {
|
|
27501
27541
|
setTimeout(() => reject(abortReasonToError(combined.reason)), 0);
|
|
27502
27542
|
};
|
|
@@ -27504,7 +27544,7 @@ ${post.additionalContext}`;
|
|
|
27504
27544
|
toolPromise.then(
|
|
27505
27545
|
(v) => {
|
|
27506
27546
|
combined.removeEventListener("abort", onAbort);
|
|
27507
|
-
|
|
27547
|
+
resolve19(v);
|
|
27508
27548
|
},
|
|
27509
27549
|
(e) => {
|
|
27510
27550
|
combined.removeEventListener("abort", onAbort);
|
|
@@ -28452,7 +28492,7 @@ var DefaultModelsRegistry = class {
|
|
|
28452
28492
|
async load(opts = {}) {
|
|
28453
28493
|
if (this.payload && !opts.force) return this.payload;
|
|
28454
28494
|
if (this.seed) {
|
|
28455
|
-
this.payload = this.seed;
|
|
28495
|
+
this.payload = this.withExtraOverlay(this.seed);
|
|
28456
28496
|
this.fetchedAt = /* @__PURE__ */ new Date();
|
|
28457
28497
|
return this.payload;
|
|
28458
28498
|
}
|
|
@@ -29072,9 +29112,9 @@ var DefaultHealthRegistry = class {
|
|
|
29072
29112
|
}
|
|
29073
29113
|
async runOne(check) {
|
|
29074
29114
|
let timer = null;
|
|
29075
|
-
const timeout = new Promise((
|
|
29115
|
+
const timeout = new Promise((resolve19) => {
|
|
29076
29116
|
timer = setTimeout(
|
|
29077
|
-
() =>
|
|
29117
|
+
() => resolve19({ status: "unhealthy", detail: `timeout after ${this.timeoutMs}ms` }),
|
|
29078
29118
|
this.timeoutMs
|
|
29079
29119
|
);
|
|
29080
29120
|
});
|
|
@@ -29272,7 +29312,7 @@ async function startMetricsServer(opts) {
|
|
|
29272
29312
|
const tls = opts.tls;
|
|
29273
29313
|
const useHttps = !!(tls?.cert && tls?.key);
|
|
29274
29314
|
const host = opts.host ?? "127.0.0.1";
|
|
29275
|
-
const
|
|
29315
|
+
const path42 = opts.path ?? "/metrics";
|
|
29276
29316
|
const healthPath = opts.healthPath ?? "/healthz";
|
|
29277
29317
|
const healthRegistry = opts.healthRegistry;
|
|
29278
29318
|
const token = opts.token;
|
|
@@ -29295,7 +29335,7 @@ async function startMetricsServer(opts) {
|
|
|
29295
29335
|
return;
|
|
29296
29336
|
}
|
|
29297
29337
|
const url = req.url.split("?")[0];
|
|
29298
|
-
if (url ===
|
|
29338
|
+
if (url === path42) {
|
|
29299
29339
|
let body;
|
|
29300
29340
|
try {
|
|
29301
29341
|
body = renderPrometheus(opts.sink.snapshot());
|
|
@@ -29341,14 +29381,14 @@ async function startMetricsServer(opts) {
|
|
|
29341
29381
|
const { createServer } = await import("node:http");
|
|
29342
29382
|
server = createServer(listener);
|
|
29343
29383
|
}
|
|
29344
|
-
await new Promise((
|
|
29384
|
+
await new Promise((resolve19, reject) => {
|
|
29345
29385
|
const onError = (err) => {
|
|
29346
29386
|
server.off("listening", onListening);
|
|
29347
29387
|
reject(err);
|
|
29348
29388
|
};
|
|
29349
29389
|
const onListening = () => {
|
|
29350
29390
|
server.off("error", onError);
|
|
29351
|
-
|
|
29391
|
+
resolve19();
|
|
29352
29392
|
};
|
|
29353
29393
|
server.once("error", onError);
|
|
29354
29394
|
server.once("listening", onListening);
|
|
@@ -29359,9 +29399,9 @@ async function startMetricsServer(opts) {
|
|
|
29359
29399
|
const protocol = useHttps ? "https" : "http";
|
|
29360
29400
|
return {
|
|
29361
29401
|
port: boundPort,
|
|
29362
|
-
url: `${protocol}://${host}:${boundPort}${
|
|
29363
|
-
close: () => new Promise((
|
|
29364
|
-
server.close((err) => err ? reject(err) :
|
|
29402
|
+
url: `${protocol}://${host}:${boundPort}${path42}`,
|
|
29403
|
+
close: () => new Promise((resolve19, reject) => {
|
|
29404
|
+
server.close((err) => err ? reject(err) : resolve19());
|
|
29365
29405
|
})
|
|
29366
29406
|
};
|
|
29367
29407
|
}
|
|
@@ -29632,6 +29672,7 @@ function startOtlpTraceExporter(opts) {
|
|
|
29632
29672
|
|
|
29633
29673
|
// src/security/permission-policy.ts
|
|
29634
29674
|
import * as fs12 from "node:fs/promises";
|
|
29675
|
+
import * as path36 from "node:path";
|
|
29635
29676
|
|
|
29636
29677
|
// src/security/permission-policy-schema.ts
|
|
29637
29678
|
var TRUST_POLICY_LIMITS = Object.freeze({
|
|
@@ -29676,19 +29717,19 @@ var UNSAFE_PROPERTY_NAMES = /* @__PURE__ */ new Set(["__proto__", "prototype", "
|
|
|
29676
29717
|
function isRecord5(value) {
|
|
29677
29718
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
29678
29719
|
}
|
|
29679
|
-
function error(diagnostics, code,
|
|
29680
|
-
diagnostics.push({ severity: "error", code, path:
|
|
29720
|
+
function error(diagnostics, code, path42, message) {
|
|
29721
|
+
diagnostics.push({ severity: "error", code, path: path42, message });
|
|
29681
29722
|
}
|
|
29682
|
-
function validatePatterns(value,
|
|
29723
|
+
function validatePatterns(value, path42, diagnostics) {
|
|
29683
29724
|
if (!Array.isArray(value)) {
|
|
29684
|
-
error(diagnostics, "invalid_pattern_list",
|
|
29725
|
+
error(diagnostics, "invalid_pattern_list", path42, "must be an array of strings");
|
|
29685
29726
|
return void 0;
|
|
29686
29727
|
}
|
|
29687
29728
|
if (value.length > TRUST_POLICY_LIMITS.maxPatternsPerRule) {
|
|
29688
29729
|
error(
|
|
29689
29730
|
diagnostics,
|
|
29690
29731
|
"too_many_patterns",
|
|
29691
|
-
|
|
29732
|
+
path42,
|
|
29692
29733
|
`must contain at most ${TRUST_POLICY_LIMITS.maxPatternsPerRule} patterns`
|
|
29693
29734
|
);
|
|
29694
29735
|
return void 0;
|
|
@@ -29696,7 +29737,7 @@ function validatePatterns(value, path40, diagnostics) {
|
|
|
29696
29737
|
const patterns = [];
|
|
29697
29738
|
const seen = /* @__PURE__ */ new Set();
|
|
29698
29739
|
for (const [index, pattern] of value.entries()) {
|
|
29699
|
-
const itemPath = `${
|
|
29740
|
+
const itemPath = `${path42}[${index}]`;
|
|
29700
29741
|
if (typeof pattern !== "string" || pattern.length === 0 || pattern.length > TRUST_POLICY_LIMITS.maxPatternChars) {
|
|
29701
29742
|
error(
|
|
29702
29743
|
diagnostics,
|
|
@@ -30111,6 +30152,8 @@ var AutoApprovePermissionPolicy = class _AutoApprovePermissionPolicy {
|
|
|
30111
30152
|
};
|
|
30112
30153
|
|
|
30113
30154
|
// src/security/permission-helpers.ts
|
|
30155
|
+
import { realpathSync } from "node:fs";
|
|
30156
|
+
import * as path35 from "node:path";
|
|
30114
30157
|
function matchesTrust(patterns, subject) {
|
|
30115
30158
|
return patterns.includes(subject) || matchAny(patterns, subject);
|
|
30116
30159
|
}
|
|
@@ -30181,9 +30224,51 @@ var SHELL_READ_VERBS = /* @__PURE__ */ new Set([
|
|
|
30181
30224
|
function stripShellQuotes(value) {
|
|
30182
30225
|
return value.replace(/^['"]|['"]$/g, "");
|
|
30183
30226
|
}
|
|
30227
|
+
var AGENT_STATE_SENSITIVE_BASENAMES = /^(?:config\.json|config\.local\.json|trust\.json|auth\.json|\.key)$/i;
|
|
30228
|
+
function unescapeGlobSubject(value) {
|
|
30229
|
+
return value.replace(/\\([*?[\]])/g, "$1");
|
|
30230
|
+
}
|
|
30231
|
+
function normalizeForCompare(value) {
|
|
30232
|
+
const forward = unescapeGlobSubject(value).replace(/\\/g, "/").replace(/\/+$/, "");
|
|
30233
|
+
return process.platform === "win32" ? forward.toLowerCase() : forward;
|
|
30234
|
+
}
|
|
30235
|
+
function realpathOfNearestExisting(p) {
|
|
30236
|
+
let probe = p;
|
|
30237
|
+
const tail = [];
|
|
30238
|
+
for (; ; ) {
|
|
30239
|
+
try {
|
|
30240
|
+
return tail.length === 0 ? realpathSync(probe) : path35.join(realpathSync(probe), ...tail);
|
|
30241
|
+
} catch {
|
|
30242
|
+
const parent = path35.dirname(probe);
|
|
30243
|
+
if (parent === probe) return p;
|
|
30244
|
+
tail.unshift(path35.basename(probe));
|
|
30245
|
+
probe = parent;
|
|
30246
|
+
}
|
|
30247
|
+
}
|
|
30248
|
+
}
|
|
30249
|
+
var agentStateRootRealCache = /* @__PURE__ */ new Map();
|
|
30250
|
+
function isInsideAgentStateRoot(absPath) {
|
|
30251
|
+
const lexicalRoot = normalizeForCompare(path35.resolve(wstackGlobalRoot()));
|
|
30252
|
+
if (!lexicalRoot) return false;
|
|
30253
|
+
const target = normalizeForCompare(absPath);
|
|
30254
|
+
if (target === lexicalRoot || target.startsWith(`${lexicalRoot}/`)) return true;
|
|
30255
|
+
let realRoot = agentStateRootRealCache.get(lexicalRoot);
|
|
30256
|
+
if (realRoot === void 0) {
|
|
30257
|
+
realRoot = normalizeForCompare(realpathOfNearestExisting(path35.resolve(wstackGlobalRoot())));
|
|
30258
|
+
agentStateRootRealCache.set(lexicalRoot, realRoot);
|
|
30259
|
+
}
|
|
30260
|
+
if (!realRoot || realRoot === lexicalRoot) return false;
|
|
30261
|
+
const realTarget = normalizeForCompare(realpathOfNearestExisting(absPath));
|
|
30262
|
+
return realTarget === realRoot || realTarget.startsWith(`${realRoot}/`);
|
|
30263
|
+
}
|
|
30264
|
+
function isProtectedAgentStatePath(absPath) {
|
|
30265
|
+
if (!isInsideAgentStateRoot(absPath)) return false;
|
|
30266
|
+
return AGENT_STATE_SENSITIVE_BASENAMES.test(path35.basename(normalizeForCompare(absPath)));
|
|
30267
|
+
}
|
|
30184
30268
|
function pathLooksSensitive(rawPath) {
|
|
30185
30269
|
const normalized = stripShellQuotes(rawPath).replace(/\\/g, "/");
|
|
30186
|
-
|
|
30270
|
+
if (SENSITIVE_READ_PATHS.some((pattern) => pattern.test(normalized))) return true;
|
|
30271
|
+
return isProtectedAgentStatePath(normalized);
|
|
30187
30272
|
}
|
|
30188
30273
|
function inputPathLooksSensitive(input) {
|
|
30189
30274
|
if (!input || typeof input !== "object") return false;
|
|
@@ -30207,6 +30292,34 @@ function shellCommandReadsSensitivePath(command) {
|
|
|
30207
30292
|
}
|
|
30208
30293
|
|
|
30209
30294
|
// src/security/permission-policy.ts
|
|
30295
|
+
function fsWriteTargetPaths(input) {
|
|
30296
|
+
const out = [];
|
|
30297
|
+
if (!input || typeof input !== "object") return out;
|
|
30298
|
+
const obj = input;
|
|
30299
|
+
for (const key of [
|
|
30300
|
+
"path",
|
|
30301
|
+
"file_path",
|
|
30302
|
+
"file",
|
|
30303
|
+
"filePath",
|
|
30304
|
+
"files",
|
|
30305
|
+
"target",
|
|
30306
|
+
"targetPath",
|
|
30307
|
+
"out",
|
|
30308
|
+
"directory",
|
|
30309
|
+
"cwd",
|
|
30310
|
+
"template"
|
|
30311
|
+
]) {
|
|
30312
|
+
const value = obj[key];
|
|
30313
|
+
if (typeof value === "string") {
|
|
30314
|
+
if (value.length > 0) out.push(value);
|
|
30315
|
+
} else if (Array.isArray(value)) {
|
|
30316
|
+
for (const item of value) {
|
|
30317
|
+
if (typeof item === "string" && item.length > 0) out.push(item);
|
|
30318
|
+
}
|
|
30319
|
+
}
|
|
30320
|
+
}
|
|
30321
|
+
return out;
|
|
30322
|
+
}
|
|
30210
30323
|
var DefaultPermissionPolicy = class {
|
|
30211
30324
|
policy = {};
|
|
30212
30325
|
loaded = false;
|
|
@@ -30292,6 +30405,30 @@ var DefaultPermissionPolicy = class {
|
|
|
30292
30405
|
getYoloDestructive() {
|
|
30293
30406
|
return this.yoloDestructive;
|
|
30294
30407
|
}
|
|
30408
|
+
/**
|
|
30409
|
+
* True when this call is an FS_WRITE whose target lands inside WrongStack's
|
|
30410
|
+
* own state root.
|
|
30411
|
+
*
|
|
30412
|
+
* FS_WRITE tools disagree on where the target path lives: write/edit use
|
|
30413
|
+
* `path`, replace/format/git `files` (string OR array), patch `directory`,
|
|
30414
|
+
* design `out`, scaffold writes under `cwd`/`template`. Checking only
|
|
30415
|
+
* `path`/`file_path` let a state-root write merely switch tools, so every
|
|
30416
|
+
* path-bearing key is inspected.
|
|
30417
|
+
*
|
|
30418
|
+
* Shared by the YOLO carve-out and the eval-cache guard so the two cannot
|
|
30419
|
+
* drift: the carve-out scans all path keys while the cache key fingerprints
|
|
30420
|
+
* only the subject key, so the cache must consult the same predicate or a
|
|
30421
|
+
* secondary state-root key can be replayed a cached `auto`.
|
|
30422
|
+
*/
|
|
30423
|
+
hasAgentStateWriteTarget(tool, input, ctx) {
|
|
30424
|
+
if (!hasCapability(tool, ToolCapabilities.FS_WRITE)) return false;
|
|
30425
|
+
for (const targetPath of fsWriteTargetPaths(input)) {
|
|
30426
|
+
const base = ctx.workingDir ?? ctx.cwd;
|
|
30427
|
+
const resolved = base ? path36.resolve(base, targetPath) : path36.resolve(targetPath);
|
|
30428
|
+
if (isInsideAgentStateRoot(resolved)) return true;
|
|
30429
|
+
}
|
|
30430
|
+
return false;
|
|
30431
|
+
}
|
|
30295
30432
|
/**
|
|
30296
30433
|
* True when YOLO is on but this specific call is a destructive shell command
|
|
30297
30434
|
* the user has not opted to auto-approve. Shared by `evaluate()` and the
|
|
@@ -30299,6 +30436,7 @@ var DefaultPermissionPolicy = class {
|
|
|
30299
30436
|
*/
|
|
30300
30437
|
yoloBlockedAsDestructive(tool, input, ctx) {
|
|
30301
30438
|
if (!this.yolo || this.yoloDestructive) return false;
|
|
30439
|
+
if (this.hasAgentStateWriteTarget(tool, input, ctx)) return true;
|
|
30302
30440
|
const isShellSurface = tool.name === "bash" || tool.name === "exec" || (tool.capabilities ?? []).includes("shell.arbitrary");
|
|
30303
30441
|
if (!isShellSurface) return false;
|
|
30304
30442
|
const command = getInputString(input, "command") ?? shellCommandLineFromInput(input);
|
|
@@ -30405,7 +30543,7 @@ var DefaultPermissionPolicy = class {
|
|
|
30405
30543
|
const subject = subjectForToolInput(tool.name, input, tool.subjectKey);
|
|
30406
30544
|
const cacheKey = `${tool.name}::${subject ?? tool.name}`;
|
|
30407
30545
|
const evalKey = `${cacheKey}::${permissionFingerprint(tool)}`;
|
|
30408
|
-
if (tool.name !== "write") {
|
|
30546
|
+
if (tool.name !== "write" && !this.hasAgentStateWriteTarget(tool, input, ctx)) {
|
|
30409
30547
|
const cached = this._evalCache.get(evalKey);
|
|
30410
30548
|
if (cached !== void 0) return cached;
|
|
30411
30549
|
}
|
|
@@ -30513,7 +30651,7 @@ var DefaultPermissionPolicy = class {
|
|
|
30513
30651
|
return decision;
|
|
30514
30652
|
}
|
|
30515
30653
|
if (tool.name === "write" && subject) {
|
|
30516
|
-
if (ctx.hasRead(subject)) {
|
|
30654
|
+
if (ctx.hasRead(subject) && !isInsideAgentStateRoot(subject)) {
|
|
30517
30655
|
return {
|
|
30518
30656
|
permission: "auto",
|
|
30519
30657
|
source: "context",
|
|
@@ -30863,13 +31001,14 @@ var DefaultPermissionPolicy = class {
|
|
|
30863
31001
|
}
|
|
30864
31002
|
add("yolo", false, "auto", "yolo", "YOLO mode is not active");
|
|
30865
31003
|
if (tool.name === "write" && subject) {
|
|
30866
|
-
const
|
|
31004
|
+
const isAgentState = isInsideAgentStateRoot(subject);
|
|
31005
|
+
const hasRead = ctx.hasRead(subject) && !isAgentState;
|
|
30867
31006
|
add(
|
|
30868
31007
|
"write smart bypass",
|
|
30869
31008
|
hasRead,
|
|
30870
31009
|
"auto",
|
|
30871
31010
|
"context",
|
|
30872
|
-
hasRead ? `file "${subject}" was already read in this session \u2014 auto-approving write` : `file "${subject}" was not read in this session \u2014 bypass does not apply`
|
|
31011
|
+
isAgentState ? `file "${subject}" is WrongStack's own state \u2014 bypass never applies, write always confirms` : hasRead ? `file "${subject}" was already read in this session \u2014 auto-approving write` : `file "${subject}" was not read in this session \u2014 bypass does not apply`
|
|
30873
31012
|
);
|
|
30874
31013
|
if (hasRead) {
|
|
30875
31014
|
winnerIndex = steps.length - 1;
|
|
@@ -30954,7 +31093,7 @@ var DefaultPermissionPolicy = class {
|
|
|
30954
31093
|
import { createCipheriv, createDecipheriv, randomBytes as randomBytes3, scryptSync } from "node:crypto";
|
|
30955
31094
|
import * as fs13 from "node:fs";
|
|
30956
31095
|
import * as fsp22 from "node:fs/promises";
|
|
30957
|
-
import * as
|
|
31096
|
+
import * as path37 from "node:path";
|
|
30958
31097
|
|
|
30959
31098
|
// src/types/secret-vault.ts
|
|
30960
31099
|
var ENCRYPTED_PREFIX_PATTERN = /^enc:v(\d+):/;
|
|
@@ -31247,7 +31386,7 @@ var DefaultSecretVault = class {
|
|
|
31247
31386
|
const oldVersion = this._keyVersion;
|
|
31248
31387
|
const newKey = randomBytes3(KEY_BYTES);
|
|
31249
31388
|
const newVersion = oldVersion + 1;
|
|
31250
|
-
fs13.mkdirSync(
|
|
31389
|
+
fs13.mkdirSync(path37.dirname(this.keyFile), { recursive: true });
|
|
31251
31390
|
const passphrase = getVaultPassphrase();
|
|
31252
31391
|
if (passphrase) {
|
|
31253
31392
|
writeKeyFileAtomicSync(this.keyFile, wrapDataKey(newKey, newVersion, passphrase));
|
|
@@ -31334,7 +31473,7 @@ var DefaultSecretVault = class {
|
|
|
31334
31473
|
} catch (err) {
|
|
31335
31474
|
if (err.code !== "ENOENT") throw err;
|
|
31336
31475
|
}
|
|
31337
|
-
fs13.mkdirSync(
|
|
31476
|
+
fs13.mkdirSync(path37.dirname(this.keyFile), { recursive: true });
|
|
31338
31477
|
const key = randomBytes3(KEY_BYTES);
|
|
31339
31478
|
const passphrase = getVaultPassphrase();
|
|
31340
31479
|
const initialBytes = passphrase ? wrapDataKey(key, 1, passphrase) : key;
|
|
@@ -31394,7 +31533,7 @@ async function rewriteConfigEncrypted(configPath, vault, patch) {
|
|
|
31394
31533
|
}
|
|
31395
31534
|
const merged = deepMerge(current, patch ?? {});
|
|
31396
31535
|
const encrypted = encryptConfigSecrets(merged, vault);
|
|
31397
|
-
await fsp22.mkdir(
|
|
31536
|
+
await fsp22.mkdir(path37.dirname(configPath), { recursive: true });
|
|
31398
31537
|
await atomicWrite(configPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
31399
31538
|
await restrictFilePermissions2(configPath);
|
|
31400
31539
|
await vault.flushHardening?.();
|
|
@@ -31449,7 +31588,7 @@ function walkCount(node, vault, counter) {
|
|
|
31449
31588
|
// src/storage/attachment-store.ts
|
|
31450
31589
|
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
31451
31590
|
import * as fsp23 from "node:fs/promises";
|
|
31452
|
-
import * as
|
|
31591
|
+
import * as path38 from "node:path";
|
|
31453
31592
|
var DEFAULT_SPOOL_THRESHOLD = 256 * 1024;
|
|
31454
31593
|
var PLACEHOLDER_RE = /\[(pasted|image|file) #(\d+)[^\]]*\]|\[file:([^\]]+)\]/g;
|
|
31455
31594
|
var DefaultAttachmentStore = class {
|
|
@@ -31470,7 +31609,7 @@ var DefaultAttachmentStore = class {
|
|
|
31470
31609
|
let data = input.data;
|
|
31471
31610
|
if (this.spoolDir && bytes >= this.spoolThreshold) {
|
|
31472
31611
|
await fsp23.mkdir(this.spoolDir, { recursive: true });
|
|
31473
|
-
spooledPath =
|
|
31612
|
+
spooledPath = path38.join(this.spoolDir, `${id}.bin`);
|
|
31474
31613
|
await atomicWrite(spooledPath, input.data, {
|
|
31475
31614
|
encoding: input.kind === "image" ? "base64" : "utf8"
|
|
31476
31615
|
});
|
|
@@ -32003,8 +32142,8 @@ var IN_PROJECT_DENIED_PATHS = [
|
|
|
32003
32142
|
reason: "The other half of the filesystem confinement switch."
|
|
32004
32143
|
}
|
|
32005
32144
|
];
|
|
32006
|
-
function deleteNestedPath(target,
|
|
32007
|
-
const segments =
|
|
32145
|
+
function deleteNestedPath(target, path42) {
|
|
32146
|
+
const segments = path42.split(".");
|
|
32008
32147
|
const last = segments[segments.length - 1];
|
|
32009
32148
|
if (last === void 0) return false;
|
|
32010
32149
|
let cursor = target;
|
|
@@ -32061,16 +32200,16 @@ function assertInProjectAllowListComplete() {
|
|
|
32061
32200
|
);
|
|
32062
32201
|
}
|
|
32063
32202
|
const orphanedPaths = IN_PROJECT_DENIED_PATHS.filter(
|
|
32064
|
-
({ path:
|
|
32065
|
-
).map(({ path:
|
|
32203
|
+
({ path: path42 }) => !IN_PROJECT_ALLOWED_KEYS.has(path42.split(".")[0] ?? "")
|
|
32204
|
+
).map(({ path: path42 }) => path42);
|
|
32066
32205
|
if (orphanedPaths.length > 0) {
|
|
32067
32206
|
problems.push(
|
|
32068
32207
|
`IN_PROJECT_DENIED_PATHS entr(ies) whose top-level parent is not allowed: ` + orphanedPaths.join(", ") + ". The parent is already stripped wholesale, so the nested denial is dead \u2014 remove it."
|
|
32069
32208
|
);
|
|
32070
32209
|
}
|
|
32071
32210
|
const malformedPaths = IN_PROJECT_DENIED_PATHS.filter(
|
|
32072
|
-
({ path:
|
|
32073
|
-
).map(({ path:
|
|
32211
|
+
({ path: path42 }) => path42.split(".").length < 2 || path42.split(".").some((s) => s.length === 0)
|
|
32212
|
+
).map(({ path: path42 }) => path42);
|
|
32074
32213
|
if (malformedPaths.length > 0) {
|
|
32075
32214
|
problems.push(
|
|
32076
32215
|
`IN_PROJECT_DENIED_PATHS entr(ies) are not dotted nested paths: ` + malformedPaths.join(", ") + ". Top-level keys belong in KNOWN_DENIED_IN_PROJECT instead."
|
|
@@ -32098,8 +32237,8 @@ function stripUnsafeInProjectFields(inProject, sourcePath, warn = (msg) => conso
|
|
|
32098
32237
|
}
|
|
32099
32238
|
stripped.push(k);
|
|
32100
32239
|
}
|
|
32101
|
-
for (const { path:
|
|
32102
|
-
if (deleteNestedPath(out,
|
|
32240
|
+
for (const { path: path42 } of IN_PROJECT_DENIED_PATHS) {
|
|
32241
|
+
if (deleteNestedPath(out, path42)) stripped.push(path42);
|
|
32103
32242
|
}
|
|
32104
32243
|
if (stripped.length > 0) {
|
|
32105
32244
|
warn(
|
|
@@ -32288,10 +32427,10 @@ function removeLegacySageEngine(config) {
|
|
|
32288
32427
|
}
|
|
32289
32428
|
|
|
32290
32429
|
// src/storage/config-loader/path-identity.ts
|
|
32291
|
-
import * as
|
|
32430
|
+
import * as path39 from "node:path";
|
|
32292
32431
|
function samePath(a, b) {
|
|
32293
|
-
let ra =
|
|
32294
|
-
let rb =
|
|
32432
|
+
let ra = path39.resolve(a);
|
|
32433
|
+
let rb = path39.resolve(b);
|
|
32295
32434
|
if (process.platform === "win32" || process.platform === "darwin") {
|
|
32296
32435
|
ra = ra.toLowerCase();
|
|
32297
32436
|
rb = rb.toLowerCase();
|
|
@@ -33272,7 +33411,7 @@ ${cat}:`);
|
|
|
33272
33411
|
|
|
33273
33412
|
// src/storage/queue-store.ts
|
|
33274
33413
|
import * as fsp25 from "node:fs/promises";
|
|
33275
|
-
import * as
|
|
33414
|
+
import * as path40 from "node:path";
|
|
33276
33415
|
var QUEUE_MAX_ITEMS = 100;
|
|
33277
33416
|
var QUEUE_MAX_BYTES = 16 * 1024 * 1024;
|
|
33278
33417
|
var QUEUE_MAX_ITEM_BYTES = 8 * 1024 * 1024;
|
|
@@ -33305,7 +33444,7 @@ var QueueStore = class {
|
|
|
33305
33444
|
traceId;
|
|
33306
33445
|
logger;
|
|
33307
33446
|
constructor(opts) {
|
|
33308
|
-
this.file =
|
|
33447
|
+
this.file = path40.join(opts.dir, "queue.json");
|
|
33309
33448
|
this.events = opts.events;
|
|
33310
33449
|
this.traceId = opts.traceId;
|
|
33311
33450
|
this.logger = opts.logger;
|
|
@@ -33521,7 +33660,7 @@ function isPersistedQueueItem(v) {
|
|
|
33521
33660
|
// src/storage/recovery-lock.ts
|
|
33522
33661
|
import * as fsp26 from "node:fs/promises";
|
|
33523
33662
|
import * as os2 from "node:os";
|
|
33524
|
-
import * as
|
|
33663
|
+
import * as path41 from "node:path";
|
|
33525
33664
|
var LOCK_FILE = "active.json";
|
|
33526
33665
|
var DEFAULT_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
33527
33666
|
var RecoveryLock = class {
|
|
@@ -33532,7 +33671,7 @@ var RecoveryLock = class {
|
|
|
33532
33671
|
sessionStore;
|
|
33533
33672
|
probe;
|
|
33534
33673
|
constructor(opts) {
|
|
33535
|
-
this.file =
|
|
33674
|
+
this.file = path41.join(opts.dir, LOCK_FILE);
|
|
33536
33675
|
this.pid = opts.pid ?? process.pid;
|
|
33537
33676
|
this.hostname = opts.hostname ?? os2.hostname();
|
|
33538
33677
|
this.maxAgeMs = opts.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
|
|
@@ -33606,7 +33745,7 @@ var RecoveryLock = class {
|
|
|
33606
33745
|
* null return before calling this.
|
|
33607
33746
|
*/
|
|
33608
33747
|
async write(sessionId) {
|
|
33609
|
-
await ensureDir(
|
|
33748
|
+
await ensureDir(path41.dirname(this.file));
|
|
33610
33749
|
const lock = {
|
|
33611
33750
|
v: 1,
|
|
33612
33751
|
sessionId,
|