@illuminis/comprism 0.1.3 → 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 +61 -2
- 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 -17
- 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 +594 -32
- package/package.json +9 -49
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readOne = readOne;
|
|
4
|
+
exports.listOne = listOne;
|
|
5
|
+
exports.fetchCommandList = fetchCommandList;
|
|
6
|
+
/**
|
|
7
|
+
* The session's command and skill list, as the service decides it (manual 6.4).
|
|
8
|
+
*
|
|
9
|
+
* The service names each file or folder it needs from the project and this
|
|
10
|
+
* reads it, inside the project and through the executor's own checks, so a
|
|
11
|
+
* secrets file is never sent and nothing outside the project is read. It asks
|
|
12
|
+
* again with what it was given until it has what it needs. Every choice about
|
|
13
|
+
* what counts as a skill, what it is called and what its line says is made on
|
|
14
|
+
* the service.
|
|
15
|
+
*/
|
|
16
|
+
const files_1 = require("../executor/files");
|
|
17
|
+
const gateway_1 = require("./gateway");
|
|
18
|
+
const ROUNDS = 6;
|
|
19
|
+
const MAX_CHARS = 8000;
|
|
20
|
+
function readOne(root, rel) {
|
|
21
|
+
const r = (0, files_1.performFileAction)(root, 'read_file', { path: rel });
|
|
22
|
+
return r.isError ? null : r.content.slice(0, MAX_CHARS);
|
|
23
|
+
}
|
|
24
|
+
function listOne(root, rel) {
|
|
25
|
+
const r = (0, files_1.performFileAction)(root, 'list_dir', { path: rel });
|
|
26
|
+
if (r.isError)
|
|
27
|
+
return null;
|
|
28
|
+
return r.content === '(empty)' ? [] : r.content.split('\n').filter(Boolean);
|
|
29
|
+
}
|
|
30
|
+
/** Ask the service for this project's list. `words` are the session words
|
|
31
|
+
* this tool runs. */
|
|
32
|
+
async function fetchCommandList(root, words) {
|
|
33
|
+
const files = {};
|
|
34
|
+
const listings = {};
|
|
35
|
+
for (let round = 0; round < ROUNDS; round += 1) {
|
|
36
|
+
const reply = await (0, gateway_1.ask)({
|
|
37
|
+
intent: 'commands', prompt: '',
|
|
38
|
+
commandsPayload: { words, round, files, listings, project: root },
|
|
39
|
+
});
|
|
40
|
+
const body = reply.commands;
|
|
41
|
+
if (!reply.ok || reply.served === false || !body) {
|
|
42
|
+
return { ok: false, items: [], needsUpdate: [], keepHistory: false };
|
|
43
|
+
}
|
|
44
|
+
if (!body.wants) {
|
|
45
|
+
return {
|
|
46
|
+
ok: true,
|
|
47
|
+
items: body.items ?? [],
|
|
48
|
+
needsUpdate: body.needs_update ?? [],
|
|
49
|
+
keepHistory: body.keep_history === true,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
for (const p of body.wants.read ?? [])
|
|
53
|
+
files[p] = readOne(root, p);
|
|
54
|
+
for (const f of body.wants.list ?? [])
|
|
55
|
+
listings[f] = listOne(root, f);
|
|
56
|
+
}
|
|
57
|
+
return { ok: false, items: [], needsUpdate: [], keepHistory: false };
|
|
58
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { WithheldReason } from './types';
|
|
2
|
+
export interface LocalVerdict {
|
|
3
|
+
recommendation: string | null;
|
|
4
|
+
withheld: WithheldReason | null;
|
|
5
|
+
withheldDetail?: string;
|
|
6
|
+
breakdown: Record<string, never>;
|
|
7
|
+
tableHashes: Record<string, never>;
|
|
8
|
+
baselineVersion: string | null;
|
|
9
|
+
policyVersion: string;
|
|
10
|
+
estimatorVersion: string;
|
|
11
|
+
/** True only on a close corpus match. Every surface must flag the rest. */
|
|
12
|
+
confident: boolean;
|
|
13
|
+
/** Which rung of the lookup answered, carried for provenance. */
|
|
14
|
+
rung: string | null;
|
|
15
|
+
}
|
|
16
|
+
export declare const POLICY_VERSION = "served-v1";
|
|
17
|
+
export declare function decide(input: {
|
|
18
|
+
prompt: string;
|
|
19
|
+
callingModel?: string;
|
|
20
|
+
contextTokens?: number;
|
|
21
|
+
freshContext?: boolean;
|
|
22
|
+
}): Promise<LocalVerdict>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.POLICY_VERSION = void 0;
|
|
4
|
+
exports.decide = decide;
|
|
5
|
+
/**
|
|
6
|
+
* The decision, as this tool now gets it: by asking.
|
|
7
|
+
*
|
|
8
|
+
* ── What this replaced ────────────────────────────────────────────────────
|
|
9
|
+
*
|
|
10
|
+
* `estimator.ts` computed the decision here, on the customer's machine, from
|
|
11
|
+
* tables and curves that are the product's whole method. That file stays in the
|
|
12
|
+
* repository because our own tests read it, and it is excluded from every
|
|
13
|
+
* published package, because a package on a public registry is readable forever
|
|
14
|
+
* by anyone who installs it.
|
|
15
|
+
*
|
|
16
|
+
* So the interception paths call this instead. It asks our server and returns
|
|
17
|
+
* the SAME SHAPE the call sites already expect, which is why swapping it in
|
|
18
|
+
* changed one import line in each of them rather than rewriting three files.
|
|
19
|
+
*
|
|
20
|
+
* The maths-bearing fields come back empty on purpose. A breakdown per candidate
|
|
21
|
+
* and the hashes of the tables consulted are the reasoning, and the reasoning
|
|
22
|
+
* stays on the server where it is written into the server's own decision record.
|
|
23
|
+
* The client records WHAT was decided; it no longer records how.
|
|
24
|
+
*/
|
|
25
|
+
const gateway_1 = require("./gateway");
|
|
26
|
+
exports.POLICY_VERSION = 'served-v1';
|
|
27
|
+
async function decide(input) {
|
|
28
|
+
const reply = await (0, gateway_1.ask)({
|
|
29
|
+
intent: 'decide',
|
|
30
|
+
prompt: input.prompt,
|
|
31
|
+
...(input.callingModel ? { callingModel: input.callingModel } : {}),
|
|
32
|
+
contextTokens: input.contextTokens ?? 0,
|
|
33
|
+
freshContext: input.freshContext ?? true,
|
|
34
|
+
});
|
|
35
|
+
const d = reply.decision;
|
|
36
|
+
return {
|
|
37
|
+
recommendation: d.model,
|
|
38
|
+
// A server that could not decide is not an error here. Rule 10: the caller
|
|
39
|
+
// runs what it was going to run, and the reason travels with the record.
|
|
40
|
+
withheld: d.model ? null : 'no_decision',
|
|
41
|
+
...(d.rationale ? { withheldDetail: d.rationale } : {}),
|
|
42
|
+
breakdown: {},
|
|
43
|
+
tableHashes: {},
|
|
44
|
+
baselineVersion: null,
|
|
45
|
+
policyVersion: exports.POLICY_VERSION,
|
|
46
|
+
estimatorVersion: exports.POLICY_VERSION,
|
|
47
|
+
confident: d.confident,
|
|
48
|
+
rung: d.rung,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalization before hashing: lowercase, collapse runs of whitespace, trim.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately mild. Aggressive normalization (stripping punctuation, stemming)
|
|
5
|
+
* would collapse genuinely different requests onto one fingerprint, and a
|
|
6
|
+
* fingerprint collision is a chain-linking error that is invisible afterwards.
|
|
7
|
+
*/
|
|
8
|
+
export declare function normalisePrompt(prompt: string): string;
|
|
9
|
+
export declare function fingerprint(prompt: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* A short, stable id. `crypto.randomUUID` would do, but ids appear in every
|
|
12
|
+
* report and a 12-character id is legible in a terminal where a UUID is noise.
|
|
13
|
+
*/
|
|
14
|
+
export declare function newId(prefix: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Context size in tokens, approximated from characters.
|
|
17
|
+
*
|
|
18
|
+
* Four characters per token is the industry's usual rule of thumb and it is an
|
|
19
|
+
* approximation, not a measurement - which is why every figure derived from it
|
|
20
|
+
* carries `derivation: 'inferred'` with this method named. The provider's own
|
|
21
|
+
* reported token counts are used wherever they exist; this is only for the
|
|
22
|
+
* context estimate that has to exist *before* the call is made.
|
|
23
|
+
*/
|
|
24
|
+
export declare const APPROX_CHARS_PER_TOKEN = 4;
|
|
25
|
+
export declare function approxTokens(text: string): number;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.APPROX_CHARS_PER_TOKEN = void 0;
|
|
4
|
+
exports.normalisePrompt = normalisePrompt;
|
|
5
|
+
exports.fingerprint = fingerprint;
|
|
6
|
+
exports.newId = newId;
|
|
7
|
+
exports.approxTokens = approxTokens;
|
|
8
|
+
/**
|
|
9
|
+
* Fingerprinting: how a request is identified without being kept.
|
|
10
|
+
*
|
|
11
|
+
* Every record refers to a request by the sha256 of its normalized text. The
|
|
12
|
+
* text itself is never written anywhere. Two consequences the rest of the
|
|
13
|
+
* system depends on:
|
|
14
|
+
*
|
|
15
|
+
* - A verbatim retry produces the identical fingerprint, which is how Phase 2
|
|
16
|
+
* recognizes two calls as attempts at the same unit of work without ever
|
|
17
|
+
* comparing the words.
|
|
18
|
+
* - Nothing can be reversed out of the record. A fingerprint identifies a
|
|
19
|
+
* request to someone who already has it, and is inert to everyone else.
|
|
20
|
+
*/
|
|
21
|
+
const node_crypto_1 = require("node:crypto");
|
|
22
|
+
/**
|
|
23
|
+
* Normalization before hashing: lowercase, collapse runs of whitespace, trim.
|
|
24
|
+
*
|
|
25
|
+
* Deliberately mild. Aggressive normalization (stripping punctuation, stemming)
|
|
26
|
+
* would collapse genuinely different requests onto one fingerprint, and a
|
|
27
|
+
* fingerprint collision is a chain-linking error that is invisible afterwards.
|
|
28
|
+
*/
|
|
29
|
+
function normalisePrompt(prompt) {
|
|
30
|
+
return prompt.replace(/\s+/g, ' ').trim().toLowerCase();
|
|
31
|
+
}
|
|
32
|
+
function fingerprint(prompt) {
|
|
33
|
+
return (0, node_crypto_1.createHash)('sha256').update(normalisePrompt(prompt), 'utf8').digest('hex');
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A short, stable id. `crypto.randomUUID` would do, but ids appear in every
|
|
37
|
+
* report and a 12-character id is legible in a terminal where a UUID is noise.
|
|
38
|
+
*/
|
|
39
|
+
function newId(prefix) {
|
|
40
|
+
const rand = (0, node_crypto_1.createHash)('sha256')
|
|
41
|
+
.update(`${process.pid}:${Date.now()}:${Math.random()}`)
|
|
42
|
+
.digest('hex')
|
|
43
|
+
.slice(0, 12);
|
|
44
|
+
return `${prefix}_${rand}`;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Context size in tokens, approximated from characters.
|
|
48
|
+
*
|
|
49
|
+
* Four characters per token is the industry's usual rule of thumb and it is an
|
|
50
|
+
* approximation, not a measurement - which is why every figure derived from it
|
|
51
|
+
* carries `derivation: 'inferred'` with this method named. The provider's own
|
|
52
|
+
* reported token counts are used wherever they exist; this is only for the
|
|
53
|
+
* context estimate that has to exist *before* the call is made.
|
|
54
|
+
*/
|
|
55
|
+
exports.APPROX_CHARS_PER_TOKEN = 4;
|
|
56
|
+
function approxTokens(text) {
|
|
57
|
+
return Math.ceil(text.length / exports.APPROX_CHARS_PER_TOKEN);
|
|
58
|
+
}
|
package/out/lib/gateway.d.ts
CHANGED
|
@@ -33,8 +33,36 @@ export interface CatalogProvider {
|
|
|
33
33
|
permitted: boolean;
|
|
34
34
|
models: CatalogModel[];
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* One session's cost, as the server worked it out.
|
|
38
|
+
*
|
|
39
|
+
* Deliberately loose below the top level: the fields are named by the service
|
|
40
|
+
* and a client that re-declared every one of them would need a release every
|
|
41
|
+
* time a cost factor was added. What matters is that nothing here is computed
|
|
42
|
+
* on this side, so a new field arrives and prints without a new version.
|
|
43
|
+
*/
|
|
44
|
+
export interface SpendReport {
|
|
45
|
+
session: Record<string, unknown> | null;
|
|
46
|
+
/** The per-session fold: the five cost factors and what they add to. */
|
|
47
|
+
cost_factors: Record<string, unknown>;
|
|
48
|
+
/** Every provider call, with its tokens, its price and the decision behind it. */
|
|
49
|
+
calls: Record<string, unknown>[];
|
|
50
|
+
/**
|
|
51
|
+
* What a client should DRAW: headings, labels, ordered rows, formatted values.
|
|
52
|
+
*
|
|
53
|
+
* Sent by the server so that adding a cost factor, renaming one or changing
|
|
54
|
+
* how a figure reads is a server change and never obliges a customer to
|
|
55
|
+
* install a new version of the tool. Loosely typed on purpose, for the same
|
|
56
|
+
* reason: a field added there must arrive here without a release.
|
|
57
|
+
*/
|
|
58
|
+
presentation?: Record<string, unknown>;
|
|
59
|
+
decisions: Record<string, unknown>[];
|
|
60
|
+
units_of_work: Record<string, unknown>[];
|
|
61
|
+
}
|
|
36
62
|
export interface GatewayReply {
|
|
37
|
-
|
|
63
|
+
/** Local transport metadata, not an authentication decision. */
|
|
64
|
+
httpStatus?: number;
|
|
65
|
+
intent: 'decide' | 'answer' | 'catalog' | 'store_key' | 'session' | 'job_start' | 'resolve_workspace' | 'sign_in' | 'sign_out' | 'attach' | 'transcribe' | 'graph' | 'spend' | 'project' | 'commands' | 'transcript' | 'context' | 'compact' | 'sessions' | 'permissions' | 'jobs' | 'agents' | 'integrations' | 'skills' | 'plugins' | 'schema' | 'usage' | 'instructions' | 'config' | 'memory' | 'worktrees' | 'privacy' | 'hooks' | 'queue' | 'review' | 'release';
|
|
38
66
|
client: string;
|
|
39
67
|
decision: Decision;
|
|
40
68
|
answer: string | null;
|
|
@@ -89,7 +117,109 @@ export interface GatewayReply {
|
|
|
89
117
|
/** Present only for a graph request: what the map holds, what it still needs,
|
|
90
118
|
* or the answer to one of the five questions. */
|
|
91
119
|
graph?: Record<string, unknown>;
|
|
120
|
+
/**
|
|
121
|
+
* One session's cost, worked out term by term. Present only for a spend
|
|
122
|
+
* request.
|
|
123
|
+
*
|
|
124
|
+
* Shaped by the server and rendered here, never recomputed here: the whole
|
|
125
|
+
* point of asking the service is that the terminal and the portal quote one
|
|
126
|
+
* set of figures. A client that added anything up itself would be a second
|
|
127
|
+
* source of truth for the one number this product sells.
|
|
128
|
+
*/
|
|
129
|
+
spend?: SpendReport | null;
|
|
130
|
+
/** The first line of a session, as the service wrote it (manual 2.2). */
|
|
131
|
+
project_line?: string | null;
|
|
132
|
+
/** The lines a project operation prints, written by the service. */
|
|
133
|
+
lines?: string[] | null;
|
|
134
|
+
data?: Record<string, unknown> | null;
|
|
135
|
+
/** Present only for a context or compact request: lines to print (6.13, 6.15). */
|
|
136
|
+
context?: {
|
|
137
|
+
lines: string[];
|
|
138
|
+
ok?: boolean;
|
|
139
|
+
} | null;
|
|
140
|
+
/** Present only for a transcript request: lines to print as sent (6.9). */
|
|
141
|
+
transcript?: {
|
|
142
|
+
job_id: string;
|
|
143
|
+
lines: string[];
|
|
144
|
+
complete: boolean;
|
|
145
|
+
} | null;
|
|
146
|
+
/** Present only for a jobs request (manual 5.14): lines to print as sent. */
|
|
147
|
+
jobs?: {
|
|
148
|
+
lines: string[];
|
|
149
|
+
job_id?: string;
|
|
150
|
+
running?: boolean;
|
|
151
|
+
} | null;
|
|
152
|
+
/** The result object a script reads (manual 10.3), built by the service. */
|
|
153
|
+
result?: Record<string, unknown> | null;
|
|
154
|
+
/** One reason word for a refusal, turned into a number by `exit_status`. */
|
|
155
|
+
reason?: string | null;
|
|
156
|
+
/** Reason word to exit number (Appendix B), as the service sends it. */
|
|
157
|
+
exit_status?: Record<string, number> | null;
|
|
158
|
+
/** Present only for a usage request: the figures and the lines to print. */
|
|
159
|
+
usage?: Record<string, unknown> | null;
|
|
160
|
+
/** Present only for a schema request: the published shape and the table. */
|
|
161
|
+
schema_doc?: Record<string, unknown> | null;
|
|
162
|
+
/** Present only for an agents request (manual 5.24): lines to print as sent. */
|
|
163
|
+
agents?: {
|
|
164
|
+
lines: string[];
|
|
165
|
+
helpers?: Array<Record<string, unknown>>;
|
|
166
|
+
wants?: {
|
|
167
|
+
read?: string[];
|
|
168
|
+
list?: string[];
|
|
169
|
+
} | null;
|
|
170
|
+
} | null;
|
|
171
|
+
/** Present only for a commands request (manual 6.4, 6.5). `wants` names
|
|
172
|
+
* the project files to send on the next round. */
|
|
173
|
+
commands?: {
|
|
174
|
+
items?: {
|
|
175
|
+
name: string;
|
|
176
|
+
description: string;
|
|
177
|
+
source: string;
|
|
178
|
+
}[];
|
|
179
|
+
needs_update?: string[];
|
|
180
|
+
keep_history?: boolean;
|
|
181
|
+
wants?: {
|
|
182
|
+
read?: string[];
|
|
183
|
+
list?: string[];
|
|
184
|
+
} | null;
|
|
185
|
+
} | null;
|
|
92
186
|
/** Who this machine is signed in as. Present only for a session request. */
|
|
187
|
+
/** For sessions: `lines` to print as they are, and the records behind
|
|
188
|
+
* them (`sessions` for a list, the one session's fields for a resume). */
|
|
189
|
+
sessions?: SessionsReply | null;
|
|
190
|
+
/** For permissions: `lines` to print as they are (manual 4.14). */
|
|
191
|
+
permissions?: {
|
|
192
|
+
lines?: string[];
|
|
193
|
+
verdict?: string;
|
|
194
|
+
} | null;
|
|
195
|
+
/** For integrations: `lines` to print as they are (web manual 9.5). */
|
|
196
|
+
integrations?: Record<string, unknown> & {
|
|
197
|
+
lines?: string[];
|
|
198
|
+
connections?: unknown[];
|
|
199
|
+
} | null;
|
|
200
|
+
/** `comprism plugins` (manual 9.15 to 9.17), in the service's words. */
|
|
201
|
+
plugins?: Record<string, unknown> & {
|
|
202
|
+
lines?: string[];
|
|
203
|
+
line?: string;
|
|
204
|
+
error?: string;
|
|
205
|
+
} | null;
|
|
206
|
+
/** `comprism skills` (manual 9.1 to 9.4): rows to draw, or what was saved. */
|
|
207
|
+
skills?: {
|
|
208
|
+
rows?: Array<{
|
|
209
|
+
name: string;
|
|
210
|
+
description: string;
|
|
211
|
+
where: string;
|
|
212
|
+
active: boolean;
|
|
213
|
+
note?: string | null;
|
|
214
|
+
}>;
|
|
215
|
+
empty?: string | null;
|
|
216
|
+
line?: string;
|
|
217
|
+
error?: string;
|
|
218
|
+
wants?: {
|
|
219
|
+
read?: string[];
|
|
220
|
+
list?: string[];
|
|
221
|
+
} | null;
|
|
222
|
+
} | null;
|
|
93
223
|
session?: SessionOut | null;
|
|
94
224
|
/** Permission for one coding job. Present only for a job_start request. */
|
|
95
225
|
job?: JobOut | null;
|
|
@@ -97,6 +227,9 @@ export interface GatewayReply {
|
|
|
97
227
|
sign_in?: SignInOut | null;
|
|
98
228
|
/** Present only for an attach or transcribe request. */
|
|
99
229
|
upload?: UploadOut | null;
|
|
230
|
+
/** For attach: why the file will not be read, from the service's fixed
|
|
231
|
+
* list. The sentence is in `message`. */
|
|
232
|
+
refusal?: string | null;
|
|
100
233
|
/**
|
|
101
234
|
* True when the request was understood, allowed and acted on.
|
|
102
235
|
*
|
|
@@ -119,6 +252,21 @@ export interface GatewayReply {
|
|
|
119
252
|
ok: boolean;
|
|
120
253
|
}
|
|
121
254
|
/** Permission to send one file, and the address to send it to. */
|
|
255
|
+
/** One session as the service describes it (CLI manual 8.4, 8.5). */
|
|
256
|
+
export interface SessionRecord {
|
|
257
|
+
session_id: string;
|
|
258
|
+
number: string;
|
|
259
|
+
title: string;
|
|
260
|
+
last_job_id?: string | null;
|
|
261
|
+
continues_job?: string | null;
|
|
262
|
+
conversation_kept?: boolean;
|
|
263
|
+
cost_usd: number;
|
|
264
|
+
jobs: number;
|
|
265
|
+
}
|
|
266
|
+
export interface SessionsReply extends Partial<SessionRecord> {
|
|
267
|
+
lines: string[];
|
|
268
|
+
sessions?: SessionRecord[];
|
|
269
|
+
}
|
|
122
270
|
export interface UploadOut {
|
|
123
271
|
/** Presented at the upload address in place of the workspace credential. */
|
|
124
272
|
ticket: string;
|
|
@@ -190,7 +338,7 @@ export interface SessionOut {
|
|
|
190
338
|
can_write: boolean;
|
|
191
339
|
}
|
|
192
340
|
export interface Ask {
|
|
193
|
-
intent: 'decide' | 'answer' | 'catalog' | 'store_key' | 'session' | 'job_start' | 'resolve_workspace' | 'sign_in' | 'sign_out' | 'attach' | 'transcribe' | 'graph';
|
|
341
|
+
intent: 'decide' | 'answer' | 'catalog' | 'store_key' | 'session' | 'job_start' | 'resolve_workspace' | 'sign_in' | 'sign_out' | 'attach' | 'transcribe' | 'graph' | 'spend' | 'project' | 'commands' | 'transcript' | 'context' | 'compact' | 'sessions' | 'permissions' | 'jobs' | 'agents' | 'integrations' | 'skills' | 'plugins' | 'schema' | 'usage' | 'instructions' | 'config' | 'memory' | 'worktrees' | 'privacy' | 'hooks' | 'queue' | 'review' | 'release';
|
|
194
342
|
prompt: string;
|
|
195
343
|
callingModel?: string;
|
|
196
344
|
contextTokens?: number;
|
|
@@ -207,11 +355,37 @@ export interface Ask {
|
|
|
207
355
|
resumeJobId?: string;
|
|
208
356
|
/** For sign_in only. Sent once, over TLS, and written nowhere. */
|
|
209
357
|
password?: string;
|
|
358
|
+
/** Company login (manual 1.10): the token a browser approval issued. */
|
|
359
|
+
deviceToken?: string;
|
|
210
360
|
/** For sign_in, when a second factor is required. */
|
|
211
361
|
challenge?: string;
|
|
212
362
|
code?: string;
|
|
213
363
|
/** For sign_in: how this machine appears where a person goes to revoke it. */
|
|
214
364
|
machineLabel?: string;
|
|
365
|
+
/** Which session to break down. Omitted means the newest one recorded. */
|
|
366
|
+
spendSession?: string;
|
|
367
|
+
/** For project: the folder facts this machine observed (manual 2.1 to 2.3). */
|
|
368
|
+
project?: Record<string, unknown>;
|
|
369
|
+
/** For instructions, config, memory and worktrees (manual 2.5 to 2.11). */
|
|
370
|
+
op?: string;
|
|
371
|
+
payload?: Record<string, unknown>;
|
|
372
|
+
/** For commands: the session words this tool runs, and the project files
|
|
373
|
+
* the service asked for on the previous round. */
|
|
374
|
+
commandsPayload?: Record<string, unknown>;
|
|
375
|
+
sessionsPayload?: Record<string, unknown>;
|
|
376
|
+
/** For jobs: op (list, find, stop) and job (manual 5.14). */
|
|
377
|
+
jobsPayload?: Record<string, unknown>;
|
|
378
|
+
/** For agents: the helper definition files this machine read (manual 5.24). */
|
|
379
|
+
agentsPayload?: Record<string, unknown>;
|
|
380
|
+
/** For usage: this machine's offset from UTC in minutes (manual 10.12). */
|
|
381
|
+
tzMinutes?: number;
|
|
382
|
+
skillsPayload?: Record<string, unknown>;
|
|
383
|
+
integrationsPayload?: Record<string, unknown>;
|
|
384
|
+
pluginsPayload?: Record<string, unknown>;
|
|
385
|
+
/** For permissions: op, action, target and the settings files (manual 4.14). */
|
|
386
|
+
permissionsPayload?: Record<string, unknown>;
|
|
387
|
+
/** For transcript: the job whose record to print (manual 6.9). */
|
|
388
|
+
jobId?: string;
|
|
215
389
|
/** For graph: which of the map's operations this is. */
|
|
216
390
|
graphOp?: 'status' | 'stamps' | 'update' | 'finish' | 'ask' | 'forget' | 'policy';
|
|
217
391
|
/** For graph: the project on this machine the map belongs to. */
|
|
@@ -226,6 +400,14 @@ export interface Ask {
|
|
|
226
400
|
* that could carry it.
|
|
227
401
|
*/
|
|
228
402
|
graphPayload?: Record<string, unknown>;
|
|
403
|
+
/** For attach: the file's name and size, asked about before its bytes are
|
|
404
|
+
* sent. Never its contents (manual 3.10). */
|
|
405
|
+
attachment?: {
|
|
406
|
+
filename: string;
|
|
407
|
+
size_bytes: number;
|
|
408
|
+
};
|
|
409
|
+
/** For answer: ids of files already attached, read before the question. */
|
|
410
|
+
attachments?: string[];
|
|
229
411
|
}
|
|
230
412
|
/**
|
|
231
413
|
* The same door, at an address this machine is not signed in to yet.
|
|
@@ -237,3 +419,5 @@ export interface Ask {
|
|
|
237
419
|
*/
|
|
238
420
|
export declare function askAt(url: string, input: Ask, tenant?: string): Promise<GatewayReply>;
|
|
239
421
|
export declare function ask(input: Ask): Promise<GatewayReply>;
|
|
422
|
+
/** A sentence for a certificate failure, or null when the failure was not one. */
|
|
423
|
+
export declare function certificateProblem(e: unknown): string | null;
|
package/out/lib/gateway.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.askAt = askAt;
|
|
4
4
|
exports.ask = ask;
|
|
5
|
+
exports.certificateProblem = certificateProblem;
|
|
5
6
|
/**
|
|
6
7
|
* The one door, from this side of it.
|
|
7
8
|
*
|
|
@@ -21,6 +22,7 @@ exports.ask = ask;
|
|
|
21
22
|
* the shape of the reply, which is not a secret and cannot be one.
|
|
22
23
|
*/
|
|
23
24
|
const connection_1 = require("./connection");
|
|
25
|
+
const version_1 = require("./version");
|
|
24
26
|
/**
|
|
25
27
|
* A decision that decides nothing, for when the door cannot be reached.
|
|
26
28
|
*
|
|
@@ -105,6 +107,9 @@ async function post(url, input, credential, tenant) {
|
|
|
105
107
|
headers.authorization = `Bearer ${conn.workspaceKey}`;
|
|
106
108
|
if (conn.tenant)
|
|
107
109
|
headers['X-Tenant-ID'] = conn.tenant;
|
|
110
|
+
// Which tool is asking, so the service can say when a feature needs a newer
|
|
111
|
+
// one (manual 1.7). It decides; this only says what it is.
|
|
112
|
+
headers['X-Comprism-Version'] = version_1.COMPRISM_VERSION;
|
|
108
113
|
// Forwarded, never written to disk: the customer's money stays the
|
|
109
114
|
// customer's, and we hold no secret of theirs on their behalf.
|
|
110
115
|
if (input.providerKey)
|
|
@@ -113,6 +118,11 @@ async function post(url, input, credential, tenant) {
|
|
|
113
118
|
const res = await fetch(`${conn.url.replace(/\/+$/, '')}/api/v1/dev/gateway`, {
|
|
114
119
|
method: 'POST',
|
|
115
120
|
headers,
|
|
121
|
+
// Never waits forever. A service that restarts mid request, or a network
|
|
122
|
+
// that goes quiet, answers as unreachable (Appendix B, 6) rather than
|
|
123
|
+
// leaving the terminal hanging. Longer for a question a model answers.
|
|
124
|
+
signal: AbortSignal.timeout(['answer', 'decide', 'compact', 'transcribe'].includes(input.intent)
|
|
125
|
+
? 300_000 : 120_000),
|
|
116
126
|
body: JSON.stringify({
|
|
117
127
|
intent: input.intent,
|
|
118
128
|
client: 'cli',
|
|
@@ -128,10 +138,27 @@ async function post(url, input, credential, tenant) {
|
|
|
128
138
|
...(input.password ? { password: input.password } : {}),
|
|
129
139
|
...(input.challenge ? { challenge: input.challenge } : {}),
|
|
130
140
|
...(input.code ? { code: input.code } : {}),
|
|
141
|
+
...(input.deviceToken ? { device_token: input.deviceToken } : {}),
|
|
131
142
|
...(input.machineLabel ? { machine_label: input.machineLabel } : {}),
|
|
143
|
+
...(input.spendSession ? { spend_session: input.spendSession } : {}),
|
|
144
|
+
...(input.project ? { project: input.project } : {}),
|
|
145
|
+
...(input.op ? { op: input.op } : {}),
|
|
146
|
+
...(input.payload ? { payload: input.payload } : {}),
|
|
147
|
+
...(input.commandsPayload ? { commands_payload: input.commandsPayload } : {}),
|
|
148
|
+
...(input.sessionsPayload ? { sessions_payload: input.sessionsPayload } : {}),
|
|
149
|
+
...(input.jobsPayload ? { jobs_payload: input.jobsPayload } : {}),
|
|
150
|
+
...(input.agentsPayload ? { agents_payload: input.agentsPayload } : {}),
|
|
151
|
+
...(input.tzMinutes !== undefined ? { tz_minutes: input.tzMinutes } : {}),
|
|
152
|
+
...(input.skillsPayload ? { skills_payload: input.skillsPayload } : {}),
|
|
153
|
+
...(input.integrationsPayload ? { integrations_payload: input.integrationsPayload } : {}),
|
|
154
|
+
...(input.pluginsPayload ? { plugins_payload: input.pluginsPayload } : {}),
|
|
155
|
+
...(input.permissionsPayload ? { permissions_payload: input.permissionsPayload } : {}),
|
|
156
|
+
...(input.jobId ? { job_id: input.jobId } : {}),
|
|
132
157
|
...(input.graphOp ? { graph_op: input.graphOp } : {}),
|
|
133
158
|
...(input.workspace ? { workspace: input.workspace } : {}),
|
|
134
159
|
...(input.graphPayload ? { graph_payload: input.graphPayload } : {}),
|
|
160
|
+
...(input.attachment ? { attachment: input.attachment } : {}),
|
|
161
|
+
...(input.attachments?.length ? { attachments: input.attachments } : {}),
|
|
135
162
|
}),
|
|
136
163
|
});
|
|
137
164
|
if (!res.ok) {
|
|
@@ -156,16 +183,44 @@ async function post(url, input, credential, tenant) {
|
|
|
156
183
|
// credential path was alive and would have worked. Newer builds answer
|
|
157
184
|
// 200 with `served: false` and never reach this line.
|
|
158
185
|
if (res.status === 422)
|
|
159
|
-
return { ...failed, served: false };
|
|
160
|
-
return failed;
|
|
186
|
+
return { ...failed, served: false, httpStatus: res.status };
|
|
187
|
+
return { ...failed, httpStatus: res.status };
|
|
161
188
|
}
|
|
162
189
|
// `ok` is this client's own marker and the server never sends it: it
|
|
163
190
|
// records that the workspace answered at all. Set here, on the one path
|
|
164
191
|
// where that is true, so no caller has to infer it from an empty field.
|
|
165
192
|
const reply = (await res.json());
|
|
193
|
+
if (reply.reason === 'upgrade') {
|
|
194
|
+
// Said before any work starts or anything is charged, and the number is
|
|
195
|
+
// Appendix B's 10 (manual 1.7).
|
|
196
|
+
process.stderr.write(` ${String(reply.message || 'This needs a newer comprism. Run comprism update.').split('\n').join('\n ')}\n`);
|
|
197
|
+
process.exit(10);
|
|
198
|
+
}
|
|
166
199
|
return { ...reply, ok: true };
|
|
167
200
|
}
|
|
168
|
-
catch {
|
|
169
|
-
|
|
201
|
+
catch (e) {
|
|
202
|
+
// A certificate problem is said as one, with the setting to change, never
|
|
203
|
+
// as "could not be reached" (manual 1.11).
|
|
204
|
+
return openFailure(input.intent, input.callingModel, certificateProblem(e) ?? 'the service could not be reached');
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/** The certificate codes Node reports when a company's own authority is not
|
|
208
|
+
* trusted, or a certificate is wrong (manual 1.11). */
|
|
209
|
+
const CERT_CODES = new Set(["UNABLE_TO_VERIFY_LEAF_SIGNATURE", "SELF_SIGNED_CERT_IN_CHAIN",
|
|
210
|
+
"DEPTH_ZERO_SELF_SIGNED_CERT", "UNABLE_TO_GET_ISSUER_CERT", "UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
|
|
211
|
+
"CERT_HAS_EXPIRED", "ERR_TLS_CERT_ALTNAME_INVALID", "CERT_UNTRUSTED"]);
|
|
212
|
+
/** A sentence for a certificate failure, or null when the failure was not one. */
|
|
213
|
+
function certificateProblem(e) {
|
|
214
|
+
let cause = e;
|
|
215
|
+
for (let i = 0; i < 4 && cause; i += 1) {
|
|
216
|
+
const code = cause.code;
|
|
217
|
+
if (code && CERT_CODES.has(code)) {
|
|
218
|
+
const file = process.env.NODE_EXTRA_CA_CERTS;
|
|
219
|
+
return `a certificate problem (${code}): the service's certificate is not trusted on this machine. `
|
|
220
|
+
+ (file ? `NODE_EXTRA_CA_CERTS is ${file}; check it holds your company's certificate authority.`
|
|
221
|
+
: "If your company uses its own certificate authority, set NODE_EXTRA_CA_CERTS to its certificate file.");
|
|
222
|
+
}
|
|
223
|
+
cause = cause.cause;
|
|
170
224
|
}
|
|
225
|
+
return null;
|
|
171
226
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare function historyFile(): string;
|
|
2
|
+
export declare class History {
|
|
3
|
+
/** Newest first, as shown on the prompt line. Shared with the reader, which
|
|
4
|
+
* walks it with Up and Down. */
|
|
5
|
+
readonly entries: string[];
|
|
6
|
+
/** Newest first, as sent. What the file holds. */
|
|
7
|
+
private saved;
|
|
8
|
+
/** The company's rule: true keeps, false removes, null (the service could
|
|
9
|
+
* not be asked) keeps this session's requests in memory and leaves any
|
|
10
|
+
* file exactly as it is. */
|
|
11
|
+
private keep;
|
|
12
|
+
/** Begin a session under the company's rule. */
|
|
13
|
+
start(keep: boolean | null): void;
|
|
14
|
+
private off;
|
|
15
|
+
/** `history off`: nothing is remembered, in memory or on disk. */
|
|
16
|
+
disable(): void;
|
|
17
|
+
/** Remember one request. `shown` is how it looked at the prompt, paste
|
|
18
|
+
* labels included; `sent` is what was sent. */
|
|
19
|
+
add(shown: string, sent: string): void;
|
|
20
|
+
/** End the session. Without permission to keep, nothing is left behind. */
|
|
21
|
+
finish(): void;
|
|
22
|
+
private write;
|
|
23
|
+
private remove;
|
|
24
|
+
}
|