@illuminis/comprism 0.1.2 → 0.1.4
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/README.md +98 -36
- package/out/agent/command.d.ts +75 -4
- package/out/agent/command.js +220 -25
- package/out/agent/render.d.ts +17 -2
- package/out/agent/render.js +157 -14
- package/out/agent/session.d.ts +141 -2
- package/out/agent/session.js +735 -149
- package/out/commands/agents.d.ts +2 -0
- package/out/commands/agents.js +79 -0
- package/out/commands/ask.d.ts +1 -1
- package/out/commands/ask.js +78 -11
- package/out/commands/commands-thin.js +79 -17
- package/out/commands/config.d.ts +1 -0
- package/out/commands/config.js +138 -0
- package/out/commands/cost.d.ts +1 -0
- package/out/commands/cost.js +167 -0
- package/out/commands/hooks.d.ts +1 -0
- package/out/commands/hooks.js +83 -0
- package/out/commands/install.d.ts +44 -1
- package/out/commands/install.js +198 -4
- package/out/commands/instructions.d.ts +1 -0
- package/out/commands/instructions.js +113 -0
- package/out/commands/integrations.d.ts +3 -0
- package/out/commands/integrations.js +215 -0
- package/out/commands/jobs.d.ts +5 -0
- package/out/commands/jobs.js +157 -0
- package/out/commands/login.js +188 -36
- package/out/commands/memory.d.ts +3 -0
- package/out/commands/memory.js +113 -0
- package/out/commands/permissions.d.ts +1 -0
- package/out/commands/permissions.js +94 -0
- package/out/commands/plugins.d.ts +4 -0
- package/out/commands/plugins.js +192 -0
- package/out/commands/privacy.d.ts +1 -0
- package/out/commands/privacy.js +57 -0
- package/out/commands/providerKey.d.ts +32 -0
- package/out/commands/providerKey.js +108 -0
- package/out/commands/repl.d.ts +8 -1
- package/out/commands/repl.js +1207 -118
- package/out/commands/report.d.ts +39 -0
- package/out/commands/report.js +115 -0
- package/out/commands/review.d.ts +5 -0
- package/out/commands/review.js +223 -0
- package/out/commands/sessions.d.ts +23 -0
- package/out/commands/sessions.js +115 -0
- package/out/commands/settings.d.ts +3 -1
- package/out/commands/settings.js +18 -16
- package/out/commands/skills.d.ts +21 -0
- package/out/commands/skills.js +207 -0
- package/out/commands/unattended.d.ts +7 -0
- package/out/commands/unattended.js +351 -0
- package/out/commands/update.d.ts +1 -0
- package/out/commands/update.js +123 -0
- package/out/commands/worktrees.d.ts +5 -0
- package/out/commands/worktrees.js +186 -0
- package/out/executor/browser.d.ts +14 -0
- package/out/executor/browser.js +270 -0
- package/out/executor/diagnostics.d.ts +2 -0
- package/out/executor/diagnostics.js +181 -0
- package/out/executor/files.js +270 -40
- package/out/executor/git.js +42 -29
- package/out/executor/hooks.d.ts +42 -58
- package/out/executor/hooks.js +89 -182
- package/out/executor/index.d.ts +21 -5
- package/out/executor/index.js +160 -14
- package/out/executor/paths.d.ts +6 -1
- package/out/executor/paths.js +34 -6
- package/out/executor/sandbox.d.ts +40 -0
- package/out/executor/sandbox.js +299 -0
- package/out/executor/shell.d.ts +49 -4
- package/out/executor/shell.js +302 -56
- package/out/executor/toolservers.d.ts +20 -0
- package/out/executor/toolservers.js +189 -0
- package/out/executor/worktree.d.ts +9 -0
- package/out/executor/worktree.js +119 -0
- package/out/graph/read-python.js +2 -1
- package/out/lib/attach.d.ts +56 -12
- package/out/lib/attach.js +230 -63
- package/out/lib/clipboard.d.ts +23 -0
- package/out/lib/clipboard.js +182 -0
- package/out/lib/commandlist.d.ts +20 -0
- package/out/lib/commandlist.js +58 -0
- package/out/lib/decision.d.ts +22 -0
- package/out/lib/decision.js +50 -0
- package/out/lib/fingerprint.d.ts +25 -0
- package/out/lib/fingerprint.js +58 -0
- package/out/lib/gateway.d.ts +186 -2
- package/out/lib/gateway.js +59 -4
- package/out/lib/history.d.ts +24 -0
- package/out/lib/history.js +137 -0
- package/out/lib/ide.d.ts +19 -0
- package/out/lib/ide.js +131 -0
- package/out/lib/keyboard.d.ts +95 -0
- package/out/lib/keyboard.js +383 -0
- package/out/lib/machine.d.ts +21 -0
- package/out/lib/machine.js +91 -0
- package/out/lib/notify.d.ts +4 -0
- package/out/lib/notify.js +52 -0
- package/out/lib/output.d.ts +48 -0
- package/out/lib/output.js +108 -0
- package/out/lib/project-ops.d.ts +19 -0
- package/out/lib/project-ops.js +146 -0
- package/out/lib/project.d.ts +28 -0
- package/out/lib/project.js +114 -0
- package/out/lib/prompt.js +15 -2
- package/out/lib/queue.d.ts +13 -0
- package/out/lib/queue.js +116 -0
- package/out/lib/readiness.d.ts +19 -0
- package/out/lib/readiness.js +170 -1
- package/out/lib/self.d.ts +23 -0
- package/out/lib/self.js +124 -0
- package/out/lib/sessions.d.ts +19 -0
- package/out/lib/sessions.js +221 -0
- package/out/lib/stdin.d.ts +32 -0
- package/out/lib/stdin.js +117 -0
- package/out/lib/store.d.ts +40 -0
- package/out/lib/store.js +138 -0
- package/out/lib/sync.d.ts +18 -0
- package/out/lib/sync.js +81 -0
- package/out/lib/ui.d.ts +2 -4
- package/out/lib/ui.js +31 -25
- package/out/lib/voice.js +24 -0
- package/out/postinstall.js +42 -14
- package/out/providers/anthropic.d.ts +22 -0
- package/out/providers/anthropic.js +80 -0
- package/out/providers/index.d.ts +8 -0
- package/out/providers/index.js +83 -0
- package/out/providers/openai.d.ts +11 -0
- package/out/providers/openai.js +57 -0
- package/out/thin.js +609 -21
- package/package.json +9 -49
package/out/commands/login.js
CHANGED
|
@@ -127,7 +127,113 @@ async function post(url, path, body, tenant) {
|
|
|
127
127
|
catch { /* non-JSON body */ }
|
|
128
128
|
return { status: res.status, json };
|
|
129
129
|
}
|
|
130
|
+
const DEVICE_GRANT = 'urn:ietf:params:oauth:grant-type:device_code';
|
|
131
|
+
/** The built in public client the portal accepts for this product's CLI. */
|
|
132
|
+
const CLIENT_ID = 'completionprism-cli';
|
|
133
|
+
function headersFor(tenant) {
|
|
134
|
+
return tenant ? { 'X-Tenant-ID': tenant } : {};
|
|
135
|
+
}
|
|
136
|
+
/** Whether this workspace's company signs in through its own identity provider. */
|
|
137
|
+
async function usesCompanyLogin(url, tenant) {
|
|
138
|
+
try {
|
|
139
|
+
const res = await fetch(`${url}/api/v1/auth/sso/providers`, { headers: headersFor(tenant) });
|
|
140
|
+
if (!res.ok)
|
|
141
|
+
return false;
|
|
142
|
+
const body = await res.json();
|
|
143
|
+
return (body.providers?.length ?? 0) > 0 && body.password_enabled === false;
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function openInBrowser(address) {
|
|
150
|
+
const { spawn } = require('node:child_process');
|
|
151
|
+
const [cmd, argv] = process.platform === 'darwin' ? ['open', [address]]
|
|
152
|
+
: process.platform === 'win32' ? ['cmd', ['/c', 'start', '', address]]
|
|
153
|
+
: ['xdg-open', [address]];
|
|
154
|
+
try {
|
|
155
|
+
spawn(cmd, argv, { stdio: 'ignore', detached: true }).on('error', () => { }).unref();
|
|
156
|
+
}
|
|
157
|
+
catch { /* the address is printed as well */ }
|
|
158
|
+
}
|
|
159
|
+
/** The portal's own device sign in: approve in a browser, get a token back. */
|
|
160
|
+
async function approveInBrowser(url, tenant, noBrowser) {
|
|
161
|
+
const form = (fields) => ({
|
|
162
|
+
method: 'POST',
|
|
163
|
+
headers: { ...headersFor(tenant), 'content-type': 'application/x-www-form-urlencoded' },
|
|
164
|
+
body: new URLSearchParams(fields).toString(),
|
|
165
|
+
});
|
|
166
|
+
let started;
|
|
167
|
+
try {
|
|
168
|
+
const res = await fetch(`${url}/oauth/device_authorization`, form({ client_id: CLIENT_ID, scope: 'api:read api:write' }));
|
|
169
|
+
if (!res.ok) {
|
|
170
|
+
out(ui.fail(res.status === 404 || res.status === 405
|
|
171
|
+
? 'That workspace is running a build without browser sign in.'
|
|
172
|
+
: 'The workspace would not start a browser sign in.'));
|
|
173
|
+
return '';
|
|
174
|
+
}
|
|
175
|
+
started = await res.json();
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
out(ui.fail(`Could not reach ${url}. Check your connection and try again.`));
|
|
179
|
+
return '';
|
|
180
|
+
}
|
|
181
|
+
out();
|
|
182
|
+
if (noBrowser) {
|
|
183
|
+
out(` On any device, open ${ui.c.bold(started.verification_uri)}`);
|
|
184
|
+
out(` and enter the code ${ui.c.bold(started.user_code)}`);
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
out(ui.info('Your company signs in through its own login page. Opening your browser.'));
|
|
188
|
+
out(` If it does not open, go to ${started.verification_uri_complete}`);
|
|
189
|
+
out(` and confirm the code ${ui.c.bold(started.user_code)}`);
|
|
190
|
+
openInBrowser(started.verification_uri_complete);
|
|
191
|
+
}
|
|
192
|
+
out(ui.c.dim(' waiting for you to approve it there...'));
|
|
193
|
+
const deadline = Date.now() + Math.max(30, started.expires_in || 600) * 1000;
|
|
194
|
+
let wait = Math.max(1, started.interval || 5);
|
|
195
|
+
while (Date.now() < deadline) {
|
|
196
|
+
await new Promise((r) => setTimeout(r, wait * 1000));
|
|
197
|
+
let res;
|
|
198
|
+
try {
|
|
199
|
+
res = await fetch(`${url}/oauth/token`, form({ grant_type: DEVICE_GRANT, device_code: started.device_code, client_id: CLIENT_ID }));
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
const body = await res.json().catch(() => ({}));
|
|
205
|
+
if (res.ok && body.access_token)
|
|
206
|
+
return body.access_token;
|
|
207
|
+
if (body.error === 'authorization_pending')
|
|
208
|
+
continue;
|
|
209
|
+
if (body.error === 'slow_down') {
|
|
210
|
+
wait += 5;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
out(ui.fail(body.error === 'access_denied' ? 'The sign in was declined in the browser.'
|
|
214
|
+
: 'That sign in was not approved.'));
|
|
215
|
+
return '';
|
|
216
|
+
}
|
|
217
|
+
out(ui.fail('That code expired before it was approved. Run comprism login again.'));
|
|
218
|
+
return '';
|
|
219
|
+
}
|
|
130
220
|
async function runLogin(args) {
|
|
221
|
+
// SIGN IN WITH AN INSTALL KEY (web manual 12.1). The key made on the
|
|
222
|
+
// Install and setup page is this machine's credential, so setup is the one
|
|
223
|
+
// command the page shows and nothing is typed. It needs no terminal, because
|
|
224
|
+
// the install script runs it on a pipe.
|
|
225
|
+
const keyAt = args.indexOf('--key');
|
|
226
|
+
if (keyAt >= 0)
|
|
227
|
+
return loginWithKey(args[keyAt + 1], args);
|
|
228
|
+
// Password and second factor entry require a person at a terminal. Do not
|
|
229
|
+
// open readline on a pipe: it can wait forever, or exit successfully at EOF
|
|
230
|
+
// without signing in. Check before workspace lookup or reading credentials.
|
|
231
|
+
if (process.stdin.isTTY !== true) {
|
|
232
|
+
out(ui.fail('Signing in requires an interactive terminal.'));
|
|
233
|
+
out(' Run comprism login in a terminal, then run your command again.');
|
|
234
|
+
process.exitCode = 1;
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
131
237
|
out(ui.banner('Sign in'));
|
|
132
238
|
out();
|
|
133
239
|
// Flags still work, for a script or a second machine. A person gets asked.
|
|
@@ -151,8 +257,12 @@ async function runLogin(args) {
|
|
|
151
257
|
if (!typedWorkspace) {
|
|
152
258
|
const live = new ui.LiveIndicator();
|
|
153
259
|
live.start('finding your workspace');
|
|
154
|
-
|
|
155
|
-
|
|
260
|
+
try {
|
|
261
|
+
typedWorkspace = (await resolveWorkspace(username)) || undefined;
|
|
262
|
+
}
|
|
263
|
+
finally {
|
|
264
|
+
live.stop();
|
|
265
|
+
}
|
|
156
266
|
// The indicator clears its own line but leaves the cursor mid-row, so the
|
|
157
267
|
// next prompt landed after a run of blanks.
|
|
158
268
|
process.stdout.write('\r');
|
|
@@ -167,8 +277,23 @@ async function runLogin(args) {
|
|
|
167
277
|
}
|
|
168
278
|
const url = workspaceUrl(typedWorkspace);
|
|
169
279
|
const tenant = tenantFor(url, typedWorkspace, flag('--tenant'));
|
|
170
|
-
|
|
171
|
-
|
|
280
|
+
// Said before the password is asked for, so a person can see which company
|
|
281
|
+
// they are about to sign in to (manual 1.3).
|
|
282
|
+
out(` workspace: ${url}`);
|
|
283
|
+
// COMPANY LOGIN (manual 1.10). A workspace whose company signs in through
|
|
284
|
+
// its own identity provider is signed in to in a browser; this tool never
|
|
285
|
+
// sees that password. `--device` is the same thing for a machine with no
|
|
286
|
+
// browser: a short code to approve from any other device.
|
|
287
|
+
const byCompany = args.includes('--device') || args.includes('--browser')
|
|
288
|
+
|| await usesCompanyLogin(url, tenant);
|
|
289
|
+
const deviceToken = byCompany ? await approveInBrowser(url, tenant, args.includes('--device')) : '';
|
|
290
|
+
if (byCompany && !deviceToken) {
|
|
291
|
+
out();
|
|
292
|
+
process.exitCode = 1;
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
const password = byCompany ? '' : await (0, prompt_1.askHidden)(' password: ');
|
|
296
|
+
if (!byCompany && !password) {
|
|
172
297
|
out(ui.fail('A password is needed.'));
|
|
173
298
|
out();
|
|
174
299
|
process.exitCode = 1;
|
|
@@ -185,7 +310,7 @@ async function runLogin(args) {
|
|
|
185
310
|
let signInMessage = '';
|
|
186
311
|
{
|
|
187
312
|
let reply = await (0, gateway_1.askAt)(url, {
|
|
188
|
-
intent: 'sign_in', prompt: username, password,
|
|
313
|
+
intent: 'sign_in', prompt: username, password, deviceToken,
|
|
189
314
|
machineLabel: `comprism on ${node_os_1.default.hostname()}`,
|
|
190
315
|
}, tenant);
|
|
191
316
|
if (reply.served === false) {
|
|
@@ -198,8 +323,9 @@ async function runLogin(args) {
|
|
|
198
323
|
}
|
|
199
324
|
if (!reply.ok) {
|
|
200
325
|
out();
|
|
201
|
-
out(ui.fail(
|
|
202
|
-
|
|
326
|
+
out(ui.fail(reply.httpStatus
|
|
327
|
+
? (reply.message || 'The service refused the sign in request.')
|
|
328
|
+
: `Could not reach ${url}. Check your connection and try again.`));
|
|
203
329
|
out();
|
|
204
330
|
process.exitCode = 1;
|
|
205
331
|
return;
|
|
@@ -210,7 +336,7 @@ async function runLogin(args) {
|
|
|
210
336
|
if (reply.sign_in?.needs_second_factor && reply.sign_in.challenge) {
|
|
211
337
|
out();
|
|
212
338
|
out(ui.info('This account uses a second step. Check your authenticator app or your email.'));
|
|
213
|
-
const code = await (0, prompt_1.
|
|
339
|
+
const code = await (0, prompt_1.askHidden)(' code from your authenticator app: ');
|
|
214
340
|
if (!code) {
|
|
215
341
|
out(ui.fail('A code is needed to finish signing in.'));
|
|
216
342
|
out();
|
|
@@ -254,31 +380,10 @@ async function runLogin(args) {
|
|
|
254
380
|
process.exitCode = 1;
|
|
255
381
|
return;
|
|
256
382
|
}
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
// The machine credential came back WITH the sign in, from the one service,
|
|
260
|
-
// which is why there is no second call here any more. An existing one is
|
|
261
|
-
// kept: signing in twice must not leave two entries in the workspace's own
|
|
262
|
-
// list of machines.
|
|
383
|
+
// A previous credential may belong to another account or workspace, or
|
|
384
|
+
// have been revoked during this sign in. Only retain the newly issued key.
|
|
263
385
|
const existing = (0, connection_1.readConnection)();
|
|
264
|
-
|
|
265
|
-
//
|
|
266
|
-
// This used to prefer whatever was already on the machine, so that signing
|
|
267
|
-
// in twice did not leave two entries in the workspace's own list of
|
|
268
|
-
// machines. The rule was right for the same person signing in again and
|
|
269
|
-
// wrong for every other case: sign in as a different account, or into a
|
|
270
|
-
// different workspace, and the machine carried on holding the OLD key. The
|
|
271
|
-
// sign in reported success, the header then said the workspace could not be
|
|
272
|
-
// reached, and nothing anywhere said that the credential belonged to
|
|
273
|
-
// somebody else. A revoked key behaved the same way.
|
|
274
|
-
//
|
|
275
|
-
// The server already ends the previous credential for this machine when it
|
|
276
|
-
// issues one, so taking the new key does not leave two live. The old one is
|
|
277
|
-
// kept only when the server issued nothing at all, which is the case where
|
|
278
|
-
// there is nothing better to hold.
|
|
279
|
-
const workspaceKey = signedIn?.machine_credential
|
|
280
|
-
|| existing?.workspaceKey
|
|
281
|
-
|| undefined;
|
|
386
|
+
const workspaceKey = signedIn?.machine_credential || undefined;
|
|
282
387
|
// `typedByHand` is the second half of the fence in `writeConnection`. It is
|
|
283
388
|
// true only when the person put the address on this command line, in this
|
|
284
389
|
// run. A workspace resolved from their email domain, or an address a server
|
|
@@ -312,16 +417,20 @@ async function runLogin(args) {
|
|
|
312
417
|
process.exitCode = 1;
|
|
313
418
|
return;
|
|
314
419
|
}
|
|
420
|
+
// So a new terminal presents the key just issued, not the last one or none.
|
|
421
|
+
for (const profile of (await Promise.resolve().then(() => __importStar(require('./install')))).finishSetup())
|
|
422
|
+
out(` Finishing setup: added one line to ${profile}`);
|
|
315
423
|
out();
|
|
316
|
-
out(ui.ok(`Signed in
|
|
424
|
+
out(ui.ok(`Signed in as ${ui.c.bold(username)} at ${ui.c.bold(signedIn?.workspace_url || url)}.`));
|
|
317
425
|
if (workspaceKey) {
|
|
318
|
-
out(` ${ui.c.dim('
|
|
426
|
+
out(` ${ui.c.dim('This machine is enrolled and can be revoked from Administration.')}`);
|
|
319
427
|
// Straight into the welcome screen, so the first thing after signing in is
|
|
320
428
|
// where they are rather than another instruction.
|
|
321
429
|
const { showWelcome } = await Promise.resolve().then(() => __importStar(require('./welcome')));
|
|
322
430
|
await showWelcome();
|
|
323
431
|
}
|
|
324
432
|
else {
|
|
433
|
+
process.exitCode = 1;
|
|
325
434
|
out(ui.warn('Signed in, but this machine could not be enrolled.'));
|
|
326
435
|
// The workspace's OWN reason, carried back with the sign in. It used to
|
|
327
436
|
// come from a local variable set by a separate call, which meant a blank
|
|
@@ -331,6 +440,48 @@ async function runLogin(args) {
|
|
|
331
440
|
}
|
|
332
441
|
out();
|
|
333
442
|
}
|
|
443
|
+
/** Enrol this machine with an install key: checked with the service, then kept. */
|
|
444
|
+
async function loginWithKey(key, args) {
|
|
445
|
+
const flag = (name) => {
|
|
446
|
+
const i = args.indexOf(name);
|
|
447
|
+
return i >= 0 ? args[i + 1] : undefined;
|
|
448
|
+
};
|
|
449
|
+
const typed = flag('--workspace');
|
|
450
|
+
if (!key || !typed) {
|
|
451
|
+
out(ui.fail('Signing in with a key needs the key and the workspace: comprism login --key <key> --workspace <address>'));
|
|
452
|
+
process.exitCode = 1;
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
const url = workspaceUrl(typed);
|
|
456
|
+
const tenant = tenantFor(url, typed, flag('--tenant'));
|
|
457
|
+
const { ask: askWith } = await Promise.resolve().then(() => __importStar(require('../lib/gateway')));
|
|
458
|
+
const existing = (0, connection_1.readConnection)();
|
|
459
|
+
try {
|
|
460
|
+
(0, connection_1.writeConnection)({
|
|
461
|
+
url, token: '', workspaceKey: key, ...(tenant ? { tenant } : {}),
|
|
462
|
+
everyMinutes: existing?.everyMinutes ?? 5,
|
|
463
|
+
connectedAt: new Date().toISOString(),
|
|
464
|
+
}, true);
|
|
465
|
+
}
|
|
466
|
+
catch (err) {
|
|
467
|
+
out(ui.fail(err instanceof Error ? err.message : 'the workspace address was refused'));
|
|
468
|
+
process.exitCode = 1;
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
const reply = await askWith({ intent: 'catalog', prompt: '' });
|
|
472
|
+
if (!reply.ok) {
|
|
473
|
+
if (existing)
|
|
474
|
+
(0, connection_1.writeConnection)(existing, true);
|
|
475
|
+
out(ui.fail(reply.message || `That key was not accepted by ${url}.`));
|
|
476
|
+
out(` ${ui.c.dim('make a new one on the Install and setup page')}`);
|
|
477
|
+
process.exitCode = 1;
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
for (const profile of (await Promise.resolve().then(() => __importStar(require('./install')))).finishSetup())
|
|
481
|
+
out(` Finishing setup: added one line to ${profile}`);
|
|
482
|
+
out(ui.ok(`This machine is enrolled at ${ui.c.bold(url)}.`));
|
|
483
|
+
out(` ${ui.c.dim('It can be revoked from Developers, Install and setup.')}`);
|
|
484
|
+
}
|
|
334
485
|
/**
|
|
335
486
|
* Which workspace an email belongs to.
|
|
336
487
|
*
|
|
@@ -359,8 +510,9 @@ async function resolveWorkspace(email) {
|
|
|
359
510
|
// because a person looking for their workspace does not have one yet.
|
|
360
511
|
const root = `https://${WORKSPACE_DOMAIN}`;
|
|
361
512
|
const reply = await (0, gateway_1.askAt)(root, { intent: 'resolve_workspace', prompt: email });
|
|
362
|
-
if (!reply.ok || reply.served === false)
|
|
363
|
-
|
|
513
|
+
if (!reply.ok || reply.served === false || reply.complete === false) {
|
|
514
|
+
throw new Error(reply.message || 'Your workspace could not be looked up. Try again later.');
|
|
515
|
+
}
|
|
364
516
|
const url = reply.session?.workspace_url;
|
|
365
517
|
if (!url)
|
|
366
518
|
return null;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.addNote = addNote;
|
|
37
|
+
exports.cmdMemory = cmdMemory;
|
|
38
|
+
/**
|
|
39
|
+
* `comprism memory` (manual 2.9): this project's notes. They are files under
|
|
40
|
+
* `.completionprism/memory/`; this command lists them, and adds, removes and
|
|
41
|
+
* opens them as the service says. Which notes are used, numbering and every
|
|
42
|
+
* word shown are the service's.
|
|
43
|
+
*/
|
|
44
|
+
const fs = __importStar(require("node:fs"));
|
|
45
|
+
const path = __importStar(require("node:path"));
|
|
46
|
+
const project_ops_1 = require("../lib/project-ops");
|
|
47
|
+
const ui = __importStar(require("../lib/ui"));
|
|
48
|
+
const out = (s = "") => process.stdout.write(s + "\n");
|
|
49
|
+
const FOLDER = ".completionprism/memory";
|
|
50
|
+
const SETTINGS_FILES = [".completionprism/settings.local.json", ".completionprism/settings.json"];
|
|
51
|
+
function notes(root) {
|
|
52
|
+
let names = [];
|
|
53
|
+
try {
|
|
54
|
+
names = fs.readdirSync(path.join(root, FOLDER)).filter((n) => n.endsWith(".md")).sort();
|
|
55
|
+
}
|
|
56
|
+
catch { /* none yet */ }
|
|
57
|
+
return names
|
|
58
|
+
.map((n) => ({ file: `${FOLDER}/${n}`, text: (0, project_ops_1.readInside)(root, `${FOLDER}/${n}`) ?? "" }))
|
|
59
|
+
.filter((n) => n.text.trim());
|
|
60
|
+
}
|
|
61
|
+
/** Carry out what the service said to write or delete, inside the project. */
|
|
62
|
+
function apply(facts, data) {
|
|
63
|
+
const write = data?.write;
|
|
64
|
+
if (write?.key)
|
|
65
|
+
(0, project_ops_1.writeSetting)(facts.root, write.file, write.key, write.value);
|
|
66
|
+
else if (write?.file && typeof write.content === "string") {
|
|
67
|
+
const full = path.join(facts.root, write.file);
|
|
68
|
+
fs.mkdirSync(path.dirname(full), { recursive: true });
|
|
69
|
+
fs.writeFileSync(full, write.content);
|
|
70
|
+
}
|
|
71
|
+
const gone = data?.delete;
|
|
72
|
+
if (typeof gone === "string" && gone.startsWith(`${FOLDER}/`))
|
|
73
|
+
fs.rmSync(path.join(facts.root, gone), { force: true });
|
|
74
|
+
}
|
|
75
|
+
/** `comprism memory add` and the session word `remember`. */
|
|
76
|
+
async function addNote(text) {
|
|
77
|
+
const facts = await (0, project_ops_1.currentProject)();
|
|
78
|
+
const reply = await (0, project_ops_1.call)("memory", "add", { text }, facts);
|
|
79
|
+
if (!reply)
|
|
80
|
+
return 1;
|
|
81
|
+
apply(facts, reply.data);
|
|
82
|
+
return 0;
|
|
83
|
+
}
|
|
84
|
+
async function cmdMemory(args) {
|
|
85
|
+
const [verb, ...rest] = args;
|
|
86
|
+
const facts = await (0, project_ops_1.currentProject)();
|
|
87
|
+
const base = { notes: notes(facts.root), files: (0, project_ops_1.readSome)(facts.root, SETTINGS_FILES) };
|
|
88
|
+
if (verb === "add")
|
|
89
|
+
return addNote(rest.join(" "));
|
|
90
|
+
if (verb === "edit") {
|
|
91
|
+
const files = base.notes.map((n) => path.join(facts.root, n.file));
|
|
92
|
+
if (!files.length) {
|
|
93
|
+
out(ui.info('No notes yet. Add one with: comprism memory add "<text>"'));
|
|
94
|
+
return 0;
|
|
95
|
+
}
|
|
96
|
+
return (await (0, project_ops_1.openEditor)(files)) ? 0 : 1;
|
|
97
|
+
}
|
|
98
|
+
if (verb === "forget" || verb === "on" || verb === "off") {
|
|
99
|
+
const reply = await (0, project_ops_1.call)("memory", verb, { ...base, number: rest[0] }, facts);
|
|
100
|
+
if (!reply)
|
|
101
|
+
return 1;
|
|
102
|
+
apply(facts, reply.data);
|
|
103
|
+
return 0;
|
|
104
|
+
}
|
|
105
|
+
if (verb) {
|
|
106
|
+
out(ui.fail(`\`memory ${verb}\` is not a command. Use add, edit, forget N, on or off.`));
|
|
107
|
+
return 2;
|
|
108
|
+
}
|
|
109
|
+
out();
|
|
110
|
+
const reply = await (0, project_ops_1.call)("memory", "list", base, facts);
|
|
111
|
+
out();
|
|
112
|
+
return reply ? 0 : 1;
|
|
113
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function cmdPermissions(args: string[]): Promise<number>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.cmdPermissions = cmdPermissions;
|
|
37
|
+
/**
|
|
38
|
+
* `comprism permissions` and `comprism permissions why <action> "<target>"`
|
|
39
|
+
* (manual 4.14).
|
|
40
|
+
*
|
|
41
|
+
* This reads the project's settings files and sends their text; the service
|
|
42
|
+
* decides and writes every line printed, with the same decision the agent's
|
|
43
|
+
* jobs use, so `why` and a real job can never disagree.
|
|
44
|
+
*/
|
|
45
|
+
const fs = __importStar(require("node:fs"));
|
|
46
|
+
const path = __importStar(require("node:path"));
|
|
47
|
+
const gateway_1 = require("../lib/gateway");
|
|
48
|
+
const ui = __importStar(require("../lib/ui"));
|
|
49
|
+
const sessions_1 = require("../lib/sessions");
|
|
50
|
+
/** The settings files that can hold rules, relative to the project root. The
|
|
51
|
+
* service decides which of them count and how. */
|
|
52
|
+
const RULE_FILES = [
|
|
53
|
+
'.completionprism/settings.json', '.completionprism/settings.local.json',
|
|
54
|
+
'.comprism/settings.json', '.comprism/settings.local.json',
|
|
55
|
+
];
|
|
56
|
+
const USAGE = 'Usage: comprism permissions, or comprism permissions why <action> "<target>"';
|
|
57
|
+
async function cmdPermissions(args) {
|
|
58
|
+
const [op, action, ...rest] = args;
|
|
59
|
+
if (op && op !== 'why') {
|
|
60
|
+
process.stderr.write(` ${USAGE}\n`);
|
|
61
|
+
return 2;
|
|
62
|
+
}
|
|
63
|
+
if (op === 'why' && (!action || rest.length === 0)) {
|
|
64
|
+
process.stderr.write(` ${USAGE}\n`);
|
|
65
|
+
return 2;
|
|
66
|
+
}
|
|
67
|
+
const { resolveProject, asWire } = await Promise.resolve().then(() => __importStar(require('../lib/project')));
|
|
68
|
+
const { currentWorkspace } = await Promise.resolve().then(() => __importStar(require('./settings')));
|
|
69
|
+
const facts = resolveProject(currentWorkspace().path, []);
|
|
70
|
+
const files = {};
|
|
71
|
+
for (const rel of RULE_FILES) {
|
|
72
|
+
try {
|
|
73
|
+
files[rel] = fs.readFileSync(path.join(facts.root, rel), 'utf8');
|
|
74
|
+
}
|
|
75
|
+
catch { /* none */ }
|
|
76
|
+
}
|
|
77
|
+
const reply = await (0, gateway_1.ask)({
|
|
78
|
+
intent: 'permissions',
|
|
79
|
+
prompt: '',
|
|
80
|
+
project: asWire(facts),
|
|
81
|
+
permissionsPayload: {
|
|
82
|
+
op: op === 'why' ? 'why' : 'list', action, target: rest.join(' '), files,
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
const lines = reply.permissions?.lines;
|
|
86
|
+
if (!reply.ok || !Array.isArray(lines)) {
|
|
87
|
+
process.stderr.write(ui.fail(reply.served === false
|
|
88
|
+
? 'Your workspace is running a build without permission answers yet.'
|
|
89
|
+
: (0, sessions_1.failure)(reply)) + '\n');
|
|
90
|
+
return (0, sessions_1.exitFor)(reply);
|
|
91
|
+
}
|
|
92
|
+
process.stdout.write(`${lines.join('\n')}\n`);
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Every text file in the folder, by path inside it. Never runs anything. */
|
|
2
|
+
export declare function readFolder(dir: string): Record<string, string>;
|
|
3
|
+
export declare const PLUGINS_HELP = " comprism plugins installed plugins and their state\n comprism plugins install <name|folder> install from your company's catalog or a folder\n --scope project|personal skip the question\n comprism plugins enable <name> comprism plugins disable <name>\n comprism plugins update <name> shows what changes, then asks\n comprism plugins remove <name>";
|
|
4
|
+
export declare function cmdPlugins(args: string[]): Promise<number>;
|