@wenrwa/marketplace-cli 0.4.5 → 0.5.0-lws.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/dist/__tests__/bridge-activity-parser.test.d.ts +1 -0
- package/dist/__tests__/bridge-activity-parser.test.js +0 -0
- package/dist/__tests__/bridge-activity-tap.test.d.ts +1 -0
- package/dist/__tests__/bridge-activity-tap.test.js +178 -0
- package/dist/__tests__/bridge-agent-launch.test.d.ts +1 -0
- package/dist/__tests__/bridge-agent-launch.test.js +47 -0
- package/dist/__tests__/bridge-api-client.test.d.ts +1 -0
- package/dist/__tests__/bridge-api-client.test.js +69 -0
- package/dist/__tests__/bridge-browser-driver.test.d.ts +1 -0
- package/dist/__tests__/bridge-browser-driver.test.js +444 -0
- package/dist/__tests__/bridge-browser-frames.test.d.ts +1 -0
- package/dist/__tests__/bridge-browser-frames.test.js +166 -0
- package/dist/__tests__/bridge-browser-idle.test.d.ts +1 -0
- package/dist/__tests__/bridge-browser-idle.test.js +259 -0
- package/dist/__tests__/bridge-browser-relay.test.d.ts +1 -0
- package/dist/__tests__/bridge-browser-relay.test.js +740 -0
- package/dist/__tests__/bridge-bundle-installer.test.d.ts +1 -0
- package/dist/__tests__/bridge-bundle-installer.test.js +126 -0
- package/dist/__tests__/bridge-cdp-client.test.d.ts +1 -0
- package/dist/__tests__/bridge-cdp-client.test.js +133 -0
- package/dist/__tests__/bridge-cdp-transport-race.test.d.ts +1 -0
- package/dist/__tests__/bridge-cdp-transport-race.test.js +79 -0
- package/dist/__tests__/bridge-chromium-launcher.test.d.ts +1 -0
- package/dist/__tests__/bridge-chromium-launcher.test.js +202 -0
- package/dist/__tests__/bridge-command-browser-options.test.d.ts +1 -0
- package/dist/__tests__/bridge-command-browser-options.test.js +37 -0
- package/dist/__tests__/bridge-config-mcp.test.js +4 -0
- package/dist/__tests__/bridge-context-manifest-frame.test.d.ts +1 -0
- package/dist/__tests__/bridge-context-manifest-frame.test.js +125 -0
- package/dist/__tests__/bridge-context-writer.test.d.ts +1 -0
- package/dist/__tests__/bridge-context-writer.test.js +161 -0
- package/dist/__tests__/bridge-dev-server-detect.test.d.ts +1 -0
- package/dist/__tests__/bridge-dev-server-detect.test.js +94 -0
- package/dist/__tests__/bridge-device-registration.test.d.ts +1 -0
- package/dist/__tests__/bridge-device-registration.test.js +33 -0
- package/dist/__tests__/bridge-fail-fast.test.d.ts +1 -0
- package/dist/__tests__/bridge-fail-fast.test.js +597 -0
- package/dist/__tests__/bridge-folder-picker-runner.test.d.ts +1 -0
- package/dist/__tests__/bridge-folder-picker-runner.test.js +37 -0
- package/dist/__tests__/bridge-folder-picker.test.d.ts +1 -0
- package/dist/__tests__/bridge-folder-picker.test.js +66 -0
- package/dist/__tests__/bridge-folder-registry.test.d.ts +1 -0
- package/dist/__tests__/bridge-folder-registry.test.js +107 -0
- package/dist/__tests__/bridge-frame-pacer.test.d.ts +1 -0
- package/dist/__tests__/bridge-frame-pacer.test.js +102 -0
- package/dist/__tests__/bridge-gitignore-matcher.test.d.ts +1 -0
- package/dist/__tests__/bridge-gitignore-matcher.test.js +55 -0
- package/dist/__tests__/bridge-install-bundle-frame.test.d.ts +1 -0
- package/dist/__tests__/bridge-install-bundle-frame.test.js +107 -0
- package/dist/__tests__/bridge-local-add-core.test.d.ts +1 -0
- package/dist/__tests__/bridge-local-add-core.test.js +48 -0
- package/dist/__tests__/bridge-local-context-no-self-echo.test.d.ts +1 -0
- package/dist/__tests__/bridge-local-context-no-self-echo.test.js +106 -0
- package/dist/__tests__/bridge-local-context-writer.test.d.ts +1 -0
- package/dist/__tests__/bridge-local-context-writer.test.js +120 -0
- package/dist/__tests__/bridge-local-path-validation-fs.test.d.ts +1 -0
- package/dist/__tests__/bridge-local-path-validation-fs.test.js +88 -0
- package/dist/__tests__/bridge-local-path-validation.test.d.ts +1 -0
- package/dist/__tests__/bridge-local-path-validation.test.js +45 -0
- package/dist/__tests__/bridge-local-tree-service.test.d.ts +1 -0
- package/dist/__tests__/bridge-local-tree-service.test.js +121 -0
- package/dist/__tests__/bridge-login-status.test.d.ts +1 -0
- package/dist/__tests__/bridge-login-status.test.js +60 -0
- package/dist/__tests__/bridge-publish-preflight.test.d.ts +1 -0
- package/dist/__tests__/bridge-publish-preflight.test.js +194 -0
- package/dist/__tests__/bridge-relay-client.test.js +356 -2
- package/dist/__tests__/bridge-relay-pucc14.test.d.ts +1 -0
- package/dist/__tests__/bridge-relay-pucc14.test.js +230 -0
- package/dist/__tests__/bridge-server-dev-server-frame.test.d.ts +1 -0
- package/dist/__tests__/bridge-server-dev-server-frame.test.js +111 -0
- package/dist/__tests__/bridge-server-local-context.test.d.ts +1 -0
- package/dist/__tests__/bridge-server-local-context.test.js +158 -0
- package/dist/__tests__/bridge-server-local-endpoints.test.d.ts +1 -0
- package/dist/__tests__/bridge-server-local-endpoints.test.js +197 -0
- package/dist/__tests__/bridge-server-local-publish.test.d.ts +1 -0
- package/dist/__tests__/bridge-server-local-publish.test.js +102 -0
- package/dist/__tests__/bridge-server-publish-preflight.test.d.ts +1 -0
- package/dist/__tests__/bridge-server-publish-preflight.test.js +133 -0
- package/dist/__tests__/bridge-server-verify-origin.test.d.ts +1 -0
- package/dist/__tests__/bridge-server-verify-origin.test.js +107 -0
- package/dist/__tests__/bridge-server.test.js +323 -2
- package/dist/__tests__/bridge-session-manager.test.js +270 -23
- package/dist/__tests__/bridge-tree-scanner.test.d.ts +1 -0
- package/dist/__tests__/bridge-tree-scanner.test.js +174 -0
- package/dist/__tests__/bridge-tree-watcher.test.d.ts +1 -0
- package/dist/__tests__/bridge-tree-watcher.test.js +111 -0
- package/dist/__tests__/bridge-workspace-multirepo.test.d.ts +1 -0
- package/dist/__tests__/bridge-workspace-multirepo.test.js +426 -0
- package/dist/__tests__/devices.test.d.ts +1 -0
- package/dist/__tests__/devices.test.js +66 -0
- package/dist/__tests__/local.test.d.ts +1 -0
- package/dist/__tests__/local.test.js +147 -0
- package/dist/__tests__/localPublish.test.d.ts +1 -0
- package/dist/__tests__/localPublish.test.js +256 -0
- package/dist/__tests__/originVerification.test.d.ts +1 -0
- package/dist/__tests__/originVerification.test.js +160 -0
- package/dist/__tests__/term-snapshot.test.d.ts +1 -0
- package/dist/__tests__/term-snapshot.test.js +80 -0
- package/dist/__tests__/writeGitignore.test.d.ts +1 -0
- package/dist/__tests__/writeGitignore.test.js +59 -0
- package/dist/bridge/activityParser.d.ts +53 -0
- package/dist/bridge/activityParser.js +202 -0
- package/dist/bridge/agentLaunch.d.ts +31 -0
- package/dist/bridge/agentLaunch.js +18 -0
- package/dist/bridge/apiClient.d.ts +56 -0
- package/dist/bridge/apiClient.js +50 -0
- package/dist/bridge/browserDriver.d.ts +123 -0
- package/dist/bridge/browserDriver.js +332 -0
- package/dist/bridge/browserFrames.d.ts +182 -0
- package/dist/bridge/browserFrames.js +179 -0
- package/dist/bridge/browserIdle.d.ts +75 -0
- package/dist/bridge/browserIdle.js +120 -0
- package/dist/bridge/bundleInstaller.d.ts +31 -0
- package/dist/bridge/bundleInstaller.js +127 -0
- package/dist/bridge/cdpClient.d.ts +47 -0
- package/dist/bridge/cdpClient.js +102 -0
- package/dist/bridge/chromiumLauncher.d.ts +45 -0
- package/dist/bridge/chromiumLauncher.js +113 -0
- package/dist/bridge/config.d.ts +3 -0
- package/dist/bridge/contextWriter.d.ts +31 -0
- package/dist/bridge/contextWriter.js +139 -0
- package/dist/bridge/devServerDetect.d.ts +41 -0
- package/dist/bridge/devServerDetect.js +123 -0
- package/dist/bridge/deviceRegistration.d.ts +28 -0
- package/dist/bridge/deviceRegistration.js +19 -0
- package/dist/bridge/folderPicker.d.ts +34 -0
- package/dist/bridge/folderPicker.js +36 -0
- package/dist/bridge/folderPickerRunner.d.ts +3 -0
- package/dist/bridge/folderPickerRunner.js +25 -0
- package/dist/bridge/folderRegistry.d.ts +19 -0
- package/dist/bridge/folderRegistry.js +100 -0
- package/dist/bridge/framePacer.d.ts +61 -0
- package/dist/bridge/framePacer.js +79 -0
- package/dist/bridge/gitignoreMatcher.d.ts +19 -0
- package/dist/bridge/gitignoreMatcher.js +0 -0
- package/dist/bridge/localAdd.d.ts +28 -0
- package/dist/bridge/localAdd.js +67 -0
- package/dist/bridge/localContextWriter.d.ts +30 -0
- package/dist/bridge/localContextWriter.js +80 -0
- package/dist/bridge/localPathValidation.d.ts +20 -0
- package/dist/bridge/localPathValidation.js +58 -0
- package/dist/bridge/localPathValidationFs.d.ts +2 -0
- package/dist/bridge/localPathValidationFs.js +98 -0
- package/dist/bridge/localPublish.d.ts +15 -0
- package/dist/bridge/localPublish.js +82 -0
- package/dist/bridge/localTreeService.d.ts +38 -0
- package/dist/bridge/localTreeService.js +51 -0
- package/dist/bridge/loginStatus.d.ts +38 -0
- package/dist/bridge/loginStatus.js +56 -0
- package/dist/bridge/originVerification.d.ts +17 -0
- package/dist/bridge/originVerification.js +55 -0
- package/dist/bridge/publishPreflight.d.ts +7 -0
- package/dist/bridge/publishPreflight.js +152 -0
- package/dist/bridge/realPty.js +11 -3
- package/dist/bridge/relayClient.d.ts +179 -0
- package/dist/bridge/relayClient.js +581 -19
- package/dist/bridge/repoCheckout.d.ts +31 -0
- package/dist/bridge/repoCheckout.js +54 -0
- package/dist/bridge/server.d.ts +136 -0
- package/dist/bridge/server.js +387 -21
- package/dist/bridge/sessionManager.d.ts +128 -6
- package/dist/bridge/sessionManager.js +217 -14
- package/dist/bridge/termSnapshot.d.ts +36 -0
- package/dist/bridge/termSnapshot.js +66 -0
- package/dist/bridge/treeScanner.d.ts +25 -0
- package/dist/bridge/treeScanner.js +125 -0
- package/dist/bridge/treeWatcher.d.ts +17 -0
- package/dist/bridge/treeWatcher.js +116 -0
- package/dist/bridge/writeGitignore.d.ts +15 -0
- package/dist/bridge/writeGitignore.js +73 -0
- package/dist/commands/bridge.d.ts +19 -0
- package/dist/commands/bridge.js +342 -2
- package/dist/commands/devices.d.ts +9 -0
- package/dist/commands/devices.js +53 -0
- package/dist/commands/local.d.ts +9 -0
- package/dist/commands/local.js +141 -0
- package/dist/index.js +4 -0
- package/package.json +3 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* pucc-int-03 — the bridge's read-only PTY activity tap (ADR-0032).
|
|
5
|
+
*
|
|
6
|
+
* Proves the relay client observes Claude Code tool-use in the PTY output and
|
|
7
|
+
* emits a coalesced `activity` frame ({ filePaths, thinking }) to the relay —
|
|
8
|
+
* WITHOUT altering the `data` frames forwarded to the browser, and never on a
|
|
9
|
+
* parse miss. Same faked-PTY / fake-relay harness as bridge-relay-pucc14.test.
|
|
10
|
+
*/
|
|
11
|
+
const ws_1 = require("ws");
|
|
12
|
+
const relayClient_1 = require("../bridge/relayClient");
|
|
13
|
+
const sessionManager_1 = require("../bridge/sessionManager");
|
|
14
|
+
const ESC = '\u001b'; // ESC byte
|
|
15
|
+
class FakePty {
|
|
16
|
+
opts;
|
|
17
|
+
written = [];
|
|
18
|
+
killed = false;
|
|
19
|
+
constructor(opts) {
|
|
20
|
+
this.opts = opts;
|
|
21
|
+
}
|
|
22
|
+
write(data) { this.written.push(data); }
|
|
23
|
+
resize() { }
|
|
24
|
+
kill() { this.killed = true; }
|
|
25
|
+
dataCb = null;
|
|
26
|
+
onData(cb) { this.dataCb = cb; }
|
|
27
|
+
onExit(_cb) { }
|
|
28
|
+
emitData(d) { this.dataCb?.(d); }
|
|
29
|
+
}
|
|
30
|
+
const makeFactory = () => {
|
|
31
|
+
const ptys = [];
|
|
32
|
+
const factory = { spawn: (o) => { const p = new FakePty(o); ptys.push(p); return p; } };
|
|
33
|
+
return { factory, ptys };
|
|
34
|
+
};
|
|
35
|
+
function collectFrames(ws) {
|
|
36
|
+
const frames = [];
|
|
37
|
+
ws.on('message', (raw) => frames.push(JSON.parse(String(raw))));
|
|
38
|
+
return frames;
|
|
39
|
+
}
|
|
40
|
+
function startFakeRelay() {
|
|
41
|
+
return new Promise((resolve) => {
|
|
42
|
+
const wss = new ws_1.WebSocketServer({ port: 0, host: '127.0.0.1' });
|
|
43
|
+
const queue = [];
|
|
44
|
+
const waiters = [];
|
|
45
|
+
wss.on('connection', (ws) => { const w = waiters.shift(); if (w)
|
|
46
|
+
w(ws);
|
|
47
|
+
else
|
|
48
|
+
queue.push(ws); });
|
|
49
|
+
wss.on('listening', () => {
|
|
50
|
+
const addr = wss.address();
|
|
51
|
+
const port = typeof addr === 'object' && addr ? addr.port : 0;
|
|
52
|
+
resolve({ wss, port, nextConnection: () => (queue.length > 0 ? Promise.resolve(queue.shift()) : new Promise((r) => waiters.push(r))) });
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function closeRelay(wss) {
|
|
57
|
+
return new Promise((resolve, reject) => {
|
|
58
|
+
for (const client of wss.clients)
|
|
59
|
+
client.terminate();
|
|
60
|
+
wss.close((err) => (err ? reject(err) : resolve()));
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
const settle = () => new Promise((r) => setTimeout(r, 20));
|
|
64
|
+
describe('bridge activity tap (pucc-int-03)', () => {
|
|
65
|
+
it('emits an activity frame with filePaths/thinking parsed from PTY output', async () => {
|
|
66
|
+
const relay = await startFakeRelay();
|
|
67
|
+
const { factory, ptys } = makeFactory();
|
|
68
|
+
const sessions = new sessionManager_1.SessionManager(factory);
|
|
69
|
+
// throttle 0 → emit immediately so the assertion is deterministic.
|
|
70
|
+
const handle = (0, relayClient_1.startRelayClient)({
|
|
71
|
+
relayUrl: `ws://127.0.0.1:${relay.port}`, relayToken: 'tok', sessions, activityThrottleMs: 0,
|
|
72
|
+
});
|
|
73
|
+
const ws = await relay.nextConnection();
|
|
74
|
+
const frames = collectFrames(ws);
|
|
75
|
+
ws.send(JSON.stringify({ t: 'open', cols: 80, rows: 24, sessionId: 'agent-A' }));
|
|
76
|
+
await settle();
|
|
77
|
+
ptys[0].emitData(`${ESC}[1m⏺${ESC}[0m Edit(src/foo.ts)\r\n`);
|
|
78
|
+
await settle();
|
|
79
|
+
const activity = frames.find((f) => f.t === 'activity');
|
|
80
|
+
expect(activity).toMatchObject({ t: 'activity', sessionId: 'agent-A', filePaths: ['src/foo.ts'], thinking: 'Editing foo.ts' });
|
|
81
|
+
handle.close();
|
|
82
|
+
await closeRelay(relay.wss);
|
|
83
|
+
});
|
|
84
|
+
it('still forwards the raw data frame to the browser UNALTERED', async () => {
|
|
85
|
+
const relay = await startFakeRelay();
|
|
86
|
+
const { factory, ptys } = makeFactory();
|
|
87
|
+
const sessions = new sessionManager_1.SessionManager(factory);
|
|
88
|
+
const handle = (0, relayClient_1.startRelayClient)({
|
|
89
|
+
relayUrl: `ws://127.0.0.1:${relay.port}`, relayToken: 'tok', sessions, activityThrottleMs: 0,
|
|
90
|
+
});
|
|
91
|
+
const ws = await relay.nextConnection();
|
|
92
|
+
const frames = collectFrames(ws);
|
|
93
|
+
ws.send(JSON.stringify({ t: 'open', cols: 80, rows: 24, sessionId: 'agent-A' }));
|
|
94
|
+
await settle();
|
|
95
|
+
const raw = `${ESC}[1m⏺${ESC}[0m Read(a.ts)\r\n`;
|
|
96
|
+
ptys[0].emitData(raw);
|
|
97
|
+
await settle();
|
|
98
|
+
// The data frame is byte-identical to the PTY output — the tap did not touch it.
|
|
99
|
+
const data = frames.find((f) => f.t === 'data');
|
|
100
|
+
expect(data).toEqual({ t: 'data', sessionId: 'agent-A', data: raw });
|
|
101
|
+
handle.close();
|
|
102
|
+
await closeRelay(relay.wss);
|
|
103
|
+
});
|
|
104
|
+
it('coalesces a burst of tool-use into a single throttled activity frame', async () => {
|
|
105
|
+
const relay = await startFakeRelay();
|
|
106
|
+
const { factory, ptys } = makeFactory();
|
|
107
|
+
const sessions = new sessionManager_1.SessionManager(factory);
|
|
108
|
+
let clock = 1000;
|
|
109
|
+
let scheduled = null;
|
|
110
|
+
const handle = (0, relayClient_1.startRelayClient)({
|
|
111
|
+
relayUrl: `ws://127.0.0.1:${relay.port}`, relayToken: 'tok', sessions,
|
|
112
|
+
activityThrottleMs: 1000,
|
|
113
|
+
nowFn: () => clock,
|
|
114
|
+
setTimeoutFn: (cb) => { scheduled = cb; return 1; },
|
|
115
|
+
clearTimeoutFn: () => { },
|
|
116
|
+
});
|
|
117
|
+
const ws = await relay.nextConnection();
|
|
118
|
+
const frames = collectFrames(ws);
|
|
119
|
+
ws.send(JSON.stringify({ t: 'open', cols: 80, rows: 24, sessionId: 'agent-A' }));
|
|
120
|
+
await settle();
|
|
121
|
+
// First signal fires immediately (lastEmit=0, elapsed >= throttle).
|
|
122
|
+
ptys[0].emitData('⏺ Edit(one.ts)\n');
|
|
123
|
+
await settle();
|
|
124
|
+
// Two more within the SAME window are coalesced behind the timer, not sent.
|
|
125
|
+
ptys[0].emitData('⏺ Edit(two.ts)\n');
|
|
126
|
+
ptys[0].emitData('⏺ Read(three.ts)\n');
|
|
127
|
+
await settle();
|
|
128
|
+
let activities = frames.filter((f) => f.t === 'activity');
|
|
129
|
+
expect(activities).toHaveLength(1);
|
|
130
|
+
expect(activities[0].filePaths).toEqual(['one.ts']);
|
|
131
|
+
// Advance the clock and fire the pending flush → the coalesced batch emits.
|
|
132
|
+
clock += 1000;
|
|
133
|
+
scheduled();
|
|
134
|
+
await settle();
|
|
135
|
+
activities = frames.filter((f) => f.t === 'activity');
|
|
136
|
+
expect(activities).toHaveLength(2);
|
|
137
|
+
expect(activities[1].filePaths).toEqual(['two.ts', 'three.ts']);
|
|
138
|
+
expect(activities[1].thinking).toBe('Reading three.ts'); // latest thinking wins
|
|
139
|
+
handle.close();
|
|
140
|
+
await closeRelay(relay.wss);
|
|
141
|
+
});
|
|
142
|
+
it('a parse miss (ordinary output) emits NO activity frame', async () => {
|
|
143
|
+
const relay = await startFakeRelay();
|
|
144
|
+
const { factory, ptys } = makeFactory();
|
|
145
|
+
const sessions = new sessionManager_1.SessionManager(factory);
|
|
146
|
+
const handle = (0, relayClient_1.startRelayClient)({
|
|
147
|
+
relayUrl: `ws://127.0.0.1:${relay.port}`, relayToken: 'tok', sessions, activityThrottleMs: 0,
|
|
148
|
+
});
|
|
149
|
+
const ws = await relay.nextConnection();
|
|
150
|
+
const frames = collectFrames(ws);
|
|
151
|
+
ws.send(JSON.stringify({ t: 'open', cols: 80, rows: 24, sessionId: 'agent-A' }));
|
|
152
|
+
await settle();
|
|
153
|
+
ptys[0].emitData('$ ls -la\r\ntotal 24\r\ndrwxr-xr-x 5 me staff\r\n');
|
|
154
|
+
await settle();
|
|
155
|
+
expect(frames.some((f) => f.t === 'activity')).toBe(false);
|
|
156
|
+
expect(frames.some((f) => f.t === 'data')).toBe(true); // data still flowed
|
|
157
|
+
handle.close();
|
|
158
|
+
await closeRelay(relay.wss);
|
|
159
|
+
});
|
|
160
|
+
it('emitActivity:false disables the tap entirely (data still flows)', async () => {
|
|
161
|
+
const relay = await startFakeRelay();
|
|
162
|
+
const { factory, ptys } = makeFactory();
|
|
163
|
+
const sessions = new sessionManager_1.SessionManager(factory);
|
|
164
|
+
const handle = (0, relayClient_1.startRelayClient)({
|
|
165
|
+
relayUrl: `ws://127.0.0.1:${relay.port}`, relayToken: 'tok', sessions, emitActivity: false, activityThrottleMs: 0,
|
|
166
|
+
});
|
|
167
|
+
const ws = await relay.nextConnection();
|
|
168
|
+
const frames = collectFrames(ws);
|
|
169
|
+
ws.send(JSON.stringify({ t: 'open', cols: 80, rows: 24, sessionId: 'agent-A' }));
|
|
170
|
+
await settle();
|
|
171
|
+
ptys[0].emitData('⏺ Edit(src/foo.ts)\n');
|
|
172
|
+
await settle();
|
|
173
|
+
expect(frames.some((f) => f.t === 'activity')).toBe(false);
|
|
174
|
+
expect(frames.some((f) => f.t === 'data')).toBe(true);
|
|
175
|
+
handle.close();
|
|
176
|
+
await closeRelay(relay.wss);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const agentLaunch_1 = require("../bridge/agentLaunch");
|
|
4
|
+
/**
|
|
5
|
+
* TDD — lws-06: pure decision of what the bridge spawns for an agent-scoped
|
|
6
|
+
* PTY (ADR-0035 D4). `claude`, never $SHELL — autonomous maps to
|
|
7
|
+
* --dangerously-skip-permissions ONLY when the agent opts in; default OFF.
|
|
8
|
+
*
|
|
9
|
+
* lws-08 (PRD D9) — every agent-scoped launch also carries a minimal env
|
|
10
|
+
* pointer at `.hiveop/context.md` (relative to the spawn cwd, the project
|
|
11
|
+
* root). This is the ONLY mechanism used to point a spawned `claude` at the
|
|
12
|
+
* manifest: no args, no stdin injection, no CLAUDE.md edit. `claude` itself
|
|
13
|
+
* doesn't read this var natively today — it exists so the context file's
|
|
14
|
+
* location is a documented, stable contract other tooling (a future MCP
|
|
15
|
+
* resource, a slash command, a system-prompt append) can rely on instead of
|
|
16
|
+
* hardcoding the path, and so a human/agent inspecting `env` in the PTY can
|
|
17
|
+
* discover it. Deliberately NOT wired into --append-system-prompt or similar
|
|
18
|
+
* — keeping this additive-only avoids coupling the launch decision to
|
|
19
|
+
* `claude` CLI flag churn.
|
|
20
|
+
*/
|
|
21
|
+
describe('resolveAgentLaunch (lws-06)', () => {
|
|
22
|
+
it('defaults to a bare `claude` invocation (autonomous OFF)', () => {
|
|
23
|
+
expect((0, agentLaunch_1.resolveAgentLaunch)({ autonomous: false })).toEqual({
|
|
24
|
+
command: 'claude',
|
|
25
|
+
args: [],
|
|
26
|
+
env: { [agentLaunch_1.HIVEOP_CONTEXT_ENV_VAR]: agentLaunch_1.HIVEOP_CONTEXT_ENV_VALUE },
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
it('an agent-scoped launch with autonomous unset also defaults OFF', () => {
|
|
30
|
+
expect((0, agentLaunch_1.resolveAgentLaunch)({})).toEqual({
|
|
31
|
+
command: 'claude',
|
|
32
|
+
args: [],
|
|
33
|
+
env: { [agentLaunch_1.HIVEOP_CONTEXT_ENV_VAR]: agentLaunch_1.HIVEOP_CONTEXT_ENV_VALUE },
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
it('autonomous:true maps to --dangerously-skip-permissions', () => {
|
|
37
|
+
expect((0, agentLaunch_1.resolveAgentLaunch)({ autonomous: true })).toEqual({
|
|
38
|
+
command: 'claude',
|
|
39
|
+
args: ['--dangerously-skip-permissions'],
|
|
40
|
+
env: { [agentLaunch_1.HIVEOP_CONTEXT_ENV_VAR]: agentLaunch_1.HIVEOP_CONTEXT_ENV_VALUE },
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
it('the context env var always points at the relative .hiveop/context.md path', () => {
|
|
44
|
+
expect(agentLaunch_1.HIVEOP_CONTEXT_ENV_VALUE).toBe('.hiveop/context.md');
|
|
45
|
+
expect((0, agentLaunch_1.resolveAgentLaunch)({}).env).toEqual({ HIVEOP_CONTEXT_FILE: '.hiveop/context.md' });
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* TDD — lws-03: bridge/apiClient.ts. A thin, injectable fetch wrapper the
|
|
5
|
+
* bridge daemon uses to talk to the backend AS ITSELF (Bearer Connect Token)
|
|
6
|
+
* — distinct from utils/client.ts, which authenticates the interactive CLI
|
|
7
|
+
* via the legacy X-Wallet-Pubkey login flow (~/.wen-market/config.json).
|
|
8
|
+
*/
|
|
9
|
+
const apiClient_1 = require("../bridge/apiClient");
|
|
10
|
+
const OPTS = { apiUrl: 'https://api.x', connectToken: 'wm_ct_' + 'a'.repeat(64) };
|
|
11
|
+
function fakeFetch(status, body) {
|
|
12
|
+
const fetchImpl = jest.fn().mockResolvedValue({
|
|
13
|
+
ok: status >= 200 && status < 300,
|
|
14
|
+
status,
|
|
15
|
+
json: async () => body,
|
|
16
|
+
});
|
|
17
|
+
return fetchImpl;
|
|
18
|
+
}
|
|
19
|
+
describe('bridge apiClient', () => {
|
|
20
|
+
it('registerDevice posts to /me/devices with the Bearer connect token', async () => {
|
|
21
|
+
const fetchImpl = fakeFetch(201, { success: true, device: { id: 'd1', name: 'bunny-mbp' } });
|
|
22
|
+
const result = await (0, apiClient_1.registerDevice)({ ...OPTS, fetchImpl }, 'bunny-mbp');
|
|
23
|
+
expect(result.device.id).toBe('d1');
|
|
24
|
+
const [url, init] = fetchImpl.mock.calls[0];
|
|
25
|
+
expect(url).toBe('https://api.x/me/devices');
|
|
26
|
+
expect(init.method).toBe('POST');
|
|
27
|
+
expect(init.headers.Authorization).toBe(`Bearer ${OPTS.connectToken}`);
|
|
28
|
+
expect(JSON.parse(init.body)).toEqual({ name: 'bunny-mbp' });
|
|
29
|
+
});
|
|
30
|
+
it('listDevices gets /me/devices', async () => {
|
|
31
|
+
const fetchImpl = fakeFetch(200, { success: true, devices: [{ id: 'd1' }] });
|
|
32
|
+
const result = await (0, apiClient_1.listDevices)({ ...OPTS, fetchImpl });
|
|
33
|
+
expect(result.devices).toHaveLength(1);
|
|
34
|
+
expect(fetchImpl.mock.calls[0][0]).toBe('https://api.x/me/devices');
|
|
35
|
+
expect(fetchImpl.mock.calls[0][1].method).toBe('GET');
|
|
36
|
+
});
|
|
37
|
+
it('revokeDevice deletes /me/devices/:id', async () => {
|
|
38
|
+
const fetchImpl = fakeFetch(200, { success: true });
|
|
39
|
+
await (0, apiClient_1.revokeDevice)({ ...OPTS, fetchImpl }, 'd1');
|
|
40
|
+
expect(fetchImpl.mock.calls[0][0]).toBe('https://api.x/me/devices/d1');
|
|
41
|
+
expect(fetchImpl.mock.calls[0][1].method).toBe('DELETE');
|
|
42
|
+
});
|
|
43
|
+
it('createLocalWorkspace posts kind:local to /workspaces', async () => {
|
|
44
|
+
const fetchImpl = fakeFetch(201, { success: true, workspace: { id: 'ws-1', name: 'my-app' } });
|
|
45
|
+
const result = await (0, apiClient_1.createLocalWorkspace)({ ...OPTS, fetchImpl }, { name: 'my-app' });
|
|
46
|
+
expect(result.workspace.id).toBe('ws-1');
|
|
47
|
+
const [url, init] = fetchImpl.mock.calls[0];
|
|
48
|
+
expect(url).toBe('https://api.x/workspaces');
|
|
49
|
+
expect(JSON.parse(init.body)).toEqual({ name: 'my-app', kind: 'local' });
|
|
50
|
+
});
|
|
51
|
+
it('deleteWorkspace deletes /workspaces/:id', async () => {
|
|
52
|
+
const fetchImpl = fakeFetch(200, { success: true });
|
|
53
|
+
await (0, apiClient_1.deleteWorkspace)({ ...OPTS, fetchImpl }, 'ws-1');
|
|
54
|
+
expect(fetchImpl.mock.calls[0][0]).toBe('https://api.x/workspaces/ws-1');
|
|
55
|
+
expect(fetchImpl.mock.calls[0][1].method).toBe('DELETE');
|
|
56
|
+
});
|
|
57
|
+
it('throws a BridgeApiError carrying the backend error code on failure', async () => {
|
|
58
|
+
const fetchImpl = fakeFetch(401, { success: false, error: { code: 'INVALID_CONNECT_TOKEN', message: 'Connect token is invalid or revoked.' } });
|
|
59
|
+
await expect((0, apiClient_1.listDevices)({ ...OPTS, fetchImpl })).rejects.toThrow(apiClient_1.BridgeApiError);
|
|
60
|
+
try {
|
|
61
|
+
await (0, apiClient_1.listDevices)({ ...OPTS, fetchImpl });
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
expect(err).toBeInstanceOf(apiClient_1.BridgeApiError);
|
|
65
|
+
expect(err.code).toBe('INVALID_CONNECT_TOKEN');
|
|
66
|
+
expect(err.status).toBe(401);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|