carrick 0.3.61 → 0.3.63
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 +32 -12
- package/bin/carrick.mjs +7 -6
- package/dist/auth/read.d.ts +6 -6
- package/dist/contract.d.ts +102 -0
- package/dist/contract.js +22 -0
- package/dist/contract.js.map +1 -1
- package/dist/init/connect.d.ts +31 -2
- package/dist/init/connect.js +153 -29
- package/dist/init/connect.js.map +1 -1
- package/dist/init/projects.d.ts +110 -0
- package/dist/init/projects.js +162 -3
- package/dist/init/projects.js.map +1 -1
- package/dist/init/repos.d.ts +61 -7
- package/dist/init/repos.js +125 -31
- package/dist/init/repos.js.map +1 -1
- package/dist/init/run.d.ts +33 -2
- package/dist/init/run.js +227 -135
- package/dist/init/run.js.map +1 -1
- package/dist/render.d.ts +20 -8
- package/dist/render.js +65 -16
- package/dist/render.js.map +1 -1
- package/package.json +6 -6
package/dist/init/repos.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repos.js","sourceRoot":"","sources":["../../src/init/repos.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAE9D,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;AAClJ,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC;IACxB,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC3F,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACnG,eAAe,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC3F,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;CACxK,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"repos.js","sourceRoot":"","sources":["../../src/init/repos.ts"],"names":[],"mappings":"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"}
|
package/dist/init/run.d.ts
CHANGED
|
@@ -1,13 +1,44 @@
|
|
|
1
|
+
import { type ResolvedRepos } from "../auth/read.ts";
|
|
2
|
+
/**
|
|
3
|
+
* The prompt that makes an agent write this repo's config and setup files.
|
|
4
|
+
*
|
|
5
|
+
* A copy of the `scaffold` MCP tool's own instructions and the dashboard copy
|
|
6
|
+
* beside them (carrick-cloud#800), whose test checks every filename against
|
|
7
|
+
* what the tool returns. It is printed here so the terminal path ends where
|
|
8
|
+
* the dashboard path ends, and it states the sequence the ruling in
|
|
9
|
+
* carrick-cloud#799 fixed: the agent writes a complete `carrick.json` from the
|
|
10
|
+
* proposal this command derived, `carrick index` proves it for nothing, and
|
|
11
|
+
* only then does the one paid scan run. Keep the two copies in step; the
|
|
12
|
+
* tool's instructions, not this text, decide what gets written.
|
|
13
|
+
*
|
|
14
|
+
* One clause is this side's alone, because only this side knows it: whether
|
|
15
|
+
* the workspace read found a hosted index for these repos. Where there is one,
|
|
16
|
+
* the paid scan has already run in CI and a laptop scan from a branch would
|
|
17
|
+
* replace that row for everyone in the workspace, so the agent is told not to
|
|
18
|
+
* run it (carrick#993, cloud half carrick-cloud#805).
|
|
19
|
+
*/
|
|
20
|
+
export declare function agentScaffoldPrompt(hosted: boolean): string;
|
|
1
21
|
export type InitOptions = {
|
|
2
22
|
workspace: string;
|
|
3
23
|
/** Require every proposed GitHub repo to belong to this project. */
|
|
4
24
|
project: string | null;
|
|
25
|
+
/** The `owner/repo` to use when the origin remote names none (carrick#991). */
|
|
26
|
+
repo: string | null;
|
|
5
27
|
/** Answer yes to the repo list rather than asking. */
|
|
6
28
|
assumeYes: boolean;
|
|
7
|
-
/** Write the files, print the lines, and do not build the index. */
|
|
8
|
-
skipIndex: boolean;
|
|
9
29
|
};
|
|
10
30
|
export declare function parseArgs(argv: string[], cwd?: string): InitOptions | string;
|
|
31
|
+
/**
|
|
32
|
+
* The repos a project holds that this folder does not, one line per project.
|
|
33
|
+
*
|
|
34
|
+
* Carrick answers across every repo in a project, so a machine holding half of
|
|
35
|
+
* one gets half the answers, and the connection lines above name only what is
|
|
36
|
+
* here. `project_repos` is the workspace read's answer to that: the whole
|
|
37
|
+
* membership of every project the requested repos are in (carrick#993 row 18).
|
|
38
|
+
* Capped and counted like the identity lines, because a project can hold two
|
|
39
|
+
* hundred.
|
|
40
|
+
*/
|
|
41
|
+
export declare function absentRepos(identity: ResolvedRepos, names: string[], project: string | null): string[];
|
|
11
42
|
/**
|
|
12
43
|
* The editor lines, one line per editor that is on the machine.
|
|
13
44
|
*
|
package/dist/init/run.js
CHANGED
|
@@ -6,35 +6,58 @@ import { spawnSync } from "node:child_process";
|
|
|
6
6
|
import { readCredential } from "../auth/credentials.js";
|
|
7
7
|
import { signIn } from "../auth/run.js";
|
|
8
8
|
import { resolveRepos } from "../auth/read.js";
|
|
9
|
-
import { deriveWorkspace,
|
|
10
|
-
import { connectRepos, reposAreInProject } from "./connect.js";
|
|
11
|
-
import {
|
|
9
|
+
import { deriveWorkspace, writeProposal, PROPOSAL_FILE, repoIdentity } from "./repos.js";
|
|
10
|
+
import { connectRepos, reposAreInProject, projectAssignments } from "./connect.js";
|
|
11
|
+
import { ensureProject, projectStep, SLUG } from "./projects.js";
|
|
12
12
|
import { connectMcpClients, mcpLines } from "./mcp.js";
|
|
13
13
|
import { hookCommand, mergeCarrickHooks } from "./settings.js";
|
|
14
14
|
import { renderTemplate } from "../templates.js";
|
|
15
|
-
import {
|
|
15
|
+
import { packageRoot } from "../native.js";
|
|
16
16
|
const EXTENSION_ID = "carrick-tools.carrick";
|
|
17
17
|
/**
|
|
18
|
-
* The prompt that makes an agent write this repo's setup files.
|
|
18
|
+
* The prompt that makes an agent write this repo's config and setup files.
|
|
19
19
|
*
|
|
20
|
-
* A copy
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* decide what gets written.
|
|
20
|
+
* A copy of the `scaffold` MCP tool's own instructions and the dashboard copy
|
|
21
|
+
* beside them (carrick-cloud#800), whose test checks every filename against
|
|
22
|
+
* what the tool returns. It is printed here so the terminal path ends where
|
|
23
|
+
* the dashboard path ends, and it states the sequence the ruling in
|
|
24
|
+
* carrick-cloud#799 fixed: the agent writes a complete `carrick.json` from the
|
|
25
|
+
* proposal this command derived, `carrick index` proves it for nothing, and
|
|
26
|
+
* only then does the one paid scan run. Keep the two copies in step; the
|
|
27
|
+
* tool's instructions, not this text, decide what gets written.
|
|
28
|
+
*
|
|
29
|
+
* One clause is this side's alone, because only this side knows it: whether
|
|
30
|
+
* the workspace read found a hosted index for these repos. Where there is one,
|
|
31
|
+
* the paid scan has already run in CI and a laptop scan from a branch would
|
|
32
|
+
* replace that row for everyone in the workspace, so the agent is told not to
|
|
33
|
+
* run it (carrick#993, cloud half carrick-cloud#805).
|
|
28
34
|
*/
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
export function agentScaffoldPrompt(hosted) {
|
|
36
|
+
return ("Run the carrick scaffold tool, passing this repo's owner/repo from " +
|
|
37
|
+
"`git remote get-url origin` as `repo`, and follow the instructions it " +
|
|
38
|
+
"returns: create each file at its path, and write carrick.json from the " +
|
|
39
|
+
"proposal in .carrick/proposal.json, taking applications as services and " +
|
|
40
|
+
"library workspace members as shared includes of the services that import " +
|
|
41
|
+
"them, with the env vars and domains each service calls. Add the Carrick " +
|
|
42
|
+
"section to AGENTS.md if this repo already has one. Then run `carrick " +
|
|
43
|
+
"index`, which is free and runs no model, and fix whatever it reports as " +
|
|
44
|
+
"unclassified or in no service. " +
|
|
45
|
+
(hosted
|
|
46
|
+
? "Do not run `carrick index --infer`: this repo already has a hosted " +
|
|
47
|
+
"index, and a laptop scan from a branch replaces the CI row for " +
|
|
48
|
+
"everyone. "
|
|
49
|
+
: // carrick#960/#1003: an agent's shell caps a command well below the
|
|
50
|
+
// fifteen minutes a first paid scan takes, so the scan is detached and
|
|
51
|
+
// the agent asks `carrick status` how it went. Mirrors the scaffold
|
|
52
|
+
// tool's own wording (carrick-cloud#821).
|
|
53
|
+
"Then run `carrick index --infer --detach` once for the scan that " +
|
|
54
|
+
"builds the index, checking `carrick status` about once a minute " +
|
|
55
|
+
"until it says the scan finished, stopped or failed. ") +
|
|
56
|
+
"Answer the closing checklist before you open the PR.");
|
|
57
|
+
}
|
|
58
|
+
const OWNER_REPO = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
|
|
36
59
|
export function parseArgs(argv, cwd = process.cwd()) {
|
|
37
|
-
const options = { workspace: cwd, project: null,
|
|
60
|
+
const options = { workspace: cwd, project: null, repo: null, assumeYes: false };
|
|
38
61
|
for (let index = 0; index < argv.length; index += 1) {
|
|
39
62
|
const argument = argv[index];
|
|
40
63
|
switch (argument) {
|
|
@@ -42,20 +65,27 @@ export function parseArgs(argv, cwd = process.cwd()) {
|
|
|
42
65
|
case "-y":
|
|
43
66
|
options.assumeYes = true;
|
|
44
67
|
break;
|
|
45
|
-
case "--skip-index":
|
|
46
|
-
options.skipIndex = true;
|
|
47
|
-
break;
|
|
48
68
|
case "--project": {
|
|
49
69
|
const value = argv[index + 1];
|
|
50
70
|
if (!value)
|
|
51
71
|
return "--project needs a slug";
|
|
52
|
-
if (
|
|
72
|
+
if (!SLUG.test(value)) {
|
|
53
73
|
return `invalid project slug "${value}": use 3-32 lowercase letters, digits, and single hyphens`;
|
|
54
74
|
}
|
|
55
75
|
options.project = value;
|
|
56
76
|
index += 1;
|
|
57
77
|
break;
|
|
58
78
|
}
|
|
79
|
+
case "--repo": {
|
|
80
|
+
const value = argv[index + 1];
|
|
81
|
+
if (!value)
|
|
82
|
+
return "--repo needs an owner/repo";
|
|
83
|
+
if (!OWNER_REPO.test(value))
|
|
84
|
+
return `invalid repo "${value}": use owner/repo as GitHub spells it`;
|
|
85
|
+
options.repo = value;
|
|
86
|
+
index += 1;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
59
89
|
case "--workspace":
|
|
60
90
|
case "-w": {
|
|
61
91
|
const value = argv[index + 1];
|
|
@@ -78,19 +108,21 @@ export function parseArgs(argv, cwd = process.cwd()) {
|
|
|
78
108
|
}
|
|
79
109
|
function help() {
|
|
80
110
|
return [
|
|
81
|
-
"carrick init [DIRECTORY] [--project SLUG]",
|
|
111
|
+
"carrick init [DIRECTORY] [--project SLUG] [--repo OWNER/REPO]",
|
|
82
112
|
"",
|
|
83
|
-
"Sign in (here, or beforehand with carrick login), then
|
|
84
|
-
"
|
|
85
|
-
"
|
|
113
|
+
"Sign in (here, or beforehand with carrick login), then set up a repository",
|
|
114
|
+
"or a folder of repos: the project, the repo connection, the agent hooks,",
|
|
115
|
+
"the MCP connection, and the service proposal your agent turns into",
|
|
116
|
+
"carrick.json. It writes nothing into the repository but the ignored",
|
|
117
|
+
".carrick directory and the hook settings, and it runs no scan.",
|
|
86
118
|
"With --project, a project missing from the workspace is offered for",
|
|
87
|
-
"creation here
|
|
88
|
-
"
|
|
119
|
+
"creation here, and the repos are put in it from the terminal once the",
|
|
120
|
+
"GitHub App grant connects them.",
|
|
89
121
|
"",
|
|
90
122
|
" -w, --workspace DIR The folder holding the repos (default: this one)",
|
|
91
123
|
" --project SLUG Require these repos in this Carrick project",
|
|
124
|
+
" --repo OWNER/REPO Name the GitHub repo whose origin remote names none",
|
|
92
125
|
" -y, --yes Take the repo list as proposed",
|
|
93
|
-
" --skip-index Write the files and print the lines, index later",
|
|
94
126
|
].join("\n");
|
|
95
127
|
}
|
|
96
128
|
function say(line = "") {
|
|
@@ -106,6 +138,16 @@ async function confirm(question) {
|
|
|
106
138
|
rl.close();
|
|
107
139
|
}
|
|
108
140
|
}
|
|
141
|
+
/** A typed answer, for the questions whose answer is not yes or no. */
|
|
142
|
+
async function ask(question) {
|
|
143
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
144
|
+
try {
|
|
145
|
+
return (await rl.question(`${question}\n> `)).trim();
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
rl.close();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
109
151
|
function writeIfChanged(target, body) {
|
|
110
152
|
const existing = fs.existsSync(target) ? fs.readFileSync(target, "utf8") : null;
|
|
111
153
|
if (existing === body)
|
|
@@ -121,6 +163,35 @@ function onPath(command) {
|
|
|
121
163
|
});
|
|
122
164
|
return probe.status === 0;
|
|
123
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* The repos a project holds that this folder does not, one line per project.
|
|
168
|
+
*
|
|
169
|
+
* Carrick answers across every repo in a project, so a machine holding half of
|
|
170
|
+
* one gets half the answers, and the connection lines above name only what is
|
|
171
|
+
* here. `project_repos` is the workspace read's answer to that: the whole
|
|
172
|
+
* membership of every project the requested repos are in (carrick#993 row 18).
|
|
173
|
+
* Capped and counted like the identity lines, because a project can hold two
|
|
174
|
+
* hundred.
|
|
175
|
+
*/
|
|
176
|
+
export function absentRepos(identity, names, project) {
|
|
177
|
+
const onDisk = new Set(names.map((name) => name.toLowerCase()));
|
|
178
|
+
const sole = identity.project_repos.length === 1;
|
|
179
|
+
const lines = [];
|
|
180
|
+
for (const entry of identity.project_repos) {
|
|
181
|
+
// With a project settled, the others are somebody else's business.
|
|
182
|
+
if (project !== null && entry.project_slug !== project)
|
|
183
|
+
continue;
|
|
184
|
+
const absent = entry.repos.filter((repo) => !onDisk.has(repo.toLowerCase()));
|
|
185
|
+
if (absent.length === 0)
|
|
186
|
+
continue;
|
|
187
|
+
const shown = absent.length > 10
|
|
188
|
+
? `${absent.slice(0, 10).join(", ")} and ${absent.length - 10} more`
|
|
189
|
+
: absent.join(", ");
|
|
190
|
+
const where = sole || entry.project_slug === project ? "this project" : `project "${entry.project_slug}"`;
|
|
191
|
+
lines.push(`Also in ${where}, not on this machine: ${shown}.`);
|
|
192
|
+
}
|
|
193
|
+
return lines;
|
|
194
|
+
}
|
|
124
195
|
/**
|
|
125
196
|
* The editor lines, one line per editor that is on the machine.
|
|
126
197
|
*
|
|
@@ -151,40 +222,6 @@ export function editorLines(onPath) {
|
|
|
151
222
|
}
|
|
152
223
|
return lines;
|
|
153
224
|
}
|
|
154
|
-
/**
|
|
155
|
-
* Make sure the named project exists, from the terminal where that is possible.
|
|
156
|
-
*
|
|
157
|
-
* Returns whether this run can state that the project exists. `false` is the
|
|
158
|
-
* honest answer for every case it could not settle — an API without the
|
|
159
|
-
* actions, a declined offer, a refused create — and the caller then prints
|
|
160
|
-
* today's browser instructions, which include creating it.
|
|
161
|
-
*/
|
|
162
|
-
async function ensureProject(token, slug, options) {
|
|
163
|
-
const { say } = options;
|
|
164
|
-
const projects = await listProjects(token);
|
|
165
|
-
if (projects === null)
|
|
166
|
-
return false;
|
|
167
|
-
if (projects.some((project) => project.slug === slug && !project.archived)) {
|
|
168
|
-
say(`Project "${slug}" is in this workspace.`);
|
|
169
|
-
return true;
|
|
170
|
-
}
|
|
171
|
-
say(projects.length === 0
|
|
172
|
-
? "This workspace has no projects yet."
|
|
173
|
-
: "Projects in this workspace:");
|
|
174
|
-
for (const line of projectLines(projects))
|
|
175
|
-
say(line);
|
|
176
|
-
const create = options.assumeYes || (options.interactive && (await confirm(`Create project "${slug}"?`)));
|
|
177
|
-
if (!create)
|
|
178
|
-
return false;
|
|
179
|
-
const outcome = await createProject(token, slug);
|
|
180
|
-
if (outcome.kind === "created") {
|
|
181
|
-
say(`Created project "${slug}".`);
|
|
182
|
-
return true;
|
|
183
|
-
}
|
|
184
|
-
if (outcome.kind === "refused")
|
|
185
|
-
say(`Carrick did not create "${slug}": ${outcome.message}`);
|
|
186
|
-
return false;
|
|
187
|
-
}
|
|
188
225
|
export async function init(argv) {
|
|
189
226
|
const parsed = parseArgs(argv);
|
|
190
227
|
if (typeof parsed === "string") {
|
|
@@ -198,7 +235,12 @@ export async function init(argv) {
|
|
|
198
235
|
}
|
|
199
236
|
const interactive = process.stdin.isTTY === true;
|
|
200
237
|
// Authentication and all derivation validation precede local writes.
|
|
201
|
-
let
|
|
238
|
+
let derived;
|
|
239
|
+
// What the workspace read said about these repos, for the closing lines
|
|
240
|
+
// printed long after it: a repo Carrick already holds an index for must not
|
|
241
|
+
// be told to run the paid scan again (carrick#993).
|
|
242
|
+
let requested = [];
|
|
243
|
+
const hostedIndex = [];
|
|
202
244
|
try {
|
|
203
245
|
// A machine that has never signed in signs in here rather than being told
|
|
204
246
|
// to run another command: `carrick login` is the same browser round trip,
|
|
@@ -212,12 +254,46 @@ export async function init(argv) {
|
|
|
212
254
|
say("This machine is not signed in to Carrick.");
|
|
213
255
|
credential = await signIn(say);
|
|
214
256
|
}
|
|
215
|
-
|
|
216
|
-
const
|
|
257
|
+
derived = deriveWorkspace(workspace);
|
|
258
|
+
const derivedIdentities = derived.plan.repos.map((repo) => repoIdentity(repo.path));
|
|
259
|
+
// `--repo` names what a remote could not: an ssh alias ssh itself cannot
|
|
260
|
+
// resolve, a mirror, a clone with no origin. It names one repository, so
|
|
261
|
+
// it is taken only when exactly one repo here is missing an identity.
|
|
262
|
+
const unnamed = derivedIdentities.filter((repo) => repo.name === null);
|
|
263
|
+
let taken = null;
|
|
264
|
+
if (parsed.repo !== null) {
|
|
265
|
+
if (unnamed.length > 1) {
|
|
266
|
+
throw new Error(`--repo names one repository, but ${unnamed.length} repos here have no GitHub identity: ${unnamed.map((repo) => repo.path).join(", ")}. Run carrick init --repo in each of them, or fix their origin remotes.`);
|
|
267
|
+
}
|
|
268
|
+
if (unnamed.length === 0) {
|
|
269
|
+
say(`--repo ${parsed.repo} was not needed: every repo here names its own GitHub repository.`);
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
taken = unnamed[0].path;
|
|
273
|
+
say(`Taking ${parsed.repo} as the GitHub repository for ${taken}.`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
const repoIdentities = derivedIdentities.map((repo) => repo.path === taken ? { ...repo, name: parsed.repo, problem: null } : repo);
|
|
217
277
|
const names = [...new Set(repoIdentities.map((repo) => repo.name).filter((name) => name !== null))];
|
|
218
278
|
if (names.length > 200)
|
|
219
279
|
throw new Error("This workspace has more than 200 GitHub repos. Initialise smaller workspace groups.");
|
|
220
280
|
const missingIdentities = repoIdentities.filter((repo) => repo.name === null);
|
|
281
|
+
// Said before anything is requested, and said whether or not --project was
|
|
282
|
+
// given: a repo with no identity is left out of the project step, the
|
|
283
|
+
// connection check and the workspace read, and a run that dropped it in
|
|
284
|
+
// silence read as a complete one (carrick#991).
|
|
285
|
+
// A folder of clones can hold dozens, so the list is capped and the rest
|
|
286
|
+
// is counted rather than dropped.
|
|
287
|
+
for (const repo of missingIdentities.slice(0, 10)) {
|
|
288
|
+
say(`${repo.path} contributes no GitHub identity: ${repo.problem}.`);
|
|
289
|
+
}
|
|
290
|
+
if (missingIdentities.length > 10) {
|
|
291
|
+
say(`${missingIdentities.length - 10} more repos here name no GitHub identity either.`);
|
|
292
|
+
}
|
|
293
|
+
if (missingIdentities.length > 0) {
|
|
294
|
+
const one = missingIdentities.length === 1;
|
|
295
|
+
say(` Carrick has nothing to connect ${one ? "it" : "them"} to. Run carrick init --repo owner/repo${one ? "" : " in each of them"}, or give the alias a HostName github.com line in your ssh config.`);
|
|
296
|
+
}
|
|
221
297
|
if (parsed.project && missingIdentities.length > 0) {
|
|
222
298
|
throw new Error(`--project ${parsed.project} cannot verify ${missingIdentities.map((repo) => repo.path).join(", ")} because ${missingIdentities.length === 1 ? "it has" : "they have"} no GitHub origin. No project assignment was verified.`);
|
|
223
299
|
}
|
|
@@ -229,25 +305,43 @@ export async function init(argv) {
|
|
|
229
305
|
for (const name of names)
|
|
230
306
|
say(` ${name}`);
|
|
231
307
|
}
|
|
308
|
+
else if (names.length === 0) {
|
|
309
|
+
// The sentence that stops the rest of this run from reading as a
|
|
310
|
+
// complete one: no project is chosen, no connection is checked, and a
|
|
311
|
+
// later upload has no repo identity to resolve a project from.
|
|
312
|
+
say("No repo here names a GitHub repository, so this run chooses no project and checks no connection.");
|
|
313
|
+
}
|
|
314
|
+
requested = names;
|
|
232
315
|
const initial = await resolveRepos(credential.token, names);
|
|
233
316
|
// The project half of the browser round trip, where this API can do it
|
|
234
|
-
// from here
|
|
235
|
-
//
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
317
|
+
// from here: the project is created here, and `connectRepos` puts the
|
|
318
|
+
// repos in it as the grant connects them (carrick#999), so the wait is on
|
|
319
|
+
// the GitHub App grant and nothing else. Without --project the step reads
|
|
320
|
+
// the assignment the repos already have and offers the list, rather than
|
|
321
|
+
// doing nothing at all (carrick#987).
|
|
322
|
+
const prompts = { say, ask, confirm, interactive, assumeYes: parsed.assumeYes };
|
|
323
|
+
let project = parsed.project;
|
|
324
|
+
let projectExists = false;
|
|
325
|
+
if (project === null) {
|
|
326
|
+
const chosen = await projectStep(credential.token, projectAssignments(initial, names), prompts);
|
|
327
|
+
project = chosen.slug;
|
|
328
|
+
projectExists = chosen.exists;
|
|
329
|
+
}
|
|
330
|
+
else if (!reposAreInProject(initial, names, project)) {
|
|
331
|
+
projectExists = await ensureProject(credential.token, project, prompts);
|
|
332
|
+
}
|
|
243
333
|
const identity = await connectRepos(credential.token, names, initial, {
|
|
244
334
|
interactive,
|
|
245
|
-
project:
|
|
335
|
+
project: project ?? undefined,
|
|
246
336
|
projectExists,
|
|
247
337
|
say,
|
|
248
338
|
});
|
|
249
|
-
if (
|
|
250
|
-
|
|
339
|
+
if (project !== null && !reposAreInProject(identity, names, project)) {
|
|
340
|
+
// An unverified project does not end the run, whether it was named on
|
|
341
|
+
// the command line or picked here. Stopping cost someone their hooks and
|
|
342
|
+
// their proposal for a browser step they could only take afterwards, and
|
|
343
|
+
// the documented command then needed two runs (carrick#993 row 8).
|
|
344
|
+
say(`Setup continues; finish the browser steps above to put these repos in "${project}", then run carrick init --project ${project} again to verify.`);
|
|
251
345
|
}
|
|
252
346
|
say(`Carrick workspace: ${identity.workspace.slug}`);
|
|
253
347
|
if (identity.allowance_sentence)
|
|
@@ -255,18 +349,25 @@ export async function init(argv) {
|
|
|
255
349
|
for (const repo of identity.repos) {
|
|
256
350
|
if (!repo.connected)
|
|
257
351
|
say(`${repo.full_name} is not connected to this Carrick workspace.`);
|
|
258
|
-
|
|
352
|
+
// How to give it one is the last thing this command prints, once, rather
|
|
353
|
+
// than a workflow line per repo before anything is set up.
|
|
354
|
+
else if (repo.services.length === 0)
|
|
259
355
|
say(`${repo.full_name} is connected and has no hosted index yet.`);
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
say(" carrick templates workflow > .github/workflows/carrick.yml");
|
|
263
|
-
}
|
|
356
|
+
else
|
|
357
|
+
hostedIndex.push(repo.full_name);
|
|
264
358
|
}
|
|
359
|
+
// The rest of the project, which this machine does not hold. Carrick
|
|
360
|
+
// answers across every repo in a project, so a folder holding half of one
|
|
361
|
+
// is a partial index and nothing here would otherwise say so
|
|
362
|
+
// (carrick#993 row 18).
|
|
363
|
+
for (const line of absentRepos(identity, names, project))
|
|
364
|
+
say(line);
|
|
265
365
|
}
|
|
266
366
|
catch (error) {
|
|
267
367
|
process.stderr.write(`carrick init: ${error.message}\n`);
|
|
268
368
|
return 1;
|
|
269
369
|
}
|
|
370
|
+
const plan = derived.plan;
|
|
270
371
|
say(`Repos to index, in ${plan.workspace} (${plan.repos_detected_by}):`);
|
|
271
372
|
if (plan.parent_proposal) {
|
|
272
373
|
const parent = plan.parent_proposal;
|
|
@@ -292,20 +393,20 @@ export async function init(argv) {
|
|
|
292
393
|
process.stderr.write("carrick init: use --yes to accept this proposal without a terminal.\n");
|
|
293
394
|
return 1;
|
|
294
395
|
}
|
|
295
|
-
if (!await confirm("
|
|
396
|
+
if (!await confirm("Write this proposal and configure hooks?"))
|
|
296
397
|
return 0;
|
|
297
398
|
}
|
|
298
399
|
try {
|
|
299
|
-
for
|
|
300
|
-
|
|
301
|
-
//
|
|
302
|
-
|
|
400
|
+
// The proposal is a seed for an agent, not a config: nothing derived
|
|
401
|
+
// without a model is written into the repository, because the first scan
|
|
402
|
+
// is the paid one and it has to run against a config someone has read
|
|
403
|
+
// (carrick-cloud#799).
|
|
404
|
+
say(`wrote ${writeProposal(plan.workspace, derived)}`);
|
|
303
405
|
}
|
|
304
406
|
catch (error) {
|
|
305
407
|
process.stderr.write(`carrick init: ${error.message}\n`);
|
|
306
408
|
return 1;
|
|
307
409
|
}
|
|
308
|
-
say("Review carrick.json service boundaries and shared includes before committing it.");
|
|
309
410
|
// 3. The agent hooks. Merged by command: this file may already hold a user's
|
|
310
411
|
// own hooks, or the hook pack the hosted index installs.
|
|
311
412
|
const command = hookCommand({ onPath });
|
|
@@ -332,35 +433,7 @@ export async function init(argv) {
|
|
|
332
433
|
catch (error) {
|
|
333
434
|
say(`Could not configure Carrick hooks: ${error.message}. Fix the settings files and run carrick init again.`);
|
|
334
435
|
}
|
|
335
|
-
// 4. The
|
|
336
|
-
if (parsed.skipIndex) {
|
|
337
|
-
say();
|
|
338
|
-
say("Skipped the index. Build it with: carrick index");
|
|
339
|
-
}
|
|
340
|
-
else {
|
|
341
|
-
say();
|
|
342
|
-
const binary = resolveNativeBinary();
|
|
343
|
-
if (!binary.binary) {
|
|
344
|
-
process.stderr.write(`carrick init: ${binary.problem}\n`);
|
|
345
|
-
return 1;
|
|
346
|
-
}
|
|
347
|
-
// `--infer` is what makes the first run produce an index worth reading.
|
|
348
|
-
// A local scan states the facts it can derive and leaves everything only
|
|
349
|
-
// the model can classify unclassified; this run asks Carrick Cloud for
|
|
350
|
-
// those, uploads the result, and writes the same payload into `.carrick`
|
|
351
|
-
// from the same run — so there is no scan, then wait, then download
|
|
352
|
-
// (carrick#956 §8.3). Every later `carrick index`, and every hook-driven
|
|
353
|
-
// `carrick refresh`, is the free local one.
|
|
354
|
-
const scan = spawnSync(binary.binary, ["index", "--workspace", workspace, "--infer"], {
|
|
355
|
-
stdio: "inherit",
|
|
356
|
-
env: nativeEnv(),
|
|
357
|
-
});
|
|
358
|
-
if (scan.status !== 0) {
|
|
359
|
-
process.stderr.write(`carrick init: the first index did not finish. The files above are written, so fix what it reported and run: carrick index --infer\n`);
|
|
360
|
-
return scan.status ?? 1;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
// 5. The MCP connection, for work that crosses repos this machine does not
|
|
436
|
+
// 4. The MCP connection, for work that crosses repos this machine does not
|
|
364
437
|
// hold. Configured here for every client this machine has, rather than
|
|
365
438
|
// printed for one of them (carrick#955).
|
|
366
439
|
say();
|
|
@@ -369,19 +442,6 @@ export async function init(argv) {
|
|
|
369
442
|
for (const line of mcpLines(connectMcpClients()))
|
|
370
443
|
say(line);
|
|
371
444
|
say();
|
|
372
|
-
say(" The CI check, once per repo (it needs no secret). Paste this to your agent:");
|
|
373
|
-
say();
|
|
374
|
-
say(` ${AGENT_SCAFFOLD_PROMPT}`);
|
|
375
|
-
say();
|
|
376
|
-
say(" Or write the workflow yourself:");
|
|
377
|
-
say(" mkdir -p .github/workflows");
|
|
378
|
-
say(" carrick templates workflow > .github/workflows/carrick.yml");
|
|
379
|
-
say();
|
|
380
|
-
say(" The first scan on the repo's default branch writes the hosted index. A session");
|
|
381
|
-
say(" started in this folder afterwards picks it up on its own; by hand it is:");
|
|
382
|
-
say(" carrick refresh");
|
|
383
|
-
say(" carrick status");
|
|
384
|
-
say();
|
|
385
445
|
for (const line of editorLines(onPath))
|
|
386
446
|
say(line);
|
|
387
447
|
say();
|
|
@@ -393,8 +453,40 @@ export async function init(argv) {
|
|
|
393
453
|
say(" That plugin's language server is started as `carrick`, which this machine cannot resolve;");
|
|
394
454
|
say(" install it globally first, or the hooks above are the channel.");
|
|
395
455
|
}
|
|
456
|
+
say("Once the index exists, editing a file with a route or a call in it is what");
|
|
457
|
+
say("Carrick answers on; `carrick status` says what the index holds.");
|
|
458
|
+
say();
|
|
459
|
+
// No scan ran here, and that is the point (carrick-cloud#799): the one paid
|
|
460
|
+
// scan runs against a config someone has read, so the last thing this
|
|
461
|
+
// command prints is the prompt that produces that config.
|
|
462
|
+
//
|
|
463
|
+
// Unless CI has already built one. The hosted index is the whole workspace's
|
|
464
|
+
// row, and `--infer` from a laptop on a branch replaces it for everyone who
|
|
465
|
+
// queries it, so where the workspace read found services this says so and
|
|
466
|
+
// names the free command instead (carrick#993 row 2).
|
|
467
|
+
if (hostedIndex.length > 0) {
|
|
468
|
+
const subject = hostedIndex.length === requested.length && requested.length === 1
|
|
469
|
+
? "This repo"
|
|
470
|
+
: hostedIndex.length > 3
|
|
471
|
+
? `${hostedIndex.slice(0, 3).join(", ")} and ${hostedIndex.length - 3} more`
|
|
472
|
+
: hostedIndex.join(", ");
|
|
473
|
+
say(` ${subject} already ${hostedIndex.length === 1 ? "has" : "have"} a hosted index. Run \`carrick index\` (free); do not run`);
|
|
474
|
+
say(" `carrick index --infer`, a laptop scan from a branch replaces the CI row for");
|
|
475
|
+
say(` everyone. ${PROPOSAL_FILE} holds the services this run derived, to compare`);
|
|
476
|
+
say(" with the carrick.json already committed.");
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
say(` There is no index yet. ${PROPOSAL_FILE} holds the services this run derived;`);
|
|
480
|
+
say(" an agent turns it into carrick.json, adds the CI check (which needs no secret),");
|
|
481
|
+
say(" and builds the index: `carrick index` is free and runs no model, and");
|
|
482
|
+
say(" `carrick index --infer` is the single scan that asks Carrick to classify the rest.");
|
|
483
|
+
say(" By hand instead: `carrick templates workflow > .github/workflows/carrick.yml`, a");
|
|
484
|
+
say(" carrick.json per https://docs.carrick.tools/carrick-json, then those two commands.");
|
|
485
|
+
}
|
|
486
|
+
say();
|
|
487
|
+
say(" Paste this to your agent:");
|
|
396
488
|
say();
|
|
397
|
-
say(
|
|
489
|
+
say(` ${agentScaffoldPrompt(hostedIndex.length > 0)}`);
|
|
398
490
|
return 0;
|
|
399
491
|
}
|
|
400
492
|
/** `carrick templates <name>`, so the workflow above is one command. */
|