@koda-sl/baker-bridge 0.149.0-dev.7e6763861 → 0.149.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +36 -0
  2. package/dist/hono/agent.d.ts.map +1 -1
  3. package/dist/hono/agent.js +8 -1
  4. package/dist/hono/agent.js.map +1 -1
  5. package/dist/hono/bridge-job.d.ts +18 -4
  6. package/dist/hono/bridge-job.d.ts.map +1 -1
  7. package/dist/hono/bridge-job.js +37 -21
  8. package/dist/hono/bridge-job.js.map +1 -1
  9. package/dist/hono/bridge-job.test.js +190 -40
  10. package/dist/hono/bridge-job.test.js.map +1 -1
  11. package/dist/hono/cli-sync.d.ts +6 -0
  12. package/dist/hono/cli-sync.d.ts.map +1 -0
  13. package/dist/hono/cli-sync.js +108 -0
  14. package/dist/hono/cli-sync.js.map +1 -0
  15. package/dist/hono/cli-sync.test.d.ts +2 -0
  16. package/dist/hono/cli-sync.test.d.ts.map +1 -0
  17. package/dist/hono/cli-sync.test.js +122 -0
  18. package/dist/hono/cli-sync.test.js.map +1 -0
  19. package/dist/hono/main-sync.d.ts +20 -0
  20. package/dist/hono/main-sync.d.ts.map +1 -0
  21. package/dist/hono/main-sync.js +163 -0
  22. package/dist/hono/main-sync.js.map +1 -0
  23. package/dist/hono/main-sync.test.d.ts +2 -0
  24. package/dist/hono/main-sync.test.d.ts.map +1 -0
  25. package/dist/hono/main-sync.test.js +145 -0
  26. package/dist/hono/main-sync.test.js.map +1 -0
  27. package/dist/hono/session-continuity.d.ts +6 -0
  28. package/dist/hono/session-continuity.d.ts.map +1 -1
  29. package/dist/hono/session-continuity.js +5 -1
  30. package/dist/hono/session-continuity.js.map +1 -1
  31. package/dist/hono/session-usage-baseline.d.ts +0 -1
  32. package/dist/hono/session-usage-baseline.d.ts.map +1 -1
  33. package/dist/hono/session-usage-baseline.js +4 -17
  34. package/dist/hono/session-usage-baseline.js.map +1 -1
  35. package/dist/hono/types.d.ts +6 -0
  36. package/dist/hono/types.d.ts.map +1 -1
  37. package/package.json +3 -1
  38. package/dist/hono/served-model.d.ts +0 -23
  39. package/dist/hono/served-model.d.ts.map +0 -1
  40. package/dist/hono/served-model.js +0 -82
  41. package/dist/hono/served-model.js.map +0 -1
  42. package/dist/hono/served-model.test.d.ts +0 -2
  43. package/dist/hono/served-model.test.d.ts.map +0 -1
  44. package/dist/hono/served-model.test.js +0 -29
  45. package/dist/hono/served-model.test.js.map +0 -1
@@ -23,7 +23,6 @@ import { CONNECTION_INPUT_TOOL_NAME } from "./connection-input.js";
23
23
  import { CREDENTIAL_INPUT_TOOL_NAME } from "./credential-input.js";
24
24
  import { FLOW_INPUT_TOOL_NAME } from "./flow-input.js";
25
25
  import { bridgeRuntimeFiles } from "./runtime-files.js";
26
- import { alignServedModels } from "./served-model.js";
27
26
  import { INTERRUPTED_RESUME_PROMPT } from "./session-continuity.js";
28
27
  import { TAG_INPUT_TOOL_NAME } from "./tag-input.js";
29
28
  function history(entries) {
@@ -239,14 +238,11 @@ function createExecutor(options) {
239
238
  : {}),
240
239
  now: options.now,
241
240
  readUsageBaseline: async (sessionId) => options.usageBaselines?.[sessionId],
242
- alignServedModels: async (sessionId) => {
243
- if (options.claudeConfigDir) {
244
- await alignServedModels(sessionId, options.claudeConfigDir);
245
- }
246
- },
247
241
  stalledCliExitMs: 0,
248
242
  prepareAttachments: options.prepareAttachments,
249
243
  ...(options.inFlightTurns ? { inFlightTurns: options.inFlightTurns } : {}),
244
+ ...(options.catchUpWithMain ? { catchUpWithMain: options.catchUpWithMain } : {}),
245
+ ...(options.keepCliInStep ? { keepCliInStep: options.keepCliInStep } : {}),
250
246
  });
251
247
  }
252
248
  function memoryInFlightTurns(initial) {
@@ -961,40 +957,6 @@ describe("BridgeJobExecutor", () => {
961
957
  ],
962
958
  });
963
959
  });
964
- // OpenRouter answers under its own slug. A CLI resuming a transcript that names
965
- // the slug drops every earlier thinking block from its first request, which
966
- // breaks the prompt cache right after the system prompt (BAKER-331).
967
- it("hands the CLI a transcript that names the model the conversation asked for", async () => {
968
- const configDir = await mkdtemp(join(tmpdir(), "bridge-served-model-"));
969
- try {
970
- const transcriptPath = join(configDir, "projects", "-home-user-repo", "session_resume.jsonl");
971
- await mkdir(join(configDir, "projects", "-home-user-repo"), { recursive: true });
972
- await writeFile(transcriptPath, `${JSON.stringify({
973
- type: "assistant",
974
- requestedModel: "claude-opus-5-5",
975
- message: { id: "msg_1", model: "anthropic/claude-opus-5.5", content: [{ type: "thinking", thinking: "t" }] },
976
- })}\n`);
977
- const resumedFrom = [];
978
- const executor = createExecutor({
979
- loadedBoundary: cleanBoundary("session_resume"),
980
- claudeConfigDir: configDir,
981
- queryResults: [
982
- {
983
- async *[Symbol.asyncIterator]() {
984
- await Promise.resolve();
985
- resumedFrom.push(readFileSync(transcriptPath, "utf8"));
986
- yield resultMessage(0.2, "session_next");
987
- },
988
- },
989
- ],
990
- });
991
- await executor.execute({ threadId: "thread_resume", turnId: "turn_resume", prompt: "Continue", history: history([]) }, activeControls());
992
- expect(JSON.parse(resumedFrom[0] ?? "{}").message.model).toBe("claude-opus-5-5");
993
- }
994
- finally {
995
- await rm(configDir, { recursive: true, force: true });
996
- }
997
- });
998
960
  it("publishes without the conversation, and without summarizing it first", async () => {
999
961
  const queryInputs = [];
1000
962
  const savedBoundaries = [];
@@ -1385,6 +1347,38 @@ describe("BridgeJobExecutor", () => {
1385
1347
  }, activeControls());
1386
1348
  expect(queryInputs[0]?.prompt).toBe("/audit-google-ads-account 3865083115");
1387
1349
  });
1350
+ it("keeps a skill command leading when catching up with main is what brought the skill in", async () => {
1351
+ const workspace = await mkdtemp(join(tmpdir(), "baker-job-skill-caught-up-"));
1352
+ await mkdir(join(workspace, ".claude", "skills", "landing"), { recursive: true });
1353
+ projectRootMock.value = workspace;
1354
+ const queryInputs = [];
1355
+ let told = 0;
1356
+ const executor = createExecutor({
1357
+ queryInputs,
1358
+ queryResults: [scriptedMessages(resultMessage(0, "session_skill_caught_up"))],
1359
+ catchUpWithMain: async () => {
1360
+ await mkdir(join(workspace, ".claude", "skills", "audit-google-ads-account"), { recursive: true });
1361
+ return {
1362
+ inWorkspace: true,
1363
+ changed: [".claude/skills/audit-google-ads-account/SKILL.md"],
1364
+ told: () => {
1365
+ told += 1;
1366
+ return Promise.resolve();
1367
+ },
1368
+ };
1369
+ },
1370
+ });
1371
+ await executor.execute({
1372
+ threadId: "thread_skill_caught_up",
1373
+ turnId: "turn_skill_caught_up",
1374
+ prompt: "/audit-google-ads-account 3865083115",
1375
+ history: history([]),
1376
+ currentSender: { name: "Dana", userId: "user_dana" },
1377
+ }, activeControls());
1378
+ expect(queryInputs[0]?.prompt).toBe("/audit-google-ads-account 3865083115");
1379
+ expect(queryInputs[0]?.reminder).toBeUndefined();
1380
+ expect(told).toBe(0);
1381
+ });
1388
1382
  it("passes per-turn MCP servers into Agent SDK query options with the acting user", async () => {
1389
1383
  const queryInputs = [];
1390
1384
  const calls = [];
@@ -1708,6 +1702,132 @@ describe("BridgeJobExecutor", () => {
1708
1702
  expect(queryInputs[0]?.prompt).toBe("/publish");
1709
1703
  expect(queryInputs[0]?.reminder).toBeUndefined();
1710
1704
  });
1705
+ it("tells the agent which files another chat's publish just brought into its workspace", async () => {
1706
+ const queryInputs = [];
1707
+ let told = 0;
1708
+ const executor = createExecutor({
1709
+ queryInputs,
1710
+ catchUpWithMain: async () => ({
1711
+ inWorkspace: true,
1712
+ changed: ["src/pages/home/hero.md"],
1713
+ told: () => {
1714
+ told += 1;
1715
+ return Promise.resolve();
1716
+ },
1717
+ }),
1718
+ });
1719
+ await executor.execute({
1720
+ threadId: "thread_caught_up",
1721
+ turnId: "turn_caught_up",
1722
+ prompt: "Cambia el subtítulo del hero a «Sin entrada, paga en 24 meses».",
1723
+ history: history([
1724
+ { role: "user", text: "¿Qué pone ahora el hero de la home?", createdAt: 1 },
1725
+ {
1726
+ role: "assistant",
1727
+ text: "El titular dice «Paneles solares para tu casa» y el subtítulo «Instala hoy y paga en 12 meses».",
1728
+ createdAt: 2,
1729
+ },
1730
+ ]),
1731
+ }, activeControls());
1732
+ expect(queryInputs[0]?.prompt).toContain("Sin entrada, paga en 24 meses");
1733
+ expect(queryInputs[0]?.reminder).toContain("Read again any of them you work on");
1734
+ expect(queryInputs[0]?.reminder).toContain("- src/pages/home/hero.md");
1735
+ expect(told).toBe(1);
1736
+ });
1737
+ it("keeps the note for the next turn when the user stops this one while the workspace catches up", async () => {
1738
+ const queryInputs = [];
1739
+ const controls = activeControls();
1740
+ let told = 0;
1741
+ const executor = createExecutor({
1742
+ queryInputs,
1743
+ catchUpWithMain: () => {
1744
+ controls.deactivate();
1745
+ return Promise.resolve({
1746
+ inWorkspace: false,
1747
+ changed: ["src/pages/home/hero.md"],
1748
+ told: () => {
1749
+ told += 1;
1750
+ return Promise.resolve();
1751
+ },
1752
+ });
1753
+ },
1754
+ });
1755
+ const outcome = await executor.execute({ threadId: "thread_stopped", turnId: "turn_stopped", prompt: "Cambia el hero", history: history([]) }, controls);
1756
+ expect(outcome.kind).toBe("cancelled");
1757
+ expect(queryInputs).toHaveLength(0);
1758
+ expect(told).toBe(0);
1759
+ });
1760
+ it("keeps the note for the next turn when the user stops this one before its prompt goes out", async () => {
1761
+ const queryInputs = [];
1762
+ const controls = activeControls();
1763
+ let told = 0;
1764
+ const executor = createExecutor({
1765
+ queryInputs,
1766
+ mcpServersProvider: () => {
1767
+ controls.deactivate();
1768
+ return Promise.resolve(undefined);
1769
+ },
1770
+ catchUpWithMain: () => Promise.resolve({
1771
+ inWorkspace: true,
1772
+ changed: ["src/pages/home/hero.md"],
1773
+ told: () => {
1774
+ told += 1;
1775
+ return Promise.resolve();
1776
+ },
1777
+ }),
1778
+ });
1779
+ await executor.execute({ threadId: "thread_stopped_late", turnId: "turn_stopped_late", prompt: "Cambia el hero", history: history([]) }, controls);
1780
+ expect(told).toBe(0);
1781
+ });
1782
+ it("leaves the workspace of a finished Session alone while it is reviewed", async () => {
1783
+ let caughtUp = false;
1784
+ const executor = createExecutor({
1785
+ catchUpWithMain: () => {
1786
+ caughtUp = true;
1787
+ return Promise.resolve(undefined);
1788
+ },
1789
+ });
1790
+ await executor.execute({
1791
+ threadId: "thread_review_sync",
1792
+ turnId: "turn_review_sync",
1793
+ prompt: "review",
1794
+ history: history([]),
1795
+ review: { threadIds: [], chatFacts: { chatId: "chat_1" }, outputRepair: true },
1796
+ }, activeControls());
1797
+ expect(caughtUp).toBe(false);
1798
+ });
1799
+ it("brings the CLI to the release Convex sent before the turn starts", async () => {
1800
+ const queryInputs = [];
1801
+ const requested = [];
1802
+ const executor = createExecutor({
1803
+ queryInputs,
1804
+ keepCliInStep: (wanted) => {
1805
+ requested.push({ wanted, turnStarted: queryInputs.length > 0 });
1806
+ return Promise.resolve();
1807
+ },
1808
+ });
1809
+ await executor.execute({ threadId: "thread_cli", turnId: "turn_cli", prompt: "Hola", cliVersion: "0.412.0", history: history([]) }, activeControls());
1810
+ expect(requested).toEqual([{ wanted: "0.412.0", turnStarted: false }]);
1811
+ expect(queryInputs).toHaveLength(1);
1812
+ });
1813
+ it("keeps the Session's CLI while it is reviewed", async () => {
1814
+ const wanted = [];
1815
+ const executor = createExecutor({
1816
+ keepCliInStep: (version) => {
1817
+ wanted.push(version);
1818
+ return Promise.resolve();
1819
+ },
1820
+ });
1821
+ await executor.execute({
1822
+ threadId: "thread_review_cli",
1823
+ turnId: "turn_review_cli",
1824
+ prompt: "review",
1825
+ cliVersion: "0.412.0",
1826
+ history: history([]),
1827
+ review: { threadIds: [], chatFacts: { chatId: "chat_1" }, outputRepair: true },
1828
+ }, activeControls());
1829
+ expect(wanted).toEqual([]);
1830
+ });
1711
1831
  it("keeps the viewing-reference context beside the message when a stale session falls back to rehydration", async () => {
1712
1832
  const queryInputs = [];
1713
1833
  const executor = createExecutor({
@@ -1811,6 +1931,36 @@ describe("BridgeJobExecutor", () => {
1811
1931
  expect(queryInputs[0]?.options).toMatchObject({ resume: "session_interrupted", forkSession: true });
1812
1932
  expect(relay.contextSources.map((entry) => entry.source)).toEqual(["interrupted_resume"]);
1813
1933
  });
1934
+ it("tells a turn sent again after a restart what another chat published while it was down", async () => {
1935
+ const queryInputs = [];
1936
+ let told = 0;
1937
+ const executor = createExecutor({
1938
+ loadedBoundary: cleanBoundary("session_clean"),
1939
+ queryInputs,
1940
+ inFlightTurns: memoryInFlightTurns({
1941
+ version: 1,
1942
+ turnId: "turn_interrupted_sync",
1943
+ sessionId: "session_interrupted",
1944
+ updatedAtMs: 1,
1945
+ }),
1946
+ catchUpWithMain: () => Promise.resolve({
1947
+ inWorkspace: false,
1948
+ changed: ["src/pages/home/hero.md"],
1949
+ told: () => {
1950
+ told += 1;
1951
+ return Promise.resolve();
1952
+ },
1953
+ }),
1954
+ });
1955
+ await executor.execute({
1956
+ threadId: "thread_interrupted_sync",
1957
+ turnId: "turn_interrupted_sync",
1958
+ prompt: "Rebuild the five pages",
1959
+ }, activeControls());
1960
+ expect(queryInputs[0]?.prompt).toBe(INTERRUPTED_RESUME_PROMPT);
1961
+ expect(queryInputs[0]?.reminder).toContain("- src/pages/home/hero.md");
1962
+ expect(told).toBe(1);
1963
+ });
1814
1964
  it("runs the turn the ordinary way when the interrupted session cannot be resumed", async () => {
1815
1965
  const relay = recordingRelay();
1816
1966
  const queryInputs = [];