@wrongstack/core 0.298.2 → 0.299.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/index.js +7 -4
- package/dist/core/index.js +62 -8
- package/dist/defaults/index.js +120 -18
- package/dist/design/index.js +4 -1
- package/dist/execution/council-brain.d.ts +6 -2
- package/dist/execution/council-personas.d.ts +10 -0
- package/dist/execution/index.d.ts +1 -1
- package/dist/execution/index.js +57 -7
- package/dist/goal/index.js +4 -1
- package/dist/hooks/index.js +132 -6
- package/dist/hq/exposure.d.ts +0 -11
- package/dist/hq/index.js +16 -4
- package/dist/hq/protocol/client.d.ts +14 -1
- package/dist/hq/protocol/fleet.d.ts +2 -0
- package/dist/hq/protocol.js +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +207 -47
- package/dist/infrastructure/index.js +50 -2
- package/dist/infrastructure/mcp-servers.d.ts +35 -0
- package/dist/kernel/events/provider-events.d.ts +7 -1
- package/dist/kernel/events/sdd-events.d.ts +2 -0
- package/dist/plugin/index.js +4 -1
- package/dist/storage/index.js +13 -1
- package/dist/tools/council-tool.d.ts +1 -1
- package/dist/tools/index.js +61 -10
- package/dist/types/config/skills-fleet-brain.d.ts +4 -2
- package/dist/types/config/tools.d.ts +99 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/index.js +3 -3
- package/dist/types/one-shot-llm.d.ts +22 -3
- 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 +43 -21
- package/dist/worktree/worktree-manager.d.ts +16 -10
- package/instructions/coordination/subagent-baseline.md +8 -0
- package/instructions/system-lite.md +2 -0
- package/instructions/system-pro.md +14 -10
- package/instructions/system.md +11 -7
- package/package.json +3 -3
package/dist/chronicle/index.js
CHANGED
|
@@ -582,7 +582,9 @@ function safeProfileName(name) {
|
|
|
582
582
|
function activeProfileName(globalRoot) {
|
|
583
583
|
try {
|
|
584
584
|
const parsed = JSON.parse(fs2.readFileSync(path4.join(globalRoot, "config.json"), "utf8"));
|
|
585
|
-
return safeProfileName(
|
|
585
|
+
return safeProfileName(
|
|
586
|
+
typeof parsed.activeProfile === "string" ? parsed.activeProfile : void 0
|
|
587
|
+
);
|
|
586
588
|
} catch {
|
|
587
589
|
return "default";
|
|
588
590
|
}
|
|
@@ -662,6 +664,7 @@ function resolveWstackPaths(opts) {
|
|
|
662
664
|
projectPlan: path4.join(projectDir, "plan.json"),
|
|
663
665
|
projectAutophase: path4.join(projectDir, "autophase"),
|
|
664
666
|
projectSddBoards: path4.join(projectDir, "sdd-boards"),
|
|
667
|
+
projectRequirementIntakes: path4.join(projectDir, "requirement-intakes"),
|
|
665
668
|
syncConfig: path4.join(profileDir, "sync.json"),
|
|
666
669
|
configHistoryDir: path4.join(globalRoot, "config-history"),
|
|
667
670
|
projectStatus: (projectHash2) => path4.join(globalRoot, "projects", projectHash2, "status.json")
|
|
@@ -98,7 +98,9 @@ function safeProfileName(name) {
|
|
|
98
98
|
function activeProfileName(globalRoot) {
|
|
99
99
|
try {
|
|
100
100
|
const parsed = JSON.parse(fs.readFileSync(path.join(globalRoot, "config.json"), "utf8"));
|
|
101
|
-
return safeProfileName(
|
|
101
|
+
return safeProfileName(
|
|
102
|
+
typeof parsed.activeProfile === "string" ? parsed.activeProfile : void 0
|
|
103
|
+
);
|
|
102
104
|
} catch {
|
|
103
105
|
return "default";
|
|
104
106
|
}
|
|
@@ -178,6 +180,7 @@ function resolveWstackPaths(opts) {
|
|
|
178
180
|
projectPlan: path.join(projectDir, "plan.json"),
|
|
179
181
|
projectAutophase: path.join(projectDir, "autophase"),
|
|
180
182
|
projectSddBoards: path.join(projectDir, "sdd-boards"),
|
|
183
|
+
projectRequirementIntakes: path.join(projectDir, "requirement-intakes"),
|
|
181
184
|
syncConfig: path.join(profileDir, "sync.json"),
|
|
182
185
|
configHistoryDir: path.join(globalRoot, "config-history"),
|
|
183
186
|
projectStatus: (projectHash2) => path.join(globalRoot, "projects", projectHash2, "status.json")
|
|
@@ -1361,7 +1361,9 @@ function safeProfileName(name) {
|
|
|
1361
1361
|
function activeProfileName(globalRoot) {
|
|
1362
1362
|
try {
|
|
1363
1363
|
const parsed = JSON.parse(fs.readFileSync(path.join(globalRoot, "config.json"), "utf8"));
|
|
1364
|
-
return safeProfileName(
|
|
1364
|
+
return safeProfileName(
|
|
1365
|
+
typeof parsed.activeProfile === "string" ? parsed.activeProfile : void 0
|
|
1366
|
+
);
|
|
1365
1367
|
} catch {
|
|
1366
1368
|
return "default";
|
|
1367
1369
|
}
|
|
@@ -1441,6 +1443,7 @@ function resolveWstackPaths(opts) {
|
|
|
1441
1443
|
projectPlan: path.join(projectDir, "plan.json"),
|
|
1442
1444
|
projectAutophase: path.join(projectDir, "autophase"),
|
|
1443
1445
|
projectSddBoards: path.join(projectDir, "sdd-boards"),
|
|
1446
|
+
projectRequirementIntakes: path.join(projectDir, "requirement-intakes"),
|
|
1444
1447
|
syncConfig: path.join(profileDir, "sync.json"),
|
|
1445
1448
|
configHistoryDir: path.join(globalRoot, "config-history"),
|
|
1446
1449
|
projectStatus: (projectHash2) => path.join(globalRoot, "projects", projectHash2, "status.json")
|
|
@@ -12609,7 +12612,7 @@ var QUOTA_EXHAUSTED_RE = /(?:insufficient|exhausted|depleted|exceeded|no|not eno
|
|
|
12609
12612
|
var ROUTE_SCOPED_QUOTA_RE = /\b(?:for|on)\s+(?:(?:this|the)\s+)?(?:route|model)\b|\b(?:route|model)(?:[-_\s]+[\w.-]+)?[-_\s]*(?:quota|limit)\b|\b(?:quota|limit).{0,24}\b(?:for|on)\s+(?:(?:this|the)\s+)?(?:route|model)\b/i;
|
|
12610
12613
|
|
|
12611
12614
|
// src/types/provider.ts
|
|
12612
|
-
var CONTEXT_OVERFLOW_RE = /context.length|context.window|maximum context|max.*tokens?.*exceeded|prompt
|
|
12615
|
+
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;
|
|
12613
12616
|
var CONTENT_FILTER_RE = /content.(filter|policy|moderation)|safety (system|filter)/i;
|
|
12614
12617
|
var RATE_LIMIT_EXCEEDED_RE = /rate[-_\s]*limit[-_\s]*exceeded/i;
|
|
12615
12618
|
function classifyProviderError(status, body, message) {
|
|
@@ -12619,7 +12622,7 @@ function classifyProviderError(status, body, message) {
|
|
|
12619
12622
|
if (status === 408) return "timeout";
|
|
12620
12623
|
if (status === 599) return "stream_hang";
|
|
12621
12624
|
if (status === 402 || QUOTA_EXHAUSTED_RE.test(text)) return "quota_exhausted";
|
|
12622
|
-
if (status === 429 && body?.message && RATE_LIMIT_EXCEEDED_RE.test(body.message)) {
|
|
12625
|
+
if (status === 429 && body?.message && body.type !== "rate_limit_exceeded" && RATE_LIMIT_EXCEEDED_RE.test(body.message)) {
|
|
12623
12626
|
return "quota_exhausted";
|
|
12624
12627
|
}
|
|
12625
12628
|
if (type === "rate_limit_error" || status === 429) return "rate_limit";
|
|
@@ -12721,7 +12724,7 @@ var ProviderError = class extends WrongStackError {
|
|
|
12721
12724
|
const e = err;
|
|
12722
12725
|
const name = e.name;
|
|
12723
12726
|
if (typeof name !== "string" || !name.endsWith("Error")) return false;
|
|
12724
|
-
return typeof e.status === "number" && typeof e.retryable === "boolean" && typeof e.kind === "string";
|
|
12727
|
+
return typeof e.status === "number" && typeof e.retryable === "boolean" && typeof e.kind === "string" && typeof e.describe === "function";
|
|
12725
12728
|
}
|
|
12726
12729
|
constructor(message, status, retryable, providerId, opts = {}) {
|
|
12727
12730
|
const kind = opts.kind ?? classifyProviderError(status, opts.body, message);
|
package/dist/core/index.js
CHANGED
|
@@ -3804,7 +3804,7 @@ var QUOTA_EXHAUSTED_RE = /(?:insufficient|exhausted|depleted|exceeded|no|not eno
|
|
|
3804
3804
|
function effectiveInputTokens(usage) {
|
|
3805
3805
|
return usage.input + (usage.cacheRead ?? 0) + (usage.cacheWrite ?? 0);
|
|
3806
3806
|
}
|
|
3807
|
-
var CONTEXT_OVERFLOW_RE = /context.length|context.window|maximum context|max.*tokens?.*exceeded|prompt
|
|
3807
|
+
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;
|
|
3808
3808
|
var CONTENT_FILTER_RE = /content.(filter|policy|moderation)|safety (system|filter)/i;
|
|
3809
3809
|
var RATE_LIMIT_EXCEEDED_RE = /rate[-_\s]*limit[-_\s]*exceeded/i;
|
|
3810
3810
|
function classifyProviderError(status, body, message) {
|
|
@@ -3814,7 +3814,7 @@ function classifyProviderError(status, body, message) {
|
|
|
3814
3814
|
if (status === 408) return "timeout";
|
|
3815
3815
|
if (status === 599) return "stream_hang";
|
|
3816
3816
|
if (status === 402 || QUOTA_EXHAUSTED_RE.test(text)) return "quota_exhausted";
|
|
3817
|
-
if (status === 429 && body?.message && RATE_LIMIT_EXCEEDED_RE.test(body.message)) {
|
|
3817
|
+
if (status === 429 && body?.message && body.type !== "rate_limit_exceeded" && RATE_LIMIT_EXCEEDED_RE.test(body.message)) {
|
|
3818
3818
|
return "quota_exhausted";
|
|
3819
3819
|
}
|
|
3820
3820
|
if (type === "rate_limit_error" || status === 429) return "rate_limit";
|
|
@@ -3874,7 +3874,7 @@ var ProviderError = class extends WrongStackError {
|
|
|
3874
3874
|
const e = err;
|
|
3875
3875
|
const name = e.name;
|
|
3876
3876
|
if (typeof name !== "string" || !name.endsWith("Error")) return false;
|
|
3877
|
-
return typeof e.status === "number" && typeof e.retryable === "boolean" && typeof e.kind === "string";
|
|
3877
|
+
return typeof e.status === "number" && typeof e.retryable === "boolean" && typeof e.kind === "string" && typeof e.describe === "function";
|
|
3878
3878
|
}
|
|
3879
3879
|
constructor(message, status, retryable, providerId, opts = {}) {
|
|
3880
3880
|
const kind = opts.kind ?? classifyProviderError(status, opts.body, message);
|
|
@@ -5971,8 +5971,54 @@ function runWithNetworkTelemetry(context, run) {
|
|
|
5971
5971
|
return storage.run(context, run);
|
|
5972
5972
|
}
|
|
5973
5973
|
|
|
5974
|
+
// src/security/error-sanitize.ts
|
|
5975
|
+
import { homedir as homedir2 } from "node:os";
|
|
5976
|
+
var scrubber = new DefaultSecretScrubber();
|
|
5977
|
+
function scrubErrorText(text) {
|
|
5978
|
+
if (!text) return text;
|
|
5979
|
+
let out = scrubber.scrub(text);
|
|
5980
|
+
const home = safeHomedir();
|
|
5981
|
+
if (home && home.length > 2) {
|
|
5982
|
+
out = replaceAllCaseInsensitive(out, home, "~");
|
|
5983
|
+
const alt = home.includes("\\") ? home.replace(/\\/g, "/") : home.replace(/\//g, "\\");
|
|
5984
|
+
if (alt !== home) out = replaceAllCaseInsensitive(out, alt, "~");
|
|
5985
|
+
}
|
|
5986
|
+
return out;
|
|
5987
|
+
}
|
|
5988
|
+
function safeHomedir() {
|
|
5989
|
+
try {
|
|
5990
|
+
return homedir2();
|
|
5991
|
+
} catch {
|
|
5992
|
+
return "";
|
|
5993
|
+
}
|
|
5994
|
+
}
|
|
5995
|
+
function replaceAllCaseInsensitive(haystack, needle, replacement) {
|
|
5996
|
+
const lowerHay = haystack.toLowerCase();
|
|
5997
|
+
const lowerNeedle = needle.toLowerCase();
|
|
5998
|
+
let idx = lowerHay.indexOf(lowerNeedle);
|
|
5999
|
+
if (idx === -1) return haystack;
|
|
6000
|
+
let out = "";
|
|
6001
|
+
let from = 0;
|
|
6002
|
+
while (idx !== -1) {
|
|
6003
|
+
out += haystack.slice(from, idx) + replacement;
|
|
6004
|
+
from = idx + needle.length;
|
|
6005
|
+
idx = lowerHay.indexOf(lowerNeedle, from);
|
|
6006
|
+
}
|
|
6007
|
+
return out + haystack.slice(from);
|
|
6008
|
+
}
|
|
6009
|
+
|
|
5974
6010
|
// src/core/provider-runner.ts
|
|
5975
6011
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
6012
|
+
function scrubProviderBody(body) {
|
|
6013
|
+
if (!body) return void 0;
|
|
6014
|
+
return {
|
|
6015
|
+
...body,
|
|
6016
|
+
...body.type !== void 0 ? { type: scrubErrorText(body.type) } : {},
|
|
6017
|
+
...body.message !== void 0 ? { message: scrubErrorText(body.message) } : {},
|
|
6018
|
+
...body.raw !== void 0 ? { raw: scrubErrorText(body.raw) } : {},
|
|
6019
|
+
...body.requestId !== void 0 ? { requestId: scrubErrorText(body.requestId) } : {}
|
|
6020
|
+
};
|
|
6021
|
+
}
|
|
5976
6022
|
function providerLogCtx(p, r) {
|
|
5977
6023
|
return {
|
|
5978
6024
|
providerId: p.id,
|
|
@@ -6057,7 +6103,10 @@ async function runProviderWithRetry(opts) {
|
|
|
6057
6103
|
const isProviderErr = err instanceof ProviderError || ProviderError.isProviderError(err);
|
|
6058
6104
|
const errAsErr = err instanceof Error ? err : new Error(String(err));
|
|
6059
6105
|
const canRetry = retry.shouldRetry(isProviderErr ? err : errAsErr, attempt);
|
|
6060
|
-
const
|
|
6106
|
+
const providerErrorBody = isProviderErr ? scrubProviderBody(err.body) : void 0;
|
|
6107
|
+
const description = scrubErrorText(
|
|
6108
|
+
isProviderErr ? err.describe() : errAsErr.message
|
|
6109
|
+
);
|
|
6061
6110
|
const delay2 = canRetry ? Math.round(retry.delayMs(attempt, isProviderErr ? err : errAsErr)) : void 0;
|
|
6062
6111
|
events.emit("provider.attempt.failed", {
|
|
6063
6112
|
...correlation,
|
|
@@ -6070,7 +6119,8 @@ async function runProviderWithRetry(opts) {
|
|
|
6070
6119
|
retryable: canRetry,
|
|
6071
6120
|
retryScheduled: canRetry,
|
|
6072
6121
|
...delay2 !== void 0 ? { retryDelayMs: delay2 } : {},
|
|
6073
|
-
...
|
|
6122
|
+
...providerErrorBody?.requestId ? { providerRequestId: providerErrorBody.requestId } : {},
|
|
6123
|
+
...providerErrorBody ? { errorBody: providerErrorBody } : {}
|
|
6074
6124
|
});
|
|
6075
6125
|
if (!canRetry) {
|
|
6076
6126
|
events.emit("provider.error", {
|
|
@@ -6078,13 +6128,15 @@ async function runProviderWithRetry(opts) {
|
|
|
6078
6128
|
providerId: isProviderErr ? err.providerId : provider.id,
|
|
6079
6129
|
status: isProviderErr ? err.status : 0,
|
|
6080
6130
|
description,
|
|
6081
|
-
retryable: false
|
|
6131
|
+
retryable: false,
|
|
6132
|
+
...providerErrorBody ? { errorBody: providerErrorBody } : {}
|
|
6082
6133
|
});
|
|
6083
6134
|
logger.error(`Provider call failed after ${attempt + 1} attempt(s) \u2014 ${description}`, {
|
|
6084
6135
|
...providerLogCtx(provider, request),
|
|
6085
6136
|
attempts: attempt + 1,
|
|
6086
6137
|
errorDescription: description,
|
|
6087
6138
|
status: isProviderErr ? err.status : void 0,
|
|
6139
|
+
errorBody: providerErrorBody,
|
|
6088
6140
|
errorName: err instanceof Error ? err.name : void 0,
|
|
6089
6141
|
errorStack: err instanceof Error ? err.stack?.split("\n").slice(0, 3).join("\n") : void 0
|
|
6090
6142
|
});
|
|
@@ -6098,7 +6150,8 @@ async function runProviderWithRetry(opts) {
|
|
|
6098
6150
|
maxAttempts,
|
|
6099
6151
|
delayMs: delay2,
|
|
6100
6152
|
errorDescription: description,
|
|
6101
|
-
status: isProviderErr ? err.status : void 0
|
|
6153
|
+
status: isProviderErr ? err.status : void 0,
|
|
6154
|
+
errorBody: providerErrorBody
|
|
6102
6155
|
});
|
|
6103
6156
|
events.emit("provider.retry", {
|
|
6104
6157
|
sessionId: resolveEventSessionId(ctx),
|
|
@@ -6106,7 +6159,8 @@ async function runProviderWithRetry(opts) {
|
|
|
6106
6159
|
attempt: attemptNum,
|
|
6107
6160
|
delayMs: delay2,
|
|
6108
6161
|
status: isProviderErr ? err.status : 0,
|
|
6109
|
-
description
|
|
6162
|
+
description,
|
|
6163
|
+
...providerErrorBody ? { errorBody: providerErrorBody } : {}
|
|
6110
6164
|
});
|
|
6111
6165
|
await new Promise((resolve10, reject) => {
|
|
6112
6166
|
let settled = false;
|
package/dist/defaults/index.js
CHANGED
|
@@ -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")
|
|
@@ -9397,7 +9400,7 @@ function truncate(s, max) {
|
|
|
9397
9400
|
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
9401
|
|
|
9399
9402
|
// src/types/provider.ts
|
|
9400
|
-
var CONTEXT_OVERFLOW_RE = /context.length|context.window|maximum context|max.*tokens?.*exceeded|prompt
|
|
9403
|
+
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
9404
|
var CONTENT_FILTER_RE = /content.(filter|policy|moderation)|safety (system|filter)/i;
|
|
9402
9405
|
var RATE_LIMIT_EXCEEDED_RE = /rate[-_\s]*limit[-_\s]*exceeded/i;
|
|
9403
9406
|
function classifyProviderError(status, body, message) {
|
|
@@ -9407,7 +9410,7 @@ function classifyProviderError(status, body, message) {
|
|
|
9407
9410
|
if (status === 408) return "timeout";
|
|
9408
9411
|
if (status === 599) return "stream_hang";
|
|
9409
9412
|
if (status === 402 || QUOTA_EXHAUSTED_RE.test(text)) return "quota_exhausted";
|
|
9410
|
-
if (status === 429 && body?.message && RATE_LIMIT_EXCEEDED_RE.test(body.message)) {
|
|
9413
|
+
if (status === 429 && body?.message && body.type !== "rate_limit_exceeded" && RATE_LIMIT_EXCEEDED_RE.test(body.message)) {
|
|
9411
9414
|
return "quota_exhausted";
|
|
9412
9415
|
}
|
|
9413
9416
|
if (type === "rate_limit_error" || status === 429) return "rate_limit";
|
|
@@ -9467,7 +9470,7 @@ var ProviderError = class extends WrongStackError {
|
|
|
9467
9470
|
const e = err;
|
|
9468
9471
|
const name = e.name;
|
|
9469
9472
|
if (typeof name !== "string" || !name.endsWith("Error")) return false;
|
|
9470
|
-
return typeof e.status === "number" && typeof e.retryable === "boolean" && typeof e.kind === "string";
|
|
9473
|
+
return typeof e.status === "number" && typeof e.retryable === "boolean" && typeof e.kind === "string" && typeof e.describe === "function";
|
|
9471
9474
|
}
|
|
9472
9475
|
constructor(message, status, retryable, providerId, opts = {}) {
|
|
9473
9476
|
const kind = opts.kind ?? classifyProviderError(status, opts.body, message);
|
|
@@ -16311,14 +16314,14 @@ function sessionIdResolutionError(resolution) {
|
|
|
16311
16314
|
}
|
|
16312
16315
|
|
|
16313
16316
|
// src/storage/session-read-scrubber.ts
|
|
16314
|
-
function scrubPersistedSessionEvent(event,
|
|
16315
|
-
return
|
|
16317
|
+
function scrubPersistedSessionEvent(event, scrubber2) {
|
|
16318
|
+
return scrubber2.scrubObject(event);
|
|
16316
16319
|
}
|
|
16317
|
-
function scrubPersistedSessionData(data,
|
|
16318
|
-
return
|
|
16320
|
+
function scrubPersistedSessionData(data, scrubber2) {
|
|
16321
|
+
return scrubber2.scrubObject(data);
|
|
16319
16322
|
}
|
|
16320
|
-
function scrubPersistedSessionSummary(summary,
|
|
16321
|
-
const scrubbed =
|
|
16323
|
+
function scrubPersistedSessionSummary(summary, scrubber2) {
|
|
16324
|
+
const scrubbed = scrubber2.scrubObject(summary);
|
|
16322
16325
|
const { name: _name, lastUserMessage: _lastUserMessage, ...rest } = scrubbed;
|
|
16323
16326
|
const title = sessionContentText(scrubbed.title) || "(empty session)";
|
|
16324
16327
|
const name = scrubbed.name === void 0 ? "" : sessionContentText(scrubbed.name);
|
|
@@ -24675,8 +24678,54 @@ function runWithNetworkTelemetry(context, run) {
|
|
|
24675
24678
|
return storage.run(context, run);
|
|
24676
24679
|
}
|
|
24677
24680
|
|
|
24681
|
+
// src/security/error-sanitize.ts
|
|
24682
|
+
import { homedir as homedir2 } from "node:os";
|
|
24683
|
+
var scrubber = new DefaultSecretScrubber();
|
|
24684
|
+
function scrubErrorText(text) {
|
|
24685
|
+
if (!text) return text;
|
|
24686
|
+
let out = scrubber.scrub(text);
|
|
24687
|
+
const home = safeHomedir();
|
|
24688
|
+
if (home && home.length > 2) {
|
|
24689
|
+
out = replaceAllCaseInsensitive(out, home, "~");
|
|
24690
|
+
const alt = home.includes("\\") ? home.replace(/\\/g, "/") : home.replace(/\//g, "\\");
|
|
24691
|
+
if (alt !== home) out = replaceAllCaseInsensitive(out, alt, "~");
|
|
24692
|
+
}
|
|
24693
|
+
return out;
|
|
24694
|
+
}
|
|
24695
|
+
function safeHomedir() {
|
|
24696
|
+
try {
|
|
24697
|
+
return homedir2();
|
|
24698
|
+
} catch {
|
|
24699
|
+
return "";
|
|
24700
|
+
}
|
|
24701
|
+
}
|
|
24702
|
+
function replaceAllCaseInsensitive(haystack, needle, replacement) {
|
|
24703
|
+
const lowerHay = haystack.toLowerCase();
|
|
24704
|
+
const lowerNeedle = needle.toLowerCase();
|
|
24705
|
+
let idx = lowerHay.indexOf(lowerNeedle);
|
|
24706
|
+
if (idx === -1) return haystack;
|
|
24707
|
+
let out = "";
|
|
24708
|
+
let from = 0;
|
|
24709
|
+
while (idx !== -1) {
|
|
24710
|
+
out += haystack.slice(from, idx) + replacement;
|
|
24711
|
+
from = idx + needle.length;
|
|
24712
|
+
idx = lowerHay.indexOf(lowerNeedle, from);
|
|
24713
|
+
}
|
|
24714
|
+
return out + haystack.slice(from);
|
|
24715
|
+
}
|
|
24716
|
+
|
|
24678
24717
|
// src/core/provider-runner.ts
|
|
24679
24718
|
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
24719
|
+
function scrubProviderBody(body) {
|
|
24720
|
+
if (!body) return void 0;
|
|
24721
|
+
return {
|
|
24722
|
+
...body,
|
|
24723
|
+
...body.type !== void 0 ? { type: scrubErrorText(body.type) } : {},
|
|
24724
|
+
...body.message !== void 0 ? { message: scrubErrorText(body.message) } : {},
|
|
24725
|
+
...body.raw !== void 0 ? { raw: scrubErrorText(body.raw) } : {},
|
|
24726
|
+
...body.requestId !== void 0 ? { requestId: scrubErrorText(body.requestId) } : {}
|
|
24727
|
+
};
|
|
24728
|
+
}
|
|
24680
24729
|
function providerLogCtx(p, r) {
|
|
24681
24730
|
return {
|
|
24682
24731
|
providerId: p.id,
|
|
@@ -24761,7 +24810,10 @@ async function runProviderWithRetry(opts) {
|
|
|
24761
24810
|
const isProviderErr = err instanceof ProviderError || ProviderError.isProviderError(err);
|
|
24762
24811
|
const errAsErr = err instanceof Error ? err : new Error(String(err));
|
|
24763
24812
|
const canRetry = retry.shouldRetry(isProviderErr ? err : errAsErr, attempt);
|
|
24764
|
-
const
|
|
24813
|
+
const providerErrorBody = isProviderErr ? scrubProviderBody(err.body) : void 0;
|
|
24814
|
+
const description = scrubErrorText(
|
|
24815
|
+
isProviderErr ? err.describe() : errAsErr.message
|
|
24816
|
+
);
|
|
24765
24817
|
const delay = canRetry ? Math.round(retry.delayMs(attempt, isProviderErr ? err : errAsErr)) : void 0;
|
|
24766
24818
|
events.emit("provider.attempt.failed", {
|
|
24767
24819
|
...correlation,
|
|
@@ -24774,7 +24826,8 @@ async function runProviderWithRetry(opts) {
|
|
|
24774
24826
|
retryable: canRetry,
|
|
24775
24827
|
retryScheduled: canRetry,
|
|
24776
24828
|
...delay !== void 0 ? { retryDelayMs: delay } : {},
|
|
24777
|
-
...
|
|
24829
|
+
...providerErrorBody?.requestId ? { providerRequestId: providerErrorBody.requestId } : {},
|
|
24830
|
+
...providerErrorBody ? { errorBody: providerErrorBody } : {}
|
|
24778
24831
|
});
|
|
24779
24832
|
if (!canRetry) {
|
|
24780
24833
|
events.emit("provider.error", {
|
|
@@ -24782,13 +24835,15 @@ async function runProviderWithRetry(opts) {
|
|
|
24782
24835
|
providerId: isProviderErr ? err.providerId : provider.id,
|
|
24783
24836
|
status: isProviderErr ? err.status : 0,
|
|
24784
24837
|
description,
|
|
24785
|
-
retryable: false
|
|
24838
|
+
retryable: false,
|
|
24839
|
+
...providerErrorBody ? { errorBody: providerErrorBody } : {}
|
|
24786
24840
|
});
|
|
24787
24841
|
logger.error(`Provider call failed after ${attempt + 1} attempt(s) \u2014 ${description}`, {
|
|
24788
24842
|
...providerLogCtx(provider, request),
|
|
24789
24843
|
attempts: attempt + 1,
|
|
24790
24844
|
errorDescription: description,
|
|
24791
24845
|
status: isProviderErr ? err.status : void 0,
|
|
24846
|
+
errorBody: providerErrorBody,
|
|
24792
24847
|
errorName: err instanceof Error ? err.name : void 0,
|
|
24793
24848
|
errorStack: err instanceof Error ? err.stack?.split("\n").slice(0, 3).join("\n") : void 0
|
|
24794
24849
|
});
|
|
@@ -24802,7 +24857,8 @@ async function runProviderWithRetry(opts) {
|
|
|
24802
24857
|
maxAttempts,
|
|
24803
24858
|
delayMs: delay,
|
|
24804
24859
|
errorDescription: description,
|
|
24805
|
-
status: isProviderErr ? err.status : void 0
|
|
24860
|
+
status: isProviderErr ? err.status : void 0,
|
|
24861
|
+
errorBody: providerErrorBody
|
|
24806
24862
|
});
|
|
24807
24863
|
events.emit("provider.retry", {
|
|
24808
24864
|
sessionId: resolveEventSessionId(ctx),
|
|
@@ -24810,7 +24866,8 @@ async function runProviderWithRetry(opts) {
|
|
|
24810
24866
|
attempt: attemptNum,
|
|
24811
24867
|
delayMs: delay,
|
|
24812
24868
|
status: isProviderErr ? err.status : 0,
|
|
24813
|
-
description
|
|
24869
|
+
description,
|
|
24870
|
+
...providerErrorBody ? { errorBody: providerErrorBody } : {}
|
|
24814
24871
|
});
|
|
24815
24872
|
await new Promise((resolve17, reject) => {
|
|
24816
24873
|
let settled = false;
|
|
@@ -26580,14 +26637,14 @@ ${head}${TOOL_OUTPUT_ARTIFACT_OMISSION}${tail}`;
|
|
|
26580
26637
|
return content;
|
|
26581
26638
|
}
|
|
26582
26639
|
}
|
|
26583
|
-
function hashPermissionInput(input,
|
|
26640
|
+
function hashPermissionInput(input, scrubber2) {
|
|
26584
26641
|
let serialized;
|
|
26585
26642
|
try {
|
|
26586
26643
|
serialized = JSON.stringify(input) ?? "";
|
|
26587
26644
|
} catch {
|
|
26588
26645
|
serialized = String(input);
|
|
26589
26646
|
}
|
|
26590
|
-
return createHash7("sha256").update(
|
|
26647
|
+
return createHash7("sha256").update(scrubber2.scrub(serialized), "utf8").digest("hex");
|
|
26591
26648
|
}
|
|
26592
26649
|
function sliceUtf8Prefix(text, maxBytes) {
|
|
26593
26650
|
if (maxBytes <= 0) return "";
|
|
@@ -27902,6 +27959,38 @@ var sshManagerServer = () => ({
|
|
|
27902
27959
|
permission: "confirm",
|
|
27903
27960
|
requestTimeoutMs: 18e4
|
|
27904
27961
|
});
|
|
27962
|
+
var requirementIntakeServer = () => ({
|
|
27963
|
+
name: "requirement-intake",
|
|
27964
|
+
description: "WrongStack Requirements Intake \u2014 list intake records and file new ones (project-scoped, --writable)",
|
|
27965
|
+
transport: "stdio",
|
|
27966
|
+
command: "wstack-requirement-intake-mcp",
|
|
27967
|
+
args: ["--project-root", ".", "--writable"],
|
|
27968
|
+
permission: "auto"
|
|
27969
|
+
});
|
|
27970
|
+
var kanbanServer = () => ({
|
|
27971
|
+
name: "kanban",
|
|
27972
|
+
description: "WrongStack Kanban \u2014 inspect and manage project work boards (project-scoped, manage tier, no destructive ops)",
|
|
27973
|
+
transport: "stdio",
|
|
27974
|
+
command: "wstack-kanban-mcp",
|
|
27975
|
+
args: ["--project-root", ".", "--writable"],
|
|
27976
|
+
permission: "confirm"
|
|
27977
|
+
});
|
|
27978
|
+
var mailboxServer = () => ({
|
|
27979
|
+
name: "mailbox",
|
|
27980
|
+
description: "WrongStack Mailbox \u2014 read and send project agent mail (project-scoped, no admin/credentials)",
|
|
27981
|
+
transport: "stdio",
|
|
27982
|
+
command: "wstack-mailbox-mcp",
|
|
27983
|
+
args: ["--project-root", ".", "--actor", "external-agent", "--writable"],
|
|
27984
|
+
permission: "auto"
|
|
27985
|
+
});
|
|
27986
|
+
var codebaseIndexServer = () => ({
|
|
27987
|
+
name: "codebase-index",
|
|
27988
|
+
description: "WrongStack Codebase Index \u2014 symbol search and dependency graphs (project-scoped, --writable)",
|
|
27989
|
+
transport: "stdio",
|
|
27990
|
+
command: "wstack-codebase-index-mcp",
|
|
27991
|
+
args: ["--project-root", ".", "--writable"],
|
|
27992
|
+
permission: "auto"
|
|
27993
|
+
});
|
|
27905
27994
|
var allServers = () => ({
|
|
27906
27995
|
filesystem: { ...filesystemServer(), enabled: false },
|
|
27907
27996
|
github: { ...githubServer(), enabled: false },
|
|
@@ -27916,7 +28005,11 @@ var allServers = () => ({
|
|
|
27916
28005
|
"zai-vision": { ...zaiVisionServer(), enabled: false },
|
|
27917
28006
|
"minimax-vision": { ...miniMaxVisionServer(), enabled: false },
|
|
27918
28007
|
playwright: { ...playwrightServer(), enabled: false },
|
|
27919
|
-
ssh: { ...sshManagerServer(), enabled: false }
|
|
28008
|
+
ssh: { ...sshManagerServer(), enabled: false },
|
|
28009
|
+
kanban: { ...kanbanServer(), enabled: false },
|
|
28010
|
+
mailbox: { ...mailboxServer(), enabled: false },
|
|
28011
|
+
"codebase-index": { ...codebaseIndexServer(), enabled: false },
|
|
28012
|
+
"requirement-intake": { ...requirementIntakeServer(), enabled: false }
|
|
27920
28013
|
});
|
|
27921
28014
|
|
|
27922
28015
|
// src/models/codex-catalog.ts
|
|
@@ -31866,6 +31959,15 @@ var IN_PROJECT_DENIED_PATHS = [
|
|
|
31866
31959
|
reason: "Extends the exec allow-list; a repo could authorise its own binaries."
|
|
31867
31960
|
},
|
|
31868
31961
|
{ path: "tools.exec.danger", reason: "Weakens the destructive-command banner." },
|
|
31962
|
+
{
|
|
31963
|
+
// The whole subtree, not just the dangerous leaves: a persona's
|
|
31964
|
+
// `instruction` is rendered into the voter SYSTEM prompt, a profile seat
|
|
31965
|
+
// may pin providerId/model, and `defaultProfile` selects which of those
|
|
31966
|
+
// runs when the agent names no profile. Denying the parent leaves no leaf
|
|
31967
|
+
// to reclassify wrongly later.
|
|
31968
|
+
path: "tools.council",
|
|
31969
|
+
reason: "Council tool panel definitions: persona instructions are injected into the voter SYSTEM prompt and profile seats can pin an attacker-chosen providerId/model."
|
|
31970
|
+
},
|
|
31869
31971
|
{ path: "skills.extraDirs", reason: "Loads skill definitions from repo-chosen directories." },
|
|
31870
31972
|
{ path: "skills.registryUrl", reason: "Redirects skill installs to a repo-chosen host." },
|
|
31871
31973
|
// Deliberately NOT denied: skills.mode and skills.eagerMaxChars. The audit
|
package/dist/design/index.js
CHANGED
|
@@ -91,7 +91,9 @@ function safeProfileName(name) {
|
|
|
91
91
|
function activeProfileName(globalRoot) {
|
|
92
92
|
try {
|
|
93
93
|
const parsed = JSON.parse(fs.readFileSync(path.join(globalRoot, "config.json"), "utf8"));
|
|
94
|
-
return safeProfileName(
|
|
94
|
+
return safeProfileName(
|
|
95
|
+
typeof parsed.activeProfile === "string" ? parsed.activeProfile : void 0
|
|
96
|
+
);
|
|
95
97
|
} catch {
|
|
96
98
|
return "default";
|
|
97
99
|
}
|
|
@@ -171,6 +173,7 @@ function resolveWstackPaths(opts) {
|
|
|
171
173
|
projectPlan: path.join(projectDir, "plan.json"),
|
|
172
174
|
projectAutophase: path.join(projectDir, "autophase"),
|
|
173
175
|
projectSddBoards: path.join(projectDir, "sdd-boards"),
|
|
176
|
+
projectRequirementIntakes: path.join(projectDir, "requirement-intakes"),
|
|
174
177
|
syncConfig: path.join(profileDir, "sync.json"),
|
|
175
178
|
configHistoryDir: path.join(globalRoot, "config-history"),
|
|
176
179
|
projectStatus: (projectHash2) => path.join(globalRoot, "projects", projectHash2, "status.json")
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
* - maintainer — evaluates complexity, compatibility, long-term ownership.
|
|
14
14
|
* - user-advocate — evaluates from the affected user's perspective.
|
|
15
15
|
*
|
|
16
|
+
* Any other persona string is registered as an ad-hoc lens instead of being
|
|
17
|
+
* rejected — see `resolvePersonaRegistry`.
|
|
18
|
+
*
|
|
16
19
|
* @module council-brain
|
|
17
20
|
*/
|
|
18
21
|
import type { BrainArbiter, BrainDecisionRequest } from '../coordination/brain.js';
|
|
@@ -30,8 +33,9 @@ export interface CouncilVoter {
|
|
|
30
33
|
/** Model id this voter uses. */
|
|
31
34
|
model: string;
|
|
32
35
|
/**
|
|
33
|
-
* Decision lens. Built-ins: 'executor', 'skeptic', 'auditor'
|
|
34
|
-
* string is
|
|
36
|
+
* Decision lens. Built-ins: 'executor', 'skeptic', 'auditor', 'security',
|
|
37
|
+
* 'maintainer', 'user-advocate'. Any other string is registered as an ad-hoc
|
|
38
|
+
* lens whose instruction is the string itself (see `resolvePersonaRegistry`).
|
|
35
39
|
*/
|
|
36
40
|
persona?: string | undefined;
|
|
37
41
|
/** Vote weight. Default 1. */
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import type { CouncilPersona } from '../types/council.js';
|
|
2
2
|
/** Provider-neutral personas shipped with every Council installation. */
|
|
3
3
|
export declare const BUILTIN_COUNCIL_PERSONAS: readonly CouncilPersona[];
|
|
4
|
+
/**
|
|
5
|
+
* Built-in persona ids in display order.
|
|
6
|
+
*
|
|
7
|
+
* The single source every surface cycles through. The TUI panel, the WebUI
|
|
8
|
+
* settings section and `/brain council` each used to hard-code
|
|
9
|
+
* `['executor','skeptic','auditor']`, which is why `security`, `maintainer`
|
|
10
|
+
* and `user-advocate` shipped in the registry but were unreachable from any
|
|
11
|
+
* UI — exactly the lenses `risk-review` is built around.
|
|
12
|
+
*/
|
|
13
|
+
export declare const BUILTIN_COUNCIL_PERSONA_IDS: readonly string[];
|
|
4
14
|
/** Immutable registry of trusted Council persona definitions. */
|
|
5
15
|
export declare class CouncilPersonaRegistry {
|
|
6
16
|
private readonly byId;
|
|
@@ -7,7 +7,7 @@ export { BRAIN_EVALUATION_CASE_VERSION, type BrainEvaluationCaseResult, type Bra
|
|
|
7
7
|
export { type BrainApplyResult, type BrainConfigPatch, type BrainConfigSnapshot, type BrainCouncilMinRisk, type BrainCouncilPatch, type BrainDefaultsContext, type BrainPoolStrategy, type BrainRuntime, type BrainRuntimeLedgerHost, type BrainRuntimeOptions, createBrainRuntime, resolveBrainConfigDefaults, } from './brain-runtime.js';
|
|
8
8
|
export { COUNCIL_REFUSE_OPTION_ID, type CouncilBrainOptions, type CouncilVoter, createCouncilBrainArbiter, } from './council-brain.js';
|
|
9
9
|
export { type CouncilResolution, type CouncilResolutionInput, type CouncilResolutionSeat, type CouncilResolutionVote, resolveCouncilVotes, } from './council-resolution.js';
|
|
10
|
-
export { BUILTIN_COUNCIL_PERSONAS, CouncilPersonaRegistry, createCouncilPersonaRegistry, DEFAULT_COUNCIL_PERSONA_REGISTRY, } from './council-personas.js';
|
|
10
|
+
export { BUILTIN_COUNCIL_PERSONA_IDS, BUILTIN_COUNCIL_PERSONAS, CouncilPersonaRegistry, createCouncilPersonaRegistry, DEFAULT_COUNCIL_PERSONA_REGISTRY, } from './council-personas.js';
|
|
11
11
|
export { BUILTIN_COUNCIL_PROFILES, CouncilProfileRegistry, createCouncilProfileRegistry, DEFAULT_COUNCIL_APPROVAL_FRACTION, DEFAULT_COUNCIL_JUDGE_MAX_TOKENS, DEFAULT_COUNCIL_OVERALL_TIMEOUT_MS, DEFAULT_COUNCIL_PER_CALL_TIMEOUT_MS, DEFAULT_COUNCIL_PROFILE_REGISTRY, DEFAULT_COUNCIL_QUORUM_FRACTION, DEFAULT_COUNCIL_VOTER_MAX_TOKENS, normalizeCouncilProfile, resolveCouncilProfile, } from './council-profiles.js';
|
|
12
12
|
export { buildCouncilJudgeSystemPrompt, buildCouncilJudgeUserPrompt, buildCouncilQuestionPrompt, buildCouncilVoterSystemPrompt, buildCouncilVoterUserPrompt, COUNCIL_JUDGE_PROMPT_PATH, COUNCIL_VOTER_PROMPT_PATH, } from './council-prompts.js';
|
|
13
13
|
export { COUNCIL_REFUSAL_OPTION_ID, CouncilOrchestrator, type CouncilOrchestratorOptions, DEFAULT_COUNCIL_MAX_CONCURRENCY, MAX_COUNCIL_CONCURRENCY, } from './council-orchestrator.js';
|