@wenrwa/marketplace-cli 0.6.6 → 0.7.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 (74) hide show
  1. package/README.md +85 -85
  2. package/dist/__tests__/auth-login-core.test.js +2 -2
  3. package/dist/__tests__/auth.test.js +4 -4
  4. package/dist/__tests__/bridge-autostart.test.js +9 -9
  5. package/dist/__tests__/bridge-checkout-dirty-real-git.test.d.ts +1 -0
  6. package/dist/__tests__/bridge-checkout-dirty-real-git.test.js +145 -0
  7. package/dist/__tests__/bridge-checkout-inventory-reporter.test.js +6 -2
  8. package/dist/__tests__/bridge-checkout-inventory.test.js +128 -14
  9. package/dist/__tests__/bridge-checkout-park-and-remove.test.js +57 -8
  10. package/dist/__tests__/bridge-claude-trust.test.d.ts +1 -0
  11. package/dist/__tests__/bridge-claude-trust.test.js +137 -0
  12. package/dist/__tests__/bridge-command-browser-options.test.js +1 -1
  13. package/dist/__tests__/bridge-command-install-env.test.js +1 -1
  14. package/dist/__tests__/bridge-device-registration.test.js +1 -1
  15. package/dist/__tests__/bridge-folder-registry.test.js +1 -1
  16. package/dist/__tests__/bridge-local-add-core.test.js +1 -1
  17. package/dist/__tests__/bridge-match-pointer.test.d.ts +1 -0
  18. package/dist/__tests__/bridge-match-pointer.test.js +136 -0
  19. package/dist/__tests__/bridge-pairing-api.test.js +1 -1
  20. package/dist/__tests__/bridge-pairing-core.test.js +1 -1
  21. package/dist/__tests__/bridge-park-remove-frame.test.js +61 -0
  22. package/dist/__tests__/bridge-relay-client-checkout-inventory.test.js +1 -1
  23. package/dist/__tests__/bridge-relay-mode.test.js +1 -1
  24. package/dist/__tests__/bridge-server.test.js +1 -1
  25. package/dist/__tests__/config.test.js +1 -1
  26. package/dist/__tests__/devices.test.js +1 -1
  27. package/dist/__tests__/local.test.js +1 -1
  28. package/dist/__tests__/openBrowser.test.js +1 -1
  29. package/dist/__tests__/websocket.test.js +3 -3
  30. package/dist/auth/identity.d.ts +1 -1
  31. package/dist/auth/login.d.ts +2 -2
  32. package/dist/bridge/apiClient.js +2 -2
  33. package/dist/bridge/autostart.d.ts +1 -1
  34. package/dist/bridge/autostart.js +1 -1
  35. package/dist/bridge/checkoutInventory.d.ts +48 -17
  36. package/dist/bridge/checkoutInventory.js +190 -44
  37. package/dist/bridge/checkoutParkAndRemove.d.ts +22 -1
  38. package/dist/bridge/checkoutParkAndRemove.js +37 -7
  39. package/dist/bridge/claudeTrust.d.ts +37 -0
  40. package/dist/bridge/claudeTrust.js +85 -0
  41. package/dist/bridge/config.d.ts +1 -1
  42. package/dist/bridge/contextWriter.d.ts +2 -0
  43. package/dist/bridge/contextWriter.js +3 -2
  44. package/dist/bridge/deviceRegistration.d.ts +1 -1
  45. package/dist/bridge/envSanitize.d.ts +1 -1
  46. package/dist/bridge/envSanitize.js +1 -1
  47. package/dist/bridge/folderRegistry.js +1 -1
  48. package/dist/bridge/localAdd.js +1 -1
  49. package/dist/bridge/localContextWriter.d.ts +2 -0
  50. package/dist/bridge/localContextWriter.js +3 -2
  51. package/dist/bridge/memoryBrief.d.ts +16 -4
  52. package/dist/bridge/memoryBrief.js +17 -9
  53. package/dist/bridge/pairing.d.ts +1 -1
  54. package/dist/bridge/relayClient.js +11 -1
  55. package/dist/bridge/server.d.ts +1 -1
  56. package/dist/bridge/workGraphPointer.d.ts +19 -0
  57. package/dist/bridge/workGraphPointer.js +26 -1
  58. package/dist/commands/apps.js +1 -1
  59. package/dist/commands/auth.d.ts +1 -1
  60. package/dist/commands/auth.js +6 -6
  61. package/dist/commands/bridge.js +40 -13
  62. package/dist/commands/credits.js +1 -1
  63. package/dist/commands/devices.d.ts +1 -1
  64. package/dist/commands/devices.js +4 -4
  65. package/dist/commands/local.d.ts +1 -1
  66. package/dist/commands/local.js +5 -5
  67. package/dist/commands/pair.d.ts +1 -1
  68. package/dist/commands/pair.js +4 -4
  69. package/dist/index.js +2 -2
  70. package/dist/utils/config.js +2 -2
  71. package/dist/utils/openBrowser.d.ts +1 -1
  72. package/dist/utils/openBrowser.js +1 -1
  73. package/dist/utils/websocket.js +1 -1
  74. package/package.json +3 -2
@@ -37,6 +37,19 @@
37
37
  * against the same working tree would race git itself, not merely the
38
38
  * delete — hcs-05's set alone only covers the delete step.
39
39
  *
40
+ * SAVE (cli 0.6.9, owner request "why can't I get these things to save
41
+ * without removing?"): `park(id, onPhase, { remove: false })` runs the same
42
+ * commit -> push -> verify and stops there — outcome `saved`, checkout kept.
43
+ * Remove on a checkout with nothing to park now removes it (through the
44
+ * reclaimer, which re-checks clean + unattached first): everything in it is
45
+ * already on a remote, so refusing left clean match copies with no way out
46
+ * but the 14-day automatic sweep.
47
+ *
48
+ * After a verified push the parking branch is recorded as a remote-tracking
49
+ * ref (`refs/remotes/origin/park/<id>`). The clone is `--single-branch`, so
50
+ * git does not do this itself, and without it the dirty check (commits no
51
+ * remote ref contains) could never see that the work is now saved.
52
+ *
40
53
  * PHASES: `committing` / `pushing` / `removing`, reported through the
41
54
  * optional `onPhase` callback as each begins — the wire layer
42
55
  * (relayClient.ts) turns these into `park-remove-progress` frames so a UI
@@ -55,6 +68,10 @@ export type ParkAndRemoveOutcome = {
55
68
  workspaceId: string;
56
69
  outcome: 'nothing-to-park';
57
70
  branch: string;
71
+ } | {
72
+ workspaceId: string;
73
+ outcome: 'saved';
74
+ branch: string;
58
75
  } | {
59
76
  workspaceId: string;
60
77
  outcome: 'retained';
@@ -87,13 +104,17 @@ export interface CheckoutParkAndRemoveDeps {
87
104
  * hcs-05 already proved. */
88
105
  reclaimer: CheckoutReclaimer;
89
106
  }
107
+ export interface ParkOptions {
108
+ /** false = Save: back the work up and keep the checkout. Default true. */
109
+ remove?: boolean;
110
+ }
90
111
  export interface CheckoutParker {
91
112
  /** Park (commit + push + remove-on-verified-push) one checkout.
92
113
  * `onPhase`, when given, is called once per phase as it BEGINS —
93
114
  * 'committing' first, always; 'pushing' and 'removing' only if the
94
115
  * operation reaches them. Never throws — every failure mode is a typed
95
116
  * outcome, same discipline as CheckoutReclaimer#reclaim. */
96
- park(workspaceId: string, onPhase?: (phase: ParkPhase) => void): Promise<ParkAndRemoveOutcome>;
117
+ park(workspaceId: string, onPhase?: (phase: ParkPhase) => void, opts?: ParkOptions): Promise<ParkAndRemoveOutcome>;
97
118
  }
98
119
  /**
99
120
  * Deterministic from the workspace id alone (no timestamp) — PURE, so a
@@ -41,6 +41,19 @@ exports.createCheckoutParker = createCheckoutParker;
41
41
  * against the same working tree would race git itself, not merely the
42
42
  * delete — hcs-05's set alone only covers the delete step.
43
43
  *
44
+ * SAVE (cli 0.6.9, owner request "why can't I get these things to save
45
+ * without removing?"): `park(id, onPhase, { remove: false })` runs the same
46
+ * commit -> push -> verify and stops there — outcome `saved`, checkout kept.
47
+ * Remove on a checkout with nothing to park now removes it (through the
48
+ * reclaimer, which re-checks clean + unattached first): everything in it is
49
+ * already on a remote, so refusing left clean match copies with no way out
50
+ * but the 14-day automatic sweep.
51
+ *
52
+ * After a verified push the parking branch is recorded as a remote-tracking
53
+ * ref (`refs/remotes/origin/park/<id>`). The clone is `--single-branch`, so
54
+ * git does not do this itself, and without it the dirty check (commits no
55
+ * remote ref contains) could never see that the work is now saved.
56
+ *
44
57
  * PHASES: `committing` / `pushing` / `removing`, reported through the
45
58
  * optional `onPhase` callback as each begins — the wire layer
46
59
  * (relayClient.ts) turns these into `park-remove-progress` frames so a UI
@@ -81,7 +94,8 @@ function createCheckoutParker(deps) {
81
94
  // must cover the WHOLE operation (commit+push+remove) and not merely the
82
95
  // delete step, which is a SEPARATE lock (hcs-05's reclaimer, reused below).
83
96
  const inFlight = new Set();
84
- async function park(workspaceId, onPhase) {
97
+ async function park(workspaceId, onPhase, opts = {}) {
98
+ const remove = opts.remove !== false;
85
99
  // Path safety — resolved from workspaceId ALONE, reusing hcs-05's exact
86
100
  // resolver rather than a second implementation. There is no path on the
87
101
  // wire to trust in the first place.
@@ -132,14 +146,25 @@ function createCheckoutParker(deps) {
132
146
  // A failure here (no upstream configured, detached HEAD, ...) is NOT
133
147
  // a hard failure — it just means "assume there might be something to
134
148
  // push" and let the push step itself be the source of truth.
135
- const ahead = await runGit(deps.run, target, ['rev-list', '@{u}..HEAD', '--count']);
149
+ // Commits no remote-tracking ref contains — the same definition the
150
+ // dirty check uses (checkoutInventory.ts inspectDirty).
151
+ const ahead = await runGit(deps.run, target, ['rev-list', 'HEAD', '--not', '--remotes', '--count']);
136
152
  const hasUnpushed = ahead.code === 0 ? parseInt(ahead.stdout.trim(), 10) > 0 : true;
137
153
  if (!committedSomething && !hasUnpushed) {
138
- // Genuinely nothing to park. Per the issue's acceptance criterion,
139
- // this reports "nothing to park" rather than guessing at a delete —
140
- // the invariant is "delete only after a PROVEN push", and there is
141
- // no push to prove here, so the checkout is retained.
142
- return { workspaceId, outcome: 'nothing-to-park', branch };
154
+ // Genuinely nothing to park: everything here is already on a remote.
155
+ // Save reports that. Remove goes straight to the reclaimer, whose
156
+ // own immediate re-check (clean, unattached) still guards the delete.
157
+ if (!remove)
158
+ return { workspaceId, outcome: 'nothing-to-park', branch };
159
+ phase = 'removing';
160
+ onPhase?.(phase);
161
+ const [cleanResult] = await deps.reclaimer.reclaim([
162
+ { workspaceId, verdict: 'RECLAIM', reason: 'park-and-remove: nothing unsaved' },
163
+ ]);
164
+ if (cleanResult.outcome === 'removed') {
165
+ return { workspaceId, outcome: 'removed', branch, bytesFreed: cleanResult.bytesFreed };
166
+ }
167
+ return { workspaceId, outcome: 'retained', branch, phase, reason: cleanResult.reason };
143
168
  }
144
169
  // ---- PUSHING --------------------------------------------------------
145
170
  phase = 'pushing';
@@ -167,6 +192,11 @@ function createCheckoutParker(deps) {
167
192
  if (remoteSha !== localSha) {
168
193
  return { workspaceId, outcome: 'retained', branch, phase, reason: `push reported success but the remote ref points at a different commit (${remoteSha.slice(0, 8)} != ${localSha.slice(0, 8)}) — refusing to trust it` };
169
194
  }
195
+ // Record what the remote just proved, so the dirty check sees the work
196
+ // as saved. Best-effort: the push is already verified either way.
197
+ await runGit(deps.run, target, ['update-ref', `refs/remotes/origin/${branch}`, localSha]);
198
+ if (!remove)
199
+ return { workspaceId, outcome: 'saved', branch };
170
200
  // ---- REMOVING -------------------------------------------------------
171
201
  // The work is now PROVABLY on the remote. Only past this point may
172
202
  // anything be deleted, and only via hcs-05's own executor — see the
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Playtest 2026-10-01 (Qubit Forge, hosted lane) — pre-trust the workspace
3
+ * checkouts this bridge itself clones, so Claude Code never opens on its
4
+ * folder-trust dialog in them.
5
+ *
6
+ * Claude Code (2.1.28x) shows "Quick safety check: Is this a project you
7
+ * created or one you trust? … ❯ No, exit / Yes, I trust this folder" on any
8
+ * folder its config has not trusted — EVEN under --dangerously-skip-
9
+ * permissions — and the default is "No, exit". Every match / workspace gets a
10
+ * fresh /data/repos/<workspaceId>, so every first agent there met it, and a
11
+ * queued first message (Send to agent) answered it with the default: Claude
12
+ * exited to a bare shell.
13
+ *
14
+ * The container is ours, the bridge cloned the folder from the workspace's own
15
+ * repo, and the agent was launched in bypass mode by the pilot's own spawn
16
+ * choice — the trust question has nobody meaningful to ask. So the bridge
17
+ * records the answer Claude would: `projects[<dir>].hasTrustDialogAccepted =
18
+ * true` in `$CLAUDE_CONFIG_DIR/.claude.json` (where Claude keeps its global
19
+ * config when CLAUDE_CONFIG_DIR is set — verified against 2.1.286).
20
+ *
21
+ * The entry must name the checkout itself: inside a git repo Claude only walks
22
+ * up to the repo ROOT looking for a trusted entry, so trusting /data/repos
23
+ * would not count.
24
+ *
25
+ * Scope: HOSTED LANE ONLY (commands/bridge.ts wires it into the container's
26
+ * clone-on-demand path, and only when CLAUDE_CONFIG_DIR is set), and only for
27
+ * folders strictly inside the bridge's repos dir. A local-lane user's own
28
+ * Claude config is never touched.
29
+ *
30
+ * Never clobbers: an unparseable config (it also carries onboarding/login
31
+ * state) is left alone; every other key is preserved; the write is tmp+rename.
32
+ */
33
+ export type ClaudeTrustResult = 'trusted' | 'already' | 'skipped';
34
+ export declare function trustClaudeProjectDir(dir: string, opts: {
35
+ configDir: string;
36
+ reposBaseDir: string;
37
+ }): ClaudeTrustResult;
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.trustClaudeProjectDir = trustClaudeProjectDir;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ function trustClaudeProjectDir(dir, opts) {
40
+ const base = path.resolve(opts.reposBaseDir);
41
+ const target = path.resolve(dir);
42
+ if (!target.startsWith(base + path.sep))
43
+ return 'skipped';
44
+ const file = path.join(opts.configDir, '.claude.json');
45
+ let cfg = {};
46
+ let raw = null;
47
+ try {
48
+ raw = fs.readFileSync(file, 'utf-8');
49
+ }
50
+ catch {
51
+ raw = null; // no config yet — Claude merges its defaults over what we write
52
+ }
53
+ if (raw !== null) {
54
+ try {
55
+ const parsed = JSON.parse(raw);
56
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
57
+ return 'skipped';
58
+ cfg = parsed;
59
+ }
60
+ catch {
61
+ return 'skipped';
62
+ }
63
+ }
64
+ const projects = cfg.projects && typeof cfg.projects === 'object' && !Array.isArray(cfg.projects)
65
+ ? cfg.projects
66
+ : {};
67
+ const entry = projects[target] && typeof projects[target] === 'object' ? projects[target] : {};
68
+ if (entry.hasTrustDialogAccepted === true)
69
+ return 'already';
70
+ const next = { ...cfg, projects: { ...projects, [target]: { ...entry, hasTrustDialogAccepted: true } } };
71
+ fs.mkdirSync(opts.configDir, { recursive: true });
72
+ const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
73
+ try {
74
+ fs.writeFileSync(tmp, JSON.stringify(next, null, 2) + '\n', { mode: 0o600 });
75
+ fs.renameSync(tmp, file);
76
+ }
77
+ catch (err) {
78
+ try {
79
+ fs.rmSync(tmp, { force: true });
80
+ }
81
+ catch { /* best effort */ }
82
+ throw err;
83
+ }
84
+ return 'trusted';
85
+ }
@@ -1,7 +1,7 @@
1
1
  export interface BridgeConfig {
2
2
  connectToken: string;
3
3
  /** lws-03: set once this machine auto-registers as a device (first
4
- * `wen-market bridge` run) — persisted so re-registration is idempotent. */
4
+ * `hiveop bridge` run) — persisted so re-registration is idempotent. */
5
5
  deviceId?: string;
6
6
  }
7
7
  export interface DiscoveryInfo {
@@ -32,6 +32,8 @@ export declare function writeContext(input: {
32
32
  /** Absent only for a pointers-only refresh (wmr-07). */
33
33
  content?: string;
34
34
  workGraphAvailable?: boolean;
35
+ /** 2026-10-02 — a match workspace: MATCH_POINTER replaces the work-queue pointer (workSection). */
36
+ match?: boolean;
35
37
  /**
36
38
  * wmr-01 — whether to carry the workspace-memory guidance. Decided by the
37
39
  * caller on the same signal as workGraphAvailable (WENRWA_CONNECT_TOKEN),
@@ -148,8 +148,9 @@ function writeContext(input, deps) {
148
148
  return existing.slice(s0 + exports.CONTEXT_START_MARKER.length, e0).trim();
149
149
  })();
150
150
  const pointers = [];
151
- if (input.workGraphAvailable)
152
- pointers.push(workGraphPointer_1.WORK_GRAPH_POINTER);
151
+ const work = (0, workGraphPointer_1.workSection)(input);
152
+ if (work)
153
+ pointers.push(work);
153
154
  if (input.memoryAvailable)
154
155
  pointers.push((0, memoryPointer_1.memorySection)(input.memoryBrief));
155
156
  // wmr-07: a pointers-only refresh keeps the region's existing file content
@@ -1,5 +1,5 @@
1
1
  /**
2
- * lws-03 — "Connect this machine": on first `wen-market bridge` run with a
2
+ * lws-03 — "Connect this machine": on first `hiveop bridge` run with a
3
3
  * Connect Token configured, auto-register the device and persist its id
4
4
  * into bridge-config.json so re-registration is skipped thereafter (a
5
5
  * pure resolver, mirroring resolveRelayMode in commands/bridge.ts, so the
@@ -20,7 +20,7 @@ export declare const STRIPPED_ENV_PREFIXES: readonly ["CLAUDE_CODE_"];
20
20
  * fcct-27 — the RELAY CREDENTIALS are stripped here too, for a different and
21
21
  * sharper reason than the session markers above.
22
22
  *
23
- * `wen-market bridge` reads `CREW_RELAY_TOKEN` / `RELAY_TOKEN` from its own
23
+ * `hiveop bridge` reads `CREW_RELAY_TOKEN` / `RELAY_TOKEN` from its own
24
24
  * environment (the launch agent sets them), and every PTY it spawns inherits
25
25
  * that environment. Seen live 2026-08-16: a crew member's `claude` process had
26
26
  * the device-bound connect token sitting in plain view in `ps eww`. Nothing
@@ -24,7 +24,7 @@ exports.STRIPPED_ENV_PREFIXES = ['CLAUDE_CODE_'];
24
24
  * fcct-27 — the RELAY CREDENTIALS are stripped here too, for a different and
25
25
  * sharper reason than the session markers above.
26
26
  *
27
- * `wen-market bridge` reads `CREW_RELAY_TOKEN` / `RELAY_TOKEN` from its own
27
+ * `hiveop bridge` reads `CREW_RELAY_TOKEN` / `RELAY_TOKEN` from its own
28
28
  * environment (the launch agent sets them), and every PTY it spawns inherits
29
29
  * that environment. Seen live 2026-08-16: a crew member's `claude` process had
30
30
  * the device-bound connect token sitting in plain view in `ps eww`. Nothing
@@ -41,7 +41,7 @@ exports.removeEntryByWorkspaceId = removeEntryByWorkspaceId;
41
41
  exports.findEntryByPath = findEntryByPath;
42
42
  exports.findEntryByWorkspaceId = findEntryByWorkspaceId;
43
43
  /**
44
- * lws-03 — folder→workspace registry. Backs `wen-market local add/list/
44
+ * lws-03 — folder→workspace registry. Backs `hiveop local add/list/
45
45
  * remove` and the discovery advertisement (server.ts). Lives alongside the
46
46
  * bridge's other dotfiles under ~/.wen-market/ rather than a second dotdir,
47
47
  * matching config.ts's convention. File-backed so it survives daemon
@@ -36,7 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.addLocalWorkspaceCore = addLocalWorkspaceCore;
37
37
  /**
38
38
  * lws-05 — bridge-side idempotent add core, behind POST /local/add. Mirrors
39
- * `wen-market local add`'s behavior (commands/local.ts) so the arena
39
+ * `hiveop local add`'s behavior (commands/local.ts) so the arena
40
40
  * create-modal's Browse/typed-path attach mechanisms (PRD D3b/D3c) end at the
41
41
  * exact same registered-workspace outcome as the CLI mechanism (D3a) —
42
42
  * deps-injected so server.ts can wire it without this module knowing about
@@ -29,6 +29,8 @@ export declare function writeLocalContext(input: {
29
29
  /** Absent only for a pointers-only refresh (wmr-07). */
30
30
  content?: string;
31
31
  workGraphAvailable?: boolean;
32
+ /** 2026-10-02 — a match workspace: MATCH_POINTER replaces the work-queue pointer (workSection). */
33
+ match?: boolean;
32
34
  /** wmr-04 — two-lane parity with contextWriter.ts. Gated by the caller on
33
35
  * the local lane's own honest signal (did THIS bridge run register the
34
36
  * MCP server), not on a container env var that does not exist here. */
@@ -89,8 +89,9 @@ function writeLocalContext(input, deps) {
89
89
  // this would be a two-lane bug nobody would notice until a local pilot
90
90
  // reported missing memory.
91
91
  const pointers = [];
92
- if (input.workGraphAvailable)
93
- pointers.push(workGraphPointer_1.WORK_GRAPH_POINTER);
92
+ const work = (0, workGraphPointer_1.workSection)(input);
93
+ if (work)
94
+ pointers.push(work);
94
95
  if (input.memoryAvailable)
95
96
  pointers.push((0, memoryPointer_1.memorySection)(input.memoryBrief));
96
97
  // wmr-07 — the whole local file is bridge-owned, so "preserve the pushed
@@ -33,9 +33,21 @@ export interface FetchMemoryBriefOpts {
33
33
  timeoutMs?: number;
34
34
  }
35
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.
36
+ * The brief reply as the bridge uses it: the brief text (null when empty) and
37
+ * whether the workspace is a MATCH (2026-10-02 — the reply's `match: true`;
38
+ * absent on an ordinary workspace and from an older backend).
39
+ */
40
+ export interface WorkspaceBriefInfo {
41
+ brief: string | null;
42
+ match: boolean;
43
+ }
44
+ /**
45
+ * Fetch the brief reply for `workspaceId`. Same failure contract as the module
46
+ * header: never throws, never hangs — any failure resolves null (unknown).
47
+ */
48
+ export declare function fetchWorkspaceBrief(workspaceId: string, opts?: FetchMemoryBriefOpts): Promise<WorkspaceBriefInfo | null>;
49
+ /**
50
+ * Fetch the workspace memory brief for `workspaceId` — the brief text only
51
+ * (wmr-02's contract, unchanged: null on any failure or an empty brief).
40
52
  */
41
53
  export declare function fetchMemoryBrief(workspaceId: string, opts?: FetchMemoryBriefOpts): Promise<string | null>;
@@ -16,17 +16,16 @@
16
16
  * point of failure for opening a terminal.
17
17
  */
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.fetchWorkspaceBrief = fetchWorkspaceBrief;
19
20
  exports.fetchMemoryBrief = fetchMemoryBrief;
20
21
  const DEFAULT_API_URL = 'https://api.wenrwa.com/api/v1';
21
22
  /** Bounded so a hanging backend can never stall a terminal open. */
22
23
  const DEFAULT_TIMEOUT_MS = 4000;
23
24
  /**
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.
25
+ * Fetch the brief reply for `workspaceId`. Same failure contract as the module
26
+ * header: never throws, never hangs — any failure resolves null (unknown).
28
27
  */
29
- async function fetchMemoryBrief(workspaceId, opts = {}) {
28
+ async function fetchWorkspaceBrief(workspaceId, opts = {}) {
30
29
  const token = process.env.WENRWA_CONNECT_TOKEN;
31
30
  if (!token)
32
31
  return null; // missing/empty token — never even attempt the call
@@ -47,10 +46,12 @@ async function fetchMemoryBrief(workspaceId, opts = {}) {
47
46
  if (!res.ok)
48
47
  return null;
49
48
  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;
49
+ if (body?.success !== true)
50
+ return null;
51
+ return {
52
+ brief: typeof body.brief === 'string' && body.brief.length > 0 ? body.brief : null,
53
+ match: body.match === true,
54
+ };
54
55
  }
55
56
  catch {
56
57
  // network error, abort/timeout, or json() throwing on malformed JSON —
@@ -61,3 +62,10 @@ async function fetchMemoryBrief(workspaceId, opts = {}) {
61
62
  clearTimeout(timer);
62
63
  }
63
64
  }
65
+ /**
66
+ * Fetch the workspace memory brief for `workspaceId` — the brief text only
67
+ * (wmr-02's contract, unchanged: null on any failure or an empty brief).
68
+ */
69
+ async function fetchMemoryBrief(workspaceId, opts = {}) {
70
+ return (await fetchWorkspaceBrief(workspaceId, opts))?.brief ?? null;
71
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * lws-14 — device-code pairing (GitHub-CLI / Apple-TV pattern), replacing
3
- * "mint a Connect Token, copy it, paste it into a shell". `wen-market pair`
3
+ * "mint a Connect Token, copy it, paste it into a shell". `hiveop pair`
4
4
  * requests a code, prints it, and polls until a human approves it in the
5
5
  * browser — no secret is ever typed or pasted by the user.
6
6
  *
@@ -1300,7 +1300,13 @@ function startRelayClient(opts) {
1300
1300
  });
1301
1301
  break;
1302
1302
  }
1303
+ case 'inventory-scan': {
1304
+ checkoutInventoryReporter?.trigger();
1305
+ break;
1306
+ }
1307
+ case 'park-save':
1303
1308
  case 'park-remove': {
1309
+ const removeAfter = frame.t === 'park-remove';
1304
1310
  // hcs-06: ALWAYS user-initiated (see the frame's own doc comment
1305
1311
  // in the ClientFrame union above) — commit + push + (only on a
1306
1312
  // verified push) remove, reporting real phases as
@@ -1320,9 +1326,13 @@ function startRelayClient(opts) {
1320
1326
  parker
1321
1327
  .park(frame.workspaceId, (phase) => {
1322
1328
  send(socket, { t: 'park-remove-progress', workspaceId: frame.workspaceId, ...sidFields, phase });
1323
- })
1329
+ }, { remove: removeAfter })
1324
1330
  .then((result) => {
1325
1331
  send(socket, { t: 'park-remove-result', ...sidFields, ...result });
1332
+ // The row's truth is the inventory, not this result: re-scan
1333
+ // so a saved checkout reads "Saved" without waiting for the
1334
+ // next connect.
1335
+ checkoutInventoryReporter?.trigger();
1326
1336
  })
1327
1337
  .catch((err) => {
1328
1338
  console.error('[bridge] park-and-remove failed:', err);
@@ -19,7 +19,7 @@ export interface BridgeServerOpts {
19
19
  * (cloned on first use). Absent/null result → shell opens in $HOME. */
20
20
  resolveCwd?: (repoUrl: string) => Promise<string | null>;
21
21
  /** lws-03: the registered local workspaces to advertise on /discovery, so
22
- * the arena create-modal can live-detect `wen-market local add` without a
22
+ * the arena create-modal can live-detect `hiveop local add` without a
23
23
  * daemon restart. A GETTER (not a static array) — server.ts calls it on
24
24
  * every /discovery request, so callers should back it with a fresh
25
25
  * folderRegistry.loadFolderRegistry() read (or an in-memory cache kept
@@ -32,3 +32,22 @@
32
32
  * spec — never "skip the spec, the queue replaces it."
33
33
  */
34
34
  export declare const WORK_GRAPH_POINTER: string;
35
+ /**
36
+ * Qubit Forge playtest 2026-10-02 — the guidance a MATCH workspace gets INSTEAD
37
+ * of the work-queue pointer. An agent in a practice match read "the HiveOp work
38
+ * queue decides what to work on" and went looking for issues to claim. A match
39
+ * has no queue to work: its missions are scored by hidden tests when the pilot
40
+ * presses Submit, against the code on the default branch. So: commit and push,
41
+ * and leave the issue tools alone (claiming or finishing a mission issue does
42
+ * not score it).
43
+ */
44
+ export declare const MATCH_POINTER: string;
45
+ /**
46
+ * The work section of the pointer block: match guidance for a match
47
+ * workspace, else the work-queue pointer when its tools are registered.
48
+ * One function so the hosted and local writers cannot diverge.
49
+ */
50
+ export declare function workSection(input: {
51
+ workGraphAvailable?: boolean;
52
+ match?: boolean;
53
+ }): string | null;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WORK_GRAPH_POINTER = void 0;
3
+ exports.MATCH_POINTER = exports.WORK_GRAPH_POINTER = void 0;
4
+ exports.workSection = workSection;
4
5
  /**
5
6
  * wgcp-01 — the one piece of guidance that tells an agent the workspace work
6
7
  * graph exists at all. Nothing today does: the MCP tools (`list_ready_issues`,
@@ -39,3 +40,27 @@ exports.WORK_GRAPH_POINTER = [
39
40
  'The HiveOp work queue — not the repo — decides WHAT to work on next: `list_ready_issues` to see what is ready, `claim_issue` before starting, `finish_issue` when done.',
40
41
  'Repo files (including `issues/*.md`) may hold the spec for an item you claimed — read them for detail; just do not pick work from them.',
41
42
  ].join('\n');
43
+ /**
44
+ * Qubit Forge playtest 2026-10-02 — the guidance a MATCH workspace gets INSTEAD
45
+ * of the work-queue pointer. An agent in a practice match read "the HiveOp work
46
+ * queue decides what to work on" and went looking for issues to claim. A match
47
+ * has no queue to work: its missions are scored by hidden tests when the pilot
48
+ * presses Submit, against the code on the default branch. So: commit and push,
49
+ * and leave the issue tools alone (claiming or finishing a mission issue does
50
+ * not score it).
51
+ */
52
+ exports.MATCH_POINTER = [
53
+ '## Match',
54
+ 'This workspace is a HiveOp match. Missions are scored when the pilot presses Submit: hidden tests run against the code committed and pushed to the default branch.',
55
+ 'Commit and push your work when it is ready. Do not use the issue tools (`list_ready_issues`, `claim_issue`, `finish_issue`) — there is no queue to work here; the mission files (MISSIONS.md, README.md) say what to build.',
56
+ ].join('\n');
57
+ /**
58
+ * The work section of the pointer block: match guidance for a match
59
+ * workspace, else the work-queue pointer when its tools are registered.
60
+ * One function so the hosted and local writers cannot diverge.
61
+ */
62
+ function workSection(input) {
63
+ if (input.match)
64
+ return exports.MATCH_POINTER;
65
+ return input.workGraphAvailable ? exports.WORK_GRAPH_POINTER : null;
66
+ }
@@ -26,7 +26,7 @@ exports.appsCommand
26
26
  const data = await client.get(`/projects?${params}`);
27
27
  const projects = data.projects || [];
28
28
  if (projects.length === 0) {
29
- console.log('No apps found. Create one with: wen-market apps create');
29
+ console.log('No apps found. Create one with: hiveop apps create');
30
30
  return;
31
31
  }
32
32
  console.log(`${chalk_1.default.dim(`Showing ${projects.length} of ${data.total || projects.length} apps`)}\n`);
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * wha-08 (docs/prd/retire-wallet-header-auth.md, docs/CONTEXT-identity.md) —
3
- * `wen-market auth login` / `auth logout` / `auth whoami`.
3
+ * `hiveop auth login` / `auth logout` / `auth whoami`.
4
4
  *
5
5
  * `login` runs the device-code flow (lws-14's mechanism, purpose=cli_login —
6
6
  * see auth/login.ts): a code is minted and printed with the approval URL
@@ -39,7 +39,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.authCommand = void 0;
40
40
  /**
41
41
  * wha-08 (docs/prd/retire-wallet-header-auth.md, docs/CONTEXT-identity.md) —
42
- * `wen-market auth login` / `auth logout` / `auth whoami`.
42
+ * `hiveop auth login` / `auth logout` / `auth whoami`.
43
43
  *
44
44
  * `login` runs the device-code flow (lws-14's mechanism, purpose=cli_login —
45
45
  * see auth/login.ts): a code is minted and printed with the approval URL
@@ -131,7 +131,7 @@ exports.authCommand
131
131
  .action(async () => {
132
132
  const config = (0, config_1.loadConfig)();
133
133
  if (!config) {
134
- (0, format_1.error)('Not signed in. Run: wen-market auth login');
134
+ (0, format_1.error)('Not signed in. Run: hiveop auth login');
135
135
  process.exit(1);
136
136
  return;
137
137
  }
@@ -151,7 +151,7 @@ exports.authCommand
151
151
  async function confirmReplaceExistingLogin(existing) {
152
152
  const label = (0, apiKeyFormat_1.shortenKey)(existing.apiKey);
153
153
  if (!(0, prompt_1.isInteractive)()) {
154
- (0, format_1.error)(`Already signed in (${label}). Run this in an interactive terminal to confirm, or \`wen-market auth logout\` first.`);
154
+ (0, format_1.error)(`Already signed in (${label}). Run this in an interactive terminal to confirm, or \`hiveop auth logout\` first.`);
155
155
  return false;
156
156
  }
157
157
  const yes = await (0, prompt_1.confirm)(`Already signed in as ${label}. Sign in again? (y/N) `, false);
@@ -163,12 +163,12 @@ async function confirmReplaceExistingLogin(existing) {
163
163
  // ── --api-key (CI) path ─────────────────────────────────────────────────
164
164
  async function loginWithApiKey(key, apiUrl) {
165
165
  if ((0, apiKeyFormat_1.looksLikeWalletPubkey)(key)) {
166
- (0, format_1.error)(`That's a wallet address, not an API key. Run \`wen-market auth login\` or create a key at ${SETTINGS_KEYS_URL}`);
166
+ (0, format_1.error)(`That's a wallet address, not an API key. Run \`hiveop auth login\` or create a key at ${SETTINGS_KEYS_URL}`);
167
167
  process.exit(1);
168
168
  return;
169
169
  }
170
170
  if (!(0, apiKeyFormat_1.isRealApiKey)(key)) {
171
- (0, format_1.error)(`Not a valid API key (expected one starting with wm_sk_). Run \`wen-market auth login\` or create a key at ${SETTINGS_KEYS_URL}`);
171
+ (0, format_1.error)(`Not a valid API key (expected one starting with wm_sk_). Run \`hiveop auth login\` or create a key at ${SETTINGS_KEYS_URL}`);
172
172
  process.exit(1);
173
173
  return;
174
174
  }
@@ -228,7 +228,7 @@ async function reportLoginOutcome(outcome, apiUrl) {
228
228
  return;
229
229
  case 'expired':
230
230
  case 'timeout':
231
- (0, format_1.error)('Code expired — run `wen-market auth login` again.');
231
+ (0, format_1.error)('Code expired — run `hiveop auth login` again.');
232
232
  return;
233
233
  case 'cancelled':
234
234
  default: