@wrongstack/core 0.298.3 → 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/chronicle/index.js +4 -1
- package/dist/coordination/agents/index.js +4 -1
- 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 +127 -24
- 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 +288 -34
- 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 +358 -117
- package/dist/design/index.js +4 -1
- package/dist/execution/autonomy-brain.d.ts +7 -0
- package/dist/execution/council-brain.d.ts +17 -2
- package/dist/execution/council-orchestrator.d.ts +23 -4
- package/dist/execution/council-personas.d.ts +10 -0
- package/dist/execution/council-prompts.d.ts +12 -1
- package/dist/execution/index.d.ts +1 -1
- package/dist/execution/index.js +412 -145
- package/dist/fleet-notifier.d.ts +9 -2
- package/dist/goal/index.js +4 -1
- package/dist/hooks/index.js +140 -10
- package/dist/hq/exposure.d.ts +0 -11
- package/dist/hq/index.js +34 -8
- package/dist/hq/protocol/client.d.ts +14 -1
- package/dist/hq/protocol/fleet.d.ts +22 -0
- package/dist/hq/protocol.js +12 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1718 -753
- package/dist/infrastructure/index.js +50 -2
- package/dist/infrastructure/mcp-servers.d.ts +35 -0
- package/dist/kernel/events/brain-events.d.ts +9 -0
- package/dist/kernel/events/provider-events.d.ts +49 -2
- package/dist/kernel/events/sdd-events.d.ts +2 -0
- 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 +138 -22
- 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 +46 -9
- package/dist/tools/council-tool.d.ts +1 -1
- package/dist/tools/fallback-system-config-view-tool.d.ts +1 -1
- package/dist/tools/index.js +449 -112
- package/dist/types/config/skills-fleet-brain.d.ts +4 -2
- package/dist/types/config/tools.d.ts +99 -0
- package/dist/types/council.d.ts +11 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/types/index.js +3 -3
- package/dist/types/multi-agent.d.ts +10 -0
- package/dist/types/one-shot-llm.d.ts +31 -3
- package/dist/types/plugin.d.ts +28 -0
- package/dist/types/session.d.ts +5 -1
- package/dist/utils/index.js +4 -1
- package/dist/utils/wstack-paths.d.ts +2 -0
- package/dist/worktree/index.js +47 -25
- package/dist/worktree/worktree-manager.d.ts +16 -10
- package/instructions/coordination/subagent-baseline.md +8 -0
- package/instructions/system-lite.md +83 -3
- package/instructions/system-pro.md +286 -97
- package/instructions/system.md +236 -85
- 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();
|
|
@@ -1374,7 +1374,9 @@ function safeProfileName(name) {
|
|
|
1374
1374
|
function activeProfileName(globalRoot) {
|
|
1375
1375
|
try {
|
|
1376
1376
|
const parsed = JSON.parse(fs.readFileSync(path.join(globalRoot, "config.json"), "utf8"));
|
|
1377
|
-
return safeProfileName(
|
|
1377
|
+
return safeProfileName(
|
|
1378
|
+
typeof parsed.activeProfile === "string" ? parsed.activeProfile : void 0
|
|
1379
|
+
);
|
|
1378
1380
|
} catch {
|
|
1379
1381
|
return "default";
|
|
1380
1382
|
}
|
|
@@ -1454,6 +1456,7 @@ function resolveWstackPaths(opts) {
|
|
|
1454
1456
|
projectPlan: path.join(projectDir, "plan.json"),
|
|
1455
1457
|
projectAutophase: path.join(projectDir, "autophase"),
|
|
1456
1458
|
projectSddBoards: path.join(projectDir, "sdd-boards"),
|
|
1459
|
+
projectRequirementIntakes: path.join(projectDir, "requirement-intakes"),
|
|
1457
1460
|
syncConfig: path.join(profileDir, "sync.json"),
|
|
1458
1461
|
configHistoryDir: path.join(globalRoot, "config-history"),
|
|
1459
1462
|
projectStatus: (projectHash2) => path.join(globalRoot, "projects", projectHash2, "status.json")
|
|
@@ -5303,7 +5306,7 @@ function createDelegateTool(opts) {
|
|
|
5303
5306
|
};
|
|
5304
5307
|
}
|
|
5305
5308
|
async function awaitDelegateAttempt(director, subagentId, taskId, timeoutMs, abortSignal) {
|
|
5306
|
-
return new Promise((
|
|
5309
|
+
return new Promise((resolve19) => {
|
|
5307
5310
|
let settled = false;
|
|
5308
5311
|
let timer;
|
|
5309
5312
|
let offAbort = () => {
|
|
@@ -5316,7 +5319,7 @@ async function awaitDelegateAttempt(director, subagentId, taskId, timeoutMs, abo
|
|
|
5316
5319
|
offIter();
|
|
5317
5320
|
offProgress();
|
|
5318
5321
|
offAbort();
|
|
5319
|
-
|
|
5322
|
+
resolve19(value);
|
|
5320
5323
|
};
|
|
5321
5324
|
const arm = () => {
|
|
5322
5325
|
if (timer) clearTimeout(timer);
|
|
@@ -5658,6 +5661,21 @@ var DirectorStateCheckpoint = class {
|
|
|
5658
5661
|
resume(snapshot) {
|
|
5659
5662
|
this.snapshot = snapshot;
|
|
5660
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
|
+
}
|
|
5661
5679
|
current() {
|
|
5662
5680
|
return this.snapshot;
|
|
5663
5681
|
}
|
|
@@ -7170,10 +7188,10 @@ var DirectorTaskRegistry = class _DirectorTaskRegistry {
|
|
|
7170
7188
|
pending: taskIds.filter((id) => !done.has(id))
|
|
7171
7189
|
});
|
|
7172
7190
|
}
|
|
7173
|
-
return new Promise((
|
|
7191
|
+
return new Promise((resolve19) => {
|
|
7174
7192
|
const entry = {
|
|
7175
7193
|
ids: new Set(taskIds),
|
|
7176
|
-
resolve: (result) =>
|
|
7194
|
+
resolve: (result) => resolve19({
|
|
7177
7195
|
completed: [result],
|
|
7178
7196
|
pending: taskIds.filter((id) => id !== result.taskId)
|
|
7179
7197
|
})
|
|
@@ -7181,7 +7199,7 @@ var DirectorTaskRegistry = class _DirectorTaskRegistry {
|
|
|
7181
7199
|
if (opts?.timeoutMs !== void 0) {
|
|
7182
7200
|
entry.timer = setTimeout(() => {
|
|
7183
7201
|
this.anyWaiters.delete(entry);
|
|
7184
|
-
|
|
7202
|
+
resolve19({ completed: [], pending: [...taskIds], timedOut: true });
|
|
7185
7203
|
}, opts.timeoutMs);
|
|
7186
7204
|
}
|
|
7187
7205
|
this.anyWaiters.add(entry);
|
|
@@ -7299,11 +7317,11 @@ ${JSON.stringify(result.result, null, 2)}
|
|
|
7299
7317
|
this.makeStoppedResult(taskId, "director", `Unknown task id "${taskId}" \u2014 never assigned`)
|
|
7300
7318
|
);
|
|
7301
7319
|
}
|
|
7302
|
-
let
|
|
7320
|
+
let resolve19;
|
|
7303
7321
|
const promise = new Promise((done) => {
|
|
7304
|
-
|
|
7322
|
+
resolve19 = done;
|
|
7305
7323
|
});
|
|
7306
|
-
this.taskWaiters.set(taskId, { promise, resolve:
|
|
7324
|
+
this.taskWaiters.set(taskId, { promise, resolve: resolve19 });
|
|
7307
7325
|
return promise;
|
|
7308
7326
|
}
|
|
7309
7327
|
recordAssignment(task) {
|
|
@@ -9397,7 +9415,7 @@ function truncate(s, max) {
|
|
|
9397
9415
|
var QUOTA_EXHAUSTED_RE = /(?:insufficient|exhausted|depleted|exceeded|no|not enough)[-_\s]*(?:quota|credit|balance)|(?:quota|credit|balance)(?:\s+(?:has|have))?(?:\s+been)?[-_\s]*(?:exhausted|depleted|exceeded|insufficient)|billing[_\s-]*(?:hard[_\s-]*)?limit|payment required|spending limit|plan limit|usage[-_\s]*limit[-_\s]*(?:reached|exceeded)/i;
|
|
9398
9416
|
|
|
9399
9417
|
// src/types/provider.ts
|
|
9400
|
-
var CONTEXT_OVERFLOW_RE = /context.length|context.window|maximum context|max.*tokens?.*exceeded|prompt
|
|
9418
|
+
var CONTEXT_OVERFLOW_RE = /context.length|context.window|maximum context|max.*tokens?.*exceeded|(?:prompt|request|input|messages?).{0,12}too (?:large|long)|exceeds the context|\btokens\b.*exceed|too many tokens|reduce the length|resulted in \d+ tokens|context_length_exceeded/i;
|
|
9401
9419
|
var CONTENT_FILTER_RE = /content.(filter|policy|moderation)|safety (system|filter)/i;
|
|
9402
9420
|
var RATE_LIMIT_EXCEEDED_RE = /rate[-_\s]*limit[-_\s]*exceeded/i;
|
|
9403
9421
|
function classifyProviderError(status, body, message) {
|
|
@@ -9407,7 +9425,7 @@ function classifyProviderError(status, body, message) {
|
|
|
9407
9425
|
if (status === 408) return "timeout";
|
|
9408
9426
|
if (status === 599) return "stream_hang";
|
|
9409
9427
|
if (status === 402 || QUOTA_EXHAUSTED_RE.test(text)) return "quota_exhausted";
|
|
9410
|
-
if (status === 429 && body?.message && RATE_LIMIT_EXCEEDED_RE.test(body.message)) {
|
|
9428
|
+
if (status === 429 && body?.message && body.type !== "rate_limit_exceeded" && RATE_LIMIT_EXCEEDED_RE.test(body.message)) {
|
|
9411
9429
|
return "quota_exhausted";
|
|
9412
9430
|
}
|
|
9413
9431
|
if (type === "rate_limit_error" || status === 429) return "rate_limit";
|
|
@@ -9467,7 +9485,7 @@ var ProviderError = class extends WrongStackError {
|
|
|
9467
9485
|
const e = err;
|
|
9468
9486
|
const name = e.name;
|
|
9469
9487
|
if (typeof name !== "string" || !name.endsWith("Error")) return false;
|
|
9470
|
-
return typeof e.status === "number" && typeof e.retryable === "boolean" && typeof e.kind === "string";
|
|
9488
|
+
return typeof e.status === "number" && typeof e.retryable === "boolean" && typeof e.kind === "string" && typeof e.describe === "function";
|
|
9471
9489
|
}
|
|
9472
9490
|
constructor(message, status, retryable, providerId, opts = {}) {
|
|
9473
9491
|
const kind = opts.kind ?? classifyProviderError(status, opts.body, message);
|
|
@@ -11057,7 +11075,7 @@ async function spawn(host, config, priceLookup) {
|
|
|
11057
11075
|
if (host.spawnDepth >= maxSpawnDepth) {
|
|
11058
11076
|
throw new FleetSpawnBudgetError("max_spawn_depth", maxSpawnDepth, host.spawnDepth);
|
|
11059
11077
|
}
|
|
11060
|
-
if (host.spawnCount >= host.maxSpawns) {
|
|
11078
|
+
if (host.spawnCount >= host.maxSpawns && !config.spawnBudgetExempt) {
|
|
11061
11079
|
throw new FleetSpawnBudgetError("max_spawns", host.maxSpawns, host.spawnCount + 1);
|
|
11062
11080
|
}
|
|
11063
11081
|
if (host.maxFleetCostUsd < Number.POSITIVE_INFINITY) {
|
|
@@ -11108,7 +11126,9 @@ async function spawn(host, config, priceLookup) {
|
|
|
11108
11126
|
...Number.isFinite(budget?.remainingSpawns ?? host.maxSpawns - host.spawnCount) ? {
|
|
11109
11127
|
remainingSpawns: Math.max(
|
|
11110
11128
|
0,
|
|
11111
|
-
|
|
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)
|
|
11112
11132
|
)
|
|
11113
11133
|
} : {},
|
|
11114
11134
|
...Number.isFinite(maxFleetTokens) ? { maxTokens: maxFleetTokens } : {},
|
|
@@ -11121,7 +11141,9 @@ async function spawn(host, config, priceLookup) {
|
|
|
11121
11141
|
if (host.fleetManager) {
|
|
11122
11142
|
host.fleetManager.recordSpawn(result.subagentId, config, priceLookup);
|
|
11123
11143
|
} else {
|
|
11124
|
-
|
|
11144
|
+
if (!config.spawnBudgetExempt) {
|
|
11145
|
+
host.spawnCount += 1;
|
|
11146
|
+
}
|
|
11125
11147
|
host.subagentMeta.set(result.subagentId, {
|
|
11126
11148
|
provider: config.provider,
|
|
11127
11149
|
model: config.model
|
|
@@ -11473,12 +11495,12 @@ async function executeSubagentWithTimeout({
|
|
|
11473
11495
|
}
|
|
11474
11496
|
return new Promise((resolveDecision) => {
|
|
11475
11497
|
let settled = false;
|
|
11476
|
-
const
|
|
11498
|
+
const resolve19 = (d) => {
|
|
11477
11499
|
if (settled) return;
|
|
11478
11500
|
settled = true;
|
|
11479
11501
|
resolveDecision(d);
|
|
11480
11502
|
};
|
|
11481
|
-
const fallback = setTimeout(() =>
|
|
11503
|
+
const fallback = setTimeout(() => resolve19("stop"), DECISION_TIMEOUT_MS);
|
|
11482
11504
|
const sessionId = currentSessionId();
|
|
11483
11505
|
budget._events?.emit("budget.threshold_reached", {
|
|
11484
11506
|
...sessionId ? { sessionId } : {},
|
|
@@ -11488,11 +11510,11 @@ async function executeSubagentWithTimeout({
|
|
|
11488
11510
|
timeoutMs: DECISION_TIMEOUT_MS,
|
|
11489
11511
|
extend: (extra) => {
|
|
11490
11512
|
clearTimeout(fallback);
|
|
11491
|
-
queueMicrotask(() =>
|
|
11513
|
+
queueMicrotask(() => resolve19({ extend: extra }));
|
|
11492
11514
|
},
|
|
11493
11515
|
deny: () => {
|
|
11494
11516
|
clearTimeout(fallback);
|
|
11495
|
-
|
|
11517
|
+
resolve19("stop");
|
|
11496
11518
|
}
|
|
11497
11519
|
});
|
|
11498
11520
|
});
|
|
@@ -11879,7 +11901,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
11879
11901
|
taskIds.map((id) => {
|
|
11880
11902
|
const cached = this.completedResults.find((r) => r.taskId === id);
|
|
11881
11903
|
if (cached) return cached;
|
|
11882
|
-
return new Promise((
|
|
11904
|
+
return new Promise((resolve19, reject) => {
|
|
11883
11905
|
const timeout = setTimeout(() => {
|
|
11884
11906
|
this.off("task.completed", handler);
|
|
11885
11907
|
reject(new Error(`awaitTasks timed out waiting for task "${id}"`));
|
|
@@ -11888,7 +11910,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
11888
11910
|
if (result.taskId === id) {
|
|
11889
11911
|
clearTimeout(timeout);
|
|
11890
11912
|
this.off("task.completed", handler);
|
|
11891
|
-
|
|
11913
|
+
resolve19(result);
|
|
11892
11914
|
}
|
|
11893
11915
|
};
|
|
11894
11916
|
this.on("task.completed", handler);
|
|
@@ -11913,13 +11935,13 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
11913
11935
|
const done = new Set(completed.map((r) => r.taskId));
|
|
11914
11936
|
return { completed, pending: taskIds.filter((id) => !done.has(id)) };
|
|
11915
11937
|
}
|
|
11916
|
-
return new Promise((
|
|
11938
|
+
return new Promise((resolve19) => {
|
|
11917
11939
|
let timer;
|
|
11918
11940
|
const handler = ({ result }) => {
|
|
11919
11941
|
if (!ids.has(result.taskId)) return;
|
|
11920
11942
|
if (timer) clearTimeout(timer);
|
|
11921
11943
|
this.off("task.completed", handler);
|
|
11922
|
-
|
|
11944
|
+
resolve19({
|
|
11923
11945
|
completed: [result],
|
|
11924
11946
|
pending: taskIds.filter((id) => id !== result.taskId)
|
|
11925
11947
|
});
|
|
@@ -11927,7 +11949,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
11927
11949
|
if (opts?.timeoutMs !== void 0) {
|
|
11928
11950
|
timer = setTimeout(() => {
|
|
11929
11951
|
this.off("task.completed", handler);
|
|
11930
|
-
|
|
11952
|
+
resolve19({ completed: [], pending: [...taskIds], timedOut: true });
|
|
11931
11953
|
}, opts.timeoutMs);
|
|
11932
11954
|
}
|
|
11933
11955
|
this.on("task.completed", handler);
|
|
@@ -12046,8 +12068,17 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
12046
12068
|
durationMs: 0
|
|
12047
12069
|
};
|
|
12048
12070
|
this.completedResults.push(synthetic);
|
|
12071
|
+
this.trimCompletedResults();
|
|
12049
12072
|
this.emit("task.completed", { task, result: synthetic });
|
|
12050
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
|
+
}
|
|
12051
12082
|
async runDispatched(subagentId, task) {
|
|
12052
12083
|
const subagent = this.subagents.get(subagentId);
|
|
12053
12084
|
if (!subagent) return;
|
|
@@ -12181,12 +12212,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
12181
12212
|
}
|
|
12182
12213
|
recordCompletion(result) {
|
|
12183
12214
|
this.completedResults.push(result);
|
|
12184
|
-
|
|
12185
|
-
this.completedResults.splice(
|
|
12186
|
-
0,
|
|
12187
|
-
this.completedResults.length - _DefaultMultiAgentCoordinator.MAX_COMPLETED_RESULTS
|
|
12188
|
-
);
|
|
12189
|
-
}
|
|
12215
|
+
this.trimCompletedResults();
|
|
12190
12216
|
this.totalIterations += result.iterations;
|
|
12191
12217
|
if (this.inFlight > 0) {
|
|
12192
12218
|
this.inFlight--;
|
|
@@ -13604,10 +13630,10 @@ function validateAgainstSchema(value, schema) {
|
|
|
13604
13630
|
return { ok: errors.length === 0, errors };
|
|
13605
13631
|
}
|
|
13606
13632
|
var MAX_SCHEMA_DEPTH = 64;
|
|
13607
|
-
function walk(value, schema,
|
|
13633
|
+
function walk(value, schema, path42, errors, depth) {
|
|
13608
13634
|
if (depth > MAX_SCHEMA_DEPTH) {
|
|
13609
13635
|
errors.push({
|
|
13610
|
-
path:
|
|
13636
|
+
path: path42 || "<root>",
|
|
13611
13637
|
message: `schema nesting exceeds maximum depth (${MAX_SCHEMA_DEPTH})`
|
|
13612
13638
|
});
|
|
13613
13639
|
return;
|
|
@@ -13615,7 +13641,7 @@ function walk(value, schema, path40, errors, depth) {
|
|
|
13615
13641
|
if (schema.enum !== void 0) {
|
|
13616
13642
|
if (!enumIncludes(schema.enum, value)) {
|
|
13617
13643
|
errors.push({
|
|
13618
|
-
path:
|
|
13644
|
+
path: path42 || "<root>",
|
|
13619
13645
|
message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`
|
|
13620
13646
|
});
|
|
13621
13647
|
return;
|
|
@@ -13624,7 +13650,7 @@ function walk(value, schema, path40, errors, depth) {
|
|
|
13624
13650
|
if (typeof schema.type === "string") {
|
|
13625
13651
|
if (!checkType(value, schema.type)) {
|
|
13626
13652
|
errors.push({
|
|
13627
|
-
path:
|
|
13653
|
+
path: path42 || "<root>",
|
|
13628
13654
|
message: `expected ${schema.type}, got ${describeType(value)} (${previewValue(value)})`
|
|
13629
13655
|
});
|
|
13630
13656
|
return;
|
|
@@ -13636,7 +13662,7 @@ function walk(value, schema, path40, errors, depth) {
|
|
|
13636
13662
|
if (!(req in obj)) {
|
|
13637
13663
|
const expected = schema.properties?.[req]?.type;
|
|
13638
13664
|
errors.push({
|
|
13639
|
-
path: joinPath(
|
|
13665
|
+
path: joinPath(path42, req),
|
|
13640
13666
|
message: `required property missing${typeof expected === "string" ? ` (expected ${expected})` : ""}`
|
|
13641
13667
|
});
|
|
13642
13668
|
}
|
|
@@ -13644,14 +13670,14 @@ function walk(value, schema, path40, errors, depth) {
|
|
|
13644
13670
|
if (schema.properties) {
|
|
13645
13671
|
for (const [key, subSchema] of Object.entries(schema.properties)) {
|
|
13646
13672
|
if (key in obj) {
|
|
13647
|
-
walk(obj[key], subSchema, joinPath(
|
|
13673
|
+
walk(obj[key], subSchema, joinPath(path42, key), errors, depth + 1);
|
|
13648
13674
|
}
|
|
13649
13675
|
}
|
|
13650
13676
|
}
|
|
13651
13677
|
}
|
|
13652
13678
|
if (schema.type === "array" && Array.isArray(value) && schema.items) {
|
|
13653
13679
|
for (let i = 0; i < value.length; i++) {
|
|
13654
|
-
walk(value[i], schema.items, `${
|
|
13680
|
+
walk(value[i], schema.items, `${path42}[${i}]`, errors, depth + 1);
|
|
13655
13681
|
}
|
|
13656
13682
|
}
|
|
13657
13683
|
}
|
|
@@ -13947,7 +13973,7 @@ function invalid(sessionId) {
|
|
|
13947
13973
|
|
|
13948
13974
|
// src/utils/sleep.ts
|
|
13949
13975
|
function sleep(ms) {
|
|
13950
|
-
return new Promise((
|
|
13976
|
+
return new Promise((resolve19) => setTimeout(resolve19, ms));
|
|
13951
13977
|
}
|
|
13952
13978
|
|
|
13953
13979
|
// src/utils/slug.ts
|
|
@@ -16218,7 +16244,7 @@ var SessionCheckpointCas = class {
|
|
|
16218
16244
|
}
|
|
16219
16245
|
};
|
|
16220
16246
|
function defaultRunGit(args, cwd) {
|
|
16221
|
-
return new Promise((
|
|
16247
|
+
return new Promise((resolve19) => {
|
|
16222
16248
|
const stdoutChunks = [];
|
|
16223
16249
|
const stderrChunks = [];
|
|
16224
16250
|
let stdoutBytes = 0;
|
|
@@ -16261,8 +16287,8 @@ function defaultRunGit(args, cwd) {
|
|
|
16261
16287
|
stdoutTruncated,
|
|
16262
16288
|
stderrTruncated
|
|
16263
16289
|
});
|
|
16264
|
-
child.on("error", (err) =>
|
|
16265
|
-
child.on("close", (code) =>
|
|
16290
|
+
child.on("error", (err) => resolve19(result(1, err.message)));
|
|
16291
|
+
child.on("close", (code) => resolve19(result(code ?? 1)));
|
|
16266
16292
|
});
|
|
16267
16293
|
}
|
|
16268
16294
|
|
|
@@ -16311,14 +16337,14 @@ function sessionIdResolutionError(resolution) {
|
|
|
16311
16337
|
}
|
|
16312
16338
|
|
|
16313
16339
|
// src/storage/session-read-scrubber.ts
|
|
16314
|
-
function scrubPersistedSessionEvent(event,
|
|
16315
|
-
return
|
|
16340
|
+
function scrubPersistedSessionEvent(event, scrubber2) {
|
|
16341
|
+
return scrubber2.scrubObject(event);
|
|
16316
16342
|
}
|
|
16317
|
-
function scrubPersistedSessionData(data,
|
|
16318
|
-
return
|
|
16343
|
+
function scrubPersistedSessionData(data, scrubber2) {
|
|
16344
|
+
return scrubber2.scrubObject(data);
|
|
16319
16345
|
}
|
|
16320
|
-
function scrubPersistedSessionSummary(summary,
|
|
16321
|
-
const scrubbed =
|
|
16346
|
+
function scrubPersistedSessionSummary(summary, scrubber2) {
|
|
16347
|
+
const scrubbed = scrubber2.scrubObject(summary);
|
|
16322
16348
|
const { name: _name, lastUserMessage: _lastUserMessage, ...rest } = scrubbed;
|
|
16323
16349
|
const title = sessionContentText(scrubbed.title) || "(empty session)";
|
|
16324
16350
|
const name = scrubbed.name === void 0 ? "" : sessionContentText(scrubbed.name);
|
|
@@ -18902,6 +18928,7 @@ var Director = class _Director {
|
|
|
18902
18928
|
}
|
|
18903
18929
|
setCheckpointState(snapshot) {
|
|
18904
18930
|
setCheckpointState(this.checkpointHost(), snapshot);
|
|
18931
|
+
this.applyResumeBudget(snapshot);
|
|
18905
18932
|
}
|
|
18906
18933
|
async readSession(subagentId, tail) {
|
|
18907
18934
|
return readDirectorSubagentSession({
|
|
@@ -18953,6 +18980,22 @@ var Director = class _Director {
|
|
|
18953
18980
|
}
|
|
18954
18981
|
resumeFromCheckpoint(snapshot) {
|
|
18955
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
|
+
);
|
|
18956
18999
|
}
|
|
18957
19000
|
};
|
|
18958
19001
|
|
|
@@ -21620,12 +21663,12 @@ function verifyFiles(tokens, files) {
|
|
|
21620
21663
|
const violations = [];
|
|
21621
21664
|
let onPalette = 0;
|
|
21622
21665
|
let offPalette = 0;
|
|
21623
|
-
for (const { path:
|
|
21666
|
+
for (const { path: path42, text } of files) {
|
|
21624
21667
|
const lines = text.split("\n");
|
|
21625
21668
|
lines.forEach((lineText, i) => {
|
|
21626
21669
|
const lineNo = i + 1;
|
|
21627
21670
|
const flag = (snippet, reason, axis = "color") => {
|
|
21628
|
-
violations.push({ file:
|
|
21671
|
+
violations.push({ file: path42, line: lineNo, snippet: snippet.slice(0, 80), reason, axis });
|
|
21629
21672
|
};
|
|
21630
21673
|
for (const re of [HEX_RE, FUNC_COLOR_RE]) {
|
|
21631
21674
|
re.lastIndex = 0;
|
|
@@ -22308,9 +22351,9 @@ function buildRecoveryStrategies(opts) {
|
|
|
22308
22351
|
const delayMs = err.body?.retryAfterMs ?? 5e3;
|
|
22309
22352
|
const delay = Math.min(6e4, Math.max(1e3, delayMs));
|
|
22310
22353
|
if (ctx?.signal) {
|
|
22311
|
-
await new Promise((
|
|
22354
|
+
await new Promise((resolve19) => {
|
|
22312
22355
|
if (ctx.signal.aborted) {
|
|
22313
|
-
|
|
22356
|
+
resolve19();
|
|
22314
22357
|
return;
|
|
22315
22358
|
}
|
|
22316
22359
|
let settled = false;
|
|
@@ -22321,7 +22364,7 @@ function buildRecoveryStrategies(opts) {
|
|
|
22321
22364
|
settled = true;
|
|
22322
22365
|
if (timer !== void 0) clearTimeout(timer);
|
|
22323
22366
|
ctx.signal.removeEventListener("abort", onAbort);
|
|
22324
|
-
|
|
22367
|
+
resolve19();
|
|
22325
22368
|
};
|
|
22326
22369
|
timer = setTimeout(finish, delay);
|
|
22327
22370
|
ctx.signal.addEventListener("abort", onAbort, { once: true });
|
|
@@ -24514,8 +24557,8 @@ async function streamProviderToResponse(provider, req, signal, ctx, events, logg
|
|
|
24514
24557
|
});
|
|
24515
24558
|
await Promise.race([
|
|
24516
24559
|
drainPromise,
|
|
24517
|
-
new Promise((
|
|
24518
|
-
drainTimer = setTimeout(
|
|
24560
|
+
new Promise((resolve19) => {
|
|
24561
|
+
drainTimer = setTimeout(resolve19, STREAM_DRAIN_TIMEOUT_MS);
|
|
24519
24562
|
})
|
|
24520
24563
|
]);
|
|
24521
24564
|
} finally {
|
|
@@ -24675,8 +24718,54 @@ function runWithNetworkTelemetry(context, run) {
|
|
|
24675
24718
|
return storage.run(context, run);
|
|
24676
24719
|
}
|
|
24677
24720
|
|
|
24721
|
+
// src/security/error-sanitize.ts
|
|
24722
|
+
import { homedir as homedir2 } from "node:os";
|
|
24723
|
+
var scrubber = new DefaultSecretScrubber();
|
|
24724
|
+
function scrubErrorText(text) {
|
|
24725
|
+
if (!text) return text;
|
|
24726
|
+
let out = scrubber.scrub(text);
|
|
24727
|
+
const home = safeHomedir();
|
|
24728
|
+
if (home && home.length > 2) {
|
|
24729
|
+
out = replaceAllCaseInsensitive(out, home, "~");
|
|
24730
|
+
const alt = home.includes("\\") ? home.replace(/\\/g, "/") : home.replace(/\//g, "\\");
|
|
24731
|
+
if (alt !== home) out = replaceAllCaseInsensitive(out, alt, "~");
|
|
24732
|
+
}
|
|
24733
|
+
return out;
|
|
24734
|
+
}
|
|
24735
|
+
function safeHomedir() {
|
|
24736
|
+
try {
|
|
24737
|
+
return homedir2();
|
|
24738
|
+
} catch {
|
|
24739
|
+
return "";
|
|
24740
|
+
}
|
|
24741
|
+
}
|
|
24742
|
+
function replaceAllCaseInsensitive(haystack, needle, replacement) {
|
|
24743
|
+
const lowerHay = haystack.toLowerCase();
|
|
24744
|
+
const lowerNeedle = needle.toLowerCase();
|
|
24745
|
+
let idx = lowerHay.indexOf(lowerNeedle);
|
|
24746
|
+
if (idx === -1) return haystack;
|
|
24747
|
+
let out = "";
|
|
24748
|
+
let from = 0;
|
|
24749
|
+
while (idx !== -1) {
|
|
24750
|
+
out += haystack.slice(from, idx) + replacement;
|
|
24751
|
+
from = idx + needle.length;
|
|
24752
|
+
idx = lowerHay.indexOf(lowerNeedle, from);
|
|
24753
|
+
}
|
|
24754
|
+
return out + haystack.slice(from);
|
|
24755
|
+
}
|
|
24756
|
+
|
|
24678
24757
|
// src/core/provider-runner.ts
|
|
24679
24758
|
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
24759
|
+
function scrubProviderBody(body) {
|
|
24760
|
+
if (!body) return void 0;
|
|
24761
|
+
return {
|
|
24762
|
+
...body,
|
|
24763
|
+
...body.type !== void 0 ? { type: scrubErrorText(body.type) } : {},
|
|
24764
|
+
...body.message !== void 0 ? { message: scrubErrorText(body.message) } : {},
|
|
24765
|
+
...body.raw !== void 0 ? { raw: scrubErrorText(body.raw) } : {},
|
|
24766
|
+
...body.requestId !== void 0 ? { requestId: scrubErrorText(body.requestId) } : {}
|
|
24767
|
+
};
|
|
24768
|
+
}
|
|
24680
24769
|
function providerLogCtx(p, r) {
|
|
24681
24770
|
return {
|
|
24682
24771
|
providerId: p.id,
|
|
@@ -24761,7 +24850,10 @@ async function runProviderWithRetry(opts) {
|
|
|
24761
24850
|
const isProviderErr = err instanceof ProviderError || ProviderError.isProviderError(err);
|
|
24762
24851
|
const errAsErr = err instanceof Error ? err : new Error(String(err));
|
|
24763
24852
|
const canRetry = retry.shouldRetry(isProviderErr ? err : errAsErr, attempt);
|
|
24764
|
-
const
|
|
24853
|
+
const providerErrorBody = isProviderErr ? scrubProviderBody(err.body) : void 0;
|
|
24854
|
+
const description = scrubErrorText(
|
|
24855
|
+
isProviderErr ? err.describe() : errAsErr.message
|
|
24856
|
+
);
|
|
24765
24857
|
const delay = canRetry ? Math.round(retry.delayMs(attempt, isProviderErr ? err : errAsErr)) : void 0;
|
|
24766
24858
|
events.emit("provider.attempt.failed", {
|
|
24767
24859
|
...correlation,
|
|
@@ -24774,7 +24866,8 @@ async function runProviderWithRetry(opts) {
|
|
|
24774
24866
|
retryable: canRetry,
|
|
24775
24867
|
retryScheduled: canRetry,
|
|
24776
24868
|
...delay !== void 0 ? { retryDelayMs: delay } : {},
|
|
24777
|
-
...
|
|
24869
|
+
...providerErrorBody?.requestId ? { providerRequestId: providerErrorBody.requestId } : {},
|
|
24870
|
+
...providerErrorBody ? { errorBody: providerErrorBody } : {}
|
|
24778
24871
|
});
|
|
24779
24872
|
if (!canRetry) {
|
|
24780
24873
|
events.emit("provider.error", {
|
|
@@ -24782,13 +24875,15 @@ async function runProviderWithRetry(opts) {
|
|
|
24782
24875
|
providerId: isProviderErr ? err.providerId : provider.id,
|
|
24783
24876
|
status: isProviderErr ? err.status : 0,
|
|
24784
24877
|
description,
|
|
24785
|
-
retryable: false
|
|
24878
|
+
retryable: false,
|
|
24879
|
+
...providerErrorBody ? { errorBody: providerErrorBody } : {}
|
|
24786
24880
|
});
|
|
24787
24881
|
logger.error(`Provider call failed after ${attempt + 1} attempt(s) \u2014 ${description}`, {
|
|
24788
24882
|
...providerLogCtx(provider, request),
|
|
24789
24883
|
attempts: attempt + 1,
|
|
24790
24884
|
errorDescription: description,
|
|
24791
24885
|
status: isProviderErr ? err.status : void 0,
|
|
24886
|
+
errorBody: providerErrorBody,
|
|
24792
24887
|
errorName: err instanceof Error ? err.name : void 0,
|
|
24793
24888
|
errorStack: err instanceof Error ? err.stack?.split("\n").slice(0, 3).join("\n") : void 0
|
|
24794
24889
|
});
|
|
@@ -24802,7 +24897,8 @@ async function runProviderWithRetry(opts) {
|
|
|
24802
24897
|
maxAttempts,
|
|
24803
24898
|
delayMs: delay,
|
|
24804
24899
|
errorDescription: description,
|
|
24805
|
-
status: isProviderErr ? err.status : void 0
|
|
24900
|
+
status: isProviderErr ? err.status : void 0,
|
|
24901
|
+
errorBody: providerErrorBody
|
|
24806
24902
|
});
|
|
24807
24903
|
events.emit("provider.retry", {
|
|
24808
24904
|
sessionId: resolveEventSessionId(ctx),
|
|
@@ -24810,9 +24906,10 @@ async function runProviderWithRetry(opts) {
|
|
|
24810
24906
|
attempt: attemptNum,
|
|
24811
24907
|
delayMs: delay,
|
|
24812
24908
|
status: isProviderErr ? err.status : 0,
|
|
24813
|
-
description
|
|
24909
|
+
description,
|
|
24910
|
+
...providerErrorBody ? { errorBody: providerErrorBody } : {}
|
|
24814
24911
|
});
|
|
24815
|
-
await new Promise((
|
|
24912
|
+
await new Promise((resolve19, reject) => {
|
|
24816
24913
|
let settled = false;
|
|
24817
24914
|
const cleanup = () => {
|
|
24818
24915
|
clearTimeout(t);
|
|
@@ -24828,7 +24925,7 @@ async function runProviderWithRetry(opts) {
|
|
|
24828
24925
|
if (settled) return;
|
|
24829
24926
|
settled = true;
|
|
24830
24927
|
cleanup();
|
|
24831
|
-
|
|
24928
|
+
resolve19();
|
|
24832
24929
|
}, delay);
|
|
24833
24930
|
if (signal.aborted) {
|
|
24834
24931
|
onAbort();
|
|
@@ -26580,14 +26677,14 @@ ${head}${TOOL_OUTPUT_ARTIFACT_OMISSION}${tail}`;
|
|
|
26580
26677
|
return content;
|
|
26581
26678
|
}
|
|
26582
26679
|
}
|
|
26583
|
-
function hashPermissionInput(input,
|
|
26680
|
+
function hashPermissionInput(input, scrubber2) {
|
|
26584
26681
|
let serialized;
|
|
26585
26682
|
try {
|
|
26586
26683
|
serialized = JSON.stringify(input) ?? "";
|
|
26587
26684
|
} catch {
|
|
26588
26685
|
serialized = String(input);
|
|
26589
26686
|
}
|
|
26590
|
-
return createHash7("sha256").update(
|
|
26687
|
+
return createHash7("sha256").update(scrubber2.scrub(serialized), "utf8").digest("hex");
|
|
26591
26688
|
}
|
|
26592
26689
|
function sliceUtf8Prefix(text, maxBytes) {
|
|
26593
26690
|
if (maxBytes <= 0) return "";
|
|
@@ -27090,18 +27187,18 @@ ${errorDetails}`,
|
|
|
27090
27187
|
if (this.opts.confirmAwaiter) {
|
|
27091
27188
|
const awaiter = this.opts.confirmAwaiter;
|
|
27092
27189
|
const choice = await new Promise(
|
|
27093
|
-
(
|
|
27190
|
+
(resolve19, reject) => {
|
|
27094
27191
|
const signal = ctx.signal;
|
|
27095
|
-
const onAbort = () =>
|
|
27192
|
+
const onAbort = () => resolve19("abort");
|
|
27096
27193
|
if (signal.aborted) {
|
|
27097
|
-
|
|
27194
|
+
resolve19("abort");
|
|
27098
27195
|
return;
|
|
27099
27196
|
}
|
|
27100
27197
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
27101
27198
|
awaiter(tool, use.input, use.id, suggestedPattern).then(
|
|
27102
27199
|
(c) => {
|
|
27103
27200
|
signal.removeEventListener("abort", onAbort);
|
|
27104
|
-
|
|
27201
|
+
resolve19(c);
|
|
27105
27202
|
},
|
|
27106
27203
|
(e) => {
|
|
27107
27204
|
signal.removeEventListener("abort", onAbort);
|
|
@@ -27439,7 +27536,7 @@ ${post.additionalContext}`;
|
|
|
27439
27536
|
toolPromise.catch(() => {
|
|
27440
27537
|
});
|
|
27441
27538
|
try {
|
|
27442
|
-
output = await new Promise((
|
|
27539
|
+
output = await new Promise((resolve19, reject) => {
|
|
27443
27540
|
const onAbort = () => {
|
|
27444
27541
|
setTimeout(() => reject(abortReasonToError(combined.reason)), 0);
|
|
27445
27542
|
};
|
|
@@ -27447,7 +27544,7 @@ ${post.additionalContext}`;
|
|
|
27447
27544
|
toolPromise.then(
|
|
27448
27545
|
(v) => {
|
|
27449
27546
|
combined.removeEventListener("abort", onAbort);
|
|
27450
|
-
|
|
27547
|
+
resolve19(v);
|
|
27451
27548
|
},
|
|
27452
27549
|
(e) => {
|
|
27453
27550
|
combined.removeEventListener("abort", onAbort);
|
|
@@ -27902,6 +27999,38 @@ var sshManagerServer = () => ({
|
|
|
27902
27999
|
permission: "confirm",
|
|
27903
28000
|
requestTimeoutMs: 18e4
|
|
27904
28001
|
});
|
|
28002
|
+
var requirementIntakeServer = () => ({
|
|
28003
|
+
name: "requirement-intake",
|
|
28004
|
+
description: "WrongStack Requirements Intake \u2014 list intake records and file new ones (project-scoped, --writable)",
|
|
28005
|
+
transport: "stdio",
|
|
28006
|
+
command: "wstack-requirement-intake-mcp",
|
|
28007
|
+
args: ["--project-root", ".", "--writable"],
|
|
28008
|
+
permission: "auto"
|
|
28009
|
+
});
|
|
28010
|
+
var kanbanServer = () => ({
|
|
28011
|
+
name: "kanban",
|
|
28012
|
+
description: "WrongStack Kanban \u2014 inspect and manage project work boards (project-scoped, manage tier, no destructive ops)",
|
|
28013
|
+
transport: "stdio",
|
|
28014
|
+
command: "wstack-kanban-mcp",
|
|
28015
|
+
args: ["--project-root", ".", "--writable"],
|
|
28016
|
+
permission: "confirm"
|
|
28017
|
+
});
|
|
28018
|
+
var mailboxServer = () => ({
|
|
28019
|
+
name: "mailbox",
|
|
28020
|
+
description: "WrongStack Mailbox \u2014 read and send project agent mail (project-scoped, no admin/credentials)",
|
|
28021
|
+
transport: "stdio",
|
|
28022
|
+
command: "wstack-mailbox-mcp",
|
|
28023
|
+
args: ["--project-root", ".", "--actor", "external-agent", "--writable"],
|
|
28024
|
+
permission: "auto"
|
|
28025
|
+
});
|
|
28026
|
+
var codebaseIndexServer = () => ({
|
|
28027
|
+
name: "codebase-index",
|
|
28028
|
+
description: "WrongStack Codebase Index \u2014 symbol search and dependency graphs (project-scoped, --writable)",
|
|
28029
|
+
transport: "stdio",
|
|
28030
|
+
command: "wstack-codebase-index-mcp",
|
|
28031
|
+
args: ["--project-root", ".", "--writable"],
|
|
28032
|
+
permission: "auto"
|
|
28033
|
+
});
|
|
27905
28034
|
var allServers = () => ({
|
|
27906
28035
|
filesystem: { ...filesystemServer(), enabled: false },
|
|
27907
28036
|
github: { ...githubServer(), enabled: false },
|
|
@@ -27916,7 +28045,11 @@ var allServers = () => ({
|
|
|
27916
28045
|
"zai-vision": { ...zaiVisionServer(), enabled: false },
|
|
27917
28046
|
"minimax-vision": { ...miniMaxVisionServer(), enabled: false },
|
|
27918
28047
|
playwright: { ...playwrightServer(), enabled: false },
|
|
27919
|
-
ssh: { ...sshManagerServer(), enabled: false }
|
|
28048
|
+
ssh: { ...sshManagerServer(), enabled: false },
|
|
28049
|
+
kanban: { ...kanbanServer(), enabled: false },
|
|
28050
|
+
mailbox: { ...mailboxServer(), enabled: false },
|
|
28051
|
+
"codebase-index": { ...codebaseIndexServer(), enabled: false },
|
|
28052
|
+
"requirement-intake": { ...requirementIntakeServer(), enabled: false }
|
|
27920
28053
|
});
|
|
27921
28054
|
|
|
27922
28055
|
// src/models/codex-catalog.ts
|
|
@@ -28359,7 +28492,7 @@ var DefaultModelsRegistry = class {
|
|
|
28359
28492
|
async load(opts = {}) {
|
|
28360
28493
|
if (this.payload && !opts.force) return this.payload;
|
|
28361
28494
|
if (this.seed) {
|
|
28362
|
-
this.payload = this.seed;
|
|
28495
|
+
this.payload = this.withExtraOverlay(this.seed);
|
|
28363
28496
|
this.fetchedAt = /* @__PURE__ */ new Date();
|
|
28364
28497
|
return this.payload;
|
|
28365
28498
|
}
|
|
@@ -28979,9 +29112,9 @@ var DefaultHealthRegistry = class {
|
|
|
28979
29112
|
}
|
|
28980
29113
|
async runOne(check) {
|
|
28981
29114
|
let timer = null;
|
|
28982
|
-
const timeout = new Promise((
|
|
29115
|
+
const timeout = new Promise((resolve19) => {
|
|
28983
29116
|
timer = setTimeout(
|
|
28984
|
-
() =>
|
|
29117
|
+
() => resolve19({ status: "unhealthy", detail: `timeout after ${this.timeoutMs}ms` }),
|
|
28985
29118
|
this.timeoutMs
|
|
28986
29119
|
);
|
|
28987
29120
|
});
|
|
@@ -29179,7 +29312,7 @@ async function startMetricsServer(opts) {
|
|
|
29179
29312
|
const tls = opts.tls;
|
|
29180
29313
|
const useHttps = !!(tls?.cert && tls?.key);
|
|
29181
29314
|
const host = opts.host ?? "127.0.0.1";
|
|
29182
|
-
const
|
|
29315
|
+
const path42 = opts.path ?? "/metrics";
|
|
29183
29316
|
const healthPath = opts.healthPath ?? "/healthz";
|
|
29184
29317
|
const healthRegistry = opts.healthRegistry;
|
|
29185
29318
|
const token = opts.token;
|
|
@@ -29202,7 +29335,7 @@ async function startMetricsServer(opts) {
|
|
|
29202
29335
|
return;
|
|
29203
29336
|
}
|
|
29204
29337
|
const url = req.url.split("?")[0];
|
|
29205
|
-
if (url ===
|
|
29338
|
+
if (url === path42) {
|
|
29206
29339
|
let body;
|
|
29207
29340
|
try {
|
|
29208
29341
|
body = renderPrometheus(opts.sink.snapshot());
|
|
@@ -29248,14 +29381,14 @@ async function startMetricsServer(opts) {
|
|
|
29248
29381
|
const { createServer } = await import("node:http");
|
|
29249
29382
|
server = createServer(listener);
|
|
29250
29383
|
}
|
|
29251
|
-
await new Promise((
|
|
29384
|
+
await new Promise((resolve19, reject) => {
|
|
29252
29385
|
const onError = (err) => {
|
|
29253
29386
|
server.off("listening", onListening);
|
|
29254
29387
|
reject(err);
|
|
29255
29388
|
};
|
|
29256
29389
|
const onListening = () => {
|
|
29257
29390
|
server.off("error", onError);
|
|
29258
|
-
|
|
29391
|
+
resolve19();
|
|
29259
29392
|
};
|
|
29260
29393
|
server.once("error", onError);
|
|
29261
29394
|
server.once("listening", onListening);
|
|
@@ -29266,9 +29399,9 @@ async function startMetricsServer(opts) {
|
|
|
29266
29399
|
const protocol = useHttps ? "https" : "http";
|
|
29267
29400
|
return {
|
|
29268
29401
|
port: boundPort,
|
|
29269
|
-
url: `${protocol}://${host}:${boundPort}${
|
|
29270
|
-
close: () => new Promise((
|
|
29271
|
-
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());
|
|
29272
29405
|
})
|
|
29273
29406
|
};
|
|
29274
29407
|
}
|
|
@@ -29539,6 +29672,7 @@ function startOtlpTraceExporter(opts) {
|
|
|
29539
29672
|
|
|
29540
29673
|
// src/security/permission-policy.ts
|
|
29541
29674
|
import * as fs12 from "node:fs/promises";
|
|
29675
|
+
import * as path36 from "node:path";
|
|
29542
29676
|
|
|
29543
29677
|
// src/security/permission-policy-schema.ts
|
|
29544
29678
|
var TRUST_POLICY_LIMITS = Object.freeze({
|
|
@@ -29583,19 +29717,19 @@ var UNSAFE_PROPERTY_NAMES = /* @__PURE__ */ new Set(["__proto__", "prototype", "
|
|
|
29583
29717
|
function isRecord5(value) {
|
|
29584
29718
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
29585
29719
|
}
|
|
29586
|
-
function error(diagnostics, code,
|
|
29587
|
-
diagnostics.push({ severity: "error", code, path:
|
|
29720
|
+
function error(diagnostics, code, path42, message) {
|
|
29721
|
+
diagnostics.push({ severity: "error", code, path: path42, message });
|
|
29588
29722
|
}
|
|
29589
|
-
function validatePatterns(value,
|
|
29723
|
+
function validatePatterns(value, path42, diagnostics) {
|
|
29590
29724
|
if (!Array.isArray(value)) {
|
|
29591
|
-
error(diagnostics, "invalid_pattern_list",
|
|
29725
|
+
error(diagnostics, "invalid_pattern_list", path42, "must be an array of strings");
|
|
29592
29726
|
return void 0;
|
|
29593
29727
|
}
|
|
29594
29728
|
if (value.length > TRUST_POLICY_LIMITS.maxPatternsPerRule) {
|
|
29595
29729
|
error(
|
|
29596
29730
|
diagnostics,
|
|
29597
29731
|
"too_many_patterns",
|
|
29598
|
-
|
|
29732
|
+
path42,
|
|
29599
29733
|
`must contain at most ${TRUST_POLICY_LIMITS.maxPatternsPerRule} patterns`
|
|
29600
29734
|
);
|
|
29601
29735
|
return void 0;
|
|
@@ -29603,7 +29737,7 @@ function validatePatterns(value, path40, diagnostics) {
|
|
|
29603
29737
|
const patterns = [];
|
|
29604
29738
|
const seen = /* @__PURE__ */ new Set();
|
|
29605
29739
|
for (const [index, pattern] of value.entries()) {
|
|
29606
|
-
const itemPath = `${
|
|
29740
|
+
const itemPath = `${path42}[${index}]`;
|
|
29607
29741
|
if (typeof pattern !== "string" || pattern.length === 0 || pattern.length > TRUST_POLICY_LIMITS.maxPatternChars) {
|
|
29608
29742
|
error(
|
|
29609
29743
|
diagnostics,
|
|
@@ -30018,6 +30152,8 @@ var AutoApprovePermissionPolicy = class _AutoApprovePermissionPolicy {
|
|
|
30018
30152
|
};
|
|
30019
30153
|
|
|
30020
30154
|
// src/security/permission-helpers.ts
|
|
30155
|
+
import { realpathSync } from "node:fs";
|
|
30156
|
+
import * as path35 from "node:path";
|
|
30021
30157
|
function matchesTrust(patterns, subject) {
|
|
30022
30158
|
return patterns.includes(subject) || matchAny(patterns, subject);
|
|
30023
30159
|
}
|
|
@@ -30088,9 +30224,51 @@ var SHELL_READ_VERBS = /* @__PURE__ */ new Set([
|
|
|
30088
30224
|
function stripShellQuotes(value) {
|
|
30089
30225
|
return value.replace(/^['"]|['"]$/g, "");
|
|
30090
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
|
+
}
|
|
30091
30268
|
function pathLooksSensitive(rawPath) {
|
|
30092
30269
|
const normalized = stripShellQuotes(rawPath).replace(/\\/g, "/");
|
|
30093
|
-
|
|
30270
|
+
if (SENSITIVE_READ_PATHS.some((pattern) => pattern.test(normalized))) return true;
|
|
30271
|
+
return isProtectedAgentStatePath(normalized);
|
|
30094
30272
|
}
|
|
30095
30273
|
function inputPathLooksSensitive(input) {
|
|
30096
30274
|
if (!input || typeof input !== "object") return false;
|
|
@@ -30114,6 +30292,34 @@ function shellCommandReadsSensitivePath(command) {
|
|
|
30114
30292
|
}
|
|
30115
30293
|
|
|
30116
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
|
+
}
|
|
30117
30323
|
var DefaultPermissionPolicy = class {
|
|
30118
30324
|
policy = {};
|
|
30119
30325
|
loaded = false;
|
|
@@ -30199,6 +30405,30 @@ var DefaultPermissionPolicy = class {
|
|
|
30199
30405
|
getYoloDestructive() {
|
|
30200
30406
|
return this.yoloDestructive;
|
|
30201
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
|
+
}
|
|
30202
30432
|
/**
|
|
30203
30433
|
* True when YOLO is on but this specific call is a destructive shell command
|
|
30204
30434
|
* the user has not opted to auto-approve. Shared by `evaluate()` and the
|
|
@@ -30206,6 +30436,7 @@ var DefaultPermissionPolicy = class {
|
|
|
30206
30436
|
*/
|
|
30207
30437
|
yoloBlockedAsDestructive(tool, input, ctx) {
|
|
30208
30438
|
if (!this.yolo || this.yoloDestructive) return false;
|
|
30439
|
+
if (this.hasAgentStateWriteTarget(tool, input, ctx)) return true;
|
|
30209
30440
|
const isShellSurface = tool.name === "bash" || tool.name === "exec" || (tool.capabilities ?? []).includes("shell.arbitrary");
|
|
30210
30441
|
if (!isShellSurface) return false;
|
|
30211
30442
|
const command = getInputString(input, "command") ?? shellCommandLineFromInput(input);
|
|
@@ -30312,7 +30543,7 @@ var DefaultPermissionPolicy = class {
|
|
|
30312
30543
|
const subject = subjectForToolInput(tool.name, input, tool.subjectKey);
|
|
30313
30544
|
const cacheKey = `${tool.name}::${subject ?? tool.name}`;
|
|
30314
30545
|
const evalKey = `${cacheKey}::${permissionFingerprint(tool)}`;
|
|
30315
|
-
if (tool.name !== "write") {
|
|
30546
|
+
if (tool.name !== "write" && !this.hasAgentStateWriteTarget(tool, input, ctx)) {
|
|
30316
30547
|
const cached = this._evalCache.get(evalKey);
|
|
30317
30548
|
if (cached !== void 0) return cached;
|
|
30318
30549
|
}
|
|
@@ -30420,7 +30651,7 @@ var DefaultPermissionPolicy = class {
|
|
|
30420
30651
|
return decision;
|
|
30421
30652
|
}
|
|
30422
30653
|
if (tool.name === "write" && subject) {
|
|
30423
|
-
if (ctx.hasRead(subject)) {
|
|
30654
|
+
if (ctx.hasRead(subject) && !isInsideAgentStateRoot(subject)) {
|
|
30424
30655
|
return {
|
|
30425
30656
|
permission: "auto",
|
|
30426
30657
|
source: "context",
|
|
@@ -30770,13 +31001,14 @@ var DefaultPermissionPolicy = class {
|
|
|
30770
31001
|
}
|
|
30771
31002
|
add("yolo", false, "auto", "yolo", "YOLO mode is not active");
|
|
30772
31003
|
if (tool.name === "write" && subject) {
|
|
30773
|
-
const
|
|
31004
|
+
const isAgentState = isInsideAgentStateRoot(subject);
|
|
31005
|
+
const hasRead = ctx.hasRead(subject) && !isAgentState;
|
|
30774
31006
|
add(
|
|
30775
31007
|
"write smart bypass",
|
|
30776
31008
|
hasRead,
|
|
30777
31009
|
"auto",
|
|
30778
31010
|
"context",
|
|
30779
|
-
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`
|
|
30780
31012
|
);
|
|
30781
31013
|
if (hasRead) {
|
|
30782
31014
|
winnerIndex = steps.length - 1;
|
|
@@ -30861,7 +31093,7 @@ var DefaultPermissionPolicy = class {
|
|
|
30861
31093
|
import { createCipheriv, createDecipheriv, randomBytes as randomBytes3, scryptSync } from "node:crypto";
|
|
30862
31094
|
import * as fs13 from "node:fs";
|
|
30863
31095
|
import * as fsp22 from "node:fs/promises";
|
|
30864
|
-
import * as
|
|
31096
|
+
import * as path37 from "node:path";
|
|
30865
31097
|
|
|
30866
31098
|
// src/types/secret-vault.ts
|
|
30867
31099
|
var ENCRYPTED_PREFIX_PATTERN = /^enc:v(\d+):/;
|
|
@@ -31154,7 +31386,7 @@ var DefaultSecretVault = class {
|
|
|
31154
31386
|
const oldVersion = this._keyVersion;
|
|
31155
31387
|
const newKey = randomBytes3(KEY_BYTES);
|
|
31156
31388
|
const newVersion = oldVersion + 1;
|
|
31157
|
-
fs13.mkdirSync(
|
|
31389
|
+
fs13.mkdirSync(path37.dirname(this.keyFile), { recursive: true });
|
|
31158
31390
|
const passphrase = getVaultPassphrase();
|
|
31159
31391
|
if (passphrase) {
|
|
31160
31392
|
writeKeyFileAtomicSync(this.keyFile, wrapDataKey(newKey, newVersion, passphrase));
|
|
@@ -31241,7 +31473,7 @@ var DefaultSecretVault = class {
|
|
|
31241
31473
|
} catch (err) {
|
|
31242
31474
|
if (err.code !== "ENOENT") throw err;
|
|
31243
31475
|
}
|
|
31244
|
-
fs13.mkdirSync(
|
|
31476
|
+
fs13.mkdirSync(path37.dirname(this.keyFile), { recursive: true });
|
|
31245
31477
|
const key = randomBytes3(KEY_BYTES);
|
|
31246
31478
|
const passphrase = getVaultPassphrase();
|
|
31247
31479
|
const initialBytes = passphrase ? wrapDataKey(key, 1, passphrase) : key;
|
|
@@ -31301,7 +31533,7 @@ async function rewriteConfigEncrypted(configPath, vault, patch) {
|
|
|
31301
31533
|
}
|
|
31302
31534
|
const merged = deepMerge(current, patch ?? {});
|
|
31303
31535
|
const encrypted = encryptConfigSecrets(merged, vault);
|
|
31304
|
-
await fsp22.mkdir(
|
|
31536
|
+
await fsp22.mkdir(path37.dirname(configPath), { recursive: true });
|
|
31305
31537
|
await atomicWrite(configPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
31306
31538
|
await restrictFilePermissions2(configPath);
|
|
31307
31539
|
await vault.flushHardening?.();
|
|
@@ -31356,7 +31588,7 @@ function walkCount(node, vault, counter) {
|
|
|
31356
31588
|
// src/storage/attachment-store.ts
|
|
31357
31589
|
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
31358
31590
|
import * as fsp23 from "node:fs/promises";
|
|
31359
|
-
import * as
|
|
31591
|
+
import * as path38 from "node:path";
|
|
31360
31592
|
var DEFAULT_SPOOL_THRESHOLD = 256 * 1024;
|
|
31361
31593
|
var PLACEHOLDER_RE = /\[(pasted|image|file) #(\d+)[^\]]*\]|\[file:([^\]]+)\]/g;
|
|
31362
31594
|
var DefaultAttachmentStore = class {
|
|
@@ -31377,7 +31609,7 @@ var DefaultAttachmentStore = class {
|
|
|
31377
31609
|
let data = input.data;
|
|
31378
31610
|
if (this.spoolDir && bytes >= this.spoolThreshold) {
|
|
31379
31611
|
await fsp23.mkdir(this.spoolDir, { recursive: true });
|
|
31380
|
-
spooledPath =
|
|
31612
|
+
spooledPath = path38.join(this.spoolDir, `${id}.bin`);
|
|
31381
31613
|
await atomicWrite(spooledPath, input.data, {
|
|
31382
31614
|
encoding: input.kind === "image" ? "base64" : "utf8"
|
|
31383
31615
|
});
|
|
@@ -31866,6 +32098,15 @@ var IN_PROJECT_DENIED_PATHS = [
|
|
|
31866
32098
|
reason: "Extends the exec allow-list; a repo could authorise its own binaries."
|
|
31867
32099
|
},
|
|
31868
32100
|
{ path: "tools.exec.danger", reason: "Weakens the destructive-command banner." },
|
|
32101
|
+
{
|
|
32102
|
+
// The whole subtree, not just the dangerous leaves: a persona's
|
|
32103
|
+
// `instruction` is rendered into the voter SYSTEM prompt, a profile seat
|
|
32104
|
+
// may pin providerId/model, and `defaultProfile` selects which of those
|
|
32105
|
+
// runs when the agent names no profile. Denying the parent leaves no leaf
|
|
32106
|
+
// to reclassify wrongly later.
|
|
32107
|
+
path: "tools.council",
|
|
32108
|
+
reason: "Council tool panel definitions: persona instructions are injected into the voter SYSTEM prompt and profile seats can pin an attacker-chosen providerId/model."
|
|
32109
|
+
},
|
|
31869
32110
|
{ path: "skills.extraDirs", reason: "Loads skill definitions from repo-chosen directories." },
|
|
31870
32111
|
{ path: "skills.registryUrl", reason: "Redirects skill installs to a repo-chosen host." },
|
|
31871
32112
|
// Deliberately NOT denied: skills.mode and skills.eagerMaxChars. The audit
|
|
@@ -31901,8 +32142,8 @@ var IN_PROJECT_DENIED_PATHS = [
|
|
|
31901
32142
|
reason: "The other half of the filesystem confinement switch."
|
|
31902
32143
|
}
|
|
31903
32144
|
];
|
|
31904
|
-
function deleteNestedPath(target,
|
|
31905
|
-
const segments =
|
|
32145
|
+
function deleteNestedPath(target, path42) {
|
|
32146
|
+
const segments = path42.split(".");
|
|
31906
32147
|
const last = segments[segments.length - 1];
|
|
31907
32148
|
if (last === void 0) return false;
|
|
31908
32149
|
let cursor = target;
|
|
@@ -31959,16 +32200,16 @@ function assertInProjectAllowListComplete() {
|
|
|
31959
32200
|
);
|
|
31960
32201
|
}
|
|
31961
32202
|
const orphanedPaths = IN_PROJECT_DENIED_PATHS.filter(
|
|
31962
|
-
({ path:
|
|
31963
|
-
).map(({ path:
|
|
32203
|
+
({ path: path42 }) => !IN_PROJECT_ALLOWED_KEYS.has(path42.split(".")[0] ?? "")
|
|
32204
|
+
).map(({ path: path42 }) => path42);
|
|
31964
32205
|
if (orphanedPaths.length > 0) {
|
|
31965
32206
|
problems.push(
|
|
31966
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."
|
|
31967
32208
|
);
|
|
31968
32209
|
}
|
|
31969
32210
|
const malformedPaths = IN_PROJECT_DENIED_PATHS.filter(
|
|
31970
|
-
({ path:
|
|
31971
|
-
).map(({ path:
|
|
32211
|
+
({ path: path42 }) => path42.split(".").length < 2 || path42.split(".").some((s) => s.length === 0)
|
|
32212
|
+
).map(({ path: path42 }) => path42);
|
|
31972
32213
|
if (malformedPaths.length > 0) {
|
|
31973
32214
|
problems.push(
|
|
31974
32215
|
`IN_PROJECT_DENIED_PATHS entr(ies) are not dotted nested paths: ` + malformedPaths.join(", ") + ". Top-level keys belong in KNOWN_DENIED_IN_PROJECT instead."
|
|
@@ -31996,8 +32237,8 @@ function stripUnsafeInProjectFields(inProject, sourcePath, warn = (msg) => conso
|
|
|
31996
32237
|
}
|
|
31997
32238
|
stripped.push(k);
|
|
31998
32239
|
}
|
|
31999
|
-
for (const { path:
|
|
32000
|
-
if (deleteNestedPath(out,
|
|
32240
|
+
for (const { path: path42 } of IN_PROJECT_DENIED_PATHS) {
|
|
32241
|
+
if (deleteNestedPath(out, path42)) stripped.push(path42);
|
|
32001
32242
|
}
|
|
32002
32243
|
if (stripped.length > 0) {
|
|
32003
32244
|
warn(
|
|
@@ -32186,10 +32427,10 @@ function removeLegacySageEngine(config) {
|
|
|
32186
32427
|
}
|
|
32187
32428
|
|
|
32188
32429
|
// src/storage/config-loader/path-identity.ts
|
|
32189
|
-
import * as
|
|
32430
|
+
import * as path39 from "node:path";
|
|
32190
32431
|
function samePath(a, b) {
|
|
32191
|
-
let ra =
|
|
32192
|
-
let rb =
|
|
32432
|
+
let ra = path39.resolve(a);
|
|
32433
|
+
let rb = path39.resolve(b);
|
|
32193
32434
|
if (process.platform === "win32" || process.platform === "darwin") {
|
|
32194
32435
|
ra = ra.toLowerCase();
|
|
32195
32436
|
rb = rb.toLowerCase();
|
|
@@ -33170,7 +33411,7 @@ ${cat}:`);
|
|
|
33170
33411
|
|
|
33171
33412
|
// src/storage/queue-store.ts
|
|
33172
33413
|
import * as fsp25 from "node:fs/promises";
|
|
33173
|
-
import * as
|
|
33414
|
+
import * as path40 from "node:path";
|
|
33174
33415
|
var QUEUE_MAX_ITEMS = 100;
|
|
33175
33416
|
var QUEUE_MAX_BYTES = 16 * 1024 * 1024;
|
|
33176
33417
|
var QUEUE_MAX_ITEM_BYTES = 8 * 1024 * 1024;
|
|
@@ -33203,7 +33444,7 @@ var QueueStore = class {
|
|
|
33203
33444
|
traceId;
|
|
33204
33445
|
logger;
|
|
33205
33446
|
constructor(opts) {
|
|
33206
|
-
this.file =
|
|
33447
|
+
this.file = path40.join(opts.dir, "queue.json");
|
|
33207
33448
|
this.events = opts.events;
|
|
33208
33449
|
this.traceId = opts.traceId;
|
|
33209
33450
|
this.logger = opts.logger;
|
|
@@ -33419,7 +33660,7 @@ function isPersistedQueueItem(v) {
|
|
|
33419
33660
|
// src/storage/recovery-lock.ts
|
|
33420
33661
|
import * as fsp26 from "node:fs/promises";
|
|
33421
33662
|
import * as os2 from "node:os";
|
|
33422
|
-
import * as
|
|
33663
|
+
import * as path41 from "node:path";
|
|
33423
33664
|
var LOCK_FILE = "active.json";
|
|
33424
33665
|
var DEFAULT_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
33425
33666
|
var RecoveryLock = class {
|
|
@@ -33430,7 +33671,7 @@ var RecoveryLock = class {
|
|
|
33430
33671
|
sessionStore;
|
|
33431
33672
|
probe;
|
|
33432
33673
|
constructor(opts) {
|
|
33433
|
-
this.file =
|
|
33674
|
+
this.file = path41.join(opts.dir, LOCK_FILE);
|
|
33434
33675
|
this.pid = opts.pid ?? process.pid;
|
|
33435
33676
|
this.hostname = opts.hostname ?? os2.hostname();
|
|
33436
33677
|
this.maxAgeMs = opts.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
|
|
@@ -33504,7 +33745,7 @@ var RecoveryLock = class {
|
|
|
33504
33745
|
* null return before calling this.
|
|
33505
33746
|
*/
|
|
33506
33747
|
async write(sessionId) {
|
|
33507
|
-
await ensureDir(
|
|
33748
|
+
await ensureDir(path41.dirname(this.file));
|
|
33508
33749
|
const lock = {
|
|
33509
33750
|
v: 1,
|
|
33510
33751
|
sessionId,
|