@clue-ai/cli 0.0.9 → 0.0.10
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 +37 -26
- package/bin/clue-cli.mjs +93 -54
- package/package.json +1 -1
- package/src/cli-invocation.mjs +34 -0
- package/src/command-spec.mjs +3 -0
- package/src/init-tool.mjs +2 -1
- package/src/lifecycle-guard.mjs +168 -103
- package/src/lifecycle-init.mjs +593 -187
- package/src/semantic-agent-runner.mjs +3 -1
- package/src/setup-check.mjs +641 -47
- package/src/setup-help.mjs +69 -0
- package/src/setup-prepare.mjs +75 -15
- package/src/setup-tool.mjs +421 -388
package/README.md
CHANGED
|
@@ -6,52 +6,63 @@ The Clue product repository keeps SDKs, shared schemas, and API contracts. Tool
|
|
|
6
6
|
|
|
7
7
|
## Commands
|
|
8
8
|
|
|
9
|
+
The public npm package is `@clue-ai/cli`. The binary exposed by that package is
|
|
10
|
+
`clue-ai`, but first-run setup should not assume a global `clue-ai` install.
|
|
11
|
+
Use `npx -y @clue-ai/cli <command>` unless `.clue/setup-manifest.json`
|
|
12
|
+
explicitly provides a different invocation.
|
|
13
|
+
|
|
9
14
|
```bash
|
|
10
15
|
/clue-init
|
|
11
|
-
clue-ai setup --clue-api-key <key> --clue-api-base-url <url> --project-key <key> --environment dev
|
|
12
|
-
clue-ai setup-detect --repo .
|
|
13
|
-
clue-ai semantic-inventory --framework fastapi --backend-root-path backend --repo .
|
|
14
|
-
clue-ai semantic-workflow --framework fastapi --backend-root-path backend --repo .
|
|
15
|
-
clue-ai lifecycle-apply --plan clue-lifecycle-plan.json --repo .
|
|
16
|
-
clue-ai setup-check --framework fastapi --backend-root-path backend --repo . --target codex --require-sdk-lifecycle
|
|
17
|
-
clue-ai setup-watch --project-key <key> --environment dev --clue-api-base-url <clue-api-base-url> --watch-targets frontend:web[init,identify,set-account,event-sent]=<frontend-url>,backend:api[init,identify,set-account,logout,event-sent]=<backend-url>
|
|
18
|
-
clue-ai init --request clue-init-request.json --repo .
|
|
19
|
-
clue-ai semantic-gen --request clue-semantic-request.json --repo .
|
|
16
|
+
npx -y @clue-ai/cli setup --clue-api-key <key> --clue-api-base-url <url> --project-key <key> --environment dev
|
|
17
|
+
npx -y @clue-ai/cli setup-detect --repo .
|
|
18
|
+
npx -y @clue-ai/cli semantic-inventory --framework fastapi --backend-root-path backend --repo .
|
|
19
|
+
npx -y @clue-ai/cli semantic-workflow --framework fastapi --backend-root-path backend --repo .
|
|
20
|
+
npx -y @clue-ai/cli lifecycle-apply --plan clue-lifecycle-plan.json --repo .
|
|
21
|
+
npx -y @clue-ai/cli setup-check --framework fastapi --backend-root-path backend --repo . --target codex --require-sdk-lifecycle
|
|
22
|
+
npx -y @clue-ai/cli setup-watch --project-key <key> --environment dev --clue-api-base-url <clue-api-base-url> --watch-targets frontend:web[init,identify,set-account,event-sent]=<frontend-url>,backend:api[init,identify,set-account,logout,event-sent]=<backend-url>
|
|
23
|
+
npx -y @clue-ai/cli init --request clue-init-request.json --repo .
|
|
24
|
+
npx -y @clue-ai/cli semantic-gen --request clue-semantic-request.json --repo .
|
|
20
25
|
```
|
|
21
26
|
|
|
22
27
|
`/clue-init` is the standard user-facing command for Codex and Claude Code
|
|
23
28
|
wrappers. The command collects structured setup inputs and invokes the same
|
|
24
29
|
tool request/report contract as `clue-ai init`.
|
|
25
30
|
|
|
26
|
-
`clue-ai semantic-workflow` mechanically writes the GitHub Actions workflow that
|
|
27
|
-
|
|
28
|
-
`clue-ai semantic-gen`. Do not commit runtime semantic
|
|
29
|
-
repositories.
|
|
31
|
+
`npx -y @clue-ai/cli semantic-workflow` mechanically writes the GitHub Actions workflow that
|
|
32
|
+
passes the semantic generation request through `CLUE_SEMANTIC_REQUEST_JSON` at
|
|
33
|
+
CI runtime and then runs `npx -y @clue-ai/cli semantic-gen`. Do not commit runtime semantic
|
|
34
|
+
request files to client repositories.
|
|
30
35
|
|
|
31
|
-
`clue-ai setup` installs the target AI-tool skills and, when backend routes are
|
|
36
|
+
`npx -y @clue-ai/cli setup` installs the target AI-tool skills and, when backend routes are
|
|
32
37
|
detectable, also runs the machine-owned setup preparation:
|
|
33
38
|
|
|
34
39
|
- detects the FastAPI backend root
|
|
35
|
-
- writes `.clue/semantic-routes.json`
|
|
36
40
|
- writes `.github/workflows/clue-semantic-snapshot.yml`
|
|
37
41
|
- writes `.clue/setup-manifest.json`
|
|
42
|
+
- writes `.env.clue` when environment guidance is ready, after protecting it in `.gitignore`
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
Route inventory is computed mechanically on demand and returned in stdout; it is
|
|
45
|
+
not written to `.clue/semantic-routes.json`. The AI prompt should use generated
|
|
46
|
+
manifest/workflow artifacts as inputs and should not hand-edit route inventory
|
|
47
|
+
or semantic CI workflow files.
|
|
41
48
|
|
|
42
|
-
`clue-ai setup-detect` mechanically detects FastAPI route candidates and returns
|
|
49
|
+
`npx -y @clue-ai/cli setup-detect` mechanically detects FastAPI route candidates and returns
|
|
43
50
|
the framework, backend root path, service key candidate, route files, and route
|
|
44
51
|
count before any AI interpretation.
|
|
45
52
|
|
|
46
|
-
`clue-ai lifecycle-apply` mechanically applies an AI-produced exact replacement
|
|
47
|
-
plan after validating edit paths, lifecycle API names,
|
|
48
|
-
DOM clue tags
|
|
53
|
+
`npx -y @clue-ai/cli lifecycle-apply` mechanically applies an AI-produced exact replacement
|
|
54
|
+
plan after validating edit paths, lifecycle API names, blocked-plan status,
|
|
55
|
+
canonical SDK usage, no broad tracking, no DOM clue tags, and claimed lifecycle
|
|
56
|
+
insertion evidence.
|
|
49
57
|
|
|
50
|
-
`clue-ai setup-check` mechanically verifies installed setup skills, route
|
|
58
|
+
`npx -y @clue-ai/cli setup-check` mechanically verifies installed setup skills, route
|
|
51
59
|
inventory, semantic workflow shape, runtime request absence, obvious secret
|
|
52
|
-
leaks, and SDK lifecycle presence when requested.
|
|
60
|
+
leaks, and SDK lifecycle presence when requested. With
|
|
61
|
+
`--require-sdk-lifecycle`, a passing result is still static only; dependency
|
|
62
|
+
installation, SDK imports in the target environments, app startup, and event
|
|
63
|
+
delivery remain required before setup can be called complete.
|
|
53
64
|
|
|
54
|
-
`clue-ai setup-watch` polls the Clue API setup-check endpoint while you operate
|
|
65
|
+
`npx -y @clue-ai/cli setup-watch` polls the Clue API setup-check endpoint while you operate
|
|
55
66
|
the local service. `--clue-api-base-url` is the Clue API URL, not the customer
|
|
56
67
|
frontend URL. Use `--watch-targets` to list every local frontend/backend app by
|
|
57
68
|
service key and the lifecycle checks expected for that service, for example
|
|
@@ -59,7 +70,7 @@ service key and the lifecycle checks expected for that service, for example
|
|
|
59
70
|
Do not assume localhost ports; use the actual URLs printed by the repository's
|
|
60
71
|
dev scripts or configured in its local env.
|
|
61
72
|
|
|
62
|
-
`clue-ai setup` reads Clue values from the setup screen flags, detects local
|
|
73
|
+
`npx -y @clue-ai/cli setup` reads Clue values from the setup screen flags, detects local
|
|
63
74
|
services, writes `.clue/setup-manifest.json`, and prints service-specific env
|
|
64
75
|
blocks. Do not hand-write `CLUE_SERVICE_KEY`; use the value printed for each
|
|
65
76
|
detected service.
|
|
@@ -71,7 +82,7 @@ detected service.
|
|
|
71
82
|
- `CLUE_AI_PROVIDER`: generated from setup target when possible: `codex -> openai`, `claude_code -> anthropic`.
|
|
72
83
|
- `CLUE_AI_MODEL`: generated with a concrete default. OpenAI examples: `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.4-nano`. Anthropic examples: `claude-sonnet-4-6`, `claude-opus-4-7`, `claude-haiku-4-5-20251001`.
|
|
73
84
|
|
|
74
|
-
`clue-ai semantic-gen` runs semantic AI inside the customer repository CI with
|
|
85
|
+
`npx -y @clue-ai/cli semantic-gen` runs semantic AI inside the customer repository CI with
|
|
75
86
|
the customer-configured AI provider key. Clue receives only the final
|
|
76
87
|
privacy-safe semantic snapshot.
|
|
77
88
|
|
package/bin/clue-cli.mjs
CHANGED
|
@@ -4,6 +4,12 @@ import { createInterface } from "node:readline/promises";
|
|
|
4
4
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
5
5
|
import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
6
6
|
import { commandSpecs } from "../src/command-spec.mjs";
|
|
7
|
+
import {
|
|
8
|
+
CLUE_CLI_BINARY_NAME,
|
|
9
|
+
CLUE_CLI_PACKAGE_NAME,
|
|
10
|
+
CLUE_CLI_RECOMMENDED_PREFIX,
|
|
11
|
+
clueCliCommand,
|
|
12
|
+
} from "../src/cli-invocation.mjs";
|
|
7
13
|
import {
|
|
8
14
|
buildSemanticWorkflowRequestFromFlags,
|
|
9
15
|
runInitTool,
|
|
@@ -13,6 +19,7 @@ import { applyLifecyclePlan } from "../src/lifecycle-init.mjs";
|
|
|
13
19
|
import { runSemanticCi, runSemanticInventory } from "../src/semantic-ci.mjs";
|
|
14
20
|
import { runSetupCheck } from "../src/setup-check.mjs";
|
|
15
21
|
import { runSetupDetect } from "../src/setup-detect.mjs";
|
|
22
|
+
import { buildAiSetupHelp } from "../src/setup-help.mjs";
|
|
16
23
|
import { runSetupPrepare } from "../src/setup-prepare.mjs";
|
|
17
24
|
import { installSetupSkills } from "../src/setup-tool.mjs";
|
|
18
25
|
import {
|
|
@@ -40,6 +47,13 @@ const parseArgs = (argv) => {
|
|
|
40
47
|
|
|
41
48
|
const readJson = async (path) => JSON.parse(await readFile(path, "utf8"));
|
|
42
49
|
|
|
50
|
+
const readPackageVersion = async () => {
|
|
51
|
+
const packageJson = JSON.parse(
|
|
52
|
+
await readFile(new URL("../package.json", import.meta.url), "utf8"),
|
|
53
|
+
);
|
|
54
|
+
return String(packageJson.version);
|
|
55
|
+
};
|
|
56
|
+
|
|
43
57
|
const readTextIfExists = async (path) => {
|
|
44
58
|
try {
|
|
45
59
|
return await readFile(path, "utf8");
|
|
@@ -212,6 +226,15 @@ const readSetupManifest = async ({ repoRoot, manifestPath }) => {
|
|
|
212
226
|
return readJson(resolvedPath);
|
|
213
227
|
};
|
|
214
228
|
|
|
229
|
+
const readSetupManifestIfPresent = async ({ repoRoot, manifestPath }) => {
|
|
230
|
+
try {
|
|
231
|
+
return await readSetupManifest({ repoRoot, manifestPath });
|
|
232
|
+
} catch (error) {
|
|
233
|
+
if (error?.code === "ENOENT") return null;
|
|
234
|
+
throw error;
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
215
238
|
const manifestWatchTargets = (manifest) => {
|
|
216
239
|
const targets = manifest?.lifecycle_verification?.watch_targets;
|
|
217
240
|
if (!Array.isArray(targets) || targets.length === 0) {
|
|
@@ -265,37 +288,10 @@ const maybeProtectEnvironmentGuide = async ({
|
|
|
265
288
|
gitignore_status: "already_ignored",
|
|
266
289
|
};
|
|
267
290
|
}
|
|
268
|
-
|
|
269
|
-
await appendGitignoreEntry({ repoRoot, entry: envFilePath });
|
|
270
|
-
return {
|
|
271
|
-
env_file_path: envFilePath,
|
|
272
|
-
gitignore_status: "added",
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
if (shouldAskQuestions({ flags })) {
|
|
276
|
-
const rl = createInterface({
|
|
277
|
-
input: process.stdin,
|
|
278
|
-
output: process.stdout,
|
|
279
|
-
});
|
|
280
|
-
try {
|
|
281
|
-
const answer = await rl.question(
|
|
282
|
-
`${envFilePath} は秘密情報を含みます。.gitignore に追加しますか? [Y/n] `,
|
|
283
|
-
);
|
|
284
|
-
if (!answer.trim() || /^y(es)?$/i.test(answer.trim())) {
|
|
285
|
-
await appendGitignoreEntry({ repoRoot, entry: envFilePath });
|
|
286
|
-
return {
|
|
287
|
-
env_file_path: envFilePath,
|
|
288
|
-
gitignore_status: "added",
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
} finally {
|
|
292
|
-
rl.close();
|
|
293
|
-
}
|
|
294
|
-
}
|
|
291
|
+
await appendGitignoreEntry({ repoRoot, entry: envFilePath });
|
|
295
292
|
return {
|
|
296
293
|
env_file_path: envFilePath,
|
|
297
|
-
gitignore_status: "
|
|
298
|
-
warning: `${envFilePath} contains secrets. Do not commit it.`,
|
|
294
|
+
gitignore_status: "added",
|
|
299
295
|
};
|
|
300
296
|
};
|
|
301
297
|
|
|
@@ -338,12 +334,12 @@ const buildWatchProducerIds = ({ explicitProducerIds, watchTargets }) =>
|
|
|
338
334
|
]);
|
|
339
335
|
|
|
340
336
|
const checkTargetUrl = async (url) => {
|
|
341
|
-
if (!url) return { checked:
|
|
337
|
+
if (!url) return { checked: true, reachable: false, status: null };
|
|
342
338
|
try {
|
|
343
339
|
const response = await fetch(url, { method: "GET" });
|
|
344
340
|
return {
|
|
345
341
|
checked: true,
|
|
346
|
-
reachable: response.status <
|
|
342
|
+
reachable: response.status >= 200 && response.status < 400,
|
|
347
343
|
status: response.status,
|
|
348
344
|
};
|
|
349
345
|
} catch {
|
|
@@ -551,7 +547,7 @@ const renderWatchTargets = (targetChecks) =>
|
|
|
551
547
|
targetChecks
|
|
552
548
|
.map((target) => {
|
|
553
549
|
const urlStatus = target.urlChecked
|
|
554
|
-
? ` url:${target.urlReachable ? target.urlStatus : "unreachable"}`
|
|
550
|
+
? ` url:${target.urlReachable ? target.urlStatus : (target.urlStatus ?? "unreachable")}`
|
|
555
551
|
: "";
|
|
556
552
|
const lifecycle = target.expectedLifecycle
|
|
557
553
|
.map(
|
|
@@ -595,9 +591,7 @@ const runSetupWatch = async ({ flags, repoRoot = ".", env = process.env }) => {
|
|
|
595
591
|
const manifestPath = String(
|
|
596
592
|
flags.get("manifest") || DEFAULT_SETUP_MANIFEST_PATH,
|
|
597
593
|
);
|
|
598
|
-
const manifest =
|
|
599
|
-
? await readSetupManifest({ repoRoot, manifestPath })
|
|
600
|
-
: null;
|
|
594
|
+
const manifest = await readSetupManifestIfPresent({ repoRoot, manifestPath });
|
|
601
595
|
if (localMode && manifest?.status !== "ready_for_ai") {
|
|
602
596
|
throw new Error(
|
|
603
597
|
`setup-watch --local requires a ready setup manifest at ${manifestPath}`,
|
|
@@ -640,6 +634,11 @@ const runSetupWatch = async ({ flags, repoRoot = ".", env = process.env }) => {
|
|
|
640
634
|
: manifestWatchTargets(manifest),
|
|
641
635
|
env,
|
|
642
636
|
});
|
|
637
|
+
if (!localMode && watchTargets.length === 0) {
|
|
638
|
+
throw new Error(
|
|
639
|
+
"setup-watch requires --watch-targets or .clue/setup-manifest.json lifecycle_verification.watch_targets before setup can be treated as verified",
|
|
640
|
+
);
|
|
641
|
+
}
|
|
643
642
|
const producerIds = buildWatchProducerIds({
|
|
644
643
|
explicitProducerIds: flags.get("producer-ids"),
|
|
645
644
|
watchTargets,
|
|
@@ -745,20 +744,30 @@ const runSetupWatch = async ({ flags, repoRoot = ".", env = process.env }) => {
|
|
|
745
744
|
|
|
746
745
|
const usage = () =>
|
|
747
746
|
[
|
|
747
|
+
"Clue CLI:",
|
|
748
|
+
` npm package: ${CLUE_CLI_PACKAGE_NAME}`,
|
|
749
|
+
` binary: ${CLUE_CLI_BINARY_NAME}`,
|
|
750
|
+
` first-run invocation: ${CLUE_CLI_RECOMMENDED_PREFIX} <command>`,
|
|
751
|
+
` global ${CLUE_CLI_BINARY_NAME} installation is not required`,
|
|
752
|
+
` AI setup help: ${clueCliCommand("help --json")}`,
|
|
753
|
+
"",
|
|
748
754
|
"Usage:",
|
|
749
755
|
" /clue-init",
|
|
750
|
-
"
|
|
751
|
-
"
|
|
752
|
-
"
|
|
753
|
-
"
|
|
754
|
-
"
|
|
755
|
-
"
|
|
756
|
-
"
|
|
757
|
-
"
|
|
758
|
-
"
|
|
759
|
-
"
|
|
760
|
-
"
|
|
761
|
-
"
|
|
756
|
+
` ${clueCliCommand("setup --clue-api-key <key> --clue-api-base-url <url> --project-key <key> --environment dev")}`,
|
|
757
|
+
` ${clueCliCommand("setup-detect --repo .")}`,
|
|
758
|
+
` ${clueCliCommand("semantic-inventory --framework fastapi --backend-root-path backend --repo .")}`,
|
|
759
|
+
` ${clueCliCommand("semantic-agent-skills --output .clue/semantic-agent-skills.json")}`,
|
|
760
|
+
` ${clueCliCommand("semantic-workflow --framework fastapi --backend-root-path backend --repo .")}`,
|
|
761
|
+
` ${clueCliCommand("lifecycle-apply --plan clue-lifecycle-plan.json --repo .")}`,
|
|
762
|
+
` ${clueCliCommand("setup-check --framework fastapi --backend-root-path backend --repo . --target codex")}`,
|
|
763
|
+
` ${clueCliCommand("init --request clue-init-request.json --repo .")}`,
|
|
764
|
+
` ${clueCliCommand("semantic-gen --request clue-semantic-request.json --repo . [--previous-snapshot-file previous.json]")}`,
|
|
765
|
+
` ${clueCliCommand("semantic-gen --request-env CLUE_SEMANTIC_REQUEST_JSON --repo .")}`,
|
|
766
|
+
"",
|
|
767
|
+
"User-operated verification:",
|
|
768
|
+
` ${clueCliCommand("setup-watch --local")}`,
|
|
769
|
+
` ${clueCliCommand("setup-watch --project-key <key> --environment dev --clue-api-base-url <clue-api-base-url> --watch-targets frontend:web[init,identify,set-account,logout,event-sent]=<frontend-url>,backend:api[init,identify,set-account,logout,event-sent]=<backend-url>")}`,
|
|
770
|
+
" setup-watch is for the user running real local services; AI implementation agents must not run it automatically.",
|
|
762
771
|
].join("\n");
|
|
763
772
|
|
|
764
773
|
const renderEnvironmentInstructions = (instructions) => {
|
|
@@ -777,7 +786,24 @@ const renderEnvironmentInstructions = (instructions) => {
|
|
|
777
786
|
|
|
778
787
|
const main = async () => {
|
|
779
788
|
const { command, flags } = parseArgs(process.argv.slice(2));
|
|
780
|
-
if (
|
|
789
|
+
if (
|
|
790
|
+
command === "version" ||
|
|
791
|
+
command === "--version" ||
|
|
792
|
+
flags.has("version")
|
|
793
|
+
) {
|
|
794
|
+
process.stdout.write(`${await readPackageVersion()}\n`);
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
if (
|
|
799
|
+
(command === "help" || command === "--help" || flags.has("help")) &&
|
|
800
|
+
flags.has("json")
|
|
801
|
+
) {
|
|
802
|
+
process.stdout.write(`${JSON.stringify(buildAiSetupHelp(), null, 2)}\n`);
|
|
803
|
+
return;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
if (command === "help" || command === "--help" || flags.has("help")) {
|
|
781
807
|
process.stdout.write(`${usage()}\n`);
|
|
782
808
|
return;
|
|
783
809
|
}
|
|
@@ -806,6 +832,13 @@ const main = async () => {
|
|
|
806
832
|
? flags.get("target")
|
|
807
833
|
: undefined,
|
|
808
834
|
});
|
|
835
|
+
const preEnvironmentFileProtection = flags.has("skills-only")
|
|
836
|
+
? null
|
|
837
|
+
: await maybeProtectEnvironmentGuide({
|
|
838
|
+
repoRoot,
|
|
839
|
+
envFilePath: ".env.clue",
|
|
840
|
+
flags,
|
|
841
|
+
});
|
|
809
842
|
const preparation = flags.has("skills-only")
|
|
810
843
|
? {
|
|
811
844
|
status: "skipped",
|
|
@@ -822,11 +855,15 @@ const main = async () => {
|
|
|
822
855
|
environment: flags.get("environment"),
|
|
823
856
|
},
|
|
824
857
|
});
|
|
825
|
-
const environmentFileProtection =
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
858
|
+
const environmentFileProtection =
|
|
859
|
+
preEnvironmentFileProtection?.env_file_path ===
|
|
860
|
+
preparation.environment_instructions?.env_file_path
|
|
861
|
+
? preEnvironmentFileProtection
|
|
862
|
+
: await maybeProtectEnvironmentGuide({
|
|
863
|
+
repoRoot,
|
|
864
|
+
envFilePath: preparation.environment_instructions?.env_file_path,
|
|
865
|
+
flags,
|
|
866
|
+
});
|
|
830
867
|
if (environmentFileProtection) {
|
|
831
868
|
preparation.environment_file_protection = environmentFileProtection;
|
|
832
869
|
}
|
|
@@ -971,7 +1008,9 @@ const main = async () => {
|
|
|
971
1008
|
const agentSkillsPath = flags.get("agent-skills-file");
|
|
972
1009
|
const agentSkills =
|
|
973
1010
|
typeof agentSkillsPath === "string"
|
|
974
|
-
? validateSemanticAgentSkillBundle(
|
|
1011
|
+
? validateSemanticAgentSkillBundle(
|
|
1012
|
+
await readJson(resolve(agentSkillsPath)),
|
|
1013
|
+
)
|
|
975
1014
|
: undefined;
|
|
976
1015
|
const result = await runSemanticCi({
|
|
977
1016
|
repoRoot,
|
package/package.json
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const CLUE_CLI_PACKAGE_NAME = "@clue-ai/cli";
|
|
2
|
+
export const CLUE_CLI_BINARY_NAME = "clue-ai";
|
|
3
|
+
export const CLUE_CLI_RECOMMENDED_PREFIX = `npx -y ${CLUE_CLI_PACKAGE_NAME}`;
|
|
4
|
+
export const CLUE_CLI_LEGACY_NPX_PREFIX = `npx ${CLUE_CLI_PACKAGE_NAME}`;
|
|
5
|
+
|
|
6
|
+
export const CLUE_CLI_INVOCATION_CONTRACT = {
|
|
7
|
+
package_name: CLUE_CLI_PACKAGE_NAME,
|
|
8
|
+
binary_name: CLUE_CLI_BINARY_NAME,
|
|
9
|
+
recommended_prefix: CLUE_CLI_RECOMMENDED_PREFIX,
|
|
10
|
+
global_binary_required: false,
|
|
11
|
+
version_check_command: `${CLUE_CLI_RECOMMENDED_PREFIX} --version`,
|
|
12
|
+
help_command: `${CLUE_CLI_RECOMMENDED_PREFIX} --help`,
|
|
13
|
+
ai_help_command: `${CLUE_CLI_RECOMMENDED_PREFIX} help --json`,
|
|
14
|
+
rule: "Use the recommended_prefix for Clue CLI commands. Do not discover or require a global clue-ai binary; missing global clue-ai is normal. For AI setup scope and responsibility rules, run ai_help_command.",
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const clueCliCommand = (args) =>
|
|
18
|
+
`${CLUE_CLI_RECOMMENDED_PREFIX} ${args}`;
|
|
19
|
+
|
|
20
|
+
export const SEMANTIC_GEN_WORKFLOW_COMMAND = clueCliCommand(
|
|
21
|
+
"semantic-gen --request-env CLUE_SEMANTIC_REQUEST_JSON --repo .",
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
export const LEGACY_SEMANTIC_GEN_WORKFLOW_COMMAND = `${CLUE_CLI_LEGACY_NPX_PREFIX} semantic-gen --request-env CLUE_SEMANTIC_REQUEST_JSON --repo .`;
|
|
25
|
+
|
|
26
|
+
export const SEMANTIC_GEN_WORKFLOW_COMPATIBLE_COMMANDS = [
|
|
27
|
+
SEMANTIC_GEN_WORKFLOW_COMMAND,
|
|
28
|
+
LEGACY_SEMANTIC_GEN_WORKFLOW_COMMAND,
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
export const workflowHasCompatibleSemanticGenCommand = (workflow) =>
|
|
32
|
+
SEMANTIC_GEN_WORKFLOW_COMPATIBLE_COMMANDS.some((command) =>
|
|
33
|
+
workflow.includes(command),
|
|
34
|
+
);
|
package/src/command-spec.mjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { CLUE_CLI_INVOCATION_CONTRACT } from "./cli-invocation.mjs";
|
|
2
|
+
|
|
1
3
|
export const CLUE_INIT_COMMAND_NAME = "/clue-init";
|
|
2
4
|
|
|
3
5
|
export const REQUIRED_SECRET_NAMES = [
|
|
@@ -24,6 +26,7 @@ export const CLUE_INIT_COMMAND = {
|
|
|
24
26
|
required_fields: CLUE_INIT_COMMAND_FIELDS,
|
|
25
27
|
required_secret_names: REQUIRED_SECRET_NAMES,
|
|
26
28
|
required_variable_names: REQUIRED_VARIABLE_NAMES,
|
|
29
|
+
cli_invocation: CLUE_CLI_INVOCATION_CONTRACT,
|
|
27
30
|
};
|
|
28
31
|
|
|
29
32
|
export const commandSpecs = [CLUE_INIT_COMMAND];
|
package/src/init-tool.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { buildInitReport, validateInitRequest } from "./contracts.mjs";
|
|
4
|
+
import { SEMANTIC_GEN_WORKFLOW_COMMAND } from "./cli-invocation.mjs";
|
|
4
5
|
import {
|
|
5
6
|
applyLifecyclePlan,
|
|
6
7
|
planLifecycleInsertions,
|
|
@@ -158,7 +159,7 @@ jobs:
|
|
|
158
159
|
CLUE_SEMANTIC_REQUEST_JSON: |
|
|
159
160
|
${indentMultiline(workflowRequestPayload(request), 12)}
|
|
160
161
|
run: |
|
|
161
|
-
|
|
162
|
+
${SEMANTIC_GEN_WORKFLOW_COMMAND}
|
|
162
163
|
`;
|
|
163
164
|
|
|
164
165
|
export const writeSemanticWorkflow = async ({ repoRoot, request }) => {
|