@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,344 @@
|
|
|
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.keyState = keyState;
|
|
40
|
+
exports.hasAnyKey = hasAnyKey;
|
|
41
|
+
exports.cmdKeys = cmdKeys;
|
|
42
|
+
/**
|
|
43
|
+
* `comprism keys` — the provider keys, and the one thing the product cannot
|
|
44
|
+
* work without.
|
|
45
|
+
*
|
|
46
|
+
* ── Why a key is not optional ─────────────────────────────────────────────
|
|
47
|
+
*
|
|
48
|
+
* Every answer is billed to the CUSTOMER'S OWN provider account. That is the
|
|
49
|
+
* whole basis of the product's claim: a saving on somebody else's bill is a
|
|
50
|
+
* marketing number, and a saving on your own bill is an invoice you can check.
|
|
51
|
+
*
|
|
52
|
+
* So with no key there is nothing to run and nothing to measure. A person in
|
|
53
|
+
* that state is not "partly set up", they are stopped, and the product says so
|
|
54
|
+
* and takes them straight here rather than letting them discover it one
|
|
55
|
+
* refused prompt at a time.
|
|
56
|
+
*
|
|
57
|
+
* ── Two ways in, because people keep their secrets differently ────────────
|
|
58
|
+
*
|
|
59
|
+
* PASTE ONE. Pick a vendor, paste the key. It goes once, over TLS, to the
|
|
60
|
+
* workspace, is checked with the vendor before it is kept, and is never
|
|
61
|
+
* written to this machine.
|
|
62
|
+
*
|
|
63
|
+
* POINT AT A FILE. Many developers already keep their keys in an environment
|
|
64
|
+
* file. Naming that file is faster than pasting four keys, and the file never
|
|
65
|
+
* leaves the machine: it is read here and the values are sent the same way.
|
|
66
|
+
*/
|
|
67
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
68
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
69
|
+
const prompt_1 = require("../lib/prompt");
|
|
70
|
+
const gateway_1 = require("../lib/gateway");
|
|
71
|
+
const ui = __importStar(require("../lib/ui"));
|
|
72
|
+
const out = (s = '') => process.stdout.write(s + '\n');
|
|
73
|
+
/**
|
|
74
|
+
* The vendors, and the environment variable each one is conventionally kept in.
|
|
75
|
+
*
|
|
76
|
+
* Named here rather than fetched, because these are OUR OWN vendor names and
|
|
77
|
+
* the standard variable names their own documentation uses. Neither is model
|
|
78
|
+
* logic and neither changes when a price does.
|
|
79
|
+
*/
|
|
80
|
+
const PROVIDERS = [
|
|
81
|
+
{ key: 'anthropic', label: 'Anthropic', env: 'ANTHROPIC_API_KEY' },
|
|
82
|
+
{ key: 'openai', label: 'OpenAI', env: 'OPENAI_API_KEY' },
|
|
83
|
+
{ key: 'google', label: 'Google', env: 'GOOGLE_GEMINI_API_KEY' },
|
|
84
|
+
{ key: 'xai', label: 'xAI', env: 'GROK_API_KEY' },
|
|
85
|
+
];
|
|
86
|
+
/**
|
|
87
|
+
* What the workspace says it can reach.
|
|
88
|
+
*
|
|
89
|
+
* **The workspace is the only source of truth.** This function does not look at
|
|
90
|
+
* the machine, and no caller may treat a key found on the machine as an answer
|
|
91
|
+
* to this question. A key sitting in somebody's shell is not a key the account
|
|
92
|
+
* holds: it works for that one shell, it is invisible to the portal, to the
|
|
93
|
+
* editor and to their colleagues, and a product that counts it tells four
|
|
94
|
+
* different people four different things about the same account.
|
|
95
|
+
*
|
|
96
|
+
* The machine is still SEARCHED, but only in `offerLocalImport` below, and only
|
|
97
|
+
* once this has answered `{ reached: true, hasKey: false }`. That is the owner's
|
|
98
|
+
* rule of 17 September 2026: look on the computer when the account has nothing,
|
|
99
|
+
* and when something is found, store it on the server through the one service.
|
|
100
|
+
*/
|
|
101
|
+
async function keyState() {
|
|
102
|
+
const reply = await (0, gateway_1.ask)({ intent: 'catalog', prompt: '' });
|
|
103
|
+
// `ok` is false when we never heard from the workspace. Every other field is
|
|
104
|
+
// then this client's placeholder, and reading an empty `providers` as "no
|
|
105
|
+
// keys" is precisely the fault above.
|
|
106
|
+
if (!reply.ok)
|
|
107
|
+
return { reached: false, why: reply.message || 'the workspace could not be reached' };
|
|
108
|
+
// An older workspace that does not serve this question has also not told us
|
|
109
|
+
// there are no keys. It has told us it cannot answer.
|
|
110
|
+
if (reply.served === false)
|
|
111
|
+
return { reached: false, why: reply.message || 'this workspace is running an older build' };
|
|
112
|
+
// The workspace answered but could not establish part of what it answered.
|
|
113
|
+
// An empty vendor list here is a list we failed to obtain, not a list of
|
|
114
|
+
// nothing, and drawing it as "you have no keys" is the original fault with
|
|
115
|
+
// one more layer in front of it.
|
|
116
|
+
if (reply.complete === false)
|
|
117
|
+
return { reached: false, why: reply.message || 'your workspace could not check its vendor keys' };
|
|
118
|
+
return { reached: true, hasKey: reply.providers.some((p) => p.has_key) };
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Kept for callers that genuinely only need a yes.
|
|
122
|
+
*
|
|
123
|
+
* Unreachable counts as NO here, and every caller must have already reported
|
|
124
|
+
* the unreachable case in its own words before calling this. Prefer `keyState`.
|
|
125
|
+
*/
|
|
126
|
+
async function hasAnyKey() {
|
|
127
|
+
const state = await keyState();
|
|
128
|
+
return state.reached && state.hasKey;
|
|
129
|
+
}
|
|
130
|
+
/** Read `NAME=value` pairs out of an environment file. Comments ignored. */
|
|
131
|
+
function readEnvFile(file) {
|
|
132
|
+
const found = {};
|
|
133
|
+
for (const line of node_fs_1.default.readFileSync(file, 'utf8').split('\n')) {
|
|
134
|
+
const trimmed = line.trim();
|
|
135
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
136
|
+
continue;
|
|
137
|
+
const eq = trimmed.indexOf('=');
|
|
138
|
+
if (eq < 1)
|
|
139
|
+
continue;
|
|
140
|
+
const name = trimmed.slice(0, eq).replace(/^export\s+/, '').trim();
|
|
141
|
+
// Surrounding quotes are a shell convention, not part of the value.
|
|
142
|
+
const value = trimmed.slice(eq + 1).trim().replace(/^["']|["']$/g, '');
|
|
143
|
+
if (name && value)
|
|
144
|
+
found[name] = value;
|
|
145
|
+
}
|
|
146
|
+
return found;
|
|
147
|
+
}
|
|
148
|
+
async function store(provider, label, value) {
|
|
149
|
+
const live = new ui.LiveIndicator();
|
|
150
|
+
live.start(`checking the key with ${label}`);
|
|
151
|
+
const reply = await (0, gateway_1.ask)({ intent: 'store_key', prompt: '', provider, key: value });
|
|
152
|
+
live.stop();
|
|
153
|
+
process.stdout.write('\r');
|
|
154
|
+
if (reply.stored) {
|
|
155
|
+
out(ui.ok(`${label} key stored and confirmed working.`));
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
out(ui.fail(`${label}: ${reply.message || 'the key was not accepted'}`));
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
/** Show which vendors this workspace can already reach. */
|
|
162
|
+
/**
|
|
163
|
+
* How a vendor's name is written, as the vendor writes it.
|
|
164
|
+
*
|
|
165
|
+
* The workspace returns a machine name and title-cases it, which turns `openai`
|
|
166
|
+
* into "Openai" and `xai` into "Xai". Neither company spells itself that way,
|
|
167
|
+
* and a product that misspells its suppliers' names on the first screen a
|
|
168
|
+
* developer sees looks like it was assembled rather than built.
|
|
169
|
+
*/
|
|
170
|
+
function vendorLabel(providerKey, fallback) {
|
|
171
|
+
const known = PROVIDERS.find((p) => p.key === providerKey.toLowerCase());
|
|
172
|
+
return known ? known.label : fallback;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* The vendor list, and whether the account holds a key for each.
|
|
176
|
+
*
|
|
177
|
+
* Returns how many are stored, so the caller can tell "all set" from "nothing
|
|
178
|
+
* set" without asking the workspace a second time.
|
|
179
|
+
*/
|
|
180
|
+
async function show() {
|
|
181
|
+
const reply = await (0, gateway_1.ask)({ intent: 'catalog', prompt: '' });
|
|
182
|
+
if (!reply.ok || reply.served === false || reply.complete === false) {
|
|
183
|
+
// NOT "you have no keys". We did not get an answer, so nothing is known
|
|
184
|
+
// about this account, and saying otherwise is the 17 September fault.
|
|
185
|
+
out(ui.fail('Your workspace could not be reached, so nothing is known about your keys.'));
|
|
186
|
+
out(` ${ui.c.dim(reply.message || reply.decision.rationale || 'no answer from the workspace')}`);
|
|
187
|
+
out();
|
|
188
|
+
return { reached: false, stored: 0, total: 0 };
|
|
189
|
+
}
|
|
190
|
+
if (reply.providers.length === 0) {
|
|
191
|
+
// A workspace with no vendors at all is not a workspace that told us it
|
|
192
|
+
// holds no keys. Treated as unreachable so no caller offers to take one.
|
|
193
|
+
out(ui.fail('Your workspace returned no vendors, so nothing is known about your keys.'));
|
|
194
|
+
out(` ${ui.c.dim(reply.message || 'the vendor list came back empty')}`);
|
|
195
|
+
out();
|
|
196
|
+
return { reached: false, stored: 0, total: 0 };
|
|
197
|
+
}
|
|
198
|
+
for (const p of reply.providers) {
|
|
199
|
+
out(` ${p.has_key ? ui.c.green('stored ') : ui.c.dim('none ')} ${vendorLabel(p.provider, p.label)}`);
|
|
200
|
+
}
|
|
201
|
+
out();
|
|
202
|
+
return {
|
|
203
|
+
reached: true,
|
|
204
|
+
stored: reply.providers.filter((p) => p.has_key).length,
|
|
205
|
+
total: reply.providers.length,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
async function cmdKeys(args) {
|
|
209
|
+
out(ui.banner('Provider keys'));
|
|
210
|
+
out();
|
|
211
|
+
out(ui.c.dim(' Every answer is billed to your own provider account, so your saving'));
|
|
212
|
+
out(ui.c.dim(' is a figure on your own invoice rather than a claim of ours.'));
|
|
213
|
+
out();
|
|
214
|
+
const state = await show();
|
|
215
|
+
// Point at a file, either named on the line or asked for. Always honored
|
|
216
|
+
// when it was ASKED FOR: somebody replacing a key that has been rotated is
|
|
217
|
+
// doing something perfectly reasonable, and this is the only path that adds
|
|
218
|
+
// one, so refusing it because keys already exist would be refusing the job.
|
|
219
|
+
const fileFlag = args.indexOf('--file');
|
|
220
|
+
if (fileFlag >= 0 || args.includes('--from-file')) {
|
|
221
|
+
const named = fileFlag >= 0 ? args[fileFlag + 1] : undefined;
|
|
222
|
+
return fromFile(named);
|
|
223
|
+
}
|
|
224
|
+
// Nothing was reachable. Offering to take a key here is the exact fault
|
|
225
|
+
// reported on 17 September: a person with four working keys was asked to
|
|
226
|
+
// paste one because the product could not ask the account and drew the
|
|
227
|
+
// silence as an absence.
|
|
228
|
+
if (!state.reached) {
|
|
229
|
+
out(` ${ui.c.dim('check the address with')} ${ui.c.bold('comprism status')}${ui.c.dim(', or sign in again with')} ${ui.c.bold('comprism login')}`);
|
|
230
|
+
out();
|
|
231
|
+
process.exitCode = 1;
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
// Every vendor already has a key. There is nothing to do, so the command
|
|
235
|
+
// says so and stops rather than walking somebody through a form to replace
|
|
236
|
+
// something that is working. Rule set by the owner, 17 September 2026: look
|
|
237
|
+
// on the computer only when the ACCOUNT has none.
|
|
238
|
+
if (state.total > 0 && state.stored === state.total) {
|
|
239
|
+
out(` ${ui.c.green('Every vendor has a key stored on your account.')}`);
|
|
240
|
+
out(` ${ui.c.dim('to replace one, run')} ${ui.c.bold('comprism keys --file <path>')}${ui.c.dim(', or add it in the portal')}`);
|
|
241
|
+
out();
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
out(` ${ui.c.dim('1')}. paste a key for one vendor`);
|
|
245
|
+
out(` ${ui.c.dim('2')}. point at a file that already holds your keys`);
|
|
246
|
+
out();
|
|
247
|
+
const how = await (0, prompt_1.ask)(' 1 or 2: ');
|
|
248
|
+
if (how === '2') {
|
|
249
|
+
(0, prompt_1.closePrompt)();
|
|
250
|
+
return fromFile(undefined);
|
|
251
|
+
}
|
|
252
|
+
PROVIDERS.forEach((p, i) => out(` ${String(i + 1).padStart(2)}. ${p.label}`));
|
|
253
|
+
out();
|
|
254
|
+
const pick = await (0, prompt_1.ask)(' vendor: ');
|
|
255
|
+
const chosen = PROVIDERS[Number(pick) - 1]
|
|
256
|
+
|| PROVIDERS.find((p) => p.key === pick.toLowerCase()
|
|
257
|
+
|| p.label.toLowerCase() === pick.toLowerCase());
|
|
258
|
+
if (!chosen) {
|
|
259
|
+
(0, prompt_1.closePrompt)();
|
|
260
|
+
out(ui.fail(`"${pick}" is not one of the vendors above.`));
|
|
261
|
+
out();
|
|
262
|
+
process.exitCode = 1;
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
// Hidden, like a password. A key pasted in the clear sits in the scrollback
|
|
266
|
+
// of a terminal somebody else may be looking at.
|
|
267
|
+
const value = await (0, prompt_1.askHidden)(` ${chosen.label} key: `);
|
|
268
|
+
(0, prompt_1.closePrompt)();
|
|
269
|
+
if (!value) {
|
|
270
|
+
out(ui.fail('Nothing was pasted.'));
|
|
271
|
+
out();
|
|
272
|
+
process.exitCode = 1;
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
out();
|
|
276
|
+
const ok = await store(chosen.key, chosen.label, value);
|
|
277
|
+
out();
|
|
278
|
+
if (!ok)
|
|
279
|
+
process.exitCode = 1;
|
|
280
|
+
}
|
|
281
|
+
async function fromFile(named) {
|
|
282
|
+
let file = named;
|
|
283
|
+
if (!file) {
|
|
284
|
+
// The two places almost everybody keeps them, offered rather than guessed.
|
|
285
|
+
const guesses = ['.env', node_path_1.default.join(process.env.HOME || '', '.env')]
|
|
286
|
+
.filter((f) => node_fs_1.default.existsSync(f));
|
|
287
|
+
if (guesses.length) {
|
|
288
|
+
out(ui.c.dim(` found: ${guesses.join(' ')}`));
|
|
289
|
+
}
|
|
290
|
+
file = await (0, prompt_1.ask)(' file holding your keys: ');
|
|
291
|
+
(0, prompt_1.closePrompt)();
|
|
292
|
+
}
|
|
293
|
+
if (!file) {
|
|
294
|
+
out(ui.fail('No file named.'));
|
|
295
|
+
out();
|
|
296
|
+
process.exitCode = 1;
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
const resolved = node_path_1.default.resolve(file.replace(/^~/, process.env.HOME || '~'));
|
|
300
|
+
if (!node_fs_1.default.existsSync(resolved)) {
|
|
301
|
+
out(ui.fail(`There is no file at ${resolved}.`));
|
|
302
|
+
out();
|
|
303
|
+
process.exitCode = 1;
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const values = readEnvFile(resolved);
|
|
307
|
+
const matched = PROVIDERS.filter((p) => values[p.env]);
|
|
308
|
+
if (matched.length === 0) {
|
|
309
|
+
out(ui.fail('That file holds no key this product recognizes.'));
|
|
310
|
+
out(` ${ui.c.dim(`looked for: ${PROVIDERS.map((p) => p.env).join(', ')}`)}`);
|
|
311
|
+
out();
|
|
312
|
+
process.exitCode = 1;
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
out();
|
|
316
|
+
out(ui.info(`${matched.length} key(s) found. Checking each one with its vendor.`));
|
|
317
|
+
out();
|
|
318
|
+
let kept = 0;
|
|
319
|
+
for (const p of matched) {
|
|
320
|
+
if (await store(p.key, p.label, values[p.env]))
|
|
321
|
+
kept += 1;
|
|
322
|
+
}
|
|
323
|
+
// NOTHING is remembered about where the file was.
|
|
324
|
+
//
|
|
325
|
+
// This used to write a shell command into the machine's own settings so a
|
|
326
|
+
// later run could re-read the key from that file. It was well meant and it
|
|
327
|
+
// was wrong: it taught the machine to go and fetch a vendor credential
|
|
328
|
+
// locally, which is the one behavior the owner ruled out on 17 September
|
|
329
|
+
// 2026. It also left a working instruction for reading a secret sitting in a
|
|
330
|
+
// settings file, worth nothing to us and something to anybody who gets the
|
|
331
|
+
// laptop.
|
|
332
|
+
//
|
|
333
|
+
// The keys are on the account now. That is the whole point of having sent
|
|
334
|
+
// them, and re-reading the file would be asking a question we already know
|
|
335
|
+
// the answer to.
|
|
336
|
+
out();
|
|
337
|
+
out(kept > 0
|
|
338
|
+
? ui.ok(`${kept} of ${matched.length} key(s) stored.`)
|
|
339
|
+
: ui.fail('No key in that file was accepted.'));
|
|
340
|
+
out(` ${ui.c.dim(`the file itself never left this machine; only the values did, once, over TLS`)}`);
|
|
341
|
+
out();
|
|
342
|
+
if (kept === 0)
|
|
343
|
+
process.exitCode = 1;
|
|
344
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turn what a person typed into the address of their workspace.
|
|
3
|
+
*
|
|
4
|
+
* Accepts the workspace name, which is the normal case, and also a full URL or
|
|
5
|
+
* a bare host, because somebody who was given a link will paste the link. All
|
|
6
|
+
* three arrive at the same place rather than at an error message.
|
|
7
|
+
*/
|
|
8
|
+
export declare function workspaceUrl(typed: string): string;
|
|
9
|
+
export declare function cmdLogin(args: string[]): Promise<void>;
|