@wrongstack/cli 0.298.1 → 0.298.2
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/data/README.md +51 -0
- package/dist/{auth-NLLGEYQR.js → auth-G5YKKSRH.js} +3 -3
- package/dist/chimera-reviewer-policy.d.ts +8 -1
- package/dist/{chunk-I2BM6FK6.js → chunk-L5CE52XW.js} +2 -2
- package/dist/{chunk-JBSQ7ONN.js → chunk-ZNZJ34RF.js} +1 -1
- package/dist/{cli-main-7QLL2PY6.js → cli-main-ZDZMCVLM.js} +295 -108
- package/dist/{execution-HJ643JGZ.js → execution-BY556FCF.js} +83 -8
- package/dist/execution-chimera-review.d.ts +11 -1
- package/dist/index.js +3 -3
- package/dist/live-settings-input.d.ts +8 -0
- package/package.json +22 -22
package/data/README.md
CHANGED
|
@@ -75,3 +75,54 @@ pnpm run sync:models -- --diff # what we override
|
|
|
75
75
|
Then edit `providers.json` and commit. Keep it **small and curated** — it is an override layer,
|
|
76
76
|
not a mirror of models.dev. Once models.dev catches up, drop the now-redundant override (`--diff`
|
|
77
77
|
flags those).
|
|
78
|
+
|
|
79
|
+
## Overlay vs. per-user `customModels` — when to use which
|
|
80
|
+
|
|
81
|
+
There are **two** override layers in WrongStack, for two different audiences:
|
|
82
|
+
|
|
83
|
+
| Layer | Location | Audience | Purpose |
|
|
84
|
+
|---|---|---|---|
|
|
85
|
+
| **Curated overlay** | `packages/cli/data/providers.json` (this file) | **All users, repo-wide** | Fix upstream errors, add models/providers models.dev doesn't list, remove bad entries (`_removeProviders` / `_removeModels` magic keys). Ships with every release. |
|
|
86
|
+
| **`customModels` config** | `~/.wrongstack/profiles/<name>/config.json` → `providers.<id>.customModels` | **One user, one profile** | Per-user model visibility + per-model metadata overrides (limits, cost, modalities, capability flags) via the WebUI ModelListEditor or TUI `/auth` panel. |
|
|
87
|
+
|
|
88
|
+
**Decision rule:** if the fix benefits every user of the product (an upstream data error, a brand-new
|
|
89
|
+
model id), it belongs in the **overlay** — commit it here. If it's personal tuning (my context limit,
|
|
90
|
+
my custom endpoint's pricing), it belongs in the user's **`customModels`** config — never here.
|
|
91
|
+
|
|
92
|
+
Both layers deep-merge one level into `limit` / `cost` / `modalities` objects, and both follow the
|
|
93
|
+
same precedence contract at resolution time:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
top-level config.models > providers.<id>.customModels > overlay > models.dev catalog > wire-family defaults
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The top-level `config.models` record overrides provider-local entries for the same model id
|
|
100
|
+
(`mergeCustomModelDefs` in `packages/core/src/utils/merge-custom-models.ts`). Inline
|
|
101
|
+
models.dev-style objects inside `providers.<id>.models` are normalized into `customModels` at
|
|
102
|
+
config load — they are not a separate runtime layer.
|
|
103
|
+
|
|
104
|
+
## Catalog cache & boot refresh
|
|
105
|
+
|
|
106
|
+
The live models.dev catalog is fetched at boot and cached:
|
|
107
|
+
|
|
108
|
+
- **Cache:** `~/.wrongstack/cache/models.dev.json` (fetched at startup; `--no-models-refresh`
|
|
109
|
+
skips the network fetch and uses the stale cache).
|
|
110
|
+
- **Overlay cache:** `~/.wrongstack/cache/models-overlay.json` (fetched from GitHub raw; the
|
|
111
|
+
bundled `providers.json` is the offline floor).
|
|
112
|
+
- Resolution: `merged = mergeModelsPayload(cachedModelsDev, overlay)` — the overlay always wins.
|
|
113
|
+
|
|
114
|
+
If models.dev is unreachable and no cache exists, a non-empty overlay still drives the catalog
|
|
115
|
+
on its own. Users never edit the cache files — they are regenerated on boot.
|
|
116
|
+
|
|
117
|
+
## Modalities format (important)
|
|
118
|
+
|
|
119
|
+
`modalities.input` and `modalities.output` are **plain string arrays**, not objects:
|
|
120
|
+
|
|
121
|
+
```jsonc
|
|
122
|
+
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
So `modalities.input[0] === "text"` (a string). The known values are `"text" | "image" | "audio" |
|
|
126
|
+
"video" | "pdf"` (see `MODELS_DEV_MODALITY_VALUES` in `packages/core/src/models/models-dev-schema.ts`).
|
|
127
|
+
New upstream values are tolerated at parse time — the schema validates "array of non-empty strings",
|
|
128
|
+
not a closed enum.
|
|
@@ -13,10 +13,10 @@ import {
|
|
|
13
13
|
runOAuthLoginKind,
|
|
14
14
|
runOAuthLoginMenu,
|
|
15
15
|
validateFamily
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-L5CE52XW.js";
|
|
17
17
|
import {
|
|
18
18
|
parseAuthFlags
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-ZNZJ34RF.js";
|
|
20
20
|
import "./chunk-66T43Q4Y.js";
|
|
21
21
|
import "./chunk-GO3TJICK.js";
|
|
22
22
|
import {
|
|
@@ -501,4 +501,4 @@ async function runAuthRemove(deps, providerId) {
|
|
|
501
501
|
export {
|
|
502
502
|
authCmd
|
|
503
503
|
};
|
|
504
|
-
//# sourceMappingURL=auth-
|
|
504
|
+
//# sourceMappingURL=auth-G5YKKSRH.js.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ProviderModelStatusTracker } from '@wrongstack/core/coordination';
|
|
1
2
|
import type { SubagentConfig, SubagentError, TaskResult } from '@wrongstack/core/types';
|
|
2
3
|
/**
|
|
3
4
|
* Resolve the fallback-model chain used when spawning the chimera-review
|
|
@@ -19,8 +20,14 @@ export declare function __resetReviewerRoundRobinCursor(value?: number): void;
|
|
|
19
20
|
* Builds the pool from the configured primary + fallback chain, then picks
|
|
20
21
|
* the next entry via round-robin. When the pool has <=1 usable entry the
|
|
21
22
|
* original primary/fallbacks are returned unchanged.
|
|
23
|
+
*
|
|
24
|
+
* When a {@link ProviderModelStatusTracker} is supplied, blocked entries
|
|
25
|
+
* (waiting-room / token-reset-limit room) are filtered from both the pool
|
|
26
|
+
* and the round-robin pick so a 429-stricken model is never re-spawned on
|
|
27
|
+
* a concurrent reviewer turn. Without the tracker, the legacy pre-waiting-
|
|
28
|
+
* room behavior is preserved.
|
|
22
29
|
*/
|
|
23
|
-
export declare function assignReviewerModelsRoundRobin(provider: string, model: string, fallbackModels: readonly string[]): {
|
|
30
|
+
export declare function assignReviewerModelsRoundRobin(provider: string, model: string, fallbackModels: readonly string[], statusTracker?: ProviderModelStatusTracker | undefined): {
|
|
24
31
|
provider: string;
|
|
25
32
|
model: string;
|
|
26
33
|
fallbackModels: string[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
LOCAL_LLM_PRESETS,
|
|
3
3
|
runLiveProviderPicker
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ZNZJ34RF.js";
|
|
5
5
|
import {
|
|
6
6
|
openBrowser,
|
|
7
7
|
runCodexOAuthLogin,
|
|
@@ -1327,4 +1327,4 @@ export {
|
|
|
1327
1327
|
addKeyForProvider,
|
|
1328
1328
|
runAuthLocal
|
|
1329
1329
|
};
|
|
1330
|
-
//# sourceMappingURL=chunk-
|
|
1330
|
+
//# sourceMappingURL=chunk-L5CE52XW.js.map
|
|
@@ -80,11 +80,11 @@ import {
|
|
|
80
80
|
runClaudeOAuthLogin,
|
|
81
81
|
runCopilotOAuthLogin,
|
|
82
82
|
validateFamily
|
|
83
|
-
} from "./chunk-
|
|
83
|
+
} from "./chunk-L5CE52XW.js";
|
|
84
84
|
import {
|
|
85
85
|
LOCAL_LLM_PRESETS,
|
|
86
86
|
parseSpawnFlags
|
|
87
|
-
} from "./chunk-
|
|
87
|
+
} from "./chunk-ZNZJ34RF.js";
|
|
88
88
|
import {
|
|
89
89
|
buildPickableProviders
|
|
90
90
|
} from "./chunk-66T43Q4Y.js";
|
|
@@ -381,6 +381,187 @@ function createAuthPanelHost(deps) {
|
|
|
381
381
|
return true;
|
|
382
382
|
});
|
|
383
383
|
},
|
|
384
|
+
editModelDetails(providerId, modelId, io) {
|
|
385
|
+
return runFlow(async () => {
|
|
386
|
+
const providers = await loadProviders();
|
|
387
|
+
const cfg = providers[providerId];
|
|
388
|
+
if (!cfg) {
|
|
389
|
+
io.onLog(`\u2717 Provider "${providerId}" no longer in config.`);
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
const catalogModel = await deps.modelsRegistry.getModel(
|
|
393
|
+
cfg.type && cfg.type !== providerId ? cfg.type : providerId,
|
|
394
|
+
modelId
|
|
395
|
+
).catch(() => void 0);
|
|
396
|
+
const existing = cfg.customModels?.[modelId];
|
|
397
|
+
const currentMd = existing?.modelsDev ?? {};
|
|
398
|
+
io.onLog(
|
|
399
|
+
catalogModel ? `Catalog reference: ctx=${catalogModel.capabilities.maxContext ?? "?"}, out=${catalogModel.capabilities.maxOutput ?? "?"}` : `(no catalog entry for ${modelId})`
|
|
400
|
+
);
|
|
401
|
+
const name = (await io.prompt(
|
|
402
|
+
`Name (current: ${currentMd["name"] ?? modelId})`,
|
|
403
|
+
{ secret: false }
|
|
404
|
+
)).trim();
|
|
405
|
+
const ctxRaw = (await io.prompt(
|
|
406
|
+
`Context window (current: ${currentMd.limit?.["context"] ?? "?"}, catalog: ${catalogModel?.capabilities.maxContext ?? "?"})`,
|
|
407
|
+
{ secret: false }
|
|
408
|
+
)).trim();
|
|
409
|
+
const outRaw = (await io.prompt(
|
|
410
|
+
`Max output (current: ${existing?.maxOutput ?? currentMd.limit?.["output"] ?? "?"}, catalog: ${catalogModel?.capabilities.maxOutput ?? "?"})`,
|
|
411
|
+
{ secret: false }
|
|
412
|
+
)).trim();
|
|
413
|
+
const costInRaw = (await io.prompt(
|
|
414
|
+
`Cost input $/1M (current: ${currentMd.cost?.["input"] ?? "?"}, catalog: ${catalogModel?.cost?.input ?? "?"})`,
|
|
415
|
+
{ secret: false }
|
|
416
|
+
)).trim();
|
|
417
|
+
const costOutRaw = (await io.prompt(
|
|
418
|
+
`Cost output $/1M (current: ${currentMd.cost?.["output"] ?? "?"}, catalog: ${catalogModel?.cost?.output ?? "?"})`,
|
|
419
|
+
{ secret: false }
|
|
420
|
+
)).trim();
|
|
421
|
+
const modelsDev = {};
|
|
422
|
+
if (name) modelsDev["name"] = name;
|
|
423
|
+
const limit = {};
|
|
424
|
+
if (ctxRaw) {
|
|
425
|
+
const n = Number(ctxRaw);
|
|
426
|
+
if (!Number.isNaN(n) && n >= 0) limit["context"] = n;
|
|
427
|
+
}
|
|
428
|
+
if (outRaw) {
|
|
429
|
+
const n = Number(outRaw);
|
|
430
|
+
if (!Number.isNaN(n) && n >= 0) limit["output"] = n;
|
|
431
|
+
}
|
|
432
|
+
if (Object.keys(limit).length > 0) modelsDev["limit"] = limit;
|
|
433
|
+
const cost = {};
|
|
434
|
+
if (costInRaw) {
|
|
435
|
+
const n = Number(costInRaw);
|
|
436
|
+
if (!Number.isNaN(n) && n >= 0) cost["input"] = n;
|
|
437
|
+
}
|
|
438
|
+
if (costOutRaw) {
|
|
439
|
+
const n = Number(costOutRaw);
|
|
440
|
+
if (!Number.isNaN(n) && n >= 0) cost["output"] = n;
|
|
441
|
+
}
|
|
442
|
+
if (Object.keys(cost).length > 0) modelsDev["cost"] = cost;
|
|
443
|
+
if (Object.keys(modelsDev).length === 0) {
|
|
444
|
+
io.onLog("(no changes \u2014 nothing entered)");
|
|
445
|
+
return true;
|
|
446
|
+
}
|
|
447
|
+
const err = await mutate((all) => {
|
|
448
|
+
const p = all[providerId];
|
|
449
|
+
if (!p) return `Provider "${providerId}" no longer in config.`;
|
|
450
|
+
if (!p.customModels) p.customModels = {};
|
|
451
|
+
const existingEntry = p.customModels[modelId] ?? {};
|
|
452
|
+
p.customModels[modelId] = {
|
|
453
|
+
...existingEntry,
|
|
454
|
+
modelsDev: {
|
|
455
|
+
...existingEntry.modelsDev ?? {},
|
|
456
|
+
...modelsDev,
|
|
457
|
+
// Deep-merge limit/cost so partial overrides don't wipe sub-fields
|
|
458
|
+
...limit || existingEntry.modelsDev ? {
|
|
459
|
+
limit: {
|
|
460
|
+
...existingEntry.modelsDev?.["limit"] ?? {},
|
|
461
|
+
...limit
|
|
462
|
+
}
|
|
463
|
+
} : {},
|
|
464
|
+
...cost || existingEntry.modelsDev?.["cost"] ? {
|
|
465
|
+
cost: {
|
|
466
|
+
...existingEntry.modelsDev?.["cost"] ?? {},
|
|
467
|
+
...cost
|
|
468
|
+
}
|
|
469
|
+
} : {}
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
return null;
|
|
473
|
+
});
|
|
474
|
+
if (err) {
|
|
475
|
+
io.onLog(`\u2717 ${err}`);
|
|
476
|
+
return false;
|
|
477
|
+
}
|
|
478
|
+
io.onLog(`\u2713 ${modelId} updated`);
|
|
479
|
+
return true;
|
|
480
|
+
});
|
|
481
|
+
},
|
|
482
|
+
addModel(providerId, io, opts) {
|
|
483
|
+
return runFlow(async () => {
|
|
484
|
+
const providers = await loadProviders();
|
|
485
|
+
const cfg = providers[providerId];
|
|
486
|
+
if (!cfg) {
|
|
487
|
+
io.onLog(`\u2713 Provider "${providerId}" no longer in config.`);
|
|
488
|
+
return false;
|
|
489
|
+
}
|
|
490
|
+
const modelId = (await io.prompt("Model id", { secret: false })).trim();
|
|
491
|
+
if (!modelId) {
|
|
492
|
+
io.onLog("\u2717 Model id is required.");
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
if (opts?.fromCatalog) {
|
|
496
|
+
const catalogModel = await deps.modelsRegistry.getModel(
|
|
497
|
+
cfg.type && cfg.type !== providerId ? cfg.type : providerId,
|
|
498
|
+
modelId
|
|
499
|
+
).catch(() => void 0);
|
|
500
|
+
if (catalogModel) {
|
|
501
|
+
io.onLog(
|
|
502
|
+
`Found in catalog: ctx=${catalogModel.capabilities.maxContext}, out=${catalogModel.capabilities.maxOutput}`
|
|
503
|
+
);
|
|
504
|
+
} else {
|
|
505
|
+
io.onLog(`(not found in catalog \u2014 entering as custom)`);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
const err = await mutate((all) => {
|
|
509
|
+
const p = all[providerId];
|
|
510
|
+
if (!p) return `Provider "${providerId}" no longer in config.`;
|
|
511
|
+
if (!p.models) p.models = [];
|
|
512
|
+
if (!p.models.includes(modelId)) p.models.push(modelId);
|
|
513
|
+
return null;
|
|
514
|
+
});
|
|
515
|
+
if (err) {
|
|
516
|
+
io.onLog(`\u2717 ${err}`);
|
|
517
|
+
return false;
|
|
518
|
+
}
|
|
519
|
+
io.onLog(`\u2713 Added model "${modelId}" to ${providerId}`);
|
|
520
|
+
return true;
|
|
521
|
+
});
|
|
522
|
+
},
|
|
523
|
+
removeModel(providerId, modelId) {
|
|
524
|
+
return (async () => {
|
|
525
|
+
const err = await mutate((all) => {
|
|
526
|
+
const p = all[providerId];
|
|
527
|
+
if (!p) return `Provider "${providerId}" no longer in config.`;
|
|
528
|
+
if (p.models) {
|
|
529
|
+
p.models = p.models.filter((m) => m !== modelId);
|
|
530
|
+
if (p.models.length === 0) delete p.models;
|
|
531
|
+
}
|
|
532
|
+
if (p.customModels && modelId in p.customModels) {
|
|
533
|
+
delete p.customModels[modelId];
|
|
534
|
+
if (Object.keys(p.customModels).length === 0) delete p.customModels;
|
|
535
|
+
}
|
|
536
|
+
return null;
|
|
537
|
+
});
|
|
538
|
+
return err;
|
|
539
|
+
})();
|
|
540
|
+
},
|
|
541
|
+
resetModelToCatalog(providerId, modelId) {
|
|
542
|
+
return (async () => {
|
|
543
|
+
const providers = await loadProviders();
|
|
544
|
+
const cfg = providers[providerId];
|
|
545
|
+
if (!cfg) return `Provider "${providerId}" no longer in config.`;
|
|
546
|
+
const catalogModel = await deps.modelsRegistry.getModel(
|
|
547
|
+
cfg.type && cfg.type !== providerId ? cfg.type : providerId,
|
|
548
|
+
modelId
|
|
549
|
+
).catch(() => void 0);
|
|
550
|
+
if (!catalogModel) {
|
|
551
|
+
return `Model "${modelId}" not found in catalog \u2014 cannot reset.`;
|
|
552
|
+
}
|
|
553
|
+
const err = await mutate((all) => {
|
|
554
|
+
const p = all[providerId];
|
|
555
|
+
if (!p) return `Provider "${providerId}" no longer in config.`;
|
|
556
|
+
if (p.customModels && modelId in p.customModels) {
|
|
557
|
+
delete p.customModels[modelId];
|
|
558
|
+
if (Object.keys(p.customModels).length === 0) delete p.customModels;
|
|
559
|
+
}
|
|
560
|
+
return null;
|
|
561
|
+
});
|
|
562
|
+
return err;
|
|
563
|
+
})();
|
|
564
|
+
},
|
|
384
565
|
addCatalogProvider(catalogId, io) {
|
|
385
566
|
return runFlow(async () => {
|
|
386
567
|
const catalog = await deps.modelsRegistry.listProviders();
|
|
@@ -2842,7 +3023,7 @@ import {
|
|
|
2842
3023
|
} from "@wrongstack/acp";
|
|
2843
3024
|
import { ToolValidationError } from "@wrongstack/core/types";
|
|
2844
3025
|
function buildAcpSubagentRunner(subagentId) {
|
|
2845
|
-
let cmd = ACP_AGENT_COMMANDS[subagentId];
|
|
3026
|
+
let cmd = Object.prototype.hasOwnProperty.call(ACP_AGENT_COMMANDS, subagentId) ? ACP_AGENT_COMMANDS[subagentId] : void 0;
|
|
2846
3027
|
if (!cmd) {
|
|
2847
3028
|
const desc = findAgentDescriptor(subagentId);
|
|
2848
3029
|
if (desc) {
|
|
@@ -3182,6 +3363,75 @@ import { DefaultTokenCounter } from "@wrongstack/core/infrastructure";
|
|
|
3182
3363
|
import { EventBus } from "@wrongstack/core/kernel";
|
|
3183
3364
|
import { AutoApprovePermissionPolicy } from "@wrongstack/core/security";
|
|
3184
3365
|
|
|
3366
|
+
// src/fleet/host-context.ts
|
|
3367
|
+
import { TOKENS as TOKENS2 } from "@wrongstack/core/kernel";
|
|
3368
|
+
import { getSageRetrieval } from "@wrongstack/sage";
|
|
3369
|
+
async function resolveHostSubagentSkillContent(deps, roster, subCfg) {
|
|
3370
|
+
const rosterSkillNames = subCfg.role ? roster[subCfg.role]?.skillNames : void 0;
|
|
3371
|
+
const skillNames = [...new Set(subCfg.skillNames ?? rosterSkillNames ?? [])];
|
|
3372
|
+
const directContent = subCfg.skillContent?.trim();
|
|
3373
|
+
if (skillNames.length === 0 || !deps.skillLoader) return directContent ?? "";
|
|
3374
|
+
const resolved = [];
|
|
3375
|
+
let usedChars = 0;
|
|
3376
|
+
const maxChars = 16e3;
|
|
3377
|
+
const maxCharsPerSkill = 4e3;
|
|
3378
|
+
for (const skillName of skillNames) {
|
|
3379
|
+
try {
|
|
3380
|
+
const manifest = await deps.skillLoader.find(skillName);
|
|
3381
|
+
if (!manifest) continue;
|
|
3382
|
+
const body = (await deps.skillLoader.readSaveBody(skillName)).trim();
|
|
3383
|
+
if (!body) continue;
|
|
3384
|
+
const entry = `## Skill: ${skillName}
|
|
3385
|
+
|
|
3386
|
+
${body.slice(0, maxCharsPerSkill)}`;
|
|
3387
|
+
if (usedChars + entry.length > maxChars) {
|
|
3388
|
+
console.warn(
|
|
3389
|
+
`[MultiAgentHost] resolveSubagentSkillContent: budget (${maxChars}) exhausted after ${resolved.length} skill(s); dropping "${skillName}" and remaining skills`
|
|
3390
|
+
);
|
|
3391
|
+
break;
|
|
3392
|
+
}
|
|
3393
|
+
resolved.push(entry);
|
|
3394
|
+
usedChars += entry.length;
|
|
3395
|
+
} catch {
|
|
3396
|
+
}
|
|
3397
|
+
}
|
|
3398
|
+
const sections = [
|
|
3399
|
+
directContent,
|
|
3400
|
+
resolved.length > 0 ? `# Role-prioritized skills
|
|
3401
|
+
|
|
3402
|
+
Apply these skills first for this assignment.
|
|
3403
|
+
|
|
3404
|
+
${resolved.join("\n\n---\n\n")}` : void 0
|
|
3405
|
+
].filter((section) => Boolean(section));
|
|
3406
|
+
return sections.join("\n\n");
|
|
3407
|
+
}
|
|
3408
|
+
async function retrieveHostSubagentMemory(deps, getLeaderMode, subCfg, taskContext) {
|
|
3409
|
+
const memoryPort = deps.container.safeResolve(TOKENS2.MemoryStore);
|
|
3410
|
+
const memory = memoryPort ? getSageRetrieval(memoryPort) : void 0;
|
|
3411
|
+
if (!memory?.retrieveForAudience) return [];
|
|
3412
|
+
const contextualTaskType = typeof taskContext?.["taskType"] === "string" ? taskContext["taskType"] : void 0;
|
|
3413
|
+
try {
|
|
3414
|
+
const taskType = subCfg.memoryContext?.taskType ?? contextualTaskType;
|
|
3415
|
+
const mode = subCfg.memoryContext?.mode ?? getLeaderMode?.();
|
|
3416
|
+
const matches = await memory.retrieveForAudience(
|
|
3417
|
+
{
|
|
3418
|
+
...subCfg.role !== void 0 ? { role: subCfg.role } : {},
|
|
3419
|
+
...taskType !== void 0 ? { taskType } : {},
|
|
3420
|
+
...mode !== void 0 ? { mode } : {}
|
|
3421
|
+
},
|
|
3422
|
+
20
|
|
3423
|
+
);
|
|
3424
|
+
await memory.recordInjection?.(
|
|
3425
|
+
matches.map((item) => item.id),
|
|
3426
|
+
"subagent_audience",
|
|
3427
|
+
deps.session.id
|
|
3428
|
+
);
|
|
3429
|
+
return matches.map((item) => item.text);
|
|
3430
|
+
} catch {
|
|
3431
|
+
return [];
|
|
3432
|
+
}
|
|
3433
|
+
}
|
|
3434
|
+
|
|
3185
3435
|
// src/fleet/host-event-bridge.ts
|
|
3186
3436
|
import * as path4 from "node:path";
|
|
3187
3437
|
var BRIDGE_TEXT_CAP = 360;
|
|
@@ -3352,106 +3602,6 @@ function installSubagentEventBridge(opts) {
|
|
|
3352
3602
|
};
|
|
3353
3603
|
}
|
|
3354
3604
|
|
|
3355
|
-
// src/fleet/host-session-writer.ts
|
|
3356
|
-
function createParentSubagentSessionWriter(parentSession) {
|
|
3357
|
-
return {
|
|
3358
|
-
id: parentSession.id,
|
|
3359
|
-
transcriptPath: parentSession.transcriptPath,
|
|
3360
|
-
get pendingToolUses() {
|
|
3361
|
-
return [];
|
|
3362
|
-
},
|
|
3363
|
-
append: (event) => parentSession.append({ ...event }),
|
|
3364
|
-
appendBatch: (events) => parentSession.appendBatch(events.map((event) => ({ ...event }))),
|
|
3365
|
-
flush: () => parentSession.flush(),
|
|
3366
|
-
close: async () => {
|
|
3367
|
-
},
|
|
3368
|
-
recordFileChange: () => {
|
|
3369
|
-
},
|
|
3370
|
-
recordSideEffect: () => {
|
|
3371
|
-
},
|
|
3372
|
-
writeCheckpoint: async () => {
|
|
3373
|
-
},
|
|
3374
|
-
writeFileSnapshot: async () => {
|
|
3375
|
-
},
|
|
3376
|
-
truncateToCheckpoint: async () => 0,
|
|
3377
|
-
clearSession: async () => {
|
|
3378
|
-
},
|
|
3379
|
-
writeInFlightMarker: async () => {
|
|
3380
|
-
},
|
|
3381
|
-
clearInFlightMarker: async () => {
|
|
3382
|
-
}
|
|
3383
|
-
};
|
|
3384
|
-
}
|
|
3385
|
-
|
|
3386
|
-
// src/fleet/host-context.ts
|
|
3387
|
-
import { TOKENS as TOKENS2 } from "@wrongstack/core/kernel";
|
|
3388
|
-
import { getSageRetrieval } from "@wrongstack/sage";
|
|
3389
|
-
async function resolveHostSubagentSkillContent(deps, roster, subCfg) {
|
|
3390
|
-
const rosterSkillNames = subCfg.role ? roster[subCfg.role]?.skillNames : void 0;
|
|
3391
|
-
const skillNames = [...new Set(subCfg.skillNames ?? rosterSkillNames ?? [])];
|
|
3392
|
-
const directContent = subCfg.skillContent?.trim();
|
|
3393
|
-
if (skillNames.length === 0 || !deps.skillLoader) return directContent ?? "";
|
|
3394
|
-
const resolved = [];
|
|
3395
|
-
let usedChars = 0;
|
|
3396
|
-
const maxChars = 16e3;
|
|
3397
|
-
const maxCharsPerSkill = 4e3;
|
|
3398
|
-
for (const skillName of skillNames) {
|
|
3399
|
-
try {
|
|
3400
|
-
const manifest = await deps.skillLoader.find(skillName);
|
|
3401
|
-
if (!manifest) continue;
|
|
3402
|
-
const body = (await deps.skillLoader.readSaveBody(skillName)).trim();
|
|
3403
|
-
if (!body) continue;
|
|
3404
|
-
const entry = `## Skill: ${skillName}
|
|
3405
|
-
|
|
3406
|
-
${body.slice(0, maxCharsPerSkill)}`;
|
|
3407
|
-
if (usedChars + entry.length > maxChars) {
|
|
3408
|
-
console.warn(
|
|
3409
|
-
`[MultiAgentHost] resolveSubagentSkillContent: budget (${maxChars}) exhausted after ${resolved.length} skill(s); dropping "${skillName}" and remaining skills`
|
|
3410
|
-
);
|
|
3411
|
-
break;
|
|
3412
|
-
}
|
|
3413
|
-
resolved.push(entry);
|
|
3414
|
-
usedChars += entry.length;
|
|
3415
|
-
} catch {
|
|
3416
|
-
}
|
|
3417
|
-
}
|
|
3418
|
-
const sections = [
|
|
3419
|
-
directContent,
|
|
3420
|
-
resolved.length > 0 ? `# Role-prioritized skills
|
|
3421
|
-
|
|
3422
|
-
Apply these skills first for this assignment.
|
|
3423
|
-
|
|
3424
|
-
${resolved.join("\n\n---\n\n")}` : void 0
|
|
3425
|
-
].filter((section) => Boolean(section));
|
|
3426
|
-
return sections.join("\n\n");
|
|
3427
|
-
}
|
|
3428
|
-
async function retrieveHostSubagentMemory(deps, getLeaderMode, subCfg, taskContext) {
|
|
3429
|
-
const memoryPort = deps.container.safeResolve(TOKENS2.MemoryStore);
|
|
3430
|
-
const memory = memoryPort ? getSageRetrieval(memoryPort) : void 0;
|
|
3431
|
-
if (!memory?.retrieveForAudience) return [];
|
|
3432
|
-
const contextualTaskType = typeof taskContext?.["taskType"] === "string" ? taskContext["taskType"] : void 0;
|
|
3433
|
-
try {
|
|
3434
|
-
const taskType = subCfg.memoryContext?.taskType ?? contextualTaskType;
|
|
3435
|
-
const mode = subCfg.memoryContext?.mode ?? getLeaderMode?.();
|
|
3436
|
-
const matches = await memory.retrieveForAudience(
|
|
3437
|
-
{
|
|
3438
|
-
...subCfg.role !== void 0 ? { role: subCfg.role } : {},
|
|
3439
|
-
...taskType !== void 0 ? { taskType } : {},
|
|
3440
|
-
...mode !== void 0 ? { mode } : {}
|
|
3441
|
-
},
|
|
3442
|
-
20
|
|
3443
|
-
);
|
|
3444
|
-
await memory.recordInjection?.(
|
|
3445
|
-
matches.map((item) => item.id),
|
|
3446
|
-
"subagent_audience",
|
|
3447
|
-
deps.session.id
|
|
3448
|
-
);
|
|
3449
|
-
return matches.map((item) => item.text);
|
|
3450
|
-
} catch {
|
|
3451
|
-
return [];
|
|
3452
|
-
}
|
|
3453
|
-
}
|
|
3454
|
-
|
|
3455
3605
|
// src/fleet/host-provider.ts
|
|
3456
3606
|
import { makeProviderFromConfig, withCatalogCapabilities } from "@wrongstack/providers";
|
|
3457
3607
|
async function buildHostSubagentProvider(deps, config, overrideId, model) {
|
|
@@ -3532,6 +3682,37 @@ function resolveHostSubagentModelSelection(liveConfig, effectiveCfg, matrixTarge
|
|
|
3532
3682
|
};
|
|
3533
3683
|
}
|
|
3534
3684
|
|
|
3685
|
+
// src/fleet/host-session-writer.ts
|
|
3686
|
+
function createParentSubagentSessionWriter(parentSession) {
|
|
3687
|
+
return {
|
|
3688
|
+
id: parentSession.id,
|
|
3689
|
+
transcriptPath: parentSession.transcriptPath,
|
|
3690
|
+
get pendingToolUses() {
|
|
3691
|
+
return [];
|
|
3692
|
+
},
|
|
3693
|
+
append: (event) => parentSession.append({ ...event }),
|
|
3694
|
+
appendBatch: (events) => parentSession.appendBatch(events.map((event) => ({ ...event }))),
|
|
3695
|
+
flush: () => parentSession.flush(),
|
|
3696
|
+
close: async () => {
|
|
3697
|
+
},
|
|
3698
|
+
recordFileChange: () => {
|
|
3699
|
+
},
|
|
3700
|
+
recordSideEffect: () => {
|
|
3701
|
+
},
|
|
3702
|
+
writeCheckpoint: async () => {
|
|
3703
|
+
},
|
|
3704
|
+
writeFileSnapshot: async () => {
|
|
3705
|
+
},
|
|
3706
|
+
truncateToCheckpoint: async () => 0,
|
|
3707
|
+
clearSession: async () => {
|
|
3708
|
+
},
|
|
3709
|
+
writeInFlightMarker: async () => {
|
|
3710
|
+
},
|
|
3711
|
+
clearInFlightMarker: async () => {
|
|
3712
|
+
}
|
|
3713
|
+
};
|
|
3714
|
+
}
|
|
3715
|
+
|
|
3535
3716
|
// src/fleet/host-subagent-factory.ts
|
|
3536
3717
|
function createHostSubagentFactory(config, host) {
|
|
3537
3718
|
return async (subCfg, task) => {
|
|
@@ -3544,7 +3725,14 @@ function createHostSubagentFactory(config, host) {
|
|
|
3544
3725
|
const effectiveCfg = projectCfg ? applyProjectAgentConfig(subCfg, projectCfg, {
|
|
3545
3726
|
protectSystemRole: isSystemRole
|
|
3546
3727
|
}) : subCfg;
|
|
3547
|
-
const matrixTarget = effectiveCfg.model ? void 0 : resolveSubagentModelTarget(liveConfig, effectiveCfg.role
|
|
3728
|
+
const matrixTarget = effectiveCfg.model ? void 0 : resolveSubagentModelTarget(liveConfig, effectiveCfg.role, {
|
|
3729
|
+
// Thread the shared tracker so the resolved matrix target skips
|
|
3730
|
+
// (provider, model) pairs currently in the waiting room. Without
|
|
3731
|
+
// this, the subagent factory would seed its own primary from a
|
|
3732
|
+
// doomed model the leader just 429-stricken, and the fallback
|
|
3733
|
+
// extension would have to spend a turn rotating away.
|
|
3734
|
+
...host.opts.statusTracker ? { statusTracker: host.opts.statusTracker } : {}
|
|
3735
|
+
});
|
|
3548
3736
|
const modelSelection = resolveHostSubagentModelSelection(
|
|
3549
3737
|
liveConfig,
|
|
3550
3738
|
effectiveCfg,
|
|
@@ -3573,8 +3761,7 @@ function createHostSubagentFactory(config, host) {
|
|
|
3573
3761
|
providerError = err;
|
|
3574
3762
|
}
|
|
3575
3763
|
}
|
|
3576
|
-
if (!provider)
|
|
3577
|
-
throw providerError ?? new Error("No permitted provider/model could be built.");
|
|
3764
|
+
if (!provider) throw providerError ?? new Error("No permitted provider/model could be built.");
|
|
3578
3765
|
let subReasoningConfig = await resolveHostSubagentReasoningConfig(
|
|
3579
3766
|
host.deps,
|
|
3580
3767
|
effProvider,
|
|
@@ -29806,7 +29993,7 @@ async function runInteractive(cliCtx) {
|
|
|
29806
29993
|
onEvent: evOn
|
|
29807
29994
|
});
|
|
29808
29995
|
const savedProviderCfg = config.providers?.[config.provider];
|
|
29809
|
-
const { execute } = await import("./execution-
|
|
29996
|
+
const { execute } = await import("./execution-BY556FCF.js");
|
|
29810
29997
|
const stopHeapWatchdog = startSharedHeapWatchdog({
|
|
29811
29998
|
collectStats: () => {
|
|
29812
29999
|
const hqQueue = hqPublisherRef.current?.getQueueStats();
|
|
@@ -30038,4 +30225,4 @@ export {
|
|
|
30038
30225
|
CLI_VERSION,
|
|
30039
30226
|
runInteractive
|
|
30040
30227
|
};
|
|
30041
|
-
//# sourceMappingURL=cli-main-
|
|
30228
|
+
//# sourceMappingURL=cli-main-ZDZMCVLM.js.map
|
|
@@ -1289,6 +1289,29 @@ import { decryptConfigSecrets, encryptConfigSecrets, noOpVault } from "@wrongsta
|
|
|
1289
1289
|
import { normalizeTokenSavingTier, resolveFleetChatVerbosity } from "@wrongstack/core/types";
|
|
1290
1290
|
import { atomicWrite } from "@wrongstack/core/utils";
|
|
1291
1291
|
import { getProcessRegistry } from "@wrongstack/tools";
|
|
1292
|
+
var PANEL_IDS_CLI = [
|
|
1293
|
+
"projectPicker",
|
|
1294
|
+
"fleet",
|
|
1295
|
+
"agents",
|
|
1296
|
+
"worktree",
|
|
1297
|
+
"plan",
|
|
1298
|
+
"todos",
|
|
1299
|
+
"queue",
|
|
1300
|
+
"processList",
|
|
1301
|
+
"goal",
|
|
1302
|
+
"sessions",
|
|
1303
|
+
"coordinator",
|
|
1304
|
+
"kanban",
|
|
1305
|
+
"connections"
|
|
1306
|
+
];
|
|
1307
|
+
function coercePanelPositionMap(v) {
|
|
1308
|
+
const out = {};
|
|
1309
|
+
for (const id of PANEL_IDS_CLI) {
|
|
1310
|
+
const value = v?.[id];
|
|
1311
|
+
out[id] = value === "sidebar" ? "sidebar" : "bottom";
|
|
1312
|
+
}
|
|
1313
|
+
return out;
|
|
1314
|
+
}
|
|
1292
1315
|
function coerceAgentSwarmMode(v) {
|
|
1293
1316
|
if (v === true || v === void 0) return "bottom";
|
|
1294
1317
|
if (v === false) return "off";
|
|
@@ -1365,6 +1388,16 @@ function createSettingsAdapter(ctx) {
|
|
|
1365
1388
|
breakerAutoKillResetMs: cfg.circuitBreaker?.autoKillResetMs ?? 6e4,
|
|
1366
1389
|
showModelReasoning: autonomy?.showModelReasoning ?? true,
|
|
1367
1390
|
showAgentSwarmPanel: coerceAgentSwarmMode(autonomy?.showAgentSwarmPanel),
|
|
1391
|
+
// Migrate the legacy `autonomy.showAgentSwarmPanel: 'sidebar'` into
|
|
1392
|
+
// the new per-panel `panelPositions.fleet` map at the read boundary
|
|
1393
|
+
// so users with old configs (no `panelPositions` key on disk) get
|
|
1394
|
+
// their sidebar routing. Only migrate when the per-panel key is
|
|
1395
|
+
// UNDEFINED — an explicit `panelPositions.fleet: 'bottom'` must
|
|
1396
|
+
// NOT be reverted to `'sidebar'`.
|
|
1397
|
+
panelPositions: coercePanelPositionMap({
|
|
1398
|
+
...autonomy?.panelPositions,
|
|
1399
|
+
...coerceAgentSwarmMode(autonomy?.showAgentSwarmPanel) === "sidebar" && autonomy?.panelPositions?.fleet === void 0 ? { fleet: "sidebar" } : {}
|
|
1400
|
+
}),
|
|
1368
1401
|
showSageMemoryInject: autonomy?.showSageMemoryInject ?? false,
|
|
1369
1402
|
readSymbols: autonomy?.readAdvancedMode ?? false,
|
|
1370
1403
|
sageMemoryInjectThreshold: cfg.Sage?.inject ? cfg.Sage.inject?.relationFloor : void 0
|
|
@@ -1372,7 +1405,7 @@ function createSettingsAdapter(ctx) {
|
|
|
1372
1405
|
}
|
|
1373
1406
|
async function saveSettings(s) {
|
|
1374
1407
|
try {
|
|
1375
|
-
if (s.mode !== void 0 || s.delayMs !== void 0 || s.titleAnimation !== void 0 || s.yolo !== void 0 || s.fleetChatVerbosity !== void 0 || s.chime !== void 0 || s.confirmExit !== void 0 || s.mouseMode !== void 0 || s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0 || s.featureTokenSaving !== void 0 || s.allowOutsideProjectRoot !== void 0 || s.contextAutoCompact !== void 0 || s.contextStrategy !== void 0 || s.contextMode !== void 0 || s.maxConcurrent !== void 0 || s.logLevel !== void 0 || s.auditLevel !== void 0 || s.indexOnStart !== void 0 || s.maxIterations !== void 0 || s.restrictFsToRoot !== void 0 || s.nextPrediction !== void 0 || s.debugStream !== void 0 || s.shellBangWarningDontShowAgain !== void 0 || s.configScope !== void 0 || s.enhanceDelayMs !== void 0 || s.enhanceEnabled !== void 0 || s.enhanceLanguage !== void 0 || s.midRunSendPicker !== void 0 || s.statuslineMode !== void 0 || s.thinkingWord !== void 0 || s.animationStyle !== void 0 || s.autonomyNextPrompt !== void 0 || s.autoProceedMaxIterations !== void 0 || s.reasoningMode !== void 0 || s.reasoningEffort !== void 0 || s.reasoningPreserve !== void 0 || s.cacheTtl !== void 0 || s.breakerEnabled !== void 0 || s.breakerAutoKillResetMs !== void 0 || s.showModelReasoning !== void 0 || s.showAgentSwarmPanel !== void 0 || s.showSageMemoryInject !== void 0 || s.sageMemoryInjectThreshold !== void 0 || s.readSymbols !== void 0) {
|
|
1408
|
+
if (s.mode !== void 0 || s.delayMs !== void 0 || s.titleAnimation !== void 0 || s.yolo !== void 0 || s.fleetChatVerbosity !== void 0 || s.chime !== void 0 || s.confirmExit !== void 0 || s.mouseMode !== void 0 || s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0 || s.featureTokenSaving !== void 0 || s.allowOutsideProjectRoot !== void 0 || s.contextAutoCompact !== void 0 || s.contextStrategy !== void 0 || s.contextMode !== void 0 || s.maxConcurrent !== void 0 || s.logLevel !== void 0 || s.auditLevel !== void 0 || s.indexOnStart !== void 0 || s.maxIterations !== void 0 || s.restrictFsToRoot !== void 0 || s.nextPrediction !== void 0 || s.debugStream !== void 0 || s.shellBangWarningDontShowAgain !== void 0 || s.configScope !== void 0 || s.enhanceDelayMs !== void 0 || s.enhanceEnabled !== void 0 || s.enhanceLanguage !== void 0 || s.midRunSendPicker !== void 0 || s.statuslineMode !== void 0 || s.thinkingWord !== void 0 || s.animationStyle !== void 0 || s.autonomyNextPrompt !== void 0 || s.autoProceedMaxIterations !== void 0 || s.reasoningMode !== void 0 || s.reasoningEffort !== void 0 || s.reasoningPreserve !== void 0 || s.cacheTtl !== void 0 || s.breakerEnabled !== void 0 || s.breakerAutoKillResetMs !== void 0 || s.showModelReasoning !== void 0 || s.showAgentSwarmPanel !== void 0 || s.panelPositions !== void 0 || s.showSageMemoryInject !== void 0 || s.sageMemoryInjectThreshold !== void 0 || s.readSymbols !== void 0) {
|
|
1376
1409
|
const cfg = configStore.get();
|
|
1377
1410
|
const activeProfileName = cfg.activeProfile ?? "default";
|
|
1378
1411
|
const persistDeps = {
|
|
@@ -1421,6 +1454,7 @@ function createSettingsAdapter(ctx) {
|
|
|
1421
1454
|
if (s.showModelReasoning !== void 0) autonomy.showModelReasoning = s.showModelReasoning;
|
|
1422
1455
|
if (s.showAgentSwarmPanel !== void 0)
|
|
1423
1456
|
autonomy.showAgentSwarmPanel = s.showAgentSwarmPanel;
|
|
1457
|
+
if (s.panelPositions !== void 0) autonomy.panelPositions = s.panelPositions;
|
|
1424
1458
|
if (s.showSageMemoryInject !== void 0)
|
|
1425
1459
|
autonomy.showSageMemoryInject = s.showSageMemoryInject;
|
|
1426
1460
|
if (s.readSymbols !== void 0) autonomy.readAdvancedMode = s.readSymbols;
|
|
@@ -1517,8 +1551,24 @@ function createSettingsAdapter(ctx) {
|
|
|
1517
1551
|
decrypted,
|
|
1518
1552
|
targetPath
|
|
1519
1553
|
);
|
|
1554
|
+
let mergedToWrite = decrypted;
|
|
1555
|
+
if (actualTarget !== targetPath) {
|
|
1556
|
+
try {
|
|
1557
|
+
const destRaw = await fs3.readFile(actualTarget, "utf8");
|
|
1558
|
+
const destParsed = JSON.parse(destRaw);
|
|
1559
|
+
const destDecrypted = decryptConfigSecrets(destParsed, noOpVault);
|
|
1560
|
+
mergedToWrite = { ...destDecrypted, ...decrypted };
|
|
1561
|
+
} catch (err) {
|
|
1562
|
+
if (err.code !== "ENOENT") {
|
|
1563
|
+
throw new Error(
|
|
1564
|
+
`Failed to read destination config at ${actualTarget}: ${err instanceof Error ? err.message : String(err)}`,
|
|
1565
|
+
{ cause: err }
|
|
1566
|
+
);
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1520
1570
|
const isProjectTarget = actualTarget === wpaths.inProjectConfig;
|
|
1521
|
-
const toWrite = isProjectTarget ? filterSafeForProject(
|
|
1571
|
+
const toWrite = isProjectTarget ? filterSafeForProject(mergedToWrite) : mergedToWrite;
|
|
1522
1572
|
const encrypted = encryptConfigSecrets(toWrite, noOpVault);
|
|
1523
1573
|
await fs3.mkdir(path7.dirname(actualTarget), { recursive: true });
|
|
1524
1574
|
await atomicWrite(actualTarget, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
@@ -1773,8 +1823,8 @@ var reviewerRoundRobinCursor = 0;
|
|
|
1773
1823
|
function __resetReviewerRoundRobinCursor(value = 0) {
|
|
1774
1824
|
reviewerRoundRobinCursor = value;
|
|
1775
1825
|
}
|
|
1776
|
-
function assignReviewerModelsRoundRobin(provider, model, fallbackModels) {
|
|
1777
|
-
const pool = buildReviewerModelPool(provider, model, fallbackModels);
|
|
1826
|
+
function assignReviewerModelsRoundRobin(provider, model, fallbackModels, statusTracker) {
|
|
1827
|
+
const pool = buildReviewerModelPool(provider, model, fallbackModels, statusTracker);
|
|
1778
1828
|
if (pool.length <= 1) {
|
|
1779
1829
|
return {
|
|
1780
1830
|
provider,
|
|
@@ -1786,7 +1836,8 @@ function assignReviewerModelsRoundRobin(provider, model, fallbackModels) {
|
|
|
1786
1836
|
pool,
|
|
1787
1837
|
reviewerRoundRobinCursor,
|
|
1788
1838
|
provider,
|
|
1789
|
-
model
|
|
1839
|
+
model,
|
|
1840
|
+
statusTracker
|
|
1790
1841
|
);
|
|
1791
1842
|
reviewerRoundRobinCursor = assignment.nextCursor;
|
|
1792
1843
|
return {
|
|
@@ -2810,6 +2861,7 @@ function installChimeraReviewHandler({
|
|
|
2810
2861
|
agent,
|
|
2811
2862
|
config,
|
|
2812
2863
|
projectDir,
|
|
2864
|
+
statusTracker,
|
|
2813
2865
|
persistReview = persistChimeraReview,
|
|
2814
2866
|
setPendingWork
|
|
2815
2867
|
}) {
|
|
@@ -2876,7 +2928,12 @@ function installChimeraReviewHandler({
|
|
|
2876
2928
|
const baseProvider = rawProvider || tProvider || config.provider;
|
|
2877
2929
|
const baseModel = rawModel || tModel || config.model;
|
|
2878
2930
|
const baseFallbacks = p.reviewFallbackModels ? [...p.reviewFallbackModels] : resolveReviewerFallbackModels(void 0);
|
|
2879
|
-
const assigned = assignReviewerModelsRoundRobin(
|
|
2931
|
+
const assigned = assignReviewerModelsRoundRobin(
|
|
2932
|
+
baseProvider,
|
|
2933
|
+
baseModel,
|
|
2934
|
+
baseFallbacks,
|
|
2935
|
+
statusTracker
|
|
2936
|
+
);
|
|
2880
2937
|
const ladder = buildReviewerAttemptLadder({
|
|
2881
2938
|
assigned,
|
|
2882
2939
|
profileChain: effectiveFallbackChain(config),
|
|
@@ -3016,7 +3073,20 @@ ${reviewBody}`;
|
|
|
3016
3073
|
audience: "leaders",
|
|
3017
3074
|
subject,
|
|
3018
3075
|
body,
|
|
3019
|
-
priority: "normal"
|
|
3076
|
+
priority: "normal",
|
|
3077
|
+
// Session-affinity stamp: the recipient's leader filter
|
|
3078
|
+
// uses this to drop the message for any leader whose current
|
|
3079
|
+
// session id does NOT match the originating session of the
|
|
3080
|
+
// review (`reviewSessionId` is captured above from the
|
|
3081
|
+
// agent's active run / session id). Without this token the
|
|
3082
|
+
// project-wide mailbox would deliver every chimera result to
|
|
3083
|
+
// every leader, inviting them to act on reports that belong
|
|
3084
|
+
// to a different session.
|
|
3085
|
+
sessionAffinity: {
|
|
3086
|
+
sessionId: reviewSessionId,
|
|
3087
|
+
reportId,
|
|
3088
|
+
kind: "chimera.review"
|
|
3089
|
+
}
|
|
3020
3090
|
});
|
|
3021
3091
|
if (!mailMsg?.id) throw new Error("mailbox.send returned no message id");
|
|
3022
3092
|
reviewMailMessageId = mailMsg.id;
|
|
@@ -4446,6 +4516,11 @@ async function execute(deps) {
|
|
|
4446
4516
|
agent,
|
|
4447
4517
|
config,
|
|
4448
4518
|
projectDir: wpaths.projectDir,
|
|
4519
|
+
// Thread the shared tracker so the round-robin Chimera reviewer picks
|
|
4520
|
+
// skip (provider, model) pairs currently in the waiting room. Without
|
|
4521
|
+
// this, a 429-stricken model is re-spawned on every concurrent reviewer
|
|
4522
|
+
// turn and burns the whole chain instead of staying quarantined.
|
|
4523
|
+
statusTracker,
|
|
4449
4524
|
setPendingWork: (work) => {
|
|
4450
4525
|
pendingChimeraWork = work;
|
|
4451
4526
|
}
|
|
@@ -4867,4 +4942,4 @@ export {
|
|
|
4867
4942
|
execute,
|
|
4868
4943
|
resolveReviewerFallbackModels
|
|
4869
4944
|
};
|
|
4870
|
-
//# sourceMappingURL=execution-
|
|
4945
|
+
//# sourceMappingURL=execution-BY556FCF.js.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ProviderModelStatusTracker } from '@wrongstack/core/coordination';
|
|
1
2
|
import { type ChimeraReviewCompletePayload } from '@wrongstack/core/plugin';
|
|
2
3
|
import type { ExecuteDeps } from './execute-deps.js';
|
|
3
4
|
type Director = NonNullable<ExecuteDeps['fleet']['director']>;
|
|
@@ -27,9 +28,18 @@ export type InstallChimeraReviewHandlerOptions = {
|
|
|
27
28
|
agent: Agent;
|
|
28
29
|
config: Config;
|
|
29
30
|
projectDir: string;
|
|
31
|
+
/**
|
|
32
|
+
* Shared provider/model status tracker. When supplied, the round-robin
|
|
33
|
+
* Chimera reviewer spawn skips (provider, model) pairs currently in the
|
|
34
|
+
* waiting room (`state: 'blocked'`) so a 429-stricken model is never
|
|
35
|
+
* re-spawned on a concurrent reviewer turn. The tracker is the same
|
|
36
|
+
* singleton the leader's `/provider-status` reads from; see
|
|
37
|
+
* `packages/core/src/coordination/provider-status-tracker.ts`.
|
|
38
|
+
*/
|
|
39
|
+
statusTracker?: ProviderModelStatusTracker | undefined;
|
|
30
40
|
persistReview?: ((payload: ChimeraReviewCompletePayload, projectDir: string) => Promise<void>) | undefined;
|
|
31
41
|
setPendingWork: (work: PendingChimeraWork) => void;
|
|
32
42
|
};
|
|
33
|
-
export declare function installChimeraReviewHandler({ events, director, session, mailbox, agent, config, projectDir, persistReview, setPendingWork, }: InstallChimeraReviewHandlerOptions): void;
|
|
43
|
+
export declare function installChimeraReviewHandler({ events, director, session, mailbox, agent, config, projectDir, statusTracker, persistReview, setPendingWork, }: InstallChimeraReviewHandlerOptions): void;
|
|
34
44
|
export {};
|
|
35
45
|
//# sourceMappingURL=execution-chimera-review.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
parseArgs,
|
|
37
37
|
runPicker,
|
|
38
38
|
saveToGlobalConfig
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-ZNZJ34RF.js";
|
|
40
40
|
import {
|
|
41
41
|
isKeylessLocalProvider,
|
|
42
42
|
visibleModelIds
|
|
@@ -1497,7 +1497,7 @@ function compactSingleLine(text) {
|
|
|
1497
1497
|
var loaders = {
|
|
1498
1498
|
acp: async () => (await import("./acp-S4LZQB66.js")).acpCmd,
|
|
1499
1499
|
init: async () => (await import("./init-E2NDDOHI.js")).initCmd,
|
|
1500
|
-
auth: async () => (await import("./auth-
|
|
1500
|
+
auth: async () => (await import("./auth-G5YKKSRH.js")).authCmd,
|
|
1501
1501
|
update: async () => (await import("./update-MV6TUACD.js")).updateCmd,
|
|
1502
1502
|
sessions: async () => (await import("./sessions-config-NLCMK3BY.js")).sessionsCmd,
|
|
1503
1503
|
config: async () => (await import("./sessions-config-NLCMK3BY.js")).configCmd,
|
|
@@ -3149,7 +3149,7 @@ async function initializeCli(argv) {
|
|
|
3149
3149
|
async function main(argv) {
|
|
3150
3150
|
const cliCtx = await initializeCli(argv);
|
|
3151
3151
|
if (typeof cliCtx === "number") return cliCtx;
|
|
3152
|
-
const { runInteractive } = await import("./cli-main-
|
|
3152
|
+
const { runInteractive } = await import("./cli-main-ZDZMCVLM.js");
|
|
3153
3153
|
return runInteractive(cliCtx);
|
|
3154
3154
|
}
|
|
3155
3155
|
|
|
@@ -66,6 +66,14 @@ export interface LiveSettingsInput {
|
|
|
66
66
|
/** Agent swarm panel placement: 'bottom' (lower region), 'sidebar' (right sidebar), or 'off' (hidden).
|
|
67
67
|
* Backward-compat: legacy boolean values are coerced by the TUI settings adapter. Default: 'bottom'. */
|
|
68
68
|
showAgentSwarmPanel?: 'bottom' | 'sidebar' | 'off' | boolean | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* Per-panel position map (one entry per F-key panel id). Each value is
|
|
71
|
+
* 'bottom' (F-key behavior) or 'sidebar' (right-sidebar twin). Persisted
|
|
72
|
+
* as `autonomy.panelPositions` in the project/profile config. The TUI
|
|
73
|
+
* auto-save hook passes a full PanelPositionMap (13 entries); the adapter
|
|
74
|
+
* stores it as-is. Default: every panel 'bottom' when unset.
|
|
75
|
+
*/
|
|
76
|
+
panelPositions?: Readonly<Record<string, 'bottom' | 'sidebar'>> | undefined;
|
|
69
77
|
/** Show SAGE Memory Inject blocks in tool results. Default: false. */
|
|
70
78
|
showSageMemoryInject?: boolean | undefined;
|
|
71
79
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/cli",
|
|
3
|
-
"version": "0.298.
|
|
3
|
+
"version": "0.298.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "WrongStack CLI — terminal AI coding agent with provider catalog from models.dev. Provides `wrongstack` and `wstack` binaries.",
|
|
6
6
|
"keywords": [
|
|
@@ -42,29 +42,29 @@
|
|
|
42
42
|
],
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"ws": "^8.21.1",
|
|
45
|
-
"@wrongstack/
|
|
46
|
-
"@wrongstack/
|
|
47
|
-
"@wrongstack/
|
|
48
|
-
"@wrongstack/
|
|
49
|
-
"@wrongstack/
|
|
50
|
-
"@wrongstack/
|
|
51
|
-
"@wrongstack/
|
|
52
|
-
"@wrongstack/
|
|
53
|
-
"@wrongstack/
|
|
54
|
-
"@wrongstack/
|
|
55
|
-
"@wrongstack/security-scanner": "0.298.
|
|
56
|
-
"@wrongstack/simpleui": "0.298.
|
|
57
|
-
"@wrongstack/
|
|
58
|
-
"@wrongstack/
|
|
59
|
-
"@wrongstack/
|
|
60
|
-
"@wrongstack/
|
|
61
|
-
"@wrongstack/
|
|
62
|
-
"@wrongstack/
|
|
63
|
-
"@wrongstack/
|
|
64
|
-
"@wrongstack/webui
|
|
45
|
+
"@wrongstack/bench": "0.298.2",
|
|
46
|
+
"@wrongstack/acp": "0.298.2",
|
|
47
|
+
"@wrongstack/kanban": "0.298.2",
|
|
48
|
+
"@wrongstack/plug-lsp": "0.298.2",
|
|
49
|
+
"@wrongstack/mcp": "0.298.2",
|
|
50
|
+
"@wrongstack/plugins": "0.298.2",
|
|
51
|
+
"@wrongstack/core": "0.298.2",
|
|
52
|
+
"@wrongstack/sdd": "0.298.2",
|
|
53
|
+
"@wrongstack/runtime": "0.298.2",
|
|
54
|
+
"@wrongstack/providers": "0.298.2",
|
|
55
|
+
"@wrongstack/security-scanner": "0.298.2",
|
|
56
|
+
"@wrongstack/simpleui": "0.298.2",
|
|
57
|
+
"@wrongstack/sage": "0.298.2",
|
|
58
|
+
"@wrongstack/telegram": "0.298.2",
|
|
59
|
+
"@wrongstack/techstack": "0.298.2",
|
|
60
|
+
"@wrongstack/tools": "0.298.2",
|
|
61
|
+
"@wrongstack/tui": "0.298.2",
|
|
62
|
+
"@wrongstack/webui-hq": "0.298.2",
|
|
63
|
+
"@wrongstack/webui-server": "0.298.2",
|
|
64
|
+
"@wrongstack/webui": "0.298.2"
|
|
65
65
|
},
|
|
66
66
|
"optionalDependencies": {
|
|
67
|
-
"@wrongstack/desktop": "0.298.
|
|
67
|
+
"@wrongstack/desktop": "0.298.2"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@types/node": "^26.1.2",
|