@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,123 @@
|
|
|
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.cmdUpdate = cmdUpdate;
|
|
37
|
+
/**
|
|
38
|
+
* `comprism update` and `comprism update --check` (manual 1.7).
|
|
39
|
+
*
|
|
40
|
+
* The service holds the release record; this compares it with the installed
|
|
41
|
+
* version and, only when asked, installs the newer one the same way this copy
|
|
42
|
+
* was installed (manual 1.1): npm for npm, the workspace's own install script
|
|
43
|
+
* for the install script, pip for Python. It never updates itself on its own
|
|
44
|
+
* and never moves a machine from one option to another. The sign in and
|
|
45
|
+
* settings live outside the program, so an update keeps them; a failed install
|
|
46
|
+
* leaves the old version.
|
|
47
|
+
*/
|
|
48
|
+
const child_process_1 = require("child_process");
|
|
49
|
+
const fs = __importStar(require("fs"));
|
|
50
|
+
const path = __importStar(require("path"));
|
|
51
|
+
const ui = __importStar(require("../lib/ui"));
|
|
52
|
+
const gateway_1 = require("../lib/gateway");
|
|
53
|
+
const self_1 = require("../lib/self");
|
|
54
|
+
const version_1 = require("../lib/version");
|
|
55
|
+
const install_1 = require("./install");
|
|
56
|
+
const out = (s = "") => process.stdout.write(`${s}\n`);
|
|
57
|
+
const METHOD_NAME = {
|
|
58
|
+
script: "the install script",
|
|
59
|
+
npm: "npm",
|
|
60
|
+
python: "Python (pip)",
|
|
61
|
+
};
|
|
62
|
+
/** The command that installs `version` the way this copy was installed. */
|
|
63
|
+
function updateCommand(method, version) {
|
|
64
|
+
if (method === "npm") {
|
|
65
|
+
const target = process.env.COMPRISM_UPDATE_PACKAGE || `@illuminis/comprism@${version}`;
|
|
66
|
+
return process.platform === "win32"
|
|
67
|
+
? { file: "npm.cmd", args: ["install", "-g", target], shell: true }
|
|
68
|
+
: { file: "npm", args: ["install", "-g", target] };
|
|
69
|
+
}
|
|
70
|
+
const base = (0, install_1.tenantBaseUrl)();
|
|
71
|
+
if (method === "script") {
|
|
72
|
+
if (!base)
|
|
73
|
+
return { manual: "comprism login, then comprism update" };
|
|
74
|
+
return process.platform === "win32"
|
|
75
|
+
? { file: "powershell.exe", args: ["-NoProfile", "-Command", `irm ${base}/install.ps1 | iex`] }
|
|
76
|
+
: { file: "/bin/sh", args: ["-c", `curl -fsSL ${base}/install.sh | sh`] };
|
|
77
|
+
}
|
|
78
|
+
// Python: the interpreter of the environment pip installed into, when this
|
|
79
|
+
// copy sits in one (a virtual environment or pipx's). Anywhere else is a
|
|
80
|
+
// Python this tool has no business changing, so it says what to run.
|
|
81
|
+
const pin = `comprism-cli==${version}`;
|
|
82
|
+
const index = base ? ["--extra-index-url", `${base}/pypi/simple/`] : [];
|
|
83
|
+
const here = path.dirname(fs.realpathSync(process.execPath));
|
|
84
|
+
for (const name of process.platform === "win32" ? ["python.exe"] : ["python3", "python"]) {
|
|
85
|
+
const python = path.join(here, name);
|
|
86
|
+
if (fs.existsSync(python))
|
|
87
|
+
return { file: python, args: ["-m", "pip", "install", "--upgrade", ...index, pin] };
|
|
88
|
+
}
|
|
89
|
+
return { manual: `python3 -m pip install --upgrade ${index.join(" ")} ${pin}`.replace(/ +/g, " ") };
|
|
90
|
+
}
|
|
91
|
+
async function cmdUpdate(args) {
|
|
92
|
+
const reply = await (0, gateway_1.ask)({ intent: "release", prompt: "" });
|
|
93
|
+
const data = (reply.data ?? {});
|
|
94
|
+
if (!reply.ok || !data.latest) {
|
|
95
|
+
out(ui.fail(reply.message || "The service could not say which version is newest."));
|
|
96
|
+
return reply.ok ? 1 : 6;
|
|
97
|
+
}
|
|
98
|
+
const method = (0, self_1.installMethod)();
|
|
99
|
+
out(` installed ${version_1.COMPRISM_VERSION}, with ${METHOD_NAME[method]}`);
|
|
100
|
+
out(` newest ${data.latest}`);
|
|
101
|
+
if (!data.update_available) {
|
|
102
|
+
out(ui.ok("You have the newest version."));
|
|
103
|
+
return 0;
|
|
104
|
+
}
|
|
105
|
+
if (args.includes("--check")) {
|
|
106
|
+
out(` A newer version is available. Install it with: comprism update`);
|
|
107
|
+
return 0;
|
|
108
|
+
}
|
|
109
|
+
const how = updateCommand(method, data.latest);
|
|
110
|
+
if ("manual" in how) {
|
|
111
|
+
out(ui.fail("This copy is in a Python this tool does not change. Update it with:"));
|
|
112
|
+
out(` ${how.manual}`);
|
|
113
|
+
return 1;
|
|
114
|
+
}
|
|
115
|
+
out(ui.c.dim(` updating with ${METHOD_NAME[method]} ...`));
|
|
116
|
+
const r = (0, child_process_1.spawnSync)(how.file, how.args, { stdio: "inherit", shell: how.shell ?? false });
|
|
117
|
+
if (r.status !== 0) {
|
|
118
|
+
out(ui.fail(`The update did not complete, so ${version_1.COMPRISM_VERSION} is still installed and working.`));
|
|
119
|
+
return 1;
|
|
120
|
+
}
|
|
121
|
+
out(ui.ok(`Updated to ${data.latest}. Your sign in and settings are unchanged.`));
|
|
122
|
+
return 0;
|
|
123
|
+
}
|
|
@@ -1 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
import type { SessionOut } from '../lib/gateway';
|
|
2
|
+
/**
|
|
3
|
+
* Who this machine is signed in as, and everything else the header prints.
|
|
4
|
+
*
|
|
5
|
+
* ── One call, to the one service ──────────────────────────────────────────
|
|
6
|
+
*
|
|
7
|
+
* This used to call the platform's own `whoami` for the identity, and the
|
|
8
|
+
* header then had no way at all to say how many vendor keys the account held.
|
|
9
|
+
* Two questions, two addresses, and the header could show a person facts that
|
|
10
|
+
* disagreed with each other. On 17 September 2026 it did exactly that: "User
|
|
11
|
+
* unknown" beside a company name, and a session that then announced no provider
|
|
12
|
+
* key was stored while four were stored and active.
|
|
13
|
+
*
|
|
14
|
+
* Every line below now comes from one request to the single service, so the
|
|
15
|
+
* header either shows a consistent picture or says plainly that it could not
|
|
16
|
+
* reach the workspace. There is no third state in which half of it is true.
|
|
17
|
+
*
|
|
18
|
+
* Null rather than an error when it cannot be reached. A header is the wrong
|
|
19
|
+
* place to fail: somebody on a plane still gets the local facts, and the lines
|
|
20
|
+
* needing the server say so.
|
|
21
|
+
*/
|
|
22
|
+
export declare function session(): Promise<SessionOut | null>;
|
|
23
|
+
/** `known` is who this machine is, when the caller already has it (the last
|
|
24
|
+
* answer, drawn at once while a fresh one is asked for). */
|
|
25
|
+
export declare function showWelcome(known?: SessionOut | null, signingIn?: boolean, withMark?: boolean): Promise<void>;
|
package/out/commands/welcome.js
CHANGED
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.session = session;
|
|
36
37
|
exports.showWelcome = showWelcome;
|
|
37
38
|
/**
|
|
38
39
|
* The first thing anybody sees.
|
|
@@ -95,33 +96,46 @@ async function session() {
|
|
|
95
96
|
return reply.session;
|
|
96
97
|
}
|
|
97
98
|
/**
|
|
98
|
-
* The mark: a
|
|
99
|
+
* The mark: the app icon as a terminal can draw it cleanly. A five layer prism,
|
|
100
|
+
* each layer two blocks wider than the one above and a shade deeper, with
|
|
101
|
+
* three beams leaving its right side (up, level and down) and a ring of the
|
|
102
|
+
* icon's cyan to purple around it (owner, 28 September 2026).
|
|
99
103
|
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
* on a font. A full block renders identically everywhere, so the only thing
|
|
104
|
-
* carrying the design is the color, which is the point of a prism.
|
|
104
|
+
* Solid blocks only, no blended edges and no white, because a terminal draws a
|
|
105
|
+
* solid block sharply in any font and a white one vanishes on a white screen.
|
|
106
|
+
* Drawn two pixels to a character, so it is nine lines tall.
|
|
105
107
|
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
* base carries all eight. That is a prism doing its job: one input at the top,
|
|
109
|
-
* the whole spectrum at the bottom. Banding it by row would have shown four of
|
|
110
|
-
* the eight and read as a striped triangle instead.
|
|
111
|
-
*
|
|
112
|
-
* The eight values come from the same helper as the rule beneath it, so the
|
|
113
|
-
* mark and the rule can never drift apart.
|
|
108
|
+
* Without color the picture cannot be drawn, so the four row block pyramid
|
|
109
|
+
* stands in: full blocks only, which render the same in every font.
|
|
114
110
|
*/
|
|
115
|
-
const
|
|
111
|
+
const ICON = [
|
|
112
|
+
'..........................................53a6ed51a1ed509cee4f98ee4d93ee4c8eee4a89ee..................................................................',
|
|
113
|
+
'..............................54abed53a6ed51a1ed..............................4984ef477fef467bef......................................................',
|
|
114
|
+
'........................54abed53a6ed......................................................4476ef4371ef................................................',
|
|
115
|
+
'..................54abed53a6ed..................................................................426cf04067f0..........................................',
|
|
116
|
+
'..................53a6ed....................................a8d8f7a8d8f7..............................3f62f0..........................................',
|
|
117
|
+
'............53a6ed51a1ed....................................a8d8f7a8d8f7..............................3f5ff0425ef0..................4292f23f8af43b82f6',
|
|
118
|
+
'............51a1ed....................................74aef074aef074aef074aef0..............................455cf0......49a2ee469af0..................',
|
|
119
|
+
'............509cee....................................74aef074aef074aef074aef0........................54bbe851b3ea4daaec..............................',
|
|
120
|
+
'............4f98ee..............................4f86e64f86e64f86e64f86e64f86e64f86e6......5bcbe458c3e6......4b59f1....................................',
|
|
121
|
+
'............4d93ee..............................4f86e64f86e64f86e64f86e64f86e64f86e6f07a36f0e35befe25aeee259ece158eae057e9df56e8de55e6de54e4dd53e3dc52',
|
|
122
|
+
'............4c8eee........................3e60d83e60d83e60d83e60d83e60d83e60d83e60d83e60d8ed7435ea6e34......5056f1....................................',
|
|
123
|
+
'............4a89ee........................3e60d83e60d83e60d83e60d83e60d83e60d83e60d83e60d8............e76932e46331e15d30..............................',
|
|
124
|
+
'............4984ef477fef............2e3a9a2e3a9a2e3a9a2e3a9a2e3a9a2e3a9a2e3a9a2e3a9a2e3a9a2e3a9a......5355f15653f2......de572fdb512e..................',
|
|
125
|
+
'..................467bef............2e3a9a2e3a9a2e3a9a2e3a9a2e3a9a2e3a9a2e3a9a2e3a9a2e3a9a2e3a9a......5653f2........................d84c2cd5462bd2402a',
|
|
126
|
+
'..................4476ef4371ef..................................................................5653f25952f2..........................................',
|
|
127
|
+
'........................426cf04067f0......................................................5653f25952f2................................................',
|
|
128
|
+
'..............................3f62f03f5ff0425ef0..............................5355f15653f25952f2......................................................',
|
|
129
|
+
'..........................................455cf0485bf14b59f14e58f15056f15355f15653f2..................................................................',
|
|
130
|
+
];
|
|
116
131
|
function mark() {
|
|
132
|
+
const picture = ui.pixelArt(ICON);
|
|
133
|
+
if (picture.length)
|
|
134
|
+
return picture;
|
|
117
135
|
const rows = [];
|
|
118
136
|
for (let r = 1; r <= 4; r++) {
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
let line = ' '.repeat(left);
|
|
122
|
-
for (let i = 0; i < blocks; i++)
|
|
123
|
-
line += ui.spectrumAt(left + i, '\u2588');
|
|
124
|
-
rows.push(line + ' '.repeat(left));
|
|
137
|
+
const left = 4 - r;
|
|
138
|
+
rows.push(' '.repeat(left) + '\u2588'.repeat(r * 2) + ' '.repeat(left));
|
|
125
139
|
}
|
|
126
140
|
return rows;
|
|
127
141
|
}
|
|
@@ -133,19 +147,31 @@ function row(label, value) {
|
|
|
133
147
|
function readable(name) {
|
|
134
148
|
return name.replace(/[-_]/g, ' ').replace(/\b\w/g, (m) => m.toUpperCase());
|
|
135
149
|
}
|
|
136
|
-
|
|
150
|
+
/** `known` is who this machine is, when the caller already has it (the last
|
|
151
|
+
* answer, drawn at once while a fresh one is asked for). */
|
|
152
|
+
async function showWelcome(known, signingIn = false, withMark = true) {
|
|
137
153
|
const conn = (0, connection_1.readConnection)();
|
|
138
154
|
const cfg = (0, config_1.loadConfig)();
|
|
139
155
|
const folder = (0, settings_1.currentWorkspace)();
|
|
140
|
-
const me = await session();
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
156
|
+
const me = known !== undefined ? known : await session();
|
|
157
|
+
// The mark once per start. Signing in first draws it; the session that
|
|
158
|
+
// follows draws only the account, so nobody sees the same screen twice.
|
|
159
|
+
if (withMark) {
|
|
160
|
+
const art = mark();
|
|
161
|
+
// The name and the line under it sit beside the middle of the mark.
|
|
162
|
+
const at = Math.max(0, Math.floor(art.length / 2) - 1);
|
|
163
|
+
const beside = {
|
|
164
|
+
[at]: `${ui.c.bold('CompletionPrism')} ${ui.c.dim(`v${version_1.COMPRISM_VERSION}`)}`,
|
|
165
|
+
[at + 1]: ui.c.muted('Optimize AI completion economics by optimizing work.'),
|
|
166
|
+
};
|
|
167
|
+
out();
|
|
168
|
+
art.forEach((line, i) => out(beside[i] ? ` ${line} ${beside[i]}` : ` ${line}`));
|
|
169
|
+
out(ui.prismRule());
|
|
170
|
+
out();
|
|
171
|
+
}
|
|
172
|
+
// Signing in comes next and says everything else itself.
|
|
173
|
+
if (signingIn && !conn?.url)
|
|
174
|
+
return;
|
|
149
175
|
if (!conn?.url) {
|
|
150
176
|
// Nothing else here is knowable yet, and the one useful thing to say is the
|
|
151
177
|
// single command that changes that.
|
|
@@ -153,8 +179,12 @@ async function showWelcome() {
|
|
|
153
179
|
out(row('Comparing', cfg.defaultModel || 'not set'));
|
|
154
180
|
out(row('Workspace', `${folder.path} ${ui.c.dim('(where you are)')}`));
|
|
155
181
|
out();
|
|
156
|
-
|
|
157
|
-
|
|
182
|
+
// Not said when signing in follows at once: naming a command to type, just
|
|
183
|
+
// above the sign in it would start, reads as a second step.
|
|
184
|
+
if (!signingIn) {
|
|
185
|
+
out(` ${ui.c.dim('start with')} ${ui.c.bold('comprism login')}`);
|
|
186
|
+
out();
|
|
187
|
+
}
|
|
158
188
|
return;
|
|
159
189
|
}
|
|
160
190
|
const company = me?.company || readable(conn.tenant || 'unknown');
|
|
@@ -165,10 +195,16 @@ async function showWelcome() {
|
|
|
165
195
|
// machine happens to hold. A client that can only echo its own stored address
|
|
166
196
|
// can never tell a person that the address is the thing that is wrong, which
|
|
167
197
|
// is exactly what happened when a machine sat pointed at a dead laptop port.
|
|
168
|
-
|
|
198
|
+
// Except on this laptop: there the server names its public address, which is
|
|
199
|
+
// not where this machine is talking, and "you are on production" is the
|
|
200
|
+
// single most confusing thing a developer testing locally can be told.
|
|
201
|
+
const local = (0, connection_1.isLocalAddress)(conn.url);
|
|
202
|
+
const address = local
|
|
203
|
+
? `${conn.url.replace(/^https?:\/\//, '')} ${ui.c.dim('(this laptop)')}`
|
|
204
|
+
: (me?.workspace_url || conn.url).replace(/^https?:\/\//, '');
|
|
169
205
|
out(row('User', who));
|
|
170
206
|
out(row('Company', company));
|
|
171
|
-
out(row('Server', ui.c.dim(address)));
|
|
207
|
+
out(row('Server', local ? address : ui.c.dim(address)));
|
|
172
208
|
out(row('Comparing', `${cfg.defaultModel || ui.c.amber('not set')} ${ui.c.dim('change with `comprism model`')}`));
|
|
173
209
|
out(row('Workspace', `${folder.path} ${ui.c.dim(folder.source === 'cwd' ? '(where you are)' : '(saved)')}`));
|
|
174
210
|
if (plan) {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ProjectFacts } from "../lib/project";
|
|
2
|
+
/** The folder a `--worktree` job runs in, creating the worktree the first time.
|
|
3
|
+
* Null after saying why, when it cannot be made. */
|
|
4
|
+
export declare function ensureWorktree(facts: ProjectFacts, name: string, session: string): Promise<string | null>;
|
|
5
|
+
export declare function cmdWorktrees(args: string[]): Promise<number>;
|
|
@@ -0,0 +1,186 @@
|
|
|
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.ensureWorktree = ensureWorktree;
|
|
37
|
+
exports.cmdWorktrees = cmdWorktrees;
|
|
38
|
+
/**
|
|
39
|
+
* Separate copies of the repository (manual 2.11): `comprism work --worktree`,
|
|
40
|
+
* `comprism worktrees`, `open` and `remove`.
|
|
41
|
+
*
|
|
42
|
+
* This machine runs Git, because the repository is here. The service records
|
|
43
|
+
* each worktree the tool creates, decides what may be removed, and writes what
|
|
44
|
+
* a person reads. This file refuses on its own as well, immediately before
|
|
45
|
+
* removing anything, so losing work needs both to agree.
|
|
46
|
+
*/
|
|
47
|
+
const node_child_process_1 = require("node:child_process");
|
|
48
|
+
const fs = __importStar(require("node:fs"));
|
|
49
|
+
const path = __importStar(require("node:path"));
|
|
50
|
+
const project_ops_1 = require("../lib/project-ops");
|
|
51
|
+
const ui = __importStar(require("../lib/ui"));
|
|
52
|
+
const out = (s = "") => process.stdout.write(s + "\n");
|
|
53
|
+
/** Git with an argument list, never a shell string. Throws on failure. */
|
|
54
|
+
function git(args, cwd) {
|
|
55
|
+
return (0, node_child_process_1.execFileSync)("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
56
|
+
}
|
|
57
|
+
function hasBranch(root, branch) {
|
|
58
|
+
try {
|
|
59
|
+
git(["rev-parse", "--verify", "--quiet", `refs/heads/${branch}`], root);
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** The worktree folder goes in the repository's own ignore list, once. */
|
|
67
|
+
function exclude(root, line) {
|
|
68
|
+
const common = git(["rev-parse", "--git-common-dir"], root).trim();
|
|
69
|
+
const file = path.join(path.resolve(root, common), "info", "exclude");
|
|
70
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
71
|
+
const now = fs.existsSync(file) ? fs.readFileSync(file, "utf8") : "";
|
|
72
|
+
if (!now.split(/\r?\n/).includes(line)) {
|
|
73
|
+
fs.appendFileSync(file, `${now && !now.endsWith("\n") ? "\n" : ""}${line}\n`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** The folder a `--worktree` job runs in, creating the worktree the first time.
|
|
77
|
+
* Null after saying why, when it cannot be made. */
|
|
78
|
+
async function ensureWorktree(facts, name, session) {
|
|
79
|
+
try {
|
|
80
|
+
git(["rev-parse", "--git-dir"], facts.root);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
out(ui.fail("A worktree needs a Git repository. This folder is not one."));
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const plan = await (0, project_ops_1.call)("worktrees", "plan", { name }, facts, true);
|
|
87
|
+
if (!plan)
|
|
88
|
+
return null;
|
|
89
|
+
const { branch, path: where, exclude: line, exists } = plan.data;
|
|
90
|
+
const local = path.resolve(where);
|
|
91
|
+
if (exists && fs.existsSync(local)) {
|
|
92
|
+
out(ui.c.dim(` using worktree ${name} at ${local}`));
|
|
93
|
+
return local;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
exclude(facts.root, line);
|
|
97
|
+
git(["worktree", "add", ...(hasBranch(facts.root, branch) ? [local, branch] : ["-b", branch, local])], facts.root);
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
out(ui.fail(`Git could not create the worktree: ${String(err.stderr || err).trim()}`));
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const recorded = await (0, project_ops_1.call)("worktrees", "record", { name, branch, path: local, session }, facts);
|
|
104
|
+
return recorded ? local : null;
|
|
105
|
+
}
|
|
106
|
+
async function remove(facts, name, discard) {
|
|
107
|
+
const listed = await (0, project_ops_1.call)("worktrees", "open", { name }, facts, true);
|
|
108
|
+
if (!listed)
|
|
109
|
+
return 1;
|
|
110
|
+
const where = String(listed.data?.path ?? "");
|
|
111
|
+
const branch = `comprism/${name}`;
|
|
112
|
+
let dirty = [];
|
|
113
|
+
let onlyHere = 0;
|
|
114
|
+
if (fs.existsSync(where)) {
|
|
115
|
+
dirty = git(["status", "--porcelain"], where).split(/\r?\n/).filter(Boolean).map((l) => l.slice(3));
|
|
116
|
+
}
|
|
117
|
+
if (hasBranch(facts.root, branch)) {
|
|
118
|
+
// Commits on this branch and on no other. The other branches are named one
|
|
119
|
+
// by one: `--exclude` with `--not --branches` silently counts nothing.
|
|
120
|
+
const others = git(["for-each-ref", "--format=%(refname)", "refs/heads"], facts.root)
|
|
121
|
+
.split(/\r?\n/).filter((r) => r && r !== `refs/heads/${branch}`);
|
|
122
|
+
const commits = git(["rev-list", `refs/heads/${branch}`, "--not", ...others], facts.root);
|
|
123
|
+
onlyHere = commits.split(/\r?\n/).filter(Boolean).length;
|
|
124
|
+
}
|
|
125
|
+
let confirmed = false;
|
|
126
|
+
if (discard) {
|
|
127
|
+
if (!process.stdin.isTTY) {
|
|
128
|
+
out(ui.fail(`--discard needs you to type the worktree's name, ${name}, at a terminal.`));
|
|
129
|
+
return 1;
|
|
130
|
+
}
|
|
131
|
+
const { ask, closePrompt } = await Promise.resolve().then(() => __importStar(require("../lib/prompt")));
|
|
132
|
+
confirmed = (await ask(` type ${name} to discard it and anything only it holds: `)).trim() === name;
|
|
133
|
+
closePrompt();
|
|
134
|
+
}
|
|
135
|
+
const verdict = await (0, project_ops_1.call)("worktrees", "check_remove", { name, dirty, only_here: onlyHere, discard, confirmed }, facts, true);
|
|
136
|
+
if (!verdict)
|
|
137
|
+
return 1;
|
|
138
|
+
// This machine's own check, immediately before acting: never lose work that
|
|
139
|
+
// was not explicitly discarded by name.
|
|
140
|
+
if (dirty.length && !(discard && confirmed)) {
|
|
141
|
+
out(ui.fail(`${name} has uncommitted changes, so it was not removed.`));
|
|
142
|
+
return 1;
|
|
143
|
+
}
|
|
144
|
+
const d = verdict.data;
|
|
145
|
+
try {
|
|
146
|
+
if (fs.existsSync(d.remove))
|
|
147
|
+
git(["worktree", "remove", ...(d.force ? ["--force"] : []), d.remove], facts.root);
|
|
148
|
+
else
|
|
149
|
+
git(["worktree", "prune"], facts.root);
|
|
150
|
+
if (d.delete_branch && hasBranch(facts.root, d.branch))
|
|
151
|
+
git(["branch", "-D", d.branch], facts.root);
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
out(ui.fail(`Git could not remove it: ${String(err.stderr || err).trim()}`));
|
|
155
|
+
return 1;
|
|
156
|
+
}
|
|
157
|
+
await (0, project_ops_1.call)("worktrees", "forget", { name }, facts, true);
|
|
158
|
+
for (const line of verdict.lines ?? [])
|
|
159
|
+
out(line);
|
|
160
|
+
return 0;
|
|
161
|
+
}
|
|
162
|
+
async function cmdWorktrees(args) {
|
|
163
|
+
const facts = await (0, project_ops_1.currentProject)();
|
|
164
|
+
const [verb, name] = args.filter((a) => !a.startsWith("--"));
|
|
165
|
+
if (!verb) {
|
|
166
|
+
const all = await (0, project_ops_1.call)("worktrees", "list", {}, facts, true);
|
|
167
|
+
if (!all)
|
|
168
|
+
return 1;
|
|
169
|
+
const rows = all.data?.worktrees ?? [];
|
|
170
|
+
const present = rows.filter((r) => fs.existsSync(r.path)).map((r) => r.name);
|
|
171
|
+
out();
|
|
172
|
+
await (0, project_ops_1.call)("worktrees", "list", { present }, facts);
|
|
173
|
+
out();
|
|
174
|
+
return 0;
|
|
175
|
+
}
|
|
176
|
+
if ((verb === "open" || verb === "remove") && !name) {
|
|
177
|
+
out(ui.fail(`Say which worktree: comprism worktrees ${verb} <name>`));
|
|
178
|
+
return 2;
|
|
179
|
+
}
|
|
180
|
+
if (verb === "open")
|
|
181
|
+
return (await (0, project_ops_1.call)("worktrees", "open", { name }, facts)) ? 0 : 1;
|
|
182
|
+
if (verb === "remove")
|
|
183
|
+
return remove(facts, name, args.includes("--discard"));
|
|
184
|
+
out(ui.fail(`\`worktrees ${verb}\` is not a command. Use open or remove.`));
|
|
185
|
+
return 2;
|
|
186
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RunResult } from "./shell";
|
|
2
|
+
/** The browser program on this machine, or null. `COMPRISM_BROWSER` wins. */
|
|
3
|
+
export declare function findBrowser(): string | null;
|
|
4
|
+
/** The actions this machine can offer, only when a browser is installed. */
|
|
5
|
+
export declare const BROWSER_ACTIONS: string[];
|
|
6
|
+
/** The browser for one job, started on first use and closed with the job. */
|
|
7
|
+
export declare class Browser {
|
|
8
|
+
private readonly root;
|
|
9
|
+
private session;
|
|
10
|
+
constructor(root: string);
|
|
11
|
+
private page;
|
|
12
|
+
perform(name: string, a: Record<string, unknown>): Promise<RunResult>;
|
|
13
|
+
close(): void;
|
|
14
|
+
}
|