roughbook 0.0.0-stage → 0.1.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 (144) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +166 -2
  3. package/dist/agents/claude.js +214 -0
  4. package/dist/agents/claude.js.map +1 -0
  5. package/dist/agents/codex.js +179 -0
  6. package/dist/agents/codex.js.map +1 -0
  7. package/dist/agents/command.js +47 -0
  8. package/dist/agents/command.js.map +1 -0
  9. package/dist/agents/index.js +21 -0
  10. package/dist/agents/index.js.map +1 -0
  11. package/dist/agents/process.js +76 -0
  12. package/dist/agents/process.js.map +1 -0
  13. package/dist/agents/session.js +26 -0
  14. package/dist/agents/session.js.map +1 -0
  15. package/dist/agents/types.js +2 -0
  16. package/dist/agents/types.js.map +1 -0
  17. package/dist/api/client.js +138 -0
  18. package/dist/api/client.js.map +1 -0
  19. package/dist/api/errors.js +40 -0
  20. package/dist/api/errors.js.map +1 -0
  21. package/dist/api/outbox.js +105 -0
  22. package/dist/api/outbox.js.map +1 -0
  23. package/dist/api/types.js +4 -0
  24. package/dist/api/types.js.map +1 -0
  25. package/dist/cli.js +10 -0
  26. package/dist/cli.js.map +1 -0
  27. package/dist/commands/agents.js +39 -0
  28. package/dist/commands/agents.js.map +1 -0
  29. package/dist/commands/context.js +27 -0
  30. package/dist/commands/context.js.map +1 -0
  31. package/dist/commands/done.js +125 -0
  32. package/dist/commands/done.js.map +1 -0
  33. package/dist/commands/index.js +101 -0
  34. package/dist/commands/index.js.map +1 -0
  35. package/dist/commands/init.js +203 -0
  36. package/dist/commands/init.js.map +1 -0
  37. package/dist/commands/login.js +93 -0
  38. package/dist/commands/login.js.map +1 -0
  39. package/dist/commands/logout.js +34 -0
  40. package/dist/commands/logout.js.map +1 -0
  41. package/dist/commands/promote.js +105 -0
  42. package/dist/commands/promote.js.map +1 -0
  43. package/dist/commands/pull.js +45 -0
  44. package/dist/commands/pull.js.map +1 -0
  45. package/dist/commands/revert.js +39 -0
  46. package/dist/commands/revert.js.map +1 -0
  47. package/dist/commands/review.js +73 -0
  48. package/dist/commands/review.js.map +1 -0
  49. package/dist/commands/run.js +147 -0
  50. package/dist/commands/run.js.map +1 -0
  51. package/dist/commands/shared.js +81 -0
  52. package/dist/commands/shared.js.map +1 -0
  53. package/dist/commands/start.js +119 -0
  54. package/dist/commands/start.js.map +1 -0
  55. package/dist/commands/status.js +62 -0
  56. package/dist/commands/status.js.map +1 -0
  57. package/dist/config/credentials.js +17 -0
  58. package/dist/config/credentials.js.map +1 -0
  59. package/dist/config/server.js +29 -0
  60. package/dist/config/server.js.map +1 -0
  61. package/dist/config/settings.js +21 -0
  62. package/dist/config/settings.js.map +1 -0
  63. package/dist/config/userDir.js +18 -0
  64. package/dist/config/userDir.js.map +1 -0
  65. package/dist/fs/json.js +44 -0
  66. package/dist/fs/json.js.map +1 -0
  67. package/dist/fs/lock.js +38 -0
  68. package/dist/fs/lock.js.map +1 -0
  69. package/dist/io.js +26 -0
  70. package/dist/io.js.map +1 -0
  71. package/dist/launch/open.js +48 -0
  72. package/dist/launch/open.js.map +1 -0
  73. package/dist/launch/platform.js +38 -0
  74. package/dist/launch/platform.js.map +1 -0
  75. package/dist/launch/pty.js +61 -0
  76. package/dist/launch/pty.js.map +1 -0
  77. package/dist/launch/terminal.js +194 -0
  78. package/dist/launch/terminal.js.map +1 -0
  79. package/dist/launch/which.js +59 -0
  80. package/dist/launch/which.js.map +1 -0
  81. package/dist/repo/diff.js +26 -0
  82. package/dist/repo/diff.js.map +1 -0
  83. package/dist/repo/framework.js +41 -0
  84. package/dist/repo/framework.js.map +1 -0
  85. package/dist/repo/link.js +28 -0
  86. package/dist/repo/link.js.map +1 -0
  87. package/dist/repo/prep.js +447 -0
  88. package/dist/repo/prep.js.map +1 -0
  89. package/dist/repo/preview.js +144 -0
  90. package/dist/repo/preview.js.map +1 -0
  91. package/dist/repo/root.js +48 -0
  92. package/dist/repo/root.js.map +1 -0
  93. package/dist/repo/scratch.js +111 -0
  94. package/dist/repo/scratch.js.map +1 -0
  95. package/dist/runs/checks.js +160 -0
  96. package/dist/runs/checks.js.map +1 -0
  97. package/dist/runs/lifecycle.js +142 -0
  98. package/dist/runs/lifecycle.js.map +1 -0
  99. package/dist/runs/promote.js +185 -0
  100. package/dist/runs/promote.js.map +1 -0
  101. package/dist/runs/pull.js +182 -0
  102. package/dist/runs/pull.js.map +1 -0
  103. package/dist/runs/reviews.js +34 -0
  104. package/dist/runs/reviews.js.map +1 -0
  105. package/dist/runs/slots.js +96 -0
  106. package/dist/runs/slots.js.map +1 -0
  107. package/dist/runs/snapshot.js +265 -0
  108. package/dist/runs/snapshot.js.map +1 -0
  109. package/dist/runs/store.js +38 -0
  110. package/dist/runs/store.js.map +1 -0
  111. package/dist/runs/types.js +3 -0
  112. package/dist/runs/types.js.map +1 -0
  113. package/dist/runs/watch.js +42 -0
  114. package/dist/runs/watch.js.map +1 -0
  115. package/dist/screenshot/browser.js +163 -0
  116. package/dist/screenshot/browser.js.map +1 -0
  117. package/dist/screenshot/iteration.js +37 -0
  118. package/dist/screenshot/iteration.js.map +1 -0
  119. package/dist/server/app.js +321 -0
  120. package/dist/server/app.js.map +1 -0
  121. package/dist/server/security.js +44 -0
  122. package/dist/server/security.js.map +1 -0
  123. package/dist/server/studio.js +618 -0
  124. package/dist/server/studio.js.map +1 -0
  125. package/dist/server/terminals.js +142 -0
  126. package/dist/server/terminals.js.map +1 -0
  127. package/dist/ui/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  128. package/dist/ui/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  129. package/dist/ui/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
  130. package/dist/ui/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
  131. package/dist/ui/assets/index-D-TSXfvz.css +1 -0
  132. package/dist/ui/assets/index-HGV8FKwI.js +27 -0
  133. package/dist/ui/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
  134. package/dist/ui/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
  135. package/dist/ui/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
  136. package/dist/ui/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
  137. package/dist/ui/assets/space-grotesk-latin-400-normal-BnQMeOim.woff +0 -0
  138. package/dist/ui/assets/space-grotesk-latin-400-normal-CJ-V5oYT.woff2 +0 -0
  139. package/dist/ui/assets/space-grotesk-latin-500-normal-CNSSEhBt.woff +0 -0
  140. package/dist/ui/assets/space-grotesk-latin-500-normal-lFbtlQH6.woff2 +0 -0
  141. package/dist/ui/index.html +14 -0
  142. package/dist/version.js +4 -0
  143. package/dist/version.js.map +1 -0
  144. package/package.json +68 -4
@@ -0,0 +1,105 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { readJson, writeJsonAtomic } from '../fs/json.js';
3
+ import { statePath } from '../repo/root.js';
4
+ import { withLock } from '../fs/lock.js';
5
+ import { ApiError, OfflineError } from './errors.js';
6
+ const KEEP_DROPPED = 50;
7
+ /**
8
+ * Reviews and run results go out in the order they were made, even offline: each is written here
9
+ * first and sent when the backend can be reached, with its id as the idempotency key, so one sent
10
+ * twice is applied once.
11
+ */
12
+ export class Outbox {
13
+ file;
14
+ now;
15
+ constructor(file, now = () => new Date()) {
16
+ this.file = file;
17
+ this.now = now;
18
+ }
19
+ async pending() {
20
+ return (await this.read()).entries;
21
+ }
22
+ async dropped() {
23
+ return (await this.read()).dropped;
24
+ }
25
+ /**
26
+ * Queues a POST behind anything already waiting and tries to send the lot. Resolves with the
27
+ * backend's answer when it went out now, or `queued` when it will go later; rejects with the
28
+ * ApiError when the backend refused it.
29
+ */
30
+ async send(api, path, body) {
31
+ const id = randomUUID();
32
+ await withLock(this.file, async () => {
33
+ const state = await this.read();
34
+ state.entries.push({
35
+ id,
36
+ path,
37
+ body,
38
+ queuedAt: this.now().toISOString(),
39
+ attempts: 0,
40
+ lastError: null
41
+ });
42
+ await writeJsonAtomic(this.file, state);
43
+ });
44
+ const result = await this.flush(api);
45
+ if (result.sent.has(id))
46
+ return { status: 'sent', data: result.sent.get(id) };
47
+ const refused = result.dropped.find(entry => entry.id === id);
48
+ if (refused)
49
+ throw new ApiError(refused.code, refused.status);
50
+ return { status: 'queued' };
51
+ }
52
+ /** Sends what is waiting, oldest first, and stops at the first one that cannot go yet. */
53
+ async flush(api) {
54
+ return withLock(this.file, async () => {
55
+ const state = await this.read();
56
+ const sent = new Map();
57
+ const dropped = [];
58
+ const left = [];
59
+ let blocked = false;
60
+ for (const entry of state.entries) {
61
+ if (blocked) {
62
+ left.push(entry);
63
+ continue;
64
+ }
65
+ try {
66
+ sent.set(entry.id, await api.request('POST', entry.path, entry.body, { idempotencyKey: entry.id }));
67
+ }
68
+ catch (error) {
69
+ if (error instanceof ApiError && !error.retryable) {
70
+ dropped.push({
71
+ id: entry.id,
72
+ path: entry.path,
73
+ code: error.code,
74
+ status: error.status,
75
+ droppedAt: this.now().toISOString()
76
+ });
77
+ continue;
78
+ }
79
+ if (!(error instanceof ApiError) && !(error instanceof OfflineError))
80
+ throw error;
81
+ blocked = true;
82
+ left.push({
83
+ ...entry,
84
+ attempts: entry.attempts + 1,
85
+ lastError: error instanceof ApiError ? error.code : 'OFFLINE'
86
+ });
87
+ }
88
+ }
89
+ await writeJsonAtomic(this.file, {
90
+ entries: left,
91
+ dropped: [...state.dropped, ...dropped].slice(-KEEP_DROPPED)
92
+ });
93
+ return { sent, dropped, left: left.length };
94
+ });
95
+ }
96
+ async read() {
97
+ const state = await readJson(this.file);
98
+ return { entries: state?.entries ?? [], dropped: state?.dropped ?? [] };
99
+ }
100
+ }
101
+ /** The repo's outbox, in `rough/.roughbook/`. */
102
+ export function outboxFor(repoRoot) {
103
+ return new Outbox(statePath(repoRoot, 'outbox.json'));
104
+ }
105
+ //# sourceMappingURL=outbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbox.js","sourceRoot":"","sources":["../../src/api/outbox.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ // What the backend's /studio routes answer. Kept by hand beside the backend's validators; the
2
+ // route tests on both sides pin the shapes.
3
+ export {};
4
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/api/types.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,4CAA4C"}
package/dist/cli.js ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import { main } from './commands/index.js';
3
+ import { terminalIo } from './io.js';
4
+ // The only place that reads the working directory: everything below takes the repo root from it.
5
+ process.exitCode = await main(process.argv.slice(2), {
6
+ cwd: process.cwd(),
7
+ env: process.env,
8
+ io: terminalIo()
9
+ });
10
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,iGAAiG;AACjG,OAAO,CAAC,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IACnD,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;IAClB,GAAG,EAAE,OAAO,CAAC,GAAG;IAChB,EAAE,EAAE,UAAU,EAAE;CACjB,CAAC,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { parseArgs } from 'node:util';
2
+ import { ADAPTERS } from '../agents/index.js';
3
+ import { readSettings, saveSettings } from '../config/settings.js';
4
+ import { chooseAgent, sendHeartbeat } from './shared.js';
5
+ export const agents = {
6
+ name: 'agents',
7
+ summary: 'List the coding agents found here, and choose the default',
8
+ usage: 'agents [--default <agent>]',
9
+ needsRepo: false,
10
+ async run(args, context) {
11
+ const { io } = context;
12
+ const { values } = parseArgs({ args, options: { default: { type: 'string' } } });
13
+ if (values.default !== undefined) {
14
+ const { adapter } = await chooseAgent(context, values.default);
15
+ await saveSettings(context.configDir, { defaultAgent: adapter.id });
16
+ io.out(`${adapter.name} is now the default agent.`);
17
+ io.out('');
18
+ }
19
+ const settings = await readSettings(context.configDir);
20
+ const detections = await Promise.all(ADAPTERS.map(adapter => context.detect(adapter)));
21
+ for (const detection of detections) {
22
+ const mark = detection.id === settings.defaultAgent ? '*' : ' ';
23
+ if (!detection.found) {
24
+ io.out(`${mark} ${detection.name} (${detection.id}): not found`);
25
+ continue;
26
+ }
27
+ io.out(`${mark} ${detection.name} (${detection.id}): ${detection.version ?? 'version unknown'}, from ${detection.executable?.source ?? 'unknown'}`);
28
+ io.out(` Signed in: ${detection.signIn ?? 'it does not say'}`);
29
+ io.out(` Unattended: ${detection.headless.ready ? 'ready (roughbook run --headless)' : detection.headless.reason}`);
30
+ }
31
+ if (!settings.defaultAgent) {
32
+ io.out('');
33
+ io.out('No default yet: roughbook run uses the first one found. Set one with --default.');
34
+ }
35
+ await sendHeartbeat(context, detections);
36
+ return 0;
37
+ }
38
+ };
39
+ //# sourceMappingURL=agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/commands/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAEnE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEzD,MAAM,CAAC,MAAM,MAAM,GAAY;IAC7B,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,2DAA2D;IACpE,KAAK,EAAE,4BAA4B;IACnC,SAAS,EAAE,KAAK;IAChB,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO;QACrB,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC;QACvB,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;QACjF,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YACjC,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YAC/D,MAAM,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;YACpE,EAAE,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,4BAA4B,CAAC,CAAC;YACpD,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACb,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACvD,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACvF,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,SAAS,CAAC,EAAE,KAAK,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;YAChE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;gBACrB,EAAE,CAAC,GAAG,CAAC,GAAG,IAAI,IAAI,SAAS,CAAC,IAAI,KAAK,SAAS,CAAC,EAAE,cAAc,CAAC,CAAC;gBACjE,SAAS;YACX,CAAC;YACD,EAAE,CAAC,GAAG,CACJ,GAAG,IAAI,IAAI,SAAS,CAAC,IAAI,KAAK,SAAS,CAAC,EAAE,MAAM,SAAS,CAAC,OAAO,IAAI,iBAAiB,UAAU,SAAS,CAAC,UAAU,EAAE,MAAM,IAAI,SAAS,EAAE,CAC5I,CAAC;YACF,EAAE,CAAC,GAAG,CAAC,mBAAmB,SAAS,CAAC,MAAM,IAAI,iBAAiB,EAAE,CAAC,CAAC;YACnE,EAAE,CAAC,GAAG,CACJ,mBAAmB,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,CAC/G,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;YAC3B,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACX,EAAE,CAAC,GAAG,CAAC,iFAAiF,CAAC,CAAC;QAC5F,CAAC;QACD,MAAM,aAAa,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QACzC,OAAO,CAAC,CAAC;IACX,CAAC;CACF,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { StudioApi } from '../api/client.js';
2
+ import { readCredentials } from '../config/credentials.js';
3
+ import { resolveServer } from '../config/server.js';
4
+ import { currentOs } from '../launch/platform.js';
5
+ import { STUDIO_VERSION } from '../version.js';
6
+ /** `roughbook-studio/0.1.0 (windows)`: the version and OS, nothing about the machine or repo. */
7
+ export function userAgent() {
8
+ return `roughbook-studio/${STUDIO_VERSION} (${currentOs()})`;
9
+ }
10
+ /** A client for the saved sign-in, or a signed-out one for the server to sign in to. */
11
+ export async function openApi(context, serverFlag) {
12
+ const credentials = await readCredentials(context.configDir);
13
+ const server = resolveServer(serverFlag, context.env, credentials?.server);
14
+ const token = credentials && credentials.server === server ? credentials.token : null;
15
+ return {
16
+ api: new StudioApi({ server, token, userAgent: userAgent(), fetch: context.fetch }),
17
+ credentials: token ? credentials : null
18
+ };
19
+ }
20
+ /** The signed-in client, or an error telling the designer to sign in. */
21
+ export async function requireApi(context) {
22
+ const { api } = await openApi(context);
23
+ if (!api.signedIn)
24
+ throw new Error('Not signed in. Run roughbook login first.');
25
+ return api;
26
+ }
27
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/commands/context.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAoB,MAAM,0BAA0B,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGlD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAqC/C,iGAAiG;AACjG,MAAM,UAAU,SAAS;IACvB,OAAO,oBAAoB,cAAc,KAAK,SAAS,EAAE,GAAG,CAAC;AAC/D,CAAC;AAED,wFAAwF;AACxF,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,OAAuB,EACvB,UAAmB;IAEnB,MAAM,WAAW,GAAG,MAAM,eAAe,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,aAAa,CAAC,UAAU,EAAE,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;IAC3E,MAAM,KAAK,GAAG,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACtF,OAAO;QACL,GAAG,EAAE,IAAI,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;QACnF,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI;KACxC,CAAC;AACJ,CAAC;AAED,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAuB;IACtD,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,IAAI,CAAC,GAAG,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAChF,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,125 @@
1
+ import { parseArgs } from 'node:util';
2
+ import { outboxFor } from '../api/outbox.js';
3
+ import { requireRepoLink } from '../repo/link.js';
4
+ import { finishRun } from '../runs/lifecycle.js';
5
+ import { listRuns } from '../runs/store.js';
6
+ import { requireApi } from './context.js';
7
+ /** Where the app's dev server runs when nothing says otherwise. */
8
+ export const DEFAULT_DEV_URL = 'http://localhost:3000';
9
+ export function devUrl(flag, env) {
10
+ const url = (flag ?? env.ROUGHBOOK_DEV_URL ?? DEFAULT_DEV_URL).replace(/\/+$/, '');
11
+ if (!/^https?:\/\/(localhost|127\.0\.0\.1|\[::1\])(:\d{2,5})?$/.test(url)) {
12
+ throw new Error(`The dev server must be on this machine, such as ${DEFAULT_DEV_URL}.`);
13
+ }
14
+ return url;
15
+ }
16
+ /** Finishes one run and, when it made something to look at, takes its screenshots. */
17
+ export async function finishWithScreenshots(context, api, outbox, link, runId, options) {
18
+ const repoRoot = context.repoRoot;
19
+ const run = await finishRun(repoRoot, api, outbox, link, runId, options);
20
+ if (!options.screenshots || run.failure || run.outcome === 'cancelled')
21
+ return { run, shots: null };
22
+ const shots = await context.screenshot(repoRoot, options.devUrl, { page: run.page, component: run.component, iteration: run.iteration }, context.env);
23
+ return { run, shots };
24
+ }
25
+ /** Finishes one run, takes its screenshots, and says how it went. */
26
+ export async function completeRun(context, api, outbox, link, run, options) {
27
+ const { io } = context;
28
+ const { run: finished, shots } = await finishWithScreenshots(context, api, outbox, link, run.runId, options);
29
+ const label = `${finished.page}/${finished.component}/${finished.iteration}`;
30
+ // The warnings are counted beside it, so completed_with_warnings reads as completed.
31
+ const outcome = (finished.outcome ?? 'completed').replace('_with_warnings', '');
32
+ const count = finished.warnings.length;
33
+ io.out(`${label}: ${outcome}${count ? `, ${count} warning${count === 1 ? '' : 's'}` : ''}`);
34
+ if (finished.failure)
35
+ io.out(` x ${finished.failure.message}`);
36
+ for (const warning of finished.warnings)
37
+ io.out(` ! ${warning.message}`);
38
+ if (finished.outOfScope.length) {
39
+ io.out(' Changed outside the iteration; put each back with roughbook revert:');
40
+ for (const file of finished.outOfScope) {
41
+ io.out(` roughbook revert ${label} ${file}`);
42
+ }
43
+ }
44
+ if (shots) {
45
+ const files = Object.values(shots.files);
46
+ if (files.length)
47
+ io.out(` Screenshots: ${files.join(', ')}`);
48
+ if (shots.warning)
49
+ io.out(` ${shots.warning}`);
50
+ }
51
+ if (finished.reported === 'queued') {
52
+ io.out(' The result waits in the outbox and goes to the server when it can be reached.');
53
+ }
54
+ return finished;
55
+ }
56
+ /** Runs still open, matched by run id (or its first eight characters) or by iteration. */
57
+ function pick(open, name) {
58
+ return open.filter(run => run.runId === name ||
59
+ (name.length >= 8 && run.runId.startsWith(name)) ||
60
+ run.iteration === name ||
61
+ `${run.page}/${run.component}/${run.iteration}` === name);
62
+ }
63
+ export const done = {
64
+ name: 'done',
65
+ summary: 'Finish a run: check its iteration, take screenshots, report it',
66
+ usage: 'done [<run or iteration>] [--all] [--failed | --cancelled] [--dev-url <url>]',
67
+ needsRepo: true,
68
+ async run(args, context) {
69
+ const { io } = context;
70
+ const { values, positionals } = parseArgs({
71
+ args,
72
+ allowPositionals: true,
73
+ options: {
74
+ all: { type: 'boolean', default: false },
75
+ failed: { type: 'boolean', default: false },
76
+ cancelled: { type: 'boolean', default: false },
77
+ 'dev-url': { type: 'string' },
78
+ 'no-screenshots': { type: 'boolean', default: false }
79
+ }
80
+ });
81
+ if (values.failed && values.cancelled)
82
+ throw new Error('Choose --failed or --cancelled.');
83
+ const repoRoot = context.repoRoot;
84
+ const open = (await listRuns(repoRoot)).filter(run => run.status === 'started');
85
+ if (!open.length) {
86
+ io.out('No run is open in this repo.');
87
+ return 0;
88
+ }
89
+ let runs;
90
+ if (positionals[0]) {
91
+ runs = pick(open, positionals[0]);
92
+ if (!runs.length)
93
+ throw new Error(`No open run matches ${positionals[0]}.`);
94
+ if (runs.length > 1) {
95
+ throw new Error(`${positionals[0]} matches ${runs.length} open runs; name one by its page and component.`);
96
+ }
97
+ }
98
+ else if (values.all || open.length === 1) {
99
+ runs = open;
100
+ }
101
+ else {
102
+ io.out('Several runs are open:');
103
+ for (const run of open) {
104
+ io.out(` ${run.page}/${run.component}/${run.iteration} (${run.agent}, ${run.runId})`);
105
+ }
106
+ throw new Error('Name one, or pass --all to finish them all.');
107
+ }
108
+ const api = await requireApi(context);
109
+ const link = await requireRepoLink(repoRoot);
110
+ const outbox = outboxFor(repoRoot);
111
+ const url = devUrl(values['dev-url'], context.env);
112
+ let failed = false;
113
+ for (const run of runs) {
114
+ const finished = await completeRun(context, api, outbox, link, run, {
115
+ outcome: values.failed ? 'failed' : values.cancelled ? 'cancelled' : undefined,
116
+ devUrl: url,
117
+ screenshots: !values['no-screenshots']
118
+ });
119
+ // A run the designer marked failed is not the command failing.
120
+ failed ||= finished.outcome === 'failed' && !values.failed;
121
+ }
122
+ return failed ? 1 : 0;
123
+ }
124
+ };
125
+ //# sourceMappingURL=done.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"done.js","sourceRoot":"","sources":["../../src/commands/done.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ import { hostLookup } from '../agents/index.js';
2
+ import { runHeadless } from '../agents/process.js';
3
+ import { describeError } from '../api/errors.js';
4
+ import { userConfigDir } from '../config/userDir.js';
5
+ import { openUrl } from '../launch/open.js';
6
+ import { hostPlatform } from '../launch/platform.js';
7
+ import { launchTerminal } from '../launch/terminal.js';
8
+ import { screenshotIteration } from '../screenshot/iteration.js';
9
+ import { findRepoRoot } from '../repo/root.js';
10
+ import { STUDIO_VERSION } from '../version.js';
11
+ import { agents } from './agents.js';
12
+ import { done } from './done.js';
13
+ import { init } from './init.js';
14
+ import { login } from './login.js';
15
+ import { logout } from './logout.js';
16
+ import { promote } from './promote.js';
17
+ import { pull } from './pull.js';
18
+ import { revert } from './revert.js';
19
+ import { review } from './review.js';
20
+ import { run } from './run.js';
21
+ import { start } from './start.js';
22
+ import { status } from './status.js';
23
+ /** Every command, in the order `roughbook help` lists them. */
24
+ export const COMMANDS = [
25
+ login,
26
+ init,
27
+ start,
28
+ run,
29
+ done,
30
+ review,
31
+ revert,
32
+ pull,
33
+ promote,
34
+ agents,
35
+ status,
36
+ logout
37
+ ];
38
+ function printHelp(io) {
39
+ io.out(`Roughbook studio ${STUDIO_VERSION}`);
40
+ io.out('');
41
+ io.out('Usage: roughbook <command> [options]');
42
+ io.out('');
43
+ const width = Math.max(0, ...COMMANDS.map(command => command.usage.length));
44
+ for (const command of COMMANDS)
45
+ io.out(` ${command.usage.padEnd(width)} ${command.summary}`);
46
+ io.out(` ${'help'.padEnd(width)} Show this list`);
47
+ io.out(` ${'--version'.padEnd(width)} Show the studio's version`);
48
+ }
49
+ /** Until Ctrl+C, or the terminal closing. */
50
+ function untilSignalled() {
51
+ return new Promise(resolve => {
52
+ process.once('SIGINT', () => resolve());
53
+ process.once('SIGTERM', () => resolve());
54
+ });
55
+ }
56
+ /** Runs one command line and returns the exit code: 0 done, 1 failed, 2 not understood. */
57
+ export async function main(argv, options) {
58
+ const { io } = options;
59
+ const [name, ...args] = argv;
60
+ if (!name || name === 'help' || name === '--help' || name === '-h') {
61
+ printHelp(io);
62
+ return 0;
63
+ }
64
+ if (name === '--version' || name === '-v' || name === 'version') {
65
+ io.out(STUDIO_VERSION);
66
+ return 0;
67
+ }
68
+ const command = COMMANDS.find(item => item.name === name);
69
+ if (!command) {
70
+ io.err(`Unknown command: ${name}. Run roughbook help for the list.`);
71
+ return 2;
72
+ }
73
+ const context = {
74
+ io,
75
+ cwd: options.cwd,
76
+ env: options.env,
77
+ repoRoot: findRepoRoot(options.cwd),
78
+ configDir: userConfigDir(options.env),
79
+ fetch: options.fetch,
80
+ sleep: options.sleep ?? (ms => new Promise(resolve => setTimeout(resolve, ms))),
81
+ openUrl: options.openUrl ?? openUrl,
82
+ platform: options.platform ?? hostPlatform(),
83
+ detect: options.detect ?? (adapter => adapter.detect(hostLookup(options.env))),
84
+ launchTerminal: options.launchTerminal ?? launchTerminal,
85
+ runHeadless: options.runHeadless ?? runHeadless,
86
+ screenshot: options.screenshot ?? screenshotIteration,
87
+ waitForStop: options.waitForStop ?? untilSignalled
88
+ };
89
+ if (command.needsRepo && !context.repoRoot) {
90
+ io.err('This folder is not in a Roughbook repo. Run roughbook init in the repo first.');
91
+ return 1;
92
+ }
93
+ try {
94
+ return await command.run(args, context);
95
+ }
96
+ catch (error) {
97
+ io.err(describeError(error));
98
+ return 1;
99
+ }
100
+ }
101
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"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"}