@wrongstack/cli 1.0.11 → 1.0.13

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.
@@ -3228,8 +3228,8 @@ import {
3228
3228
  runtimeToolReferencesFromText
3229
3229
  } from "@wrongstack/core/agent-catalog";
3230
3230
  import { TOKENS as TOKENS3 } from "@wrongstack/core/kernel";
3231
- import { formatProjectSuppliedBlock } from "@wrongstack/core/utils";
3232
- import { getSageRetrieval } from "@wrongstack/sage";
3231
+ import { formatMemoryEvidenceBlock, formatProjectSuppliedBlock } from "@wrongstack/core/utils";
3232
+ import { formatMemoryHintsDetailed, getSageRetrieval } from "@wrongstack/sage";
3233
3233
  var EAGER_SKILL_LIMIT = DEFAULT_EAGER_SKILL_LIMIT;
3234
3234
  var MIN_TRIMMED_BODY_CHARS = 800;
3235
3235
  async function resolveHostSubagentSkillResolution(deps, roster, subCfg, availableToolNames = []) {
@@ -3344,8 +3344,9 @@ _(body trimmed)_` : body,
3344
3344
  async function retrieveHostSubagentMemory(deps, getLeaderMode, subCfg, taskContext, owningSessionId) {
3345
3345
  const memoryPort = deps.container.safeResolve(TOKENS3.MemoryStore);
3346
3346
  const memory = memoryPort ? getSageRetrieval(memoryPort) : void 0;
3347
- if (!memory?.retrieveForAudience) return [];
3347
+ if (!memory?.retrieveForAudience) return void 0;
3348
3348
  const contextualTaskType = typeof taskContext?.["taskType"] === "string" ? taskContext["taskType"] : void 0;
3349
+ const sessionId = owningSessionId ?? deps.session.id;
3349
3350
  try {
3350
3351
  const taskType = subCfg.memoryContext?.taskType ?? contextualTaskType;
3351
3352
  const mode = subCfg.memoryContext?.mode ?? getLeaderMode?.();
@@ -3355,18 +3356,30 @@ async function retrieveHostSubagentMemory(deps, getLeaderMode, subCfg, taskConte
3355
3356
  ...taskType !== void 0 ? { taskType } : {},
3356
3357
  ...mode !== void 0 ? { mode } : {}
3357
3358
  },
3358
- 20
3359
+ 20,
3360
+ void 0,
3361
+ // The owning conversation's own session-scoped audience memories are
3362
+ // visible to its workers; other sessions' stay hidden.
3363
+ sessionId
3359
3364
  );
3360
- await memory.recordInjection?.(
3361
- matches.map((item) => item.id),
3362
- "subagent_audience",
3363
- owningSessionId ?? deps.session.id
3365
+ const eligible = matches.filter(
3366
+ (item) => item.status === "active" && item.contextPolicy !== "never"
3364
3367
  );
3365
- return matches.map((item) => item.text);
3368
+ const rendered = formatMemoryHintsDetailed(eligible, {
3369
+ heading: "SAGE: project memory for this agent role",
3370
+ maxChars: SUBAGENT_AUDIENCE_MEMORY_CHARS
3371
+ });
3372
+ if (!rendered.text || rendered.memoryIds.length === 0) return void 0;
3373
+ try {
3374
+ await memory.recordInjection?.(rendered.memoryIds, "subagent_audience", sessionId);
3375
+ } catch {
3376
+ }
3377
+ return formatMemoryEvidenceBlock("sage.subagent-audience", rendered.text);
3366
3378
  } catch {
3367
- return [];
3379
+ return void 0;
3368
3380
  }
3369
3381
  }
3382
+ var SUBAGENT_AUDIENCE_MEMORY_CHARS = 4e3;
3370
3383
 
3371
3384
  // src/fleet/host-session-writer.ts
3372
3385
  import { stampAgentId } from "@wrongstack/core/storage";
@@ -3592,13 +3605,7 @@ ${message} Falling back to the assigned checkout.` : `${message} Falling back to
3592
3605
  task?.context,
3593
3606
  owningSessionId
3594
3607
  );
3595
- if (audienceMemory.length > 0) {
3596
- baseSystem.push({
3597
- type: "text",
3598
- text: `Project memory for this agent role:
3599
- ${audienceMemory.map((text) => `- ${text}`).join("\n")}`
3600
- });
3601
- }
3608
+ if (audienceMemory) baseSystem.push({ type: "text", text: audienceMemory });
3602
3609
  const skillResolution = await resolveHostSubagentSkillResolution(
3603
3610
  host.deps,
3604
3611
  host.roster,
@@ -11230,10 +11237,10 @@ function buildCodebaseMapCommand(opts) {
11230
11237
  const check = /(^|\s)--check(\s|$)/.test(text);
11231
11238
  const enrich = /(^|\s)--enrich(\s|$)/.test(text);
11232
11239
  const embed = /(^|\s)--embed(\s|$)/.test(text);
11233
- const exportMatch = /(^|\s)--export(?:[= ]([^\s]+))?(\s|$)/.exec(text);
11240
+ const exportMatch = /(^|\s)--export(?:[= ]([^\s-][^\s]*))?(\s|$)/.exec(text);
11234
11241
  const maxFilesMatch = /--max-files[= ](\d+)/.exec(text);
11235
11242
  const tokensMatch = /--tokens[= ](\d+)/.exec(text);
11236
- const maxTokens = tokensMatch ? Number(tokensMatch[1]) : void 0;
11243
+ const maxTokens = tokensMatch ? Math.min(Math.max(Number(tokensMatch[1]), MIN_MAP_TOKENS), MAX_MAP_TOKENS) : void 0;
11237
11244
  const projectRoot = opts.projectRoot;
11238
11245
  try {
11239
11246
  if (embed) {
@@ -11321,6 +11328,8 @@ function buildCodebaseMapCommand(opts) {
11321
11328
  };
11322
11329
  }
11323
11330
  var DEFAULT_EXPORT_FILE = "atlas.html";
11331
+ var MIN_MAP_TOKENS = 100;
11332
+ var MAX_MAP_TOKENS = 2e4;
11324
11333
  function noIndexMessage() {
11325
11334
  return color17.yellow(
11326
11335
  `No codebase index for this project yet. Run ${color17.bold("/codebase-reindex")} first.`
@@ -11405,14 +11414,17 @@ function buildCodebaseReindexCommand(opts) {
11405
11414
  "refresh \u2014 e.g. after a large branch switch, merge, or external edit."
11406
11415
  ].join("\n"),
11407
11416
  async run(args, _ctx) {
11408
- const force = /\b(force|--force|-f)\b/.test(args.trim());
11417
+ const force = /(^|\s)(force|--force|-f)(\s|$)/.test(args.trim());
11409
11418
  opts.renderer.write(color18.dim(`${force ? "Rebuilding" : "Reindexing"} codebase index\u2026
11410
11419
  `));
11411
11420
  try {
11412
11421
  resetIndexCircuitBreaker();
11413
11422
  const r = await runStartupIndex({ projectRoot: opts.projectRoot, force });
11414
- const summary = `${color18.green("\u2713")} codebase index ${force ? "rebuilt" : "updated"} ` + color18.dim(`\u2014 ${r.symbolsIndexed} symbols \xB7 ${r.filesIndexed} files \xB7 ${r.durationMs}ms`) + (r.errors.length ? `
11415
- ${color18.yellow(` ${r.errors.length} file(s) had errors`)}` : "");
11423
+ const outcomes = r.fileOutcomes;
11424
+ const fileSummary = outcomes ? `${outcomes.parsed} parsed \xB7 ${outcomes.skipped} unchanged` + (outcomes.failed > 0 ? ` \xB7 ${outcomes.failed} failed` : "") : `${r.filesIndexed} files`;
11425
+ const summary = `${color18.green("\u2713")} codebase index ${force || r.autoRecovered ? "rebuilt" : "updated"} ` + color18.dim(`\u2014 ${r.symbolsIndexed} symbols \xB7 ${fileSummary} \xB7 ${r.durationMs}ms`) + (r.autoRecovered ? `
11426
+ ${color18.yellow(" corrupt index detected \u2014 rebuilt from scratch")}` : "") + (r.errors.length ? `
11427
+ ${color18.yellow(` ${r.errors.length} error(s) reported`)}` : "");
11416
11428
  return { message: summary };
11417
11429
  } catch (err) {
11418
11430
  const msg = `${color18.red("Codebase reindex failed:")} ${toErrorMessage7(err)}`;
@@ -21159,8 +21171,17 @@ async function applyDispatch(Sage, report) {
21159
21171
  let mergeFail = 0;
21160
21172
  for (const merge of report.merges.merges) {
21161
21173
  try {
21162
- await Sage.updateSage(merge.supersededId, { status: "superseded" });
21163
- await Sage.updateSage(merge.keeperId, { supersedes: [merge.supersededId] });
21174
+ const keeper = await Sage.getSage(merge.keeperId);
21175
+ if (!keeper || keeper.status !== "active" && keeper.status !== "stale") {
21176
+ throw new Error(`keeper ${merge.keeperId} is no longer active`);
21177
+ }
21178
+ await Sage.updateSage(merge.supersededId, {
21179
+ status: "superseded",
21180
+ supersededBy: merge.keeperId
21181
+ });
21182
+ await Sage.updateSage(merge.keeperId, {
21183
+ supersedes: [.../* @__PURE__ */ new Set([...keeper.supersedes ?? [], merge.supersededId])]
21184
+ });
21164
21185
  mergeOk++;
21165
21186
  } catch (err) {
21166
21187
  mergeFail++;
@@ -21439,12 +21460,58 @@ function buildMemoryCommand(opts) {
21439
21460
  case "candidates": {
21440
21461
  if (!Sage) return requiresSage("candidates");
21441
21462
  const action = rest[0]?.toLowerCase() ?? "list";
21463
+ if (action === "resolve") {
21464
+ const decision = rest[2]?.toLowerCase();
21465
+ if (!rest[1] || decision !== "delete" && decision !== "archive" && decision !== "keep") {
21466
+ return {
21467
+ message: "Usage: /memory candidates resolve <candidate-id> delete|archive|keep [reason]"
21468
+ };
21469
+ }
21470
+ try {
21471
+ const resolution = await Sage.resolveCandidate(
21472
+ rest[1],
21473
+ decision,
21474
+ rest.slice(3).join(" ") || void 0
21475
+ );
21476
+ if (!resolution) return { message: `Candidate ${rest[1]} was not found.` };
21477
+ if (resolution.error) {
21478
+ return { message: `Could not resolve ${rest[1]}: ${resolution.error}` };
21479
+ }
21480
+ return {
21481
+ message: `Resolved ${rest[1]}: ${decision}${resolution.applied ? "" : " (target memory unchanged)"}.`
21482
+ };
21483
+ } catch (error) {
21484
+ return {
21485
+ message: `Could not resolve ${rest[1]}: ${error instanceof Error ? error.message : String(error)}`
21486
+ };
21487
+ }
21488
+ }
21442
21489
  if (action === "accept") {
21443
21490
  if (!rest[1]) return { message: "Usage: /memory candidates accept <candidate-id>" };
21444
- const accepted = await Sage.acceptCandidate(rest[1]);
21445
- return {
21446
- message: accepted ? `Accepted ${rest[1]} as ${accepted.id}.` : `Candidate ${rest[1]} was not found.`
21447
- };
21491
+ try {
21492
+ const review = (await Sage.listCandidates(false)).find(
21493
+ (c) => c.id === rest[1] && c.kind === "memory_review"
21494
+ );
21495
+ if (review) {
21496
+ const decision = review.suggestedAction === "archive" ? "archive" : "delete";
21497
+ const resolution = await Sage.resolveCandidate(rest[1], decision);
21498
+ if (!resolution) return { message: `Candidate ${rest[1]} was not found.` };
21499
+ if (resolution.error) {
21500
+ return { message: `Could not accept ${rest[1]}: ${resolution.error}` };
21501
+ }
21502
+ return {
21503
+ message: `Accepted review ${rest[1]}: ${decision}${resolution.applied ? "" : " (target memory unchanged)"}.`
21504
+ };
21505
+ }
21506
+ const accepted = await Sage.acceptCandidate(rest[1]);
21507
+ return {
21508
+ message: accepted ? `Accepted ${rest[1]} as ${accepted.id}.` : `Candidate ${rest[1]} was not found.`
21509
+ };
21510
+ } catch (error) {
21511
+ return {
21512
+ message: `Could not accept ${rest[1]}: ${error instanceof Error ? error.message : String(error)}`
21513
+ };
21514
+ }
21448
21515
  }
21449
21516
  if (action === "reject") {
21450
21517
  if (!rest[1])
@@ -31520,7 +31587,8 @@ function buildTodosCommand(opts) {
31520
31587
  ];
31521
31588
  const result = await updateTodos(nextTodos);
31522
31589
  const projected = ctx.todos.find((todo) => todo.id === doneItem.id);
31523
- if (isManagedProjection(doneItem) && projected?.status !== "completed") {
31590
+ const completedAndCleared = ctx.todos.length === 0 && !result.kanban_warnings?.length;
31591
+ if (isManagedProjection(doneItem) && projected?.status !== "completed" && !completedAndCleared) {
31524
31592
  return {
31525
31593
  message: result.kanban_warnings?.[0] ?? `Kanban kept ${doneItem.content} at ${projected?.status ?? "its current state"}.`
31526
31594
  };
@@ -36688,7 +36756,38 @@ import {
36688
36756
  setContextQueryEmbedder,
36689
36757
  shutdownCodebaseIndexHost
36690
36758
  } from "@wrongstack/tools";
36691
- var FILE_EDIT_TOOLS = /* @__PURE__ */ new Set(["write", "edit"]);
36759
+ function editedFilePaths(toolName2, input, cwd) {
36760
+ const args = input ?? {};
36761
+ const resolve9 = (value, base = cwd) => typeof value === "string" && value.length > 0 ? [path30.resolve(base, value)] : [];
36762
+ switch (toolName2) {
36763
+ case "write":
36764
+ case "edit":
36765
+ return resolve9(args["path"]);
36766
+ case "codebase-ast-replace":
36767
+ return resolve9(args["file"]);
36768
+ case "format": {
36769
+ if (args["check"] === true) return [];
36770
+ const files = args["files"];
36771
+ const base = typeof args["cwd"] === "string" ? path30.resolve(cwd, args["cwd"]) : cwd;
36772
+ return (Array.isArray(files) ? files : [files]).flatMap((file) => resolve9(file, base));
36773
+ }
36774
+ case "patch": {
36775
+ if (args["dry_run"] === true || typeof args["patch"] !== "string") return [];
36776
+ const base = typeof args["directory"] === "string" ? path30.resolve(cwd, args["directory"]) : cwd;
36777
+ const strip = typeof args["strip"] === "number" ? args["strip"] : 1;
36778
+ const out = /* @__PURE__ */ new Set();
36779
+ for (const match of args["patch"].matchAll(/^(?:\+\+\+|---) ([^\t\r\n]+)/gm)) {
36780
+ const header = (match[1] ?? "").trim().replace(/^"(.*)"$/, "$1");
36781
+ if (!header || header === "/dev/null") continue;
36782
+ const stripped = header.split("/").slice(strip).join("/");
36783
+ if (stripped) out.add(path30.resolve(base, stripped));
36784
+ }
36785
+ return [...out];
36786
+ }
36787
+ default:
36788
+ return [];
36789
+ }
36790
+ }
36692
36791
  async function setupCodebaseIndexing(deps) {
36693
36792
  const { config, context, pipelines, projectRoot, logger } = deps;
36694
36793
  const idx = config.indexing;
@@ -36727,16 +36826,17 @@ async function setupCodebaseIndexing(deps) {
36727
36826
  handler: async (payload, next) => {
36728
36827
  try {
36729
36828
  const tool = payload.tool;
36730
- if (tool?.mutating && FILE_EDIT_TOOLS.has(tool.name) && !payload.result.is_error) {
36731
- const fp = payload.toolUse.input?.path;
36732
- if (typeof fp === "string" && fp.length > 0) {
36733
- const activeRoot = payload.ctx.projectRoot;
36734
- const abs = path30.resolve(payload.ctx.cwd, fp);
36735
- const rel = path30.relative(activeRoot, abs);
36736
- const inside = rel !== ".." && !rel.startsWith(`..${path30.sep}`) && !path30.isAbsolute(rel);
36737
- if (inside && isIndexableFile(abs)) {
36738
- enqueueReindex({ projectRoot: activeRoot, files: [abs], debounceMs, onError });
36829
+ if (tool && !payload.result.is_error) {
36830
+ const activeRoot = payload.ctx.projectRoot;
36831
+ const files = editedFilePaths(tool.name, payload.toolUse.input, payload.ctx.cwd).filter(
36832
+ (abs) => {
36833
+ const rel = path30.relative(activeRoot, abs);
36834
+ const inside = rel !== ".." && !rel.startsWith(`..${path30.sep}`) && !path30.isAbsolute(rel);
36835
+ return inside && isIndexableFile(abs);
36739
36836
  }
36837
+ );
36838
+ if (files.length > 0) {
36839
+ enqueueReindex({ projectRoot: activeRoot, files, debounceMs, onError });
36740
36840
  }
36741
36841
  }
36742
36842
  } catch {
@@ -38955,4 +39055,4 @@ export {
38955
39055
  CLI_VERSION,
38956
39056
  runInteractive
38957
39057
  };
38958
- //# sourceMappingURL=cli-main-WC5JNIWY.js.map
39058
+ //# sourceMappingURL=cli-main-6JWASRH2.js.map
@@ -19,5 +19,5 @@ export declare function retrieveHostSubagentMemory(deps: MultiAgentDeps, getLead
19
19
  * without it every background tab's memory reads were recorded against a
20
20
  * conversation that never made them.
21
21
  */
22
- owningSessionId?: string): Promise<string[]>;
22
+ owningSessionId?: string): Promise<string | undefined>;
23
23
  //# sourceMappingURL=host-context.d.ts.map
package/dist/index.js CHANGED
@@ -23,7 +23,7 @@ async function main(argv) {
23
23
  const { initializeCli } = await import("./cli-context-5IF7ZYEY.js");
24
24
  const cliCtx = await initializeCli(argv);
25
25
  if (typeof cliCtx === "number") return cliCtx;
26
- const { runInteractive } = await import("./cli-main-WC5JNIWY.js");
26
+ const { runInteractive } = await import("./cli-main-6JWASRH2.js");
27
27
  return runInteractive(cliCtx);
28
28
  }
29
29
 
@@ -17,6 +17,14 @@
17
17
  */
18
18
  import type { AgentPipelines, Context } from '@wrongstack/core/agent';
19
19
  import type { IndexingConfig, Logger } from '@wrongstack/core/types';
20
+ /**
21
+ * Project files a successful file-changing tool call wrote, resolved against
22
+ * `cwd`. Only `write`/`edit` were handled, so `codebase-ast-replace`, `patch`
23
+ * and `format` left the index describing the pre-edit code until a restart
24
+ * (external watching is off by default) — incoming calls and impact analysis
25
+ * then answered for a function body that no longer existed.
26
+ */
27
+ export declare function editedFilePaths(toolName: string, input: unknown, cwd: string): string[];
20
28
  interface CodebaseIndexingDeps {
21
29
  config: {
22
30
  indexing?: IndexingConfig | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/cli",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
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": [
@@ -41,36 +41,36 @@
41
41
  "data"
42
42
  ],
43
43
  "dependencies": {
44
- "@wrongstack/acp": "1.0.11",
45
- "@wrongstack/bench": "1.0.11",
46
- "@wrongstack/core": "1.0.11",
47
- "@wrongstack/kanban": "1.0.11",
48
- "@wrongstack/mcp": "1.0.11",
49
- "@wrongstack/persistence": "1.0.11",
50
- "@wrongstack/plug-lsp": "1.0.11",
51
- "@wrongstack/plugins": "1.0.11",
52
- "@wrongstack/primitives": "1.0.11",
53
- "@wrongstack/providers": "1.0.11",
54
- "@wrongstack/requirement-intake": "1.0.11",
55
- "@wrongstack/runtime": "1.0.11",
56
- "@wrongstack/sage": "1.0.11",
57
- "@wrongstack/sdd": "1.0.11",
58
- "@wrongstack/security-scanner": "1.0.11",
59
- "@wrongstack/simpleui": "1.0.11",
60
- "@wrongstack/techstack": "1.0.11",
61
- "@wrongstack/telegram": "1.0.11",
62
- "@wrongstack/tools": "1.0.11",
63
- "@wrongstack/tui": "1.0.11",
64
- "@wrongstack/vector-memory": "1.0.11",
65
- "@wrongstack/webui": "1.0.11",
66
- "@wrongstack/webui-hq": "1.0.11",
67
- "@wrongstack/webui-protocol": "1.0.11",
68
- "@wrongstack/webui-server": "1.0.11",
69
- "@wrongstack/wrongtrace": "1.0.11",
44
+ "@wrongstack/acp": "1.0.13",
45
+ "@wrongstack/bench": "1.0.13",
46
+ "@wrongstack/core": "1.0.13",
47
+ "@wrongstack/kanban": "1.0.13",
48
+ "@wrongstack/mcp": "1.0.13",
49
+ "@wrongstack/persistence": "1.0.13",
50
+ "@wrongstack/plug-lsp": "1.0.13",
51
+ "@wrongstack/plugins": "1.0.13",
52
+ "@wrongstack/primitives": "1.0.13",
53
+ "@wrongstack/providers": "1.0.13",
54
+ "@wrongstack/requirement-intake": "1.0.13",
55
+ "@wrongstack/runtime": "1.0.13",
56
+ "@wrongstack/sage": "1.0.13",
57
+ "@wrongstack/sdd": "1.0.13",
58
+ "@wrongstack/security-scanner": "1.0.13",
59
+ "@wrongstack/simpleui": "1.0.13",
60
+ "@wrongstack/techstack": "1.0.13",
61
+ "@wrongstack/telegram": "1.0.13",
62
+ "@wrongstack/tools": "1.0.13",
63
+ "@wrongstack/tui": "1.0.13",
64
+ "@wrongstack/vector-memory": "1.0.13",
65
+ "@wrongstack/webui": "1.0.13",
66
+ "@wrongstack/webui-hq": "1.0.13",
67
+ "@wrongstack/webui-protocol": "1.0.13",
68
+ "@wrongstack/webui-server": "1.0.13",
69
+ "@wrongstack/wrongtrace": "1.0.13",
70
70
  "ws": "^8.21.3"
71
71
  },
72
72
  "optionalDependencies": {
73
- "@wrongstack/desktop": "1.0.11"
73
+ "@wrongstack/desktop": "1.0.13"
74
74
  },
75
75
  "devDependencies": {
76
76
  "@types/node": "^26.5.1",