@koda-sl/baker-bridge 0.149.0-dev.7e6763861 → 0.150.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/dist/hono/agent.d.ts.map +1 -1
- package/dist/hono/agent.js +8 -1
- package/dist/hono/agent.js.map +1 -1
- package/dist/hono/bridge-job.d.ts +18 -3
- package/dist/hono/bridge-job.d.ts.map +1 -1
- package/dist/hono/bridge-job.js +36 -9
- package/dist/hono/bridge-job.js.map +1 -1
- package/dist/hono/bridge-job.test.js +191 -7
- package/dist/hono/bridge-job.test.js.map +1 -1
- package/dist/hono/cli-sync.d.ts +6 -0
- package/dist/hono/cli-sync.d.ts.map +1 -0
- package/dist/hono/cli-sync.js +108 -0
- package/dist/hono/cli-sync.js.map +1 -0
- package/dist/hono/cli-sync.test.d.ts +2 -0
- package/dist/hono/cli-sync.test.d.ts.map +1 -0
- package/dist/hono/cli-sync.test.js +122 -0
- package/dist/hono/cli-sync.test.js.map +1 -0
- package/dist/hono/main-sync.d.ts +20 -0
- package/dist/hono/main-sync.d.ts.map +1 -0
- package/dist/hono/main-sync.js +163 -0
- package/dist/hono/main-sync.js.map +1 -0
- package/dist/hono/main-sync.test.d.ts +2 -0
- package/dist/hono/main-sync.test.d.ts.map +1 -0
- package/dist/hono/main-sync.test.js +145 -0
- package/dist/hono/main-sync.test.js.map +1 -0
- package/dist/hono/session-continuity.d.ts +6 -0
- package/dist/hono/session-continuity.d.ts.map +1 -1
- package/dist/hono/session-continuity.js +5 -1
- package/dist/hono/session-continuity.js.map +1 -1
- package/dist/hono/types.d.ts +6 -0
- package/dist/hono/types.d.ts.map +1 -1
- package/package.json +3 -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) {
|
|
@@ -974,10 +970,10 @@ describe("BridgeJobExecutor", () => {
|
|
|
974
970
|
requestedModel: "claude-opus-5-5",
|
|
975
971
|
message: { id: "msg_1", model: "anthropic/claude-opus-5.5", content: [{ type: "thinking", thinking: "t" }] },
|
|
976
972
|
})}\n`);
|
|
973
|
+
vi.stubEnv("CLAUDE_CONFIG_DIR", configDir);
|
|
977
974
|
const resumedFrom = [];
|
|
978
975
|
const executor = createExecutor({
|
|
979
976
|
loadedBoundary: cleanBoundary("session_resume"),
|
|
980
|
-
claudeConfigDir: configDir,
|
|
981
977
|
queryResults: [
|
|
982
978
|
{
|
|
983
979
|
async *[Symbol.asyncIterator]() {
|
|
@@ -1385,6 +1381,38 @@ describe("BridgeJobExecutor", () => {
|
|
|
1385
1381
|
}, activeControls());
|
|
1386
1382
|
expect(queryInputs[0]?.prompt).toBe("/audit-google-ads-account 3865083115");
|
|
1387
1383
|
});
|
|
1384
|
+
it("keeps a skill command leading when catching up with main is what brought the skill in", async () => {
|
|
1385
|
+
const workspace = await mkdtemp(join(tmpdir(), "baker-job-skill-caught-up-"));
|
|
1386
|
+
await mkdir(join(workspace, ".claude", "skills", "landing"), { recursive: true });
|
|
1387
|
+
projectRootMock.value = workspace;
|
|
1388
|
+
const queryInputs = [];
|
|
1389
|
+
let told = 0;
|
|
1390
|
+
const executor = createExecutor({
|
|
1391
|
+
queryInputs,
|
|
1392
|
+
queryResults: [scriptedMessages(resultMessage(0, "session_skill_caught_up"))],
|
|
1393
|
+
catchUpWithMain: async () => {
|
|
1394
|
+
await mkdir(join(workspace, ".claude", "skills", "audit-google-ads-account"), { recursive: true });
|
|
1395
|
+
return {
|
|
1396
|
+
inWorkspace: true,
|
|
1397
|
+
changed: [".claude/skills/audit-google-ads-account/SKILL.md"],
|
|
1398
|
+
told: () => {
|
|
1399
|
+
told += 1;
|
|
1400
|
+
return Promise.resolve();
|
|
1401
|
+
},
|
|
1402
|
+
};
|
|
1403
|
+
},
|
|
1404
|
+
});
|
|
1405
|
+
await executor.execute({
|
|
1406
|
+
threadId: "thread_skill_caught_up",
|
|
1407
|
+
turnId: "turn_skill_caught_up",
|
|
1408
|
+
prompt: "/audit-google-ads-account 3865083115",
|
|
1409
|
+
history: history([]),
|
|
1410
|
+
currentSender: { name: "Dana", userId: "user_dana" },
|
|
1411
|
+
}, activeControls());
|
|
1412
|
+
expect(queryInputs[0]?.prompt).toBe("/audit-google-ads-account 3865083115");
|
|
1413
|
+
expect(queryInputs[0]?.reminder).toBeUndefined();
|
|
1414
|
+
expect(told).toBe(0);
|
|
1415
|
+
});
|
|
1388
1416
|
it("passes per-turn MCP servers into Agent SDK query options with the acting user", async () => {
|
|
1389
1417
|
const queryInputs = [];
|
|
1390
1418
|
const calls = [];
|
|
@@ -1708,6 +1736,132 @@ describe("BridgeJobExecutor", () => {
|
|
|
1708
1736
|
expect(queryInputs[0]?.prompt).toBe("/publish");
|
|
1709
1737
|
expect(queryInputs[0]?.reminder).toBeUndefined();
|
|
1710
1738
|
});
|
|
1739
|
+
it("tells the agent which files another chat's publish just brought into its workspace", async () => {
|
|
1740
|
+
const queryInputs = [];
|
|
1741
|
+
let told = 0;
|
|
1742
|
+
const executor = createExecutor({
|
|
1743
|
+
queryInputs,
|
|
1744
|
+
catchUpWithMain: async () => ({
|
|
1745
|
+
inWorkspace: true,
|
|
1746
|
+
changed: ["src/pages/home/hero.md"],
|
|
1747
|
+
told: () => {
|
|
1748
|
+
told += 1;
|
|
1749
|
+
return Promise.resolve();
|
|
1750
|
+
},
|
|
1751
|
+
}),
|
|
1752
|
+
});
|
|
1753
|
+
await executor.execute({
|
|
1754
|
+
threadId: "thread_caught_up",
|
|
1755
|
+
turnId: "turn_caught_up",
|
|
1756
|
+
prompt: "Cambia el subtítulo del hero a «Sin entrada, paga en 24 meses».",
|
|
1757
|
+
history: history([
|
|
1758
|
+
{ role: "user", text: "¿Qué pone ahora el hero de la home?", createdAt: 1 },
|
|
1759
|
+
{
|
|
1760
|
+
role: "assistant",
|
|
1761
|
+
text: "El titular dice «Paneles solares para tu casa» y el subtítulo «Instala hoy y paga en 12 meses».",
|
|
1762
|
+
createdAt: 2,
|
|
1763
|
+
},
|
|
1764
|
+
]),
|
|
1765
|
+
}, activeControls());
|
|
1766
|
+
expect(queryInputs[0]?.prompt).toContain("Sin entrada, paga en 24 meses");
|
|
1767
|
+
expect(queryInputs[0]?.reminder).toContain("Read again any of them you work on");
|
|
1768
|
+
expect(queryInputs[0]?.reminder).toContain("- src/pages/home/hero.md");
|
|
1769
|
+
expect(told).toBe(1);
|
|
1770
|
+
});
|
|
1771
|
+
it("keeps the note for the next turn when the user stops this one while the workspace catches up", async () => {
|
|
1772
|
+
const queryInputs = [];
|
|
1773
|
+
const controls = activeControls();
|
|
1774
|
+
let told = 0;
|
|
1775
|
+
const executor = createExecutor({
|
|
1776
|
+
queryInputs,
|
|
1777
|
+
catchUpWithMain: () => {
|
|
1778
|
+
controls.deactivate();
|
|
1779
|
+
return Promise.resolve({
|
|
1780
|
+
inWorkspace: false,
|
|
1781
|
+
changed: ["src/pages/home/hero.md"],
|
|
1782
|
+
told: () => {
|
|
1783
|
+
told += 1;
|
|
1784
|
+
return Promise.resolve();
|
|
1785
|
+
},
|
|
1786
|
+
});
|
|
1787
|
+
},
|
|
1788
|
+
});
|
|
1789
|
+
const outcome = await executor.execute({ threadId: "thread_stopped", turnId: "turn_stopped", prompt: "Cambia el hero", history: history([]) }, controls);
|
|
1790
|
+
expect(outcome.kind).toBe("cancelled");
|
|
1791
|
+
expect(queryInputs).toHaveLength(0);
|
|
1792
|
+
expect(told).toBe(0);
|
|
1793
|
+
});
|
|
1794
|
+
it("keeps the note for the next turn when the user stops this one before its prompt goes out", async () => {
|
|
1795
|
+
const queryInputs = [];
|
|
1796
|
+
const controls = activeControls();
|
|
1797
|
+
let told = 0;
|
|
1798
|
+
const executor = createExecutor({
|
|
1799
|
+
queryInputs,
|
|
1800
|
+
mcpServersProvider: () => {
|
|
1801
|
+
controls.deactivate();
|
|
1802
|
+
return Promise.resolve(undefined);
|
|
1803
|
+
},
|
|
1804
|
+
catchUpWithMain: () => Promise.resolve({
|
|
1805
|
+
inWorkspace: true,
|
|
1806
|
+
changed: ["src/pages/home/hero.md"],
|
|
1807
|
+
told: () => {
|
|
1808
|
+
told += 1;
|
|
1809
|
+
return Promise.resolve();
|
|
1810
|
+
},
|
|
1811
|
+
}),
|
|
1812
|
+
});
|
|
1813
|
+
await executor.execute({ threadId: "thread_stopped_late", turnId: "turn_stopped_late", prompt: "Cambia el hero", history: history([]) }, controls);
|
|
1814
|
+
expect(told).toBe(0);
|
|
1815
|
+
});
|
|
1816
|
+
it("leaves the workspace of a finished Session alone while it is reviewed", async () => {
|
|
1817
|
+
let caughtUp = false;
|
|
1818
|
+
const executor = createExecutor({
|
|
1819
|
+
catchUpWithMain: () => {
|
|
1820
|
+
caughtUp = true;
|
|
1821
|
+
return Promise.resolve(undefined);
|
|
1822
|
+
},
|
|
1823
|
+
});
|
|
1824
|
+
await executor.execute({
|
|
1825
|
+
threadId: "thread_review_sync",
|
|
1826
|
+
turnId: "turn_review_sync",
|
|
1827
|
+
prompt: "review",
|
|
1828
|
+
history: history([]),
|
|
1829
|
+
review: { threadIds: [], chatFacts: { chatId: "chat_1" }, outputRepair: true },
|
|
1830
|
+
}, activeControls());
|
|
1831
|
+
expect(caughtUp).toBe(false);
|
|
1832
|
+
});
|
|
1833
|
+
it("brings the CLI to the release Convex sent before the turn starts", async () => {
|
|
1834
|
+
const queryInputs = [];
|
|
1835
|
+
const requested = [];
|
|
1836
|
+
const executor = createExecutor({
|
|
1837
|
+
queryInputs,
|
|
1838
|
+
keepCliInStep: (wanted) => {
|
|
1839
|
+
requested.push({ wanted, turnStarted: queryInputs.length > 0 });
|
|
1840
|
+
return Promise.resolve();
|
|
1841
|
+
},
|
|
1842
|
+
});
|
|
1843
|
+
await executor.execute({ threadId: "thread_cli", turnId: "turn_cli", prompt: "Hola", cliVersion: "0.412.0", history: history([]) }, activeControls());
|
|
1844
|
+
expect(requested).toEqual([{ wanted: "0.412.0", turnStarted: false }]);
|
|
1845
|
+
expect(queryInputs).toHaveLength(1);
|
|
1846
|
+
});
|
|
1847
|
+
it("keeps the Session's CLI while it is reviewed", async () => {
|
|
1848
|
+
const wanted = [];
|
|
1849
|
+
const executor = createExecutor({
|
|
1850
|
+
keepCliInStep: (version) => {
|
|
1851
|
+
wanted.push(version);
|
|
1852
|
+
return Promise.resolve();
|
|
1853
|
+
},
|
|
1854
|
+
});
|
|
1855
|
+
await executor.execute({
|
|
1856
|
+
threadId: "thread_review_cli",
|
|
1857
|
+
turnId: "turn_review_cli",
|
|
1858
|
+
prompt: "review",
|
|
1859
|
+
cliVersion: "0.412.0",
|
|
1860
|
+
history: history([]),
|
|
1861
|
+
review: { threadIds: [], chatFacts: { chatId: "chat_1" }, outputRepair: true },
|
|
1862
|
+
}, activeControls());
|
|
1863
|
+
expect(wanted).toEqual([]);
|
|
1864
|
+
});
|
|
1711
1865
|
it("keeps the viewing-reference context beside the message when a stale session falls back to rehydration", async () => {
|
|
1712
1866
|
const queryInputs = [];
|
|
1713
1867
|
const executor = createExecutor({
|
|
@@ -1811,6 +1965,36 @@ describe("BridgeJobExecutor", () => {
|
|
|
1811
1965
|
expect(queryInputs[0]?.options).toMatchObject({ resume: "session_interrupted", forkSession: true });
|
|
1812
1966
|
expect(relay.contextSources.map((entry) => entry.source)).toEqual(["interrupted_resume"]);
|
|
1813
1967
|
});
|
|
1968
|
+
it("tells a turn sent again after a restart what another chat published while it was down", async () => {
|
|
1969
|
+
const queryInputs = [];
|
|
1970
|
+
let told = 0;
|
|
1971
|
+
const executor = createExecutor({
|
|
1972
|
+
loadedBoundary: cleanBoundary("session_clean"),
|
|
1973
|
+
queryInputs,
|
|
1974
|
+
inFlightTurns: memoryInFlightTurns({
|
|
1975
|
+
version: 1,
|
|
1976
|
+
turnId: "turn_interrupted_sync",
|
|
1977
|
+
sessionId: "session_interrupted",
|
|
1978
|
+
updatedAtMs: 1,
|
|
1979
|
+
}),
|
|
1980
|
+
catchUpWithMain: () => Promise.resolve({
|
|
1981
|
+
inWorkspace: false,
|
|
1982
|
+
changed: ["src/pages/home/hero.md"],
|
|
1983
|
+
told: () => {
|
|
1984
|
+
told += 1;
|
|
1985
|
+
return Promise.resolve();
|
|
1986
|
+
},
|
|
1987
|
+
}),
|
|
1988
|
+
});
|
|
1989
|
+
await executor.execute({
|
|
1990
|
+
threadId: "thread_interrupted_sync",
|
|
1991
|
+
turnId: "turn_interrupted_sync",
|
|
1992
|
+
prompt: "Rebuild the five pages",
|
|
1993
|
+
}, activeControls());
|
|
1994
|
+
expect(queryInputs[0]?.prompt).toBe(INTERRUPTED_RESUME_PROMPT);
|
|
1995
|
+
expect(queryInputs[0]?.reminder).toContain("- src/pages/home/hero.md");
|
|
1996
|
+
expect(told).toBe(1);
|
|
1997
|
+
});
|
|
1814
1998
|
it("runs the turn the ordinary way when the interrupted session cannot be resumed", async () => {
|
|
1815
1999
|
const relay = recordingRelay();
|
|
1816
2000
|
const queryInputs = [];
|