@wenrwa/marketplace-cli 0.8.7 → 0.8.9

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.
@@ -64,6 +64,7 @@ const sessionAnchor_1 = require("./sessionAnchor");
64
64
  const sessionTouchTracker_1 = require("./sessionTouchTracker");
65
65
  const attachmentWriter_1 = require("./attachmentWriter");
66
66
  const envSaver_1 = require("./envSaver");
67
+ const envNames_1 = require("./envNames");
67
68
  const screenshotAttach_1 = require("./screenshotAttach");
68
69
  const paneClient_1 = require("./paneClient");
69
70
  const PROTOCOL_VERSION = 1;
@@ -232,10 +233,11 @@ function startBridgeServer(opts) {
232
233
  const method = LOCAL_ENDPOINTS[url.pathname];
233
234
  const localTreeMatch = url.pathname.match(/^\/local-tree\/([^/]+)$/);
234
235
  const localFileMatch = url.pathname.match(/^\/local-file\/([^/]+)$/);
236
+ const envNamesMatch = url.pathname.match(/^\/local-env-names\/([^/]+)$/);
235
237
  // Chrome Private-Network-Access: a public origin (app.hiveop.io) calling a
236
238
  // local address sends an OPTIONS preflight that MUST be answered with
237
239
  // Access-Control-Allow-Private-Network, or the browser blocks the call.
238
- if (req.method === 'OPTIONS' && (method || localTreeMatch || localFileMatch)) {
240
+ if (req.method === 'OPTIONS' && (method || localTreeMatch || localFileMatch || envNamesMatch)) {
239
241
  if (req.headers.origin !== opts.allowedOrigin) {
240
242
  res.writeHead(403).end();
241
243
  return;
@@ -285,6 +287,41 @@ function startBridgeServer(opts) {
285
287
  });
286
288
  return;
287
289
  }
290
+ // tp-02 — GET /local-env-names/:workspaceId?token=… — the NAMES in the
291
+ // registered folder's `.env`, never a value (envNames.ts). Same
292
+ // origin+token gate as /local-tree (a GET can't carry the header).
293
+ if (envNamesMatch) {
294
+ if (req.method !== 'GET') {
295
+ res.writeHead(404).end();
296
+ return;
297
+ }
298
+ if (req.headers.origin !== opts.allowedOrigin) {
299
+ res.writeHead(403).end();
300
+ return;
301
+ }
302
+ if (url.searchParams.get('token') !== opts.sessionToken) {
303
+ res.writeHead(401, { 'access-control-allow-origin': opts.allowedOrigin }).end();
304
+ return;
305
+ }
306
+ let root = null;
307
+ try {
308
+ root = opts.resolveEnvNamesRoot ? opts.resolveEnvNamesRoot(decodeURIComponent(envNamesMatch[1])) : null;
309
+ }
310
+ catch {
311
+ root = null;
312
+ }
313
+ if (!root) {
314
+ sendJson(res, 404, { error: 'not-registered' });
315
+ return;
316
+ }
317
+ const result = (0, envNames_1.readEnvNames)(root);
318
+ if (!result.ok) {
319
+ sendJson(res, result.reason === 'too-large' ? 413 : 422, { error: result.reason });
320
+ return;
321
+ }
322
+ sendJson(res, 200, { names: result.names });
323
+ return;
324
+ }
288
325
  // lws — GET /local-file/:workspaceId?path=…&token=… — same origin+token
289
326
  // gate as /local-tree (a GET can't carry the session-token header).
290
327
  // cve-02 — POST /local-file/:workspaceId (write) lives on the same path:
@@ -397,6 +434,8 @@ function startBridgeServer(opts) {
397
434
  'terminal-attach',
398
435
  // Paste a key → .env — this bridge answers `save-env` frames.
399
436
  'save-env',
437
+ // tp-02 — GET /local-env-names answers (the Keys list, names only).
438
+ ...(opts.resolveEnvNamesRoot ? [envNames_1.ENV_NAMES_CAPABILITY] : []),
400
439
  // Screenshot drop — answers `attach-screenshot` (macOS only).
401
440
  ...((opts.screenshotDeps ?? screenshotAttach_1.realScreenshotDeps).platform === 'darwin' ? ['attach-screenshot'] : []),
402
441
  ],
@@ -22,6 +22,15 @@ export type SweepAnchorsResult = {
22
22
  ok: false;
23
23
  error: string;
24
24
  };
25
+ /** The fixed author/committer of every anchor commit — see createSessionAnchor. */
26
+ export declare const ANCHOR_IDENTITY: {
27
+ env: {
28
+ GIT_AUTHOR_NAME: string;
29
+ GIT_AUTHOR_EMAIL: string;
30
+ GIT_COMMITTER_NAME: string;
31
+ GIT_COMMITTER_EMAIL: string;
32
+ };
33
+ };
25
34
  /** Every session anchor ref lives under this namespace — sweepStaleAnchors's glob and this function must agree. */
26
35
  export declare function anchorRefName(sessionId: string): string;
27
36
  /**
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ANCHOR_IDENTITY = void 0;
36
37
  exports.anchorRefName = anchorRefName;
37
38
  exports.createSessionAnchor = createSessionAnchor;
38
39
  exports.releaseSessionAnchor = releaseSessionAnchor;
@@ -80,6 +81,15 @@ exports.sweepStaleAnchors = sweepStaleAnchors;
80
81
  const os = __importStar(require("os"));
81
82
  const path = __importStar(require("path"));
82
83
  const crypto_1 = require("crypto");
84
+ /** The fixed author/committer of every anchor commit — see createSessionAnchor. */
85
+ exports.ANCHOR_IDENTITY = {
86
+ env: {
87
+ GIT_AUTHOR_NAME: 'HiveOp',
88
+ GIT_AUTHOR_EMAIL: 'session-anchor@hiveop.local',
89
+ GIT_COMMITTER_NAME: 'HiveOp',
90
+ GIT_COMMITTER_EMAIL: 'session-anchor@hiveop.local',
91
+ },
92
+ };
83
93
  /** Every session anchor ref lives under this namespace — sweepStaleAnchors's glob and this function must agree. */
84
94
  function anchorRefName(sessionId) {
85
95
  return `refs/wenrwa/session-${sessionId}`;
@@ -114,7 +124,12 @@ async function createSessionAnchor(cwd, sessionId, deps) {
114
124
  const tree = treeRes.stdout.trim();
115
125
  // commit-tree never reads an index — no env override, and deliberately
116
126
  // no `-p <parent>`: this commit is a floating snapshot, not history.
117
- const commitRes = await deps.run('git', ['-C', cwd, 'commit-tree', tree, '-m', 'wenrwa session anchor']);
127
+ // The identity is set HERE, never inherited: a hosted box has no git
128
+ // identity at all (the agent's rides only in its PTY env), and without
129
+ // one commit-tree dies "Author identity unknown" — which is why no hosted
130
+ // session report had ever been produced (prod 2026-10-19). The anchor is
131
+ // a hidden ref nobody pushes, so a fixed identity costs nothing.
132
+ const commitRes = await deps.run('git', ['-C', cwd, 'commit-tree', tree, '-m', 'wenrwa session anchor'], exports.ANCHOR_IDENTITY);
118
133
  if (commitRes.code !== 0) {
119
134
  return { ok: false, error: `anchor-commit-failed: ${commitRes.stdout.trim() || 'git commit-tree failed'}` };
120
135
  }
@@ -119,6 +119,11 @@ const claudeTrust_1 = require("../bridge/claudeTrust");
119
119
  // servers and the organization-wide Fly private network. See
120
120
  // companionForwarder.ts's module doc comment for the full design.
121
121
  const companionForwarder_1 = require("../bridge/companionForwarder");
122
+ // tp-06 (docs/prd/team-preview.md module 4, ADR-0014) — the Team preview
123
+ // forwarder: gateway address in, one preview port out. Hosted lane only.
124
+ const previewForwarder_1 = require("../bridge/previewForwarder");
125
+ // tp-05 — the Team preview checkout runner (hosted lane only, ADR-0014).
126
+ const previewCheckout_1 = require("../bridge/previewCheckout");
122
127
  /** lws-12 — real fs binding for writeGitignore.ts: mirrors realLocalContextWriterDeps
123
128
  * above, but a `.gitignore` may already hold user content, so this is a plain
124
129
  * read + overwrite (append), never atomic-rename — there's no concurrent
@@ -635,6 +640,21 @@ exports.bridgeCommand = new commander_1.Command('bridge')
635
640
  // does not).
636
641
  rm: rmCheckoutDir,
637
642
  });
643
+ // tp-06 (ADR-0014) — the Team preview forwarder. Started here, in the
644
+ // container branch only: the local bridge never opens it. It is also a
645
+ // no-op without a `fly-local-6pn` entry, and stays off until
646
+ // HT_PREVIEW_GATEWAY names the gateway. start() never rejects.
647
+ void (0, previewForwarder_1.buildPreviewForwarder)({ readHosts: () => fs.readFileSync('/etc/hosts', 'utf-8') }).start();
648
+ // tp-05 (ADR-0014) — the Team preview checkout: main, in its own clones
649
+ // under /data/previews/<workspaceId>, with the owner's working-copy
650
+ // .env, served on 127.0.0.1:<preview port> (the port the forwarder
651
+ // above targets). Container branch only; the local bridge's relay
652
+ // client answers every preview frame `unsupported / local_lane`.
653
+ const previewRunner = new previewCheckout_1.PreviewRunner({
654
+ previewsBaseDir: process.env.WENRWA_PREVIEWS_DIR || path.join(path.dirname(reposBaseDir), 'previews'),
655
+ workingCopyDir: (workspaceId) => path.join(reposBaseDir, workspaceId),
656
+ port: (0, previewForwarder_1.resolvePreviewPorts)(process.env).previewPort,
657
+ });
638
658
  // cvt-07: the box's one shared Chromium, created lazily by the first tab.
639
659
  let browserHost;
640
660
  (0, relayClient_1.startRelayClient)({
@@ -781,6 +801,8 @@ exports.bridgeCommand = new commander_1.Command('bridge')
781
801
  // never created. Deliberately the identical closure, not a second
782
802
  // wiring: see its doc comment above.
783
803
  ensureCheckout: ensureWorkspaceCheckout,
804
+ // tp-05 — preview-start/stop/update/logs (previewFrames.ts).
805
+ preview: previewRunner,
784
806
  // pucc-int-04 (ADR-0032): install a forged crew `.claude` bundle into the
785
807
  // workspace checkout under the same /data/repos/<workspaceId> root. Pure
786
808
  // file writes (path-safe + idempotent) — Claude Code orchestrates the
@@ -909,6 +931,10 @@ exports.bridgeCommand = new commander_1.Command('bridge')
909
931
  // straight to the SAME pure claudeTranscriptReader.ts that derives
910
932
  // the path exactly as autolaunch.sh names it (psp-01: agentId ==
911
933
  // the .jsonl filename).
934
+ // tp-02 (docs/prd/team-preview.md story 39): the Keys list — the
935
+ // NAMES in /data/repos/<workspaceId>/.env, never a value
936
+ // (envNames.ts). Same root derivation + unsafe-id refusal as readFile.
937
+ resolveEnvNamesRoot: (workspaceId) => (0, bundleInstaller_1.isSafeWorkspaceId)(workspaceId) ? path.posix.resolve(reposBaseDir, workspaceId) : null,
912
938
  readTranscript: ({ workspaceId, agentId, engine, opencodeSessionId }) => (0, claudeTranscriptReader_1.readAgentTranscript)(reposBaseDir, workspaceId, agentId, {
913
939
  engine,
914
940
  opencodeSessionId,
@@ -990,6 +1016,8 @@ exports.bridgeCommand = new commander_1.Command('bridge')
990
1016
  return;
991
1017
  }
992
1018
  // ---- local mode (byte-identical to pre-ht-05 behavior) ----
1019
+ // tp-06: no Team preview forwarder here, by design (ADR-0014 scopes the
1020
+ // local lane out; a laptop must not be opened to outside traffic).
993
1021
  // 1. Connect Token: flag on first run, config thereafter.
994
1022
  if (opts.token) {
995
1023
  if (!opts.token.startsWith('wm_ct_')) {
@@ -1206,6 +1234,9 @@ exports.bridgeCommand = new commander_1.Command('bridge')
1206
1234
  const entry = (0, folderRegistry_1.findEntryByWorkspaceId)((0, folderRegistry_1.loadFolderRegistry)(), workspaceId);
1207
1235
  return entry?.path ?? null;
1208
1236
  },
1237
+ // tp-02 — GET /local-env-names/:workspaceId: the registered folder's
1238
+ // `.env` NAMES for the Keys list (values never leave envNames.ts).
1239
+ resolveEnvNamesRoot: (workspaceId) => (0, folderRegistry_1.findEntryByWorkspaceId)((0, folderRegistry_1.loadFolderRegistry)(), workspaceId)?.path ?? null,
1209
1240
  // lws-08 (PRD D9) — a context-manifest frame writes ONLY
1210
1241
  // `.hiveop/context.md` under the resolved local workspace's project
1211
1242
  // root; unknown workspaceId → null (server.ts errors the frame).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wenrwa/marketplace-cli",
3
- "version": "0.8.7",
3
+ "version": "0.8.9",
4
4
  "description": "CLI tool for the Wenrwa Agent Marketplace — monitor bounties, agents, workspaces, and treasury from your terminal",
5
5
  "author": "Wenrwa <dev@wenrwa.com>",
6
6
  "license": "MIT",