@illuminis/comprism 0.1.5 → 0.1.6
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/out/agent/command.js +4 -4
- package/out/agent/session.d.ts +6 -1
- package/out/agent/session.js +17 -8
- package/out/commands/agents.js +3 -3
- package/out/commands/ask.js +8 -8
- package/out/commands/codemap.d.ts +1 -1
- package/out/commands/codemap.js +3 -3
- package/out/commands/commands-thin.js +4 -4
- package/out/commands/config.js +1 -1
- package/out/commands/cost.js +4 -4
- package/out/commands/hooks.js +1 -1
- package/out/commands/install.d.ts +1 -1
- package/out/commands/install.js +3 -2
- package/out/commands/instructions.js +1 -1
- package/out/commands/integrations.js +4 -4
- package/out/commands/keys.js +6 -6
- package/out/commands/login.js +37 -21
- package/out/commands/permissions.js +2 -2
- package/out/commands/plugins.js +3 -3
- package/out/commands/privacy.js +2 -2
- package/out/commands/repl.js +107 -83
- package/out/commands/review.js +6 -6
- package/out/commands/settings.js +30 -123
- package/out/commands/skills.js +2 -2
- package/out/commands/unattended.js +6 -6
- package/out/commands/update.js +1 -1
- package/out/commands/welcome.js +20 -29
- package/out/commands/worktrees.d.ts +1 -1
- package/out/graph/sync.d.ts +1 -1
- package/out/graph/sync.js +6 -6
- package/out/lib/attach.js +4 -3
- package/out/lib/commandlist.d.ts +1 -1
- package/out/lib/commandlist.js +2 -2
- package/out/lib/config.d.ts +3 -2
- package/out/lib/config.js +7 -8
- package/out/lib/connection.js +1 -1
- package/out/lib/gateway.d.ts +5 -5
- package/out/lib/machine.js +1 -1
- package/out/lib/project-ops.d.ts +1 -1
- package/out/lib/project-ops.js +4 -4
- package/out/lib/queue.js +1 -1
- package/out/lib/readiness.d.ts +3 -30
- package/out/lib/readiness.js +13 -82
- package/out/lib/servicecommand.d.ts +14 -0
- package/out/lib/servicecommand.js +74 -0
- package/out/lib/sessions.js +3 -3
- package/out/lib/ui.d.ts +9 -6
- package/out/lib/ui.js +20 -26
- package/out/lib/voice.js +1 -1
- package/out/lib/words.d.ts +20 -0
- package/out/lib/words.js +27 -0
- package/out/machine/codemap/build.d.ts +45 -0
- package/out/machine/codemap/build.js +91 -0
- package/out/machine/codemap/facts.d.ts +47 -0
- package/out/machine/codemap/facts.js +12 -0
- package/out/machine/codemap/files.d.ts +45 -0
- package/out/machine/codemap/files.js +207 -0
- package/out/machine/codemap/read-locales.d.ts +29 -0
- package/out/machine/codemap/read-locales.js +246 -0
- package/out/machine/codemap/read-python.d.ts +11 -0
- package/out/machine/codemap/read-python.js +116 -0
- package/out/machine/codemap/read-typescript.d.ts +16 -0
- package/out/machine/codemap/read-typescript.js +292 -0
- package/out/machine/executor/browser.d.ts +14 -0
- package/out/machine/executor/browser.js +270 -0
- package/out/machine/executor/diagnostics.d.ts +2 -0
- package/out/machine/executor/diagnostics.js +181 -0
- package/out/machine/executor/documents.d.ts +40 -0
- package/out/machine/executor/documents.js +170 -0
- package/out/machine/executor/files.d.ts +2 -0
- package/out/machine/executor/files.js +590 -0
- package/out/machine/executor/git.d.ts +48 -0
- package/out/machine/executor/git.js +145 -0
- package/out/machine/executor/hooks.d.ts +51 -0
- package/out/machine/executor/hooks.js +154 -0
- package/out/machine/executor/index.d.ts +45 -0
- package/out/machine/executor/index.js +367 -0
- package/out/machine/executor/notebook.d.ts +2 -0
- package/out/machine/executor/notebook.js +147 -0
- package/out/machine/executor/paths.d.ts +20 -0
- package/out/machine/executor/paths.js +154 -0
- package/out/machine/executor/sandbox.d.ts +40 -0
- package/out/machine/executor/sandbox.js +299 -0
- package/out/machine/executor/shell.d.ts +86 -0
- package/out/machine/executor/shell.js +582 -0
- package/out/machine/executor/toolservers.d.ts +20 -0
- package/out/machine/executor/toolservers.js +189 -0
- package/out/machine/executor/worktree.d.ts +9 -0
- package/out/machine/executor/worktree.js +119 -0
- package/out/machine/folder/project.d.ts +28 -0
- package/out/machine/folder/project.js +114 -0
- package/out/machine/runtime/home.d.ts +2 -0
- package/out/machine/runtime/home.js +48 -0
- package/out/machine/runtime/needs.d.ts +30 -0
- package/out/machine/runtime/needs.js +89 -0
- package/out/machine/runtime/self.d.ts +23 -0
- package/out/machine/runtime/self.js +124 -0
- package/out/providers/index.js +2 -1
- package/out/thin.js +11 -10
- package/package.json +4 -4
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.gitStatus = gitStatus;
|
|
4
|
+
exports.gitDiff = gitDiff;
|
|
5
|
+
exports.gitLog = gitLog;
|
|
6
|
+
exports.gitBranch = gitBranch;
|
|
7
|
+
exports.gitCommit = gitCommit;
|
|
8
|
+
exports.gitPush = gitPush;
|
|
9
|
+
/**
|
|
10
|
+
* Reading the repository, and recording work in it.
|
|
11
|
+
*
|
|
12
|
+
* Specification: docs/modules/CODING_AGENT_BUILD_SPECIFICATION.md, register
|
|
13
|
+
* items D23 to D27.
|
|
14
|
+
*
|
|
15
|
+
* **Pushing is the only thing here that sends anything anywhere**, and it is
|
|
16
|
+
* the only one the server has to have allowed first. Pull requests, reviews,
|
|
17
|
+
* checks and releases are not git operations at all: they go through GitHub's
|
|
18
|
+
* own API, on the server, because they need the tenant's credential and that
|
|
19
|
+
* must never be sent to a client.
|
|
20
|
+
*
|
|
21
|
+
* So the split is by what each thing needs. A push needs the repository, which
|
|
22
|
+
* is here. A pull request needs the credential, which is there.
|
|
23
|
+
*
|
|
24
|
+
* Every command goes through `runCommand`, so the folder boundary, the trimmed
|
|
25
|
+
* environment, the timeout and the output cap all apply here too rather than
|
|
26
|
+
* being reimplemented for git.
|
|
27
|
+
*/
|
|
28
|
+
const shell_1 = require("./shell");
|
|
29
|
+
/** Every git call is a program and a list of arguments, with no shell.
|
|
30
|
+
*
|
|
31
|
+
* A commit message is written by a model and can contain anything: quotes,
|
|
32
|
+
* backticks, a newline, a semicolon. Pasting one into a shell string is how a
|
|
33
|
+
* message becomes a second command, and quoting it for one shell broke it on
|
|
34
|
+
* another: Windows kept the POSIX quotes as part of the message. */
|
|
35
|
+
const git = (args, opts) => (0, shell_1.runProgram)("git", args, opts);
|
|
36
|
+
async function gitStatus(opts) {
|
|
37
|
+
// Porcelain, because the human-readable format changes between versions and
|
|
38
|
+
// the model has to be able to rely on the shape.
|
|
39
|
+
const r = await git(["status", "--porcelain=v1", "--branch"], opts);
|
|
40
|
+
if (!r.isError && /^exit 0/.test(r.content) && r.content.trim().split("\n").length <= 3) {
|
|
41
|
+
return { ...r, content: `${r.content}\n\n[Nothing has changed in the working tree.]` };
|
|
42
|
+
}
|
|
43
|
+
return r;
|
|
44
|
+
}
|
|
45
|
+
async function gitDiff(opts) {
|
|
46
|
+
const parts = ["--no-pager", "diff"];
|
|
47
|
+
if (opts.staged)
|
|
48
|
+
parts.push("--staged");
|
|
49
|
+
// Color off explicitly: a diff full of escape codes costs tokens and reads
|
|
50
|
+
// as noise to a model.
|
|
51
|
+
parts.push("--no-color");
|
|
52
|
+
if (opts.path)
|
|
53
|
+
parts.push("--", opts.path);
|
|
54
|
+
return git(parts, opts);
|
|
55
|
+
}
|
|
56
|
+
async function gitLog(opts) {
|
|
57
|
+
const limit = Math.max(1, Math.min(opts.limit ?? 20, 100));
|
|
58
|
+
const parts = [
|
|
59
|
+
"--no-pager", "log", "-n", String(limit),
|
|
60
|
+
// One argument, spaces and all. When this went through a shell it had to be
|
|
61
|
+
// quoted, or git read "%an" as a revision and failed with "ambiguous
|
|
62
|
+
// argument", which reads like a broken repository.
|
|
63
|
+
"--pretty=format:%h %an %ar %s",
|
|
64
|
+
];
|
|
65
|
+
if (opts.path)
|
|
66
|
+
parts.push("--", opts.path);
|
|
67
|
+
return git(parts, opts);
|
|
68
|
+
}
|
|
69
|
+
async function gitBranch(name, opts) {
|
|
70
|
+
if (!/^[\w./-]{1,120}$/.test(name)) {
|
|
71
|
+
return {
|
|
72
|
+
isError: true,
|
|
73
|
+
content: `Refused: ${name} is not a usable branch name. Letters, numbers, dots, dashes, underscores and slashes only.`,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return git(["checkout", "-b", name], opts);
|
|
77
|
+
}
|
|
78
|
+
async function gitCommit(message, opts) {
|
|
79
|
+
if (!message.trim()) {
|
|
80
|
+
return { isError: true, content: "Refused: a commit needs a message." };
|
|
81
|
+
}
|
|
82
|
+
// Only the files named: what the agent changed, or what the person named.
|
|
83
|
+
// Never "add everything", which would sweep in the person's own unrelated
|
|
84
|
+
// work (manual 5.17).
|
|
85
|
+
if (!opts.paths?.length) {
|
|
86
|
+
return {
|
|
87
|
+
isError: true,
|
|
88
|
+
content: "Refused: nothing to commit that this session changed. Name the files to commit.",
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const staged = await git(["add", "--", ...opts.paths], opts);
|
|
92
|
+
if (staged.isError || !/^exit 0/.test(staged.content))
|
|
93
|
+
return { ...staged, isError: true };
|
|
94
|
+
// Nothing to commit is a normal outcome, not a failure. Reported plainly so
|
|
95
|
+
// the model does not conclude that committing is broken and try again.
|
|
96
|
+
const check = await git(["diff", "--staged", "--quiet"], opts);
|
|
97
|
+
if (/^exit 0\b/.test(check.content)) {
|
|
98
|
+
return { content: "Nothing to commit: no changes are staged.", summary: "nothing to commit" };
|
|
99
|
+
}
|
|
100
|
+
// Attribution, always. A commit that hides having been written by an agent is
|
|
101
|
+
// a commit somebody later reads as a colleague's careful work, and the whole
|
|
102
|
+
// record this product keeps depends on that not happening.
|
|
103
|
+
const trailer = "\n\nCo-authored-by: illuminis coding agent <agent@illuminis.ai>";
|
|
104
|
+
const made = await git(["commit", "-m", message + trailer], opts);
|
|
105
|
+
// A commit hook that refused it is a failed commit, said so (manual 5.17).
|
|
106
|
+
// Its output is the reason; what was staged is left staged for the person.
|
|
107
|
+
if (!/^exit 0/.test(made.content)) {
|
|
108
|
+
return { ...made, isError: true, summary: "commit failed", content: `Commit failed. ${made.content}` };
|
|
109
|
+
}
|
|
110
|
+
return { ...made, summary: `committed ${opts.paths.join(", ")}` };
|
|
111
|
+
}
|
|
112
|
+
/** Send commits to the remote.
|
|
113
|
+
*
|
|
114
|
+
* Reached only after the server has allowed it: the branch is one the person
|
|
115
|
+
* named for this repository, it is not a branch the project is built from, and
|
|
116
|
+
* they have just confirmed it. This function does not re-decide any of that,
|
|
117
|
+
* and it must not: a client that could decide whether it may publish is a
|
|
118
|
+
* client that could grant itself permission.
|
|
119
|
+
*
|
|
120
|
+
* **There is no force push and there is no upstream rewrite.** Not as an
|
|
121
|
+
* option, not behind a flag. Everything on the remote stays recoverable by
|
|
122
|
+
* whoever is working from it.
|
|
123
|
+
*/
|
|
124
|
+
async function gitPush(branch, opts) {
|
|
125
|
+
if (!/^[\w./-]{1,120}$/.test(branch)) {
|
|
126
|
+
return { isError: true, content: `Refused: ${branch} is not a usable branch name.` };
|
|
127
|
+
}
|
|
128
|
+
// What is about to go, named before it goes. A push that reports success
|
|
129
|
+
// without saying what it sent is a push nobody can check afterwards.
|
|
130
|
+
// A branch the remote has not seen yet has no range to compare with, so the
|
|
131
|
+
// last five commits stand in for it.
|
|
132
|
+
let ahead = await git(["--no-pager", "log", "--oneline", `origin/${branch}..HEAD`], opts);
|
|
133
|
+
if (!/^exit 0/.test(ahead.content))
|
|
134
|
+
ahead = await git(["--no-pager", "log", "--oneline", "-5"], opts);
|
|
135
|
+
// `-u` on a new branch so later pushes need no arguments, and nothing else.
|
|
136
|
+
// No `--force`, no `--force-with-lease`, no `+refs` refspec.
|
|
137
|
+
const pushed = await git(["push", ...(opts.createRemote ? ["-u"] : []), "origin", branch], opts);
|
|
138
|
+
if (pushed.isError || !/^exit 0/.test(pushed.content)) {
|
|
139
|
+
return { ...pushed, isError: true };
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
content: `Pushed to ${branch}.\n\nWhat went:\n${ahead.content}`,
|
|
143
|
+
summary: `pushed ${branch}`,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** The settings files that can hold hooks, sent as read for `comprism hooks`. */
|
|
2
|
+
export declare const FILES: string[];
|
|
3
|
+
/** One hook as the service hands it over. */
|
|
4
|
+
export interface PlannedHook {
|
|
5
|
+
when: string;
|
|
6
|
+
on?: string;
|
|
7
|
+
command: string;
|
|
8
|
+
what?: string | null;
|
|
9
|
+
timeout_s?: number;
|
|
10
|
+
source?: string;
|
|
11
|
+
}
|
|
12
|
+
/** The hooks to run around one action, in order. */
|
|
13
|
+
export interface HookPlan {
|
|
14
|
+
before?: PlannedHook[];
|
|
15
|
+
after?: PlannedHook[];
|
|
16
|
+
}
|
|
17
|
+
/** Set inside a hook's own commands, so nothing they do runs hooks again. */
|
|
18
|
+
export declare const IN_HOOK = "COMPRISM_IN_HOOK";
|
|
19
|
+
export declare function insideHook(): boolean;
|
|
20
|
+
/** The settings files present in this project, as text, for the service. */
|
|
21
|
+
export declare function hookFiles(root: string): Record<string, string>;
|
|
22
|
+
export interface HookContext {
|
|
23
|
+
when: string;
|
|
24
|
+
action?: string;
|
|
25
|
+
args?: Record<string, unknown>;
|
|
26
|
+
facts?: Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
export interface HookRun {
|
|
29
|
+
hook: PlannedHook;
|
|
30
|
+
ok: boolean;
|
|
31
|
+
timedOut: boolean;
|
|
32
|
+
output: string;
|
|
33
|
+
}
|
|
34
|
+
export interface HooksOutcome {
|
|
35
|
+
runs: HookRun[];
|
|
36
|
+
/** Set when a `before` hook refused the action. */
|
|
37
|
+
refusedBy?: string;
|
|
38
|
+
detail?: string;
|
|
39
|
+
/** `after`, `job_start`, `job_end` and `waiting` hooks that failed. */
|
|
40
|
+
failed: string[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Run the hooks the service named, one after another, in its order.
|
|
44
|
+
*
|
|
45
|
+
* Details go in as `COMPRISM_` variables and as one JSON object on standard
|
|
46
|
+
* input. Each hook has its own time limit (30 seconds unless the service said
|
|
47
|
+
* otherwise) and is stopped and reported when it runs over.
|
|
48
|
+
*/
|
|
49
|
+
export declare function runHooks(root: string, hooks: PlannedHook[], ctx: HookContext): Promise<HooksOutcome>;
|
|
50
|
+
/** One line per hook that ran, for the full view and `hooks test` (10.10). */
|
|
51
|
+
export declare function reportLines(outcome: HooksOutcome): string[];
|
|
@@ -0,0 +1,154 @@
|
|
|
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.IN_HOOK = exports.FILES = void 0;
|
|
37
|
+
exports.insideHook = insideHook;
|
|
38
|
+
exports.hookFiles = hookFiles;
|
|
39
|
+
exports.runHooks = runHooks;
|
|
40
|
+
exports.reportLines = reportLines;
|
|
41
|
+
/**
|
|
42
|
+
* Hooks: running the person's own commands at the moments the service names
|
|
43
|
+
* (manual 10.9, 10.10).
|
|
44
|
+
*
|
|
45
|
+
* Which hooks run, for which action, in what order and with what time limit is
|
|
46
|
+
* decided by the service and arrives with each action, or with a `run_hooks`
|
|
47
|
+
* request for a moment of the job. Nothing here matches a hook to an action.
|
|
48
|
+
* What is left is the physical part: read the project's settings files when
|
|
49
|
+
* `comprism hooks` asks, and run a command with the details it needs.
|
|
50
|
+
*
|
|
51
|
+
* A `before` hook can refuse its action. Nothing a hook does approves one, and
|
|
52
|
+
* a hook's own commands never set off hooks: they are not the job's actions,
|
|
53
|
+
* and a command started from inside a hook runs with every hook switched off.
|
|
54
|
+
*/
|
|
55
|
+
const fs = __importStar(require("fs"));
|
|
56
|
+
const path = __importStar(require("path"));
|
|
57
|
+
const shell_1 = require("./shell");
|
|
58
|
+
/** The settings files that can hold hooks, sent as read for `comprism hooks`. */
|
|
59
|
+
exports.FILES = [
|
|
60
|
+
".completionprism/settings.json",
|
|
61
|
+
".completionprism/settings.local.json",
|
|
62
|
+
".comprism/settings.json",
|
|
63
|
+
".claude/settings.json",
|
|
64
|
+
".illuminis/hooks.json",
|
|
65
|
+
];
|
|
66
|
+
/** Set inside a hook's own commands, so nothing they do runs hooks again. */
|
|
67
|
+
exports.IN_HOOK = "COMPRISM_IN_HOOK";
|
|
68
|
+
function insideHook() {
|
|
69
|
+
return process.env[exports.IN_HOOK] === "1";
|
|
70
|
+
}
|
|
71
|
+
/** The settings files present in this project, as text, for the service. */
|
|
72
|
+
function hookFiles(root) {
|
|
73
|
+
const out = {};
|
|
74
|
+
for (const name of exports.FILES) {
|
|
75
|
+
const file = path.join(root, name);
|
|
76
|
+
try {
|
|
77
|
+
if (fs.existsSync(file))
|
|
78
|
+
out[name] = fs.readFileSync(file, "utf8").slice(0, 200_000);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
/* unreadable is the same as absent to the service */
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
function fileOf(args) {
|
|
87
|
+
return String(args.path ?? args.file_path ?? args.to ?? "");
|
|
88
|
+
}
|
|
89
|
+
function said(h) {
|
|
90
|
+
return h.what || h.command;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Run the hooks the service named, one after another, in its order.
|
|
94
|
+
*
|
|
95
|
+
* Details go in as `COMPRISM_` variables and as one JSON object on standard
|
|
96
|
+
* input. Each hook has its own time limit (30 seconds unless the service said
|
|
97
|
+
* otherwise) and is stopped and reported when it runs over.
|
|
98
|
+
*/
|
|
99
|
+
async function runHooks(root, hooks, ctx) {
|
|
100
|
+
const outcome = { runs: [], failed: [] };
|
|
101
|
+
if (!hooks.length || insideHook())
|
|
102
|
+
return outcome;
|
|
103
|
+
const args = ctx.args ?? {};
|
|
104
|
+
const input = JSON.stringify({ when: ctx.when, action: ctx.action ?? null, input: args,
|
|
105
|
+
...(ctx.facts ?? {}) });
|
|
106
|
+
for (const hook of hooks) {
|
|
107
|
+
const secs = Math.max(1, Number(hook.timeout_s ?? 30));
|
|
108
|
+
const result = await (0, shell_1.runCommand)(hook.command, {
|
|
109
|
+
root,
|
|
110
|
+
timeoutMs: secs * 1000,
|
|
111
|
+
input,
|
|
112
|
+
label: `hook: ${hook.command}`, // client-strings-allowed: the hook's own command, shown verbatim in the job log
|
|
113
|
+
extraEnv: {
|
|
114
|
+
[exports.IN_HOOK]: "1",
|
|
115
|
+
COMPRISM_WHEN: ctx.when,
|
|
116
|
+
COMPRISM_ACTION: ctx.action ?? "",
|
|
117
|
+
COMPRISM_FILE: fileOf(args),
|
|
118
|
+
COMPRISM_COMMAND: String(args.command ?? ""),
|
|
119
|
+
COMPRISM_OUTCOME: String(ctx.facts?.outcome ?? ""),
|
|
120
|
+
// The earlier names, so a script written for them keeps working.
|
|
121
|
+
ILLUMINIS_ACTION: ctx.action ?? "",
|
|
122
|
+
ILLUMINIS_PATH: fileOf(args),
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
const timedOut = Boolean(result.facts?.timed_out);
|
|
126
|
+
const ok = !result.isError && /^exit 0/.test(result.content);
|
|
127
|
+
const output = timedOut
|
|
128
|
+
? `stopped after ${secs}s, its time limit`
|
|
129
|
+
: result.content.replace(/^exit -?\d+\s*/, "").trim().slice(0, 2000);
|
|
130
|
+
outcome.runs.push({ hook, ok, timedOut, output });
|
|
131
|
+
if (ok)
|
|
132
|
+
continue;
|
|
133
|
+
if (ctx.when === "before") {
|
|
134
|
+
outcome.refusedBy = hook.command;
|
|
135
|
+
outcome.detail = `${hook.what ?? "A hook in this project"} refused this`
|
|
136
|
+
+ (timedOut ? ` (it was stopped after ${secs}s, its time limit)` : "")
|
|
137
|
+
+ (output && !timedOut ? `: ${output.slice(0, 500)}` : ".");
|
|
138
|
+
return outcome;
|
|
139
|
+
}
|
|
140
|
+
outcome.failed.push(`${said(hook)}: ${timedOut ? `stopped after ${secs}s, its time limit` : output.slice(0, 300) || "failed"}`);
|
|
141
|
+
}
|
|
142
|
+
return outcome;
|
|
143
|
+
}
|
|
144
|
+
/** One line per hook that ran, for the full view and `hooks test` (10.10). */
|
|
145
|
+
function reportLines(outcome) {
|
|
146
|
+
const lines = [];
|
|
147
|
+
for (const run of outcome.runs) {
|
|
148
|
+
const mark = run.ok ? "ok " : run.timedOut ? "time" : "fail";
|
|
149
|
+
lines.push(`${mark} hook ${run.hook.when} ${run.hook.command}`);
|
|
150
|
+
for (const l of run.output.split("\n").filter(Boolean).slice(0, 20))
|
|
151
|
+
lines.push(` ${l}`);
|
|
152
|
+
}
|
|
153
|
+
return lines;
|
|
154
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as hooks from "./hooks";
|
|
2
|
+
import { ToolServers } from "./toolservers";
|
|
3
|
+
import { RunResult, guessTestCommand, stopEverything, stopForeground } from "./shell";
|
|
4
|
+
export { stopEverything, stopForeground, guessTestCommand };
|
|
5
|
+
export type { RunResult };
|
|
6
|
+
/** Everything a machine with a shell can do. Sent to the server on hello, and
|
|
7
|
+
* the catalog offered to the model is narrowed to it, so a client is never
|
|
8
|
+
* told about an action it cannot perform. */
|
|
9
|
+
export declare const NATIVE_CAPABILITIES: string[];
|
|
10
|
+
export interface ExecutorOptions {
|
|
11
|
+
root: string;
|
|
12
|
+
/** Folders the person added for this job (manual 2.3). */
|
|
13
|
+
added?: string[];
|
|
14
|
+
/** Called with each chunk of a running command's output, so a terminal can
|
|
15
|
+
* show it as it happens rather than in one block at the end. */
|
|
16
|
+
onOutput?: (chunk: string) => void;
|
|
17
|
+
}
|
|
18
|
+
export declare class NativeExecutor {
|
|
19
|
+
/** What this machine can do. The browser actions only where a browser is
|
|
20
|
+
* installed (manual 10.16); the service offers them only when switched on. */
|
|
21
|
+
readonly capabilities: string[];
|
|
22
|
+
/** The job's browser, started on first use (10.16). */
|
|
23
|
+
private browser?;
|
|
24
|
+
/** Close what this job opened on the machine: its browser. */
|
|
25
|
+
close(): void;
|
|
26
|
+
readonly root: string;
|
|
27
|
+
private readonly onOutput?;
|
|
28
|
+
/** The test command, once it has been worked out or supplied. Remembered so a
|
|
29
|
+
* job that had to be told does not have to be told again. */
|
|
30
|
+
private testCommand?;
|
|
31
|
+
/** Whether the last test run passed. The grading signal the whole product
|
|
32
|
+
* rests on, kept so a session can report it when the job ends. */
|
|
33
|
+
lastTestsPassed?: boolean;
|
|
34
|
+
/** The operating system's sandbox, set when the service turns it on for a
|
|
35
|
+
* job (manual 4.12). Absent, commands run with the person's own access. */
|
|
36
|
+
sandbox?: import("./sandbox").Sandbox;
|
|
37
|
+
constructor(opts: ExecutorOptions);
|
|
38
|
+
/** One executor per helper copy, rooted there and nowhere else. */
|
|
39
|
+
private readonly inCopies;
|
|
40
|
+
/** Tool servers this job started (manual 9.10), stopped when it ends. */
|
|
41
|
+
readonly toolServers: ToolServers;
|
|
42
|
+
execute(name: string, a: Record<string, unknown>, plan?: hooks.HookPlan): Promise<RunResult>;
|
|
43
|
+
private browse;
|
|
44
|
+
private perform;
|
|
45
|
+
}
|