@wrongstack/cli 1.1.4 → 1.1.5

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.
Files changed (100) hide show
  1. package/dist/{acp-MZ5MQBFN.js → acp-NKUEYJDZ.js} +6 -5
  2. package/dist/acp-leader/acp-leader-confirm.d.ts +2 -0
  3. package/dist/acp-leader/acp-leader-host-binding.d.ts +1 -0
  4. package/dist/acp-leader/acp-leader-host.d.ts +2 -0
  5. package/dist/acp-leader/acp-leader-picker.d.ts +6 -3
  6. package/dist/acp-leader/acp-leader-stream.d.ts +1 -0
  7. package/dist/{auth-IHQS6AFW.js → auth-2ZG5DBHS.js} +4 -4
  8. package/dist/boot/launch-menu-arrow.d.ts +20 -0
  9. package/dist/boot/launch-menu-types.d.ts +36 -0
  10. package/dist/boot/launch-menu.d.ts +1 -57
  11. package/dist/boot/tui-session-resume-rollback.d.ts +31 -0
  12. package/dist/{boot-auto-thin-7D4OVEWA.js → boot-auto-thin-N2CIGTXE.js} +3 -3
  13. package/dist/{chunk-TZPKOS5G.js → chunk-2XQ6SRKG.js} +2 -2
  14. package/dist/{chunk-JKTJSLUT.js → chunk-5SGMUDP5.js} +242 -18
  15. package/dist/{chunk-3EXRPTAU.js → chunk-5TQ65PXQ.js} +17 -17
  16. package/dist/{chunk-2LTHDKZX.js → chunk-7BM4LGKQ.js} +18 -18
  17. package/dist/{chunk-VAQXOZKP.js → chunk-AJM4EFCM.js} +139 -136
  18. package/dist/{chunk-C2BBH4S4.js → chunk-E3MJFAFR.js} +2 -2
  19. package/dist/{chunk-AWRZWPJ3.js → chunk-JFYQGMMM.js} +99 -75
  20. package/dist/{chunk-BIGSVBPI.js → chunk-KNYIEQAY.js} +64 -61
  21. package/dist/{chunk-GKGWPFW2.js → chunk-LUEO5HLZ.js} +1 -1
  22. package/dist/chunk-LYWOV4OX.js +252 -0
  23. package/dist/{chunk-COGI7EQU.js → chunk-M7FNHCE3.js} +621 -9
  24. package/dist/{chunk-75OLD563.js → chunk-M7PSENGF.js} +3 -1
  25. package/dist/{chunk-TAE3EGBM.js → chunk-MEBXWI7U.js} +5 -5
  26. package/dist/{chunk-I5LJLKA3.js → chunk-MKMM5RIW.js} +12 -5
  27. package/dist/{chunk-ZF4HRR5F.js → chunk-P7MEEUGT.js} +275 -250
  28. package/dist/chunk-QLYPIJ7X.js +258 -0
  29. package/dist/chunk-RN5CFAVQ.js +292 -0
  30. package/dist/{chunk-WDXNBYGD.js → chunk-TDP7CZGE.js} +6 -1
  31. package/dist/{chunk-6VPWQ4TG.js → chunk-UROB7MK5.js} +2 -1
  32. package/dist/chunk-VEESMPTX.js +254 -0
  33. package/dist/{chunk-IJLIAPCW.js → chunk-VPSAKGLK.js} +47 -47
  34. package/dist/{cli-context-E44HQ4ZO.js → cli-context-CQYGIWOU.js} +247 -236
  35. package/dist/{cli-main-OT63I2FX.js → cli-main-VRUJNUBX.js} +1743 -1491
  36. package/dist/cli-main-boot.d.ts +1 -1
  37. package/dist/config-doctor-known-keys.d.ts +33 -0
  38. package/dist/config-doctor.d.ts +2 -47
  39. package/dist/config-history-support.d.ts +36 -0
  40. package/dist/config-history.d.ts +1 -1
  41. package/dist/{config-transfer-Y7XJMJRN.js → config-transfer-B4GOZTFC.js} +2 -2
  42. package/dist/{execution-OK34CJKJ.js → execution-IV72RUSM.js} +5883 -5792
  43. package/dist/execution-tui.d.ts +30 -0
  44. package/dist/fleet/acp-wrongstack-bridge.d.ts +11 -3
  45. package/dist/fleet/host-acp.d.ts +3 -0
  46. package/dist/fleet/wrongforge-client.d.ts +116 -0
  47. package/dist/fleet/wrongforge-gateway.d.ts +20 -0
  48. package/dist/fleet/wrongforge-info.d.ts +32 -0
  49. package/dist/fleet/wrongforge-quota.d.ts +10 -0
  50. package/dist/fleet/wrongforge-runner.d.ts +37 -0
  51. package/dist/fleet/wrongforge-runtime.d.ts +10 -0
  52. package/dist/{hq-JD5AZVMG.js → hq-54PQYR5O.js} +311 -307
  53. package/dist/hq-server/sweeps.d.ts +28 -0
  54. package/dist/{hq-server-BI23EPM7.js → hq-server-YK7FBLL6.js} +3 -3
  55. package/dist/index.js +5 -5
  56. package/dist/mcp-22CFBX4H.js +236 -0
  57. package/dist/mcp-serve.d.ts +0 -63
  58. package/dist/{modeldiag-HDIKG37X.js → modeldiag-5PBB777J.js} +4 -4
  59. package/dist/{per-subcommand-help-4GYSCMLU.js → per-subcommand-help-MQGERD4E.js} +2 -2
  60. package/dist/plugin-llm-command.d.ts +9 -0
  61. package/dist/{plugin-usage-TYF5HY4K.js → plugin-usage-UWKYMNQU.js} +3 -3
  62. package/dist/{plugins-XGAXDLPT.js → plugins-VP7JQH47.js} +4 -4
  63. package/dist/{sdd-runtime-6MFUXWJK.js → sdd-runtime-HIJ4Z5TF.js} +2 -2
  64. package/dist/services/sdd/state.d.ts +2 -0
  65. package/dist/session-event-wiring-types.d.ts +62 -0
  66. package/dist/session-event-wiring.d.ts +2 -52
  67. package/dist/{sessions-config-SJVQXCIE.js → sessions-config-7MK742OW.js} +2 -2
  68. package/dist/short-circuit-flags-AGHURHMQ.js +11 -0
  69. package/dist/slash-commands/command-context-fleet.d.ts +187 -0
  70. package/dist/slash-commands/command-context-sdd-goal.d.ts +102 -0
  71. package/dist/slash-commands/command-context.d.ts +3 -282
  72. package/dist/slash-commands/project-switch-interactive.d.ts +11 -0
  73. package/dist/slash-commands/setmodel-helpers.d.ts +36 -0
  74. package/dist/subcommands/handlers/hq-token.d.ts +3 -0
  75. package/dist/subcommands/handlers/hq.d.ts +0 -21
  76. package/dist/subcommands/handlers/per-subcommand-help-operations.d.ts +8 -0
  77. package/dist/subcommands/handlers/tools-cli-args.d.ts +57 -0
  78. package/dist/subcommands/handlers/tools-cli.d.ts +5 -0
  79. package/dist/subcommands/handlers/tools-serve.d.ts +4 -0
  80. package/dist/{subcommands-YADUV7IJ.js → subcommands-OCJNO57E.js} +2 -2
  81. package/dist/tool-gateway-http.d.ts +30 -0
  82. package/dist/tool-gateway.d.ts +185 -0
  83. package/dist/tools-cli-44MLIUQO.js +509 -0
  84. package/dist/tools-serve-TRCET2M7.js +102 -0
  85. package/dist/{tools-skills-55QVTMSK.js → tools-skills-WDTMCE46.js} +7 -2
  86. package/dist/tuneup-runtime-checks.d.ts +7 -0
  87. package/dist/tuneup-types.d.ts +118 -0
  88. package/dist/tuneup.d.ts +3 -122
  89. package/dist/{typesafe-YBEADNAH.js → typesafe-QLSMFU7J.js} +1 -1
  90. package/dist/{version-help-RBZC5GZZ.js → version-help-X6CC4CFY.js} +2 -2
  91. package/dist/{webui-server-CB64CFDG.js → webui-server-V2R5WQUK.js} +44 -6
  92. package/dist/wiring/provider-runtime-setup.d.ts +3 -1
  93. package/dist/wiring/session-runtime.d.ts +1 -1
  94. package/dist/wrongforge-gateway-UOFBK56J.js +92 -0
  95. package/dist/wrongforge-leader/wrongforge-leader-gateway.d.ts +9 -0
  96. package/dist/wrongforge-leader/wrongforge-leader-picker.d.ts +12 -0
  97. package/dist/wrongforge-leader/wrongforge-leader-provider.d.ts +49 -0
  98. package/package.json +1 -1
  99. package/dist/mcp-W7A5HUXV.js +0 -560
  100. package/dist/short-circuit-flags-QEXUS3BY.js +0 -11
@@ -1,9 +1,27 @@
1
1
  import {
2
+ parseWrongForgeInfo,
3
+ reportWrongForgeQuota,
4
+ writeWrongForgeInfoCache,
2
5
  wrongstackBridgeSetup
3
- } from "./chunk-JKTJSLUT.js";
6
+ } from "./chunk-5SGMUDP5.js";
4
7
  import {
5
8
  isRestrictedMode
6
9
  } from "./chunk-3LEIFO5D.js";
10
+ import {
11
+ WRONGFORGE_AGENT_ID,
12
+ WRONGFORGE_READ_SIDE_TOOLS,
13
+ WfAborted,
14
+ WfHttpError,
15
+ cancelTask,
16
+ chooseModel,
17
+ followTask,
18
+ resolveWrongForgeEndpoint,
19
+ safeWfId,
20
+ terminalTaskRecord,
21
+ toProgress,
22
+ wfTokens,
23
+ wrongForgeCall
24
+ } from "./chunk-VEESMPTX.js";
7
25
  import {
8
26
  buildProviderForId,
9
27
  resolveProviderCfgWithProxy
@@ -12,7 +30,7 @@ import {
12
30
  ACP_LEADER_PROVIDER_ID,
13
31
  acpLeaderHost,
14
32
  trackAcpLeader
15
- } from "./chunk-GKGWPFW2.js";
33
+ } from "./chunk-LUEO5HLZ.js";
16
34
 
17
35
  // src/acp-agent-list.ts
18
36
  import { REGISTRY_ID_ALIASES } from "@wrongstack/acp";
@@ -449,6 +467,7 @@ function startAcpTurnReminders(options) {
449
467
 
450
468
  // src/acp-leader/acp-leader-confirm.ts
451
469
  import { confirmObserverCount } from "@wrongstack/core/agent";
470
+ import { DEFAULT_ALWAYS_TRUST_TTL_MS, scopedApprovalPattern } from "@wrongstack/core/security";
452
471
  var ACP_CONFIRM_TIMEOUT_MS = 12e4;
453
472
  async function confirmThroughEvents(req) {
454
473
  if (req.events.listenerCount("tool.confirm_needed") - confirmObserverCount() <= 0) return false;
@@ -489,10 +508,22 @@ async function confirmThroughEvents(req) {
489
508
  });
490
509
  });
491
510
  if (answer === "abort" || answer === "no") return false;
492
- const rule = { tool: req.tool.name, pattern: req.suggestedPattern };
493
511
  try {
494
- if (answer === "deny") await req.permission?.deny(rule);
495
- else if (answer !== "yes") await req.permission?.trust(rule);
512
+ if (answer === "deny") {
513
+ await req.permission?.deny({ tool: req.tool.name, pattern: req.suggestedPattern });
514
+ } else if (answer !== "yes") {
515
+ await req.permission?.trust({
516
+ tool: req.tool.name,
517
+ pattern: scopedApprovalPattern(
518
+ answer,
519
+ req.tool,
520
+ req.input,
521
+ req.context,
522
+ req.suggestedPattern
523
+ ),
524
+ ttlMs: DEFAULT_ALWAYS_TRUST_TTL_MS
525
+ });
526
+ }
496
527
  } catch {
497
528
  }
498
529
  return answer !== "deny";
@@ -744,7 +775,7 @@ var ToolCardRelay = class {
744
775
  name,
745
776
  id,
746
777
  input: call.rawInput,
747
- provider: "acp",
778
+ provider: this.meta.provider ?? "acp",
748
779
  model: this.meta.model
749
780
  });
750
781
  }
@@ -1176,7 +1207,8 @@ ${withNotes}` : withNotes;
1176
1207
  toolUseId,
1177
1208
  suggestedPattern,
1178
1209
  signal: request.signal,
1179
- permission: host.permission(sessionId)
1210
+ permission: host.permission(sessionId),
1211
+ context: host.context(sessionId)
1180
1212
  });
1181
1213
  }
1182
1214
  async startSession(key, agentId) {
@@ -1302,6 +1334,24 @@ function createAcpLeaderProviderFactory(opts) {
1302
1334
  };
1303
1335
  }
1304
1336
 
1337
+ // src/fleet/wrongforge-runtime.ts
1338
+ var WRONGFORGE_REASONING = {
1339
+ default: "adaptive",
1340
+ disableSupported: true,
1341
+ effortSupported: true,
1342
+ effortLevels: ["none", "minimal", "low", "medium", "high", "xhigh", "max"],
1343
+ preserveThinking: "unsupported"
1344
+ };
1345
+ function wrongForgeRuntime(reasoning, cache, info) {
1346
+ const effort = reasoning?.effort;
1347
+ return {
1348
+ ...reasoning?.enabled === false || effort === "none" ? { effort: "off" } : effort ? {
1349
+ effort: effort === "minimal" ? "low" : (effort === "xhigh" || effort === "max") && !info?.effortLevels?.includes(effort) ? "high" : effort
1350
+ } : {},
1351
+ ...cache?.ttl ? { cache: cache.ttl } : {}
1352
+ };
1353
+ }
1354
+
1305
1355
  // src/wiring/provider.ts
1306
1356
  import { ProviderAuthRegistry, ProviderRegistry } from "@wrongstack/core/registry";
1307
1357
  import { ConfigError } from "@wrongstack/core/types";
@@ -1317,6 +1367,551 @@ import {
1317
1367
  withCatalogCapabilities
1318
1368
  } from "@wrongstack/providers";
1319
1369
  import { registerBuiltinProviderAuthStrategies } from "@wrongstack/providers/oauth";
1370
+
1371
+ // src/wrongforge-leader/wrongforge-leader-provider.ts
1372
+ import { consumeBtwNotes as consumeBtwNotes3 } from "@wrongstack/core/agent";
1373
+ import { ProviderError as ProviderError3 } from "@wrongstack/core/types";
1374
+ import { toErrorMessage as toErrorMessage4 } from "@wrongstack/core/utils";
1375
+
1376
+ // src/wrongforge-leader/wrongforge-leader-gateway.ts
1377
+ import { randomBytes as randomBytes2 } from "node:crypto";
1378
+ import http from "node:http";
1379
+ import {
1380
+ compactToolDefinitionForWire,
1381
+ subjectForToolInput as subjectForToolInput2,
1382
+ toErrorMessage as toErrorMessage3
1383
+ } from "@wrongstack/core/utils";
1384
+ import { timingSafeTokenEqual } from "@wrongstack/primitives";
1385
+ var NOT_OFFERED = /* @__PURE__ */ new Set([
1386
+ "read",
1387
+ "glob",
1388
+ "grep",
1389
+ "fetch",
1390
+ "read_url_content",
1391
+ "tree",
1392
+ "clarify",
1393
+ "tool_use",
1394
+ "tool_script",
1395
+ "tool_search"
1396
+ ]);
1397
+ var MAX_BODY = 4 * 1024 * 1024;
1398
+ async function askUser(host, sessionId, tool, input) {
1399
+ const suggestedPattern = subjectForToolInput2(tool.name, input, tool.subjectKey, tool.subjectFields) ?? tool.name;
1400
+ const toolUseId = `wrongforge-${randomBytes2(6).toString("hex")}`;
1401
+ if (host.confirmAwaiter) {
1402
+ const answer = await host.confirmAwaiter(tool, input, toolUseId, suggestedPattern);
1403
+ return answer !== "no" && answer !== "deny";
1404
+ }
1405
+ if (!host.confirmThroughEvents) return false;
1406
+ return confirmThroughEvents({
1407
+ events: host.events,
1408
+ sessionId,
1409
+ tool,
1410
+ input,
1411
+ toolUseId,
1412
+ suggestedPattern,
1413
+ signal: new AbortController().signal,
1414
+ permission: host.permission(sessionId),
1415
+ context: host.context(sessionId)
1416
+ });
1417
+ }
1418
+ async function startLeaderGateway(host, sessionId) {
1419
+ const tools = (host.listTools?.() ?? []).filter((t) => !NOT_OFFERED.has(t.name));
1420
+ if (tools.length === 0) return void 0;
1421
+ const byName = new Map(tools.map((t) => [t.name, t]));
1422
+ const wireTools = tools.map(
1423
+ (t) => compactToolDefinitionForWire({
1424
+ name: t.name,
1425
+ description: t.description,
1426
+ inputSchema: t.inputSchema ?? { type: "object" }
1427
+ })
1428
+ );
1429
+ const token = randomBytes2(24).toString("hex");
1430
+ const expected = `Bearer ${token}`;
1431
+ const authorized = (req) => timingSafeTokenEqual(req.headers.authorization, expected);
1432
+ const send = (res, status, body) => {
1433
+ const text = JSON.stringify(body);
1434
+ res.writeHead(status, {
1435
+ "content-type": "application/json; charset=utf-8",
1436
+ "content-length": Buffer.byteLength(text)
1437
+ });
1438
+ res.end(text);
1439
+ };
1440
+ const server = http.createServer((req, res) => {
1441
+ if (!authorized(req)) return send(res, 401, { ok: false, error: "unauthorized" });
1442
+ const url = new URL(req.url ?? "/", "http://localhost");
1443
+ if (req.method === "GET" && url.pathname === "/v1/tools") {
1444
+ return send(res, 200, {
1445
+ tools: wireTools.map(({ name: name2, description, inputSchema }) => ({
1446
+ name: name2,
1447
+ description,
1448
+ input_schema: inputSchema
1449
+ }))
1450
+ });
1451
+ }
1452
+ const m = /^\/v1\/tools\/([^/]+)\/call$/.exec(url.pathname);
1453
+ if (req.method !== "POST" || !m) return send(res, 404, { ok: false, error: "not_found" });
1454
+ const name = decodeURIComponent(m[1] ?? "");
1455
+ const tool = byName.get(name);
1456
+ if (!tool) {
1457
+ return send(res, 404, { ok: false, tool: name, error: "not_offered" });
1458
+ }
1459
+ const chunks = [];
1460
+ let size = 0;
1461
+ req.on("data", (c) => {
1462
+ size += c.length;
1463
+ if (size > MAX_BODY) req.destroy();
1464
+ else chunks.push(c);
1465
+ });
1466
+ req.on("end", () => {
1467
+ let input = {};
1468
+ try {
1469
+ const body = JSON.parse(Buffer.concat(chunks).toString("utf8") || "{}");
1470
+ if (body.input && typeof body.input === "object" && !Array.isArray(body.input)) {
1471
+ input = body.input;
1472
+ }
1473
+ } catch {
1474
+ return send(res, 400, { ok: false, tool: name, error: "invalid_json" });
1475
+ }
1476
+ host.runTool(name, input, {
1477
+ sessionId,
1478
+ approve: (t, i) => askUser(host, sessionId, t, i)
1479
+ }).then(
1480
+ (r) => send(res, 200, { ok: !r.isError, tool: name, content: r.content }),
1481
+ (err) => send(res, 200, {
1482
+ ok: false,
1483
+ tool: name,
1484
+ error: "tool_failed",
1485
+ message: toErrorMessage3(err)
1486
+ })
1487
+ );
1488
+ });
1489
+ });
1490
+ await new Promise((resolve, reject) => {
1491
+ server.once("error", reject);
1492
+ server.listen(0, "127.0.0.1", () => {
1493
+ server.removeListener("error", reject);
1494
+ resolve();
1495
+ });
1496
+ });
1497
+ server.unref();
1498
+ const port = server.address().port;
1499
+ return {
1500
+ spec: {
1501
+ url: `http://127.0.0.1:${port}`,
1502
+ token,
1503
+ list_path: "/v1/tools",
1504
+ call_path: "/v1/tools/{name}/call",
1505
+ name_prefix: "wstack_"
1506
+ },
1507
+ tools: [...byName.keys()],
1508
+ close: () => new Promise((resolve) => server.close(() => resolve()))
1509
+ };
1510
+ }
1511
+
1512
+ // src/wrongforge-leader/wrongforge-leader-provider.ts
1513
+ var WRONGFORGE_LEADER_PROVIDER_ID = WRONGFORGE_AGENT_ID;
1514
+ var LEADER_MAX_STEPS = 150;
1515
+ var LEADER_TURN_TIMEOUT_MS = 2 * 60 * 6e4;
1516
+ var CAPABILITIES2 = {
1517
+ tools: true,
1518
+ parallelTools: false,
1519
+ vision: false,
1520
+ streaming: true,
1521
+ promptCache: true,
1522
+ systemPrompt: true,
1523
+ jsonMode: false,
1524
+ reasoning: true,
1525
+ // Learned from WrongForge's first task result (its model's window).
1526
+ maxContext: 0,
1527
+ maxOutput: 32e3,
1528
+ cacheControl: "native",
1529
+ topK: false,
1530
+ frequencyPenalty: false,
1531
+ presencePenalty: false,
1532
+ seed: false,
1533
+ structuredOutput: false,
1534
+ logprobs: false,
1535
+ audio: false,
1536
+ multipleCompletions: false,
1537
+ // WrongForge keeps the conversation (its session) and compacts it itself.
1538
+ keepsOwnContext: true
1539
+ };
1540
+ function leaderAppend(routed, tools) {
1541
+ const has = (n) => tools.includes(n);
1542
+ return [
1543
+ "In this task you LEAD a WrongStack session: a human user talks to you through",
1544
+ "WrongStack, and your reply goes to them, not to an orchestrator. Answer them directly,",
1545
+ "ask when something is truly ambiguous, and end a turn when the work or the answer is done.",
1546
+ "The worker-only rules of the WrongStack guide (no human watching, reply = report to a",
1547
+ "leader) do not apply to you; the rest (stay in the workdir, no git history rewrites, no",
1548
+ "commit or push unless asked) does.",
1549
+ ...routed ? [
1550
+ "Your own write/edit/shell tools are off: change files with WrongStack's `wstack_edit` /",
1551
+ "`wstack_write` / `wstack_patch` and run commands with `wstack_bash` (or `wstack_test`,",
1552
+ "`wstack_lint`, `wstack_typecheck`). They run in the user's session, under their rules."
1553
+ ] : [],
1554
+ ...has("delegate") ? [
1555
+ "`wstack_delegate` hands work to WrongStack workers (scope and outOfScope required); the",
1556
+ "result arrives later as a [DELEGATION RESULT] message, so end your turn or keep working."
1557
+ ] : [],
1558
+ ...has("remember") || has("memory_search") ? ["`wstack_memory_search` / `wstack_remember` are the project memory: check it, add to it."] : []
1559
+ ].join(" ");
1560
+ }
1561
+ function flatten(req) {
1562
+ const text = (m) => typeof m.content === "string" ? m.content : m.content.map((b) => "text" in b && typeof b.text === "string" ? b.text : "").filter(Boolean).join("\n");
1563
+ const system = (req.system ?? []).map((b) => b.text).join("\n\n");
1564
+ const turns = req.messages.map((m) => `[${m.role}]
1565
+ ${text(m)}`).join("\n\n");
1566
+ return [
1567
+ system ? `<instructions>
1568
+ ${system}
1569
+ </instructions>` : "",
1570
+ turns,
1571
+ "Reply to the last message, following the instructions above. Use no tools."
1572
+ ].filter(Boolean).join("\n\n");
1573
+ }
1574
+ function providerError(err, id) {
1575
+ if (err instanceof ProviderError3) return err;
1576
+ const make = (message, status, retryable, kind) => new ProviderError3(`WrongForge: ${message}`, status, retryable, id, { kind });
1577
+ if (err instanceof WfAborted) return make("the turn was cancelled", 499, false, "unknown");
1578
+ if (err instanceof WfHttpError) {
1579
+ if (err.status === 401 || err.status === 403 || err.code === "not_signed_in")
1580
+ return make(err.message, 401, false, "auth");
1581
+ if (err.status === 0) return make(err.message, 0, true, "network");
1582
+ if (err.status >= 500) return make(err.message, err.status, true, "server");
1583
+ return make(`${err.code}: ${err.message}`, err.status, false, "invalid_request");
1584
+ }
1585
+ return make(toErrorMessage4(err), 0, false, "unknown");
1586
+ }
1587
+ function taskError(record, id) {
1588
+ const make = (message, status, retryable, kind) => new ProviderError3(`WrongForge: ${message}`, status, retryable, id, { kind });
1589
+ switch (record.status) {
1590
+ case "completed":
1591
+ return void 0;
1592
+ case "cancelled":
1593
+ return make(
1594
+ `the turn was cancelled${record.cancel_reason ? ` (${record.cancel_reason})` : ""}`,
1595
+ 499,
1596
+ false,
1597
+ "unknown"
1598
+ );
1599
+ case "timed_out":
1600
+ return make("the turn hit its timeout", 408, false, "timeout");
1601
+ default: {
1602
+ const code = record.error?.code ?? "internal_error";
1603
+ const message = `${code}: ${record.error?.message ?? "no detail"}`;
1604
+ if (code === "context_overflow") return make(message, 413, false, "context_overflow");
1605
+ if (/rate.?limit|429/i.test(message)) return make(message, 429, true, "rate_limit");
1606
+ if (/quota|usage limit|extra usage/i.test(message))
1607
+ return make(message, 402, false, "quota_exhausted");
1608
+ return make(message, 500, code === "server_restarted", "server");
1609
+ }
1610
+ }
1611
+ }
1612
+ var WrongForgeLeaderProvider = class {
1613
+ constructor(opts) {
1614
+ this.opts = opts;
1615
+ this.id = opts.id ?? WRONGFORGE_LEADER_PROVIDER_ID;
1616
+ trackAcpLeader(this);
1617
+ }
1618
+ opts;
1619
+ id;
1620
+ capabilities = { ...CAPABILITIES2 };
1621
+ sessions = /* @__PURE__ */ new Map();
1622
+ sideProviders = /* @__PURE__ */ new Map();
1623
+ config() {
1624
+ return acpLeaderHost()?.getConfig() ?? this.opts.bootConfig;
1625
+ }
1626
+ client() {
1627
+ const ep = resolveWrongForgeEndpoint();
1628
+ if (!ep) {
1629
+ throw new ProviderError3(
1630
+ "WrongForge: no API key found. Start it once with `npm run serve` (it saves ~/.wrongforge/api-key) or set WRONGFORGE_API_KEY.",
1631
+ 401,
1632
+ false,
1633
+ this.id,
1634
+ { kind: "auth" }
1635
+ );
1636
+ }
1637
+ void reportWrongForgeQuota({
1638
+ endpoint: ep,
1639
+ providerId: this.id,
1640
+ fetchImpl: this.opts.fetchImpl
1641
+ });
1642
+ return wrongForgeCall(ep, this.opts.fetchImpl);
1643
+ }
1644
+ async info(call, signal) {
1645
+ try {
1646
+ const info = parseWrongForgeInfo(await call("GET", "/v1/info", void 0, signal));
1647
+ writeWrongForgeInfoCache(info);
1648
+ return info;
1649
+ } catch {
1650
+ return void 0;
1651
+ }
1652
+ }
1653
+ model(requested, info) {
1654
+ const choice = chooseModel(requested, void 0, info);
1655
+ if (choice.error) {
1656
+ throw new ProviderError3(choice.error, 400, false, this.id, { kind: "invalid_request" });
1657
+ }
1658
+ return choice.id;
1659
+ }
1660
+ /** A configured side model, when the user named one. */
1661
+ sideProvider() {
1662
+ const ref = leaderSideModel(this.config());
1663
+ if (!ref || ref.provider === this.id) return void 0;
1664
+ let provider = this.sideProviders.get(ref.provider);
1665
+ if (!provider) {
1666
+ provider = this.opts.buildProvider(ref.provider, this.config());
1667
+ if (provider) this.sideProviders.set(ref.provider, provider);
1668
+ }
1669
+ return provider ? { provider, model: ref.model } : void 0;
1670
+ }
1671
+ async complete(req, opts) {
1672
+ const side = this.sideProvider();
1673
+ if (side) return side.provider.complete({ ...req, model: side.model }, opts);
1674
+ return this.oneShot(req, opts.signal);
1675
+ }
1676
+ /** WrongForge as a plain model: one step, no tools, its own throwaway session. */
1677
+ async oneShot(req, signal) {
1678
+ const call = this.client();
1679
+ try {
1680
+ const info = await this.info(call, signal);
1681
+ const model = this.model(req.model, info);
1682
+ const host = acpLeaderHost();
1683
+ const { task } = await call(
1684
+ "POST",
1685
+ "/v1/tasks",
1686
+ {
1687
+ prompt: flatten(req),
1688
+ workdir: host?.projectRoot ?? process.cwd(),
1689
+ ...model ? { model } : {},
1690
+ max_steps: 1,
1691
+ builtin_tools: [],
1692
+ ...wrongForgeRuntime(req.reasoning, req.cache, info),
1693
+ wait: true,
1694
+ cancel_on_disconnect: true
1695
+ },
1696
+ signal
1697
+ );
1698
+ const failure = taskError(task, this.id);
1699
+ if (failure) throw failure;
1700
+ const usage = wfTokens(task.result?.usage);
1701
+ return {
1702
+ model: model ?? req.model,
1703
+ content: [{ type: "text", text: task.result?.text ?? "" }],
1704
+ stopReason: "end_turn",
1705
+ usage
1706
+ };
1707
+ } catch (err) {
1708
+ throw providerError(err, this.id);
1709
+ } finally {
1710
+ void reportWrongForgeQuota({ providerId: this.id, fetchImpl: this.opts.fetchImpl });
1711
+ }
1712
+ }
1713
+ async *stream(req, opts) {
1714
+ if (!isLeaderTurn(req)) {
1715
+ const side = this.sideProvider();
1716
+ if (side) {
1717
+ yield* side.provider.stream({ ...req, model: side.model }, opts);
1718
+ return;
1719
+ }
1720
+ const res = await this.complete(req, opts);
1721
+ yield { type: "message_start", model: res.model };
1722
+ const text = res.content.map((b) => "text" in b ? b.text : "").join("");
1723
+ if (text) {
1724
+ yield { type: "content_block_start", kind: "text" };
1725
+ yield { type: "text_delta", text };
1726
+ yield { type: "content_block_stop", index: 0 };
1727
+ }
1728
+ yield { type: "message_stop", stopReason: "end_turn", usage: res.usage };
1729
+ return;
1730
+ }
1731
+ const call = this.client();
1732
+ const host = acpLeaderHost();
1733
+ const key = req.cache?.sessionId ?? "default";
1734
+ const leader = this.sessionFor(key);
1735
+ let info;
1736
+ let model;
1737
+ let gateway;
1738
+ let joinedBefore;
1739
+ try {
1740
+ info = await this.info(call, opts.signal);
1741
+ model = this.model(req.model, info);
1742
+ if (host) leader.gateway ??= startLeaderGateway(host, key).catch(() => void 0);
1743
+ gateway = await leader.gateway;
1744
+ joinedBefore = leader.joined ?? await this.wfSessionExists(call, leader, opts.signal);
1745
+ } catch (err) {
1746
+ throw providerError(err, this.id);
1747
+ }
1748
+ const routed = gateway !== void 0 && (info?.features.includes("builtin_tools") ?? false);
1749
+ const queue = new StreamQueue();
1750
+ const blocks = new TextBlocks(queue);
1751
+ const cards = new ToolCardRelay(host?.events, {
1752
+ sessionId: req.cache?.sessionId,
1753
+ model: model ?? req.model,
1754
+ provider: this.id
1755
+ });
1756
+ yield { type: "message_start", model: model ?? req.model };
1757
+ let taskId;
1758
+ const onAbort = () => {
1759
+ if (taskId) cancelTask(call, taskId, "interrupted in WrongStack");
1760
+ };
1761
+ opts.signal.addEventListener("abort", onAbort, { once: true });
1762
+ const run = (async () => {
1763
+ const { task } = await call(
1764
+ "POST",
1765
+ "/v1/tasks",
1766
+ {
1767
+ prompt: this.promptText(req, joinedBefore),
1768
+ session_id: leader.wfSessionId,
1769
+ workdir: host?.projectRoot ?? process.cwd(),
1770
+ ...model ? { model } : {},
1771
+ max_steps: LEADER_MAX_STEPS,
1772
+ timeout_ms: LEADER_TURN_TIMEOUT_MS,
1773
+ ...wrongForgeRuntime(req.reasoning, req.cache, info),
1774
+ system_append: leaderAppend(routed, gateway?.tools ?? []),
1775
+ context: { wrongstack: { sessionId: key, role: "leader" } },
1776
+ ...gateway ? { gateway: { ...gateway.spec, optional: !routed } } : {},
1777
+ ...routed ? { builtin_tools: WRONGFORGE_READ_SIDE_TOOLS } : {}
1778
+ },
1779
+ opts.signal
1780
+ );
1781
+ taskId = task.id;
1782
+ leader.joined = true;
1783
+ for await (const ev of followTask(call, task.id, opts.signal)) {
1784
+ if (ev.type === "task.heartbeat" || ev.type === "step.finished") {
1785
+ void reportWrongForgeQuota({ providerId: this.id, fetchImpl: this.opts.fetchImpl });
1786
+ }
1787
+ const external = ev.data["external"] === true;
1788
+ for (const p of toProgress(ev)) {
1789
+ if (p.type === "message") blocks.text(p.text);
1790
+ else if (p.type === "tool_call") {
1791
+ blocks.close();
1792
+ if (!external) cards.update(p.toolCall);
1793
+ } else if (p.type === "tool_call_update" && !external) cards.update(p.toolCall);
1794
+ }
1795
+ if (ev.type === "step.finished" && typeof ev.data["context_tokens"] === "number") {
1796
+ this.observeContext(leader, req.cache?.sessionId, {
1797
+ used: ev.data["context_tokens"],
1798
+ size: this.capabilities.maxContext
1799
+ });
1800
+ }
1801
+ }
1802
+ const done = await terminalTaskRecord(call, task.id, opts.signal);
1803
+ blocks.close();
1804
+ const failure = taskError(done, this.id);
1805
+ if (failure) throw failure;
1806
+ const window = done.result?.context_window ?? 0;
1807
+ if (window > 0) this.capabilities.maxContext = window;
1808
+ if (typeof done.result?.context_tokens === "number") {
1809
+ this.observeContext(leader, req.cache?.sessionId, {
1810
+ used: done.result.context_tokens,
1811
+ size: window
1812
+ });
1813
+ }
1814
+ queue.push({
1815
+ type: "message_stop",
1816
+ stopReason: done.result?.finish_reason === "length" ? "max_tokens" : "end_turn",
1817
+ usage: wfTokens(done.result?.usage),
1818
+ ...leader.context ? { agentContext: leader.context } : {}
1819
+ });
1820
+ queue.end();
1821
+ })().catch((err) => {
1822
+ blocks.close();
1823
+ queue.fail(providerError(err, this.id));
1824
+ });
1825
+ try {
1826
+ yield* queue.drain();
1827
+ } finally {
1828
+ opts.signal.removeEventListener("abort", onAbort);
1829
+ await run;
1830
+ void reportWrongForgeQuota({ providerId: this.id, fetchImpl: this.opts.fetchImpl });
1831
+ }
1832
+ }
1833
+ /** The turn's prompt; WrongForge joining a conversation under way gets the turns before it. */
1834
+ promptText(req, joined) {
1835
+ const latest = latestUserText(req.messages);
1836
+ const earlier = joined ? void 0 : earlierConversation(req.messages);
1837
+ const prompt = earlier ? `${earlier}
1838
+
1839
+ ${latest}` : latest;
1840
+ const context = acpLeaderHost()?.context(req.cache?.sessionId);
1841
+ const notes = context?.meta ? consumeBtwNotes3(context) : [];
1842
+ return notes.length > 0 ? `${prompt}
1843
+
1844
+ ${acpBtwBlock(notes)}` : prompt;
1845
+ }
1846
+ async wfSessionExists(call, leader, signal) {
1847
+ try {
1848
+ await call(
1849
+ "GET",
1850
+ `/v1/sessions/${encodeURIComponent(leader.wfSessionId)}`,
1851
+ void 0,
1852
+ signal
1853
+ );
1854
+ return true;
1855
+ } catch (err) {
1856
+ if (err instanceof WfHttpError && err.status === 404) return false;
1857
+ throw err;
1858
+ }
1859
+ }
1860
+ sessionFor(key) {
1861
+ let leader = this.sessions.get(key);
1862
+ if (!leader) {
1863
+ leader = { wfSessionId: `wsl-${safeWfId(key)}` };
1864
+ this.sessions.set(key, leader);
1865
+ }
1866
+ return leader;
1867
+ }
1868
+ observeContext(leader, sessionId, reading) {
1869
+ leader.context = { used: reading.used, size: reading.size || this.capabilities.maxContext };
1870
+ publishLeaderContext(
1871
+ acpLeaderHost()?.events,
1872
+ sessionId,
1873
+ leader.context,
1874
+ this.capabilities.maxContext
1875
+ );
1876
+ }
1877
+ /** `/compact` on this route: WrongForge compacts its own session. */
1878
+ async compactOwnContext(opts) {
1879
+ const leader = this.sessions.get(opts.sessionId);
1880
+ if (!leader) return void 0;
1881
+ const call = this.client();
1882
+ try {
1883
+ await call(
1884
+ "POST",
1885
+ `/v1/sessions/${encodeURIComponent(leader.wfSessionId)}/compact`,
1886
+ {},
1887
+ opts.signal
1888
+ );
1889
+ } catch (err) {
1890
+ throw providerError(err, this.id);
1891
+ }
1892
+ leader.context = void 0;
1893
+ return void 0;
1894
+ }
1895
+ /** Close every session gateway (process shutdown). */
1896
+ async closeAll() {
1897
+ const all = [...this.sessions.values()];
1898
+ this.sessions.clear();
1899
+ await Promise.all(all.map((s) => s.gateway?.then((g) => g?.close()).catch(() => void 0)));
1900
+ }
1901
+ };
1902
+ function createWrongForgeLeaderProviderFactory(opts) {
1903
+ return {
1904
+ type: WRONGFORGE_LEADER_PROVIDER_ID,
1905
+ // Routing metadata only: the provider does no wire conversion.
1906
+ family: "openai-compatible",
1907
+ create: (cfg) => new WrongForgeLeaderProvider({
1908
+ ...opts,
1909
+ id: cfg.type || WRONGFORGE_LEADER_PROVIDER_ID
1910
+ })
1911
+ };
1912
+ }
1913
+
1914
+ // src/wiring/provider.ts
1320
1915
  async function setupProvider(params) {
1321
1916
  const { config, modelsRegistry, logger } = params;
1322
1917
  const providerAuthRegistry = new ProviderAuthRegistry();
@@ -1333,7 +1928,16 @@ async function setupProvider(params) {
1333
1928
  }
1334
1929
  const savedProviderCfg = config.providers?.[config.provider];
1335
1930
  const acpLeader = config.provider === ACP_LEADER_PROVIDER_ID;
1336
- let resolvedProvider = acpLeader ? {
1931
+ const wrongForgeLeader = config.provider === WRONGFORGE_LEADER_PROVIDER_ID;
1932
+ let resolvedProvider = wrongForgeLeader ? {
1933
+ id: WRONGFORGE_LEADER_PROVIDER_ID,
1934
+ name: "WrongForge",
1935
+ family: "openai-compatible",
1936
+ apiBase: void 0,
1937
+ envVars: [],
1938
+ models: [{ id: config.model, name: config.model }],
1939
+ npm: void 0
1940
+ } : acpLeader ? {
1337
1941
  id: ACP_LEADER_PROVIDER_ID,
1338
1942
  name: "ACP agent",
1339
1943
  family: "openai-compatible",
@@ -1393,6 +1997,12 @@ async function setupProvider(params) {
1393
1997
  buildProvider: (providerId, live) => buildProviderForId({ config: live, providerRegistry, logger }, providerId)
1394
1998
  })
1395
1999
  );
2000
+ providerRegistry.register(
2001
+ createWrongForgeLeaderProviderFactory({
2002
+ bootConfig: config,
2003
+ buildProvider: (providerId, live) => buildProviderForId({ config: live, providerRegistry, logger }, providerId)
2004
+ })
2005
+ );
1396
2006
  if (config.features.modelsRegistry) {
1397
2007
  try {
1398
2008
  const factories = await buildProviderFactoriesFromRegistry({
@@ -1452,7 +2062,9 @@ export {
1452
2062
  wrongstackAcpPermissionPolicy,
1453
2063
  recordAcpRateLimit,
1454
2064
  startAcpTurnReminders,
2065
+ WRONGFORGE_REASONING,
2066
+ wrongForgeRuntime,
1455
2067
  setupProvider,
1456
2068
  createGracefulShutdown
1457
2069
  };
1458
- //# sourceMappingURL=chunk-COGI7EQU.js.map
2070
+ //# sourceMappingURL=chunk-M7FNHCE3.js.map