@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
package/out/executor/hooks.d.ts
CHANGED
|
@@ -1,67 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
* Anything else is treated as a regular expression anchored at both ends, so
|
|
9
|
-
* `"git_.*"` covers the git actions without naming all five. A pattern that
|
|
10
|
-
* will not compile matches nothing and says so once, rather than matching
|
|
11
|
-
* everything: a broken pattern that ran a hook on every action would be the
|
|
12
|
-
* dangerous way to be wrong. */
|
|
13
|
-
on: string;
|
|
14
|
-
/** "before" or "after". */
|
|
15
|
-
when: "before" | "after";
|
|
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;
|
|
16
7
|
command: string;
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
what?: string | null;
|
|
9
|
+
timeout_s?: number;
|
|
10
|
+
source?: string;
|
|
19
11
|
}
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
export declare function
|
|
28
|
-
/**
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
36
|
/** Set when a `before` hook refused the action. */
|
|
37
37
|
refusedBy?: string;
|
|
38
38
|
detail?: string;
|
|
39
|
+
/** `after`, `job_start`, `job_end` and `waiting` hooks that failed. */
|
|
40
|
+
failed: string[];
|
|
39
41
|
}
|
|
40
42
|
/**
|
|
41
|
-
* Run the hooks
|
|
42
|
-
*
|
|
43
|
-
* **A non-zero exit cancels the action.** This is the one place a hook changes
|
|
44
|
-
* what happens, and it is deliberate: "do not let the agent touch anything under
|
|
45
|
-
* generated/" is a real thing to want, and refusing is the only way for a
|
|
46
|
-
* project to say it.
|
|
47
|
-
*
|
|
48
|
-
* It can only ever REFUSE. There is no exit code that approves something the
|
|
49
|
-
* agent was not already allowed to do, because a permission system inside the
|
|
50
|
-
* repository would live exactly where an attacker who got that far already is.
|
|
51
|
-
*/
|
|
52
|
-
export declare function before(root: string, action: string, args: Record<string, unknown>, hooks?: Hook[]): Promise<HookOutcome>;
|
|
53
|
-
/**
|
|
54
|
-
* Run the hooks that come after one action.
|
|
43
|
+
* Run the hooks the service named, one after another, in its order.
|
|
55
44
|
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* worth losing the work over.
|
|
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.
|
|
60
48
|
*/
|
|
61
|
-
export declare function
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}>;
|
|
65
|
-
/** The example a person copies. Kept in code so the readme and the behavior
|
|
66
|
-
* cannot drift: this is what the reader actually gets. */
|
|
67
|
-
export declare const EXAMPLE: string;
|
|
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[];
|
package/out/executor/hooks.js
CHANGED
|
@@ -33,215 +33,122 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.
|
|
37
|
-
exports.
|
|
38
|
-
exports.
|
|
39
|
-
exports.
|
|
40
|
-
exports.
|
|
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
41
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* So the configuration is read from the project itself rather than from our
|
|
55
|
-
* database. A hook that lives in the repository is reviewed like any other
|
|
56
|
-
* change, travels with a branch, and is the same for everybody who works there.
|
|
57
|
-
* A hook stored in our settings would be invisible in the repository and
|
|
58
|
-
* different for whoever configured it.
|
|
59
|
-
*
|
|
60
|
-
* ## What they are for, in practice
|
|
61
|
-
*
|
|
62
|
-
* The overwhelming case is "run the formatter after the agent edits a file", and
|
|
63
|
-
* the reason it earns a feature is that the alternative is telling the model to
|
|
64
|
-
* remember to do it, which it does four times out of five.
|
|
65
|
-
*
|
|
66
|
-
* ## What a hook may not do
|
|
67
|
-
*
|
|
68
|
-
* **It cannot approve anything and it cannot change the decision.** A hook that
|
|
69
|
-
* could turn a refusal into an approval would be a permission system in a file
|
|
70
|
-
* inside the repository, which is the wrong place for one: the repository is
|
|
71
|
-
* exactly what an attacker who has got that far already controls.
|
|
72
|
-
*
|
|
73
|
-
* A hook that fails is reported and does not stop the job, with one exception
|
|
74
|
-
* stated in `before`: a `before` hook exiting non-zero cancels that one action,
|
|
75
|
-
* because "do not let the agent touch generated files" is a real thing to want
|
|
76
|
-
* and refusing is the only way to say it.
|
|
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.
|
|
77
54
|
*/
|
|
78
55
|
const fs = __importStar(require("fs"));
|
|
79
56
|
const path = __importStar(require("path"));
|
|
80
57
|
const shell_1 = require("./shell");
|
|
81
|
-
/**
|
|
82
|
-
|
|
83
|
-
* The settings file comes first, because that is where every other thing a
|
|
84
|
-
* project says about its agent now lives, and keeping hooks somewhere else was
|
|
85
|
-
* one more folder for a newcomer to know about.
|
|
86
|
-
*
|
|
87
|
-
* `.illuminis/hooks.json` is still read, and last. It is what projects were
|
|
88
|
-
* told to write, and silently ignoring a file somebody wrote on our
|
|
89
|
-
* instructions would mean their formatter stops running with no message
|
|
90
|
-
* anywhere. Only one file is used: the first that has hooks in it wins, so a
|
|
91
|
-
* project that has moved does not get both. */
|
|
92
|
-
const CONFIGS = [
|
|
58
|
+
/** The settings files that can hold hooks, sent as read for `comprism hooks`. */
|
|
59
|
+
exports.FILES = [
|
|
93
60
|
".completionprism/settings.json",
|
|
94
61
|
".completionprism/settings.local.json",
|
|
95
62
|
".comprism/settings.json",
|
|
96
63
|
".claude/settings.json",
|
|
97
64
|
".illuminis/hooks.json",
|
|
98
65
|
];
|
|
99
|
-
/**
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
for (const name of
|
|
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) {
|
|
108
75
|
const file = path.join(root, name);
|
|
109
|
-
if (!fs.existsSync(file))
|
|
110
|
-
continue;
|
|
111
76
|
try {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const usable = hooks.filter((h) => h && typeof h.command === "string" && h.command.trim()
|
|
115
|
-
&& (h.when === "before" || h.when === "after")
|
|
116
|
-
&& typeof h.on === "string" && h.on.trim());
|
|
117
|
-
// A settings file with no hooks section is the ordinary case, and it must
|
|
118
|
-
// not stop the older file being read. Only a file that actually declares
|
|
119
|
-
// hooks ends the search.
|
|
120
|
-
if (usable.length)
|
|
121
|
-
return usable;
|
|
77
|
+
if (fs.existsSync(file))
|
|
78
|
+
out[name] = fs.readFileSync(file, "utf8").slice(0, 200_000);
|
|
122
79
|
}
|
|
123
|
-
catch
|
|
124
|
-
|
|
125
|
-
return [];
|
|
80
|
+
catch {
|
|
81
|
+
/* unreadable is the same as absent to the service */
|
|
126
82
|
}
|
|
127
83
|
}
|
|
128
|
-
return
|
|
84
|
+
return out;
|
|
129
85
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
* Exported because it is the part with the rules in it, and a rule with no
|
|
133
|
-
* test is a rule that drifts.
|
|
134
|
-
*/
|
|
135
|
-
function covers(pattern, action) {
|
|
136
|
-
const p = String(pattern ?? "").trim();
|
|
137
|
-
if (!p || !action)
|
|
138
|
-
return false;
|
|
139
|
-
if (p === "*")
|
|
140
|
-
return true;
|
|
141
|
-
if (p === action)
|
|
142
|
-
return true;
|
|
143
|
-
if (p.includes("|") && !/[\\^$.?*+()[\]{}]/.test(p)) {
|
|
144
|
-
return p.split("|").some((one) => one.trim() === action);
|
|
145
|
-
}
|
|
146
|
-
if (!/[\\^$.?*+()[\]{}|]/.test(p))
|
|
147
|
-
return false;
|
|
148
|
-
try {
|
|
149
|
-
return new RegExp(`^(?:${p})$`).test(action);
|
|
150
|
-
}
|
|
151
|
-
catch {
|
|
152
|
-
// A pattern that will not compile matches NOTHING. The other direction,
|
|
153
|
-
// matching everything, would run somebody's script on every action because
|
|
154
|
-
// of a typo, which is the expensive way to be wrong.
|
|
155
|
-
process.stderr.write(` A hook pattern is not valid and was skipped: ${p}\n`);
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
function matching(hooks, action, when) {
|
|
160
|
-
return hooks.filter((h) => h.when === when && covers(h.on, action));
|
|
86
|
+
function fileOf(args) {
|
|
87
|
+
return String(args.path ?? args.file_path ?? args.to ?? "");
|
|
161
88
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
return String(args.path ?? args.to ?? "");
|
|
89
|
+
function said(h) {
|
|
90
|
+
return h.what || h.command;
|
|
165
91
|
}
|
|
166
92
|
/**
|
|
167
|
-
* Run the hooks
|
|
168
|
-
*
|
|
169
|
-
* **A non-zero exit cancels the action.** This is the one place a hook changes
|
|
170
|
-
* what happens, and it is deliberate: "do not let the agent touch anything under
|
|
171
|
-
* generated/" is a real thing to want, and refusing is the only way for a
|
|
172
|
-
* project to say it.
|
|
93
|
+
* Run the hooks the service named, one after another, in its order.
|
|
173
94
|
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
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.
|
|
177
98
|
*/
|
|
178
|
-
async function
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
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));
|
|
182
108
|
const result = await (0, shell_1.runCommand)(hook.command, {
|
|
183
109
|
root,
|
|
184
|
-
timeoutMs:
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
extraEnv: {
|
|
110
|
+
timeoutMs: secs * 1000,
|
|
111
|
+
input,
|
|
112
|
+
label: `hook: ${hook.command}`,
|
|
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
|
+
},
|
|
188
124
|
});
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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;
|
|
196
139
|
}
|
|
140
|
+
outcome.failed.push(`${said(hook)}: ${timedOut ? `stopped after ${secs}s, its time limit` : output.slice(0, 300) || "failed"}`);
|
|
197
141
|
}
|
|
198
|
-
return
|
|
142
|
+
return outcome;
|
|
199
143
|
}
|
|
200
|
-
/**
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
async function after(root, action, args, hooks = hooksFor(root)) {
|
|
209
|
-
const applicable = matching(hooks, action, "after");
|
|
210
|
-
const failed = [];
|
|
211
|
-
let ran = 0;
|
|
212
|
-
for (const hook of applicable) {
|
|
213
|
-
const result = await (0, shell_1.runCommand)(hook.command, {
|
|
214
|
-
root, timeoutMs: 120_000,
|
|
215
|
-
extraEnv: { ILLUMINIS_ACTION: action, ILLUMINIS_PATH: targetOf(args) },
|
|
216
|
-
});
|
|
217
|
-
ran += 1;
|
|
218
|
-
if (result.isError || !/^exit 0/.test(result.content)) {
|
|
219
|
-
failed.push(`${hook.what ?? hook.command}: ${result.content.slice(0, 300)}`);
|
|
220
|
-
}
|
|
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}`);
|
|
221
152
|
}
|
|
222
|
-
return
|
|
153
|
+
return lines;
|
|
223
154
|
}
|
|
224
|
-
/** The example a person copies. Kept in code so the readme and the behavior
|
|
225
|
-
* cannot drift: this is what the reader actually gets. */
|
|
226
|
-
exports.EXAMPLE = JSON.stringify({
|
|
227
|
-
hooks: [
|
|
228
|
-
{
|
|
229
|
-
on: "write_file|edit_file|multi_edit",
|
|
230
|
-
when: "after",
|
|
231
|
-
command: "npm run lint --silent",
|
|
232
|
-
what: "Lint after anything is written",
|
|
233
|
-
},
|
|
234
|
-
{
|
|
235
|
-
on: "edit_file",
|
|
236
|
-
when: "after",
|
|
237
|
-
command: "npx prettier --write $ILLUMINIS_PATH",
|
|
238
|
-
what: "Format the file that was just changed",
|
|
239
|
-
},
|
|
240
|
-
{
|
|
241
|
-
on: "write_file",
|
|
242
|
-
when: "before",
|
|
243
|
-
command: "test \"${ILLUMINIS_PATH#generated/}\" = \"$ILLUMINIS_PATH\"",
|
|
244
|
-
what: "Nothing under generated/ is edited by hand",
|
|
245
|
-
},
|
|
246
|
-
],
|
|
247
|
-
}, null, 2);
|
package/out/executor/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import * as hooks from "./hooks";
|
|
2
|
+
import { ToolServers } from "./toolservers";
|
|
3
|
+
import { RunResult, guessTestCommand, stopEverything, stopForeground } from "./shell";
|
|
4
|
+
export { stopEverything, stopForeground, guessTestCommand };
|
|
3
5
|
export type { RunResult };
|
|
4
6
|
/** Everything a machine with a shell can do. Sent to the server on hello, and
|
|
5
7
|
* the catalog offered to the model is narrowed to it, so a client is never
|
|
@@ -7,23 +9,37 @@ export type { RunResult };
|
|
|
7
9
|
export declare const NATIVE_CAPABILITIES: string[];
|
|
8
10
|
export interface ExecutorOptions {
|
|
9
11
|
root: string;
|
|
12
|
+
/** Folders the person added for this job (manual 2.3). */
|
|
13
|
+
added?: string[];
|
|
10
14
|
/** Called with each chunk of a running command's output, so a terminal can
|
|
11
15
|
* show it as it happens rather than in one block at the end. */
|
|
12
16
|
onOutput?: (chunk: string) => void;
|
|
13
17
|
}
|
|
14
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. */
|
|
15
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;
|
|
16
26
|
readonly root: string;
|
|
17
27
|
private readonly onOutput?;
|
|
18
28
|
/** The test command, once it has been worked out or supplied. Remembered so a
|
|
19
29
|
* job that had to be told does not have to be told again. */
|
|
20
30
|
private testCommand?;
|
|
21
|
-
/** What this project asks to happen around the agent's actions, read once. */
|
|
22
|
-
private hooks?;
|
|
23
31
|
/** Whether the last test run passed. The grading signal the whole product
|
|
24
32
|
* rests on, kept so a session can report it when the job ends. */
|
|
25
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;
|
|
26
37
|
constructor(opts: ExecutorOptions);
|
|
27
|
-
|
|
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;
|
|
28
44
|
private perform;
|
|
29
45
|
}
|