@clue-ai/cli 0.0.9 → 0.0.11

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 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 . --output .clue/semantic-routes.json
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
- generates `.clue/semantic-request.runtime.json` only inside CI and then runs
28
- `clue-ai semantic-gen`. Do not commit runtime semantic request files to client
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
- The AI prompt should use those generated artifacts as inputs and should not
40
- hand-edit route inventory or semantic CI workflow files.
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, no broad tracking, and no
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
- if (flags.has("yes")) {
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: "not_ignored",
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: false, reachable: true, status: null };
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 < 500,
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 = localMode
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
- " clue-ai setup --clue-api-key <key> --clue-api-base-url <url> --project-key <key> --environment dev",
751
- " clue-ai setup-detect --repo .",
752
- " clue-ai semantic-inventory --framework fastapi --backend-root-path backend --repo . --output .clue/semantic-routes.json",
753
- " clue-ai semantic-agent-skills --output .clue/semantic-agent-skills.json",
754
- " clue-ai semantic-workflow --framework fastapi --backend-root-path backend --repo .",
755
- " clue-ai lifecycle-apply --plan clue-lifecycle-plan.json --repo .",
756
- " clue-ai setup-check --framework fastapi --backend-root-path backend --repo .",
757
- " clue-ai setup-watch --local",
758
- " 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,logout,event-sent]=<frontend-url>,backend:api[init,identify,set-account,logout,event-sent]=<backend-url>",
759
- " clue-ai init --request clue-init-request.json --repo .",
760
- " clue-ai semantic-gen --request clue-semantic-request.json --repo . [--previous-snapshot-file previous.json]",
761
- " clue-ai semantic-gen --request-env CLUE_SEMANTIC_REQUEST_JSON --repo .",
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 (command === "help" || flags.has("help")) {
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 = await maybeProtectEnvironmentGuide({
826
- repoRoot,
827
- envFilePath: preparation.environment_instructions?.env_file_path,
828
- flags,
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(await readJson(resolve(agentSkillsPath)))
1011
+ ? validateSemanticAgentSkillBundle(
1012
+ await readJson(resolve(agentSkillsPath)),
1013
+ )
975
1014
  : undefined;
976
1015
  const result = await runSemanticCi({
977
1016
  repoRoot,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clue-ai/cli",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "clue-ai": "bin/clue-cli.mjs"
@@ -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
+ );
@@ -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
- npx @clue-ai/cli semantic-gen --request-env CLUE_SEMANTIC_REQUEST_JSON --repo .
162
+ ${SEMANTIC_GEN_WORKFLOW_COMMAND}
162
163
  `;
163
164
 
164
165
  export const writeSemanticWorkflow = async ({ repoRoot, request }) => {