@retasc/cli 1.1.0 → 1.1.1

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/index.js CHANGED
@@ -15,7 +15,7 @@ const program = new Command();
15
15
  program
16
16
  .name("retasc")
17
17
  .description("Retasc — sign in, create projects, mint agent API keys, and wire your agent to the MCP server.")
18
- .version("1.1.0");
18
+ .version("1.1.1");
19
19
  function requireLogin() {
20
20
  if (!isLoggedIn()) {
21
21
  console.error("Not signed in. Run `retasc login` first.");
package/dist/lib/claim.js CHANGED
@@ -4,35 +4,23 @@
4
4
  // ../commands/claim.ts.
5
5
  import { readFileSync, existsSync } from "node:fs";
6
6
  import { join, resolve } from "node:path";
7
+ import { resolveConn } from "./keystore.js";
7
8
  const DEFAULT_MCP_URL = "https://mcp.retasc.com/mcp";
8
9
  /**
9
10
  * Resolve the agent API key + MCP URL the same way the workspace's MCP wiring does,
10
- * so `retasc claim` speaks as the *same agent* the harness already uses. Order:
11
- * explicit env (RETASC_MCP_KEY / RETASC_MCP_URL what the watchdog proxy reads)
12
- * wins, then the workspace `.mcp.json` in both shapes installMcp writes:
13
- * - stdio watchdog: { command, args, env: { RETASC_MCP_URL, RETASC_MCP_KEY } }
14
- * - http direct: { type:"http", url, headers:{ Authorization:"Bearer <key>" } }
15
- * `key` comes back empty if nothing is found, so the caller can error clearly.
11
+ * so `retasc claim` speaks as the *same agent* the harness already uses. Delegates
12
+ * to the shared `resolveConn` (RTSC-98) so it stays in lockstep with the proxy
13
+ * covering explicit env, both legacy `.mcp.json` shapes, AND the canonical
14
+ * secret-free marker (`RETASC_WORKSPACE` home keystore). `key` comes back empty
15
+ * if nothing is found, so the caller can error clearly.
16
16
  */
17
17
  export function resolveMcpConn(opts = {}) {
18
- const env = opts.env ?? process.env;
19
- let url = env.RETASC_MCP_URL || "";
20
- let key = env.RETASC_MCP_KEY || "";
21
- const entry = opts.mcpJson?.mcpServers?.retasc;
22
- if (entry) {
23
- if (!key && typeof entry.env?.RETASC_MCP_KEY === "string")
24
- key = entry.env.RETASC_MCP_KEY;
25
- if (!url && typeof entry.env?.RETASC_MCP_URL === "string")
26
- url = entry.env.RETASC_MCP_URL;
27
- if (!url && typeof entry.url === "string")
28
- url = entry.url;
29
- if (!key && typeof entry.headers?.Authorization === "string") {
30
- const m = entry.headers.Authorization.match(/^Bearer\s+(.+)$/i);
31
- if (m)
32
- key = m[1].trim();
33
- }
34
- }
35
- return { url: url || opts.defaultUrl || DEFAULT_MCP_URL, key };
18
+ const { key, url } = resolveConn({
19
+ env: opts.env,
20
+ mcpEntry: opts.mcpJson?.mcpServers?.retasc,
21
+ defaultUrl: opts.defaultUrl || DEFAULT_MCP_URL,
22
+ });
23
+ return { url: url || DEFAULT_MCP_URL, key };
36
24
  }
37
25
  /** Read & parse the workspace `.mcp.json` (or null if absent/corrupt). */
38
26
  export function readMcpJson(dir = process.cwd()) {
@@ -50,3 +50,44 @@ export function removeBinding(workspaceId) {
50
50
  export function newWorkspaceId() {
51
51
  return `ws_${randomUUID()}`;
52
52
  }
53
+ /**
54
+ * RTSC-98: the ONE place that resolves a workspace's key + MCP url. Shared by the
55
+ * proxy (env-based) and the direct commands `claim`/`tidy`/`done` (.mcp.json-based)
56
+ * so the two paths can never drift again. Precedence: explicit `RETASC_MCP_KEY`
57
+ * env → legacy inline key in the marker (env or Authorization header) → canonical
58
+ * secret-free marker (`RETASC_WORKSPACE` → home keystore). `mcpEntry` is a
59
+ * workspace `.mcp.json`'s `mcpServers.retasc` entry, or undefined when only the
60
+ * environment carries the binding (the spawned proxy).
61
+ */
62
+ export function resolveConn(opts) {
63
+ const env = opts.env ?? process.env;
64
+ const entry = opts.mcpEntry;
65
+ let key = env.RETASC_MCP_KEY || "";
66
+ let url = env.RETASC_MCP_URL || "";
67
+ if (entry) {
68
+ if (!key && typeof entry.env?.RETASC_MCP_KEY === "string")
69
+ key = entry.env.RETASC_MCP_KEY;
70
+ if (!url && typeof entry.env?.RETASC_MCP_URL === "string")
71
+ url = entry.env.RETASC_MCP_URL;
72
+ if (!url && typeof entry.url === "string")
73
+ url = entry.url;
74
+ if (!key && typeof entry.headers?.Authorization === "string") {
75
+ const m = String(entry.headers.Authorization).match(/^Bearer\s+(.+)$/i);
76
+ if (m)
77
+ key = m[1].trim();
78
+ }
79
+ }
80
+ // Canonical (RTSC-92): secret-free marker → workspace id → home keystore.
81
+ if (!key) {
82
+ const wsId = env.RETASC_WORKSPACE || entry?.env?.RETASC_WORKSPACE;
83
+ if (wsId) {
84
+ const b = getBinding(String(wsId));
85
+ if (b) {
86
+ key = b.key;
87
+ if (!url)
88
+ url = b.url;
89
+ }
90
+ }
91
+ }
92
+ return { key, url: url || opts.defaultUrl || "" };
93
+ }
package/dist/proxy.js CHANGED
@@ -8,24 +8,11 @@
8
8
  import { createInterface } from "node:readline";
9
9
  import { hostname } from "node:os";
10
10
  import { applyObservation, heartbeatRequest, isClaimLost, } from "./lib/watchdog.js";
11
- import { getBinding } from "./lib/keystore.js";
12
- // RTSC-92: resolve the workspace key. Canonical path a secret-free marker sets
13
- // RETASC_WORKSPACE; we look the key up in the home keystore (never in the repo).
14
- // Legacy path RETASC_MCP_KEY inlined in an old ./.mcp.json still works.
15
- function resolveKeyUrl() {
16
- const envUrl = process.env.RETASC_MCP_URL || "https://mcp.retasc.com/mcp";
17
- if (process.env.RETASC_MCP_KEY) {
18
- return { key: process.env.RETASC_MCP_KEY, url: envUrl };
19
- }
20
- const wsId = process.env.RETASC_WORKSPACE;
21
- if (wsId) {
22
- const entry = getBinding(wsId);
23
- if (entry)
24
- return { key: entry.key, url: entry.url || envUrl };
25
- }
26
- return { key: "", url: envUrl };
27
- }
28
- const resolved = resolveKeyUrl();
11
+ import { resolveConn } from "./lib/keystore.js";
12
+ // RTSC-92/98: resolve the workspace key via the SHARED resolver, so the proxy and
13
+ // the direct commands (claim/tidy/done) can never diverge. The proxy carries its
14
+ // binding in its own env (RETASC_MCP_KEY legacy, or RETASC_WORKSPACE keystore).
15
+ const resolved = resolveConn({ env: process.env, defaultUrl: "https://mcp.retasc.com/mcp" });
29
16
  let MCP_URL = resolved.url;
30
17
  const KEY = resolved.key;
31
18
  const HEARTBEAT_MS = Number(process.env.RETASC_HEARTBEAT_MS) || 10 * 60 * 1000;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retasc/cli",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Retasc CLI — sign in with GitHub, create projects, mint agent API keys, and wire your agent to the Retasc MCP server in one command.",
5
5
  "type": "module",
6
6
  "bin": {