@illuminis/comprism 0.1.2 → 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 +98 -36
- 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 -14
- 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 +609 -21
- package/package.json +9 -49
|
@@ -0,0 +1,113 @@
|
|
|
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.cmdInstructions = cmdInstructions;
|
|
37
|
+
/**
|
|
38
|
+
* `comprism instructions` (manual 2.5 to 2.8): every instruction source the
|
|
39
|
+
* next job receives, and editing your personal ones. The list is the service's
|
|
40
|
+
* own, from the same function the job uses.
|
|
41
|
+
*/
|
|
42
|
+
const fs = __importStar(require("node:fs"));
|
|
43
|
+
const os = __importStar(require("node:os"));
|
|
44
|
+
const path = __importStar(require("node:path"));
|
|
45
|
+
const project_ops_1 = require("../lib/project-ops");
|
|
46
|
+
const ui = __importStar(require("../lib/ui"));
|
|
47
|
+
const out = (s = "") => process.stdout.write(s + "\n");
|
|
48
|
+
/** Subfolders holding an instruction file, found by looking, not guessing. */
|
|
49
|
+
function subfolders(root, w) {
|
|
50
|
+
const found = {};
|
|
51
|
+
const skip = new Set(w.skip);
|
|
52
|
+
const queue = [["", 0]];
|
|
53
|
+
while (queue.length && Object.keys(found).length < w.max_subfolders) {
|
|
54
|
+
const [rel, depth] = queue.shift();
|
|
55
|
+
let entries;
|
|
56
|
+
try {
|
|
57
|
+
entries = fs.readdirSync(path.join(root, rel), { withFileTypes: true });
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
for (const e of entries) {
|
|
63
|
+
if (!e.isDirectory() || e.name.startsWith(".") || skip.has(e.name))
|
|
64
|
+
continue;
|
|
65
|
+
const child = rel ? `${rel}/${e.name}` : e.name;
|
|
66
|
+
for (const name of w.subfolder_files) {
|
|
67
|
+
const body = (0, project_ops_1.readInside)(root, `${child}/${name}`);
|
|
68
|
+
if (body !== undefined && body.trim()) {
|
|
69
|
+
found[`${child}/${name}`] = body;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (depth + 1 < w.max_depth)
|
|
74
|
+
queue.push([child, depth + 1]);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return found;
|
|
78
|
+
}
|
|
79
|
+
async function cmdInstructions(args) {
|
|
80
|
+
const facts = await (0, project_ops_1.currentProject)();
|
|
81
|
+
if (args[0] === "edit") {
|
|
82
|
+
if (!args.includes("--personal")) {
|
|
83
|
+
out(ui.fail("Project instructions are files in the project; edit them there. "
|
|
84
|
+
+ "For yours: comprism instructions edit --personal"));
|
|
85
|
+
return 2;
|
|
86
|
+
}
|
|
87
|
+
const now = await (0, project_ops_1.call)("instructions", "get_personal", {}, facts, true);
|
|
88
|
+
if (!now)
|
|
89
|
+
return 1;
|
|
90
|
+
const file = path.join(fs.mkdtempSync(path.join(os.tmpdir(), "comprism-")), "personal-instructions.md");
|
|
91
|
+
fs.writeFileSync(file, String(now.data?.text ?? ""));
|
|
92
|
+
const closed = await (0, project_ops_1.openEditor)([file]);
|
|
93
|
+
const text = fs.readFileSync(file, "utf8");
|
|
94
|
+
fs.rmSync(path.dirname(file), { recursive: true, force: true });
|
|
95
|
+
if (!closed) {
|
|
96
|
+
out(ui.fail("The editor did not close cleanly, so nothing was saved."));
|
|
97
|
+
return 1;
|
|
98
|
+
}
|
|
99
|
+
out();
|
|
100
|
+
return (await (0, project_ops_1.call)("instructions", "set_personal", { text }, facts)) ? 0 : 1;
|
|
101
|
+
}
|
|
102
|
+
const wanted = await (0, project_ops_1.call)("instructions", "wanted", {}, facts, true);
|
|
103
|
+
if (!wanted)
|
|
104
|
+
return 1;
|
|
105
|
+
const w = wanted.data;
|
|
106
|
+
const inSub = subfolders(facts.root, w);
|
|
107
|
+
const files = { ...(0, project_ops_1.readSome)(facts.root, w.root_files), ...inSub };
|
|
108
|
+
const folders = Object.keys(inSub).map((f) => f.slice(0, f.lastIndexOf("/")));
|
|
109
|
+
out();
|
|
110
|
+
const reply = await (0, project_ops_1.call)("instructions", "list", { files, subfolders: folders }, facts);
|
|
111
|
+
out();
|
|
112
|
+
return reply ? 0 : 1;
|
|
113
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare const INTEGRATIONS_HELP = " comprism integrations what is connected here\n comprism integrations add <name> --url <address> a tool server on the internet\n comprism integrations add <name> --command \"<cmd>\" a tool server on this machine\n --scope project|personal|company who gets it (personal by default)\n comprism integrations login <name> sign in to it\n comprism integrations tools <name> its tools\n comprism integrations remove <name> [--scope ...] remove it";
|
|
2
|
+
export declare function cmdIntegrations(args: string[]): Promise<number>;
|
|
3
|
+
export declare function projectSettings(root: string): Record<string, unknown>;
|
|
@@ -0,0 +1,215 @@
|
|
|
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.INTEGRATIONS_HELP = void 0;
|
|
37
|
+
exports.cmdIntegrations = cmdIntegrations;
|
|
38
|
+
exports.projectSettings = projectSettings;
|
|
39
|
+
/**
|
|
40
|
+
* `comprism integrations` (manual 9.10 to 9.14, 9.18): the connections here,
|
|
41
|
+
* adding one by address or by command, signing in, its tools, removing one.
|
|
42
|
+
*
|
|
43
|
+
* The service decides every status, tool, rule and word. This sends the
|
|
44
|
+
* project's settings file so the project's own connections are known, writes
|
|
45
|
+
* the key the service returns for a project connection, starts an approved
|
|
46
|
+
* local tool server only long enough to count its tools, opens the browser
|
|
47
|
+
* for a sign in and waits for it. No token ever reaches this machine.
|
|
48
|
+
*/
|
|
49
|
+
const child_process_1 = require("child_process");
|
|
50
|
+
const fs = __importStar(require("fs"));
|
|
51
|
+
const path = __importStar(require("path"));
|
|
52
|
+
const toolservers_1 = require("../executor/toolservers");
|
|
53
|
+
const gateway_1 = require("../lib/gateway");
|
|
54
|
+
const project_ops_1 = require("../lib/project-ops");
|
|
55
|
+
const project_1 = require("../lib/project");
|
|
56
|
+
const ui = __importStar(require("../lib/ui"));
|
|
57
|
+
const SETTINGS = ".completionprism/settings.json";
|
|
58
|
+
const out = (s = "") => process.stdout.write(`${s}\n`);
|
|
59
|
+
function flag(args, name) {
|
|
60
|
+
const at = args.indexOf(name);
|
|
61
|
+
return at >= 0 ? args[at + 1] : undefined;
|
|
62
|
+
}
|
|
63
|
+
async function call(root, payload) {
|
|
64
|
+
const base = { project: root, settings: (0, project_ops_1.readInside)(root, SETTINGS) ?? null };
|
|
65
|
+
let reply = await (0, gateway_1.ask)({ intent: "integrations", prompt: "", integrationsPayload: { ...base, ...payload } });
|
|
66
|
+
let body = reply.integrations;
|
|
67
|
+
// Local servers are counted on this machine, then the answer is asked again.
|
|
68
|
+
if (reply.ok && body?.probe) {
|
|
69
|
+
const servers = new toolservers_1.ToolServers(root);
|
|
70
|
+
const local_results = {};
|
|
71
|
+
for (const p of body.probe) {
|
|
72
|
+
const r = await servers.list(p.name, p.command);
|
|
73
|
+
local_results[p.name] = r.isError ? { error: r.content } : JSON.parse(r.content);
|
|
74
|
+
}
|
|
75
|
+
servers.stopAll();
|
|
76
|
+
reply = await (0, gateway_1.ask)({ intent: "integrations", prompt: "", integrationsPayload: { ...base, ...payload, local_results } });
|
|
77
|
+
body = reply.integrations;
|
|
78
|
+
}
|
|
79
|
+
if (!reply.ok || reply.served === false || !body) {
|
|
80
|
+
out(` ${ui.fail(reply.message || "Your connections could not be read from your workspace.")}`);
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
if (body.error) {
|
|
84
|
+
out(` ${ui.fail(body.error)}`);
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
return body;
|
|
88
|
+
}
|
|
89
|
+
function draw(rows) {
|
|
90
|
+
const w = (k) => Math.max(...rows.map((r) => k(r).length)) + 3;
|
|
91
|
+
const nw = w((r) => r.name), kw = w((r) => r.kind), sw = w((r) => r.status);
|
|
92
|
+
for (const r of rows) {
|
|
93
|
+
const tools = `${r.tools} tool${r.tools === 1 ? "" : "s"}`;
|
|
94
|
+
const line = `${r.name.padEnd(nw)}${r.kind.padEnd(kw)}${r.status.padEnd(sw)}${tools.padEnd(11)}${r.where}`;
|
|
95
|
+
out(` ${r.status === "connected" ? line : ui.c.dim(line)}${r.note ? ui.c.dim(` ${r.note}`) : ""}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function openBrowser(url) {
|
|
99
|
+
if (process.env.COMPRISM_NO_BROWSER === "1")
|
|
100
|
+
return;
|
|
101
|
+
const [cmd, args] = process.platform === "darwin" ? ["open", [url]]
|
|
102
|
+
: process.platform === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
|
|
103
|
+
try {
|
|
104
|
+
// nosemgrep: javascript.lang.security.detect-child-process.detect-child-process -- opens a sign in address in the browser, passed as one argument, never through a shell
|
|
105
|
+
(0, child_process_1.spawn)(cmd, args, { stdio: "ignore", detached: true }).unref();
|
|
106
|
+
}
|
|
107
|
+
catch { /* the address is printed as well */ }
|
|
108
|
+
}
|
|
109
|
+
async function login(root, name) {
|
|
110
|
+
const started = await call(root, { op: "login", name });
|
|
111
|
+
if (!started?.authorize_url)
|
|
112
|
+
return 1;
|
|
113
|
+
out(` ${started.line ?? ""}`);
|
|
114
|
+
out(ui.c.dim(` If it did not open: ${started.authorize_url}`));
|
|
115
|
+
openBrowser(started.authorize_url);
|
|
116
|
+
const waitMs = Number(process.env.COMPRISM_SIGN_IN_WAIT_MS || 180_000);
|
|
117
|
+
const until = Date.now() + waitMs;
|
|
118
|
+
while (Date.now() < until) {
|
|
119
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
120
|
+
const now = await call(root, { op: "status", name });
|
|
121
|
+
if (!now)
|
|
122
|
+
return 1;
|
|
123
|
+
if (now.row && now.row.status !== "needs sign in") {
|
|
124
|
+
out(` ${name} is ${now.row.status}${now.row.tools ? `, ${now.row.tools} tools` : ""}.`);
|
|
125
|
+
return now.row.status === "connected" ? 0 : 1;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
out(` ${ui.fail(`Sign in was not completed, so ${name} still needs sign in. Run comprism integrations login ${name} to try again.`)}`);
|
|
129
|
+
return 1;
|
|
130
|
+
}
|
|
131
|
+
exports.INTEGRATIONS_HELP = ` comprism integrations what is connected here
|
|
132
|
+
comprism integrations add <name> --url <address> a tool server on the internet
|
|
133
|
+
comprism integrations add <name> --command "<cmd>" a tool server on this machine
|
|
134
|
+
--scope project|personal|company who gets it (personal by default)
|
|
135
|
+
comprism integrations login <name> sign in to it
|
|
136
|
+
comprism integrations tools <name> its tools
|
|
137
|
+
comprism integrations remove <name> [--scope ...] remove it`;
|
|
138
|
+
async function cmdIntegrations(args) {
|
|
139
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
140
|
+
out(exports.INTEGRATIONS_HELP);
|
|
141
|
+
return 0;
|
|
142
|
+
}
|
|
143
|
+
const valued = new Set(["--url", "--command", "--scope", "--cwd"]);
|
|
144
|
+
const words = args.filter((a, i) => !a.startsWith("--") && !valued.has(args[i - 1] ?? ""));
|
|
145
|
+
const [sub, name] = words;
|
|
146
|
+
const root = (0, project_1.resolveProject)(flag(args, "--cwd") ?? process.cwd()).root;
|
|
147
|
+
const scope = flag(args, "--scope");
|
|
148
|
+
if (!sub) {
|
|
149
|
+
const body = await call(root, { op: "list" });
|
|
150
|
+
if (!body)
|
|
151
|
+
return 1;
|
|
152
|
+
if (!body.rows?.length)
|
|
153
|
+
out(` ${body.empty ?? ""}`);
|
|
154
|
+
else
|
|
155
|
+
draw(body.rows);
|
|
156
|
+
return 0;
|
|
157
|
+
}
|
|
158
|
+
if (!name && ["add", "login", "tools", "remove"].includes(sub)) {
|
|
159
|
+
out(` ${ui.fail(`comprism integrations ${sub} takes the connection's name.`)}`);
|
|
160
|
+
return 2;
|
|
161
|
+
}
|
|
162
|
+
switch (sub) {
|
|
163
|
+
case "add": {
|
|
164
|
+
const body = await call(root, { op: "add", name, url: flag(args, "--url"), command: flag(args, "--command"), scope });
|
|
165
|
+
if (!body)
|
|
166
|
+
return 1;
|
|
167
|
+
if (body.write) {
|
|
168
|
+
(0, project_ops_1.writeSetting)(root, body.write.file, body.write.key, body.write.value);
|
|
169
|
+
}
|
|
170
|
+
out(` ${body.line ?? ""}`);
|
|
171
|
+
// If the server needs a sign in, the browser opens now (9.11).
|
|
172
|
+
if (body.needs_sign_in)
|
|
173
|
+
return login(root, String(name));
|
|
174
|
+
return 0;
|
|
175
|
+
}
|
|
176
|
+
case "login":
|
|
177
|
+
return login(root, String(name));
|
|
178
|
+
case "tools": {
|
|
179
|
+
const body = await call(root, { op: "tools", name });
|
|
180
|
+
if (!body)
|
|
181
|
+
return 1;
|
|
182
|
+
if (body.line)
|
|
183
|
+
out(` ${body.line}`);
|
|
184
|
+
const tools = body.tools ?? [];
|
|
185
|
+
const w = Math.max(0, ...tools.map((t) => t.name.length)) + 3;
|
|
186
|
+
for (const t of tools) {
|
|
187
|
+
const kind = t.blocked ? "blocked" : t.reads ? "reads" : "changes";
|
|
188
|
+
out(` ${t.name.padEnd(w)}${kind.padEnd(9)}${ui.c.dim(t.description)}`);
|
|
189
|
+
}
|
|
190
|
+
return 0;
|
|
191
|
+
}
|
|
192
|
+
case "remove": {
|
|
193
|
+
const body = await call(root, { op: "remove", name, scope });
|
|
194
|
+
if (!body)
|
|
195
|
+
return 1;
|
|
196
|
+
if (body.write)
|
|
197
|
+
(0, project_ops_1.writeSetting)(root, body.write.file, body.write.key, body.write.value);
|
|
198
|
+
out(` ${body.line ?? ""}`);
|
|
199
|
+
return 0;
|
|
200
|
+
}
|
|
201
|
+
default:
|
|
202
|
+
out(` ${ui.fail(`\`integrations ${sub}\` is not an integrations command.`)}`);
|
|
203
|
+
out(exports.INTEGRATIONS_HELP);
|
|
204
|
+
return 2;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// Kept for tests that read the settings file the service told us to write.
|
|
208
|
+
function projectSettings(root) {
|
|
209
|
+
try {
|
|
210
|
+
return JSON.parse(fs.readFileSync(path.join(root, SETTINGS), "utf8"));
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
return {};
|
|
214
|
+
}
|
|
215
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Where a background job's log is noted, by job id, on this machine. */
|
|
2
|
+
export declare function pointerFor(jobId: string): string;
|
|
3
|
+
/** Written by the background process once it knows its job id. */
|
|
4
|
+
export declare function notePointer(jobId: string, log: string): void;
|
|
5
|
+
export declare function cmdJobs(args: string[]): Promise<number>;
|
|
@@ -0,0 +1,157 @@
|
|
|
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.pointerFor = pointerFor;
|
|
37
|
+
exports.notePointer = notePointer;
|
|
38
|
+
exports.cmdJobs = cmdJobs;
|
|
39
|
+
/**
|
|
40
|
+
* `comprism jobs`, `jobs attach`, `jobs stop` (manual 5.14).
|
|
41
|
+
*
|
|
42
|
+
* The list and the stopping are the service's: it knows which of this
|
|
43
|
+
* person's jobs run in the background and it stops them. Attaching is local,
|
|
44
|
+
* because a background job's output is written to a log on this machine by the
|
|
45
|
+
* process doing the work, and watching it means reading that file as it grows.
|
|
46
|
+
*/
|
|
47
|
+
const fs = __importStar(require("fs"));
|
|
48
|
+
const path = __importStar(require("path"));
|
|
49
|
+
const config_1 = require("../lib/config");
|
|
50
|
+
const gateway_1 = require("../lib/gateway");
|
|
51
|
+
const ui = __importStar(require("../lib/ui"));
|
|
52
|
+
const out = (s = "") => process.stdout.write(`${s}\n`);
|
|
53
|
+
/** Where a background job's log is noted, by job id, on this machine. */
|
|
54
|
+
function pointerFor(jobId) {
|
|
55
|
+
return path.join((0, config_1.homeDir)(), "jobs", `${jobId}.json`);
|
|
56
|
+
}
|
|
57
|
+
/** Written by the background process once it knows its job id. */
|
|
58
|
+
function notePointer(jobId, log) {
|
|
59
|
+
try {
|
|
60
|
+
fs.mkdirSync(path.join((0, config_1.homeDir)(), "jobs"), { recursive: true });
|
|
61
|
+
fs.writeFileSync(pointerFor(jobId), JSON.stringify({ log, pid: process.pid }), { mode: 0o600 });
|
|
62
|
+
}
|
|
63
|
+
catch { /* attaching is a convenience; the job runs regardless */ }
|
|
64
|
+
}
|
|
65
|
+
async function ask(op, job) {
|
|
66
|
+
return (0, gateway_1.ask)({ intent: "jobs", prompt: "", jobsPayload: { op, ...(job ? { job } : {}) } });
|
|
67
|
+
}
|
|
68
|
+
function alive(pid) {
|
|
69
|
+
try {
|
|
70
|
+
process.kill(pid, 0);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async function cmdJobs(args) {
|
|
78
|
+
const [op, name] = [args[0], args[1]];
|
|
79
|
+
if (!op || op === "list") {
|
|
80
|
+
const r = await ask("list");
|
|
81
|
+
if (!r.ok || !r.jobs) {
|
|
82
|
+
out(ui.fail(r.message || "The job list could not be read."));
|
|
83
|
+
return 1;
|
|
84
|
+
}
|
|
85
|
+
for (const line of r.jobs.lines)
|
|
86
|
+
out(` ${line}`);
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
if ((op === "attach" || op === "stop") && !name) {
|
|
90
|
+
out(ui.fail(`jobs ${op} needs a job, for example jobs ${op} j_7c21.`));
|
|
91
|
+
return 2;
|
|
92
|
+
}
|
|
93
|
+
if (op === "stop") {
|
|
94
|
+
const r = await ask("stop", name);
|
|
95
|
+
if (!r.ok || !r.jobs) {
|
|
96
|
+
out(ui.fail(r.message || "That job could not be stopped."));
|
|
97
|
+
return 1;
|
|
98
|
+
}
|
|
99
|
+
for (const line of r.jobs.lines)
|
|
100
|
+
out(` ${line}`);
|
|
101
|
+
return 0;
|
|
102
|
+
}
|
|
103
|
+
if (op === "attach") {
|
|
104
|
+
const r = await ask("find", name);
|
|
105
|
+
if (!r.ok || !r.jobs?.job_id) {
|
|
106
|
+
out(ui.fail(r.message || "There is no such job."));
|
|
107
|
+
return 1;
|
|
108
|
+
}
|
|
109
|
+
let note;
|
|
110
|
+
try {
|
|
111
|
+
note = JSON.parse(fs.readFileSync(pointerFor(r.jobs.job_id), "utf8"));
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
out(ui.fail("That job did not start on this machine, so its output is not here. The portal's Work page shows it."));
|
|
115
|
+
return 1;
|
|
116
|
+
}
|
|
117
|
+
return follow(note.log, note.pid);
|
|
118
|
+
}
|
|
119
|
+
out(ui.fail(`jobs has no ${op}. Use jobs, jobs attach <job> or jobs stop <job>.`));
|
|
120
|
+
return 2;
|
|
121
|
+
}
|
|
122
|
+
/** Print the log and keep printing as it grows, until the job's process ends
|
|
123
|
+
* or Ctrl+C. Ctrl+C here stops watching, never the job. */
|
|
124
|
+
function follow(log, pid) {
|
|
125
|
+
return new Promise((resolve) => {
|
|
126
|
+
let at = 0;
|
|
127
|
+
const pump = () => {
|
|
128
|
+
try {
|
|
129
|
+
const size = fs.statSync(log).size;
|
|
130
|
+
if (size > at) {
|
|
131
|
+
const fd = fs.openSync(log, "r");
|
|
132
|
+
const buf = Buffer.alloc(size - at);
|
|
133
|
+
fs.readSync(fd, buf, 0, buf.length, at);
|
|
134
|
+
fs.closeSync(fd);
|
|
135
|
+
at = size;
|
|
136
|
+
process.stdout.write(buf.toString());
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch { /* not written yet */ }
|
|
140
|
+
};
|
|
141
|
+
const timer = setInterval(() => {
|
|
142
|
+
pump();
|
|
143
|
+
if (!alive(pid)) {
|
|
144
|
+
clearInterval(timer);
|
|
145
|
+
pump();
|
|
146
|
+
out(ui.c.dim(" the job has finished"));
|
|
147
|
+
resolve(0);
|
|
148
|
+
}
|
|
149
|
+
}, 300);
|
|
150
|
+
process.once("SIGINT", () => {
|
|
151
|
+
clearInterval(timer);
|
|
152
|
+
out(ui.c.dim("\n stopped watching; the job carries on. jobs stop stops it."));
|
|
153
|
+
resolve(0);
|
|
154
|
+
});
|
|
155
|
+
pump();
|
|
156
|
+
});
|
|
157
|
+
}
|