@wrongstack/core 0.298.3 → 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/plugin/index.js
CHANGED
|
@@ -2603,7 +2603,9 @@ function safeProfileName(name) {
|
|
|
2603
2603
|
function activeProfileName(globalRoot) {
|
|
2604
2604
|
try {
|
|
2605
2605
|
const parsed = JSON.parse(fs.readFileSync(path.join(globalRoot, "config.json"), "utf8"));
|
|
2606
|
-
return safeProfileName(
|
|
2606
|
+
return safeProfileName(
|
|
2607
|
+
typeof parsed.activeProfile === "string" ? parsed.activeProfile : void 0
|
|
2608
|
+
);
|
|
2607
2609
|
} catch {
|
|
2608
2610
|
return "default";
|
|
2609
2611
|
}
|
|
@@ -2683,6 +2685,7 @@ function resolveWstackPaths(opts) {
|
|
|
2683
2685
|
projectPlan: path.join(projectDir, "plan.json"),
|
|
2684
2686
|
projectAutophase: path.join(projectDir, "autophase"),
|
|
2685
2687
|
projectSddBoards: path.join(projectDir, "sdd-boards"),
|
|
2688
|
+
projectRequirementIntakes: path.join(projectDir, "requirement-intakes"),
|
|
2686
2689
|
syncConfig: path.join(profileDir, "sync.json"),
|
|
2687
2690
|
configHistoryDir: path.join(globalRoot, "config-history"),
|
|
2688
2691
|
projectStatus: (projectHash2) => path.join(globalRoot, "projects", projectHash2, "status.json")
|
package/dist/storage/index.js
CHANGED
|
@@ -879,7 +879,9 @@ function safeProfileName(name) {
|
|
|
879
879
|
function activeProfileName(globalRoot) {
|
|
880
880
|
try {
|
|
881
881
|
const parsed = JSON.parse(fs2.readFileSync(path2.join(globalRoot, "config.json"), "utf8"));
|
|
882
|
-
return safeProfileName(
|
|
882
|
+
return safeProfileName(
|
|
883
|
+
typeof parsed.activeProfile === "string" ? parsed.activeProfile : void 0
|
|
884
|
+
);
|
|
883
885
|
} catch {
|
|
884
886
|
return "default";
|
|
885
887
|
}
|
|
@@ -959,6 +961,7 @@ function resolveWstackPaths(opts) {
|
|
|
959
961
|
projectPlan: path2.join(projectDir, "plan.json"),
|
|
960
962
|
projectAutophase: path2.join(projectDir, "autophase"),
|
|
961
963
|
projectSddBoards: path2.join(projectDir, "sdd-boards"),
|
|
964
|
+
projectRequirementIntakes: path2.join(projectDir, "requirement-intakes"),
|
|
962
965
|
syncConfig: path2.join(profileDir, "sync.json"),
|
|
963
966
|
configHistoryDir: path2.join(globalRoot, "config-history"),
|
|
964
967
|
projectStatus: (projectHash2) => path2.join(globalRoot, "projects", projectHash2, "status.json")
|
|
@@ -6920,6 +6923,15 @@ var IN_PROJECT_DENIED_PATHS = [
|
|
|
6920
6923
|
reason: "Extends the exec allow-list; a repo could authorise its own binaries."
|
|
6921
6924
|
},
|
|
6922
6925
|
{ path: "tools.exec.danger", reason: "Weakens the destructive-command banner." },
|
|
6926
|
+
{
|
|
6927
|
+
// The whole subtree, not just the dangerous leaves: a persona's
|
|
6928
|
+
// `instruction` is rendered into the voter SYSTEM prompt, a profile seat
|
|
6929
|
+
// may pin providerId/model, and `defaultProfile` selects which of those
|
|
6930
|
+
// runs when the agent names no profile. Denying the parent leaves no leaf
|
|
6931
|
+
// to reclassify wrongly later.
|
|
6932
|
+
path: "tools.council",
|
|
6933
|
+
reason: "Council tool panel definitions: persona instructions are injected into the voter SYSTEM prompt and profile seats can pin an attacker-chosen providerId/model."
|
|
6934
|
+
},
|
|
6923
6935
|
{ path: "skills.extraDirs", reason: "Loads skill definitions from repo-chosen directories." },
|
|
6924
6936
|
{ path: "skills.registryUrl", reason: "Redirects skill installs to a repo-chosen host." },
|
|
6925
6937
|
// Deliberately NOT denied: skills.mode and skills.eagerMaxChars. The audit
|
|
@@ -2,7 +2,7 @@ import type { FallbackProfileManager } from '../core/fallback-profile-manager.js
|
|
|
2
2
|
import type { CouncilLLMCaller, CouncilOption, CouncilProfileConfig, CouncilResult } from '../types/council.js';
|
|
3
3
|
import type { Tool } from '../types/tool.js';
|
|
4
4
|
import type { CouncilPersonaRegistry } from '../execution/council-personas.js';
|
|
5
|
-
import type
|
|
5
|
+
import { type CouncilProfileRegistry } from '../execution/council-profiles.js';
|
|
6
6
|
export declare const COUNCIL_TOOL_NAME = "council";
|
|
7
7
|
export declare const MAX_COUNCIL_TOOL_OPTIONS = 12;
|
|
8
8
|
export declare const MAX_COUNCIL_QUESTION_CHARS = 20000;
|
package/dist/tools/index.js
CHANGED
|
@@ -46,6 +46,9 @@ var BUILTIN_COUNCIL_PERSONAS = Object.freeze([
|
|
|
46
46
|
tags: ["users", "usability", "accessibility"]
|
|
47
47
|
})
|
|
48
48
|
]);
|
|
49
|
+
var BUILTIN_COUNCIL_PERSONA_IDS = Object.freeze(
|
|
50
|
+
BUILTIN_COUNCIL_PERSONAS.map((persona) => persona.id)
|
|
51
|
+
);
|
|
49
52
|
var CouncilPersonaRegistry = class _CouncilPersonaRegistry {
|
|
50
53
|
byId;
|
|
51
54
|
constructor(personas = []) {
|
|
@@ -1238,7 +1241,7 @@ var INPUT_SCHEMA = {
|
|
|
1238
1241
|
},
|
|
1239
1242
|
profile: {
|
|
1240
1243
|
type: "string",
|
|
1241
|
-
description:
|
|
1244
|
+
description: 'Registered Council profile id (e.g. "balanced", "fast", "risk-review"). Defaults to the host-configured profile.'
|
|
1242
1245
|
}
|
|
1243
1246
|
},
|
|
1244
1247
|
required: ["question"],
|
|
@@ -1249,10 +1252,12 @@ function createCouncilTool(opts) {
|
|
|
1249
1252
|
...opts,
|
|
1250
1253
|
fallbackProfileManager: opts.fallbackProfileManager
|
|
1251
1254
|
});
|
|
1255
|
+
const profiles = opts.profiles ?? DEFAULT_COUNCIL_PROFILE_REGISTRY;
|
|
1256
|
+
const profileIds = profiles.list().map((profile) => profile.id);
|
|
1252
1257
|
return {
|
|
1253
1258
|
name: COUNCIL_TOOL_NAME,
|
|
1254
1259
|
description: "Ask an independent, multi-persona Council to evaluate a decision or synthesize an answer. Uses bounded parallel voters, quorum/veto/weighted resolution, optional judging, model routing, fallback chains, and cancellation.",
|
|
1255
|
-
usageHint:
|
|
1260
|
+
usageHint: `Use for consequential or disputed decisions that benefit from independent lenses. Provide \`options\` for a vote or omit them for an open answer. Keep context evidence-focused; the Council treats it as untrusted data. Available profiles: ${profileIds.join(", ")}.`,
|
|
1256
1261
|
category: "meta",
|
|
1257
1262
|
inputSchema: INPUT_SCHEMA,
|
|
1258
1263
|
permission: "auto",
|
|
@@ -1270,11 +1275,17 @@ function createCouncilTool(opts) {
|
|
|
1270
1275
|
};
|
|
1271
1276
|
return orchestrator.ask(question);
|
|
1272
1277
|
},
|
|
1273
|
-
validate: validateCouncilToolInput
|
|
1278
|
+
validate: (input) => validateCouncilToolInput(input, profileIds)
|
|
1274
1279
|
};
|
|
1275
1280
|
}
|
|
1276
|
-
function validateCouncilToolInput(input) {
|
|
1281
|
+
function validateCouncilToolInput(input, profileIds) {
|
|
1277
1282
|
const errors = [];
|
|
1283
|
+
if (typeof input.profile === "string" && input.profile.trim()) {
|
|
1284
|
+
const id = input.profile.trim();
|
|
1285
|
+
if (!profileIds.includes(id)) {
|
|
1286
|
+
errors.push(`Unknown \`profile\` "${id}". Available: ${profileIds.join(", ")}.`);
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1278
1289
|
const question = input.question?.trim() ?? "";
|
|
1279
1290
|
if (!question) errors.push("`question` must not be empty.");
|
|
1280
1291
|
if (question.length > MAX_COUNCIL_QUESTION_CHARS) {
|
|
@@ -1418,7 +1429,7 @@ var FsError = class extends WrongStackError {
|
|
|
1418
1429
|
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;
|
|
1419
1430
|
|
|
1420
1431
|
// src/types/provider.ts
|
|
1421
|
-
var CONTEXT_OVERFLOW_RE = /context.length|context.window|maximum context|max.*tokens?.*exceeded|prompt
|
|
1432
|
+
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;
|
|
1422
1433
|
var CONTENT_FILTER_RE = /content.(filter|policy|moderation)|safety (system|filter)/i;
|
|
1423
1434
|
var RATE_LIMIT_EXCEEDED_RE = /rate[-_\s]*limit[-_\s]*exceeded/i;
|
|
1424
1435
|
function classifyProviderError(status, body, message) {
|
|
@@ -1428,7 +1439,7 @@ function classifyProviderError(status, body, message) {
|
|
|
1428
1439
|
if (status === 408) return "timeout";
|
|
1429
1440
|
if (status === 599) return "stream_hang";
|
|
1430
1441
|
if (status === 402 || QUOTA_EXHAUSTED_RE.test(text)) return "quota_exhausted";
|
|
1431
|
-
if (status === 429 && body?.message && RATE_LIMIT_EXCEEDED_RE.test(body.message)) {
|
|
1442
|
+
if (status === 429 && body?.message && body.type !== "rate_limit_exceeded" && RATE_LIMIT_EXCEEDED_RE.test(body.message)) {
|
|
1432
1443
|
return "quota_exhausted";
|
|
1433
1444
|
}
|
|
1434
1445
|
if (type === "rate_limit_error" || status === 429) return "rate_limit";
|
|
@@ -1488,7 +1499,7 @@ var ProviderError = class extends WrongStackError {
|
|
|
1488
1499
|
const e = err;
|
|
1489
1500
|
const name = e.name;
|
|
1490
1501
|
if (typeof name !== "string" || !name.endsWith("Error")) return false;
|
|
1491
|
-
return typeof e.status === "number" && typeof e.retryable === "boolean" && typeof e.kind === "string";
|
|
1502
|
+
return typeof e.status === "number" && typeof e.retryable === "boolean" && typeof e.kind === "string" && typeof e.describe === "function";
|
|
1492
1503
|
}
|
|
1493
1504
|
constructor(message, status, retryable, providerId, opts = {}) {
|
|
1494
1505
|
const kind = opts.kind ?? classifyProviderError(status, opts.body, message);
|
|
@@ -2216,7 +2227,9 @@ function safeProfileName(name) {
|
|
|
2216
2227
|
function activeProfileName(globalRoot) {
|
|
2217
2228
|
try {
|
|
2218
2229
|
const parsed = JSON.parse(fs.readFileSync(path2.join(globalRoot, "config.json"), "utf8"));
|
|
2219
|
-
return safeProfileName(
|
|
2230
|
+
return safeProfileName(
|
|
2231
|
+
typeof parsed.activeProfile === "string" ? parsed.activeProfile : void 0
|
|
2232
|
+
);
|
|
2220
2233
|
} catch {
|
|
2221
2234
|
return "default";
|
|
2222
2235
|
}
|
|
@@ -2296,6 +2309,7 @@ function resolveWstackPaths(opts) {
|
|
|
2296
2309
|
projectPlan: path2.join(projectDir, "plan.json"),
|
|
2297
2310
|
projectAutophase: path2.join(projectDir, "autophase"),
|
|
2298
2311
|
projectSddBoards: path2.join(projectDir, "sdd-boards"),
|
|
2312
|
+
projectRequirementIntakes: path2.join(projectDir, "requirement-intakes"),
|
|
2299
2313
|
syncConfig: path2.join(profileDir, "sync.json"),
|
|
2300
2314
|
configHistoryDir: path2.join(globalRoot, "config-history"),
|
|
2301
2315
|
projectStatus: (projectHash2) => path2.join(globalRoot, "projects", projectHash2, "status.json")
|
|
@@ -7187,6 +7201,38 @@ var sshManagerServer = () => ({
|
|
|
7187
7201
|
permission: "confirm",
|
|
7188
7202
|
requestTimeoutMs: 18e4
|
|
7189
7203
|
});
|
|
7204
|
+
var requirementIntakeServer = () => ({
|
|
7205
|
+
name: "requirement-intake",
|
|
7206
|
+
description: "WrongStack Requirements Intake \u2014 list intake records and file new ones (project-scoped, --writable)",
|
|
7207
|
+
transport: "stdio",
|
|
7208
|
+
command: "wstack-requirement-intake-mcp",
|
|
7209
|
+
args: ["--project-root", ".", "--writable"],
|
|
7210
|
+
permission: "auto"
|
|
7211
|
+
});
|
|
7212
|
+
var kanbanServer = () => ({
|
|
7213
|
+
name: "kanban",
|
|
7214
|
+
description: "WrongStack Kanban \u2014 inspect and manage project work boards (project-scoped, manage tier, no destructive ops)",
|
|
7215
|
+
transport: "stdio",
|
|
7216
|
+
command: "wstack-kanban-mcp",
|
|
7217
|
+
args: ["--project-root", ".", "--writable"],
|
|
7218
|
+
permission: "confirm"
|
|
7219
|
+
});
|
|
7220
|
+
var mailboxServer = () => ({
|
|
7221
|
+
name: "mailbox",
|
|
7222
|
+
description: "WrongStack Mailbox \u2014 read and send project agent mail (project-scoped, no admin/credentials)",
|
|
7223
|
+
transport: "stdio",
|
|
7224
|
+
command: "wstack-mailbox-mcp",
|
|
7225
|
+
args: ["--project-root", ".", "--actor", "external-agent", "--writable"],
|
|
7226
|
+
permission: "auto"
|
|
7227
|
+
});
|
|
7228
|
+
var codebaseIndexServer = () => ({
|
|
7229
|
+
name: "codebase-index",
|
|
7230
|
+
description: "WrongStack Codebase Index \u2014 symbol search and dependency graphs (project-scoped, --writable)",
|
|
7231
|
+
transport: "stdio",
|
|
7232
|
+
command: "wstack-codebase-index-mcp",
|
|
7233
|
+
args: ["--project-root", ".", "--writable"],
|
|
7234
|
+
permission: "auto"
|
|
7235
|
+
});
|
|
7190
7236
|
var allServers = () => ({
|
|
7191
7237
|
filesystem: { ...filesystemServer(), enabled: false },
|
|
7192
7238
|
github: { ...githubServer(), enabled: false },
|
|
@@ -7201,7 +7247,11 @@ var allServers = () => ({
|
|
|
7201
7247
|
"zai-vision": { ...zaiVisionServer(), enabled: false },
|
|
7202
7248
|
"minimax-vision": { ...miniMaxVisionServer(), enabled: false },
|
|
7203
7249
|
playwright: { ...playwrightServer(), enabled: false },
|
|
7204
|
-
ssh: { ...sshManagerServer(), enabled: false }
|
|
7250
|
+
ssh: { ...sshManagerServer(), enabled: false },
|
|
7251
|
+
kanban: { ...kanbanServer(), enabled: false },
|
|
7252
|
+
mailbox: { ...mailboxServer(), enabled: false },
|
|
7253
|
+
"codebase-index": { ...codebaseIndexServer(), enabled: false },
|
|
7254
|
+
"requirement-intake": { ...requirementIntakeServer(), enabled: false }
|
|
7205
7255
|
});
|
|
7206
7256
|
|
|
7207
7257
|
// src/utils/config-json.ts
|
|
@@ -7788,7 +7838,8 @@ var OneShotOrchestrator = class {
|
|
|
7788
7838
|
resolveTarget(input, config) {
|
|
7789
7839
|
if (input.role && this.opts.modelRouter) {
|
|
7790
7840
|
const pick = this.opts.modelRouter.pickForTask(input.role, "");
|
|
7791
|
-
|
|
7841
|
+
const hasExplicitTarget = Boolean(input.providerId || input.model);
|
|
7842
|
+
if (pick && (pick.fromMatrix === true || !hasExplicitTarget)) {
|
|
7792
7843
|
return { providerId: pick.provider, model: pick.model };
|
|
7793
7844
|
}
|
|
7794
7845
|
}
|
|
@@ -170,8 +170,10 @@ export interface BrainModelEntry {
|
|
|
170
170
|
export interface BrainCouncilVoterConfig extends BrainModelEntry {
|
|
171
171
|
/**
|
|
172
172
|
* Decision lens for this seat. Built-ins: 'executor' (progress-biased),
|
|
173
|
-
* 'skeptic' (risk-hunting), 'auditor' (cost/waste-focused)
|
|
174
|
-
*
|
|
173
|
+
* 'skeptic' (risk-hunting), 'auditor' (cost/waste-focused), 'security'
|
|
174
|
+
* (trust boundaries, abuse cases), 'maintainer' (complexity, compatibility)
|
|
175
|
+
* and 'user-advocate' (usability, recovery). Any other string is registered
|
|
176
|
+
* as an ad-hoc lens whose instruction is the string itself.
|
|
175
177
|
*/
|
|
176
178
|
persona?: string | undefined;
|
|
177
179
|
/** Vote weight in the tally. Default 1. */
|
|
@@ -50,6 +50,21 @@ export interface ToolsConfig {
|
|
|
50
50
|
* it is honored from any source.
|
|
51
51
|
*/
|
|
52
52
|
exec?: ExecToolConfig | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Agent-callable `council` tool: which panel profile it runs by default and
|
|
55
|
+
* which extra lenses/profiles are available to it.
|
|
56
|
+
*
|
|
57
|
+
* Distinct from `brain.council`, which is the Brain's own decision tier —
|
|
58
|
+
* that one is convened by the Brain on high-risk questions, this one is
|
|
59
|
+
* invoked by the agent.
|
|
60
|
+
*
|
|
61
|
+
* SECURITY: in the in-project DENY list. A persona's `instruction` is
|
|
62
|
+
* rendered into the voter SYSTEM prompt, and a profile seat may pin a
|
|
63
|
+
* `providerId`/`model` — so a repo-committed config could otherwise inject
|
|
64
|
+
* system-level instructions into every seat and reroute the calls to an
|
|
65
|
+
* attacker-chosen provider. Only honoured from the active-profile config.
|
|
66
|
+
*/
|
|
67
|
+
council?: CouncilToolConfig | undefined;
|
|
53
68
|
/**
|
|
54
69
|
* Agent-loop repetition detector tuning. The detector watches two signals:
|
|
55
70
|
* consecutive effectively-identical iterations (same tool-name set + inputs
|
|
@@ -86,6 +101,90 @@ export interface LoopDetectionConfig {
|
|
|
86
101
|
*/
|
|
87
102
|
callRepeatThreshold?: number | undefined;
|
|
88
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Configuration for the agent-callable `council` tool.
|
|
106
|
+
*
|
|
107
|
+
* The Council orchestrator has always accepted custom persona and profile
|
|
108
|
+
* registries, but no host ever built one — the tool was pinned to the three
|
|
109
|
+
* built-in profiles with no way to add a lens, change the default panel, or
|
|
110
|
+
* tune concurrency. This is that surface.
|
|
111
|
+
*/
|
|
112
|
+
export interface CouncilToolConfig {
|
|
113
|
+
/**
|
|
114
|
+
* Profile the tool runs when a call names none. Must be a built-in id
|
|
115
|
+
* (`balanced`, `fast`, `risk-review`) or one defined in `profiles`.
|
|
116
|
+
* Default `balanced`.
|
|
117
|
+
*/
|
|
118
|
+
defaultProfile?: string | undefined;
|
|
119
|
+
/** Seats polled concurrently, 1..8. Default 3. */
|
|
120
|
+
maxConcurrency?: number | undefined;
|
|
121
|
+
/**
|
|
122
|
+
* Extra decision lenses, registered alongside the six built-ins. Each needs
|
|
123
|
+
* a kebab-case `id`, a `name`, a `description` and the `instruction` that
|
|
124
|
+
* becomes the seat's system prompt.
|
|
125
|
+
*/
|
|
126
|
+
personas?: CouncilPersonaDefinition[] | undefined;
|
|
127
|
+
/**
|
|
128
|
+
* Extra panel profiles, registered alongside the built-ins. A profile whose
|
|
129
|
+
* id matches a built-in replaces it.
|
|
130
|
+
*/
|
|
131
|
+
profiles?: CouncilToolProfileDefinition[] | undefined;
|
|
132
|
+
}
|
|
133
|
+
/** A custom Council decision lens declared in configuration. */
|
|
134
|
+
export interface CouncilPersonaDefinition {
|
|
135
|
+
/** Kebab-case identifier, e.g. "latency-hawk". */
|
|
136
|
+
id: string;
|
|
137
|
+
name: string;
|
|
138
|
+
description: string;
|
|
139
|
+
/** Trusted system-level instruction for this lens. */
|
|
140
|
+
instruction: string;
|
|
141
|
+
defaultWeight?: number | undefined;
|
|
142
|
+
defaultVeto?: boolean | undefined;
|
|
143
|
+
tags?: string[] | undefined;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* A custom Council panel declared in configuration.
|
|
147
|
+
*
|
|
148
|
+
* Structurally the config-facing half of `CouncilProfileConfig`; kept as its
|
|
149
|
+
* own type so the config surface stays JSON-shaped (no readonly arrays) and
|
|
150
|
+
* documents itself where users read it.
|
|
151
|
+
*/
|
|
152
|
+
export interface CouncilToolProfileDefinition {
|
|
153
|
+
id: string;
|
|
154
|
+
name?: string | undefined;
|
|
155
|
+
description?: string | undefined;
|
|
156
|
+
seats: Array<{
|
|
157
|
+
id?: string | undefined;
|
|
158
|
+
label?: string | undefined;
|
|
159
|
+
/** Persona id — a built-in or one declared in `personas`. */
|
|
160
|
+
persona: string;
|
|
161
|
+
target?: {
|
|
162
|
+
providerId?: string | undefined;
|
|
163
|
+
model?: string | undefined;
|
|
164
|
+
/** Model-matrix role, resolved before the explicit target. */
|
|
165
|
+
role?: string | undefined;
|
|
166
|
+
fallbackProfile?: string | undefined;
|
|
167
|
+
fallbackModels?: string[] | undefined;
|
|
168
|
+
} | undefined;
|
|
169
|
+
weight?: number | undefined;
|
|
170
|
+
veto?: boolean | undefined;
|
|
171
|
+
}>;
|
|
172
|
+
/** `false` disables judging; omitted also means no judge. */
|
|
173
|
+
judge?: false | {
|
|
174
|
+
providerId?: string | undefined;
|
|
175
|
+
model?: string | undefined;
|
|
176
|
+
role?: string | undefined;
|
|
177
|
+
fallbackProfile?: string | undefined;
|
|
178
|
+
fallbackModels?: string[] | undefined;
|
|
179
|
+
} | undefined;
|
|
180
|
+
quorumFraction?: number | undefined;
|
|
181
|
+
approvalFraction?: number | undefined;
|
|
182
|
+
distinctness?: 'none' | 'model' | 'provider' | undefined;
|
|
183
|
+
voterMaxTokens?: number | undefined;
|
|
184
|
+
judgeMaxTokens?: number | undefined;
|
|
185
|
+
perCallTimeoutMs?: number | undefined;
|
|
186
|
+
overallTimeoutMs?: number | undefined;
|
|
187
|
+
}
|
|
89
188
|
/** Allow/deny extension of the `exec` tool's built-in command allowlist. */
|
|
90
189
|
export interface ExecToolConfig {
|
|
91
190
|
/**
|
package/dist/types/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export type { CacheTtl, Capabilities, JsonSchemaSpec, Provider, ProviderErrorBod
|
|
|
14
14
|
export { StreamHangError } from './provider.js';
|
|
15
15
|
export type { ProviderRunner, RunProviderOptions } from './provider-runner.js';
|
|
16
16
|
export { DEFAULT_TUI_THINKING_WORD, FLEET_CHAT_VERBOSITY_VALUES, MAX_TUI_THINKING_WORD_LENGTH, normalizeTokenSavingTier, normalizeTuiThinkingWord, resolveFleetChatVerbosity, resolveTokenSavingTier } from './config.js';
|
|
17
|
-
export type { AdaptiveConcurrencyConfig, AutonomyConfig, BrainConfig, BrainCouncilConfig, BrainCouncilVoterConfig, BrainModelEntry, CircuitBreakerRuntimeConfig, ConcreteTokenSavingTier, Config, ConfigLoader, ConfigStore, ContextConfig, CustomModelDefinition, ExecDangerConfig, ExecToolConfig, FeaturesConfig, FleetChatVerbosity, FleetConfig, FleetSupervisorConfig, GitBehaviorConfig, HqClientConfig, IndexingConfig, InputHistoryConfig, LaunchConfig, LaunchMenuChoice, LogConfig, LoopDetectionConfig, MCPHealthConfig, MCPHealthThresholds, MCPServerConfig, ModelMatrixEntry, ModelRuntimeCacheConfig, ModelRuntimeConfig, ModelRuntimeParametersConfig, ModelRuntimeReasoningConfig, PluginConfig, PluginManagerConfig, ProviderApiKey, ProviderConfig, SageConfig, SessionLoggingConfig, SkillsConfig, SyncCategory, SyncConfig, TokenSavingTier, ToolDescriptionMode, ToolDescriptionModeConfig, ToolResultRenderMode, ToolResultRenderModeConfig, ToolsConfig } from './config.js';
|
|
17
|
+
export type { AdaptiveConcurrencyConfig, AutonomyConfig, BrainConfig, BrainCouncilConfig, BrainCouncilVoterConfig, BrainModelEntry, CircuitBreakerRuntimeConfig, ConcreteTokenSavingTier, Config, ConfigLoader, ConfigStore, ContextConfig, CouncilPersonaDefinition, CouncilToolConfig, CouncilToolProfileDefinition, CustomModelDefinition, ExecDangerConfig, ExecToolConfig, FeaturesConfig, FleetChatVerbosity, FleetConfig, FleetSupervisorConfig, GitBehaviorConfig, HqClientConfig, IndexingConfig, InputHistoryConfig, LaunchConfig, LaunchMenuChoice, LogConfig, LoopDetectionConfig, MCPHealthConfig, MCPHealthThresholds, MCPServerConfig, ModelMatrixEntry, ModelRuntimeCacheConfig, ModelRuntimeConfig, ModelRuntimeParametersConfig, ModelRuntimeReasoningConfig, PluginConfig, PluginManagerConfig, ProviderApiKey, ProviderConfig, SageConfig, SessionLoggingConfig, SkillsConfig, SyncCategory, SyncConfig, TokenSavingTier, ToolDescriptionMode, ToolDescriptionModeConfig, ToolResultRenderMode, ToolResultRenderModeConfig, ToolsConfig } from './config.js';
|
|
18
18
|
export type { AnyHookOutcome, ConfiguredHook, HookEntry, HookEvent, HookFailurePolicy, HookInput, HookInvocationContext, HookMatcher, HookOutcome, HookRegistrationOptions, HttpHook, InProcessHook, PreToolUseOutcome, PreToolUseStage, ShellHook } from './hooks.js';
|
|
19
19
|
export type { Compactor, CompactReport } from './compactor.js';
|
|
20
20
|
export type { DirectoryPolicy, DirectoryRule, PermissionDecision, PermissionPolicy, PermissionTrace, PermissionTraceStep, TrustPolicy } from './permission.js';
|
|
@@ -50,6 +50,7 @@ export { CONTEXT_WINDOW_MODES, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEPRECATED_CONTEX
|
|
|
50
50
|
export type { ContextSnapshot, ContextWindowAggressiveOn, ContextWindowConfigLike, ContextWindowMode, ContextWindowModeId, ContextWindowModeSelectionId, ContextWindowPolicy, ContextWindowThresholds, DeprecatedContextWindowModeId } from './context-window.js';
|
|
51
51
|
export type { CompletedWorkEvidence, CompletedWorkSource, ContextEvidenceState, ContextFileEvidence, ContextIntentEvidence, ContextRepeatedReadEvidence, ToolEvidenceStatus, ToolOutputMetadata } from './context-evidence.js';
|
|
52
52
|
export type { CouncilDistinctness, CouncilLLMCaller, CouncilModelTarget, CouncilOption, CouncilPersona, CouncilProfileConfig, CouncilQuestion, CouncilResolutionMethod, CouncilResult, CouncilSeatConfig, CouncilUsage, CouncilVoteResult, CouncilVoteStatus, ResolvedCouncilProfile, ResolvedCouncilSeat } from './council.js';
|
|
53
|
+
export type { OneShotLLMInput, OneShotLLMResult, OneShotModelPick, OneShotModelRouter, OneShotOrchestratorOptions } from './one-shot-llm.js';
|
|
53
54
|
export type { AwaitAnyResult, CoordinatorEvents, CoordinatorStatus, DoneCondition, MultiAgentConfig, MultiAgentCoordinator, SpawnResult, SubagentConfig, SubagentContext, SubagentError, SubagentErrorKind, SubagentPartialResult, SubagentRunContext, SubagentRunOutcome, SubagentRunner, SubagentSpawnLineage, SubagentStructuredReport, TaskDelegation, TaskResult, TaskSpec } from './multi-agent.js';
|
|
54
55
|
export { DEFAULT_SPEC_TEMPLATE } from './spec.js';
|
|
55
56
|
export type { SpecAnalysis, SpecApiEndpoint, SpecRequirement, SpecSection, SpecSectionType, SpecStatus, SpecTemplate, SpecValidationResult, Specification } from './spec.js';
|
package/dist/types/index.js
CHANGED
|
@@ -324,7 +324,7 @@ var QUOTA_EXHAUSTED_RE = /(?:insufficient|exhausted|depleted|exceeded|no|not eno
|
|
|
324
324
|
function effectiveInputTokens(usage) {
|
|
325
325
|
return usage.input + (usage.cacheRead ?? 0) + (usage.cacheWrite ?? 0);
|
|
326
326
|
}
|
|
327
|
-
var CONTEXT_OVERFLOW_RE = /context.length|context.window|maximum context|max.*tokens?.*exceeded|prompt
|
|
327
|
+
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;
|
|
328
328
|
var CONTENT_FILTER_RE = /content.(filter|policy|moderation)|safety (system|filter)/i;
|
|
329
329
|
var RATE_LIMIT_EXCEEDED_RE = /rate[-_\s]*limit[-_\s]*exceeded/i;
|
|
330
330
|
function classifyProviderError(status, body, message) {
|
|
@@ -334,7 +334,7 @@ function classifyProviderError(status, body, message) {
|
|
|
334
334
|
if (status === 408) return "timeout";
|
|
335
335
|
if (status === 599) return "stream_hang";
|
|
336
336
|
if (status === 402 || QUOTA_EXHAUSTED_RE.test(text)) return "quota_exhausted";
|
|
337
|
-
if (status === 429 && body?.message && RATE_LIMIT_EXCEEDED_RE.test(body.message)) {
|
|
337
|
+
if (status === 429 && body?.message && body.type !== "rate_limit_exceeded" && RATE_LIMIT_EXCEEDED_RE.test(body.message)) {
|
|
338
338
|
return "quota_exhausted";
|
|
339
339
|
}
|
|
340
340
|
if (type === "rate_limit_error" || status === 429) return "rate_limit";
|
|
@@ -411,7 +411,7 @@ var ProviderError = class extends WrongStackError {
|
|
|
411
411
|
const e = err;
|
|
412
412
|
const name = e.name;
|
|
413
413
|
if (typeof name !== "string" || !name.endsWith("Error")) return false;
|
|
414
|
-
return typeof e.status === "number" && typeof e.retryable === "boolean" && typeof e.kind === "string";
|
|
414
|
+
return typeof e.status === "number" && typeof e.retryable === "boolean" && typeof e.kind === "string" && typeof e.describe === "function";
|
|
415
415
|
}
|
|
416
416
|
constructor(message, status, retryable, providerId, opts = {}) {
|
|
417
417
|
const kind = opts.kind ?? classifyProviderError(status, opts.body, message);
|
|
@@ -100,6 +100,21 @@ export interface OneShotLLMResult {
|
|
|
100
100
|
*/
|
|
101
101
|
error?: string | undefined;
|
|
102
102
|
}
|
|
103
|
+
/** One role→model resolution. Mirrors `ModelPick` from the ModelRouter. */
|
|
104
|
+
export interface OneShotModelPick {
|
|
105
|
+
provider: string;
|
|
106
|
+
model: string;
|
|
107
|
+
/**
|
|
108
|
+
* True when the pick came from the user's `/setmodel` matrix (explicit
|
|
109
|
+
* intent) rather than from capability heuristics. Only a matrix pick may
|
|
110
|
+
* override a caller's explicit `providerId`/`model`.
|
|
111
|
+
*/
|
|
112
|
+
fromMatrix?: boolean | undefined;
|
|
113
|
+
}
|
|
114
|
+
/** Minimal router contract consumed by role-based routing. */
|
|
115
|
+
export interface OneShotModelRouter {
|
|
116
|
+
pickForTask(role: string, description: string): OneShotModelPick | undefined;
|
|
117
|
+
}
|
|
103
118
|
/**
|
|
104
119
|
* Dependencies for OneShotOrchestrator.
|
|
105
120
|
*/
|
|
@@ -119,10 +134,14 @@ export interface OneShotOrchestratorOptions {
|
|
|
119
134
|
*/
|
|
120
135
|
fallbackProfileManager: import('../core/fallback-profile-manager.js').FallbackProfileManager;
|
|
121
136
|
/**
|
|
122
|
-
* Optional
|
|
123
|
-
*
|
|
137
|
+
* Optional role→model router. When absent, role-based routing is skipped
|
|
138
|
+
* and `role` on an input is inert.
|
|
139
|
+
*
|
|
140
|
+
* Structurally typed rather than pinned to the concrete `ModelRouter` class
|
|
141
|
+
* so a host can supply a router rebuilt from the LIVE config on every call
|
|
142
|
+
* (the `/setmodel` matrix changes mid-session). `ModelRouter` satisfies it.
|
|
124
143
|
*/
|
|
125
|
-
modelRouter?:
|
|
144
|
+
modelRouter?: OneShotModelRouter | undefined;
|
|
126
145
|
/**
|
|
127
146
|
* Optional logger for fallback warnings.
|
|
128
147
|
*/
|
package/dist/types/session.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ContentBlock } from './blocks.js';
|
|
2
2
|
import type { Message } from './messages.js';
|
|
3
|
-
import type { Usage } from './provider.js';
|
|
3
|
+
import type { ProviderErrorBody, Usage } from './provider.js';
|
|
4
4
|
export interface SessionMetadata {
|
|
5
5
|
id: string;
|
|
6
6
|
title?: string | undefined;
|
|
@@ -295,6 +295,8 @@ export type SessionEvent = {
|
|
|
295
295
|
delayMs: number;
|
|
296
296
|
status?: number | undefined;
|
|
297
297
|
description: string;
|
|
298
|
+
/** Scrubbed raw provider error envelope/body for post-run diagnosis. */
|
|
299
|
+
errorBody?: ProviderErrorBody | undefined;
|
|
298
300
|
} | {
|
|
299
301
|
type: 'provider_error';
|
|
300
302
|
ts: string;
|
|
@@ -302,6 +304,8 @@ export type SessionEvent = {
|
|
|
302
304
|
status?: number | undefined;
|
|
303
305
|
description: string;
|
|
304
306
|
retryable: boolean;
|
|
307
|
+
/** Scrubbed raw provider error envelope/body for post-run diagnosis. */
|
|
308
|
+
errorBody?: ProviderErrorBody | undefined;
|
|
305
309
|
} | {
|
|
306
310
|
type: 'checkpoint';
|
|
307
311
|
ts: string;
|
package/dist/utils/index.js
CHANGED
|
@@ -2478,7 +2478,9 @@ function safeProfileName(name) {
|
|
|
2478
2478
|
function activeProfileName(globalRoot) {
|
|
2479
2479
|
try {
|
|
2480
2480
|
const parsed = JSON.parse(fs3.readFileSync(path3.join(globalRoot, "config.json"), "utf8"));
|
|
2481
|
-
return safeProfileName(
|
|
2481
|
+
return safeProfileName(
|
|
2482
|
+
typeof parsed.activeProfile === "string" ? parsed.activeProfile : void 0
|
|
2483
|
+
);
|
|
2482
2484
|
} catch {
|
|
2483
2485
|
return "default";
|
|
2484
2486
|
}
|
|
@@ -2558,6 +2560,7 @@ function resolveWstackPaths(opts) {
|
|
|
2558
2560
|
projectPlan: path3.join(projectDir, "plan.json"),
|
|
2559
2561
|
projectAutophase: path3.join(projectDir, "autophase"),
|
|
2560
2562
|
projectSddBoards: path3.join(projectDir, "sdd-boards"),
|
|
2563
|
+
projectRequirementIntakes: path3.join(projectDir, "requirement-intakes"),
|
|
2561
2564
|
syncConfig: path3.join(profileDir, "sync.json"),
|
|
2562
2565
|
configHistoryDir: path3.join(globalRoot, "config-history"),
|
|
2563
2566
|
projectStatus: (projectHash2) => path3.join(globalRoot, "projects", projectHash2, "status.json")
|
|
@@ -124,6 +124,8 @@ export interface WstackPaths {
|
|
|
124
124
|
projectAutophase: string;
|
|
125
125
|
/** ~/.wrongstack/projects/<hash>/sdd-boards — live SDD board snapshots + JSONL event logs */
|
|
126
126
|
projectSddBoards: string;
|
|
127
|
+
/** ~/.wrongstack/projects/<hash>/requirement-intakes — requirement intake records */
|
|
128
|
+
projectRequirementIntakes: string;
|
|
127
129
|
/** ~/.wrongstack/profiles/<activeProfile>/sync.json — CloudSync configuration */
|
|
128
130
|
syncConfig: string;
|
|
129
131
|
/** ~/.wrongstack/config-history — timestamped backups on every config write */
|
package/dist/worktree/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/worktree/worktree-manager.ts
|
|
2
|
-
import { mkdir } from "node:fs/promises";
|
|
2
|
+
import { mkdir, readFile } from "node:fs/promises";
|
|
3
3
|
import { join, resolve as resolve3, sep as sep3 } from "node:path";
|
|
4
4
|
|
|
5
5
|
// src/utils/error.ts
|
|
@@ -523,6 +523,10 @@ ${merged.stderr}`);
|
|
|
523
523
|
* Safe because SDD merges are serialized — no other commit lands in between.
|
|
524
524
|
*/
|
|
525
525
|
async revertBaseTo(handle, sha) {
|
|
526
|
+
const status = await this.runGit(["status", "--porcelain"], this.projectRoot);
|
|
527
|
+
if (status.code !== 0) return false;
|
|
528
|
+
const hasTrackedDirt = status.stdout.split("\n").some((line) => line.trim().length > 0 && !line.startsWith("??"));
|
|
529
|
+
if (hasTrackedDirt) return false;
|
|
526
530
|
const co = await this.runGit(["checkout", handle.baseBranch], this.projectRoot);
|
|
527
531
|
if (co.code !== 0) return false;
|
|
528
532
|
const reset = await this.runGit(["reset", "--hard", sha], this.projectRoot);
|
|
@@ -737,29 +741,47 @@ ${merged.stderr}`);
|
|
|
737
741
|
/**
|
|
738
742
|
* True when staged content still carries conflict markers.
|
|
739
743
|
*
|
|
740
|
-
*
|
|
741
|
-
*
|
|
742
|
-
*
|
|
743
|
-
*
|
|
744
|
-
*
|
|
745
|
-
*
|
|
744
|
+
* Reads the working-tree files directly and matches a full marker line
|
|
745
|
+
* (`<<<<<<< `, `=======`, `>>>>>>> `, `||||||| `) with a lenient regex
|
|
746
|
+
* (`{7,}`) that stays platform- and config-independent — unlike the old
|
|
747
|
+
* `git diff --check` (only fires when `core.whitespace` opts in) and
|
|
748
|
+
* `git grep` (assumes the default 7-char markers).
|
|
749
|
+
*
|
|
750
|
+
* Scan set: when the caller supplies the conflicted paths (the normal
|
|
751
|
+
* path from {@link tryResolveConflict}), ONLY those files are scanned so
|
|
752
|
+
* an unrelated `=======` setext-heading underline in a staged document
|
|
753
|
+
* can't false-positive and discard valid resolution work. The staged-file
|
|
754
|
+
* listing (`git diff --cached --name-only`) is used only as a fallback
|
|
755
|
+
* when no paths are given.
|
|
746
756
|
*
|
|
747
|
-
*
|
|
748
|
-
*
|
|
749
|
-
*
|
|
750
|
-
*
|
|
757
|
+
* CRLF caveat: conflicted files checked out with CRLF (`core.autocrlf=true`,
|
|
758
|
+
* `.gitattributes eol=crlf`) carry bare markers as `=======\r\n`. Because
|
|
759
|
+
* `$` in multiline mode matches only before `\n`, carriage returns are
|
|
760
|
+
* stripped before matching so `\r` never defeats the end-of-line anchor.
|
|
751
761
|
*/
|
|
752
762
|
async hasConflictMarkers(files) {
|
|
753
|
-
const
|
|
754
|
-
const
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
)
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
+
const listed = files ?? [];
|
|
764
|
+
const paths = listed.length > 0 ? listed : (await this.runGit(["diff", "--cached", "--name-only", "-z"], this.projectRoot)).stdout.split("\0").filter(Boolean);
|
|
765
|
+
const marker = /^(?:<{7,}(?: |$)|={7,}$|>{7,}(?: |$)|\|{7,}(?: |$))/m;
|
|
766
|
+
const startMarker = /^(?:<{7,}(?: |$)|\|{7,}(?: |$))/m;
|
|
767
|
+
for (const rel of paths) {
|
|
768
|
+
try {
|
|
769
|
+
const content = (await readFile(join(this.projectRoot, rel), "utf8")).replace(/\r/g, "");
|
|
770
|
+
const lines = content.split("\n");
|
|
771
|
+
let seenStart = false;
|
|
772
|
+
for (const line of lines) {
|
|
773
|
+
if (!marker.test(line)) continue;
|
|
774
|
+
if (line.startsWith("=====")) {
|
|
775
|
+
if (!seenStart) continue;
|
|
776
|
+
} else if (startMarker.test(line)) {
|
|
777
|
+
seenStart = true;
|
|
778
|
+
}
|
|
779
|
+
return true;
|
|
780
|
+
}
|
|
781
|
+
} catch {
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
return false;
|
|
763
785
|
}
|
|
764
786
|
/**
|
|
765
787
|
* Remove the worktree + branch. Conflicted/failed handles (or `keep:true`)
|
|
@@ -153,17 +153,23 @@ export declare class WorktreeManager {
|
|
|
153
153
|
/**
|
|
154
154
|
* True when staged content still carries conflict markers.
|
|
155
155
|
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
* some document can't false-positive.
|
|
156
|
+
* Reads the working-tree files directly and matches a full marker line
|
|
157
|
+
* (`<<<<<<< `, `=======`, `>>>>>>> `, `||||||| `) with a lenient regex
|
|
158
|
+
* (`{7,}`) that stays platform- and config-independent — unlike the old
|
|
159
|
+
* `git diff --check` (only fires when `core.whitespace` opts in) and
|
|
160
|
+
* `git grep` (assumes the default 7-char markers).
|
|
162
161
|
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
162
|
+
* Scan set: when the caller supplies the conflicted paths (the normal
|
|
163
|
+
* path from {@link tryResolveConflict}), ONLY those files are scanned so
|
|
164
|
+
* an unrelated `=======` setext-heading underline in a staged document
|
|
165
|
+
* can't false-positive and discard valid resolution work. The staged-file
|
|
166
|
+
* listing (`git diff --cached --name-only`) is used only as a fallback
|
|
167
|
+
* when no paths are given.
|
|
168
|
+
*
|
|
169
|
+
* CRLF caveat: conflicted files checked out with CRLF (`core.autocrlf=true`,
|
|
170
|
+
* `.gitattributes eol=crlf`) carry bare markers as `=======\r\n`. Because
|
|
171
|
+
* `$` in multiline mode matches only before `\n`, carriage returns are
|
|
172
|
+
* stripped before matching so `\r` never defeats the end-of-line anchor.
|
|
167
173
|
*/
|
|
168
174
|
private hasConflictMarkers;
|
|
169
175
|
/**
|
|
@@ -40,6 +40,14 @@ deletion, history rewriting, force-push, or database destruction unless the
|
|
|
40
40
|
task explicitly requires the action and identifies the exact target. Recheck
|
|
41
41
|
the target before any destructive step.
|
|
42
42
|
|
|
43
|
+
## Codebase discovery
|
|
44
|
+
|
|
45
|
+
When the index is available, use it before broad `grep`/`glob` exploration:
|
|
46
|
+
- `codebase-search` to locate symbols, definitions, and candidate modules.
|
|
47
|
+
- `codebase-incoming-calls` to find all callers of a symbol before refactoring.
|
|
48
|
+
- `codebase-outgoing-calls` to understand a symbol's dependencies.
|
|
49
|
+
Read source files returned by search before relying on them.
|
|
50
|
+
|
|
43
51
|
## No further delegation
|
|
44
52
|
|
|
45
53
|
You MUST NOT call `delegate`, `spawn_subagent`, `assign_task`, or any equivalent.
|