@clue-ai/cli 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,170 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { dirname, join, resolve } from "node:path";
3
+ import {
4
+ buildSemanticWorkflowRequestFromFlags,
5
+ writeSemanticWorkflow,
6
+ } from "./init-tool.mjs";
7
+ import { runSetupDetect } from "./setup-detect.mjs";
8
+
9
+ const DEFAULT_SETUP_MANIFEST_PATH = ".clue/setup-manifest.json";
10
+
11
+ const writeJson = async ({ repoRoot, path, value }) => {
12
+ const absolutePath = join(resolve(repoRoot), path);
13
+ await mkdir(dirname(absolutePath), { recursive: true });
14
+ await writeFile(absolutePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
15
+ };
16
+
17
+ const firstCandidateOrBlocker = (detection) => {
18
+ if (!detection.detected || detection.candidates.length === 0) {
19
+ return {
20
+ candidate: null,
21
+ blockers: detection.blockers.length
22
+ ? detection.blockers
23
+ : [
24
+ {
25
+ code: "NO_SETUP_CANDIDATE",
26
+ message: "No setup candidate was mechanically detected.",
27
+ },
28
+ ],
29
+ };
30
+ }
31
+ return {
32
+ candidate: detection.candidates[0],
33
+ blockers: [],
34
+ };
35
+ };
36
+
37
+ const DEFAULT_SETUP_LIFECYCLE = [
38
+ "init",
39
+ "identify",
40
+ "set-account",
41
+ "logout",
42
+ "event-sent",
43
+ ];
44
+
45
+ const buildWatchTargets = (detection, fallbackCandidate) => {
46
+ const frontendServices = Array.isArray(detection.services?.frontend)
47
+ ? detection.services.frontend
48
+ : [];
49
+ const backendServices = Array.isArray(detection.services?.backend)
50
+ ? detection.services.backend
51
+ : [
52
+ {
53
+ kind: "backend",
54
+ framework: fallbackCandidate.framework,
55
+ root_path: fallbackCandidate.backend_root_path,
56
+ service_key: fallbackCandidate.service_key,
57
+ local_url_candidates: [],
58
+ },
59
+ ];
60
+ return [...frontendServices, ...backendServices].map((service) => ({
61
+ kind: service.kind,
62
+ framework: service.framework,
63
+ root_path: service.root_path,
64
+ service_key: service.service_key,
65
+ producer_id: service.service_key,
66
+ expected_lifecycle: DEFAULT_SETUP_LIFECYCLE,
67
+ local_url_candidates: service.local_url_candidates ?? [],
68
+ url_env_name:
69
+ service.kind === "frontend"
70
+ ? `CLUE_LOCAL_${service.service_key.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}_FRONTEND_URL`
71
+ : `CLUE_LOCAL_${service.service_key.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}_BACKEND_URL`,
72
+ }));
73
+ };
74
+
75
+ export const runSetupPrepare = async ({
76
+ repoRoot,
77
+ target,
78
+ skillRoot,
79
+ setupManifestPath = DEFAULT_SETUP_MANIFEST_PATH,
80
+ }) => {
81
+ const resolvedRepoRoot = resolve(repoRoot ?? ".");
82
+ const detection = await runSetupDetect({ repoRoot: resolvedRepoRoot });
83
+ const { candidate, blockers } = firstCandidateOrBlocker(detection);
84
+ if (!candidate) {
85
+ const manifest = {
86
+ status: "blocked",
87
+ target,
88
+ skill_root: skillRoot,
89
+ blockers,
90
+ detection,
91
+ ai_next_scope: "blocked_until_backend_routes_are_detected",
92
+ machine_owned_artifacts: [],
93
+ ai_owned_workstreams: [
94
+ "sdk_lifecycle_implementation_after_blockers_are_resolved",
95
+ ],
96
+ };
97
+ await writeJson({
98
+ repoRoot: resolvedRepoRoot,
99
+ path: setupManifestPath,
100
+ value: manifest,
101
+ });
102
+ return manifest;
103
+ }
104
+
105
+ const request = buildSemanticWorkflowRequestFromFlags({
106
+ framework: candidate.framework,
107
+ backendRootPath: candidate.backend_root_path,
108
+ serviceKey: candidate.service_key,
109
+ });
110
+ const workflow = await writeSemanticWorkflow({
111
+ repoRoot: resolvedRepoRoot,
112
+ request,
113
+ });
114
+
115
+ const manifest = {
116
+ status: "ready_for_ai",
117
+ target,
118
+ skill_root: skillRoot,
119
+ detected: {
120
+ framework: candidate.framework,
121
+ backend_root_path: candidate.backend_root_path,
122
+ service_key: candidate.service_key,
123
+ },
124
+ service_identity: {
125
+ canonical_field: "service_key",
126
+ backend_env_name: "CLUE_SERVICE_KEY",
127
+ frontend_env_name: "NEXT_PUBLIC_CLUE_SERVICE_KEY",
128
+ producer_id_derivation: "producer_id defaults to service_key",
129
+ },
130
+ lifecycle_verification: {
131
+ watch_target_format:
132
+ "frontend:<service-key>[init,identify,set-account,logout,event-sent]=<frontend-url>,backend:<service-key>[init,identify,set-account,logout,event-sent]=<backend-url>",
133
+ rule:
134
+ "setup-watch --local uses the structured watch_targets below. Lifecycle checks are fixed for setup verification and are evaluated per service_key.",
135
+ watch_targets: buildWatchTargets(detection, candidate),
136
+ },
137
+ artifacts: {
138
+ ci_workflow_path: workflow.ci_workflow_path,
139
+ setup_manifest_path: setupManifestPath,
140
+ runtime_request_committed: false,
141
+ },
142
+ machine_owned_artifacts: [workflow.ci_workflow_path, setupManifestPath],
143
+ ai_must_not_edit: [workflow.ci_workflow_path],
144
+ ai_owned_workstreams: ["sdk_lifecycle_implementation"],
145
+ required_final_check: {
146
+ command:
147
+ `npx @clue-ai/cli setup-check --framework ${candidate.framework} ` +
148
+ `--backend-root-path ${candidate.backend_root_path} --repo . --target ${target} --require-sdk-lifecycle`,
149
+ },
150
+ required_env_names: [
151
+ "NEXT_PUBLIC_CLUE_SERVICE_KEY",
152
+ "NEXT_PUBLIC_CLUE_PROJECT_KEY",
153
+ "NEXT_PUBLIC_CLUE_ENVIRONMENT",
154
+ "NEXT_PUBLIC_CLUE_INGEST_ENDPOINT",
155
+ "CLUE_SERVICE_KEY",
156
+ "CLUE_API_KEY",
157
+ "AI_PROVIDER_API_KEY",
158
+ "CLUE_PROJECT_KEY",
159
+ "CLUE_ENVIRONMENT",
160
+ "CLUE_API_BASE_URL",
161
+ "CLUE_AI_MODEL",
162
+ ],
163
+ };
164
+ await writeJson({
165
+ repoRoot: resolvedRepoRoot,
166
+ path: setupManifestPath,
167
+ value: manifest,
168
+ });
169
+ return manifest;
170
+ };
@@ -3,139 +3,256 @@ import { join, resolve } from "node:path";
3
3
  import readline from "node:readline/promises";
4
4
 
5
5
  const SKILL_NAMES = [
6
- "clue-route-semantic-snapshot",
7
- "clue-semantic-ci",
8
- "clue-sdk-instrumentation",
9
- "clue-setup-audit",
10
- "clue-local-verification",
11
- "clue-setup-report",
6
+ "clue-setup-orchestrator",
7
+ "clue-route-semantic-snapshot",
8
+ "clue-semantic-ci",
9
+ "clue-sdk-instrumentation",
10
+ "clue-setup-audit",
11
+ "clue-local-verification",
12
+ "clue-setup-report",
12
13
  ];
13
14
 
14
15
  const TARGETS = new Set(["codex", "claude_code"]);
15
16
 
16
17
  const TARGET_SKILL_ROOTS = {
17
- codex: [".agents", "skills"],
18
- claude_code: [".claude", "skills"],
18
+ codex: [".agents", "skills"],
19
+ claude_code: [".claude", "skills"],
19
20
  };
20
21
 
21
22
  const normalizeTarget = (target) => {
22
- const normalized = String(target ?? "").trim().toLowerCase().replace(/[\s-]+/g, "_");
23
- if (!TARGETS.has(normalized)) {
24
- throw new Error("target must be codex or claude_code");
25
- }
26
- return normalized;
23
+ const normalized = String(target ?? "")
24
+ .trim()
25
+ .toLowerCase()
26
+ .replace(/[\s-]+/g, "_");
27
+ if (!TARGETS.has(normalized)) {
28
+ throw new Error("AIツールは codex または claude_code を指定してください");
29
+ }
30
+ return normalized;
27
31
  };
28
32
 
29
33
  const skillBody = (name) => {
30
- const descriptions = {
31
- "clue-route-semantic-snapshot":
32
- "Use when analyzing backend routes, handlers, controllers, or endpoints to create privacy-safe Clue semantic snapshots.",
33
- "clue-semantic-ci":
34
- "Use when adding or updating Clue semantic snapshot CI for this repository.",
35
- "clue-sdk-instrumentation":
36
- "Use when adding ClueInit, ClueIdentify, ClueSetAccount, and ClueLogout lifecycle calls to a customer repository.",
37
- "clue-setup-audit":
38
- "Use when reviewing Clue setup changes for missing lifecycle calls, unsafe instrumentation, leaked secrets, or bad insertion points.",
39
- "clue-local-verification":
40
- "Use when verifying local Clue setup artifacts before checking event delivery in the Clue setup screen.",
41
- "clue-setup-report":
42
- "Use when producing the final Clue setup report with changed files, blockers, env names, and next steps.",
43
- };
34
+ const descriptions = {
35
+ "clue-setup-orchestrator":
36
+ "Use first when running the full Clue setup so one execution agent per implementation workstream and multiple monitoring agents coordinate separate setup phases.",
37
+ "clue-route-semantic-snapshot":
38
+ "Use when checking backend route coverage and semantic snapshot readiness without hand-authoring generated snapshot files.",
39
+ "clue-semantic-ci":
40
+ "Use when adding or updating Clue semantic snapshot CI for this repository.",
41
+ "clue-sdk-instrumentation":
42
+ "Use when adding ClueInit, ClueIdentify, ClueSetAccount, and ClueLogout lifecycle calls to a customer repository.",
43
+ "clue-setup-audit":
44
+ "Use when reviewing Clue setup changes for missing lifecycle calls, unsafe instrumentation, leaked secrets, or bad insertion points.",
45
+ "clue-local-verification":
46
+ "Use when verifying local Clue setup artifacts before checking event delivery in the Clue setup screen.",
47
+ "clue-setup-report":
48
+ "Use when producing the final Clue setup report with changed files, blockers, env names, and next steps.",
49
+ };
44
50
 
45
- const steps = {
46
- "clue-route-semantic-snapshot": [
47
- "Inspect only allowed source paths.",
48
- "Identify route, handler, controller, and endpoint behavior from privacy-safe evidence.",
49
- "Create semantic snapshot inputs without raw source, secrets, prompts, or completions.",
50
- "Report unresolved routes as blockers instead of guessing.",
51
- ],
52
- "clue-semantic-ci": [
53
- "Create or update `.github/workflows/clue-semantic-snapshot.yml`.",
54
- "Use `npx @clue-ai/cli semantic-ci --request .clue/semantic-request.runtime.json --repo .`.",
55
- "Reference GitHub Secrets and Variables by name only.",
56
- "Do not print or commit secret values.",
57
- ],
58
- "clue-sdk-instrumentation": [
59
- "Find the app/bootstrap entrypoint and add ClueInit only when the location is clear.",
60
- "Find login success handling and add ClueIdentify only when the user identity is available.",
61
- "Find account, workspace, organization, or tenant resolution and add ClueSetAccount only when the subject is available.",
62
- "Find logout/sign-out completion and add ClueLogout only when the session reset point is clear.",
63
- "Skip unclear lifecycle points and report blockers.",
64
- ],
65
- "clue-setup-audit": [
66
- "Review changed files line by line.",
67
- "Reject broad ClueTrack instrumentation and DOM clue tags.",
68
- "Confirm no project key, API key, secret, or env value appears in diff or report.",
69
- "Confirm lifecycle insertions are minimal and reviewable.",
70
- ],
71
- "clue-local-verification": [
72
- "Confirm generated skill files exist.",
73
- "Confirm workflow files and SDK lifecycle imports/calls exist when those phases have run.",
74
- "Confirm only env names are reported.",
75
- "Leave event delivery verification to the Clue setup screen.",
76
- ],
77
- "clue-setup-report": [
78
- "Summarize changed files.",
79
- "List completed setup phases.",
80
- "List blockers with exact file or environment names when available.",
81
- "List required env names without values.",
82
- "State that commit and push were not performed.",
83
- ],
84
- };
51
+ const steps = {
52
+ "clue-setup-orchestrator": [
53
+ "Use one execution agent per implementation workstream.",
54
+ "Each execution agent owns exactly one workstream and its tests.",
55
+ "Required execution agents: SDK Lifecycle Execution Agent, Semantic Snapshot Readiness Execution Agent, and Semantic Snapshot CI Execution Agent.",
56
+ "Run execution agents in parallel only when file ownership does not conflict; otherwise run them sequentially with monitor gates between workstreams.",
57
+ "Use multiple monitoring agents for read-only checks, or named review passes if subagents are unavailable.",
58
+ "The initial `clue-ai setup` command already performs repository discovery, semantic CI workflow generation, and setup manifest generation when backend routes can be detected.",
59
+ "Before implementation, read `.clue/setup-manifest.json` and treat it as the mechanical setup source of truth.",
60
+ "If `.clue/setup-manifest.json` has status `blocked`, stop and report its blockers instead of guessing.",
61
+ "Treat only semantic snapshot readiness, semantic snapshot CI, and SDK lifecycle implementation as implementation workstreams with execution agents.",
62
+ "Before each workstream, read and apply the matching Clue setup skill.",
63
+ "After each implementation workstream, run a monitoring check with `clue-setup-audit` before continuing.",
64
+ "For final local verification, read and apply `clue-local-verification`.",
65
+ "For the final report, read and apply `clue-setup-report`.",
66
+ "Do not continue past P0/P1 monitoring findings until fixed or reported as blocked.",
67
+ ],
68
+ "clue-route-semantic-snapshot": [
69
+ "Use this skill as the source of truth for semantic snapshot readiness and route coverage verification.",
70
+ "Do not hand-author semantic snapshot content files.",
71
+ "Do not create or commit `.clue/semantic-request.runtime.json`; the semantic CI request must be passed through the generated workflow environment instead of a repository file.",
72
+ "Keep route coverage/readiness checks separate from CI workflow creation and SDK lifecycle implementation.",
73
+ "Do not create CI workflow files or SDK lifecycle calls from this skill.",
74
+ "Do not create or commit `.clue/semantic-routes.json`; route inventory is dynamic and must be recomputed mechanically by `clue-ai semantic-inventory`, `clue-ai setup-check`, or `clue-ai semantic-ci`.",
75
+ "If route inventory must be inspected locally, run `npx @clue-ai/cli semantic-inventory --framework <framework> --backend-root-path <path> --repo .` and review stdout instead of writing a repo file.",
76
+ "Inspect only allowed source paths.",
77
+ "Identify the backend framework, backend root path, route files, controllers, handlers, and route declaration patterns from privacy-safe evidence.",
78
+ "Run `npx @clue-ai/cli semantic-inventory --framework <framework> --backend-root-path <path> --repo .` whenever possible to verify route discovery without AI or secrets.",
79
+ "If `npx` cannot be used in the current environment, use the local `clue-ai semantic-inventory` command equivalent.",
80
+ "Verify that every API route can be discovered from the selected backend root path and that unsupported frameworks are reported as blockers.",
81
+ "The semantic snapshot CI command must mechanically enumerate operation_source_key, method, path_template, route fingerprints, and privacy-safe evidence before AI interpretation.",
82
+ "AI interpretation may summarize each mechanically discovered route, but it must not create missing routes or operation_source_key values.",
83
+ "The expected generated snapshot structure includes route entries with operation_source_key, method/path_template when available, route_summary, route_confidence, confidence_reason, and source_evidence_refs.",
84
+ "The expected generated snapshot structure includes layer_evidence for data effects, side effects, validation, permissions, failures, and component fingerprints when available.",
85
+ "The expected generated snapshot structure includes operation_effects only when target object evidence and domain behavior evidence are sufficient.",
86
+ "The expected generated snapshot structure preserves unresolved_operation_effects with missing_context instead of fabricating unknown operation effects.",
87
+ "Report route coverage gaps, unsupported backend frameworks, and unclear backend roots as blockers instead of guessing.",
88
+ ],
89
+ "clue-semantic-ci": [
90
+ "Use this skill as the source of truth for semantic snapshot CI workflow format.",
91
+ "Keep CI workflow creation separate from route coverage/readiness checks and SDK lifecycle implementation.",
92
+ "Do not author semantic snapshot content, runtime request files, or SDK lifecycle calls from this skill.",
93
+ "Treat `.github/workflows/clue-semantic-snapshot.yml` as a machine-owned artifact generated by `clue-ai setup`; do not hand-edit it.",
94
+ "Create or update `.github/workflows/clue-semantic-snapshot.yml` only by running `npx @clue-ai/cli semantic-workflow --framework <framework> --backend-root-path <path> --repo .` when it must be refreshed.",
95
+ "If `npx` cannot be used in the current environment, use the local `clue-ai semantic-workflow` command equivalent instead of hand-writing the workflow.",
96
+ "The workflow must pass `CLUE_SEMANTIC_REQUEST_JSON` through the workflow environment and then call `npx @clue-ai/cli semantic-ci --request-env CLUE_SEMANTIC_REQUEST_JSON --repo .`.",
97
+ "Do not create, commit, or stage `.clue/semantic-request.runtime.json` in the customer repository.",
98
+ "The workflow must not send GitHub actor, triggering_actor, sender, repository owner, repository name, or default branch to Clue.",
99
+ "The workflow should send only repository id, commit sha, workflow run id, project key variable, service key, framework, source path allowlist, source path denylist, Clue API base URL variable, and AI model variable.",
100
+ "Use minimal GitHub permissions and checkout without persisted credentials when generating the workflow.",
101
+ "Reference GitHub Secrets and Variables by name only.",
102
+ "Required secrets are `CLUE_API_KEY` and `AI_PROVIDER_API_KEY`.",
103
+ "Required variables are `CLUE_PROJECT_KEY`, `CLUE_ENVIRONMENT`, `CLUE_API_BASE_URL`, and optionally `CLUE_AI_MODEL`.",
104
+ "Do not print or commit secret values.",
105
+ ],
106
+ "clue-sdk-instrumentation": [
107
+ "Use this skill as the source of truth for Clue SDK lifecycle implementation.",
108
+ "Keep SDK lifecycle implementation separate from semantic snapshot and CI workflow work.",
109
+ "Do not create semantic snapshot content or semantic snapshot CI workflow files from this skill.",
110
+ "Do not create no-op wrappers around nonexistent `window.Clue*` globals or local placeholder functions.",
111
+ "Lifecycle calls must resolve to real Clue SDK imports or a real repository adapter that forwards to the Clue SDK.",
112
+ "Every Clue lifecycle call must be failure-isolated with try/catch, try/except, `.catch`, or an explicit safe Clue helper so Clue failure never stops the host service.",
113
+ "Never await a Clue lifecycle call in a way that can block login, logout, account selection, request handling, page rendering, or API responses.",
114
+ "Add or report the required SDK dependency instead of fabricating lifecycle APIs.",
115
+ "When lifecycle edits are clear, write an exact replacement plan to a temporary local JSON file and apply it with `npx @clue-ai/cli lifecycle-apply --plan <plan-file> --repo .`.",
116
+ "If `npx` cannot be used in the current environment, use the local `clue-ai lifecycle-apply` command equivalent instead of manually applying the exact replacements.",
117
+ "Delete the temporary lifecycle plan file after applying it unless the user explicitly asks to keep it for review.",
118
+ "Use environment variable names for Clue configuration values; do not paste project keys or API keys into code.",
119
+ "For browser code, use `NEXT_PUBLIC_CLUE_PROJECT_KEY`, `NEXT_PUBLIC_CLUE_ENVIRONMENT`, and `NEXT_PUBLIC_CLUE_INGEST_ENDPOINT`.",
120
+ "For FastAPI code, add `clue-fastapi-sdk` to the backend dependency file when missing, import `clue_init_fastapi` plus `ClueIdentify`, `ClueSetAccount`, and `ClueLogout` where needed, and use `CLUE_PROJECT_KEY`, `CLUE_ENVIRONMENT`, `CLUE_API_KEY`, and `CLUE_INGEST_ENDPOINT`.",
121
+ "Use `CLUE_SERVICE_KEY` as the canonical local service identifier. Do not ask the user to manage a separate producer id; SDKs should send producer id as the service key for setup verification compatibility.",
122
+ "For frontend code, pass `serviceKey: process.env.NEXT_PUBLIC_CLUE_SERVICE_KEY` to `ClueInit`. Do not require a separate `NEXT_PUBLIC_CLUE_PRODUCER_ID` unless the repository already has one for compatibility.",
123
+ "For Django code, add `clue-django-sdk` to the backend dependency file when missing and use the Django SDK lifecycle helpers.",
124
+ "For other backend frameworks, use the matching Clue backend SDK if one exists; if no backend SDK exists, report a blocker instead of silently frontend-only setup.",
125
+ "Do not send raw email, raw person names, tokens, workspace names, organization names, or tenant names as lifecycle traits unless the repository already has an explicit Clue privacy policy allowing them.",
126
+ "Prefer stable ids and non-PII booleans/counts for ClueIdentify and ClueSetAccount traits.",
127
+ "Find the app/bootstrap entrypoint and add ClueInit only when the location is clear.",
128
+ "Place ClueInit in a stable app bootstrap, SDK adapter, or client singleton; do not place ClueInit inside React component lifecycle hooks, page components, sidebars, login/register success callbacks, or other paths that can run repeatedly.",
129
+ "If the repository needs lifecycle calls from UI hooks, import a shared initialized Clue adapter instead of calling ClueInit again.",
130
+ "Find every clear frontend and backend login success path and add ClueIdentify to every one when the user identity is available.",
131
+ "Find every clear frontend and backend account, workspace, organization, or tenant resolution path and add ClueSetAccount to every one when the subject is available.",
132
+ "Find every clear frontend and backend logout/sign-out/session reset completion path and add ClueLogout to every one when the reset point is clear.",
133
+ "Skip unclear lifecycle points and report blockers.",
134
+ ],
135
+ "clue-setup-audit": [
136
+ "Act as a read-only monitoring agent, not the execution agent.",
137
+ "Check one completed workstream at a time and report P0/P1 issues before more implementation continues.",
138
+ "Review changed files line by line.",
139
+ "Verify semantic snapshot, semantic CI, and SDK lifecycle responsibilities did not bleed into each other.",
140
+ "Reject hand-authored semantic snapshot content and runtime request files.",
141
+ "Reject semantic CI workflows that were not generated by or equivalent to `clue-ai semantic-workflow`.",
142
+ "Reject semantic CI workflows that send GitHub actor, triggering_actor, sender, repository owner, repository name, or default branch to Clue.",
143
+ "Reject no-op lifecycle wrappers or lifecycle calls that do not resolve to a real Clue SDK import.",
144
+ "Reject backend setup when backend routes exist but no backend Clue SDK dependency/import/init was added.",
145
+ "Reject lifecycle calls that are not failure-isolated; Clue failure must never stop the host service.",
146
+ "Reject setup that covers only one login path when multiple login success paths are clearly present.",
147
+ "Reject ClueInit inside React component lifecycle hooks, page components, sidebars, login/register success callbacks, or any repeated user interaction path.",
148
+ "Reject broad ClueTrack instrumentation and DOM clue tags.",
149
+ "Confirm no project key, API key, secret, or env value appears in diff or report.",
150
+ "Confirm lifecycle insertions are minimal and reviewable.",
151
+ ],
152
+ "clue-local-verification": [
153
+ "Act as a read-only monitoring agent for local verification evidence.",
154
+ "Verify each workstream independently before the final setup report.",
155
+ "Confirm generated skill files exist.",
156
+ "Confirm workflow files and SDK lifecycle imports/calls exist when those phases have run.",
157
+ "Confirm backend routes have a backend Clue SDK dependency/import/init when a backend exists.",
158
+ "Confirm `.github/workflows/clue-semantic-snapshot.yml` calls `npx @clue-ai/cli semantic-ci --request-env CLUE_SEMANTIC_REQUEST_JSON`.",
159
+ "Confirm the semantic workflow does not send GitHub actor, triggering_actor, sender, repository owner, repository name, or default branch to Clue.",
160
+ "Confirm `.clue/semantic-request.runtime.json` is not created, committed, or staged.",
161
+ "Run `npx @clue-ai/cli setup-check --framework <framework> --backend-root-path <path> --repo . --target <codex|claude_code> --require-sdk-lifecycle` when possible.",
162
+ "For interactive local verification, run `npx @clue-ai/cli setup-watch --project-key <project-key> --environment <environment> --clue-api-base-url <clue-api-base-url> --watch-targets frontend:<service-key>[init,identify,set-account,event-sent]=<frontend-url>,backend:<service-key>[init,identify,set-account,logout,event-sent]=<backend-url>` and operate every local frontend/backend service until all expected checks pass.",
163
+ "Only include lifecycle checks that the implementation ownership plan expects for that service. If a service emits an undeclared lifecycle event, treat it as a possible duplicate instrumentation issue.",
164
+ "Never assume localhost ports. Ask the repository scripts, env examples, or the running service output for the actual frontend/backend URLs.",
165
+ "If `npx` cannot be used in the current environment, use the local `clue-ai setup-check` command equivalent.",
166
+ "Confirm only env names are reported.",
167
+ "Leave event delivery verification to the Clue setup screen.",
168
+ ],
169
+ "clue-setup-report": [
170
+ "Use this skill only after execution and monitoring passes are finished.",
171
+ "Summarize changed files.",
172
+ "List completed setup phases.",
173
+ "List skills used for each workstream.",
174
+ "List execution agent and monitoring agents, or named review passes if subagents were unavailable.",
175
+ "List blockers with exact file or environment names when available.",
176
+ "List required env names without values.",
177
+ "List P0/P1 monitoring findings and fixes.",
178
+ "State that commit and push were not performed.",
179
+ ],
180
+ };
85
181
 
86
- return [
87
- "---",
88
- `name: ${name}`,
89
- `description: ${descriptions[name]}`,
90
- "---",
91
- "",
92
- "# Rules",
93
- "",
94
- "- Do not expose project keys, API keys, secrets, tokens, or environment variable values.",
95
- "- Do not commit or push changes.",
96
- "- Prefer existing repository patterns and minimal diffs.",
97
- "- If evidence is unclear, report a blocker instead of guessing.",
98
- "",
99
- "# Workflow",
100
- "",
101
- ...steps[name].map((step, index) => `${index + 1}. ${step}`),
102
- "",
103
- ].join("\n");
182
+ return [
183
+ "---",
184
+ `name: ${name}`,
185
+ `description: ${descriptions[name]}`,
186
+ "---",
187
+ "",
188
+ "# Rules",
189
+ "",
190
+ "- For full Clue setup, use one execution agent per implementation workstream and multiple monitoring agents for read-only checks.",
191
+ "- The full setup must start with `clue-setup-orchestrator`.",
192
+ "- Each execution agent owns exactly one workstream; monitoring agents review one workstream at a time and report P0/P1 issues.",
193
+ "- Do not continue past a P0/P1 monitoring finding until it is fixed or explicitly reported as blocked.",
194
+ "- If subagents are unavailable, run the same structure as separate named review passes and say so in the final report.",
195
+ "- Do not expose project keys, API keys, secrets, tokens, or environment variable values.",
196
+ "- Do not ask the user to paste secret values.",
197
+ "- Do not read `.env`, `.env.*`, secret files, logs, dumps, build output, coverage output, `node_modules`, vendor directories, dependency directories, or dependency output.",
198
+ "- Report only environment variable names, never values.",
199
+ "- Do not commit or push changes.",
200
+ "- Prefer existing repository patterns and minimal diffs.",
201
+ "- If evidence is unclear, report a blocker instead of guessing.",
202
+ "- Do not merge semantic snapshot, semantic CI, SDK lifecycle, audit, verification, and report responsibilities into one undifferentiated task.",
203
+ "",
204
+ "# Workflow",
205
+ "",
206
+ ...steps[name].map((step, index) => `${index + 1}. ${step}`),
207
+ "",
208
+ ].join("\n");
104
209
  };
105
210
 
106
- const askTarget = async ({ input = process.stdin, output = process.stdout } = {}) => {
107
- const rl = readline.createInterface({ input, output });
108
- try {
109
- const answer = await rl.question("Use Clue setup skills for which AI tool? [codex/claude_code] ");
110
- return normalizeTarget(answer);
111
- } finally {
112
- rl.close();
113
- }
211
+ const askTarget = async ({
212
+ input = process.stdin,
213
+ output = process.stdout,
214
+ } = {}) => {
215
+ const rl = readline.createInterface({ input, output });
216
+ try {
217
+ const answer = await rl.question(
218
+ "ClueのセットアップSkillsをどのAIツールに追加しますか? [codex/claude_code] ",
219
+ );
220
+ return normalizeTarget(answer);
221
+ } finally {
222
+ rl.close();
223
+ }
114
224
  };
115
225
 
116
226
  export const installSetupSkills = async ({
117
- repoRoot,
118
- target,
119
- input,
120
- output,
227
+ repoRoot,
228
+ target,
229
+ input,
230
+ output,
121
231
  } = {}) => {
122
- const resolvedTarget = target ? normalizeTarget(target) : await askTarget({ input, output });
123
- const resolvedRepoRoot = resolve(repoRoot ?? ".");
124
- const skillRoot = join(resolvedRepoRoot, ...TARGET_SKILL_ROOTS[resolvedTarget]);
125
- const installed = [];
232
+ const resolvedTarget = target
233
+ ? normalizeTarget(target)
234
+ : await askTarget({ input, output });
235
+ const resolvedRepoRoot = resolve(repoRoot ?? ".");
236
+ const skillRoot = join(
237
+ resolvedRepoRoot,
238
+ ...TARGET_SKILL_ROOTS[resolvedTarget],
239
+ );
240
+ const installed = [];
126
241
 
127
- for (const skillName of SKILL_NAMES) {
128
- const skillDir = join(skillRoot, skillName);
129
- const skillPath = join(skillDir, "SKILL.md");
130
- await mkdir(skillDir, { recursive: true });
131
- await writeFile(skillPath, skillBody(skillName), "utf8");
132
- installed.push(skillPath);
133
- }
242
+ for (const skillName of SKILL_NAMES) {
243
+ const skillDir = join(skillRoot, skillName);
244
+ const skillPath = join(skillDir, "SKILL.md");
245
+ await mkdir(skillDir, { recursive: true });
246
+ await writeFile(skillPath, skillBody(skillName), "utf8");
247
+ installed.push(skillPath);
248
+ }
134
249
 
135
- return {
136
- target: resolvedTarget,
137
- skill_root: join(...TARGET_SKILL_ROOTS[resolvedTarget]),
138
- skills: SKILL_NAMES,
139
- installed_files: installed.map((path) => path.replace(`${resolvedRepoRoot}/`, "")),
140
- };
250
+ return {
251
+ target: resolvedTarget,
252
+ skill_root: join(...TARGET_SKILL_ROOTS[resolvedTarget]),
253
+ skills: SKILL_NAMES,
254
+ installed_files: installed.map((path) =>
255
+ path.replace(`${resolvedRepoRoot}/`, ""),
256
+ ),
257
+ };
141
258
  };
package/bin/clue-tool.mjs DELETED
@@ -1,83 +0,0 @@
1
- #!/usr/bin/env node
2
- import { readFile } from "node:fs/promises";
3
- import { resolve } from "node:path";
4
- import { commandSpecs } from "../src/command-spec.mjs";
5
- import { runInitTool } from "../src/init-tool.mjs";
6
- import { runSemanticCi } from "../src/semantic-ci.mjs";
7
- import { installSetupSkills } from "../src/setup-tool.mjs";
8
-
9
- const parseArgs = (argv) => {
10
- const [command = "help", ...tokens] = argv;
11
- const flags = new Map();
12
- for (let index = 0; index < tokens.length; index += 1) {
13
- const token = tokens[index];
14
- if (!token.startsWith("--")) continue;
15
- const key = token.slice(2);
16
- const next = tokens[index + 1];
17
- if (next && !next.startsWith("--")) {
18
- flags.set(key, next);
19
- index += 1;
20
- } else {
21
- flags.set(key, true);
22
- }
23
- }
24
- return { command, flags };
25
- };
26
-
27
- const readJson = async (path) => JSON.parse(await readFile(path, "utf8"));
28
-
29
- const usage = () => [
30
- "Usage:",
31
- " /clue-init",
32
- " clue-ai setup",
33
- " clue-ai init --request clue-init-request.json --repo .",
34
- " clue-ai semantic-ci --request clue-semantic-request.json --repo .",
35
- ].join("\n");
36
-
37
- const main = async () => {
38
- const { command, flags } = parseArgs(process.argv.slice(2));
39
- if (command === "help" || flags.has("help")) {
40
- process.stdout.write(`${usage()}\n`);
41
- return;
42
- }
43
-
44
- if (command === "commands") {
45
- process.stdout.write(`${JSON.stringify({ commands: commandSpecs }, null, 2)}\n`);
46
- return;
47
- }
48
-
49
- const requestPath = flags.get("request");
50
- const repoRoot = resolve(String(flags.get("repo") || "."));
51
- if (command === "setup") {
52
- const report = await installSetupSkills({
53
- repoRoot,
54
- target: typeof flags.get("target") === "string" ? flags.get("target") : undefined,
55
- });
56
- process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
57
- return;
58
- }
59
-
60
- if (typeof requestPath !== "string") {
61
- throw new Error("--request is required");
62
- }
63
- const request = await readJson(resolve(requestPath));
64
-
65
- if (command === "init") {
66
- const report = await runInitTool({ repoRoot, request });
67
- process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
68
- return;
69
- }
70
-
71
- if (command === "semantic-ci") {
72
- const result = await runSemanticCi({ repoRoot, request, env: process.env });
73
- process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
74
- return;
75
- }
76
-
77
- throw new Error(`Unknown command: ${command}\n${usage()}`);
78
- };
79
-
80
- main().catch((error) => {
81
- process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
82
- process.exitCode = 1;
83
- });