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,203 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { parseArgs } from 'node:util';
|
|
3
|
+
import { confirm } from '../io.js';
|
|
4
|
+
import { changedLines } from '../repo/diff.js';
|
|
5
|
+
import { appRoot, detectFramework } from '../repo/framework.js';
|
|
6
|
+
import { readLocalLink, readRepoLink, writeLocalLink } from '../repo/link.js';
|
|
7
|
+
import { applyPrep, checkRepo, planPrep } from '../repo/prep.js';
|
|
8
|
+
import { gitInit, writeScratch } from '../repo/scratch.js';
|
|
9
|
+
import { openApi } from './context.js';
|
|
10
|
+
/** The lines of an edit shown under it, at most this many. */
|
|
11
|
+
const SHOWN_LINES = 12;
|
|
12
|
+
async function chooseProject(api, io, options, existing) {
|
|
13
|
+
const editable = (await api.projects()).filter(org => org.role !== 'viewer');
|
|
14
|
+
if (!editable.length) {
|
|
15
|
+
throw new Error('You can only view your organizations. Ask an owner to make you an editor.');
|
|
16
|
+
}
|
|
17
|
+
const orgs = options.org ? editable.filter(org => org.id === options.org) : editable;
|
|
18
|
+
if (!orgs.length)
|
|
19
|
+
throw new Error(`You cannot edit an organization with the id ${options.org}.`);
|
|
20
|
+
const create = async (org, name) => {
|
|
21
|
+
const { slug } = await api.createProject(org.id, name);
|
|
22
|
+
io.out(`Created the project ${name} (${slug}) in ${org.name}.`);
|
|
23
|
+
return { orgId: org.id, orgName: org.name, slug, name };
|
|
24
|
+
};
|
|
25
|
+
const pickOrg = async () => {
|
|
26
|
+
if (orgs.length === 1)
|
|
27
|
+
return orgs[0];
|
|
28
|
+
io.out('Which organization is it for?');
|
|
29
|
+
orgs.forEach((org, index) => io.out(` ${index + 1}. ${org.name}`));
|
|
30
|
+
const answer = await io.ask('Organization: ');
|
|
31
|
+
const org = answer === null ? undefined : orgs[Number(answer) - 1];
|
|
32
|
+
if (!org)
|
|
33
|
+
throw new Error('Pass --org <id> to choose the organization.');
|
|
34
|
+
return org;
|
|
35
|
+
};
|
|
36
|
+
if (options.new)
|
|
37
|
+
return create(await pickOrg(), options.new);
|
|
38
|
+
const all = orgs.flatMap(org => org.projects.map(project => ({
|
|
39
|
+
orgId: org.id,
|
|
40
|
+
orgName: org.name,
|
|
41
|
+
slug: project.slug,
|
|
42
|
+
name: project.name
|
|
43
|
+
})));
|
|
44
|
+
if (options.project) {
|
|
45
|
+
const matches = all.filter(choice => choice.slug === options.project);
|
|
46
|
+
if (matches.length === 1)
|
|
47
|
+
return matches[0];
|
|
48
|
+
if (!matches.length)
|
|
49
|
+
throw new Error(`No project ${options.project} that you can edit.`);
|
|
50
|
+
throw new Error(`Several organizations have a project ${options.project}. Add --org with one of: ${matches.map(choice => `${choice.orgId} (${choice.orgName})`).join(', ')}.`);
|
|
51
|
+
}
|
|
52
|
+
if (existing && !options.org) {
|
|
53
|
+
const linked = all.find(choice => choice.orgId === existing.orgId && choice.slug === existing.project);
|
|
54
|
+
if (linked)
|
|
55
|
+
return linked;
|
|
56
|
+
io.err('rough/roughbook.json names a project you cannot edit. Choose another.');
|
|
57
|
+
}
|
|
58
|
+
io.out('Which project does this repo work on?');
|
|
59
|
+
all.forEach((choice, index) => io.out(` ${index + 1}. ${choice.name} (${choice.slug})${orgs.length > 1 ? ` in ${choice.orgName}` : ''}`));
|
|
60
|
+
io.out(' n. A new project');
|
|
61
|
+
const answer = await io.ask('Project: ');
|
|
62
|
+
if (answer === null) {
|
|
63
|
+
throw new Error('Pass --project <slug> or --new <name> when nobody can answer questions.');
|
|
64
|
+
}
|
|
65
|
+
if (/^n(ew)?$/i.test(answer)) {
|
|
66
|
+
const name = await io.ask('Name of the new project: ');
|
|
67
|
+
if (!name)
|
|
68
|
+
throw new Error('A new project needs a name.');
|
|
69
|
+
return create(await pickOrg(), name);
|
|
70
|
+
}
|
|
71
|
+
const chosen = all[Number(answer) - 1];
|
|
72
|
+
if (!chosen)
|
|
73
|
+
throw new Error(`There is no choice ${answer}.`);
|
|
74
|
+
return chosen;
|
|
75
|
+
}
|
|
76
|
+
function printPlan(io, plan) {
|
|
77
|
+
if (!plan.changes.length)
|
|
78
|
+
io.out(`${plan.repo} is ready. Nothing to change.`);
|
|
79
|
+
else
|
|
80
|
+
io.out(`Changes in ${plan.repo}:`);
|
|
81
|
+
for (const change of plan.changes) {
|
|
82
|
+
io.out(` ${change.action === 'create' ? '+' : '~'} ${change.file}: ${change.summary}`);
|
|
83
|
+
if (change.action !== 'edit')
|
|
84
|
+
continue;
|
|
85
|
+
const before = plan.before[change.file] ?? '';
|
|
86
|
+
const { removed, added } = changedLines(before, change.after);
|
|
87
|
+
const lines = [
|
|
88
|
+
...removed.map(line => ` - ${line}`),
|
|
89
|
+
...added.map(line => ` + ${line}`)
|
|
90
|
+
];
|
|
91
|
+
for (const line of lines.slice(0, SHOWN_LINES))
|
|
92
|
+
io.out(line);
|
|
93
|
+
if (lines.length > SHOWN_LINES)
|
|
94
|
+
io.out(` … ${lines.length - SHOWN_LINES} more lines`);
|
|
95
|
+
}
|
|
96
|
+
for (const step of plan.manual)
|
|
97
|
+
io.out(` ! By hand: ${step}`);
|
|
98
|
+
}
|
|
99
|
+
export const init = {
|
|
100
|
+
name: 'init',
|
|
101
|
+
summary: 'Link this repo to a Roughbook project and prepare it, showing every change first',
|
|
102
|
+
usage: 'init [--project <slug> | --new <name>] [--org <id>] [--commit | --no-commit] [--yes] [--scratch <dir>]',
|
|
103
|
+
needsRepo: false,
|
|
104
|
+
async run(args, context) {
|
|
105
|
+
const { io } = context;
|
|
106
|
+
const { values } = parseArgs({
|
|
107
|
+
args,
|
|
108
|
+
options: {
|
|
109
|
+
project: { type: 'string' },
|
|
110
|
+
new: { type: 'string' },
|
|
111
|
+
org: { type: 'string' },
|
|
112
|
+
commit: { type: 'boolean' },
|
|
113
|
+
'no-commit': { type: 'boolean' },
|
|
114
|
+
yes: { type: 'boolean', short: 'y' },
|
|
115
|
+
scratch: { type: 'string' }
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
if (values.commit && values['no-commit'])
|
|
119
|
+
throw new Error('Choose --commit or --no-commit.');
|
|
120
|
+
if (values.project && values.new)
|
|
121
|
+
throw new Error('Choose --project or --new.');
|
|
122
|
+
const { api, credentials } = await openApi(context);
|
|
123
|
+
if (!credentials)
|
|
124
|
+
throw new Error('Not signed in. Run roughbook login first.');
|
|
125
|
+
let repo;
|
|
126
|
+
if (values.scratch) {
|
|
127
|
+
repo = path.resolve(context.cwd, values.scratch);
|
|
128
|
+
writeScratch(repo);
|
|
129
|
+
io.out(`Created a Next.js app in ${repo}. Run npm install there before roughbook start.`);
|
|
130
|
+
if (await gitInit(repo))
|
|
131
|
+
io.out('Started a git repository there.');
|
|
132
|
+
else
|
|
133
|
+
io.out('git was not found, so no repository was started. rough/ needs git to be kept.');
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
repo = context.repoRoot ?? appRoot(context.cwd);
|
|
137
|
+
}
|
|
138
|
+
const problems = checkRepo(repo);
|
|
139
|
+
if (problems.length) {
|
|
140
|
+
for (const problem of problems)
|
|
141
|
+
io.err(problem);
|
|
142
|
+
return 1;
|
|
143
|
+
}
|
|
144
|
+
const existing = await readRepoLink(repo).catch(() => null);
|
|
145
|
+
const choice = await chooseProject(api, io, values, existing);
|
|
146
|
+
let committed;
|
|
147
|
+
if (values.commit || values['no-commit'])
|
|
148
|
+
committed = Boolean(values.commit);
|
|
149
|
+
else if (existing)
|
|
150
|
+
committed = existing.roughCommitted;
|
|
151
|
+
else if (values.yes)
|
|
152
|
+
committed = true;
|
|
153
|
+
else {
|
|
154
|
+
committed = await confirm(io, 'Commit rough/ to git? It is the only record of your iterations.', true);
|
|
155
|
+
}
|
|
156
|
+
if (!committed) {
|
|
157
|
+
io.out('rough/ will be ignored by git, so nothing backs up its iterations.');
|
|
158
|
+
}
|
|
159
|
+
const plan = planPrep(repo, {
|
|
160
|
+
link: { version: 1, orgId: choice.orgId, project: choice.slug, roughCommitted: committed }
|
|
161
|
+
});
|
|
162
|
+
if (plan.problems.length) {
|
|
163
|
+
for (const problem of plan.problems)
|
|
164
|
+
io.err(problem);
|
|
165
|
+
return 1;
|
|
166
|
+
}
|
|
167
|
+
printPlan(io, plan);
|
|
168
|
+
if (plan.changes.length && !values.yes) {
|
|
169
|
+
const answer = await io.ask(`Apply ${plan.changes.length === 1 ? 'this change' : `these ${plan.changes.length} changes`}? [Y/n] `);
|
|
170
|
+
if (answer === null || (answer && !/^y(es)?$/i.test(answer))) {
|
|
171
|
+
io.out('Nothing was written. Run again with --yes to apply these changes.');
|
|
172
|
+
return answer === null ? 1 : 0;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const local = await readLocalLink(repo);
|
|
176
|
+
const sameLink = local?.installId === credentials.installId &&
|
|
177
|
+
existing?.orgId === choice.orgId &&
|
|
178
|
+
existing.project === choice.slug &&
|
|
179
|
+
existing.roughCommitted === committed;
|
|
180
|
+
let linkId = local?.linkId ?? null;
|
|
181
|
+
if (!sameLink || !linkId) {
|
|
182
|
+
const linked = await api.link(choice.orgId, {
|
|
183
|
+
project: choice.slug,
|
|
184
|
+
framework: detectFramework(repo),
|
|
185
|
+
roughCommitted: committed
|
|
186
|
+
});
|
|
187
|
+
linkId = linked.linkId;
|
|
188
|
+
}
|
|
189
|
+
applyPrep(plan);
|
|
190
|
+
await writeLocalLink(repo, {
|
|
191
|
+
linkId,
|
|
192
|
+
installId: credentials.installId,
|
|
193
|
+
linkedAt: new Date().toISOString()
|
|
194
|
+
});
|
|
195
|
+
io.out(`Linked to ${choice.name} (${choice.slug}) in ${choice.orgName}.`);
|
|
196
|
+
if (plan.changes.length) {
|
|
197
|
+
io.out(`Applied ${plan.changes.length} change${plan.changes.length === 1 ? '' : 's'}; review them with git diff.`);
|
|
198
|
+
}
|
|
199
|
+
io.out('Next, run roughbook start.');
|
|
200
|
+
return 0;
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
import { ApiError, OfflineError } from '../api/errors.js';
|
|
3
|
+
import { saveCredentials } from '../config/credentials.js';
|
|
4
|
+
import { currentOs } from '../launch/platform.js';
|
|
5
|
+
import { STUDIO_VERSION } from '../version.js';
|
|
6
|
+
import { openApi } from './context.js';
|
|
7
|
+
/** Consecutive unreachable polls before giving up. */
|
|
8
|
+
const OFFLINE_TRIES = 5;
|
|
9
|
+
export const login = {
|
|
10
|
+
name: 'login',
|
|
11
|
+
summary: 'Sign this machine in to Roughbook',
|
|
12
|
+
usage: 'login [--server <url>] [--no-browser]',
|
|
13
|
+
needsRepo: false,
|
|
14
|
+
async run(args, context) {
|
|
15
|
+
const { io } = context;
|
|
16
|
+
const { values } = parseArgs({
|
|
17
|
+
args,
|
|
18
|
+
options: { server: { type: 'string' }, 'no-browser': { type: 'boolean' } }
|
|
19
|
+
});
|
|
20
|
+
const { api, credentials } = await openApi(context, values.server);
|
|
21
|
+
if (credentials) {
|
|
22
|
+
try {
|
|
23
|
+
const me = await api.me();
|
|
24
|
+
io.out(`Signed in to ${api.server} as ${me.user.email} already.`);
|
|
25
|
+
io.out('Run roughbook logout first to sign in as someone else.');
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
// A token removed on the web: sign in afresh.
|
|
30
|
+
if (!(error instanceof ApiError && error.status === 401))
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const anonymous = api.signedOut();
|
|
35
|
+
const login = await anonymous.startDeviceLogin({
|
|
36
|
+
studioVersion: STUDIO_VERSION,
|
|
37
|
+
os: currentOs()
|
|
38
|
+
});
|
|
39
|
+
io.out(`To sign in, open ${login.verificationUri} and enter this code:`);
|
|
40
|
+
io.out('');
|
|
41
|
+
io.out(` ${login.userCode}`);
|
|
42
|
+
io.out('');
|
|
43
|
+
if (!values['no-browser'] && (await context.openUrl(login.verificationUriComplete))) {
|
|
44
|
+
io.out('Your browser should have opened the page.');
|
|
45
|
+
}
|
|
46
|
+
io.out('Waiting for you to approve it…');
|
|
47
|
+
let interval = login.interval * 1000;
|
|
48
|
+
let offline = 0;
|
|
49
|
+
const tries = Math.ceil(login.expiresIn / login.interval) + OFFLINE_TRIES;
|
|
50
|
+
for (let attempt = 0; attempt < tries; attempt++) {
|
|
51
|
+
await context.sleep(interval);
|
|
52
|
+
try {
|
|
53
|
+
const issued = await anonymous.pollDeviceLogin(login.deviceCode);
|
|
54
|
+
const me = await anonymous.withToken(issued.token).me();
|
|
55
|
+
await saveCredentials(context.configDir, {
|
|
56
|
+
server: api.server,
|
|
57
|
+
installId: issued.installId,
|
|
58
|
+
token: issued.token,
|
|
59
|
+
signedInAs: me.user.email,
|
|
60
|
+
savedAt: new Date().toISOString()
|
|
61
|
+
});
|
|
62
|
+
io.out(`Signed in to ${api.server} as ${me.user.email}.`);
|
|
63
|
+
io.out('Next, run roughbook init in the repo you want to design in.');
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
if (error instanceof ApiError) {
|
|
68
|
+
if (error.code === 'AUTHORIZATION_PENDING')
|
|
69
|
+
continue;
|
|
70
|
+
if (error.code === 'SLOW_DOWN') {
|
|
71
|
+
interval += 5000;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (error.code === 'ACCESS_DENIED') {
|
|
75
|
+
io.err('The sign-in was turned away. Run roughbook login to try again.');
|
|
76
|
+
return 1;
|
|
77
|
+
}
|
|
78
|
+
if (error.code === 'EXPIRED_TOKEN') {
|
|
79
|
+
io.err('The code expired before it was approved. Run roughbook login again.');
|
|
80
|
+
return 1;
|
|
81
|
+
}
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
if (error instanceof OfflineError && ++offline < OFFLINE_TRIES)
|
|
85
|
+
continue;
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
io.err('The code expired before it was approved. Run roughbook login again.');
|
|
90
|
+
return 1;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
import { ApiError, OfflineError } from '../api/errors.js';
|
|
3
|
+
import { clearCredentials } from '../config/credentials.js';
|
|
4
|
+
import { openApi } from './context.js';
|
|
5
|
+
export const logout = {
|
|
6
|
+
name: 'logout',
|
|
7
|
+
summary: 'Sign this machine out',
|
|
8
|
+
usage: 'logout',
|
|
9
|
+
needsRepo: false,
|
|
10
|
+
async run(args, context) {
|
|
11
|
+
const { io } = context;
|
|
12
|
+
parseArgs({ args, options: {} });
|
|
13
|
+
const { api, credentials } = await openApi(context);
|
|
14
|
+
if (!credentials) {
|
|
15
|
+
io.out('Not signed in.');
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
await api.logout();
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
if (error instanceof OfflineError) {
|
|
23
|
+
io.err(`Could not reach ${api.server}. This machine has forgotten its sign-in, but the token works until you remove this studio in the web's settings.`);
|
|
24
|
+
}
|
|
25
|
+
else if (!(error instanceof ApiError && error.status === 401)) {
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
await clearCredentials(context.configDir);
|
|
30
|
+
io.out('Signed out.');
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=logout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAgB,MAAM,cAAc,CAAC;AAErD,MAAM,CAAC,MAAM,MAAM,GAAY;IAC7B,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,uBAAuB;IAChC,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,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,EAAE,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;YACzB,OAAO,CAAC,CAAC;QACX,CAAC;QACD,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC;QACrB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,YAAY,EAAE,CAAC;gBAClC,EAAE,CAAC,GAAG,CACJ,mBAAmB,GAAG,CAAC,MAAM,mHAAmH,CACjJ,CAAC;YACJ,CAAC;iBAAM,IAAI,CAAC,CAAC,KAAK,YAAY,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,CAAC,EAAE,CAAC;gBAChE,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;QACD,MAAM,gBAAgB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC1C,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACtB,OAAO,CAAC,CAAC;IACX,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
import { manualCommand, planTerminal, sessionTitle } from '../launch/terminal.js';
|
|
3
|
+
import { requireRepoLink } from '../repo/link.js';
|
|
4
|
+
import { findComponent, iterationToPromote, preparePromotion } from '../runs/promote.js';
|
|
5
|
+
import { handoffLine } from '../runs/slots.js';
|
|
6
|
+
import { requireApi } from './context.js';
|
|
7
|
+
import { chooseAgent, parseComponent } from './shared.js';
|
|
8
|
+
/** The agent's session that writes the real component from the promote prompt. */
|
|
9
|
+
export function promoteSession(adapter, detection, repoRoot, target, prepared, model) {
|
|
10
|
+
const title = sessionTitle(`Promote ${target.componentName}`);
|
|
11
|
+
return {
|
|
12
|
+
title,
|
|
13
|
+
command: detection.executable.command,
|
|
14
|
+
args: [
|
|
15
|
+
...detection.executable.prefixArgs,
|
|
16
|
+
...adapter.interactiveArgs({
|
|
17
|
+
repoRoot,
|
|
18
|
+
targetFolder: `rough/${target.page}/${target.component}`,
|
|
19
|
+
promptFile: prepared.promptFile,
|
|
20
|
+
instruction: handoffLine(prepared.promptFile),
|
|
21
|
+
sessionId: prepared.promotionId,
|
|
22
|
+
model,
|
|
23
|
+
title
|
|
24
|
+
})
|
|
25
|
+
]
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export const promote = {
|
|
29
|
+
name: 'promote',
|
|
30
|
+
summary: 'Hand the selected iteration to your agent to write the real component',
|
|
31
|
+
usage: 'promote <page>/<component> [--iteration <id>] [--to <file>] [--public <folder>] [--agent <id>]',
|
|
32
|
+
needsRepo: true,
|
|
33
|
+
async run(args, context) {
|
|
34
|
+
const { io } = context;
|
|
35
|
+
const { values, positionals } = parseArgs({
|
|
36
|
+
args,
|
|
37
|
+
allowPositionals: true,
|
|
38
|
+
options: {
|
|
39
|
+
iteration: { type: 'string' },
|
|
40
|
+
to: { type: 'string' },
|
|
41
|
+
public: { type: 'string' },
|
|
42
|
+
agent: { type: 'string' },
|
|
43
|
+
model: { type: 'string' }
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
const { page, component } = parseComponent(positionals[0]);
|
|
47
|
+
const repoRoot = context.repoRoot;
|
|
48
|
+
const link = await requireRepoLink(repoRoot);
|
|
49
|
+
const api = await requireApi(context);
|
|
50
|
+
const tree = await api.project(link.orgId, link.project);
|
|
51
|
+
const record = findComponent(tree, page, component);
|
|
52
|
+
const iteration = iterationToPromote(record, values.iteration);
|
|
53
|
+
const prepared = await preparePromotion(repoRoot, api, link, tree, {
|
|
54
|
+
page,
|
|
55
|
+
component,
|
|
56
|
+
iteration,
|
|
57
|
+
targetFile: values.to,
|
|
58
|
+
publicDir: values.public
|
|
59
|
+
});
|
|
60
|
+
io.out(`Promoting ${page}/${component}/${iteration} to ${prepared.targetFile}.`);
|
|
61
|
+
for (const file of prepared.copied)
|
|
62
|
+
io.out(` Copied ${file}`);
|
|
63
|
+
if (prepared.wroteCopy)
|
|
64
|
+
io.out(` Wrote the approved copy to rough/${page}/${component}/copy.md`);
|
|
65
|
+
for (const asset of prepared.missing) {
|
|
66
|
+
io.out(` ! ${asset.file} is not in the ${asset.scope}; the prompt asks for a placeholder.`);
|
|
67
|
+
}
|
|
68
|
+
io.out(` Prompt: ${prepared.promptFile}`);
|
|
69
|
+
const instruction = handoffLine(prepared.promptFile);
|
|
70
|
+
let session = null;
|
|
71
|
+
try {
|
|
72
|
+
const { adapter, detection } = await chooseAgent(context, values.agent);
|
|
73
|
+
session = promoteSession(adapter, detection, repoRoot, { page, component, componentName: record.name }, prepared, values.model ?? null);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
io.err(error.message);
|
|
77
|
+
}
|
|
78
|
+
if (!session) {
|
|
79
|
+
io.out(`Give your agent this instruction in the repo: ${instruction}`);
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
const plan = planTerminal({
|
|
83
|
+
platform: context.platform,
|
|
84
|
+
env: context.env,
|
|
85
|
+
repoRoot,
|
|
86
|
+
sessions: [session]
|
|
87
|
+
});
|
|
88
|
+
if (plan.kind !== 'manual') {
|
|
89
|
+
try {
|
|
90
|
+
await context.launchTerminal(plan);
|
|
91
|
+
io.out(`Opened ${plan.terminal}. Review the diff when it is done; nothing is committed.`);
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
io.err(`${plan.terminal} could not be opened: ${error.message}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
io.out(plan.reason);
|
|
100
|
+
}
|
|
101
|
+
io.out(`Run this in a terminal: ${manualCommand(context.platform, repoRoot, session)}`);
|
|
102
|
+
return 0;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
//# sourceMappingURL=promote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promote.js","sourceRoot":"","sources":["../../src/commands/promote.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
import { localOrigin, readSettings } from '../config/settings.js';
|
|
3
|
+
import { requireRepoLink } from '../repo/link.js';
|
|
4
|
+
import { pullAdvice, pullSketch } from '../runs/pull.js';
|
|
5
|
+
import { requireApi } from './context.js';
|
|
6
|
+
import { parseComponent, parseIteration } from './shared.js';
|
|
7
|
+
export const pull = {
|
|
8
|
+
name: 'pull',
|
|
9
|
+
summary: 'Brings a web sketch into rough/ as a new local iteration, or lists what there is',
|
|
10
|
+
usage: 'pull <page>/<component>[/<sketch>]',
|
|
11
|
+
needsRepo: true,
|
|
12
|
+
async run(args, context) {
|
|
13
|
+
const { io } = context;
|
|
14
|
+
const { positionals } = parseArgs({ args, allowPositionals: true, options: {} });
|
|
15
|
+
const named = positionals[0] ?? '';
|
|
16
|
+
const repoRoot = context.repoRoot;
|
|
17
|
+
const link = await requireRepoLink(repoRoot);
|
|
18
|
+
const api = await requireApi(context);
|
|
19
|
+
if (named.split('/').length < 3) {
|
|
20
|
+
const { page, component } = parseComponent(named);
|
|
21
|
+
const sketches = await api.sketches(link.orgId, link.project, page, component);
|
|
22
|
+
if (!sketches.length) {
|
|
23
|
+
io.out(`${page}/${component} has no web sketches to pull.`);
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
io.out(`Web sketches of ${page}/${component}, newest first:`);
|
|
27
|
+
const width = Math.max(...sketches.map(sketch => sketch.id.length));
|
|
28
|
+
for (const sketch of sketches) {
|
|
29
|
+
const status = sketch.status === 'exploring' ? '' : ` (${sketch.status})`;
|
|
30
|
+
io.out(` ${sketch.id.padEnd(width)} ${sketch.name}${status}`);
|
|
31
|
+
}
|
|
32
|
+
io.out(`Pull one with roughbook pull ${page}/${component}/<sketch>.`);
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
const { page, component, iteration } = parseIteration(named);
|
|
36
|
+
const pulled = await pullSketch(repoRoot, api, link, { page, component, sketch: iteration }, { assetOrigin: localOrigin(await readSettings(context.configDir)) });
|
|
37
|
+
const count = pulled.files.length;
|
|
38
|
+
io.out(`${page}/${component}/${pulled.iteration}: ${pulled.folder}, from the web sketch ${pulled.parent} (${count} file${count === 1 ? '' : 's'})`);
|
|
39
|
+
for (const line of pullAdvice(pulled))
|
|
40
|
+
io.out(line);
|
|
41
|
+
io.out(`Review it in roughbook start, or refine it: roughbook run ${page}/${component} --refine ${pulled.iteration} --intent "<what to change>"`);
|
|
42
|
+
return 0;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=pull.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pull.js","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
import { revertFile } from '../runs/snapshot.js';
|
|
3
|
+
import { listRuns } from '../runs/store.js';
|
|
4
|
+
import { parseIteration } from './shared.js';
|
|
5
|
+
const SAID = {
|
|
6
|
+
restored: 'Put back as it was before the run.',
|
|
7
|
+
removed: 'Removed: the run created it.',
|
|
8
|
+
unchanged: 'Already as it was before the run.',
|
|
9
|
+
cannot: 'Cannot put it back: the studio kept no copy of it. Restore it from git or your editor.'
|
|
10
|
+
};
|
|
11
|
+
export const revert = {
|
|
12
|
+
name: 'revert',
|
|
13
|
+
summary: 'Put back a file a run changed outside its iteration',
|
|
14
|
+
usage: 'revert <page>/<component>/<iteration> <file>',
|
|
15
|
+
needsRepo: true,
|
|
16
|
+
async run(args, context) {
|
|
17
|
+
const { io } = context;
|
|
18
|
+
const { positionals } = parseArgs({ args, allowPositionals: true, options: {} });
|
|
19
|
+
const target = parseIteration(positionals[0]);
|
|
20
|
+
const file = (positionals[1] ?? '').replace(/\\/g, '/');
|
|
21
|
+
if (!file)
|
|
22
|
+
throw new Error('Name the file to put back, as roughbook done listed it.');
|
|
23
|
+
const run = (await listRuns(context.repoRoot)).find(item => item.page === target.page &&
|
|
24
|
+
item.component === target.component &&
|
|
25
|
+
item.iteration === target.iteration &&
|
|
26
|
+
item.status === 'finished');
|
|
27
|
+
if (!run) {
|
|
28
|
+
throw new Error(`No finished run made ${positionals[0]}. Run roughbook done first.`);
|
|
29
|
+
}
|
|
30
|
+
// Only what the run was flagged for: anything else is the designer's own work.
|
|
31
|
+
if (!run.outOfScope.includes(file)) {
|
|
32
|
+
throw new Error(`${file} is not among the files ${positionals[0]}'s run changed outside it.`);
|
|
33
|
+
}
|
|
34
|
+
const result = await revertFile(context.repoRoot, run.runId, file);
|
|
35
|
+
io.out(`${file}: ${SAID[result]}`);
|
|
36
|
+
return result === 'cannot' ? 1 : 0;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=revert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revert.js","sourceRoot":"","sources":["../../src/commands/revert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,IAAI,GAAG;IACX,QAAQ,EAAE,oCAAoC;IAC9C,OAAO,EAAE,8BAA8B;IACvC,SAAS,EAAE,mCAAmC;IAC9C,MAAM,EAAE,wFAAwF;CACxF,CAAC;AAEX,MAAM,CAAC,MAAM,MAAM,GAAY;IAC7B,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,qDAAqD;IAC9D,KAAK,EAAE,8CAA8C;IACrD,SAAS,EAAE,IAAI;IACf,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO;QACrB,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC;QACvB,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QACjF,MAAM,MAAM,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACxD,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;QAEtF,MAAM,GAAG,GAAG,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,QAAS,CAAC,CAAC,CAAC,IAAI,CAClD,IAAI,CAAC,EAAE,CACL,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI;YACzB,IAAI,CAAC,SAAS,KAAK,MAAM,CAAC,SAAS;YACnC,IAAI,CAAC,SAAS,KAAK,MAAM,CAAC,SAAS;YACnC,IAAI,CAAC,MAAM,KAAK,UAAU,CAC7B,CAAC;QACF,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,wBAAwB,WAAW,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC;QACvF,CAAC;QACD,+EAA+E;QAC/E,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,2BAA2B,WAAW,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC;QAChG,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,QAAS,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACpE,EAAE,CAAC,GAAG,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACnC,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrC,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
import { outboxFor } from '../api/outbox.js';
|
|
3
|
+
import { requireRepoLink } from '../repo/link.js';
|
|
4
|
+
import { sendDecision } from '../runs/reviews.js';
|
|
5
|
+
import { requireApi } from './context.js';
|
|
6
|
+
import { parseIteration } from './shared.js';
|
|
7
|
+
const DECISIONS = ['explore', 'refine', 'select', 'reject'];
|
|
8
|
+
export const review = {
|
|
9
|
+
name: 'review',
|
|
10
|
+
summary: 'Select, reject or note observations on a local iteration',
|
|
11
|
+
usage: 'review <page>/<component>/<iteration> (--select [--reason <text>] | --reject <reason> [--why <text>] | --note <observation>...)',
|
|
12
|
+
needsRepo: true,
|
|
13
|
+
async run(args, context) {
|
|
14
|
+
const { io } = context;
|
|
15
|
+
const { values, positionals } = parseArgs({
|
|
16
|
+
args,
|
|
17
|
+
allowPositionals: true,
|
|
18
|
+
options: {
|
|
19
|
+
select: { type: 'boolean', default: false },
|
|
20
|
+
reason: { type: 'string' },
|
|
21
|
+
reject: { type: 'string' },
|
|
22
|
+
why: { type: 'string' },
|
|
23
|
+
note: { type: 'string', multiple: true },
|
|
24
|
+
decision: { type: 'string' }
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
const target = parseIteration(positionals[0]);
|
|
28
|
+
const asked = [values.select, values.reject !== undefined, Boolean(values.note?.length)];
|
|
29
|
+
if (asked.filter(Boolean).length !== 1) {
|
|
30
|
+
throw new Error('Choose one: --select, --reject "<reason>", or --note "<observation>".');
|
|
31
|
+
}
|
|
32
|
+
let decision;
|
|
33
|
+
if (values.select) {
|
|
34
|
+
decision = { kind: 'select', reason: values.reason };
|
|
35
|
+
}
|
|
36
|
+
else if (values.reject !== undefined) {
|
|
37
|
+
if (!values.reject.trim())
|
|
38
|
+
throw new Error('A rejection needs a reason; it teaches the next prompt.');
|
|
39
|
+
decision = { kind: 'reject', reason: values.reject, why: values.why };
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
const wanted = values.decision;
|
|
43
|
+
if (wanted !== undefined && !DECISIONS.includes(wanted)) {
|
|
44
|
+
throw new Error(`--decision is one of ${DECISIONS.join(', ')}.`);
|
|
45
|
+
}
|
|
46
|
+
decision = {
|
|
47
|
+
kind: 'review',
|
|
48
|
+
observations: values.note,
|
|
49
|
+
...(wanted ? { decision: wanted } : {}),
|
|
50
|
+
...(values.reason ? { reason: values.reason } : {})
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const repoRoot = context.repoRoot;
|
|
54
|
+
const result = await sendDecision(await requireApi(context), outboxFor(repoRoot), await requireRepoLink(repoRoot), target, decision);
|
|
55
|
+
if (result.status === 'queued') {
|
|
56
|
+
io.out('Saved in the outbox; it goes to the server when it can be reached.');
|
|
57
|
+
return 0;
|
|
58
|
+
}
|
|
59
|
+
if (decision.kind === 'select') {
|
|
60
|
+
// Selecting the selected iteration clears the selection, as on the web.
|
|
61
|
+
const iterations = Array.isArray(result.data)
|
|
62
|
+
? result.data
|
|
63
|
+
: [];
|
|
64
|
+
const now = iterations.find(item => item.id === target.iteration)?.status;
|
|
65
|
+
io.out(now === 'selected' ? `${target.iteration} is selected.` : 'The selection is cleared.');
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
io.out(decision.kind === 'reject' ? `${target.iteration} is rejected.` : 'Review saved.');
|
|
69
|
+
}
|
|
70
|
+
return 0;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=review.js.map
|