@wenrwa/marketplace-cli 0.5.23 → 0.6.2
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__/auth-api-key-format.test.d.ts +1 -0
- package/dist/__tests__/auth-api-key-format.test.js +41 -0
- package/dist/__tests__/auth-identity.test.d.ts +1 -0
- package/dist/__tests__/auth-identity.test.js +46 -0
- package/dist/__tests__/auth-login-core.test.d.ts +1 -0
- package/dist/__tests__/auth-login-core.test.js +145 -0
- package/dist/__tests__/auth.test.js +246 -57
- package/dist/__tests__/bridge-bundle-installer.test.js +101 -0
- package/dist/__tests__/bridge-context-writer.test.js +168 -1
- package/dist/__tests__/bridge-local-context-writer.test.js +51 -2
- package/dist/__tests__/bridge-memory-brief.test.d.ts +1 -0
- package/dist/__tests__/bridge-memory-brief.test.js +107 -0
- package/dist/__tests__/bridge-memory-pointer.test.d.ts +1 -0
- package/dist/__tests__/bridge-memory-pointer.test.js +92 -0
- package/dist/__tests__/client.test.js +26 -4
- package/dist/__tests__/config.test.js +36 -4
- package/dist/__tests__/openBrowser.test.d.ts +1 -0
- package/dist/__tests__/openBrowser.test.js +42 -0
- package/dist/__tests__/prompt.test.d.ts +1 -0
- package/dist/__tests__/prompt.test.js +49 -0
- package/dist/auth/identity.d.ts +22 -0
- package/dist/auth/identity.js +20 -0
- package/dist/auth/login.d.ts +80 -0
- package/dist/auth/login.js +61 -0
- package/dist/bridge/apiClient.d.ts +25 -0
- package/dist/bridge/apiClient.js +7 -1
- package/dist/bridge/bundleInstaller.d.ts +14 -0
- package/dist/bridge/bundleInstaller.js +56 -2
- package/dist/bridge/contextWriter.d.ts +24 -1
- package/dist/bridge/contextWriter.js +61 -5
- package/dist/bridge/localContextWriter.d.ts +13 -1
- package/dist/bridge/localContextWriter.js +31 -4
- package/dist/bridge/memoryBrief.d.ts +41 -0
- package/dist/bridge/memoryBrief.js +63 -0
- package/dist/bridge/memoryPointer.d.ts +49 -0
- package/dist/bridge/memoryPointer.js +62 -0
- package/dist/bridge/pairing.js +7 -1
- package/dist/bridge/relayClient.d.ts +20 -1
- package/dist/bridge/relayClient.js +45 -6
- package/dist/bridge/server.d.ts +10 -1
- package/dist/bridge/server.js +29 -10
- package/dist/commands/auth.d.ts +17 -0
- package/dist/commands/auth.js +202 -27
- package/dist/commands/bridge.js +82 -2
- package/dist/utils/apiKeyFormat.d.ts +9 -0
- package/dist/utils/apiKeyFormat.js +26 -0
- package/dist/utils/client.js +7 -1
- package/dist/utils/config.d.ts +3 -0
- package/dist/utils/config.js +28 -2
- package/dist/utils/openBrowser.d.ts +16 -0
- package/dist/utils/openBrowser.js +30 -0
- package/dist/utils/prompt.d.ts +9 -0
- package/dist/utils/prompt.js +63 -0
- package/package.json +2 -2
|
@@ -26,6 +26,18 @@ export interface LocalContextWriteResult {
|
|
|
26
26
|
*/
|
|
27
27
|
export declare function writeLocalContext(input: {
|
|
28
28
|
projectRoot: string;
|
|
29
|
-
|
|
29
|
+
/** Absent only for a pointers-only refresh (wmr-07). */
|
|
30
|
+
content?: string;
|
|
30
31
|
workGraphAvailable?: boolean;
|
|
32
|
+
/** wmr-04 — two-lane parity with contextWriter.ts. Gated by the caller on
|
|
33
|
+
* the local lane's own honest signal (did THIS bridge run register the
|
|
34
|
+
* MCP server), not on a container env var that does not exist here. */
|
|
35
|
+
memoryAvailable?: boolean;
|
|
36
|
+
/** wmr-04 — this workspace's composed brief, or null when the fetch failed
|
|
37
|
+
* or there is nothing yet. Never blocks the write (PRD D2). */
|
|
38
|
+
memoryBrief?: string | null;
|
|
39
|
+
/** wmr-07 — refresh only the standing pointers, keeping the pushed file
|
|
40
|
+
* content. The local twin of contextWriter's flag; same reason (the
|
|
41
|
+
* manifest frame only arrives when the pilot has files selected). */
|
|
42
|
+
pointersOnly?: boolean;
|
|
31
43
|
}, deps: LocalContextWriterDeps): LocalContextWriteResult;
|
|
@@ -55,6 +55,16 @@ exports.writeLocalContext = writeLocalContext;
|
|
|
55
55
|
*/
|
|
56
56
|
const path = __importStar(require("path"));
|
|
57
57
|
const workGraphPointer_1 = require("./workGraphPointer");
|
|
58
|
+
const memoryPointer_1 = require("./memoryPointer");
|
|
59
|
+
const contextWriter_1 = require("./contextWriter");
|
|
60
|
+
/** Split a bridge-owned context file into its pointer block and the rest. */
|
|
61
|
+
function splitPointers(body) {
|
|
62
|
+
const start = body.indexOf(contextWriter_1.POINTERS_START_MARKER);
|
|
63
|
+
const end = body.indexOf(contextWriter_1.POINTERS_END_MARKER);
|
|
64
|
+
if (start === -1 || end === -1 || end < start)
|
|
65
|
+
return { rest: body.trim() };
|
|
66
|
+
return { rest: (body.slice(0, start) + body.slice(end + contextWriter_1.POINTERS_END_MARKER.length)).trim() };
|
|
67
|
+
}
|
|
58
68
|
exports.LOCAL_CONTEXT_DIR = '.hiveop';
|
|
59
69
|
exports.LOCAL_CONTEXT_FILENAME = 'context.md';
|
|
60
70
|
exports.LOCAL_CONTEXT_RELATIVE_PATH = `${exports.LOCAL_CONTEXT_DIR}/${exports.LOCAL_CONTEXT_FILENAME}`;
|
|
@@ -72,10 +82,27 @@ function writeLocalContext(input, deps) {
|
|
|
72
82
|
// to pre-wgcp-01 behavior (never pointing at unregistered MCP tools); when
|
|
73
83
|
// present, the pointer alone is reason enough to write the file, even with
|
|
74
84
|
// no pushed manifest this turn.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
85
|
+
//
|
|
86
|
+
// wmr-04 adds the memory section under the same rule, assembled as a list of
|
|
87
|
+
// present sections so the joining and empty-content logic is stated once —
|
|
88
|
+
// the same shape contextWriter.ts uses, because the two lanes diverging on
|
|
89
|
+
// this would be a two-lane bug nobody would notice until a local pilot
|
|
90
|
+
// reported missing memory.
|
|
91
|
+
const pointers = [];
|
|
92
|
+
if (input.workGraphAvailable)
|
|
93
|
+
pointers.push(workGraphPointer_1.WORK_GRAPH_POINTER);
|
|
94
|
+
if (input.memoryAvailable)
|
|
95
|
+
pointers.push((0, memoryPointer_1.memorySection)(input.memoryBrief));
|
|
96
|
+
// wmr-07 — the whole local file is bridge-owned, so "preserve the pushed
|
|
97
|
+
// content" means keeping what is already on disk below the pointer fence.
|
|
98
|
+
const existingBody = existed ? deps.readFile(contextPath) : '';
|
|
99
|
+
const fileContent = input.pointersOnly
|
|
100
|
+
? splitPointers(existingBody).rest
|
|
101
|
+
: (input.content ?? '').trim();
|
|
102
|
+
const block = pointers.length > 0
|
|
103
|
+
? `${contextWriter_1.POINTERS_START_MARKER}\n${pointers.join('\n\n')}\n${contextWriter_1.POINTERS_END_MARKER}`
|
|
104
|
+
: '';
|
|
105
|
+
const content = [block, fileContent].filter((part) => part.length > 0).join('\n\n');
|
|
79
106
|
const isEmpty = content.trim().length === 0;
|
|
80
107
|
if (isEmpty) {
|
|
81
108
|
if (!existed)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wmr-02 — bridge-side fetcher for the workspace memory brief
|
|
3
|
+
* (`GET /workspaces/:id/memory/brief`, PRD decision D2 —
|
|
4
|
+
* docs/prd/workspace-memory-read-path.md). Mirrors storageQuotaFetch.ts's
|
|
5
|
+
* shape: injectable fetchImpl (defaults to the global fetch every Node
|
|
6
|
+
* >=18 the CLI already requires ships), ANY failure resolves null, never
|
|
7
|
+
* throws. This is deliberately a separate slice from anything that
|
|
8
|
+
* consumes the brief — proving the failure behaviour before depending on
|
|
9
|
+
* it is the whole point (see the PRD).
|
|
10
|
+
*
|
|
11
|
+
* Its entire contract: never throws, never hangs. On a non-200, network
|
|
12
|
+
* error, malformed/missing body, a missing/empty Connect Token, or a
|
|
13
|
+
* timeout, it resolves null so the caller writes the context region
|
|
14
|
+
* exactly as it would have anyway — memory can never become a single
|
|
15
|
+
* point of failure for opening a terminal.
|
|
16
|
+
*/
|
|
17
|
+
export type FetchLike = (url: string, init?: {
|
|
18
|
+
method?: string;
|
|
19
|
+
headers?: Record<string, string>;
|
|
20
|
+
signal?: AbortSignal;
|
|
21
|
+
}) => Promise<{
|
|
22
|
+
ok: boolean;
|
|
23
|
+
status: number;
|
|
24
|
+
json: () => Promise<unknown>;
|
|
25
|
+
}>;
|
|
26
|
+
export interface FetchMemoryBriefOpts {
|
|
27
|
+
/** Injectable transport — tests stub this so nothing hits the network,
|
|
28
|
+
* same discipline as apiClient.ts / storageQuotaFetch.ts. Defaults to
|
|
29
|
+
* the global fetch. */
|
|
30
|
+
fetchImpl?: FetchLike;
|
|
31
|
+
/** Overrides the default bounded timeout, in ms. Tests use this to keep
|
|
32
|
+
* the timeout case fast without waiting out the real default. */
|
|
33
|
+
timeoutMs?: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Fetch the workspace memory brief for `workspaceId`. See the module
|
|
37
|
+
* header for the full failure contract — every branch below returns null
|
|
38
|
+
* rather than propagating an error or letting a slow response block the
|
|
39
|
+
* caller.
|
|
40
|
+
*/
|
|
41
|
+
export declare function fetchMemoryBrief(workspaceId: string, opts?: FetchMemoryBriefOpts): Promise<string | null>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* wmr-02 — bridge-side fetcher for the workspace memory brief
|
|
4
|
+
* (`GET /workspaces/:id/memory/brief`, PRD decision D2 —
|
|
5
|
+
* docs/prd/workspace-memory-read-path.md). Mirrors storageQuotaFetch.ts's
|
|
6
|
+
* shape: injectable fetchImpl (defaults to the global fetch every Node
|
|
7
|
+
* >=18 the CLI already requires ships), ANY failure resolves null, never
|
|
8
|
+
* throws. This is deliberately a separate slice from anything that
|
|
9
|
+
* consumes the brief — proving the failure behaviour before depending on
|
|
10
|
+
* it is the whole point (see the PRD).
|
|
11
|
+
*
|
|
12
|
+
* Its entire contract: never throws, never hangs. On a non-200, network
|
|
13
|
+
* error, malformed/missing body, a missing/empty Connect Token, or a
|
|
14
|
+
* timeout, it resolves null so the caller writes the context region
|
|
15
|
+
* exactly as it would have anyway — memory can never become a single
|
|
16
|
+
* point of failure for opening a terminal.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.fetchMemoryBrief = fetchMemoryBrief;
|
|
20
|
+
const DEFAULT_API_URL = 'https://api.wenrwa.com/api/v1';
|
|
21
|
+
/** Bounded so a hanging backend can never stall a terminal open. */
|
|
22
|
+
const DEFAULT_TIMEOUT_MS = 4000;
|
|
23
|
+
/**
|
|
24
|
+
* Fetch the workspace memory brief for `workspaceId`. See the module
|
|
25
|
+
* header for the full failure contract — every branch below returns null
|
|
26
|
+
* rather than propagating an error or letting a slow response block the
|
|
27
|
+
* caller.
|
|
28
|
+
*/
|
|
29
|
+
async function fetchMemoryBrief(workspaceId, opts = {}) {
|
|
30
|
+
const token = process.env.WENRWA_CONNECT_TOKEN;
|
|
31
|
+
if (!token)
|
|
32
|
+
return null; // missing/empty token — never even attempt the call
|
|
33
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
34
|
+
if (!fetchImpl)
|
|
35
|
+
return null;
|
|
36
|
+
const apiUrl = process.env.MARKETPLACE_API_URL || DEFAULT_API_URL;
|
|
37
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
38
|
+
const url = `${apiUrl}/workspaces/${encodeURIComponent(workspaceId)}/memory/brief`;
|
|
39
|
+
const controller = new AbortController();
|
|
40
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
41
|
+
try {
|
|
42
|
+
const res = await fetchImpl(url, {
|
|
43
|
+
method: 'GET',
|
|
44
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
45
|
+
signal: controller.signal,
|
|
46
|
+
});
|
|
47
|
+
if (!res.ok)
|
|
48
|
+
return null;
|
|
49
|
+
const body = (await res.json());
|
|
50
|
+
if (body?.success !== true || typeof body.brief !== 'string' || body.brief.length === 0) {
|
|
51
|
+
return null; // malformed/missing body — never a fabricated brief
|
|
52
|
+
}
|
|
53
|
+
return body.brief;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// network error, abort/timeout, or json() throwing on malformed JSON —
|
|
57
|
+
// all collapse to the same UNKNOWN outcome, never thrown to the caller.
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
clearTimeout(timer);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wmr-01 — the guidance that tells an agent workspace memory exists at all.
|
|
3
|
+
*
|
|
4
|
+
* Workspace Memory (ADR-0044) shipped complete — store, verdicts, curation UI,
|
|
5
|
+
* MCP tools — and held ZERO entries in production for a month. Two reasons, and
|
|
6
|
+
* only one of them was a bug: agents were structurally forbidden from writing
|
|
7
|
+
* (a Connect Token allowlist omission, fixed in cb5e725), and nothing ever told
|
|
8
|
+
* them the store existed. Fixing the first without the second just swaps a 403
|
|
9
|
+
* for an agent that never calls the tool.
|
|
10
|
+
*
|
|
11
|
+
* Delivered through the SAME managed-region mechanism as the work-graph pointer
|
|
12
|
+
* (wgcp-01, workGraphPointer.ts) — contextWriter.ts for the hosted lane,
|
|
13
|
+
* localContextWriter.ts for local. No new delivery channel, and no image
|
|
14
|
+
* rebuild: `--append-system-prompt` does not exist in this codebase, and the
|
|
15
|
+
* hosted lane launches `claude` from a script baked into the image, so argv is
|
|
16
|
+
* not reachable from here.
|
|
17
|
+
*
|
|
18
|
+
* Gated by the CALLER on `WENRWA_CONNECT_TOKEN`, exactly as the work-graph
|
|
19
|
+
* pointer is: absent means the MCP tools this text names are not registered in
|
|
20
|
+
* this process, and pointing an agent at a tool it does not have is worse than
|
|
21
|
+
* silence.
|
|
22
|
+
*
|
|
23
|
+
* WHAT THIS TEXT HAS TO EARN. It rides in every agent's context on every
|
|
24
|
+
* attach, so it states a floor as well as a prompt: without one, the cheapest
|
|
25
|
+
* thing for a model to record is whatever it just read, which is exactly what
|
|
26
|
+
* the code already says and what nobody needs repeated. It also never tells an
|
|
27
|
+
* agent that memory is settled truth — entries carry verdicts, the brief
|
|
28
|
+
* renders its own `⚠ re-verify before relying:` flags, and the predecessor
|
|
29
|
+
* this epic replaced (lib/agent-memory.ts) failed precisely by prompting
|
|
30
|
+
* "confirmed facts — do not re-verify".
|
|
31
|
+
*/
|
|
32
|
+
export declare const MEMORY_POINTER: string;
|
|
33
|
+
/**
|
|
34
|
+
* wmr-03 — the memory section as it appears in the managed region: the
|
|
35
|
+
* standing instruction, followed by this workspace's brief when there is one.
|
|
36
|
+
*
|
|
37
|
+
* THE BRIEF IS CARRIED VERBATIM. It arrives already composed and already
|
|
38
|
+
* capped by the backend (brief.service.ts: 2048 bytes, tiered pinned →
|
|
39
|
+
* STILL_VALID/ASSERTED → DRIFTED → UNVERIFIED, each rendered with its own flag
|
|
40
|
+
* text). Re-ranking, re-wrapping or re-capping it here would give the agent a
|
|
41
|
+
* different view of the same workspace than the Memory panel gives the human,
|
|
42
|
+
* and the two would drift apart with no test able to see it. The one judgement
|
|
43
|
+
* this function makes is whether there is anything to show at all.
|
|
44
|
+
*
|
|
45
|
+
* `null` — the fetch failed, or the workspace has no memory yet — renders the
|
|
46
|
+
* instruction alone rather than an empty heading. An empty heading reads as
|
|
47
|
+
* "this workspace knows nothing", which is a different and wrong claim.
|
|
48
|
+
*/
|
|
49
|
+
export declare function memorySection(brief: string | null | undefined): string;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MEMORY_POINTER = void 0;
|
|
4
|
+
exports.memorySection = memorySection;
|
|
5
|
+
/**
|
|
6
|
+
* wmr-01 — the guidance that tells an agent workspace memory exists at all.
|
|
7
|
+
*
|
|
8
|
+
* Workspace Memory (ADR-0044) shipped complete — store, verdicts, curation UI,
|
|
9
|
+
* MCP tools — and held ZERO entries in production for a month. Two reasons, and
|
|
10
|
+
* only one of them was a bug: agents were structurally forbidden from writing
|
|
11
|
+
* (a Connect Token allowlist omission, fixed in cb5e725), and nothing ever told
|
|
12
|
+
* them the store existed. Fixing the first without the second just swaps a 403
|
|
13
|
+
* for an agent that never calls the tool.
|
|
14
|
+
*
|
|
15
|
+
* Delivered through the SAME managed-region mechanism as the work-graph pointer
|
|
16
|
+
* (wgcp-01, workGraphPointer.ts) — contextWriter.ts for the hosted lane,
|
|
17
|
+
* localContextWriter.ts for local. No new delivery channel, and no image
|
|
18
|
+
* rebuild: `--append-system-prompt` does not exist in this codebase, and the
|
|
19
|
+
* hosted lane launches `claude` from a script baked into the image, so argv is
|
|
20
|
+
* not reachable from here.
|
|
21
|
+
*
|
|
22
|
+
* Gated by the CALLER on `WENRWA_CONNECT_TOKEN`, exactly as the work-graph
|
|
23
|
+
* pointer is: absent means the MCP tools this text names are not registered in
|
|
24
|
+
* this process, and pointing an agent at a tool it does not have is worse than
|
|
25
|
+
* silence.
|
|
26
|
+
*
|
|
27
|
+
* WHAT THIS TEXT HAS TO EARN. It rides in every agent's context on every
|
|
28
|
+
* attach, so it states a floor as well as a prompt: without one, the cheapest
|
|
29
|
+
* thing for a model to record is whatever it just read, which is exactly what
|
|
30
|
+
* the code already says and what nobody needs repeated. It also never tells an
|
|
31
|
+
* agent that memory is settled truth — entries carry verdicts, the brief
|
|
32
|
+
* renders its own `⚠ re-verify before relying:` flags, and the predecessor
|
|
33
|
+
* this epic replaced (lib/agent-memory.ts) failed precisely by prompting
|
|
34
|
+
* "confirmed facts — do not re-verify".
|
|
35
|
+
*/
|
|
36
|
+
exports.MEMORY_POINTER = [
|
|
37
|
+
'## Workspace memory',
|
|
38
|
+
'This workspace has a shared memory other agents read: `memory_write` to record something, `memory_recall` to search it.',
|
|
39
|
+
'Worth recording: a correction you were given, a decision and the reason behind it, a non-obvious fact and the file you learned it from.',
|
|
40
|
+
'Not worth recording: anything the code already states, or anything you merely read this session.',
|
|
41
|
+
].join('\n');
|
|
42
|
+
/**
|
|
43
|
+
* wmr-03 — the memory section as it appears in the managed region: the
|
|
44
|
+
* standing instruction, followed by this workspace's brief when there is one.
|
|
45
|
+
*
|
|
46
|
+
* THE BRIEF IS CARRIED VERBATIM. It arrives already composed and already
|
|
47
|
+
* capped by the backend (brief.service.ts: 2048 bytes, tiered pinned →
|
|
48
|
+
* STILL_VALID/ASSERTED → DRIFTED → UNVERIFIED, each rendered with its own flag
|
|
49
|
+
* text). Re-ranking, re-wrapping or re-capping it here would give the agent a
|
|
50
|
+
* different view of the same workspace than the Memory panel gives the human,
|
|
51
|
+
* and the two would drift apart with no test able to see it. The one judgement
|
|
52
|
+
* this function makes is whether there is anything to show at all.
|
|
53
|
+
*
|
|
54
|
+
* `null` — the fetch failed, or the workspace has no memory yet — renders the
|
|
55
|
+
* instruction alone rather than an empty heading. An empty heading reads as
|
|
56
|
+
* "this workspace knows nothing", which is a different and wrong claim.
|
|
57
|
+
*/
|
|
58
|
+
function memorySection(brief) {
|
|
59
|
+
if (!brief || brief.trim().length === 0)
|
|
60
|
+
return exports.MEMORY_POINTER;
|
|
61
|
+
return `${exports.MEMORY_POINTER}\n\n${brief.trim()}`;
|
|
62
|
+
}
|
package/dist/bridge/pairing.js
CHANGED
|
@@ -18,7 +18,13 @@ async function runPairingPoll(deps) {
|
|
|
18
18
|
const result = await deps.poll();
|
|
19
19
|
if (deps.isCancelled())
|
|
20
20
|
return { outcome: 'cancelled' };
|
|
21
|
-
|
|
21
|
+
// wha-08: PairingPollResponse's 'approved' status now also covers
|
|
22
|
+
// cli_login (auth/login.ts), which carries an apiKey instead of a
|
|
23
|
+
// connectToken/deviceId — `purpose !== 'cli_login'` is a type-only
|
|
24
|
+
// narrowing, never a behavior change: a bridge pollToken never yields a
|
|
25
|
+
// cli_login-shaped response, so this condition is always true for any
|
|
26
|
+
// real bridge poll.
|
|
27
|
+
if (result.status === 'approved' && result.purpose !== 'cli_login') {
|
|
22
28
|
return { outcome: 'approved', connectToken: result.connectToken, deviceId: result.deviceId };
|
|
23
29
|
}
|
|
24
30
|
if (result.status === 'expired') {
|
|
@@ -221,13 +221,32 @@ export interface RelayClientOpts {
|
|
|
221
221
|
* error (legacy / local bridge has no workspace checkouts). This opens NO PTY
|
|
222
222
|
* and does NOT feed Claude Code via keystrokes — the context arrives as a FILE.
|
|
223
223
|
*/
|
|
224
|
+
/**
|
|
225
|
+
* wmr-07 — refresh this workspace's standing pointers (work graph, memory
|
|
226
|
+
* brief) without touching its pushed file content. Called when a session
|
|
227
|
+
* opens, because the context-manifest frame only arrives when the pilot has
|
|
228
|
+
* files selected. Absent → nothing happens, exactly as before.
|
|
229
|
+
*/
|
|
230
|
+
refreshContextPointers?: (args: {
|
|
231
|
+
workspaceId: string;
|
|
232
|
+
}) => void | Promise<void>;
|
|
224
233
|
writeContext?: (manifest: {
|
|
225
234
|
workspaceId: string;
|
|
226
235
|
content: string;
|
|
227
236
|
}) => {
|
|
228
237
|
action: string;
|
|
229
238
|
claudeMdPath: string | null;
|
|
230
|
-
} | void
|
|
239
|
+
} | void
|
|
240
|
+
/**
|
|
241
|
+
* wmr-03 — may be async: the hosted implementation fetches this
|
|
242
|
+
* workspace's memory brief before writing the region. The frame handler
|
|
243
|
+
* below resolves it rather than becoming async itself, so no other frame
|
|
244
|
+
* type's ordering changes.
|
|
245
|
+
*/
|
|
246
|
+
| Promise<{
|
|
247
|
+
action: string;
|
|
248
|
+
claudeMdPath: string | null;
|
|
249
|
+
} | void>;
|
|
231
250
|
/**
|
|
232
251
|
* cve-06 (ADR-0047 / ADR-0032): read ONE file out of the container's
|
|
233
252
|
* workspace checkout — the hosted-lane counterpart of the local bridge's
|
|
@@ -1009,6 +1009,31 @@ function startRelayClient(opts) {
|
|
|
1009
1009
|
relayOwned.set(sessionId, { workspaceId });
|
|
1010
1010
|
// tchp-21 — best-effort, fire-and-forget: never blocks `opened`.
|
|
1011
1011
|
maybeCreateSessionAnchor(sessionId, cwd);
|
|
1012
|
+
/*
|
|
1013
|
+
wmr-07 — refresh the standing pointers (work graph, workspace
|
|
1014
|
+
memory + its brief) for this workspace now that a session
|
|
1015
|
+
exists.
|
|
1016
|
+
|
|
1017
|
+
This is the trigger the whole delivery was missing. wmr-01..04
|
|
1018
|
+
rode the context-manifest frame on the assumption it fires when
|
|
1019
|
+
a terminal attaches; it does not — arena only pushes one when
|
|
1020
|
+
the pilot has FILES SELECTED, so for an ordinary workspace the
|
|
1021
|
+
region was never written and neither the memory brief nor the
|
|
1022
|
+
work-graph pointer (shipped months earlier) ever arrived.
|
|
1023
|
+
Confirmed on a live container: CLAUDE.md untouched for 20 hours
|
|
1024
|
+
with neither present.
|
|
1025
|
+
|
|
1026
|
+
Doing it here needs no browser, no selection, and no arena at
|
|
1027
|
+
all — only a session opening, which is exactly when an agent is
|
|
1028
|
+
about to read the file. Pointers-only, so the pilot's pushed
|
|
1029
|
+
file content is preserved. Fire-and-forget: this must never
|
|
1030
|
+
delay or fail an `opened`.
|
|
1031
|
+
*/
|
|
1032
|
+
if (workspaceId && opts.refreshContextPointers) {
|
|
1033
|
+
void Promise.resolve(opts.refreshContextPointers({ workspaceId })).catch((err) => {
|
|
1034
|
+
console.error('[bridge] context pointer refresh failed (non-fatal):', err);
|
|
1035
|
+
});
|
|
1036
|
+
}
|
|
1012
1037
|
attachTo(sessionId)
|
|
1013
1038
|
.then(() => {
|
|
1014
1039
|
send(socket, {
|
|
@@ -1274,12 +1299,26 @@ function startRelayClient(opts) {
|
|
|
1274
1299
|
send(socket, { t: 'error', message: 'context-manifest unsupported (no workspace checkouts)' });
|
|
1275
1300
|
break;
|
|
1276
1301
|
}
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1302
|
+
// wmr-03: the implementation may be async (it fetches the memory
|
|
1303
|
+
// brief). Resolved here so the outer message handler stays sync —
|
|
1304
|
+
// making IT async would change ordering for every frame type. A
|
|
1305
|
+
// rejection can only come from a bug in the writer, never from the
|
|
1306
|
+
// brief fetch (which resolves null on any failure, PRD D2), so it
|
|
1307
|
+
// is answered rather than thrown into an unhandled rejection.
|
|
1308
|
+
Promise.resolve(opts.writeContext({ workspaceId: frame.workspaceId, content: frame.content ?? '' }))
|
|
1309
|
+
.then((result) => {
|
|
1310
|
+
send(socket, {
|
|
1311
|
+
t: 'context-written',
|
|
1312
|
+
workspaceId: frame.workspaceId,
|
|
1313
|
+
...(frame.sessionId ? { sessionId: frame.sessionId } : {}),
|
|
1314
|
+
...(result && typeof result === 'object' ? { action: result.action } : {}),
|
|
1315
|
+
});
|
|
1316
|
+
})
|
|
1317
|
+
.catch((err) => {
|
|
1318
|
+
send(socket, {
|
|
1319
|
+
t: 'error',
|
|
1320
|
+
message: `context-manifest failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1321
|
+
});
|
|
1283
1322
|
});
|
|
1284
1323
|
break;
|
|
1285
1324
|
}
|
package/dist/bridge/server.d.ts
CHANGED
|
@@ -197,10 +197,19 @@ export interface BridgeServerOpts {
|
|
|
197
197
|
* this is a FILE write, not PTY input (ADR-0028), mirroring the hosted
|
|
198
198
|
* lane's contextWriter.ts/relayClient.ts contract.
|
|
199
199
|
*/
|
|
200
|
+
/** wmr-04 — may be async: the implementation fetches this workspace's memory
|
|
201
|
+
* brief before writing. The frame handler resolves it rather than becoming
|
|
202
|
+
* async itself, so no other frame type's ordering changes. */
|
|
203
|
+
/** wmr-07 — the local twin of the hosted refreshContextPointers: write this
|
|
204
|
+
* workspace's standing pointers when a session opens, without waiting for a
|
|
205
|
+
* context-manifest that only arrives when files are selected. */
|
|
206
|
+
refreshLocalContextPointers?: (args: {
|
|
207
|
+
workspaceId: string;
|
|
208
|
+
}) => void | Promise<void>;
|
|
200
209
|
writeLocalContext?: (params: {
|
|
201
210
|
workspaceId: string;
|
|
202
211
|
content: string;
|
|
203
|
-
}) => LocalContextWriteResult | null
|
|
212
|
+
}) => LocalContextWriteResult | null | Promise<LocalContextWriteResult | null>;
|
|
204
213
|
/**
|
|
205
214
|
* fcct-24 — path to the local HiveOp activity JSONL file the activity
|
|
206
215
|
* hooks (registered via a directly-spawned agent's `--settings`, see
|
package/dist/bridge/server.js
CHANGED
|
@@ -766,6 +766,14 @@ function startBridgeServer(opts) {
|
|
|
766
766
|
send(ws, { t: 'error', message });
|
|
767
767
|
break;
|
|
768
768
|
}
|
|
769
|
+
// wmr-07 — same trigger as the hosted lane: the pointers are
|
|
770
|
+
// refreshed when a session opens, not when a manifest happens to
|
|
771
|
+
// be pushed. Fire-and-forget; never delays or fails `opened`.
|
|
772
|
+
if (frame.workspaceId && opts.refreshLocalContextPointers) {
|
|
773
|
+
void Promise.resolve(opts.refreshLocalContextPointers({ workspaceId: frame.workspaceId })).catch((err) => {
|
|
774
|
+
console.error('[bridge] local context pointer refresh failed (non-fatal):', err);
|
|
775
|
+
});
|
|
776
|
+
}
|
|
769
777
|
attachTo(sessionId).then(() => {
|
|
770
778
|
send(ws, {
|
|
771
779
|
t: 'opened',
|
|
@@ -874,16 +882,27 @@ function startBridgeServer(opts) {
|
|
|
874
882
|
send(ws, { t: 'error', message: 'context-manifest unsupported (no local writer wired)' });
|
|
875
883
|
break;
|
|
876
884
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
885
|
+
// wmr-04: mirrors the hosted lane — resolved here so the outer
|
|
886
|
+
// handler stays sync. A rejection can only be a bug in the writer;
|
|
887
|
+
// the brief fetch resolves null on any failure (PRD D2).
|
|
888
|
+
Promise.resolve(opts.writeLocalContext({ workspaceId: frame.workspaceId, content: frame.content }))
|
|
889
|
+
.then((result) => {
|
|
890
|
+
if (!result) {
|
|
891
|
+
send(ws, { t: 'error', message: 'unknown local workspace' });
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
send(ws, {
|
|
895
|
+
t: 'context-written',
|
|
896
|
+
workspaceId: frame.workspaceId,
|
|
897
|
+
...(frame.sessionId ? { sessionId: frame.sessionId } : {}),
|
|
898
|
+
action: result.action,
|
|
899
|
+
});
|
|
900
|
+
})
|
|
901
|
+
.catch((err) => {
|
|
902
|
+
send(ws, {
|
|
903
|
+
t: 'error',
|
|
904
|
+
message: `context-manifest failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
905
|
+
});
|
|
887
906
|
});
|
|
888
907
|
break;
|
|
889
908
|
}
|
package/dist/commands/auth.d.ts
CHANGED
|
@@ -1,2 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wha-08 (docs/prd/retire-wallet-header-auth.md, docs/CONTEXT-identity.md) —
|
|
3
|
+
* `wen-market auth login` / `auth logout` / `auth whoami`.
|
|
4
|
+
*
|
|
5
|
+
* `login` runs the device-code flow (lws-14's mechanism, purpose=cli_login —
|
|
6
|
+
* see auth/login.ts): a code is minted and printed with the approval URL
|
|
7
|
+
* (https://marketplace.wenrwa.com/settings/cli-login?code=<CODE>), the
|
|
8
|
+
* browser is opened as best-effort convenience, and the CLI polls until a
|
|
9
|
+
* human approves or denies it there. `--api-key` skips all of that for CI:
|
|
10
|
+
* an existing key is verified with one authenticated call and saved
|
|
11
|
+
* directly. Either way the CLI authenticates as an API key (X-API-Key) —
|
|
12
|
+
* never the retired X-Wallet-Pubkey header (see utils/client.ts).
|
|
13
|
+
*
|
|
14
|
+
* `logout` revokes the stored key server-side (DELETE /keys/:id — see
|
|
15
|
+
* ApiKeyController#revoke's wha-08 self-revoke-only guard) before deleting
|
|
16
|
+
* it locally, so a copied config file stops working too.
|
|
17
|
+
*/
|
|
1
18
|
import { Command } from 'commander';
|
|
2
19
|
export declare const authCommand: Command;
|