carrick 0.3.81 → 0.3.83
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 +46 -19
- package/bin/carrick.mjs +45 -2
- package/dist/contract.d.ts +17 -0
- package/dist/contract.js.map +1 -1
- package/dist/hook/apply-patch.d.ts +13 -0
- package/dist/hook/apply-patch.js +100 -0
- package/dist/hook/apply-patch.js.map +1 -0
- package/dist/hook/post-edit.d.ts +30 -1
- package/dist/hook/post-edit.js +95 -24
- package/dist/hook/post-edit.js.map +1 -1
- package/dist/hook/reuse.d.ts +97 -0
- package/dist/hook/reuse.js +245 -0
- package/dist/hook/reuse.js.map +1 -0
- package/dist/hook/stop.d.ts +3 -0
- package/dist/hook/stop.js +76 -0
- package/dist/hook/stop.js.map +1 -0
- package/dist/hook/user-prompt.d.ts +9 -0
- package/dist/hook/user-prompt.js +79 -0
- package/dist/hook/user-prompt.js.map +1 -0
- package/dist/init/codex.d.ts +51 -0
- package/dist/init/codex.js +167 -0
- package/dist/init/codex.js.map +1 -0
- package/dist/init/connect.d.ts +13 -0
- package/dist/init/connect.js +21 -15
- package/dist/init/connect.js.map +1 -1
- package/dist/init/doctor.d.ts +36 -0
- package/dist/init/doctor.js +97 -2
- package/dist/init/doctor.js.map +1 -1
- package/dist/init/files.d.ts +16 -0
- package/dist/init/files.js +35 -0
- package/dist/init/files.js.map +1 -0
- package/dist/init/outdated.d.ts +54 -0
- package/dist/init/outdated.js +175 -0
- package/dist/init/outdated.js.map +1 -0
- package/dist/init/output.d.ts +35 -3
- package/dist/init/output.js +115 -23
- package/dist/init/output.js.map +1 -1
- package/dist/init/projects.d.ts +27 -13
- package/dist/init/projects.js +48 -50
- package/dist/init/projects.js.map +1 -1
- package/dist/init/remove.d.ts +0 -2
- package/dist/init/remove.js +91 -23
- package/dist/init/remove.js.map +1 -1
- package/dist/init/repos.d.ts +34 -0
- package/dist/init/repos.js +77 -0
- package/dist/init/repos.js.map +1 -1
- package/dist/init/run.d.ts +73 -6
- package/dist/init/run.js +382 -101
- package/dist/init/run.js.map +1 -1
- package/dist/init/settings.d.ts +20 -0
- package/dist/init/settings.js +42 -4
- package/dist/init/settings.js.map +1 -1
- package/dist/init/task-skills.d.ts +97 -0
- package/dist/init/task-skills.js +267 -0
- package/dist/init/task-skills.js.map +1 -0
- package/dist/init/workspace-file.d.ts +73 -0
- package/dist/init/workspace-file.js +173 -0
- package/dist/init/workspace-file.js.map +1 -0
- package/dist/scan.d.ts +13 -5
- package/dist/scan.js +21 -10
- package/dist/scan.js.map +1 -1
- package/dist/templates.d.ts +9 -0
- package/dist/templates.js +9 -1
- package/dist/templates.js.map +1 -1
- package/package.json +6 -6
- package/plugin/hooks/hooks.json +11 -0
- package/sidecar/dist/src/capture/check-classify.d.ts +10 -1
- package/sidecar/dist/src/capture/check-classify.js +66 -8
- package/sidecar/dist/src/capture/check-deep.d.ts +16 -4
- package/sidecar/dist/src/capture/check-deep.js +21 -17
- package/sidecar/dist/src/capture/check-fields.d.ts +83 -0
- package/sidecar/dist/src/capture/check-fields.js +259 -0
- package/sidecar/dist/src/capture/check-probe.d.ts +21 -1
- package/sidecar/dist/src/capture/check-probe.js +39 -0
- package/sidecar/dist/src/capture/check.js +9 -2
- package/templates/skills/carrick-census.md +89 -0
- package/templates/skills/carrick-drift.md +107 -0
- package/templates/skills/carrick-impact.md +108 -0
- package/templates/skills/carrick-reuse.md +106 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// The hook entries `carrick init` writes into a project's `.codex/hooks.json`
|
|
2
|
+
// (carrick#1335).
|
|
3
|
+
//
|
|
4
|
+
// Codex reads hooks from `$CODEX_HOME/hooks.json` and from a project's
|
|
5
|
+
// `.codex/hooks.json` (`codex-rs/hooks/src/engine/discovery.rs`,
|
|
6
|
+
// `ConfigLayerSource::Project`). The project file is the one init writes: what
|
|
7
|
+
// it configures is this workspace, and a machine-wide file would follow the
|
|
8
|
+
// user to every repository they open.
|
|
9
|
+
//
|
|
10
|
+
// The document is the same shape as a `.claude` settings file — groups nested
|
|
11
|
+
// under a `hooks` key, `{ "type": "command", "command": ..., "timeout": ... }`
|
|
12
|
+
// entries, a `matcher` per group (`codex-rs/config/src/hook_config.rs`,
|
|
13
|
+
// `HooksFile`) — so the merge, the reader and the remover are the ones in
|
|
14
|
+
// `settings.ts` and only the entries differ. Same rule as the other file, for
|
|
15
|
+
// the same reason: entries whose command is this CLI are the only ones touched,
|
|
16
|
+
// and a hooks file a user already has keeps everything else in it.
|
|
17
|
+
//
|
|
18
|
+
// Two entries, which is the whole nudge on this host:
|
|
19
|
+
//
|
|
20
|
+
// * `PostToolUse` on `apply_patch`, which records what an edit added. The
|
|
21
|
+
// matcher is a regex (`codex-rs/hooks/src/engine/dispatcher.rs`) and
|
|
22
|
+
// `apply_patch` is the canonical tool name Codex puts on the payload.
|
|
23
|
+
// * `UserPromptSubmit`, which speaks the accumulated set once. Codex's `Stop`
|
|
24
|
+
// event cannot emit `additionalContext` at all, so this is the only
|
|
25
|
+
// non-blocking way to reach the model there — and the cost is that the line
|
|
26
|
+
// arrives with the next prompt.
|
|
27
|
+
//
|
|
28
|
+
// One thing this file cannot do for the user: a project hook is untrusted until
|
|
29
|
+
// Codex records its hash, and an untrusted hook is discovered and not run
|
|
30
|
+
// (`hook_trust_status` in `discovery.rs`). Codex asks about it at its next
|
|
31
|
+
// start. `carrick init` says so; nothing here can answer it.
|
|
32
|
+
//
|
|
33
|
+
// Reference: `docs/reference/task-skills.md`, "The reuse nudge".
|
|
34
|
+
import fs from "node:fs";
|
|
35
|
+
import path from "node:path";
|
|
36
|
+
import { writeIfChanged } from "./files.js";
|
|
37
|
+
import { flattenHooks, installedCarrickHooks, mergeHookSet, removeCarrickHooks, } from "./settings.js";
|
|
38
|
+
/** Codex's project config folder, relative to the workspace. */
|
|
39
|
+
export const CODEX_DIR = ".codex";
|
|
40
|
+
/** The file init writes, relative to the workspace. */
|
|
41
|
+
export const CODEX_HOOKS_FILE = path.join(CODEX_DIR, "hooks.json");
|
|
42
|
+
/** What this package registers with Codex, and the only entries it removes. */
|
|
43
|
+
export function codexHooks(command = "carrick") {
|
|
44
|
+
return {
|
|
45
|
+
// One call can carry a patch touching several files, and each one is a
|
|
46
|
+
// separate `carrick check`, so this timeout is not the single-file 15 the
|
|
47
|
+
// Claude entry uses. Codex applies the value as written for this event
|
|
48
|
+
// (`normalize_command_hook` clamps only SessionEnd and Interrupt).
|
|
49
|
+
PostToolUse: [
|
|
50
|
+
{
|
|
51
|
+
matcher: "apply_patch",
|
|
52
|
+
hooks: [{ type: "command", command: `${command} hook post-edit`, timeout: 60 }],
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
// The next prompt after the task that added the functions. It reads one
|
|
56
|
+
// small file and prints nothing when there is nothing new, so the timeout
|
|
57
|
+
// is the short one.
|
|
58
|
+
UserPromptSubmit: [
|
|
59
|
+
{
|
|
60
|
+
hooks: [{ type: "command", command: `${command} hook user-prompt`, timeout: 5 }],
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/** What `codexHooks` writes, flattened the way `installedCarrickHooks` reads. */
|
|
66
|
+
export function expectedCodexHooks(command = "carrick") {
|
|
67
|
+
return flattenHooks(codexHooks(command));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Whether Codex is set up for this workspace.
|
|
71
|
+
*
|
|
72
|
+
* The test is its project config folder, which is the layer Codex reads project
|
|
73
|
+
* hooks and project config from and the folder this file lives in. A workspace
|
|
74
|
+
* with no `.codex/` has nothing of Codex's in it, and `carrick doctor` says
|
|
75
|
+
* nothing about Codex there rather than warning every Claude Code user about a
|
|
76
|
+
* host they do not run.
|
|
77
|
+
*/
|
|
78
|
+
export function codexInUse(workspace) {
|
|
79
|
+
try {
|
|
80
|
+
return fs.statSync(path.join(workspace, CODEX_DIR)).isDirectory();
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** Our entries in a `.codex/hooks.json`, or an empty list where there is none. */
|
|
87
|
+
export function installedCodexHooks(workspace) {
|
|
88
|
+
const body = readHooksFile(workspace);
|
|
89
|
+
return body === null ? [] : installedCarrickHooks(body);
|
|
90
|
+
}
|
|
91
|
+
/** The file as it is, or null when it is not there. Throws nothing but I/O. */
|
|
92
|
+
export function readHooksFile(workspace) {
|
|
93
|
+
try {
|
|
94
|
+
return fs.readFileSync(path.join(workspace, CODEX_HOOKS_FILE), "utf8");
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Write our entries into the project's Codex hooks file, merging.
|
|
102
|
+
*
|
|
103
|
+
* Throws on a file that is not JSON, exactly as the `.claude` writer does: a
|
|
104
|
+
* file somebody hand-edited into something unparseable is reported, never
|
|
105
|
+
* overwritten.
|
|
106
|
+
*/
|
|
107
|
+
export function writeCodexHooks(workspace, command) {
|
|
108
|
+
const existing = readHooksFile(workspace);
|
|
109
|
+
const merged = mergeHookSet(existing, codexHooks(command));
|
|
110
|
+
return writeIfChanged(path.join(workspace, CODEX_HOOKS_FILE), merged.body);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Whether what is left of a hooks file is nothing but the shape of one.
|
|
114
|
+
*
|
|
115
|
+
* `.codex/hooks.json` differs from a settings file in who it belongs to: init
|
|
116
|
+
* is the reason it exists, so a file holding no hooks and nothing else after
|
|
117
|
+
* our entries come out is ours to delete rather than an empty husk to leave in
|
|
118
|
+
* somebody's repository. A `description`, a key we never write, or anyone
|
|
119
|
+
* else's entry all make it theirs.
|
|
120
|
+
*/
|
|
121
|
+
export function isEmptyHooksDocument(body) {
|
|
122
|
+
let parsed;
|
|
123
|
+
try {
|
|
124
|
+
parsed = body.trim() === "" ? {} : JSON.parse(body);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
130
|
+
return false;
|
|
131
|
+
const keys = Object.keys(parsed);
|
|
132
|
+
if (keys.length > 1 || (keys.length === 1 && keys[0] !== "hooks"))
|
|
133
|
+
return false;
|
|
134
|
+
const hooks = parsed["hooks"];
|
|
135
|
+
if (hooks === undefined)
|
|
136
|
+
return true;
|
|
137
|
+
return typeof hooks === "object" && hooks !== null && Object.keys(hooks).length === 0;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Take our entries out again, and the file with them where it held only ours.
|
|
141
|
+
*
|
|
142
|
+
* Null when there was nothing of ours there, so `carrick remove` stays silent
|
|
143
|
+
* about a machine that never installed it. A `.codex` directory emptied by the
|
|
144
|
+
* deletion goes too; one holding anything else of Codex's stays.
|
|
145
|
+
*/
|
|
146
|
+
export function uninstallCodexHooks(workspace) {
|
|
147
|
+
const existing = readHooksFile(workspace);
|
|
148
|
+
if (existing === null)
|
|
149
|
+
return null;
|
|
150
|
+
const cleaned = removeCarrickHooks(existing);
|
|
151
|
+
if (!cleaned.changed)
|
|
152
|
+
return null;
|
|
153
|
+
const target = path.join(workspace, CODEX_HOOKS_FILE);
|
|
154
|
+
if (!isEmptyHooksDocument(cleaned.body)) {
|
|
155
|
+
fs.writeFileSync(target, cleaned.body);
|
|
156
|
+
return "removed";
|
|
157
|
+
}
|
|
158
|
+
fs.rmSync(target);
|
|
159
|
+
try {
|
|
160
|
+
fs.rmdirSync(path.join(workspace, CODEX_DIR));
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
// Holds something else of Codex's. That is the answer, not a failure.
|
|
164
|
+
}
|
|
165
|
+
return "file removed";
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=codex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/init/codex.ts"],"names":[],"mappings":"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"}
|
package/dist/init/connect.d.ts
CHANGED
|
@@ -6,6 +6,19 @@ type ConnectOptions = {
|
|
|
6
6
|
project?: string;
|
|
7
7
|
/** True when this run has already seen or created the project (carrick#955). */
|
|
8
8
|
projectExists?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* The repos this run may take OUT of another project, lowercased.
|
|
11
|
+
*
|
|
12
|
+
* A move changes what every agent querying either project can see, so it is
|
|
13
|
+
* named in the proposal and consented to there; this set is that consent
|
|
14
|
+
* arriving (carrick#1338). A repo that was not connected at all when the
|
|
15
|
+
* proposal was read is in it too: the App grant lands it in the workspace's
|
|
16
|
+
* default project seconds later, and placing it where the run asked for is
|
|
17
|
+
* the grant finishing rather than a move out of a project anyone chose.
|
|
18
|
+
*/
|
|
19
|
+
movable?: Set<string>;
|
|
20
|
+
/** How a project is printed: display name beside slug, where one is known. */
|
|
21
|
+
label?: (slug: string) => string;
|
|
9
22
|
open?: (url: string) => Promise<boolean>;
|
|
10
23
|
poll?: (signal?: AbortSignal) => Promise<ResolvedRepos>;
|
|
11
24
|
/** Placing repos in the project, injected so tests state the server (carrick#999). */
|
package/dist/init/connect.js
CHANGED
|
@@ -38,7 +38,7 @@ export function projectAssignments(identity, repos) {
|
|
|
38
38
|
return repo?.connected === true ? repo.project_slug : null;
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
|
-
function reportAssignments(identity, repos, previous, say) {
|
|
41
|
+
function reportAssignments(identity, repos, previous, say, label) {
|
|
42
42
|
for (const name of repos) {
|
|
43
43
|
const current = assignment(identity, name);
|
|
44
44
|
if (previous.get(name.toLowerCase()) === current)
|
|
@@ -47,18 +47,22 @@ function reportAssignments(identity, repos, previous, say) {
|
|
|
47
47
|
const actualName = repo?.full_name ?? name;
|
|
48
48
|
say(current === "not connected"
|
|
49
49
|
? `${actualName} is not connected to this workspace.`
|
|
50
|
-
: `${actualName} is currently in project
|
|
50
|
+
: `${actualName} is currently in project ${label(current)}.`);
|
|
51
51
|
previous.set(name.toLowerCase(), current);
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
/**
|
|
55
|
-
* The repos this run may still place: connected to the workspace,
|
|
56
|
-
* other project than the one asked for.
|
|
55
|
+
* The repos this run may still place: connected to the workspace, in some
|
|
56
|
+
* other project than the one asked for, and consented to in the proposal.
|
|
57
|
+
*
|
|
58
|
+
* A connected repo that was not consented to is left exactly where it is. The
|
|
59
|
+
* caller says so once and prints the browser step, because a project move is
|
|
60
|
+
* not something a `--yes` to a list of packages grants (carrick#1338).
|
|
57
61
|
*/
|
|
58
|
-
function misplaced(identity, repos, project) {
|
|
62
|
+
function misplaced(identity, repos, project, movable) {
|
|
59
63
|
return repos.filter((name) => {
|
|
60
64
|
const repo = identity.repos.find((candidate) => candidate.full_name.toLowerCase() === name.toLowerCase());
|
|
61
|
-
return repo?.connected === true && repo.project_slug !== project;
|
|
65
|
+
return (repo?.connected === true && repo.project_slug !== project && movable.has(name.toLowerCase()));
|
|
62
66
|
});
|
|
63
67
|
}
|
|
64
68
|
/**
|
|
@@ -79,6 +83,8 @@ export async function connectRepos(token, repos, initial, options) {
|
|
|
79
83
|
const assignments = new Map();
|
|
80
84
|
const poll = options.poll ?? ((signal) => resolveRepos(token, repos, fetch, signal));
|
|
81
85
|
const project = options.project;
|
|
86
|
+
const label = options.label ?? ((slug) => slug);
|
|
87
|
+
const movable = options.movable ?? new Set();
|
|
82
88
|
// A repo that is already where it was asked to be is not news: the run states
|
|
83
89
|
// the project once, on the line naming the login (carrick#1026). Seeding the
|
|
84
90
|
// map with those repos leaves this reporting only what CHANGED or what is
|
|
@@ -115,7 +121,7 @@ export async function connectRepos(token, repos, initial, options) {
|
|
|
115
121
|
const place = async (identity, signal) => {
|
|
116
122
|
if (!placeable || project === undefined)
|
|
117
123
|
return false;
|
|
118
|
-
const pending = misplaced(identity, repos, project);
|
|
124
|
+
const pending = misplaced(identity, repos, project, movable);
|
|
119
125
|
if (pending.length === 0)
|
|
120
126
|
return false;
|
|
121
127
|
const outcome = await assign(pending, signal);
|
|
@@ -125,7 +131,7 @@ export async function connectRepos(token, repos, initial, options) {
|
|
|
125
131
|
// is printed by the caller, after the steps that come before it.
|
|
126
132
|
placeable = false;
|
|
127
133
|
if (outcome.kind === "refused") {
|
|
128
|
-
options.say(`Carrick did not assign the requested repos to
|
|
134
|
+
options.say(`Carrick did not assign the requested repos to ${label(project)}: ${outcome.message}`);
|
|
129
135
|
}
|
|
130
136
|
return false;
|
|
131
137
|
}
|
|
@@ -134,7 +140,7 @@ export async function connectRepos(token, repos, initial, options) {
|
|
|
134
140
|
if (repo.assigned) {
|
|
135
141
|
moved = moved || repo.moved;
|
|
136
142
|
if (repo.moved)
|
|
137
|
-
sayOnce(`Moved ${repo.full_name} into project
|
|
143
|
+
sayOnce(`Moved ${repo.full_name} into project ${label(project)}.`);
|
|
138
144
|
}
|
|
139
145
|
else {
|
|
140
146
|
sayOnce(`${repo.full_name} was not moved: ${repo.reason ?? "Carrick gave no reason."}`);
|
|
@@ -147,12 +153,12 @@ export async function connectRepos(token, repos, initial, options) {
|
|
|
147
153
|
if (!(await place(identity, signal)))
|
|
148
154
|
return identity;
|
|
149
155
|
const latest = await poll(signal);
|
|
150
|
-
reportAssignments(latest, repos, assignments, options.say);
|
|
156
|
+
reportAssignments(latest, repos, assignments, options.say, label);
|
|
151
157
|
return latest;
|
|
152
158
|
};
|
|
153
159
|
let latest = initial;
|
|
154
160
|
if (project !== undefined) {
|
|
155
|
-
reportAssignments(latest, repos, assignments, options.say);
|
|
161
|
+
reportAssignments(latest, repos, assignments, options.say, label);
|
|
156
162
|
if (reposAreInProject(latest, repos, project)) {
|
|
157
163
|
return latest;
|
|
158
164
|
}
|
|
@@ -181,13 +187,13 @@ export async function connectRepos(token, repos, initial, options) {
|
|
|
181
187
|
}
|
|
182
188
|
if (!options.interactive) {
|
|
183
189
|
if (project !== undefined) {
|
|
184
|
-
options.say(`Project
|
|
190
|
+
options.say(`Project ${label(project)} is not verified for every requested repo.`);
|
|
185
191
|
}
|
|
186
192
|
return latest;
|
|
187
193
|
}
|
|
188
194
|
options.say(ADMIN_WAIT);
|
|
189
195
|
options.say(project !== undefined
|
|
190
|
-
? `Waiting for every requested repo to reach project
|
|
196
|
+
? `Waiting for every requested repo to reach project ${label(project)}. Press Ctrl-C to stop.`
|
|
191
197
|
: "Waiting for repository connections. Press Ctrl-C to continue setup without waiting.");
|
|
192
198
|
const controller = new AbortController();
|
|
193
199
|
const cancel = () => controller.abort();
|
|
@@ -211,7 +217,7 @@ export async function connectRepos(token, repos, initial, options) {
|
|
|
211
217
|
signal.throwIfAborted();
|
|
212
218
|
latest = await poll(signal);
|
|
213
219
|
if (project !== undefined) {
|
|
214
|
-
reportAssignments(latest, repos, assignments, options.say);
|
|
220
|
+
reportAssignments(latest, repos, assignments, options.say, label);
|
|
215
221
|
latest = await settle(latest, signal);
|
|
216
222
|
if (reposAreInProject(latest, repos, project)) {
|
|
217
223
|
return latest;
|
|
@@ -239,7 +245,7 @@ export async function connectRepos(token, repos, initial, options) {
|
|
|
239
245
|
process.removeListener("SIGINT", cancel);
|
|
240
246
|
}
|
|
241
247
|
options.say(project !== undefined
|
|
242
|
-
? `Stopped waiting; project
|
|
248
|
+
? `Stopped waiting; project ${label(project)} is not verified for every requested repo.`
|
|
243
249
|
: "Stopped waiting for repository connections; continuing local setup.");
|
|
244
250
|
return latest;
|
|
245
251
|
}
|
package/dist/init/connect.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/init/connect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAsB,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAsB,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/init/connect.ts"],"names":[],"mappings":"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"}
|
package/dist/init/doctor.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type McpInspection } from "./mcp.ts";
|
|
2
2
|
import { type InitOutput } from "./output.ts";
|
|
3
|
+
import { type InstalledSkill } from "./task-skills.ts";
|
|
3
4
|
import type { StatusResult } from "../contract.ts";
|
|
4
5
|
export type DoctorOptions = {
|
|
5
6
|
workspace: string;
|
|
@@ -120,6 +121,41 @@ export declare function realMachine(): HookMachine;
|
|
|
120
121
|
* absolute path is stale the moment that install is replaced.
|
|
121
122
|
*/
|
|
122
123
|
export declare function checkHooks(workspace: string, machine: HookMachine): Line[];
|
|
124
|
+
/**
|
|
125
|
+
* The hook entries in this workspace's Codex config (carrick#1335).
|
|
126
|
+
*
|
|
127
|
+
* Asked only where Codex is set up for this workspace, and the test for that is
|
|
128
|
+
* its project config folder: `.codex/` is the layer Codex reads project hooks
|
|
129
|
+
* from, and it is the folder `carrick init` writes the entries into. A
|
|
130
|
+
* workspace without one runs Codex nowhere near this repository, and a warning
|
|
131
|
+
* there would fire on every Claude Code user for a host they do not have.
|
|
132
|
+
*
|
|
133
|
+
* What it does NOT re-ask is whether the command still resolves. That is one
|
|
134
|
+
* machine-wide question about one install, `checkHooks` above asks it of the
|
|
135
|
+
* same command string, and asking twice would print the same finding twice.
|
|
136
|
+
*/
|
|
137
|
+
export declare function checkCodexHooks(workspace: string): Line[];
|
|
138
|
+
/**
|
|
139
|
+
* The task skills, which no check could see until now (carrick#1331).
|
|
140
|
+
*
|
|
141
|
+
* Three different things, and they are not the same finding:
|
|
142
|
+
*
|
|
143
|
+
* * **Missing** is a workspace where the bodies an agent is meant to read are
|
|
144
|
+
* not there at all — a repo set up before this package shipped them, or one
|
|
145
|
+
* somebody deleted them from. `carrick init` writes them.
|
|
146
|
+
* * **Written by an older version** is the upgrade nobody is told about
|
|
147
|
+
* (carrick#1333): the file is still ours, byte for byte as it was written,
|
|
148
|
+
* and the body this version renders has moved on. `carrick init` refreshes
|
|
149
|
+
* exactly these.
|
|
150
|
+
* * **Edited here** is somebody's own work, and it is reported as a note
|
|
151
|
+
* rather than a fault: a skill a team has changed is a skill they meant to
|
|
152
|
+
* change, and `carrick init` leaves it alone. Saying it matters because it
|
|
153
|
+
* is also the file that stops receiving what later versions ship.
|
|
154
|
+
*
|
|
155
|
+
* A file nobody here wrote — a skill of the same name from somewhere else — is
|
|
156
|
+
* not reported at all. It is not ours, and doctor has nothing to say about it.
|
|
157
|
+
*/
|
|
158
|
+
export declare function checkTaskSkills(installed: InstalledSkill[]): Line[];
|
|
123
159
|
/** The MCP server entry in each agent client this machine has. */
|
|
124
160
|
export declare function checkMcp(inspections: McpInspection[]): Line[];
|
|
125
161
|
/** Read-only git, for how far a commit is behind the branch CI indexes. */
|
package/dist/init/doctor.js
CHANGED
|
@@ -37,8 +37,9 @@ import { inspectMcpClients, mcpLine } from "./mcp.js";
|
|
|
37
37
|
import { readInstallId } from "./install-id.js";
|
|
38
38
|
import { createOutput, DOCS } from "./output.js";
|
|
39
39
|
import { repoRoots } from "./repos.js";
|
|
40
|
-
import { expectedCarrickHooks, hookTarget, installedCarrickHooks, ownEntryPoint, } from "./settings.js";
|
|
41
|
-
import {
|
|
40
|
+
import { expectedCarrickHooks, hookTarget, installedCarrickHooks, ownEntryPoint, SETTINGS_FILES, } from "./settings.js";
|
|
41
|
+
import { CODEX_HOOKS_FILE, codexInUse, expectedCodexHooks, readHooksFile } from "./codex.js";
|
|
42
|
+
import { inspectTaskSkills, TASK_SKILLS } from "./task-skills.js";
|
|
42
43
|
export function parseArgs(argv, cwd = process.cwd()) {
|
|
43
44
|
const options = { workspace: cwd };
|
|
44
45
|
for (let index = 0; index < argv.length; index += 1) {
|
|
@@ -518,6 +519,98 @@ export function checkHooks(workspace, machine) {
|
|
|
518
519
|
function isTransient(target) {
|
|
519
520
|
return target.includes(`${path.sep}_npx${path.sep}`);
|
|
520
521
|
}
|
|
522
|
+
/**
|
|
523
|
+
* The hook entries in this workspace's Codex config (carrick#1335).
|
|
524
|
+
*
|
|
525
|
+
* Asked only where Codex is set up for this workspace, and the test for that is
|
|
526
|
+
* its project config folder: `.codex/` is the layer Codex reads project hooks
|
|
527
|
+
* from, and it is the folder `carrick init` writes the entries into. A
|
|
528
|
+
* workspace without one runs Codex nowhere near this repository, and a warning
|
|
529
|
+
* there would fire on every Claude Code user for a host they do not have.
|
|
530
|
+
*
|
|
531
|
+
* What it does NOT re-ask is whether the command still resolves. That is one
|
|
532
|
+
* machine-wide question about one install, `checkHooks` above asks it of the
|
|
533
|
+
* same command string, and asking twice would print the same finding twice.
|
|
534
|
+
*/
|
|
535
|
+
export function checkCodexHooks(workspace) {
|
|
536
|
+
if (!codexInUse(workspace))
|
|
537
|
+
return [];
|
|
538
|
+
const body = readHooksFile(workspace);
|
|
539
|
+
if (body === null) {
|
|
540
|
+
return [
|
|
541
|
+
warn(`Codex is set up in this folder and ${CODEX_HOOKS_FILE} is not there, so nothing records or names what a task adds under Codex. \`carrick init\` writes it.`),
|
|
542
|
+
];
|
|
543
|
+
}
|
|
544
|
+
let installed;
|
|
545
|
+
try {
|
|
546
|
+
installed = installedCarrickHooks(body);
|
|
547
|
+
}
|
|
548
|
+
catch (error) {
|
|
549
|
+
return [
|
|
550
|
+
refuse(`${CODEX_HOOKS_FILE} is not valid JSON (${error.message}), so no hook in it runs.`),
|
|
551
|
+
];
|
|
552
|
+
}
|
|
553
|
+
if (installed.length === 0) {
|
|
554
|
+
return [
|
|
555
|
+
warn(`No Carrick hook entries in ${CODEX_HOOKS_FILE}, so nothing records or names what a task adds under Codex. \`carrick init\` writes them.`),
|
|
556
|
+
];
|
|
557
|
+
}
|
|
558
|
+
// The prefix the file itself names, so an install that had to write an
|
|
559
|
+
// absolute path is compared against its own entries and not against a bare
|
|
560
|
+
// `carrick` it never wrote.
|
|
561
|
+
const prefix = installed[0].command.split(/\s+hook\s+/)[0];
|
|
562
|
+
const missing = expectedCodexHooks(prefix).filter((want) => !installed.some((have) => have.event === want.event &&
|
|
563
|
+
have.command === want.command &&
|
|
564
|
+
have.matcher === want.matcher &&
|
|
565
|
+
have.timeout === want.timeout));
|
|
566
|
+
if (missing.length === 0) {
|
|
567
|
+
return [done(`Codex hook entries are installed here, in ${CODEX_HOOKS_FILE}.`)];
|
|
568
|
+
}
|
|
569
|
+
return [
|
|
570
|
+
warn(`The Codex hook entries here are not the ones this version installs: ${missing
|
|
571
|
+
.map((entry) => `${entry.event} \`${entry.command}\`${entry.matcher ? ` (matcher ${entry.matcher})` : ""}`)
|
|
572
|
+
.join(", ")} ${missing.length === 1 ? "is" : "are"} not in ${CODEX_HOOKS_FILE}. Re-run \`carrick init\`.`),
|
|
573
|
+
];
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* The task skills, which no check could see until now (carrick#1331).
|
|
577
|
+
*
|
|
578
|
+
* Three different things, and they are not the same finding:
|
|
579
|
+
*
|
|
580
|
+
* * **Missing** is a workspace where the bodies an agent is meant to read are
|
|
581
|
+
* not there at all — a repo set up before this package shipped them, or one
|
|
582
|
+
* somebody deleted them from. `carrick init` writes them.
|
|
583
|
+
* * **Written by an older version** is the upgrade nobody is told about
|
|
584
|
+
* (carrick#1333): the file is still ours, byte for byte as it was written,
|
|
585
|
+
* and the body this version renders has moved on. `carrick init` refreshes
|
|
586
|
+
* exactly these.
|
|
587
|
+
* * **Edited here** is somebody's own work, and it is reported as a note
|
|
588
|
+
* rather than a fault: a skill a team has changed is a skill they meant to
|
|
589
|
+
* change, and `carrick init` leaves it alone. Saying it matters because it
|
|
590
|
+
* is also the file that stops receiving what later versions ship.
|
|
591
|
+
*
|
|
592
|
+
* A file nobody here wrote — a skill of the same name from somewhere else — is
|
|
593
|
+
* not reported at all. It is not ours, and doctor has nothing to say about it.
|
|
594
|
+
*/
|
|
595
|
+
export function checkTaskSkills(installed) {
|
|
596
|
+
const lines = [];
|
|
597
|
+
const missing = installed.filter((skill) => skill.state === "absent");
|
|
598
|
+
const stale = installed.filter((skill) => skill.state === "ours" && !skill.current);
|
|
599
|
+
const edited = installed.filter((skill) => skill.state === "edited");
|
|
600
|
+
if (missing.length > 0) {
|
|
601
|
+
lines.push(warn(`${missing.length} of the ${installed.length} task skill file(s) are missing here (${missing[0].path} and others), so your agent has no Carrick task to follow. \`carrick init\` writes them.`));
|
|
602
|
+
}
|
|
603
|
+
if (stale.length > 0) {
|
|
604
|
+
lines.push(warn(`${stale.length} task skill file(s) here were written by an older version of carrick (${stale[0].path} and others). Re-run \`carrick init\`: it rewrites the ones still untouched and leaves the rest.`));
|
|
605
|
+
}
|
|
606
|
+
for (const skill of edited) {
|
|
607
|
+
lines.push(say(`${skill.path} has been edited here, so \`carrick init\` leaves it as it is and it stays at the version you changed.`));
|
|
608
|
+
}
|
|
609
|
+
if (findingCount(lines) === 0 && installed.some((skill) => skill.state === "ours")) {
|
|
610
|
+
lines.push(done(`Task skills installed here and current: ${TASK_SKILLS.join(", ")}.`));
|
|
611
|
+
}
|
|
612
|
+
return lines;
|
|
613
|
+
}
|
|
521
614
|
/** The MCP server entry in each agent client this machine has. */
|
|
522
615
|
export function checkMcp(inspections) {
|
|
523
616
|
if (inspections.length === 0) {
|
|
@@ -658,6 +751,8 @@ export async function doctor(argv, out = createOutput()) {
|
|
|
658
751
|
...checkDeclaredPaths(repos),
|
|
659
752
|
...checkWorkflow(repos),
|
|
660
753
|
...checkHooks(workspace, realMachine()),
|
|
754
|
+
...checkCodexHooks(workspace),
|
|
755
|
+
...checkTaskSkills(inspectTaskSkills(workspace)),
|
|
661
756
|
...checkMcp(inspectMcpClients()),
|
|
662
757
|
...(await readIndex(workspace)),
|
|
663
758
|
];
|