@h-rig/cli 0.0.6-alpha.13 → 0.0.6-alpha.15

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.
@@ -1,6 +1,5 @@
1
1
  // @bun
2
2
  // packages/cli/src/commands/_server-client.ts
3
- import { spawnSync } from "child_process";
4
3
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
5
4
  import { resolve as resolve2 } from "path";
6
5
 
@@ -99,13 +98,14 @@ function resolveSelectedConnection(projectRoot, options = {}) {
99
98
  }
100
99
 
101
100
  // packages/cli/src/commands/_server-client.ts
102
- var cachedGitHubBearerToken;
101
+ var scopedGitHubBearerTokens = new Map;
103
102
  function cleanToken(value) {
104
103
  const trimmed = value?.trim();
105
104
  return trimmed ? trimmed : null;
106
105
  }
107
- function setGitHubBearerTokenForCurrentProcess(token) {
108
- cachedGitHubBearerToken = cleanToken(token ?? undefined);
106
+ function setGitHubBearerTokenForCurrentProcess(token, projectRoot) {
107
+ const scopedKey = resolve2(projectRoot ?? process.cwd());
108
+ scopedGitHubBearerTokens.set(scopedKey, cleanToken(token ?? undefined));
109
109
  }
110
110
  function readPrivateRemoteSessionToken(projectRoot) {
111
111
  const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
@@ -119,25 +119,13 @@ function readPrivateRemoteSessionToken(projectRoot) {
119
119
  }
120
120
  }
121
121
  function readGitHubBearerTokenForRemote(projectRoot) {
122
- if (cachedGitHubBearerToken !== undefined)
123
- return cachedGitHubBearerToken;
122
+ const scopedKey = resolve2(projectRoot);
123
+ if (scopedGitHubBearerTokens.has(scopedKey))
124
+ return scopedGitHubBearerTokens.get(scopedKey) ?? null;
124
125
  const privateSession = readPrivateRemoteSessionToken(projectRoot);
125
- if (privateSession) {
126
- cachedGitHubBearerToken = privateSession;
127
- return cachedGitHubBearerToken;
128
- }
129
- const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
130
- if (envToken) {
131
- cachedGitHubBearerToken = envToken;
132
- return cachedGitHubBearerToken;
133
- }
134
- const result = spawnSync("gh", ["auth", "token"], {
135
- encoding: "utf8",
136
- timeout: 5000,
137
- stdio: ["ignore", "pipe", "ignore"]
138
- });
139
- cachedGitHubBearerToken = result.status === 0 ? cleanToken(result.stdout) : null;
140
- return cachedGitHubBearerToken;
126
+ if (privateSession)
127
+ return privateSession;
128
+ return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
141
129
  }
142
130
  async function ensureServerForCli(projectRoot) {
143
131
  try {
@@ -335,6 +323,37 @@ async function getRunLogsViaServer(context, runId, options = {}) {
335
323
  const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
336
324
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { entries: [] };
337
325
  }
326
+ async function getRunTimelineViaServer(context, runId, options = {}) {
327
+ const url = new URL(`http://rig.local/api/runs/${encodeURIComponent(runId)}/timeline`);
328
+ if (options.limit !== undefined)
329
+ url.searchParams.set("limit", String(options.limit));
330
+ if (options.cursor)
331
+ url.searchParams.set("cursor", options.cursor);
332
+ const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
333
+ return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { entries: [] };
334
+ }
335
+ async function ensureTaskLabelsViaServer(context) {
336
+ const payload = await requestServerJson(context, "/api/workspace/task-labels", { method: "POST" });
337
+ return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
338
+ }
339
+ async function listGitHubProjectsViaServer(context, owner) {
340
+ const url = new URL("http://rig.local/api/github/projects");
341
+ url.searchParams.set("owner", owner);
342
+ const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
343
+ return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { projects: [] };
344
+ }
345
+ async function getGitHubProjectStatusFieldViaServer(context, projectId) {
346
+ const payload = await requestServerJson(context, `/api/github/projects/${encodeURIComponent(projectId)}/status-field`);
347
+ return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
348
+ }
349
+ async function updateWorkspaceTaskViaServer(context, input) {
350
+ const payload = await requestServerJson(context, "/api/tasks/update", {
351
+ method: "POST",
352
+ headers: { "content-type": "application/json" },
353
+ body: JSON.stringify(input)
354
+ });
355
+ return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { ok: true };
356
+ }
338
357
  async function stopRunViaServer(context, runId) {
339
358
  const payload = await requestServerJson(context, "/api/runs/stop", {
340
359
  method: "POST",
@@ -383,6 +402,7 @@ async function submitTaskRunViaServer(context, input) {
383
402
  return { runId };
384
403
  }
385
404
  export {
405
+ updateWorkspaceTaskViaServer,
386
406
  switchServerProjectRootViaServer,
387
407
  submitTaskRunViaServer,
388
408
  stopRunViaServer,
@@ -394,9 +414,13 @@ export {
394
414
  prepareRemoteCheckoutViaServer,
395
415
  postGitHubTokenViaServer,
396
416
  listWorkspaceTasksViaServer,
417
+ listGitHubProjectsViaServer,
397
418
  getWorkspaceTaskViaServer,
419
+ getRunTimelineViaServer,
398
420
  getRunLogsViaServer,
399
421
  getRunDetailsViaServer,
422
+ getGitHubProjectStatusFieldViaServer,
400
423
  getGitHubAuthStatusViaServer,
424
+ ensureTaskLabelsViaServer,
401
425
  ensureServerForCli
402
426
  };
@@ -4,7 +4,6 @@ import { mkdir, readdir, readFile, writeFile } from "fs/promises";
4
4
  import { dirname as dirname2, resolve as resolve3, relative, sep } from "path";
5
5
 
6
6
  // packages/cli/src/commands/_server-client.ts
7
- import { spawnSync } from "child_process";
8
7
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
9
8
  import { resolve as resolve2 } from "path";
10
9
 
@@ -103,7 +102,7 @@ function resolveSelectedConnection(projectRoot, options = {}) {
103
102
  }
104
103
 
105
104
  // packages/cli/src/commands/_server-client.ts
106
- var cachedGitHubBearerToken;
105
+ var scopedGitHubBearerTokens = new Map;
107
106
  function cleanToken(value) {
108
107
  const trimmed = value?.trim();
109
108
  return trimmed ? trimmed : null;
@@ -120,25 +119,13 @@ function readPrivateRemoteSessionToken(projectRoot) {
120
119
  }
121
120
  }
122
121
  function readGitHubBearerTokenForRemote(projectRoot) {
123
- if (cachedGitHubBearerToken !== undefined)
124
- return cachedGitHubBearerToken;
122
+ const scopedKey = resolve2(projectRoot);
123
+ if (scopedGitHubBearerTokens.has(scopedKey))
124
+ return scopedGitHubBearerTokens.get(scopedKey) ?? null;
125
125
  const privateSession = readPrivateRemoteSessionToken(projectRoot);
126
- if (privateSession) {
127
- cachedGitHubBearerToken = privateSession;
128
- return cachedGitHubBearerToken;
129
- }
130
- const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
131
- if (envToken) {
132
- cachedGitHubBearerToken = envToken;
133
- return cachedGitHubBearerToken;
134
- }
135
- const result = spawnSync("gh", ["auth", "token"], {
136
- encoding: "utf8",
137
- timeout: 5000,
138
- stdio: ["ignore", "pipe", "ignore"]
139
- });
140
- cachedGitHubBearerToken = result.status === 0 ? cleanToken(result.stdout) : null;
141
- return cachedGitHubBearerToken;
126
+ if (privateSession)
127
+ return privateSession;
128
+ return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
142
129
  }
143
130
  async function ensureServerForCli(projectRoot) {
144
131
  try {
@@ -1,6 +1,6 @@
1
1
  // @bun
2
- // packages/cli/src/commands/_task-picker.ts
3
- import { createInterface } from "readline/promises";
2
+ // packages/cli/src/commands/_operator-surface.ts
3
+ import { createInterface as createPromptInterface } from "readline/promises";
4
4
  function taskId(task) {
5
5
  return typeof task.id === "string" && task.id.trim() ? task.id : "<unknown>";
6
6
  }
@@ -13,6 +13,19 @@ function taskStatus(task) {
13
13
  function renderTaskPickerRows(tasks) {
14
14
  return tasks.map((task, index) => `${index + 1}. ${taskId(task)} \xB7 ${taskStatus(task)} \xB7 ${taskTitle(task)}`);
15
15
  }
16
+ async function promptForTaskSelection(question) {
17
+ const rl = createPromptInterface({ input: process.stdin, output: process.stdout });
18
+ try {
19
+ return await rl.question(question);
20
+ } finally {
21
+ rl.close();
22
+ }
23
+ }
24
+
25
+ // packages/cli/src/commands/_task-picker.ts
26
+ function taskId2(task) {
27
+ return typeof task.id === "string" && task.id.trim() ? task.id : "<unknown>";
28
+ }
16
29
  async function selectTaskWithTextPicker(tasks, io = {}) {
17
30
  if (tasks.length === 0)
18
31
  return null;
@@ -22,17 +35,12 @@ async function selectTaskWithTextPicker(tasks, io = {}) {
22
35
  if (!isTty) {
23
36
  throw new Error("task run requires an interactive terminal to pick a task; pass --task <id>, --next, or --detach with a task id.");
24
37
  }
25
- const prompt = io.prompt ?? (async (question) => {
26
- const rl = createInterface({ input: process.stdin, output: process.stdout });
27
- try {
28
- return await rl.question(question);
29
- } finally {
30
- rl.close();
31
- }
32
- });
33
- console.log("Select Rig task:");
38
+ const prompt = io.prompt ?? promptForTaskSelection;
39
+ const renderer = io.renderer ?? { writeLine: (line) => process.stdout.write(`${line}
40
+ `) };
41
+ renderer.writeLine("Select Rig task:");
34
42
  for (const row of renderTaskPickerRows(tasks))
35
- console.log(` ${row}`);
43
+ renderer.writeLine(` ${row}`);
36
44
  const answer = (await prompt(`Task [1-${tasks.length}] or id: `)).trim();
37
45
  if (!answer)
38
46
  return null;
@@ -40,7 +48,7 @@ async function selectTaskWithTextPicker(tasks, io = {}) {
40
48
  const index = Number.parseInt(answer, 10) - 1;
41
49
  return tasks[index] ?? null;
42
50
  }
43
- return tasks.find((task) => taskId(task) === answer) ?? null;
51
+ return tasks.find((task) => taskId2(task) === answer) ?? null;
44
52
  }
45
53
  export {
46
54
  selectTaskWithTextPicker,
@@ -221,6 +221,7 @@ import { ensureProjectMainFreshBeforeRun } from "@rig/runtime/control-plane/proj
221
221
 
222
222
  // packages/cli/src/commands/_server-client.ts
223
223
  import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
224
+ var scopedGitHubBearerTokens = new Map;
224
225
 
225
226
  // packages/cli/src/commands/_preflight.ts
226
227
  async function runProjectMainSyncPreflight(context, options) {
@@ -104,11 +104,10 @@ function resolveSelectedConnection(projectRoot, options = {}) {
104
104
  }
105
105
 
106
106
  // packages/cli/src/commands/_server-client.ts
107
- import { spawnSync } from "child_process";
108
107
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
109
108
  import { resolve as resolve2 } from "path";
110
109
  import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
111
- var cachedGitHubBearerToken;
110
+ var scopedGitHubBearerTokens = new Map;
112
111
  function cleanToken(value) {
113
112
  const trimmed = value?.trim();
114
113
  return trimmed ? trimmed : null;
@@ -125,25 +124,13 @@ function readPrivateRemoteSessionToken(projectRoot) {
125
124
  }
126
125
  }
127
126
  function readGitHubBearerTokenForRemote(projectRoot) {
128
- if (cachedGitHubBearerToken !== undefined)
129
- return cachedGitHubBearerToken;
127
+ const scopedKey = resolve2(projectRoot);
128
+ if (scopedGitHubBearerTokens.has(scopedKey))
129
+ return scopedGitHubBearerTokens.get(scopedKey) ?? null;
130
130
  const privateSession = readPrivateRemoteSessionToken(projectRoot);
131
- if (privateSession) {
132
- cachedGitHubBearerToken = privateSession;
133
- return cachedGitHubBearerToken;
134
- }
135
- const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
136
- if (envToken) {
137
- cachedGitHubBearerToken = envToken;
138
- return cachedGitHubBearerToken;
139
- }
140
- const result = spawnSync("gh", ["auth", "token"], {
141
- encoding: "utf8",
142
- timeout: 5000,
143
- stdio: ["ignore", "pipe", "ignore"]
144
- });
145
- cachedGitHubBearerToken = result.status === 0 ? cleanToken(result.stdout) : null;
146
- return cachedGitHubBearerToken;
131
+ if (privateSession)
132
+ return privateSession;
133
+ return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
147
134
  }
148
135
  async function ensureServerForCli(projectRoot) {
149
136
  try {
@@ -1,6 +1,6 @@
1
1
  // @bun
2
2
  // packages/cli/src/commands/github.ts
3
- import { spawnSync as spawnSync2 } from "child_process";
3
+ import { spawnSync } from "child_process";
4
4
 
5
5
  // packages/cli/src/runner.ts
6
6
  import { EventBus } from "@rig/runtime/control-plane/runtime/events";
@@ -32,7 +32,6 @@ function takeOption(args, option) {
32
32
  }
33
33
 
34
34
  // packages/cli/src/commands/_server-client.ts
35
- import { spawnSync } from "child_process";
36
35
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
37
36
  import { resolve as resolve2 } from "path";
38
37
  import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
@@ -120,7 +119,7 @@ function resolveSelectedConnection(projectRoot, options = {}) {
120
119
  }
121
120
 
122
121
  // packages/cli/src/commands/_server-client.ts
123
- var cachedGitHubBearerToken;
122
+ var scopedGitHubBearerTokens = new Map;
124
123
  function cleanToken(value) {
125
124
  const trimmed = value?.trim();
126
125
  return trimmed ? trimmed : null;
@@ -137,25 +136,13 @@ function readPrivateRemoteSessionToken(projectRoot) {
137
136
  }
138
137
  }
139
138
  function readGitHubBearerTokenForRemote(projectRoot) {
140
- if (cachedGitHubBearerToken !== undefined)
141
- return cachedGitHubBearerToken;
139
+ const scopedKey = resolve2(projectRoot);
140
+ if (scopedGitHubBearerTokens.has(scopedKey))
141
+ return scopedGitHubBearerTokens.get(scopedKey) ?? null;
142
142
  const privateSession = readPrivateRemoteSessionToken(projectRoot);
143
- if (privateSession) {
144
- cachedGitHubBearerToken = privateSession;
145
- return cachedGitHubBearerToken;
146
- }
147
- const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
148
- if (envToken) {
149
- cachedGitHubBearerToken = envToken;
150
- return cachedGitHubBearerToken;
151
- }
152
- const result = spawnSync("gh", ["auth", "token"], {
153
- encoding: "utf8",
154
- timeout: 5000,
155
- stdio: ["ignore", "pipe", "ignore"]
156
- });
157
- cachedGitHubBearerToken = result.status === 0 ? cleanToken(result.stdout) : null;
158
- return cachedGitHubBearerToken;
143
+ if (privateSession)
144
+ return privateSession;
145
+ return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
159
146
  }
160
147
  async function ensureServerForCli(projectRoot) {
161
148
  try {
@@ -244,7 +231,7 @@ function printPayload(context, payload, fallback) {
244
231
  console.log(fallback);
245
232
  }
246
233
  function readGhToken() {
247
- const result = spawnSync2("gh", ["auth", "token"], { encoding: "utf8" });
234
+ const result = spawnSync("gh", ["auth", "token"], { encoding: "utf8" });
248
235
  if (result.status !== 0) {
249
236
  const detail = result.stderr?.trim() || result.stdout?.trim() || "gh auth token failed";
250
237
  throw new CliError2(`Could not import GitHub token from gh: ${detail}`, 1);