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.
- package/LICENSE +201 -0
- package/README.md +166 -2
- package/dist/agents/claude.js +214 -0
- package/dist/agents/claude.js.map +1 -0
- package/dist/agents/codex.js +179 -0
- package/dist/agents/codex.js.map +1 -0
- package/dist/agents/command.js +47 -0
- package/dist/agents/command.js.map +1 -0
- package/dist/agents/index.js +21 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/process.js +76 -0
- package/dist/agents/process.js.map +1 -0
- package/dist/agents/session.js +26 -0
- package/dist/agents/session.js.map +1 -0
- package/dist/agents/types.js +2 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/api/client.js +138 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/errors.js +40 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/outbox.js +105 -0
- package/dist/api/outbox.js.map +1 -0
- package/dist/api/types.js +4 -0
- package/dist/api/types.js.map +1 -0
- package/dist/cli.js +10 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/agents.js +39 -0
- package/dist/commands/agents.js.map +1 -0
- package/dist/commands/context.js +27 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/done.js +125 -0
- package/dist/commands/done.js.map +1 -0
- package/dist/commands/index.js +101 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.js +203 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/login.js +93 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.js +34 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/promote.js +105 -0
- package/dist/commands/promote.js.map +1 -0
- package/dist/commands/pull.js +45 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/revert.js +39 -0
- package/dist/commands/revert.js.map +1 -0
- package/dist/commands/review.js +73 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/run.js +147 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/shared.js +81 -0
- package/dist/commands/shared.js.map +1 -0
- package/dist/commands/start.js +119 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.js +62 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/config/credentials.js +17 -0
- package/dist/config/credentials.js.map +1 -0
- package/dist/config/server.js +29 -0
- package/dist/config/server.js.map +1 -0
- package/dist/config/settings.js +21 -0
- package/dist/config/settings.js.map +1 -0
- package/dist/config/userDir.js +18 -0
- package/dist/config/userDir.js.map +1 -0
- package/dist/fs/json.js +44 -0
- package/dist/fs/json.js.map +1 -0
- package/dist/fs/lock.js +38 -0
- package/dist/fs/lock.js.map +1 -0
- package/dist/io.js +26 -0
- package/dist/io.js.map +1 -0
- package/dist/launch/open.js +48 -0
- package/dist/launch/open.js.map +1 -0
- package/dist/launch/platform.js +38 -0
- package/dist/launch/platform.js.map +1 -0
- package/dist/launch/pty.js +61 -0
- package/dist/launch/pty.js.map +1 -0
- package/dist/launch/terminal.js +194 -0
- package/dist/launch/terminal.js.map +1 -0
- package/dist/launch/which.js +59 -0
- package/dist/launch/which.js.map +1 -0
- package/dist/repo/diff.js +26 -0
- package/dist/repo/diff.js.map +1 -0
- package/dist/repo/framework.js +41 -0
- package/dist/repo/framework.js.map +1 -0
- package/dist/repo/link.js +28 -0
- package/dist/repo/link.js.map +1 -0
- package/dist/repo/prep.js +447 -0
- package/dist/repo/prep.js.map +1 -0
- package/dist/repo/preview.js +144 -0
- package/dist/repo/preview.js.map +1 -0
- package/dist/repo/root.js +48 -0
- package/dist/repo/root.js.map +1 -0
- package/dist/repo/scratch.js +111 -0
- package/dist/repo/scratch.js.map +1 -0
- package/dist/runs/checks.js +160 -0
- package/dist/runs/checks.js.map +1 -0
- package/dist/runs/lifecycle.js +142 -0
- package/dist/runs/lifecycle.js.map +1 -0
- package/dist/runs/promote.js +185 -0
- package/dist/runs/promote.js.map +1 -0
- package/dist/runs/pull.js +182 -0
- package/dist/runs/pull.js.map +1 -0
- package/dist/runs/reviews.js +34 -0
- package/dist/runs/reviews.js.map +1 -0
- package/dist/runs/slots.js +96 -0
- package/dist/runs/slots.js.map +1 -0
- package/dist/runs/snapshot.js +265 -0
- package/dist/runs/snapshot.js.map +1 -0
- package/dist/runs/store.js +38 -0
- package/dist/runs/store.js.map +1 -0
- package/dist/runs/types.js +3 -0
- package/dist/runs/types.js.map +1 -0
- package/dist/runs/watch.js +42 -0
- package/dist/runs/watch.js.map +1 -0
- package/dist/screenshot/browser.js +163 -0
- package/dist/screenshot/browser.js.map +1 -0
- package/dist/screenshot/iteration.js +37 -0
- package/dist/screenshot/iteration.js.map +1 -0
- package/dist/server/app.js +321 -0
- package/dist/server/app.js.map +1 -0
- package/dist/server/security.js +44 -0
- package/dist/server/security.js.map +1 -0
- package/dist/server/studio.js +618 -0
- package/dist/server/studio.js.map +1 -0
- package/dist/server/terminals.js +142 -0
- package/dist/server/terminals.js.map +1 -0
- package/dist/ui/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
- package/dist/ui/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- package/dist/ui/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
- package/dist/ui/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
- package/dist/ui/assets/index-D-TSXfvz.css +1 -0
- package/dist/ui/assets/index-HGV8FKwI.js +27 -0
- package/dist/ui/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
- package/dist/ui/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
- package/dist/ui/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
- package/dist/ui/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
- package/dist/ui/assets/space-grotesk-latin-400-normal-BnQMeOim.woff +0 -0
- package/dist/ui/assets/space-grotesk-latin-400-normal-CJ-V5oYT.woff2 +0 -0
- package/dist/ui/assets/space-grotesk-latin-500-normal-CNSSEhBt.woff +0 -0
- package/dist/ui/assets/space-grotesk-latin-500-normal-lFbtlQH6.woff2 +0 -0
- package/dist/ui/index.html +14 -0
- package/dist/version.js +4 -0
- package/dist/version.js.map +1 -0
- package/package.json +68 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/commands/review.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
import { runTarget, terminalSessions } from '../agents/session.js';
|
|
3
|
+
import { outboxFor } from '../api/outbox.js';
|
|
4
|
+
import { manualCommand, planTerminal } from '../launch/terminal.js';
|
|
5
|
+
import { localOrigin, readSettings } from '../config/settings.js';
|
|
6
|
+
import { requireRepoLink } from '../repo/link.js';
|
|
7
|
+
import { startRuns } from '../runs/lifecycle.js';
|
|
8
|
+
import { requireApi } from './context.js';
|
|
9
|
+
import { DEFAULT_DEV_URL, completeRun } from './done.js';
|
|
10
|
+
import { chooseAgent, parseComponent } from './shared.js';
|
|
11
|
+
/** What the designer asked for: new directions, a fork, or a refinement. */
|
|
12
|
+
function runKind(values) {
|
|
13
|
+
const asked = [values.direction?.length, values.fork, values.refine].filter(Boolean).length;
|
|
14
|
+
if (asked !== 1) {
|
|
15
|
+
throw new Error('Say what to run: --direction "<idea>" (up to eight), --fork <iteration>, or --refine <iteration> --intent "<what to change>".');
|
|
16
|
+
}
|
|
17
|
+
if (values.direction?.length) {
|
|
18
|
+
if (values.direction.length > 8)
|
|
19
|
+
throw new Error('At most eight directions at once.');
|
|
20
|
+
return {
|
|
21
|
+
kind: 'generate',
|
|
22
|
+
directions: values.direction.map(direction => ({
|
|
23
|
+
direction,
|
|
24
|
+
...(values.hypothesis ? { hypothesis: values.hypothesis } : {})
|
|
25
|
+
}))
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (values.fork)
|
|
29
|
+
return { kind: 'fork', parent: values.fork };
|
|
30
|
+
if (!values.intent)
|
|
31
|
+
throw new Error('A refinement needs --intent "<what to change>".');
|
|
32
|
+
return {
|
|
33
|
+
kind: 'refine',
|
|
34
|
+
parent: values.refine,
|
|
35
|
+
preset: values.preset ?? 'custom',
|
|
36
|
+
intent: values.intent,
|
|
37
|
+
...(values.preserve ? { preserve: values.preserve } : {})
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export const run = {
|
|
41
|
+
name: 'run',
|
|
42
|
+
summary: 'Start iterations with a coding agent, in a terminal or unattended',
|
|
43
|
+
usage: 'run <page>/<component> (--direction <idea>... | --fork <iteration> | --refine <iteration> --intent <text>) [--agent <id>] [--headless]',
|
|
44
|
+
needsRepo: true,
|
|
45
|
+
async run(args, context) {
|
|
46
|
+
const { io } = context;
|
|
47
|
+
const { values, positionals } = parseArgs({
|
|
48
|
+
args,
|
|
49
|
+
allowPositionals: true,
|
|
50
|
+
options: {
|
|
51
|
+
direction: { type: 'string', multiple: true },
|
|
52
|
+
hypothesis: { type: 'string' },
|
|
53
|
+
fork: { type: 'string' },
|
|
54
|
+
refine: { type: 'string' },
|
|
55
|
+
intent: { type: 'string' },
|
|
56
|
+
preset: { type: 'string' },
|
|
57
|
+
preserve: { type: 'string' },
|
|
58
|
+
agent: { type: 'string' },
|
|
59
|
+
model: { type: 'string' },
|
|
60
|
+
headless: { type: 'boolean', default: false },
|
|
61
|
+
'dev-url': { type: 'string' },
|
|
62
|
+
'no-screenshots': { type: 'boolean', default: false }
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
const { page, component } = parseComponent(positionals[0]);
|
|
66
|
+
const kind = runKind(values);
|
|
67
|
+
const repoRoot = context.repoRoot;
|
|
68
|
+
const link = await requireRepoLink(repoRoot);
|
|
69
|
+
const { adapter, detection } = await chooseAgent(context, values.agent);
|
|
70
|
+
const model = values.model ?? null;
|
|
71
|
+
const executable = detection.executable;
|
|
72
|
+
if (values.headless && !detection.headless.ready)
|
|
73
|
+
throw new Error(detection.headless.reason);
|
|
74
|
+
const api = await requireApi(context);
|
|
75
|
+
const outbox = outboxFor(repoRoot);
|
|
76
|
+
// Decisions waiting in the outbox reach the server first, so this prompt remembers them.
|
|
77
|
+
await outbox.flush(api);
|
|
78
|
+
const request = {
|
|
79
|
+
page,
|
|
80
|
+
component,
|
|
81
|
+
agent: adapter.id,
|
|
82
|
+
mode: values.headless ? 'headless' : 'interactive',
|
|
83
|
+
...kind
|
|
84
|
+
};
|
|
85
|
+
const runs = await startRuns(repoRoot, api, link, request, {
|
|
86
|
+
assetOrigin: localOrigin(await readSettings(context.configDir))
|
|
87
|
+
});
|
|
88
|
+
for (const item of runs) {
|
|
89
|
+
io.out(`${item.page}/${item.component}/${item.iteration}: ${item.promptFile}`);
|
|
90
|
+
}
|
|
91
|
+
if (values.headless) {
|
|
92
|
+
io.out(`Running ${adapter.name} unattended. Its output is summarized here.`);
|
|
93
|
+
const devUrl = values['dev-url'] ?? context.env.ROUGHBOOK_DEV_URL ?? DEFAULT_DEV_URL;
|
|
94
|
+
const finished = await Promise.all(runs.map(async (record) => {
|
|
95
|
+
const invocation = adapter.headless(runTarget(repoRoot, record, model), executable, context.env);
|
|
96
|
+
if ('refused' in invocation)
|
|
97
|
+
throw new Error(invocation.refused);
|
|
98
|
+
const result = await context.runHeadless(adapter, invocation, {
|
|
99
|
+
env: context.env,
|
|
100
|
+
model,
|
|
101
|
+
onEvent: event => {
|
|
102
|
+
if (event.kind === 'file')
|
|
103
|
+
io.out(` ${record.iteration}: wrote ${event.name}`);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
if (result.error)
|
|
107
|
+
io.err(` ${record.iteration}: ${result.error}`);
|
|
108
|
+
return completeRun(context, api, outbox, link, record, {
|
|
109
|
+
outcome: result.ok ? undefined : result.cancelled ? 'cancelled' : 'failed',
|
|
110
|
+
usage: result.usage,
|
|
111
|
+
devUrl,
|
|
112
|
+
screenshots: !values['no-screenshots']
|
|
113
|
+
});
|
|
114
|
+
}));
|
|
115
|
+
return finished.every(item => item.outcome !== 'failed') ? 0 : 1;
|
|
116
|
+
}
|
|
117
|
+
const sessions = terminalSessions(adapter, executable, repoRoot, runs, model);
|
|
118
|
+
const plan = planTerminal({
|
|
119
|
+
platform: context.platform,
|
|
120
|
+
env: context.env,
|
|
121
|
+
repoRoot,
|
|
122
|
+
sessions
|
|
123
|
+
});
|
|
124
|
+
let opened = false;
|
|
125
|
+
if (plan.kind !== 'manual') {
|
|
126
|
+
try {
|
|
127
|
+
await context.launchTerminal(plan);
|
|
128
|
+
opened = true;
|
|
129
|
+
io.out(`Opened ${runs.length === 1 ? 'a session' : `${runs.length} sessions`} of ${adapter.name} in ${plan.terminal}.`);
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
io.err(`${plan.terminal} could not be opened: ${error.message}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (!opened) {
|
|
136
|
+
if (plan.kind === 'manual')
|
|
137
|
+
io.out(plan.reason);
|
|
138
|
+
io.out('Run each of these in a terminal:');
|
|
139
|
+
for (const session of sessions) {
|
|
140
|
+
io.out(` ${manualCommand(context.platform, repoRoot, session)}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
io.out('When the agent has finished, run roughbook done.');
|
|
144
|
+
return 0;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { ADAPTERS, adapterFor } from '../agents/index.js';
|
|
2
|
+
import { readSettings } from '../config/settings.js';
|
|
3
|
+
import { currentOs } from '../launch/platform.js';
|
|
4
|
+
import { ITERATION, SLUG } from '../repo/preview.js';
|
|
5
|
+
import { STUDIO_VERSION } from '../version.js';
|
|
6
|
+
import { openApi } from './context.js';
|
|
7
|
+
function badTarget(what, example) {
|
|
8
|
+
return new Error(`Name the ${what}, such as ${example}.`);
|
|
9
|
+
}
|
|
10
|
+
/** `<page>/<component>`. */
|
|
11
|
+
export function parseComponent(text) {
|
|
12
|
+
const [page, component, ...rest] = (text ?? '').split('/');
|
|
13
|
+
if (!page || !component || rest.length || !SLUG.test(page) || !SLUG.test(component)) {
|
|
14
|
+
throw badTarget('component as <page>/<component>', 'homepage/hero');
|
|
15
|
+
}
|
|
16
|
+
return { page, component };
|
|
17
|
+
}
|
|
18
|
+
/** `<page>/<component>/<iteration>`. */
|
|
19
|
+
export function parseIteration(text) {
|
|
20
|
+
const parts = (text ?? '').split('/');
|
|
21
|
+
const iteration = parts.pop() ?? '';
|
|
22
|
+
if (!ITERATION.test(iteration)) {
|
|
23
|
+
throw badTarget('iteration as <page>/<component>/iteration-NN', 'homepage/hero/iteration-02');
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
return { ...parseComponent(parts.join('/')), iteration };
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
throw badTarget('iteration as <page>/<component>/iteration-NN', 'homepage/hero/iteration-02');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function isAgent(id) {
|
|
33
|
+
return ADAPTERS.some(adapter => adapter.id === id);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The agent to use: the one named, else this install's default, else the first one found. Refused
|
|
37
|
+
* when it is not installed, with the adapter's own advice.
|
|
38
|
+
*/
|
|
39
|
+
export async function chooseAgent(context, named) {
|
|
40
|
+
const wanted = named ?? (await readSettings(context.configDir)).defaultAgent ?? undefined;
|
|
41
|
+
if (wanted !== undefined) {
|
|
42
|
+
if (!isAgent(wanted)) {
|
|
43
|
+
throw new Error(`Unknown agent ${wanted}. Choose one of: ${ADAPTERS.map(item => item.id).join(', ')}.`);
|
|
44
|
+
}
|
|
45
|
+
const adapter = adapterFor(wanted);
|
|
46
|
+
const detection = await context.detect(adapter);
|
|
47
|
+
if (!detection.found)
|
|
48
|
+
throw new Error(adapter.notFound);
|
|
49
|
+
return { adapter, detection };
|
|
50
|
+
}
|
|
51
|
+
for (const adapter of ADAPTERS) {
|
|
52
|
+
const detection = await context.detect(adapter);
|
|
53
|
+
if (detection.found)
|
|
54
|
+
return { adapter, detection };
|
|
55
|
+
}
|
|
56
|
+
throw new Error(`No coding agent was found. ${ADAPTERS.map(adapter => adapter.notFound).join(' ')}`);
|
|
57
|
+
}
|
|
58
|
+
/** Tells the backend this studio's version and agents; quietly does nothing when it cannot. */
|
|
59
|
+
export async function sendHeartbeat(context, detections) {
|
|
60
|
+
try {
|
|
61
|
+
const { api } = await openApi(context);
|
|
62
|
+
if (!api.signedIn)
|
|
63
|
+
return;
|
|
64
|
+
await api.heartbeat({
|
|
65
|
+
studioVersion: STUDIO_VERSION,
|
|
66
|
+
os: currentOs(context.platform),
|
|
67
|
+
agents: detections
|
|
68
|
+
.filter(item => item.found)
|
|
69
|
+
.map(item => ({
|
|
70
|
+
id: item.id,
|
|
71
|
+
version: item.version && /^[0-9A-Za-z.+-]{1,40}$/.test(item.version) ? item.version : null,
|
|
72
|
+
signedIn: item.signedIn,
|
|
73
|
+
headless: item.headless.ready
|
|
74
|
+
}))
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// The heartbeat is a courtesy; the command's own work matters.
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/commands/shared.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { parseArgs } from 'node:util';
|
|
4
|
+
import { DEFAULT_LOCAL_PORT, readSettings, saveSettings } from '../config/settings.js';
|
|
5
|
+
import { loadPty } from '../launch/pty.js';
|
|
6
|
+
import { requireRepoLink } from '../repo/link.js';
|
|
7
|
+
import { createLocalServer } from '../server/app.js';
|
|
8
|
+
import { newToken } from '../server/security.js';
|
|
9
|
+
import { LocalStudio } from '../server/studio.js';
|
|
10
|
+
import { requireApi } from './context.js';
|
|
11
|
+
import { devUrl } from './done.js';
|
|
12
|
+
const REGISTRY_EVERY_MS = 1500;
|
|
13
|
+
const OUTBOX_EVERY_MS = 30_000;
|
|
14
|
+
/** The built UI: beside the compiled commands in the package, or in dist/ when run from source. */
|
|
15
|
+
export function findUiDir() {
|
|
16
|
+
const candidates = [
|
|
17
|
+
new URL('../ui/', import.meta.url),
|
|
18
|
+
new URL('../../dist/ui/', import.meta.url)
|
|
19
|
+
];
|
|
20
|
+
for (const candidate of candidates) {
|
|
21
|
+
const dir = fileURLToPath(candidate);
|
|
22
|
+
if (fs.existsSync(`${dir}index.html`))
|
|
23
|
+
return dir;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
function listen(server, port) {
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
server.once('error', error => {
|
|
30
|
+
if (error.code === 'EADDRINUSE') {
|
|
31
|
+
reject(new Error(`Port ${port} is in use. Is roughbook start already running here? Choose another with --port.`));
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
reject(error);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
server.listen(port, '127.0.0.1', () => resolve());
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function parsePort(text) {
|
|
41
|
+
const port = Number(text);
|
|
42
|
+
if (!Number.isInteger(port) || port < 1024 || port > 65535) {
|
|
43
|
+
throw new Error('The port is a number from 1024 to 65535.');
|
|
44
|
+
}
|
|
45
|
+
return port;
|
|
46
|
+
}
|
|
47
|
+
export const start = {
|
|
48
|
+
name: 'start',
|
|
49
|
+
summary: 'Open the local UI: iterations, review, runs, Done and promote',
|
|
50
|
+
usage: 'start [--port <port>] [--dev-url <url>] [--no-open]',
|
|
51
|
+
needsRepo: true,
|
|
52
|
+
async run(args, context) {
|
|
53
|
+
const { io } = context;
|
|
54
|
+
const { values } = parseArgs({
|
|
55
|
+
args,
|
|
56
|
+
options: {
|
|
57
|
+
port: { type: 'string' },
|
|
58
|
+
'dev-url': { type: 'string' },
|
|
59
|
+
'no-open': { type: 'boolean', default: false }
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
const repoRoot = context.repoRoot;
|
|
63
|
+
const link = await requireRepoLink(repoRoot);
|
|
64
|
+
const api = await requireApi(context);
|
|
65
|
+
const settings = await readSettings(context.configDir);
|
|
66
|
+
const saved = settings.localPort ?? DEFAULT_LOCAL_PORT;
|
|
67
|
+
const port = values.port ? parsePort(values.port) : saved;
|
|
68
|
+
const dev = devUrl(values['dev-url'], context.env);
|
|
69
|
+
const pty = loadPty(context.env);
|
|
70
|
+
const studio = new LocalStudio({
|
|
71
|
+
context: { ...context, repoRoot },
|
|
72
|
+
api,
|
|
73
|
+
link,
|
|
74
|
+
devUrl: dev,
|
|
75
|
+
port,
|
|
76
|
+
pty
|
|
77
|
+
});
|
|
78
|
+
const token = newToken();
|
|
79
|
+
const server = createLocalServer({
|
|
80
|
+
studio,
|
|
81
|
+
port,
|
|
82
|
+
token,
|
|
83
|
+
uiDir: findUiDir(),
|
|
84
|
+
devUrl: dev,
|
|
85
|
+
project: link.project
|
|
86
|
+
});
|
|
87
|
+
await listen(server, port);
|
|
88
|
+
if (port !== saved) {
|
|
89
|
+
// Iterations load their asset files from this address, so new prompts name it from now on.
|
|
90
|
+
await saveSettings(context.configDir, { localPort: port });
|
|
91
|
+
io.out(`New prompts name port ${port} for asset files; iterations made before use ${saved}.`);
|
|
92
|
+
}
|
|
93
|
+
const url = `http://127.0.0.1:${port}/#token=${token}`;
|
|
94
|
+
io.out(`Roughbook is open for ${link.project} at ${url}`);
|
|
95
|
+
io.out(`Iterations render through ${dev}; start the app's dev server there.`);
|
|
96
|
+
if (!pty.ok)
|
|
97
|
+
io.out(`Runs open in your own terminal: ${pty.reason}`);
|
|
98
|
+
io.out('Press Ctrl+C to stop.');
|
|
99
|
+
if (!values['no-open'] && !(await context.openUrl(url))) {
|
|
100
|
+
io.out('Open the address above in a browser.');
|
|
101
|
+
}
|
|
102
|
+
studio.keepRegistry();
|
|
103
|
+
void studio.flushOutbox();
|
|
104
|
+
void studio.heartbeat();
|
|
105
|
+
const timers = [
|
|
106
|
+
setInterval(() => studio.keepRegistry(), REGISTRY_EVERY_MS),
|
|
107
|
+
setInterval(() => void studio.flushOutbox(), OUTBOX_EVERY_MS)
|
|
108
|
+
];
|
|
109
|
+
await context.waitForStop();
|
|
110
|
+
for (const timer of timers)
|
|
111
|
+
clearInterval(timer);
|
|
112
|
+
studio.close();
|
|
113
|
+
server.closeAllConnections();
|
|
114
|
+
await new Promise(resolve => server.close(resolve));
|
|
115
|
+
io.out('Stopped. Sessions in the built-in terminal were ended.');
|
|
116
|
+
return 0;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
//# sourceMappingURL=start.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
import { ApiError, OfflineError } from '../api/errors.js';
|
|
3
|
+
import { outboxFor } from '../api/outbox.js';
|
|
4
|
+
import { readLocalLink, readRepoLink } from '../repo/link.js';
|
|
5
|
+
import { openApi } from './context.js';
|
|
6
|
+
export const status = {
|
|
7
|
+
name: 'status',
|
|
8
|
+
summary: 'Show the sign-in, the linked project and what is waiting to be sent',
|
|
9
|
+
usage: 'status',
|
|
10
|
+
needsRepo: false,
|
|
11
|
+
async run(args, context) {
|
|
12
|
+
const { io } = context;
|
|
13
|
+
parseArgs({ args, options: {} });
|
|
14
|
+
const { api, credentials } = await openApi(context);
|
|
15
|
+
io.out(`Server: ${api.server}`);
|
|
16
|
+
let projects = null;
|
|
17
|
+
if (!credentials) {
|
|
18
|
+
io.out('Signed in: no (run roughbook login)');
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
try {
|
|
22
|
+
const me = await api.me();
|
|
23
|
+
io.out(`Signed in: ${me.user.email}`);
|
|
24
|
+
projects = await api.projects();
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
if (error instanceof OfflineError) {
|
|
28
|
+
io.out(`Signed in: ${credentials.signedInAs ?? 'yes'} (the server cannot be reached)`);
|
|
29
|
+
}
|
|
30
|
+
else if (error instanceof ApiError && error.status === 401) {
|
|
31
|
+
io.out('Signed in: no longer (run roughbook login)');
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!context.repoRoot) {
|
|
39
|
+
io.out('Repo: not in a linked repo');
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
|
42
|
+
io.out(`Repo: ${context.repoRoot}`);
|
|
43
|
+
const link = await readRepoLink(context.repoRoot);
|
|
44
|
+
if (link) {
|
|
45
|
+
const org = projects?.find(item => item.id === link.orgId);
|
|
46
|
+
const project = org?.projects.find(item => item.slug === link.project);
|
|
47
|
+
io.out(`Project: ${project ? `${project.name} (${link.project})` : link.project}${org ? ` in ${org.name}` : ''}`);
|
|
48
|
+
io.out(`rough/: ${link.roughCommitted ? 'committed to git' : 'not committed'}`);
|
|
49
|
+
if (!(await readLocalLink(context.repoRoot))) {
|
|
50
|
+
io.out(' not linked on this machine yet (run roughbook init)');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const outbox = outboxFor(context.repoRoot);
|
|
54
|
+
const pending = await outbox.pending();
|
|
55
|
+
const dropped = await outbox.dropped();
|
|
56
|
+
io.out(`Waiting: ${pending.length ? `${pending.length} to send` : 'nothing to send'}`);
|
|
57
|
+
if (dropped.length)
|
|
58
|
+
io.out(`Refused: ${dropped.length} the server would not accept`);
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAgB,MAAM,cAAc,CAAC;AAErD,MAAM,CAAC,MAAM,MAAM,GAAY;IAC7B,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,qEAAqE;IAC9E,KAAK,EAAE,QAAQ;IACf,SAAS,EAAE,KAAK;IAChB,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO;QACrB,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC;QACvB,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QACjC,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;QACpD,EAAE,CAAC,GAAG,CAAC,eAAe,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAEpC,IAAI,QAAQ,GAAoD,IAAI,CAAC;QACrE,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,EAAE,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;QACjD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC;gBACH,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,EAAE,EAAE,CAAC;gBAC1B,EAAE,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;gBACvC,QAAQ,GAAG,MAAM,GAAG,CAAC,QAAQ,EAAE,CAAC;YAClC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,KAAK,YAAY,YAAY,EAAE,CAAC;oBAClC,EAAE,CAAC,GAAG,CAAC,eAAe,WAAW,CAAC,UAAU,IAAI,KAAK,iCAAiC,CAAC,CAAC;gBAC1F,CAAC;qBAAM,IAAI,KAAK,YAAY,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;oBAC7D,EAAE,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;gBACxD,CAAC;qBAAM,CAAC;oBACN,MAAM,KAAK,CAAC;gBACd,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YACtB,EAAE,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;YAC3C,OAAO,CAAC,CAAC;QACX,CAAC;QACD,EAAE,CAAC,GAAG,CAAC,eAAe,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAClD,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,GAAG,GAAG,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3D,MAAM,OAAO,GAAG,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC;YACvE,EAAE,CAAC,GAAG,CACJ,eAAe,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAC7G,CAAC;YACF,EAAE,CAAC,GAAG,CAAC,eAAe,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC;YACpF,IAAI,CAAC,CAAC,MAAM,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;gBAC7C,EAAE,CAAC,GAAG,CAAC,iEAAiE,CAAC,CAAC;YAC5E,CAAC;QACH,CAAC;QACD,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;QACvC,EAAE,CAAC,GAAG,CAAC,eAAe,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,UAAU,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC;QAC1F,IAAI,OAAO,CAAC,MAAM;YAAE,EAAE,CAAC,GAAG,CAAC,eAAe,OAAO,CAAC,MAAM,8BAA8B,CAAC,CAAC;QACxF,OAAO,CAAC,CAAC;IACX,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { rm } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { readJson, writeJsonAtomic } from '../fs/json.js';
|
|
4
|
+
export function credentialsFile(configDir) {
|
|
5
|
+
return path.join(configDir, 'credentials.json');
|
|
6
|
+
}
|
|
7
|
+
export async function readCredentials(configDir) {
|
|
8
|
+
return readJson(credentialsFile(configDir));
|
|
9
|
+
}
|
|
10
|
+
/** Readable by this user only, where the OS has file modes. */
|
|
11
|
+
export async function saveCredentials(configDir, credentials) {
|
|
12
|
+
await writeJsonAtomic(credentialsFile(configDir), credentials, { mode: 0o600 });
|
|
13
|
+
}
|
|
14
|
+
export async function clearCredentials(configDir) {
|
|
15
|
+
await rm(credentialsFile(configDir), { force: true });
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/config/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACtC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAY1D,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,SAAiB;IACrD,OAAO,QAAQ,CAAc,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,+DAA+D;AAC/D,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,SAAiB,EAAE,WAAwB;IAC/E,MAAM,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAClF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,SAAiB;IACtD,MAAM,EAAE,CAAC,eAAe,CAAC,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The backend the studio talks to until hosting is decided (the split plan's open question 1).
|
|
3
|
+
* `ROUGHBOOK_SERVER` or `roughbook login --server` chooses another.
|
|
4
|
+
*/
|
|
5
|
+
export const DEFAULT_SERVER = 'http://localhost:4000';
|
|
6
|
+
const LOCAL_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]']);
|
|
7
|
+
/**
|
|
8
|
+
* A server's origin, checked: https, or plain http only to this machine, since every request
|
|
9
|
+
* carries the install token.
|
|
10
|
+
*/
|
|
11
|
+
export function normalizeServer(input) {
|
|
12
|
+
let url;
|
|
13
|
+
try {
|
|
14
|
+
url = new URL(input);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
throw new Error(`Not a server address: ${input}`);
|
|
18
|
+
}
|
|
19
|
+
const local = LOCAL_HOSTS.has(url.hostname) || url.hostname.endsWith('.localhost');
|
|
20
|
+
if (url.protocol !== 'https:' && !(url.protocol === 'http:' && local)) {
|
|
21
|
+
throw new Error(`Use https for ${url.host}; plain http is only for this machine.`);
|
|
22
|
+
}
|
|
23
|
+
return url.origin;
|
|
24
|
+
}
|
|
25
|
+
/** The first of the flag, the environment and the saved sign-in, else the default. */
|
|
26
|
+
export function resolveServer(flag, env, saved) {
|
|
27
|
+
return normalizeServer(flag || env.ROUGHBOOK_SERVER || saved || DEFAULT_SERVER);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/config/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,uBAAuB,CAAC;AAEtD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;AAEjE;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,EAAE,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IACnF,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,KAAK,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,iBAAiB,GAAG,CAAC,IAAI,wCAAwC,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC;AACpB,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,aAAa,CAC3B,IAAwB,EACxB,GAAsB,EACtB,KAAyB;IAEzB,OAAO,eAAe,CAAC,IAAI,IAAI,GAAG,CAAC,gBAAgB,IAAI,KAAK,IAAI,cAAc,CAAC,CAAC;AAClF,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { readJson, writeJsonAtomic } from '../fs/json.js';
|
|
3
|
+
/** Where `roughbook start` serves the local UI when no port was chosen. */
|
|
4
|
+
export const DEFAULT_LOCAL_PORT = 4848;
|
|
5
|
+
const DEFAULTS = { defaultAgent: null, localPort: null };
|
|
6
|
+
/** The local server's address, which prompts give agents for the asset files. */
|
|
7
|
+
export function localOrigin(settings) {
|
|
8
|
+
return `http://127.0.0.1:${settings.localPort ?? DEFAULT_LOCAL_PORT}`;
|
|
9
|
+
}
|
|
10
|
+
export function settingsFile(configDir) {
|
|
11
|
+
return path.join(configDir, 'settings.json');
|
|
12
|
+
}
|
|
13
|
+
export async function readSettings(configDir) {
|
|
14
|
+
return { ...DEFAULTS, ...(await readJson(settingsFile(configDir))) };
|
|
15
|
+
}
|
|
16
|
+
export async function saveSettings(configDir, patch) {
|
|
17
|
+
const settings = { ...(await readSettings(configDir)), ...patch };
|
|
18
|
+
await writeJsonAtomic(settingsFile(configDir), settings);
|
|
19
|
+
return settings;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/config/settings.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAG1D,2EAA2E;AAC3E,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAavC,MAAM,QAAQ,GAAa,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AAEnE,iFAAiF;AACjF,MAAM,UAAU,WAAW,CAAC,QAAqC;IAC/D,OAAO,oBAAoB,QAAQ,CAAC,SAAS,IAAI,kBAAkB,EAAE,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,SAAiB;IAC5C,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,SAAiB;IAClD,OAAO,EAAE,GAAG,QAAQ,EAAE,GAAG,CAAC,MAAM,QAAQ,CAAoB,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;AAC1F,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,SAAiB,EAAE,KAAwB;IAC5E,MAAM,QAAQ,GAAG,EAAE,GAAG,CAAC,MAAM,YAAY,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;IAClE,MAAM,eAAe,CAAC,YAAY,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,CAAC;IACzD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Where the studio keeps the install token: the place each OS sets aside for an application's
|
|
5
|
+
* settings, outside every repo. `ROUGHBOOK_CONFIG_DIR` overrides it.
|
|
6
|
+
*/
|
|
7
|
+
export function userConfigDir(env = process.env, platform = process.platform, home = os.homedir()) {
|
|
8
|
+
if (env.ROUGHBOOK_CONFIG_DIR)
|
|
9
|
+
return path.resolve(env.ROUGHBOOK_CONFIG_DIR);
|
|
10
|
+
if (platform === 'win32') {
|
|
11
|
+
return path.win32.join(env.APPDATA || path.win32.join(home, 'AppData', 'Roaming'), 'Roughbook');
|
|
12
|
+
}
|
|
13
|
+
if (platform === 'darwin') {
|
|
14
|
+
return path.posix.join(home, 'Library', 'Application Support', 'Roughbook');
|
|
15
|
+
}
|
|
16
|
+
return path.posix.join(env.XDG_CONFIG_HOME || path.posix.join(home, '.config'), 'roughbook');
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=userDir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"userDir.js","sourceRoot":"","sources":["../../src/config/userDir.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAyB,OAAO,CAAC,GAAG,EACpC,WAA4B,OAAO,CAAC,QAAQ,EAC5C,OAAe,EAAE,CAAC,OAAO,EAAE;IAE3B,IAAI,GAAG,CAAC,oBAAoB;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAC5E,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,WAAW,CAAC,CAAC;IAClG,CAAC;IACD,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,qBAAqB,EAAE,WAAW,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,WAAW,CAAC,CAAC;AAC/F,CAAC"}
|
package/dist/fs/json.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
/** A JSON file's value, or null when the file does not exist. */
|
|
5
|
+
export async function readJson(file) {
|
|
6
|
+
let text;
|
|
7
|
+
try {
|
|
8
|
+
text = await readFile(file, 'utf8');
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
if (error.code === 'ENOENT')
|
|
12
|
+
return null;
|
|
13
|
+
throw error;
|
|
14
|
+
}
|
|
15
|
+
return JSON.parse(text);
|
|
16
|
+
}
|
|
17
|
+
/** Two-space JSON with `\n` line endings and a final newline, the same on every OS. */
|
|
18
|
+
export function formatJson(value) {
|
|
19
|
+
return `${JSON.stringify(value, null, 2)}\n`;
|
|
20
|
+
}
|
|
21
|
+
const BUSY = new Set(['EPERM', 'EBUSY', 'EACCES']);
|
|
22
|
+
/**
|
|
23
|
+
* Writes beside the file and renames over it, so a reader never sees half a file. Windows refuses
|
|
24
|
+
* the rename while another process has the file open, so it is retried for a moment.
|
|
25
|
+
*/
|
|
26
|
+
export async function writeJsonAtomic(file, value, options = {}) {
|
|
27
|
+
await mkdir(path.dirname(file), { recursive: true });
|
|
28
|
+
const temp = `${file}.${randomBytes(6).toString('hex')}.tmp`;
|
|
29
|
+
await writeFile(temp, formatJson(value), { mode: options.mode });
|
|
30
|
+
for (let attempt = 0;; attempt++) {
|
|
31
|
+
try {
|
|
32
|
+
await rename(temp, file);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (attempt >= 10 || !BUSY.has(error.code ?? '')) {
|
|
37
|
+
await rm(temp, { force: true });
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
await new Promise(resolve => setTimeout(resolve, 20 * (attempt + 1)));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/fs/json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,iEAAiE;AACjE,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAI,IAAY;IAC5C,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QACpE,MAAM,KAAK,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAM,CAAC;AAC/B,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;AAC/C,CAAC;AAED,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AAEnD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAY,EACZ,KAAc,EACd,UAA6B,EAAE;IAE/B,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,MAAM,IAAI,GAAG,GAAG,IAAI,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;IAC7D,MAAM,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACjE,KAAK,IAAI,OAAO,GAAG,CAAC,GAAI,OAAO,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACzB,OAAO;QACT,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,OAAO,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAE,KAA+B,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,CAAC;gBAC5E,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBAChC,MAAM,KAAK,CAAC;YACd,CAAC;YACD,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACxE,CAAC;IACH,CAAC;AACH,CAAC"}
|