@illuminis/comprism 0.1.3 → 0.1.5
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 +221 -26
- package/out/agent/render.d.ts +56 -8
- package/out/agent/render.js +441 -39
- package/out/agent/session.d.ts +156 -2
- package/out/agent/session.js +795 -154
- 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 +88 -12
- 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 +249 -43
- 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 +12 -1
- package/out/commands/repl.js +1649 -122
- 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/welcome.d.ts +25 -1
- package/out/commands/welcome.js +71 -35
- 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 +190 -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 +98 -0
- package/out/lib/keyboard.js +390 -0
- package/out/lib/lastlogin.d.ts +14 -0
- package/out/lib/lastlogin.js +105 -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/picker.d.ts +1 -0
- package/out/lib/picker.js +158 -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.d.ts +3 -0
- package/out/lib/prompt.js +36 -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/startcache.d.ts +13 -0
- package/out/lib/startcache.js +78 -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 +10 -4
- package/out/lib/ui.js +65 -25
- package/out/lib/voice.d.ts +36 -0
- package/out/lib/voice.js +160 -1
- package/out/native/dictate +0 -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 +595 -33
- package/package.json +11 -50
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ToolServers = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Tool servers on this machine (manual 9.10): started when a job needs one,
|
|
6
|
+
* spoken to over standard input and output, stopped when the job ends.
|
|
7
|
+
*
|
|
8
|
+
* A local helper and nothing more. Which servers exist, whether one may run
|
|
9
|
+
* in this project, whether a call is allowed and what a result means are all
|
|
10
|
+
* the service's. This starts the command the person approved, asks for the
|
|
11
|
+
* tool list, carries one call, and reports what came back or why nothing did.
|
|
12
|
+
*
|
|
13
|
+
* Only the two methods an agent needs: list the tools, call a tool.
|
|
14
|
+
*/
|
|
15
|
+
const child_process_1 = require("child_process");
|
|
16
|
+
/** How long one request may take before it is reported as not answered. */
|
|
17
|
+
const timeoutMs = () => Number(process.env.COMPRISM_TOOL_SERVER_TIMEOUT_MS || 30_000);
|
|
18
|
+
/** What one result may carry back. The service cuts it again. */
|
|
19
|
+
const MAX_RESULT_CHARS = 20_000;
|
|
20
|
+
class Server {
|
|
21
|
+
name;
|
|
22
|
+
command;
|
|
23
|
+
proc;
|
|
24
|
+
buffer = "";
|
|
25
|
+
nextId = 1;
|
|
26
|
+
pending = new Map();
|
|
27
|
+
gone = null;
|
|
28
|
+
ready;
|
|
29
|
+
constructor(name, command, cwd) {
|
|
30
|
+
this.name = name;
|
|
31
|
+
this.command = command;
|
|
32
|
+
// The command exactly as the person approved it, through their shell, the
|
|
33
|
+
// way they would type it themselves.
|
|
34
|
+
// nosemgrep: javascript.lang.security.detect-child-process.detect-child-process -- the tool server command exactly as the person approved it
|
|
35
|
+
this.proc = (0, child_process_1.spawn)(this.command, { cwd, shell: true, stdio: ["pipe", "pipe", "pipe"],
|
|
36
|
+
windowsHide: true });
|
|
37
|
+
this.proc.stdout.setEncoding("utf8");
|
|
38
|
+
this.proc.stdout.on("data", (chunk) => this.read(chunk));
|
|
39
|
+
this.proc.stderr.on("data", () => { });
|
|
40
|
+
this.proc.stdin.on("error", () => { });
|
|
41
|
+
this.proc.on("error", (e) => this.fail(`could not be started: ${e.message}`));
|
|
42
|
+
this.proc.on("exit", (code) => this.fail(`stopped${code === null ? "" : ` (exit ${code})`}`));
|
|
43
|
+
this.ready = this.request("initialize", {
|
|
44
|
+
protocolVersion: "2025-06-18", capabilities: {},
|
|
45
|
+
clientInfo: { name: "comprism", version: "1" },
|
|
46
|
+
}).then(() => { this.notify("notifications/initialized"); });
|
|
47
|
+
this.ready.catch(() => { });
|
|
48
|
+
}
|
|
49
|
+
fail(why) {
|
|
50
|
+
if (this.gone)
|
|
51
|
+
return;
|
|
52
|
+
this.gone = `The tool server ${this.name} ${why}.`;
|
|
53
|
+
for (const [, p] of this.pending) {
|
|
54
|
+
clearTimeout(p.timer);
|
|
55
|
+
p.reject(new Error(this.gone));
|
|
56
|
+
}
|
|
57
|
+
this.pending.clear();
|
|
58
|
+
}
|
|
59
|
+
read(chunk) {
|
|
60
|
+
this.buffer += chunk;
|
|
61
|
+
let at;
|
|
62
|
+
while ((at = this.buffer.indexOf("\n")) >= 0) {
|
|
63
|
+
const line = this.buffer.slice(0, at).trim();
|
|
64
|
+
this.buffer = this.buffer.slice(at + 1);
|
|
65
|
+
if (!line)
|
|
66
|
+
continue;
|
|
67
|
+
let msg;
|
|
68
|
+
try {
|
|
69
|
+
msg = JSON.parse(line);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// A reply that is not a reply: every waiting request is told so.
|
|
73
|
+
for (const [id, p] of this.pending) {
|
|
74
|
+
clearTimeout(p.timer);
|
|
75
|
+
p.reject(new Error(`The tool server ${this.name} sent something that is not a reply.`));
|
|
76
|
+
this.pending.delete(id);
|
|
77
|
+
}
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const id = typeof msg.id === "number" ? msg.id : Number(msg.id);
|
|
81
|
+
const waiting = this.pending.get(id);
|
|
82
|
+
if (!waiting)
|
|
83
|
+
continue;
|
|
84
|
+
clearTimeout(waiting.timer);
|
|
85
|
+
this.pending.delete(id);
|
|
86
|
+
if (msg.error) {
|
|
87
|
+
const e = msg.error;
|
|
88
|
+
waiting.reject(new Error(`The tool server ${this.name} refused: ${e.message ?? "an error"}.`));
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
waiting.resolve((msg.result ?? {}));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
notify(method) {
|
|
96
|
+
if (this.gone)
|
|
97
|
+
return;
|
|
98
|
+
this.proc.stdin.write(JSON.stringify({ jsonrpc: "2.0", method }) + "\n");
|
|
99
|
+
}
|
|
100
|
+
request(method, params) {
|
|
101
|
+
if (this.gone)
|
|
102
|
+
return Promise.reject(new Error(this.gone));
|
|
103
|
+
const id = this.nextId++;
|
|
104
|
+
return new Promise((resolve, reject) => {
|
|
105
|
+
const timer = setTimeout(() => {
|
|
106
|
+
this.pending.delete(id);
|
|
107
|
+
reject(new Error(`The tool server ${this.name} did not answer within ${Math.max(1, Math.round(timeoutMs() / 1000))} seconds.`));
|
|
108
|
+
}, timeoutMs());
|
|
109
|
+
this.pending.set(id, { resolve, reject, timer });
|
|
110
|
+
this.proc.stdin.write(JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n");
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
stop() {
|
|
114
|
+
this.fail("was stopped");
|
|
115
|
+
try {
|
|
116
|
+
this.proc.stdin.end();
|
|
117
|
+
}
|
|
118
|
+
catch { /* already closed */ }
|
|
119
|
+
// On Windows the command runs under cmd.exe, and ending cmd.exe leaves
|
|
120
|
+
// the server itself running. The whole tree is ended instead, so nothing
|
|
121
|
+
// outlives the job (manual 9.10).
|
|
122
|
+
if (process.platform === "win32" && this.proc.pid && this.proc.exitCode === null) {
|
|
123
|
+
try {
|
|
124
|
+
(0, child_process_1.spawnSync)("taskkill", ["/pid", String(this.proc.pid), "/T", "/F"], { windowsHide: true, stdio: "ignore" });
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
catch { /* fall through to the ordinary stop */ }
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
this.proc.kill();
|
|
131
|
+
}
|
|
132
|
+
catch { /* already gone */ }
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/** The tool servers one job started, by name. */
|
|
136
|
+
class ToolServers {
|
|
137
|
+
cwd;
|
|
138
|
+
running = new Map();
|
|
139
|
+
constructor(cwd) {
|
|
140
|
+
this.cwd = cwd;
|
|
141
|
+
}
|
|
142
|
+
async server(name, command) {
|
|
143
|
+
let s = this.running.get(name);
|
|
144
|
+
if (!s || s.command !== command) {
|
|
145
|
+
s?.stop();
|
|
146
|
+
s = new Server(name, command, this.cwd);
|
|
147
|
+
this.running.set(name, s);
|
|
148
|
+
}
|
|
149
|
+
await s.ready;
|
|
150
|
+
return s;
|
|
151
|
+
}
|
|
152
|
+
/** The server's tools, as it described them, as JSON text. */
|
|
153
|
+
async list(name, command) {
|
|
154
|
+
try {
|
|
155
|
+
const s = await this.server(name, command);
|
|
156
|
+
const r = await s.request("tools/list", {});
|
|
157
|
+
if (!Array.isArray(r.tools)) {
|
|
158
|
+
return { isError: true, content: `The tool server ${name} sent something that is not a tool list.` };
|
|
159
|
+
}
|
|
160
|
+
return { isError: false, content: JSON.stringify(r.tools) };
|
|
161
|
+
}
|
|
162
|
+
catch (e) {
|
|
163
|
+
this.running.get(name)?.stop();
|
|
164
|
+
this.running.delete(name);
|
|
165
|
+
return { isError: true, content: e.message };
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/** One call, and the text the server returned. */
|
|
169
|
+
async call(name, command, tool, args) {
|
|
170
|
+
try {
|
|
171
|
+
const s = await this.server(name, command);
|
|
172
|
+
const r = await s.request("tools/call", { name: tool, arguments: args ?? {} });
|
|
173
|
+
const blocks = Array.isArray(r.content) ? r.content : [];
|
|
174
|
+
const text = blocks.filter((b) => b.type === "text").map((b) => String(b.text ?? "")).join("\n").trim();
|
|
175
|
+
return { isError: r.isError === true, content: (text || "(the tool returned nothing)").slice(0, MAX_RESULT_CHARS) };
|
|
176
|
+
}
|
|
177
|
+
catch (e) {
|
|
178
|
+
return { isError: true, content: e.message };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/** Every server this job started, stopped. Called when the job ends. */
|
|
182
|
+
stopAll() {
|
|
183
|
+
for (const [, s] of this.running)
|
|
184
|
+
s.stop();
|
|
185
|
+
this.running.clear();
|
|
186
|
+
}
|
|
187
|
+
get count() { return this.running.size; }
|
|
188
|
+
}
|
|
189
|
+
exports.ToolServers = ToolServers;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { RunResult, ShellOptions } from "./shell";
|
|
2
|
+
/** Where a copy is, by its id, or undefined. */
|
|
3
|
+
export declare function worktreePath(id: string): string | undefined;
|
|
4
|
+
export declare function openWorktree(id: string, opts: ShellOptions): Promise<RunResult>;
|
|
5
|
+
/** What the helper changed in its copy, as one diff. */
|
|
6
|
+
export declare function diffWorktree(id: string, opts: ShellOptions): Promise<RunResult>;
|
|
7
|
+
export declare function closeWorktree(id: string, opts: ShellOptions): Promise<RunResult>;
|
|
8
|
+
/** Every copy this process made, removed; for the end of a session. */
|
|
9
|
+
export declare function closeAllWorktrees(root: string): Promise<void>;
|
|
@@ -0,0 +1,119 @@
|
|
|
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.worktreePath = worktreePath;
|
|
37
|
+
exports.openWorktree = openWorktree;
|
|
38
|
+
exports.diffWorktree = diffWorktree;
|
|
39
|
+
exports.closeWorktree = closeWorktree;
|
|
40
|
+
exports.closeAllWorktrees = closeAllWorktrees;
|
|
41
|
+
/**
|
|
42
|
+
* A helper's own copy of the project (manual 5.26).
|
|
43
|
+
*
|
|
44
|
+
* A git worktree in the temporary folder, started from the project as it is
|
|
45
|
+
* now: the last commit plus the person's uncommitted changes to tracked files,
|
|
46
|
+
* committed inside the copy as its starting point. The helper's edits land
|
|
47
|
+
* there and nowhere else; what comes back is a diff against that starting
|
|
48
|
+
* point, which the service applies to the real folder with the usual approval.
|
|
49
|
+
* Nothing here decides anything: it makes the copy, reads its diff, and
|
|
50
|
+
* removes it.
|
|
51
|
+
*/
|
|
52
|
+
const fs = __importStar(require("fs"));
|
|
53
|
+
const os = __importStar(require("os"));
|
|
54
|
+
const path = __importStar(require("path"));
|
|
55
|
+
const shell_1 = require("./shell");
|
|
56
|
+
const copies = new Map();
|
|
57
|
+
const git = (args, opts) => (0, shell_1.runProgram)("git", args, opts);
|
|
58
|
+
const okExit = (r) => !r.isError && /^exit 0/.test(r.content);
|
|
59
|
+
const body = (r) => r.content.replace(/^exit -?\d+\n\n/, "");
|
|
60
|
+
/** Where a copy is, by its id, or undefined. */
|
|
61
|
+
function worktreePath(id) {
|
|
62
|
+
return copies.get(id);
|
|
63
|
+
}
|
|
64
|
+
async function openWorktree(id, opts) {
|
|
65
|
+
if (!/^[\w-]{1,40}$/.test(id))
|
|
66
|
+
return { isError: true, content: "Refused: not a usable copy name." };
|
|
67
|
+
if (copies.has(id))
|
|
68
|
+
return { content: copies.get(id), summary: `copy ${id}` };
|
|
69
|
+
const where = fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()), `comprism-helper-${id}-`));
|
|
70
|
+
fs.rmdirSync(where);
|
|
71
|
+
const made = await git(["worktree", "add", "--detach", "-q", where, "HEAD"], opts);
|
|
72
|
+
if (!okExit(made))
|
|
73
|
+
return { isError: true, content: `A separate copy could not be made: ${body(made)}` };
|
|
74
|
+
const inCopy = { ...opts, root: where, cwd: undefined };
|
|
75
|
+
// The person's uncommitted changes, so the helper starts from what they see.
|
|
76
|
+
const pending = await git(["diff", "--binary", "HEAD"], opts);
|
|
77
|
+
const patch = body(pending);
|
|
78
|
+
if (okExit(pending) && patch.trim() && patch.trim() !== "(no output)") {
|
|
79
|
+
const file = path.join(where, ".comprism-start.patch");
|
|
80
|
+
fs.writeFileSync(file, patch.endsWith("\n") ? patch : `${patch}\n`);
|
|
81
|
+
await git(["apply", "--whitespace=nowarn", file], inCopy);
|
|
82
|
+
fs.unlinkSync(file);
|
|
83
|
+
}
|
|
84
|
+
await git(["add", "-A"], inCopy);
|
|
85
|
+
await git(["-c", "user.name=comprism", "-c", "user.email=helper@illuminis.ai",
|
|
86
|
+
"commit", "-q", "--allow-empty", "--no-verify", "-m", "start"], inCopy);
|
|
87
|
+
copies.set(id, fs.realpathSync(where));
|
|
88
|
+
return { content: copies.get(id), summary: `copy ${id}` };
|
|
89
|
+
}
|
|
90
|
+
/** What the helper changed in its copy, as one diff. */
|
|
91
|
+
async function diffWorktree(id, opts) {
|
|
92
|
+
const where = copies.get(id);
|
|
93
|
+
if (!where)
|
|
94
|
+
return { isError: true, content: `There is no copy called ${id}.` };
|
|
95
|
+
const inCopy = { ...opts, root: where, cwd: undefined };
|
|
96
|
+
await git(["add", "-A"], inCopy);
|
|
97
|
+
const d = await git(["--no-pager", "diff", "--cached", "--binary", "--no-color", "HEAD"], inCopy);
|
|
98
|
+
if (!okExit(d))
|
|
99
|
+
return { isError: true, content: body(d) };
|
|
100
|
+
const text = body(d).trim() === "(no output)" ? "" : body(d);
|
|
101
|
+
return { content: text, summary: text ? "changes" : "no changes", facts: { changed: text ? 1 : 0 } };
|
|
102
|
+
}
|
|
103
|
+
async function closeWorktree(id, opts) {
|
|
104
|
+
const where = copies.get(id);
|
|
105
|
+
if (!where)
|
|
106
|
+
return { content: `${id} is already gone.` };
|
|
107
|
+
await git(["worktree", "remove", "--force", where], opts);
|
|
108
|
+
try {
|
|
109
|
+
fs.rmSync(where, { recursive: true, force: true });
|
|
110
|
+
}
|
|
111
|
+
catch { /* removed above */ }
|
|
112
|
+
copies.delete(id);
|
|
113
|
+
return { content: `Removed ${id}.` };
|
|
114
|
+
}
|
|
115
|
+
/** Every copy this process made, removed; for the end of a session. */
|
|
116
|
+
async function closeAllWorktrees(root) {
|
|
117
|
+
for (const id of [...copies.keys()])
|
|
118
|
+
await closeWorktree(id, { root });
|
|
119
|
+
}
|
package/out/graph/read-python.js
CHANGED
|
@@ -51,9 +51,10 @@ const child_process_1 = require("child_process");
|
|
|
51
51
|
const fs = __importStar(require("fs"));
|
|
52
52
|
const os = __importStar(require("os"));
|
|
53
53
|
const path = __importStar(require("path"));
|
|
54
|
+
const self_1 = require("../lib/self");
|
|
54
55
|
/** The reader script, beside the built code in both a checkout and an install. */
|
|
55
56
|
function scriptPath() {
|
|
56
|
-
return path.resolve(__dirname, "..", "..", "scripts", "read_python.py");
|
|
57
|
+
return (0, self_1.shippedFile)("read_python.py", path.resolve(__dirname, "..", "..", "scripts", "read_python.py"));
|
|
57
58
|
}
|
|
58
59
|
let interpreter;
|
|
59
60
|
/** Which Python this machine has, or null. Asked once per process. */
|
package/out/lib/attach.d.ts
CHANGED
|
@@ -9,13 +9,27 @@ export interface Attached {
|
|
|
9
9
|
/** The text was longer than one turn can carry and was cut. */
|
|
10
10
|
truncated: boolean;
|
|
11
11
|
isImage: boolean;
|
|
12
|
+
/** Bytes on disk, which the job record keeps (manual 3.11). */
|
|
13
|
+
sizeBytes: number;
|
|
14
|
+
/** What the service says about the file after its name, worded by the
|
|
15
|
+
* service so every client shows the same line (manual 3.1 and 3.6). */
|
|
16
|
+
summary: string;
|
|
17
|
+
}
|
|
18
|
+
/** Why one named file was left out, in the service's fixed list (manual 3.10). */
|
|
19
|
+
export interface Problem {
|
|
20
|
+
code: string;
|
|
21
|
+
message: string;
|
|
12
22
|
}
|
|
13
23
|
/** A path somebody named, before anything has been read. */
|
|
14
24
|
export interface Mention {
|
|
15
25
|
/** Exactly as it appeared, so it can be taken back out of the sentence. */
|
|
16
26
|
raw: string;
|
|
17
|
-
/** Resolved
|
|
27
|
+
/** Resolved and unescaped. */
|
|
18
28
|
file: string;
|
|
29
|
+
/** As the person wrote it, unescaped, for the messages they read. */
|
|
30
|
+
shown: string;
|
|
31
|
+
/** Set when the file cannot be attached; nothing is sent for it. */
|
|
32
|
+
problem?: Problem;
|
|
19
33
|
}
|
|
20
34
|
/**
|
|
21
35
|
* Take the shell's escaping back off a path.
|
|
@@ -23,17 +37,32 @@ export interface Mention {
|
|
|
23
37
|
* A dragged file arrives as `/Users/me/My\ Report.pdf`, and a pasted one is
|
|
24
38
|
* often in quotes. Both are the shell's way of saying "this is one thing", and
|
|
25
39
|
* neither is part of the name.
|
|
40
|
+
*
|
|
41
|
+
* On Windows a backslash is the folder separator and never an escape: its
|
|
42
|
+
* terminals quote a dragged path instead. Stripping backslashes there turned
|
|
43
|
+
* `C:\Users\me\notes.txt` into `C:Usersmenotes.txt`, which was the Windows
|
|
44
|
+
* failure found in prompt 01.
|
|
45
|
+
*/
|
|
46
|
+
export declare function unescapePath(token: string, platform?: string): string;
|
|
47
|
+
/**
|
|
48
|
+
* What stops a file being attached, checked on this machine before anything is
|
|
49
|
+
* sent (manual 3.10). Only the four facts the service cannot see: whether the
|
|
50
|
+
* file is there, is a folder, can be read, or is a link to nothing.
|
|
26
51
|
*/
|
|
27
|
-
export declare function
|
|
52
|
+
export declare function localProblem(file: string, shown: string): Problem | undefined;
|
|
28
53
|
/**
|
|
29
54
|
* Every file the typed line points at, in the order they were named.
|
|
30
55
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
56
|
+
* Anything after an `@` is a request to attach, so a problem with it is
|
|
57
|
+
* reported. Any other path (absolute, `~/`, `./`, `../`, quoted) that is not a
|
|
58
|
+
* readable file is left alone and stays part of the question: somebody writing
|
|
59
|
+
* about a path they plan to create, or a folder they want looked at, is doing
|
|
60
|
+
* something perfectly ordinary.
|
|
35
61
|
*/
|
|
36
|
-
export declare function mentions(line: string,
|
|
62
|
+
export declare function mentions(line: string, root: string, here?: string, platform?: string): Mention[];
|
|
63
|
+
/** The line begins with an absolute path to something on the disk, as a
|
|
64
|
+
* dragged file does, rather than with a slashed command word. */
|
|
65
|
+
export declare function startsWithPath(line: string, platform?: string): boolean;
|
|
37
66
|
/**
|
|
38
67
|
* The question with the long paths taken out and the file names left in.
|
|
39
68
|
*
|
|
@@ -43,20 +72,35 @@ export declare function mentions(line: string, cwd: string): Mention[];
|
|
|
43
72
|
* nothing but a place for the model to try to open something it cannot reach.
|
|
44
73
|
*/
|
|
45
74
|
export declare function withoutPaths(line: string, found: Mention[]): string;
|
|
75
|
+
/** The line with every mention taken out: empty when it named files and said
|
|
76
|
+
* nothing else, which is a drag and drop waiting for its question. */
|
|
77
|
+
export declare function withoutMentions(line: string, found: Mention[]): string;
|
|
46
78
|
/**
|
|
47
79
|
* Hand the files to the server and get back the ids the question will carry.
|
|
48
80
|
*
|
|
49
81
|
* One at a time and in order, because the caps are per file and a refusal names
|
|
50
|
-
* which file it is refusing.
|
|
51
|
-
*
|
|
52
|
-
*
|
|
82
|
+
* which file it is refusing. The service is asked first, by name and size, so a
|
|
83
|
+
* program file or a file over the limit is refused before a byte of it moves.
|
|
84
|
+
* A file that cannot be read does not stop the others.
|
|
53
85
|
*/
|
|
54
86
|
export declare function upload(baseUrl: string, credential: string, files: string[]): Promise<{
|
|
55
87
|
attached: Attached[];
|
|
56
88
|
refused: {
|
|
57
89
|
file: string;
|
|
58
90
|
why: string;
|
|
91
|
+
code?: string;
|
|
59
92
|
}[];
|
|
60
93
|
}>;
|
|
61
|
-
/**
|
|
62
|
-
export declare function describe(
|
|
94
|
+
/** One `attached` line per file, names in a column, as manual 3.1 shows. */
|
|
95
|
+
export declare function describe(items: Attached[]): string[];
|
|
96
|
+
/** The waiting list, numbered for `detach N` (manual 3.6). */
|
|
97
|
+
export declare function listing(items: Attached[]): string[];
|
|
98
|
+
/**
|
|
99
|
+
* File names from the project for Tab after `@` (manual 3.1).
|
|
100
|
+
*
|
|
101
|
+
* A bounded walk, because a completion that takes a second is one nobody uses.
|
|
102
|
+
*/
|
|
103
|
+
export declare function projectFiles(root: string, limit?: number): string[];
|
|
104
|
+
/** What Tab completes the line to, in readline's shape: the choices, and the
|
|
105
|
+
* part of the line they replace. */
|
|
106
|
+
export declare function completeAt(line: string, files: () => string[]): [string[], string];
|