@illuminis/comprism 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 +15 -0
- package/README.md +281 -0
- package/out/agent/command.d.ts +86 -0
- package/out/agent/command.js +259 -0
- package/out/agent/render.d.ts +97 -0
- package/out/agent/render.js +255 -0
- package/out/agent/session.d.ts +175 -0
- package/out/agent/session.js +573 -0
- package/out/commands/ask.d.ts +1 -0
- package/out/commands/ask.js +146 -0
- package/out/commands/codemap.d.ts +2 -0
- package/out/commands/codemap.js +151 -0
- package/out/commands/commands-thin.d.ts +39 -0
- package/out/commands/commands-thin.js +182 -0
- package/out/commands/install.d.ts +163 -0
- package/out/commands/install.js +543 -0
- package/out/commands/keys.d.ts +55 -0
- package/out/commands/keys.js +344 -0
- package/out/commands/login.d.ts +9 -0
- package/out/commands/login.js +384 -0
- package/out/commands/repl.d.ts +1 -0
- package/out/commands/repl.js +752 -0
- package/out/commands/settings.d.ts +21 -0
- package/out/commands/settings.js +244 -0
- package/out/commands/welcome.d.ts +1 -0
- package/out/commands/welcome.js +196 -0
- package/out/executor/documents.d.ts +40 -0
- package/out/executor/documents.js +170 -0
- package/out/executor/files.d.ts +2 -0
- package/out/executor/files.js +360 -0
- package/out/executor/git.d.ts +48 -0
- package/out/executor/git.js +132 -0
- package/out/executor/hooks.d.ts +67 -0
- package/out/executor/hooks.js +247 -0
- package/out/executor/index.d.ts +29 -0
- package/out/executor/index.js +221 -0
- package/out/executor/notebook.d.ts +2 -0
- package/out/executor/notebook.js +147 -0
- package/out/executor/paths.d.ts +15 -0
- package/out/executor/paths.js +126 -0
- package/out/executor/shell.d.ts +41 -0
- package/out/executor/shell.js +336 -0
- package/out/graph/build.d.ts +45 -0
- package/out/graph/build.js +91 -0
- package/out/graph/facts.d.ts +47 -0
- package/out/graph/facts.js +12 -0
- package/out/graph/files.d.ts +45 -0
- package/out/graph/files.js +207 -0
- package/out/graph/read-locales.d.ts +29 -0
- package/out/graph/read-locales.js +246 -0
- package/out/graph/read-python.d.ts +11 -0
- package/out/graph/read-python.js +115 -0
- package/out/graph/read-typescript.d.ts +16 -0
- package/out/graph/read-typescript.js +292 -0
- package/out/graph/sync.d.ts +66 -0
- package/out/graph/sync.js +242 -0
- package/out/lib/attach.d.ts +62 -0
- package/out/lib/attach.js +228 -0
- package/out/lib/config.d.ts +93 -0
- package/out/lib/config.js +198 -0
- package/out/lib/connection.d.ts +73 -0
- package/out/lib/connection.js +188 -0
- package/out/lib/gateway.d.ts +239 -0
- package/out/lib/gateway.js +171 -0
- package/out/lib/prompt.d.ts +34 -0
- package/out/lib/prompt.js +108 -0
- package/out/lib/types.d.ts +417 -0
- package/out/lib/types.js +21 -0
- package/out/lib/ui.d.ts +114 -0
- package/out/lib/ui.js +265 -0
- package/out/lib/version.d.ts +24 -0
- package/out/lib/version.js +27 -0
- package/out/lib/voice.d.ts +50 -0
- package/out/lib/voice.js +218 -0
- package/out/postinstall.d.ts +2 -0
- package/out/postinstall.js +92 -0
- package/out/thin.d.ts +2 -0
- package/out/thin.js +259 -0
- package/package.json +101 -0
- package/scripts/read_python.py +270 -0
|
@@ -0,0 +1,384 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.workspaceUrl = workspaceUrl;
|
|
40
|
+
exports.cmdLogin = cmdLogin;
|
|
41
|
+
/**
|
|
42
|
+
* `comprism login` — the whole sign in, asked one question at a time.
|
|
43
|
+
*
|
|
44
|
+
* ── Why this replaced what was there ──────────────────────────────────────
|
|
45
|
+
*
|
|
46
|
+
* Signing in used to mean typing this, correctly, from memory:
|
|
47
|
+
*
|
|
48
|
+
* comprism connect --url https://base-tenant.completionprism.illuminis.ai --email you@company.com
|
|
49
|
+
*
|
|
50
|
+
* A new customer does not know their workspace address, has never seen that
|
|
51
|
+
* flag, and gets no second chance at a first impression. Worse, if their
|
|
52
|
+
* account required a second factor the command refused outright and told them
|
|
53
|
+
* to go and find a token in a browser, which meant the terminal product was
|
|
54
|
+
* unreachable for every account a security team had done the right thing to.
|
|
55
|
+
*
|
|
56
|
+
* So: one word, then two questions, then the code if their account asks for one.
|
|
57
|
+
*
|
|
58
|
+
* comprism login
|
|
59
|
+
* email: you@acme.com
|
|
60
|
+
* password: ••••••••
|
|
61
|
+
* code: 123456
|
|
62
|
+
*
|
|
63
|
+
* THE WORKSPACE IS NOT ASKED FOR. It is looked up from the email's domain,
|
|
64
|
+
* which the product already does for the browser sign in: a domain maps to at
|
|
65
|
+
* most one workspace, enforced by a unique index, so there is never a choice to
|
|
66
|
+
* put in front of anybody. An unknown domain, which is what a personal email
|
|
67
|
+
* is, resolves to the shared individuals workspace, because that is exactly
|
|
68
|
+
* where signing up puts it.
|
|
69
|
+
*
|
|
70
|
+
* The lookup reads the workspace registry and never the user list, so it cannot
|
|
71
|
+
* be used to find out who has an account.
|
|
72
|
+
*
|
|
73
|
+
* `--workspace` still works, for a person whose company runs a workspace under
|
|
74
|
+
* a domain that is not in their email, and for our own testing.
|
|
75
|
+
*/
|
|
76
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
77
|
+
const connection_1 = require("../lib/connection");
|
|
78
|
+
const gateway_1 = require("../lib/gateway");
|
|
79
|
+
const ui = __importStar(require("../lib/ui"));
|
|
80
|
+
const prompt_1 = require("../lib/prompt");
|
|
81
|
+
const out = (s = '') => process.stdout.write(s + '\n');
|
|
82
|
+
/** Where a named workspace lives. One format, stated once. */
|
|
83
|
+
const WORKSPACE_DOMAIN = 'completionprism.illuminis.ai';
|
|
84
|
+
/**
|
|
85
|
+
* Turn what a person typed into the address of their workspace.
|
|
86
|
+
*
|
|
87
|
+
* Accepts the workspace name, which is the normal case, and also a full URL or
|
|
88
|
+
* a bare host, because somebody who was given a link will paste the link. All
|
|
89
|
+
* three arrive at the same place rather than at an error message.
|
|
90
|
+
*/
|
|
91
|
+
function workspaceUrl(typed) {
|
|
92
|
+
const value = typed.trim().replace(/\/+$/, '');
|
|
93
|
+
if (/^https?:\/\//i.test(value))
|
|
94
|
+
return value;
|
|
95
|
+
// A host with a port, or a machine on this network, is already an address.
|
|
96
|
+
// Without this, `localhost:8009` had our domain appended to it and the
|
|
97
|
+
// command reported a network problem for what was really a parsing one.
|
|
98
|
+
if (/^(localhost|127\.0\.0\.1)(:\d+)?$/i.test(value))
|
|
99
|
+
return `http://${value}`;
|
|
100
|
+
if (value.includes(':'))
|
|
101
|
+
return `http://${value}`;
|
|
102
|
+
if (value.includes('.'))
|
|
103
|
+
return `https://${value}`;
|
|
104
|
+
return `https://${value}.${WORKSPACE_DOMAIN}`;
|
|
105
|
+
}
|
|
106
|
+
/** Localhost needs the tenant named, because there is no subdomain to read. */
|
|
107
|
+
function tenantFor(url, typed, flagged) {
|
|
108
|
+
if (flagged)
|
|
109
|
+
return flagged;
|
|
110
|
+
if (!/localhost|127\.0\.0\.1/.test(url))
|
|
111
|
+
return undefined;
|
|
112
|
+
// There is no subdomain on a local address to read the tenant from, so the
|
|
113
|
+
// developer tenant is assumed unless one was named.
|
|
114
|
+
return 'base-tenant';
|
|
115
|
+
}
|
|
116
|
+
async function post(url, path, body, tenant) {
|
|
117
|
+
const headers = { 'content-type': 'application/json' };
|
|
118
|
+
if (tenant)
|
|
119
|
+
headers['X-Tenant-ID'] = tenant;
|
|
120
|
+
const res = await fetch(`${url}${path}`, {
|
|
121
|
+
method: 'POST', headers, body: JSON.stringify(body),
|
|
122
|
+
});
|
|
123
|
+
let json = {};
|
|
124
|
+
try {
|
|
125
|
+
json = (await res.json());
|
|
126
|
+
}
|
|
127
|
+
catch { /* non-JSON body */ }
|
|
128
|
+
return { status: res.status, json };
|
|
129
|
+
}
|
|
130
|
+
async function runLogin(args) {
|
|
131
|
+
out(ui.banner('Sign in'));
|
|
132
|
+
out();
|
|
133
|
+
// Flags still work, for a script or a second machine. A person gets asked.
|
|
134
|
+
const flag = (name) => {
|
|
135
|
+
const i = args.indexOf(name);
|
|
136
|
+
return i >= 0 ? args[i + 1] : undefined;
|
|
137
|
+
};
|
|
138
|
+
const username = flag('--username') || flag('--email') || await (0, prompt_1.ask)(' email: ');
|
|
139
|
+
if (!username) {
|
|
140
|
+
out(ui.fail('An email address is needed.'));
|
|
141
|
+
out();
|
|
142
|
+
process.exitCode = 1;
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
// Where this person's workspace is. Asked of the product, not of them.
|
|
146
|
+
let typedWorkspace = flag('--workspace');
|
|
147
|
+
// Captured BEFORE the email lookup can fill it in. A workspace the product
|
|
148
|
+
// worked out is not a workspace the person typed, and only the second may be
|
|
149
|
+
// a local address. See the fence in `writeConnection`.
|
|
150
|
+
const typedByHand = Boolean(typedWorkspace);
|
|
151
|
+
if (!typedWorkspace) {
|
|
152
|
+
const live = new ui.LiveIndicator();
|
|
153
|
+
live.start('finding your workspace');
|
|
154
|
+
typedWorkspace = (await resolveWorkspace(username)) || undefined;
|
|
155
|
+
live.stop();
|
|
156
|
+
// The indicator clears its own line but leaves the cursor mid-row, so the
|
|
157
|
+
// next prompt landed after a run of blanks.
|
|
158
|
+
process.stdout.write('\r');
|
|
159
|
+
if (!typedWorkspace) {
|
|
160
|
+
out();
|
|
161
|
+
out(ui.fail('No workspace is registered for that email address.'));
|
|
162
|
+
out(` ${ui.c.dim('if your company uses a different domain, pass --workspace <name>')}`);
|
|
163
|
+
out();
|
|
164
|
+
process.exitCode = 1;
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const url = workspaceUrl(typedWorkspace);
|
|
169
|
+
const tenant = tenantFor(url, typedWorkspace, flag('--tenant'));
|
|
170
|
+
const password = await (0, prompt_1.askHidden)(' password: ');
|
|
171
|
+
if (!password) {
|
|
172
|
+
out(ui.fail('A password is needed.'));
|
|
173
|
+
out();
|
|
174
|
+
process.exitCode = 1;
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
// EVERYTHING BELOW GOES THROUGH THE ONE SERVICE.
|
|
178
|
+
//
|
|
179
|
+
// This used to call three separate addresses in sequence: sign in, second
|
|
180
|
+
// factor, then machine enrollment. Three doors for one act, and the tool had
|
|
181
|
+
// to know the order to knock on them in, which is product logic living on a
|
|
182
|
+
// customer's laptop. It is now one question, asked twice only when a second
|
|
183
|
+
// factor is genuinely required.
|
|
184
|
+
let signedIn = null;
|
|
185
|
+
let signInMessage = '';
|
|
186
|
+
{
|
|
187
|
+
let reply = await (0, gateway_1.askAt)(url, {
|
|
188
|
+
intent: 'sign_in', prompt: username, password,
|
|
189
|
+
machineLabel: `comprism on ${node_os_1.default.hostname()}`,
|
|
190
|
+
}, tenant);
|
|
191
|
+
if (reply.served === false) {
|
|
192
|
+
out();
|
|
193
|
+
out(ui.fail('That workspace is running a build that cannot sign you in yet.'));
|
|
194
|
+
out(` ${ui.c.dim(reply.message || 'the workspace is behind this copy of the tool')}`);
|
|
195
|
+
out();
|
|
196
|
+
process.exitCode = 1;
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (!reply.ok) {
|
|
200
|
+
out();
|
|
201
|
+
out(ui.fail(`Could not reach ${url}.`));
|
|
202
|
+
out(` ${ui.c.dim('check the workspace name, and that you are on the network')}`);
|
|
203
|
+
out();
|
|
204
|
+
process.exitCode = 1;
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
// A second factor is a normal ANSWER, not a failure. This is the whole
|
|
208
|
+
// reason the command exists: an older one gave up here and sent people to a
|
|
209
|
+
// browser to find a token by hand.
|
|
210
|
+
if (reply.sign_in?.needs_second_factor && reply.sign_in.challenge) {
|
|
211
|
+
out();
|
|
212
|
+
out(ui.info('This account uses a second step. Check your authenticator app or your email.'));
|
|
213
|
+
const code = await (0, prompt_1.ask)(' code: ');
|
|
214
|
+
if (!code) {
|
|
215
|
+
out(ui.fail('A code is needed to finish signing in.'));
|
|
216
|
+
out();
|
|
217
|
+
process.exitCode = 1;
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
reply = await (0, gateway_1.askAt)(url, {
|
|
221
|
+
intent: 'sign_in', prompt: username,
|
|
222
|
+
challenge: reply.sign_in.challenge, code,
|
|
223
|
+
machineLabel: `comprism on ${node_os_1.default.hostname()}`,
|
|
224
|
+
}, tenant);
|
|
225
|
+
if (!reply.ok || !reply.sign_in?.token) {
|
|
226
|
+
out();
|
|
227
|
+
out(ui.fail(reply.message || 'That code was not accepted. Codes expire after a few minutes.'));
|
|
228
|
+
out();
|
|
229
|
+
process.exitCode = 1;
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (!reply.sign_in?.token) {
|
|
234
|
+
out();
|
|
235
|
+
out(ui.fail(reply.message || 'That username and password were not accepted.'));
|
|
236
|
+
out(` ${ui.c.dim('check the workspace name too: a right password in the wrong workspace looks the same')}`);
|
|
237
|
+
out();
|
|
238
|
+
process.exitCode = 1;
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
signedIn = reply.sign_in;
|
|
242
|
+
signInMessage = reply.message || '';
|
|
243
|
+
if (reply.complete === false && reply.message) {
|
|
244
|
+
// Signed in, but something about it is incomplete. Said, not swallowed.
|
|
245
|
+
out();
|
|
246
|
+
out(ui.warn(reply.message));
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
const token = signedIn?.token;
|
|
250
|
+
if (!token) {
|
|
251
|
+
out();
|
|
252
|
+
out(ui.fail('Sign in succeeded but no session came back.'));
|
|
253
|
+
out();
|
|
254
|
+
process.exitCode = 1;
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
// Enrol the machine while we still hold the session, so signing in is one
|
|
258
|
+
// step rather than a sign in followed by something else to remember.
|
|
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.
|
|
263
|
+
const existing = (0, connection_1.readConnection)();
|
|
264
|
+
// The key this sign in just issued wins.
|
|
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;
|
|
282
|
+
// `typedByHand` is the second half of the fence in `writeConnection`. It is
|
|
283
|
+
// true only when the person put the address on this command line, in this
|
|
284
|
+
// run. A workspace resolved from their email domain, or an address a server
|
|
285
|
+
// handed back, can never install a laptop address however convincingly it
|
|
286
|
+
// asks.
|
|
287
|
+
try {
|
|
288
|
+
(0, connection_1.writeConnection)({
|
|
289
|
+
// The address the SERVER says it answers on, UNLESS the person named one
|
|
290
|
+
// themselves on this command line.
|
|
291
|
+
//
|
|
292
|
+
// Preferring the server is right for everybody who did not type an
|
|
293
|
+
// address: a tool that stores its own guess can never be told by anybody
|
|
294
|
+
// that the guess was wrong, which is how a machine sat pointed at a dead
|
|
295
|
+
// port for an evening. It is exactly wrong for somebody who DID type one.
|
|
296
|
+
// They typed it because they meant it, and the server, being asked where
|
|
297
|
+
// it lives, answers with its public address and quietly replaces the one
|
|
298
|
+
// they chose. That made testing a change against a local copy impossible:
|
|
299
|
+
// sign in, and the tool went straight back to production.
|
|
300
|
+
url: (typedByHand && url) || signedIn?.workspace_url || url,
|
|
301
|
+
token,
|
|
302
|
+
...(tenant ? { tenant } : {}),
|
|
303
|
+
...(workspaceKey ? { workspaceKey } : {}),
|
|
304
|
+
everyMinutes: existing?.everyMinutes ?? 5,
|
|
305
|
+
connectedAt: existing?.connectedAt || new Date().toISOString(),
|
|
306
|
+
}, typedByHand);
|
|
307
|
+
}
|
|
308
|
+
catch (err) {
|
|
309
|
+
out();
|
|
310
|
+
out(ui.fail(err instanceof Error ? err.message : 'the workspace address was refused'));
|
|
311
|
+
out();
|
|
312
|
+
process.exitCode = 1;
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
out();
|
|
316
|
+
out(ui.ok(`Signed in to ${ui.c.bold(url)}`));
|
|
317
|
+
if (workspaceKey) {
|
|
318
|
+
out(` ${ui.c.dim('this machine is enrolled and revocable on its own')}`);
|
|
319
|
+
// Straight into the welcome screen, so the first thing after signing in is
|
|
320
|
+
// where they are rather than another instruction.
|
|
321
|
+
const { showWelcome } = await Promise.resolve().then(() => __importStar(require('./welcome')));
|
|
322
|
+
await showWelcome();
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
out(ui.warn('Signed in, but this machine could not be enrolled.'));
|
|
326
|
+
// The workspace's OWN reason, carried back with the sign in. It used to
|
|
327
|
+
// come from a local variable set by a separate call, which meant a blank
|
|
328
|
+
// line whenever that call had not been the thing that failed.
|
|
329
|
+
out(` ${ui.c.dim(signInMessage || 'the workspace did not say why')}`);
|
|
330
|
+
out(` ${ui.c.dim('you are signed in; this machine cannot ask for work until it is enrolled')}`);
|
|
331
|
+
}
|
|
332
|
+
out();
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Which workspace an email belongs to.
|
|
336
|
+
*
|
|
337
|
+
* Asked of the app root, which is tenant-agnostic by design and serves this
|
|
338
|
+
* exact question for the browser sign in. Returns the workspace name, or null
|
|
339
|
+
* when the product cannot place the address.
|
|
340
|
+
*/
|
|
341
|
+
async function resolveWorkspace(email) {
|
|
342
|
+
// ONE root, and it is production.
|
|
343
|
+
//
|
|
344
|
+
// This list used to put `http://localhost:8009` first whenever COMPRISM_DEV
|
|
345
|
+
// was set. An environment variable exported once, in a shell profile or by a
|
|
346
|
+
// test, then silently redirected every future sign in on that machine to a
|
|
347
|
+
// port that is usually not listening. That is half of how a developer's own
|
|
348
|
+
// machine came to be pointed at his laptop on 17 September 2026, reporting
|
|
349
|
+
// that his account had no keys while four were stored and active.
|
|
350
|
+
//
|
|
351
|
+
// Working against a local server is still supported and is now something a
|
|
352
|
+
// person SAYS rather than something an environment does to them:
|
|
353
|
+
// `comprism login --workspace localhost:8009`.
|
|
354
|
+
// ASKED OF THE ONE SERVICE, at the product's own address.
|
|
355
|
+
//
|
|
356
|
+
// This used to post to the authentication route directly, which made the
|
|
357
|
+
// lookup a second door the tool had to know about and knock on in the right
|
|
358
|
+
// order. It is now an intent like every other, answered without a credential
|
|
359
|
+
// because a person looking for their workspace does not have one yet.
|
|
360
|
+
const root = `https://${WORKSPACE_DOMAIN}`;
|
|
361
|
+
const reply = await (0, gateway_1.askAt)(root, { intent: 'resolve_workspace', prompt: email });
|
|
362
|
+
if (!reply.ok || reply.served === false)
|
|
363
|
+
return null;
|
|
364
|
+
const url = reply.session?.workspace_url;
|
|
365
|
+
if (!url)
|
|
366
|
+
return null;
|
|
367
|
+
try {
|
|
368
|
+
// The answer is a sign-in address. Its host is the workspace address.
|
|
369
|
+
return new URL(url).host;
|
|
370
|
+
}
|
|
371
|
+
catch {
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
async function cmdLogin(args) {
|
|
376
|
+
try {
|
|
377
|
+
await runLogin(args);
|
|
378
|
+
}
|
|
379
|
+
finally {
|
|
380
|
+
// Always, on every path. A reader left open holds the terminal and the
|
|
381
|
+
// command appears to hang after it has finished its work.
|
|
382
|
+
(0, prompt_1.closePrompt)();
|
|
383
|
+
}
|
|
384
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runRepl(): Promise<void>;
|