@clue-ai/cli 0.0.3 → 0.0.4

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.
@@ -4,8 +4,7 @@ Run the Clue SDK initialization tool with structured inputs.
4
4
 
5
5
  Required fields:
6
6
 
7
- - `project_key`
8
- - `service_key`
7
+ - `project_key` as an environment variable reference or placeholder, not a pasted secret value
9
8
  - `framework`
10
9
  - `backend_root_path`
11
10
  - `environment`
@@ -19,9 +18,12 @@ Required secrets:
19
18
 
20
19
  Behavior:
21
20
 
22
- 1. Collect the required fields as structured input.
23
- 2. Build the canonical init request.
24
- 3. Run `clue-ai init --request <generated-request.json> --repo .`.
25
- 4. Show the generated report and low-confidence review points.
21
+ 1. Follow the installed `clue-setup-orchestrator` skill and its monitoring gates.
22
+ 2. Collect the required fields as structured input without asking for secret values.
23
+ 3. Derive `service_key` from `backend_root_path` and repository structure; do not ask the user to type it.
24
+ 4. Build the canonical init request.
25
+ 5. Run `clue-ai init --request <generated-request.json> --repo .`.
26
+ 6. Show the generated report and low-confidence review points.
26
27
 
27
28
  Do not ask the user to write a free-form setup prompt.
29
+ Do not ask the user to paste project key, API key, service key, token, or environment values.
@@ -4,8 +4,7 @@ Run the Clue SDK initialization tool with structured inputs.
4
4
 
5
5
  Required fields:
6
6
 
7
- - `project_key`
8
- - `service_key`
7
+ - `project_key` as an environment variable reference or placeholder, not a pasted secret value
9
8
  - `framework`
10
9
  - `backend_root_path`
11
10
  - `environment`
@@ -19,9 +18,12 @@ Required secrets:
19
18
 
20
19
  Behavior:
21
20
 
22
- 1. Collect the required fields as structured input.
23
- 2. Build the canonical init request.
24
- 3. Run `clue-ai init --request <generated-request.json> --repo .`.
25
- 4. Show the generated report and low-confidence review points.
21
+ 1. Follow the installed `clue-setup-orchestrator` skill and its monitoring gates.
22
+ 2. Collect the required fields as structured input without asking for secret values.
23
+ 3. Derive `service_key` from `backend_root_path` and repository structure; do not ask the user to type it.
24
+ 4. Build the canonical init request.
25
+ 5. Run `clue-ai init --request <generated-request.json> --repo .`.
26
+ 6. Show the generated report and low-confidence review points.
26
27
 
27
28
  Do not ask the user to write a free-form setup prompt.
29
+ Do not ask the user to paste project key, API key, service key, token, or environment values.
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@clue-ai/cli",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "type": "module",
5
5
  "bin": {
6
- "clue-ai": "bin/clue-tool.mjs"
6
+ "clue-ai": "bin/clue-cli.mjs"
7
7
  },
8
8
  "files": [
9
9
  "bin/",
@@ -7,7 +7,6 @@ export const REQUIRED_SECRET_NAMES = [
7
7
 
8
8
  export const CLUE_INIT_COMMAND_FIELDS = [
9
9
  "project_key",
10
- "service_key",
11
10
  "framework",
12
11
  "backend_root_path",
13
12
  "environment",
@@ -45,15 +44,35 @@ const normalizeStringArray = (value, fallback, field) => {
45
44
  .map((entry) => entry.trim());
46
45
  };
47
46
 
47
+ const deriveServiceKeyFromBackendRootPath = (backendRootPath) => {
48
+ const segment = backendRootPath
49
+ .split("/")
50
+ .map((part) => part.trim())
51
+ .filter(Boolean)
52
+ .at(-1);
53
+ const normalized = segment
54
+ ?.toLowerCase()
55
+ .replace(/[^a-z0-9_-]+/g, "-")
56
+ .replace(/^-+|-+$/g, "");
57
+ if (!normalized) {
58
+ throw new Error(`service_key cannot be derived from backend_root_path for ${CLUE_INIT_COMMAND_NAME}`);
59
+ }
60
+ return normalized;
61
+ };
62
+
48
63
  export const buildClueInitRequestFromCommandInput = ({
49
64
  targetTool,
50
65
  input,
51
66
  }) => {
52
67
  const backendRootPath = requireField(input, "backend_root_path");
68
+ const serviceKey =
69
+ typeof input?.service_key === "string" && input.service_key.trim()
70
+ ? input.service_key.trim()
71
+ : deriveServiceKeyFromBackendRootPath(backendRootPath);
53
72
  return {
54
73
  target_tool: targetTool,
55
74
  project_key: requireField(input, "project_key"),
56
- service_key: requireField(input, "service_key"),
75
+ service_key: serviceKey,
57
76
  framework: requireField(input, "framework"),
58
77
  environment: requireField(input, "environment"),
59
78
  allowed_source_paths: normalizeStringArray(
@@ -13,6 +13,7 @@ const FUNCTION_PATTERN = /(?:async\s+def|def)\s+(?<name>[A-Za-z_][A-Za-z0-9_]*)\
13
13
  const ROUTER_ASSIGNMENT = /\b(?<name>[A-Za-z_][A-Za-z0-9_]*)\s*=\s*APIRouter\s*\(/g;
14
14
  const INCLUDE_ROUTER_CALL = /\b(?<owner>[A-Za-z_][A-Za-z0-9_]*)\.include_router\s*\(/g;
15
15
  const FROM_IMPORT = /^\s*from\s+(?<module>[A-Za-z0-9_.]+|\.+[A-Za-z0-9_.]*)\s+import\s+(?<names>[A-Za-z0-9_,\s]+)$/gm;
16
+ const IMPORT_MODULE = /^\s*import\s+(?<modules>[A-Za-z0-9_.,\s]+)$/gm;
16
17
 
17
18
  const sha256 = (value) => `sha256:${createHash("sha256").update(value).digest("hex")}`;
18
19
 
@@ -125,6 +126,41 @@ const resolveImportFile = ({ filesByRelativePath, currentRelativePath, moduleNam
125
126
  return null;
126
127
  };
127
128
 
129
+ const resolveFromImportEntry = ({
130
+ filesByRelativePath,
131
+ currentRelativePath,
132
+ moduleName,
133
+ importedName,
134
+ }) => {
135
+ const childModuleName =
136
+ moduleName.endsWith(".") || moduleName === "."
137
+ ? `${moduleName}${importedName}`
138
+ : `${moduleName}.${importedName}`;
139
+ const childFile = resolveImportFile({
140
+ filesByRelativePath,
141
+ currentRelativePath,
142
+ moduleName: childModuleName,
143
+ });
144
+ if (childFile) {
145
+ return {
146
+ file: childFile,
147
+ name: undefined,
148
+ };
149
+ }
150
+ const moduleFile = resolveImportFile({
151
+ filesByRelativePath,
152
+ currentRelativePath,
153
+ moduleName,
154
+ });
155
+ if (!moduleFile) {
156
+ return null;
157
+ }
158
+ return {
159
+ file: moduleFile,
160
+ name: importedName,
161
+ };
162
+ };
163
+
128
164
  const parseRouterAssignments = (source, relativePath) => {
129
165
  const prefixes = new Map();
130
166
  for (const match of source.matchAll(ROUTER_ASSIGNMENT)) {
@@ -141,44 +177,99 @@ const parseRouterAssignments = (source, relativePath) => {
141
177
  const parseImports = ({ source, currentRelativePath, filesByRelativePath }) => {
142
178
  const imports = new Map();
143
179
  for (const match of source.matchAll(FROM_IMPORT)) {
144
- const targetFile = resolveImportFile({
145
- filesByRelativePath,
146
- currentRelativePath,
147
- moduleName: match.groups.module,
148
- });
149
- if (!targetFile) {
150
- continue;
151
- }
152
180
  for (const entry of parseImportNames(match.groups.names)) {
181
+ const resolved = resolveFromImportEntry({
182
+ filesByRelativePath,
183
+ currentRelativePath,
184
+ moduleName: match.groups.module,
185
+ importedName: entry.importedName,
186
+ });
187
+ if (!resolved) {
188
+ continue;
189
+ }
153
190
  imports.set(entry.localName, {
191
+ file: resolved.file,
192
+ name: resolved.name,
193
+ });
194
+ }
195
+ }
196
+ for (const match of source.matchAll(IMPORT_MODULE)) {
197
+ for (const entry of parseImportNames(match.groups.modules)) {
198
+ const targetFile = resolveImportFile({
199
+ filesByRelativePath,
200
+ currentRelativePath,
201
+ moduleName: entry.importedName,
202
+ });
203
+ if (!targetFile) {
204
+ continue;
205
+ }
206
+ imports.set(entry.localName.split(".").at(-1), {
154
207
  file: targetFile,
155
- name: entry.importedName,
208
+ name: undefined,
156
209
  });
157
210
  }
158
211
  }
159
212
  return imports;
160
213
  };
161
214
 
215
+ const routerKey = (file, routerName) => `${file}::${routerName}`;
216
+
217
+ const resolveRouterTarget = ({ target, relativePath, imports }) => {
218
+ const parts = target.split(".");
219
+ if (parts.length === 1) {
220
+ const imported = imports.get(target);
221
+ return {
222
+ file: imported?.file ?? relativePath,
223
+ routerName: imported?.name ?? target,
224
+ };
225
+ }
226
+ const imported = imports.get(parts[0]);
227
+ if (!imported?.file || imported.name) {
228
+ throw new Error(`${relativePath}: include_router dotted target cannot be analyzed safely`);
229
+ }
230
+ if (parts.length !== 2) {
231
+ throw new Error(`${relativePath}: include_router dotted target cannot be analyzed safely`);
232
+ }
233
+ return {
234
+ file: imported.file,
235
+ routerName: parts[1],
236
+ };
237
+ };
238
+
162
239
  const parseIncludeRouters = ({ source, relativePath, imports }) => {
163
240
  const includes = [];
164
241
  for (const match of source.matchAll(INCLUDE_ROUTER_CALL)) {
165
242
  const openParenIndex = match.index + match[0].length - 1;
166
243
  const args = readCallArgs(source, openParenIndex);
167
- const routerMatch = /^\s*(?<router>[A-Za-z_][A-Za-z0-9_]*)/.exec(args);
244
+ const routerMatch = /^\s*(?<router>[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*)/.exec(args);
168
245
  if (!routerMatch?.groups?.router) {
169
246
  throw new Error(`${relativePath}: include_router target cannot be analyzed safely`);
170
247
  }
171
- const routerName = routerMatch.groups.router;
172
- const imported = imports.get(routerName);
248
+ const resolved = resolveRouterTarget({
249
+ target: routerMatch.groups.router,
250
+ relativePath,
251
+ imports,
252
+ });
173
253
  includes.push({
174
- file: imported?.file ?? relativePath,
175
- routerName: imported?.name ?? routerName,
254
+ ownerName: match.groups.owner,
255
+ file: resolved.file,
256
+ routerName: resolved.routerName,
176
257
  prefix: extractPrefix({ args, relativePath, callName: "include_router" }),
177
258
  });
178
259
  }
179
260
  return includes;
180
261
  };
181
262
 
263
+ const addIncludePrefix = (prefixesByRouterKey, key, prefix) => {
264
+ const current = prefixesByRouterKey.get(key) ?? [];
265
+ if (!current.includes(prefix)) {
266
+ current.push(prefix);
267
+ prefixesByRouterKey.set(key, current);
268
+ return true;
269
+ }
270
+ return false;
271
+ };
272
+
182
273
  const findNextFunction = (source, fromIndex) => {
183
274
  FUNCTION_PATTERN.lastIndex = fromIndex;
184
275
  const match = FUNCTION_PATTERN.exec(source);
@@ -270,6 +361,14 @@ export const analyzeFastApiRoutes = async ({ repoRoot, files }) => {
270
361
  });
271
362
  }
272
363
 
364
+ const routerPrefixesByKey = new Map();
365
+ for (const record of records) {
366
+ for (const [routerName, prefix] of record.routerPrefixes.entries()) {
367
+ routerPrefixesByKey.set(routerKey(record.relativePath, routerName), prefix);
368
+ }
369
+ }
370
+
371
+ const includeEdges = [];
273
372
  const includePrefixes = new Map();
274
373
  for (const record of records) {
275
374
  for (const include of parseIncludeRouters({
@@ -277,10 +376,42 @@ export const analyzeFastApiRoutes = async ({ repoRoot, files }) => {
277
376
  relativePath: record.relativePath,
278
377
  imports: record.imports,
279
378
  })) {
280
- const key = `${include.file}::${include.routerName}`;
281
- const current = includePrefixes.get(key) ?? [];
282
- current.push(include.prefix);
283
- includePrefixes.set(key, current);
379
+ const parentKey = record.routerPrefixes.has(include.ownerName)
380
+ ? routerKey(record.relativePath, include.ownerName)
381
+ : null;
382
+ includeEdges.push({
383
+ parentKey,
384
+ targetKey: routerKey(include.file, include.routerName),
385
+ prefix: include.prefix,
386
+ });
387
+ if (!parentKey) {
388
+ addIncludePrefix(
389
+ includePrefixes,
390
+ routerKey(include.file, include.routerName),
391
+ include.prefix,
392
+ );
393
+ }
394
+ }
395
+ }
396
+ let changed = true;
397
+ while (changed) {
398
+ changed = false;
399
+ for (const edge of includeEdges) {
400
+ if (!edge.parentKey) {
401
+ continue;
402
+ }
403
+ for (const parentPrefix of includePrefixes.get(edge.parentKey) ?? []) {
404
+ changed =
405
+ addIncludePrefix(
406
+ includePrefixes,
407
+ edge.targetKey,
408
+ combinePaths(
409
+ parentPrefix,
410
+ routerPrefixesByKey.get(edge.parentKey) ?? "",
411
+ edge.prefix,
412
+ ),
413
+ ) || changed;
414
+ }
284
415
  }
285
416
  }
286
417
 
@@ -289,7 +420,7 @@ export const analyzeFastApiRoutes = async ({ repoRoot, files }) => {
289
420
  const buildForDecorator = ({ match, method, decoratorPath }) => {
290
421
  const routerName = match.groups.router;
291
422
  const functionInfo = findNextFunction(record.source, match.index + match[0].length);
292
- const key = `${record.relativePath}::${routerName}`;
423
+ const key = routerKey(record.relativePath, routerName);
293
424
  const localRouterPrefix = record.routerPrefixes.get(routerName) ?? "";
294
425
  const prefixes = includePrefixes.get(key) ?? [""];
295
426
  for (const includePrefix of prefixes) {
@@ -209,6 +209,64 @@ const callAiProvider = async ({ request, apiKey, routes }) => {
209
209
  );
210
210
  };
211
211
 
212
+ const semanticGenerationFailureReason = (error) => {
213
+ if (!(error instanceof Error)) {
214
+ return "AI semantic generation failed for this route.";
215
+ }
216
+ const providerStatusMatch = /AI provider failed: (?<status>\d+)/.exec(
217
+ error.message,
218
+ );
219
+ if (providerStatusMatch?.groups?.status) {
220
+ return `AI semantic generation failed for this route: provider_${providerStatusMatch.groups.status}.`;
221
+ }
222
+ if (/empty semantic generation content/.test(error.message)) {
223
+ return "AI semantic generation returned empty content for this route.";
224
+ }
225
+ if (error instanceof SyntaxError) {
226
+ return "AI semantic generation returned malformed JSON for this route.";
227
+ }
228
+ return "AI semantic generation failed for this route.";
229
+ };
230
+
231
+ const unavailableAiRoute = (operationSourceKey, confidenceReason) => ({
232
+ operation_source_key: operationSourceKey,
233
+ confidence_reason: confidenceReason,
234
+ });
235
+
236
+ const generateAiRoutesPerRoute = async ({ request, apiKey, routes }) => {
237
+ const aiRoutes = new Map();
238
+ for (const route of routes) {
239
+ try {
240
+ const routeAiRoutes = await callAiProvider({
241
+ request,
242
+ apiKey,
243
+ routes: [route],
244
+ });
245
+ const aiRoute = routeAiRoutes.get(route.operation_source_key);
246
+ if (aiRoute?.semantics) {
247
+ aiRoutes.set(route.operation_source_key, aiRoute);
248
+ } else {
249
+ aiRoutes.set(
250
+ route.operation_source_key,
251
+ unavailableAiRoute(
252
+ route.operation_source_key,
253
+ "AI semantic generation omitted this route.",
254
+ ),
255
+ );
256
+ }
257
+ } catch (error) {
258
+ aiRoutes.set(
259
+ route.operation_source_key,
260
+ unavailableAiRoute(
261
+ route.operation_source_key,
262
+ semanticGenerationFailureReason(error),
263
+ ),
264
+ );
265
+ }
266
+ }
267
+ return aiRoutes;
268
+ };
269
+
212
270
  const buildAiSelectionPrompt = (selectionCandidates) =>
213
271
  JSON.stringify({
214
272
  task: "Choose adopted semantic values from deterministic and AI candidates. Return JSON only.",
@@ -1420,7 +1478,8 @@ const buildSnapshot = ({ request, routes, aiRoutes, aiSelectionDecisions }) => {
1420
1478
  const baseRoute = !aiRoute?.semantics
1421
1479
  ? fallbackSemantics(
1422
1480
  routeWithVersion,
1423
- "AI semantics were unavailable for this route.",
1481
+ aiRoute?.confidence_reason ??
1482
+ "AI semantics were unavailable for this route.",
1424
1483
  hashScope,
1425
1484
  )
1426
1485
  : {
@@ -1799,7 +1858,7 @@ export const runSemanticCi = async ({ repoRoot, request: rawRequest, env }) => {
1799
1858
  ),
1800
1859
  }));
1801
1860
  const aiProviderApiKey = requireAiProviderApiKey(env);
1802
- const aiRoutes = await callAiProvider({
1861
+ const aiRoutes = await generateAiRoutesPerRoute({
1803
1862
  request,
1804
1863
  apiKey: aiProviderApiKey,
1805
1864
  routes: promptRoutes,
@@ -3,6 +3,7 @@ import { join, resolve } from "node:path";
3
3
  import readline from "node:readline/promises";
4
4
 
5
5
  const SKILL_NAMES = [
6
+ "clue-setup-orchestrator",
6
7
  "clue-route-semantic-snapshot",
7
8
  "clue-semantic-ci",
8
9
  "clue-sdk-instrumentation",
@@ -21,13 +22,15 @@ const TARGET_SKILL_ROOTS = {
21
22
  const normalizeTarget = (target) => {
22
23
  const normalized = String(target ?? "").trim().toLowerCase().replace(/[\s-]+/g, "_");
23
24
  if (!TARGETS.has(normalized)) {
24
- throw new Error("target must be codex or claude_code");
25
+ throw new Error("AIツールは codex または claude_code を指定してください");
25
26
  }
26
27
  return normalized;
27
28
  };
28
29
 
29
30
  const skillBody = (name) => {
30
31
  const descriptions = {
32
+ "clue-setup-orchestrator":
33
+ "Use first when running the full Clue setup so one execution agent per implementation workstream and multiple monitoring agents coordinate separate setup phases.",
31
34
  "clue-route-semantic-snapshot":
32
35
  "Use when analyzing backend routes, handlers, controllers, or endpoints to create privacy-safe Clue semantic snapshots.",
33
36
  "clue-semantic-ci":
@@ -43,19 +46,48 @@ const skillBody = (name) => {
43
46
  };
44
47
 
45
48
  const steps = {
49
+ "clue-setup-orchestrator": [
50
+ "Use one execution agent per implementation workstream.",
51
+ "Each execution agent owns exactly one workstream and its tests.",
52
+ "Required execution agents: SDK Lifecycle Execution Agent, Semantic Snapshot Execution Agent, and Semantic Snapshot CI Execution Agent.",
53
+ "Run execution agents in parallel only when file ownership does not conflict; otherwise run them sequentially with monitor gates between workstreams.",
54
+ "Use multiple monitoring agents for read-only checks, or named review passes if subagents are unavailable.",
55
+ "Run setup phases separately in this order: repository discovery, semantic snapshot, semantic snapshot CI, SDK lifecycle implementation, verification, final report.",
56
+ "Treat only semantic snapshot, semantic snapshot CI, and SDK lifecycle implementation as implementation workstreams with execution agents.",
57
+ "Before each workstream, read and apply the matching Clue setup skill.",
58
+ "After each implementation workstream, run a monitoring check with `clue-setup-audit` before continuing.",
59
+ "For final local verification, read and apply `clue-local-verification`.",
60
+ "For the final report, read and apply `clue-setup-report`.",
61
+ "Do not continue past P0/P1 monitoring findings until fixed or reported as blocked.",
62
+ ],
46
63
  "clue-route-semantic-snapshot": [
64
+ "Use this skill as the source of truth for semantic snapshot content and structure.",
65
+ "Keep semantic snapshot authoring separate from CI workflow creation and SDK lifecycle implementation.",
66
+ "Do not create CI workflow files or SDK lifecycle calls from this skill.",
47
67
  "Inspect only allowed source paths.",
48
68
  "Identify route, handler, controller, and endpoint behavior from privacy-safe evidence.",
69
+ "Create route entries with operation_source_key, method/path_template when available, route_summary, route_confidence, confidence_reason, and source_evidence_refs.",
70
+ "Create layer_evidence for data effects, side effects, validation, permissions, failures, and component fingerprints when available.",
71
+ "Create operation_effects only when target object evidence and domain behavior evidence are sufficient.",
72
+ "Create target_object_profiles, target_object_catalog, and target_object_mappings for accepted operation effects.",
73
+ "Preserve unresolved_operation_effects with missing_context instead of fabricating unknown operation effects.",
74
+ "Include source_evidence_refs and ai_inference_evidence without raw source, secrets, prompts, or completions.",
49
75
  "Create semantic snapshot inputs without raw source, secrets, prompts, or completions.",
50
76
  "Report unresolved routes as blockers instead of guessing.",
51
77
  ],
52
78
  "clue-semantic-ci": [
79
+ "Use this skill as the source of truth for semantic snapshot CI workflow format.",
80
+ "Keep CI workflow creation separate from semantic snapshot content authoring and SDK lifecycle implementation.",
81
+ "Do not author semantic snapshot content or SDK lifecycle calls from this skill.",
53
82
  "Create or update `.github/workflows/clue-semantic-snapshot.yml`.",
54
83
  "Use `npx @clue-ai/cli semantic-ci --request .clue/semantic-request.runtime.json --repo .`.",
55
84
  "Reference GitHub Secrets and Variables by name only.",
56
85
  "Do not print or commit secret values.",
57
86
  ],
58
87
  "clue-sdk-instrumentation": [
88
+ "Use this skill as the source of truth for Clue SDK lifecycle implementation.",
89
+ "Keep SDK lifecycle implementation separate from semantic snapshot and CI workflow work.",
90
+ "Do not create semantic snapshot content or semantic snapshot CI workflow files from this skill.",
59
91
  "Find the app/bootstrap entrypoint and add ClueInit only when the location is clear.",
60
92
  "Find login success handling and add ClueIdentify only when the user identity is available.",
61
93
  "Find account, workspace, organization, or tenant resolution and add ClueSetAccount only when the subject is available.",
@@ -63,22 +95,31 @@ const skillBody = (name) => {
63
95
  "Skip unclear lifecycle points and report blockers.",
64
96
  ],
65
97
  "clue-setup-audit": [
98
+ "Act as a read-only monitoring agent, not the execution agent.",
99
+ "Check one completed workstream at a time and report P0/P1 issues before more implementation continues.",
66
100
  "Review changed files line by line.",
101
+ "Verify semantic snapshot, semantic CI, and SDK lifecycle responsibilities did not bleed into each other.",
67
102
  "Reject broad ClueTrack instrumentation and DOM clue tags.",
68
103
  "Confirm no project key, API key, secret, or env value appears in diff or report.",
69
104
  "Confirm lifecycle insertions are minimal and reviewable.",
70
105
  ],
71
106
  "clue-local-verification": [
107
+ "Act as a read-only monitoring agent for local verification evidence.",
108
+ "Verify each workstream independently before the final setup report.",
72
109
  "Confirm generated skill files exist.",
73
110
  "Confirm workflow files and SDK lifecycle imports/calls exist when those phases have run.",
74
111
  "Confirm only env names are reported.",
75
112
  "Leave event delivery verification to the Clue setup screen.",
76
113
  ],
77
114
  "clue-setup-report": [
115
+ "Use this skill only after execution and monitoring passes are finished.",
78
116
  "Summarize changed files.",
79
117
  "List completed setup phases.",
118
+ "List skills used for each workstream.",
119
+ "List execution agent and monitoring agents, or named review passes if subagents were unavailable.",
80
120
  "List blockers with exact file or environment names when available.",
81
121
  "List required env names without values.",
122
+ "List P0/P1 monitoring findings and fixes.",
82
123
  "State that commit and push were not performed.",
83
124
  ],
84
125
  };
@@ -91,10 +132,19 @@ const skillBody = (name) => {
91
132
  "",
92
133
  "# Rules",
93
134
  "",
135
+ "- For full Clue setup, use one execution agent per implementation workstream and multiple monitoring agents for read-only checks.",
136
+ "- The full setup must start with `clue-setup-orchestrator`.",
137
+ "- Each execution agent owns exactly one workstream; monitoring agents review one workstream at a time and report P0/P1 issues.",
138
+ "- Do not continue past a P0/P1 monitoring finding until it is fixed or explicitly reported as blocked.",
139
+ "- If subagents are unavailable, run the same structure as separate named review passes and say so in the final report.",
94
140
  "- Do not expose project keys, API keys, secrets, tokens, or environment variable values.",
141
+ "- Do not ask the user to paste secret values.",
142
+ "- Do not read `.env`, `.env.*`, secret files, logs, dumps, build output, coverage output, `node_modules`, vendor directories, dependency directories, or dependency output.",
143
+ "- Report only environment variable names, never values.",
95
144
  "- Do not commit or push changes.",
96
145
  "- Prefer existing repository patterns and minimal diffs.",
97
146
  "- If evidence is unclear, report a blocker instead of guessing.",
147
+ "- Do not merge semantic snapshot, semantic CI, SDK lifecycle, audit, verification, and report responsibilities into one undifferentiated task.",
98
148
  "",
99
149
  "# Workflow",
100
150
  "",
@@ -106,7 +156,9 @@ const skillBody = (name) => {
106
156
  const askTarget = async ({ input = process.stdin, output = process.stdout } = {}) => {
107
157
  const rl = readline.createInterface({ input, output });
108
158
  try {
109
- const answer = await rl.question("Use Clue setup skills for which AI tool? [codex/claude_code] ");
159
+ const answer = await rl.question(
160
+ "ClueのセットアップSkillsをどのAIツールに追加しますか? [codex/claude_code] ",
161
+ );
110
162
  return normalizeTarget(answer);
111
163
  } finally {
112
164
  rl.close();
File without changes