@aragon-agent/cli 0.6.28 → 0.6.31

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.
Files changed (80) hide show
  1. package/CHANGELOG.md +2123 -1975
  2. package/README.md +81 -14
  3. package/dist/agent/project-guidance-prompt.js +20 -20
  4. package/dist/agent/reducer.js +47 -2
  5. package/dist/cli.js +169 -56
  6. package/dist/commands/builtins.js +4 -0
  7. package/dist/commands/perf.d.ts +25 -1
  8. package/dist/commands/perf.js +26 -2
  9. package/dist/commands/registry.d.ts +6 -0
  10. package/dist/config/env.js +4 -0
  11. package/dist/config/load.d.ts +3 -1
  12. package/dist/config/load.js +12 -1
  13. package/dist/config/schema.d.ts +27 -0
  14. package/dist/config/schema.js +9 -0
  15. package/dist/config/ui-state.d.ts +9 -0
  16. package/dist/config/ui-state.js +9 -0
  17. package/dist/input/limits.d.ts +20 -0
  18. package/dist/input/limits.js +20 -0
  19. package/dist/input/stdin-filter.js +68 -5
  20. package/dist/ui/App.d.ts +11 -1
  21. package/dist/ui/App.js +155 -67
  22. package/dist/ui/AutocompletePopup.js +1 -1
  23. package/dist/ui/Header.js +7 -2
  24. package/dist/ui/Markdown.js +30 -3
  25. package/dist/ui/PromptInput.js +41 -3
  26. package/dist/ui/ScrollbackShell.d.ts +28 -0
  27. package/dist/ui/ScrollbackShell.js +10 -0
  28. package/dist/ui/Transcript.js +7 -0
  29. package/dist/ui/frame-differ.d.ts +12 -0
  30. package/dist/ui/layout/Gutter.js +1 -1
  31. package/dist/ui/layout/OverlayFrame.d.ts +15 -0
  32. package/dist/ui/layout/OverlayFrame.js +18 -0
  33. package/dist/ui/layout/ScrollIndicator.js +10 -3
  34. package/dist/ui/layout/budget.d.ts +15 -0
  35. package/dist/ui/layout/budget.js +15 -0
  36. package/dist/ui/layout/header-hints.d.ts +9 -0
  37. package/dist/ui/layout/header-hints.js +14 -1
  38. package/dist/ui/layout/status-layout.js +63 -2
  39. package/dist/ui/markdown-blocks.d.ts +26 -5
  40. package/dist/ui/markdown-blocks.js +110 -33
  41. package/dist/ui/overlays/HelpOverlay.d.ts +1 -1
  42. package/dist/ui/overlays/HelpOverlay.js +21 -3
  43. package/dist/ui/screen.d.ts +16 -0
  44. package/dist/ui/screen.js +32 -0
  45. package/dist/ui/scrollback/budget.d.ts +43 -0
  46. package/dist/ui/scrollback/budget.js +44 -0
  47. package/dist/ui/scrollback/drain.d.ts +32 -0
  48. package/dist/ui/scrollback/drain.js +64 -0
  49. package/dist/ui/scrollback/exit-summary.d.ts +23 -0
  50. package/dist/ui/scrollback/exit-summary.js +25 -0
  51. package/dist/ui/scrollback/limits.d.ts +25 -0
  52. package/dist/ui/scrollback/limits.js +25 -0
  53. package/dist/ui/scrollback/live-preview.d.ts +26 -0
  54. package/dist/ui/scrollback/live-preview.js +106 -0
  55. package/dist/ui/scrollback/renderer.d.ts +38 -0
  56. package/dist/ui/scrollback/renderer.js +158 -0
  57. package/dist/ui/scrollback/scrollback-writer.d.ts +74 -0
  58. package/dist/ui/scrollback/scrollback-writer.js +263 -0
  59. package/dist/ui/scrollback/settled-boundary.d.ts +42 -0
  60. package/dist/ui/scrollback/settled-boundary.js +106 -0
  61. package/dist/ui/scrollback/use-scrollback-view.d.ts +92 -0
  62. package/dist/ui/scrollback/use-scrollback-view.js +263 -0
  63. package/dist/ui/scrollback/writer-shapes.d.ts +61 -0
  64. package/dist/ui/scrollback/writer-shapes.js +114 -0
  65. package/dist/ui/stdout-frame-writer.js +12 -2
  66. package/dist/ui/terminal-plan.d.ts +52 -0
  67. package/dist/ui/terminal-plan.js +49 -0
  68. package/dist/ui/transcript-text.d.ts +11 -0
  69. package/dist/ui/transcript-text.js +21 -7
  70. package/dist/ui/use-startup-notices.d.ts +12 -1
  71. package/dist/ui/use-startup-notices.js +28 -2
  72. package/dist/ui/use-wheel-routing.d.ts +10 -7
  73. package/dist/ui/use-wheel-routing.js +11 -6
  74. package/package.json +2 -2
  75. package/skills/project-indexer/SKILL.md +163 -163
  76. package/skills/project-indexer/templates/cleancode-overrides.md +46 -46
  77. package/skills/project-indexer/templates/cleancode-template.md +94 -94
  78. package/skills/project-indexer/templates/config-template.md +69 -69
  79. package/skills/project-indexer/templates/index-template.md +129 -129
  80. package/skills/skill-creator/SKILL.md +96 -96
@@ -14,7 +14,7 @@
14
14
  import { useEffect, useRef } from 'react';
15
15
  import { MODE_TOGGLE_KEYS } from '../agent/agent-mode.js';
16
16
  import { readConfigFile } from '../config/store.js';
17
- import { getMouseNoticeVersion, getVtInputNoticeVersion } from '../config/ui-state.js';
17
+ import { getMouseNoticeVersion, getScrollModeNoticeVersion, getVtInputNoticeVersion, } from '../config/ui-state.js';
18
18
  import { getLogger } from '../logging/logger.js';
19
19
  /**
20
20
  * The revision of the mouse notice a user must have seen for it to stay quiet
@@ -93,7 +93,17 @@ export function vtInputDeadNotice(nodeVersion) {
93
93
  `as a PLAIN TAB - ${cost}${toggle}, and Shift+Up / Shift+Down to scroll. ` +
94
94
  'Node 22.17.0+ (or 24.2.0+) restores both.');
95
95
  }
96
- export function useStartupNotices(dispatch, mouseNotice, retainNotice, vtInputNotice) {
96
+ /**
97
+ * The revision of the native-scroll notice a user must have seen for it to stay
98
+ * quiet (`state.json::scrollModeNoticeVersion`). BUMP IT WHENEVER THE ADVICE
99
+ * CHANGES, never for a rewording (tui-native-terminal-scroll D12).
100
+ */
101
+ export const SCROLL_MODE_NOTICE_VERSION = 1;
102
+ export function scrollModeNoticeText() {
103
+ return ('Scrolling now uses your terminal: wheel, scrollbar, selection and search all work as ' +
104
+ 'usual. Prefer the old full-screen view? Run: aragon config set scrollMode app');
105
+ }
106
+ export function useStartupNotices(dispatch, mouseNotice, retainNotice, vtInputNotice, scrollModeNotice) {
97
107
  // The sink gives up after repeated write failures (a read-only log directory,
98
108
  // a full disk). Silently logging nothing is exactly the state a user must not
99
109
  // discover later, from an empty file, while trying to explain a bug.
@@ -167,6 +177,22 @@ export function useStartupNotices(dispatch, mouseNotice, retainNotice, vtInputNo
167
177
  });
168
178
  vtNoticeRef.current?.onSeen();
169
179
  }, [vtNodeVersion, dispatch]);
180
+ // The one-shot native-scroll notice (D12): a default-behaviour change has to be
181
+ // discoverable and reversible. `>=`, like the notices above: a state file written
182
+ // by a newer build has already told this user.
183
+ const scrollNoticeRef = useRef(scrollModeNotice);
184
+ scrollNoticeRef.current = scrollModeNotice;
185
+ const scrollNoticeWanted = scrollModeNotice !== undefined;
186
+ const scrollNoticeShown = useRef(false);
187
+ useEffect(() => {
188
+ if (!scrollNoticeWanted || scrollNoticeShown.current)
189
+ return;
190
+ if (getScrollModeNoticeVersion() >= SCROLL_MODE_NOTICE_VERSION)
191
+ return;
192
+ scrollNoticeShown.current = true;
193
+ dispatch({ type: 'notice', level: 'info', text: scrollModeNoticeText() });
194
+ scrollNoticeRef.current?.onSeen();
195
+ }, [scrollNoticeWanted, dispatch]);
170
196
  // A `warn` notice rather than a toast: it is about a value the user typed, so
171
197
  // it belongs in the transcript where it can be scrolled back to, not in a row
172
198
  // that expires. DEPENDS ON THE TWO SCALARS, never on the options object —
@@ -22,13 +22,6 @@
22
22
  import type { Overlay } from '../agent/reducer.js';
23
23
  import type { MouseSource } from '../input/stdin-filter.js';
24
24
  import type { ScrollIntent } from './layout/scroll.js';
25
- /**
26
- * Rows a PgUp/PgDn — and a Shift+wheel notch — moves inside a controlled
27
- * overlay. Declared here rather than in `App.tsx` because both the keyboard
28
- * branch and the wheel branch need it and `App` imports this module; the other
29
- * direction would be a cycle.
30
- */
31
- export declare const OVERLAY_PAGE = 8;
32
25
  export interface WheelRoutingOptions {
33
26
  isPointerCaptured?: () => boolean;
34
27
  isActive?: () => boolean;
@@ -39,6 +32,16 @@ export interface WheelRoutingOptions {
39
32
  onScroll: (kind: ScrollIntent, repeat: number) => void;
40
33
  /** Signed row delta; the caller clamps at 0 the way the keyboard branch does. */
41
34
  onOverlayScroll: (delta: number) => void;
35
+ /**
36
+ * Rows one Shift+wheel notch turns inside a controlled overlay (defect 11).
37
+ *
38
+ * A GETTER, read at event time for the same reason `getOverlay` is: the window
39
+ * height changes with the terminal, with `statusExpanded` and with the rail, and
40
+ * a value captured when the subscription was built is the value that goes stale.
41
+ * `App` answers with `overlayPageSize(...)`, the same function its keyboard
42
+ * branch uses, so the wheel and `PgDn` can never disagree.
43
+ */
44
+ getOverlayPage?: () => number;
42
45
  }
43
46
  export interface WheelRouting {
44
47
  /**
@@ -21,12 +21,15 @@
21
21
  */
22
22
  import { useCallback, useEffect, useRef } from 'react';
23
23
  /**
24
- * Rows a PgUp/PgDn — and a Shift+wheel notch — moves inside a controlled
25
- * overlay. Declared here rather than in `App.tsx` because both the keyboard
26
- * branch and the wheel branch need it and `App` imports this module; the other
27
- * direction would be a cycle.
24
+ * Page rows used ONLY when the host supplies no `getOverlayPage`.
25
+ *
26
+ * `App` always supplies one (defect 11): the step is the overlay's visible window
27
+ * minus two rows of context, so `PgDn` in `/help` turns a page instead of 42% of
28
+ * one. This fallback exists so a host that owns no overlay window - this module's
29
+ * own routing tests are the only such host - still gets a page rather than
30
+ * silently degrading a Shift+wheel to a three-row notch.
28
31
  */
29
- export const OVERLAY_PAGE = 8;
32
+ const FALLBACK_OVERLAY_PAGE = 8;
30
33
  /** Transcript rows per notch. The terminal's own convention. */
31
34
  const CONTENT_LINES_PER_NOTCH = 3;
32
35
  /** Overlay rows per notch. Overlay content is short; a page needs Shift. */
@@ -113,7 +116,9 @@ export function useWheelRouting(options) {
113
116
  // D-3: the row is not consulted here either. Behind an overlay the
114
117
  // composer is inactive and the overlay is the only scrollable thing on
115
118
  // screen, so a notch anywhere scrolls it.
116
- const step = event.shift ? OVERLAY_PAGE : OVERLAY_LINES_PER_NOTCH;
119
+ const step = event.shift
120
+ ? current.getOverlayPage?.() ?? FALLBACK_OVERLAY_PAGE
121
+ : OVERLAY_LINES_PER_NOTCH;
117
122
  current.onOverlayScroll(event.dir === 'up' ? -step : step);
118
123
  return;
119
124
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aragon-agent/cli",
3
- "version": "0.6.28",
3
+ "version": "0.6.31",
4
4
  "description": "AragonAgent CLI — a Claude-Code / Codex-style interactive terminal UI (TUI) on top of the @aragon-agent/core engine. Installable and runnable via npm / npx.",
5
5
  "license": "MIT",
6
6
  "author": "AragonAgent contributors",
@@ -56,7 +56,7 @@
56
56
  "prepublishOnly": "npm run build"
57
57
  },
58
58
  "dependencies": {
59
- "@aragon-agent/core": "^0.2.40",
59
+ "@aragon-agent/core": "^0.2.43",
60
60
  "chalk": "^5.6.2",
61
61
  "cli-highlight": "^2.0.0",
62
62
  "commander": "^12.1.0",
@@ -1,163 +1,163 @@
1
- ---
2
- name: project-indexer
3
- description: Generate and use a project index for quick codebase understanding in new sessions. Scans the workspace, extracts exported symbols, writes .claude-index/index.md plus config, and injects a Google-style Clean Code Guidelines section into CLAUDE.md. Use when the user says "explore the project", "generate index", "regenerate index", "更新索引", "生成索引", or presses Ctrl+I.
4
- version: 1.1.0
5
- license: MIT
6
- keywords: [productivity, codebase, indexing, navigation, cleancode]
7
- # The read-only tools (read_file, list_dir, glob, grep, ask_user, todo_write)
8
- # are always available inside a skill frame via the tool floor; this ceiling
9
- # adds exactly the two writers the generated files need.
10
- allowed-tools:
11
- - write_file
12
- - edit_file
13
- ---
14
-
15
- # Project Indexer
16
-
17
- Generate a structured index of any codebase so a new session understands the
18
- project with minimal context usage. The index is a **navigation map**, not a
19
- code copy: enough to see the project globally (type, stack, architecture),
20
- navigate on demand (feature map, file index), and know which symbols exist
21
- without reading every file.
22
-
23
- ## Current request
24
-
25
- $ARGUMENTS
26
-
27
- ## Step 1: Check for an existing index
28
-
29
- - If `.claude-index/index.md` exists and has the key sections (Project
30
- Overview, Feature Map, File Index), go to "Using an existing index".
31
- - If it exists but is empty or malformed, tell the user and regenerate
32
- (first-time flow), preserving `config.md` if intact.
33
- - Otherwise run the first-time flow.
34
-
35
- ## Using an existing index
36
-
37
- 1. Read `.claude-index/index.md` and `CLAUDE.md` (if present).
38
- 2. Summarize in 3-5 bullets: structure, stack, feature areas, key entry
39
- points. Offer to help.
40
- 3. For later questions, navigate via the Feature Map / File Index and read
41
- real source only when detail is needed.
42
-
43
- ## First-time flow
44
-
45
- ### Step 2: Gather configuration (ask_user)
46
-
47
- Ask with `ask_user`, defaults offered in every question:
48
-
49
- 1. **Exclusions** - A) defaults (node_modules, .git, dist, build,
50
- __pycache__, .venv, vendor, coverage, .next, .nuxt, .cache, target, bin,
51
- obj, .idea, .vscode) B) add more C) custom list.
52
- 2. **Priority directories** - A) auto-detect (recommended) B) specify C) all
53
- equally.
54
- 3. **Tech stack** - auto-detect unless the user names one.
55
- 4. **Clean Code Guidelines** (injected into CLAUDE.md) - A) Google strict
56
- (method 60, file 1000 - recommended) B) Google relaxed (method 600)
57
- C) custom D) skip.
58
-
59
- If C: ask **one `ask_user` call per limit** showing default and range -
60
- MAX_FILE_LINES 1000 (200-5000), MAX_METHOD_LINES 60 (20-600),
61
- MAX_FUNCTION_PARAMS 5 (2-10), MAX_CYCLOMATIC 10 (5-25); fall back to the
62
- default on an out-of-range answer and say so in the summary.
63
- MAX_LINE_LENGTH (default 100, Python 80) and MAX_NESTING_DEPTH (4) are never
64
- asked. If the user skips every question, use all defaults.
65
-
66
- Treat the answer as `CleanCodeConfig.preset`: strict | relaxed | custom |
67
- disabled. D (`disabled`) skips the Clean Code composition below, never adds
68
- markers, and persists `Enabled: No`.
69
-
70
- ### Step 3: Scan and analyze
71
-
72
- 1. Traverse the tree with the exclusion rules (`glob`, never one giant read).
73
- 2. Detect project type (frontend/backend/fullstack/library/CLI/monorepo),
74
- languages with percentages, frameworks, entry points.
75
- 3. Group files by feature/domain and extract exported symbols - full support
76
- for JS/TS (.js/.jsx/.ts/.tsx/.mjs) and Python; best-effort for Java,
77
- Kotlin, Go, Rust, C/C++, C#, Ruby, PHP; unknown types are listed without
78
- symbols.
79
- 4. Analyze module-level dependencies (import graph).
80
-
81
- Adaptive sizing: <50 files -> full detail; 50-200 -> full coverage with
82
- concise descriptions; 200+ -> detail the priority directories, summarize the
83
- rest, group similar utilities. Over 1000 files after exclusions: warn and
84
- suggest more exclusions before continuing; sample representative files with
85
- glob/grep rather than reading everything. Keep language/framework findings in
86
- working memory - do NOT write an intermediate JSON file.
87
-
88
- ### Step 4: Write `.claude-index/`
89
-
90
- 1. `config.md` - exclusions, priorities, tech stack, plus an Index Settings
91
- block (Generated date, Project Root, Index Version) and a Clean Code
92
- Settings block (Enabled / Preset / the six limits; when the user picked
93
- skip, write `Enabled: No`, `Preset: disabled` and the strict numbers so a
94
- later "enable cleancode" can flip it back).
95
- 2. `index.md` - follow `templates/index-template.md` in this skill's
96
- directory: Project Overview, Feature Map (per area: entry file, one-line
97
- description, key exports with signatures), Module Dependencies, File Index
98
- (per-directory tables, one line per file).
99
-
100
- ### Step 5: Compose the Clean Code Guidelines (skip when disabled)
101
-
102
- Read `templates/cleancode-template.md` and `templates/cleancode-overrides.md`
103
- from this skill's directory, then:
104
-
105
- 1. Primary languages = every language with >= 10% of post-exclusion source
106
- files; if none clears 10%, use the `Other` row.
107
- 2. Take the **minimum** across all matching rows for each numeric column.
108
- 3. Apply the user preset: strict/relaxed values intersect with the language
109
- minimum (never looser than the baseline); custom numbers are honoured
110
- verbatim with divergence noted.
111
- 4. Substitute every placeholder: `{{MAX_FILE_LINES}}`, `{{MAX_METHOD_LINES}}`,
112
- `{{MAX_FUNCTION_PARAMS}}`, `{{MAX_CYCLOMATIC}}`, `{{MAX_LINE_LENGTH}}`,
113
- `{{MAX_NESTING_DEPTH}}`, `{{PRIMARY_LANGUAGES}}` (comma-joined languages)
114
- and `{{LANGUAGE_HINTS}}` (one `- Language: note` bullet per matching row,
115
- deduped by exact string).
116
- 5. Verify no `{{...}}` placeholder remains. Do not count characters at
117
- runtime.
118
-
119
- ### Step 6: Update CLAUDE.md
120
-
121
- - `## Project Index` section: upsert (replace when present, else append at
122
- end; create the file when missing). Contents: Location
123
- `.claude-index/index.md`, Last Updated (YYYY-MM-DD), Contents line, a
124
- Usage line, and "Regenerate: say 'regenerate index' / '更新索引'".
125
- - `## Clean Code Guidelines` section (unless disabled): wrap the rendered
126
- body in `<!-- project-indexer:cleancode:begin v1.1.0 -->` and
127
- `<!-- project-indexer:cleancode:end -->`. Locate an existing block with
128
- the version-agnostic regex `<!-- project-indexer:cleancode:begin
129
- v\d+\.\d+\.\d+ -->` (NEVER a literal-version match) plus the literal end
130
- marker; fallback: the region from a `## Clean Code Guidelines` heading to
131
- the next `## ` heading or EOF. Replace the found block; if none, insert
132
- after the Project Index section (first-insert only; when both sections
133
- already exist preserve the user's ordering and everything between them).
134
- Write UTF-8; add a trailing newline when missing.
135
-
136
- ### Step 7: Report
137
-
138
- List what was created/updated, the feature-area count, files indexed and
139
- symbols extracted. Offer to start work.
140
-
141
- ## Regeneration ("regenerate index" / "更新索引")
142
-
143
- 1. Read `config.md` and preserve exclusions, priorities, stack.
144
- 2. Clean Code handling: if CLAUDE.md has markers or the heading, ask
145
- A) refresh B) keep C) remove; honour `Enabled: No` from config.md by
146
- skipping silently with one reminder line. When no block exists and
147
- Enabled is Yes/absent, compose and inject (announce before writing).
148
- 3. Confirm the plan (exclusions, priorities, cleancode decision) with the
149
- user, then re-run Steps 3-7.
150
-
151
- Special triggers: "disable cleancode" removes the block and sets
152
- `Enabled: No`; "enable cleancode" re-composes it and sets `Enabled: Yes` -
153
- both without a full rescan.
154
-
155
- ## Edge cases
156
-
157
- - Inaccessible directories: list them under a "Skipped Directories" note and
158
- continue; never fail the whole run for one unreadable path.
159
- - No recognizable source files: generate a minimal index (overview + file
160
- listing) and say so.
161
- - The user pressed Ctrl+I: they already confirmed once - do not re-ask the
162
- global "proceed?" question, but still ask the configuration questions
163
- above (or reuse `.claude-index/config.md` when it exists).
1
+ ---
2
+ name: project-indexer
3
+ description: Generate and use a project index for quick codebase understanding in new sessions. Scans the workspace, extracts exported symbols, writes .claude-index/index.md plus config, and injects a Google-style Clean Code Guidelines section into CLAUDE.md. Use when the user says "explore the project", "generate index", "regenerate index", "更新索引", "生成索引", or presses Ctrl+I.
4
+ version: 1.1.0
5
+ license: MIT
6
+ keywords: [productivity, codebase, indexing, navigation, cleancode]
7
+ # The read-only tools (read_file, list_dir, glob, grep, ask_user, todo_write)
8
+ # are always available inside a skill frame via the tool floor; this ceiling
9
+ # adds exactly the two writers the generated files need.
10
+ allowed-tools:
11
+ - write_file
12
+ - edit_file
13
+ ---
14
+
15
+ # Project Indexer
16
+
17
+ Generate a structured index of any codebase so a new session understands the
18
+ project with minimal context usage. The index is a **navigation map**, not a
19
+ code copy: enough to see the project globally (type, stack, architecture),
20
+ navigate on demand (feature map, file index), and know which symbols exist
21
+ without reading every file.
22
+
23
+ ## Current request
24
+
25
+ $ARGUMENTS
26
+
27
+ ## Step 1: Check for an existing index
28
+
29
+ - If `.claude-index/index.md` exists and has the key sections (Project
30
+ Overview, Feature Map, File Index), go to "Using an existing index".
31
+ - If it exists but is empty or malformed, tell the user and regenerate
32
+ (first-time flow), preserving `config.md` if intact.
33
+ - Otherwise run the first-time flow.
34
+
35
+ ## Using an existing index
36
+
37
+ 1. Read `.claude-index/index.md` and `CLAUDE.md` (if present).
38
+ 2. Summarize in 3-5 bullets: structure, stack, feature areas, key entry
39
+ points. Offer to help.
40
+ 3. For later questions, navigate via the Feature Map / File Index and read
41
+ real source only when detail is needed.
42
+
43
+ ## First-time flow
44
+
45
+ ### Step 2: Gather configuration (ask_user)
46
+
47
+ Ask with `ask_user`, defaults offered in every question:
48
+
49
+ 1. **Exclusions** - A) defaults (node_modules, .git, dist, build,
50
+ __pycache__, .venv, vendor, coverage, .next, .nuxt, .cache, target, bin,
51
+ obj, .idea, .vscode) B) add more C) custom list.
52
+ 2. **Priority directories** - A) auto-detect (recommended) B) specify C) all
53
+ equally.
54
+ 3. **Tech stack** - auto-detect unless the user names one.
55
+ 4. **Clean Code Guidelines** (injected into CLAUDE.md) - A) Google strict
56
+ (method 60, file 1000 - recommended) B) Google relaxed (method 600)
57
+ C) custom D) skip.
58
+
59
+ If C: ask **one `ask_user` call per limit** showing default and range -
60
+ MAX_FILE_LINES 1000 (200-5000), MAX_METHOD_LINES 60 (20-600),
61
+ MAX_FUNCTION_PARAMS 5 (2-10), MAX_CYCLOMATIC 10 (5-25); fall back to the
62
+ default on an out-of-range answer and say so in the summary.
63
+ MAX_LINE_LENGTH (default 100, Python 80) and MAX_NESTING_DEPTH (4) are never
64
+ asked. If the user skips every question, use all defaults.
65
+
66
+ Treat the answer as `CleanCodeConfig.preset`: strict | relaxed | custom |
67
+ disabled. D (`disabled`) skips the Clean Code composition below, never adds
68
+ markers, and persists `Enabled: No`.
69
+
70
+ ### Step 3: Scan and analyze
71
+
72
+ 1. Traverse the tree with the exclusion rules (`glob`, never one giant read).
73
+ 2. Detect project type (frontend/backend/fullstack/library/CLI/monorepo),
74
+ languages with percentages, frameworks, entry points.
75
+ 3. Group files by feature/domain and extract exported symbols - full support
76
+ for JS/TS (.js/.jsx/.ts/.tsx/.mjs) and Python; best-effort for Java,
77
+ Kotlin, Go, Rust, C/C++, C#, Ruby, PHP; unknown types are listed without
78
+ symbols.
79
+ 4. Analyze module-level dependencies (import graph).
80
+
81
+ Adaptive sizing: <50 files -> full detail; 50-200 -> full coverage with
82
+ concise descriptions; 200+ -> detail the priority directories, summarize the
83
+ rest, group similar utilities. Over 1000 files after exclusions: warn and
84
+ suggest more exclusions before continuing; sample representative files with
85
+ glob/grep rather than reading everything. Keep language/framework findings in
86
+ working memory - do NOT write an intermediate JSON file.
87
+
88
+ ### Step 4: Write `.claude-index/`
89
+
90
+ 1. `config.md` - exclusions, priorities, tech stack, plus an Index Settings
91
+ block (Generated date, Project Root, Index Version) and a Clean Code
92
+ Settings block (Enabled / Preset / the six limits; when the user picked
93
+ skip, write `Enabled: No`, `Preset: disabled` and the strict numbers so a
94
+ later "enable cleancode" can flip it back).
95
+ 2. `index.md` - follow `templates/index-template.md` in this skill's
96
+ directory: Project Overview, Feature Map (per area: entry file, one-line
97
+ description, key exports with signatures), Module Dependencies, File Index
98
+ (per-directory tables, one line per file).
99
+
100
+ ### Step 5: Compose the Clean Code Guidelines (skip when disabled)
101
+
102
+ Read `templates/cleancode-template.md` and `templates/cleancode-overrides.md`
103
+ from this skill's directory, then:
104
+
105
+ 1. Primary languages = every language with >= 10% of post-exclusion source
106
+ files; if none clears 10%, use the `Other` row.
107
+ 2. Take the **minimum** across all matching rows for each numeric column.
108
+ 3. Apply the user preset: strict/relaxed values intersect with the language
109
+ minimum (never looser than the baseline); custom numbers are honoured
110
+ verbatim with divergence noted.
111
+ 4. Substitute every placeholder: `{{MAX_FILE_LINES}}`, `{{MAX_METHOD_LINES}}`,
112
+ `{{MAX_FUNCTION_PARAMS}}`, `{{MAX_CYCLOMATIC}}`, `{{MAX_LINE_LENGTH}}`,
113
+ `{{MAX_NESTING_DEPTH}}`, `{{PRIMARY_LANGUAGES}}` (comma-joined languages)
114
+ and `{{LANGUAGE_HINTS}}` (one `- Language: note` bullet per matching row,
115
+ deduped by exact string).
116
+ 5. Verify no `{{...}}` placeholder remains. Do not count characters at
117
+ runtime.
118
+
119
+ ### Step 6: Update CLAUDE.md
120
+
121
+ - `## Project Index` section: upsert (replace when present, else append at
122
+ end; create the file when missing). Contents: Location
123
+ `.claude-index/index.md`, Last Updated (YYYY-MM-DD), Contents line, a
124
+ Usage line, and "Regenerate: say 'regenerate index' / '更新索引'".
125
+ - `## Clean Code Guidelines` section (unless disabled): wrap the rendered
126
+ body in `<!-- project-indexer:cleancode:begin v1.1.0 -->` and
127
+ `<!-- project-indexer:cleancode:end -->`. Locate an existing block with
128
+ the version-agnostic regex `<!-- project-indexer:cleancode:begin
129
+ v\d+\.\d+\.\d+ -->` (NEVER a literal-version match) plus the literal end
130
+ marker; fallback: the region from a `## Clean Code Guidelines` heading to
131
+ the next `## ` heading or EOF. Replace the found block; if none, insert
132
+ after the Project Index section (first-insert only; when both sections
133
+ already exist preserve the user's ordering and everything between them).
134
+ Write UTF-8; add a trailing newline when missing.
135
+
136
+ ### Step 7: Report
137
+
138
+ List what was created/updated, the feature-area count, files indexed and
139
+ symbols extracted. Offer to start work.
140
+
141
+ ## Regeneration ("regenerate index" / "更新索引")
142
+
143
+ 1. Read `config.md` and preserve exclusions, priorities, stack.
144
+ 2. Clean Code handling: if CLAUDE.md has markers or the heading, ask
145
+ A) refresh B) keep C) remove; honour `Enabled: No` from config.md by
146
+ skipping silently with one reminder line. When no block exists and
147
+ Enabled is Yes/absent, compose and inject (announce before writing).
148
+ 3. Confirm the plan (exclusions, priorities, cleancode decision) with the
149
+ user, then re-run Steps 3-7.
150
+
151
+ Special triggers: "disable cleancode" removes the block and sets
152
+ `Enabled: No`; "enable cleancode" re-composes it and sets `Enabled: Yes` -
153
+ both without a full rescan.
154
+
155
+ ## Edge cases
156
+
157
+ - Inaccessible directories: list them under a "Skipped Directories" note and
158
+ continue; never fail the whole run for one unreadable path.
159
+ - No recognizable source files: generate a minimal index (overview + file
160
+ listing) and say so.
161
+ - The user pressed Ctrl+I: they already confirmed once - do not re-ask the
162
+ global "proceed?" question, but still ask the configuration questions
163
+ above (or reuse `.claude-index/config.md` when it exists).
@@ -1,46 +1,46 @@
1
- # Clean Code — Language Override Table
2
-
3
- > Read by `project-indexer` at Step 5. The skill intersects the rows below
4
- > with the **primary languages** detected during the scan (any language whose
5
- > source files account for >= 10% of the post-exclusion total).
6
- >
7
- > When two or more rows apply, the skill **takes the minimum** for every
8
- > numeric column. Notes from each matching row are concatenated and rendered
9
- > as bullets in the `{{LANGUAGE_HINTS}}` placeholder of
10
- > `cleancode-template.md`.
11
- >
12
- > Defaults (used when no row matches, i.e. the `Other` row) live in the last
13
- > row. Numeric units: `MAX_FILE_LINES` and `MAX_METHOD_LINES` are physical
14
- > lines of source. `MAX_LINE_LENGTH` is columns. `MAX_FUNCTION_PARAMS` is the
15
- > count of positional + keyword parameters in a single signature.
16
-
17
- | Language | MAX_FILE_LINES | MAX_METHOD_LINES | MAX_LINE_LENGTH | MAX_FUNCTION_PARAMS | Notes |
18
- |-------------|----------------|------------------|-----------------|---------------------|-------|
19
- | TypeScript | 1000 | 60 | 100 | 5 | Prefer `interface` over `type` for public APIs. |
20
- | JavaScript | 1000 | 60 | 100 | 5 | Avoid `any`; use JSDoc when no TS. |
21
- | Python | 800 | 50 | 80 | 5 | PEP 8 + Google docstrings. |
22
- | Go | 800 | 60 | 120 | 4 | Errors as values; no panic in library code. |
23
- | Java | 1500 | 40 | 100 | 5 | Google Java Style. |
24
- | Kotlin | 1500 | 40 | 100 | 5 | KtLint defaults. |
25
- | Rust | 1000 | 60 | 100 | 5 | `clippy::pedantic` recommended. |
26
- | C / C++ | 1000 | 50 | 100 | 5 | Google C++ Style. |
27
- | Other | 1000 | 60 | 100 | 5 | Generic fallback. |
28
-
29
- ## Merge Rules
30
-
31
- 1. **Detection threshold** — only languages with >= 10% of source files (after
32
- exclusions) contribute. If no language clears 10%, use the `Other` row.
33
- 2. **Numeric merge** — `min()` across every matching row, per column.
34
- 3. **Note merge** — collect each matching row's `Notes` cell, dedupe by exact
35
- string match, render as a bullet list. Example for TypeScript + Python:
36
- - `- TypeScript: Prefer interface over type for public APIs.`
37
- - `- Python: PEP 8 + Google docstrings.`
38
- 4. **Fixed defaults (not in the table, applied unconditionally)** —
39
- `MAX_CYCLOMATIC = 10`, `MAX_NESTING_DEPTH = 4`. These can still be
40
- overridden by the user via the Custom preset.
41
-
42
- ## Adding a Language
43
-
44
- When extending this table, keep the column order identical and use the
45
- strictest reasonable value for each cell so the `min()` merge stays
46
- meaningful for polyglot repos.
1
+ # Clean Code — Language Override Table
2
+
3
+ > Read by `project-indexer` at Step 5. The skill intersects the rows below
4
+ > with the **primary languages** detected during the scan (any language whose
5
+ > source files account for >= 10% of the post-exclusion total).
6
+ >
7
+ > When two or more rows apply, the skill **takes the minimum** for every
8
+ > numeric column. Notes from each matching row are concatenated and rendered
9
+ > as bullets in the `{{LANGUAGE_HINTS}}` placeholder of
10
+ > `cleancode-template.md`.
11
+ >
12
+ > Defaults (used when no row matches, i.e. the `Other` row) live in the last
13
+ > row. Numeric units: `MAX_FILE_LINES` and `MAX_METHOD_LINES` are physical
14
+ > lines of source. `MAX_LINE_LENGTH` is columns. `MAX_FUNCTION_PARAMS` is the
15
+ > count of positional + keyword parameters in a single signature.
16
+
17
+ | Language | MAX_FILE_LINES | MAX_METHOD_LINES | MAX_LINE_LENGTH | MAX_FUNCTION_PARAMS | Notes |
18
+ |-------------|----------------|------------------|-----------------|---------------------|-------|
19
+ | TypeScript | 1000 | 60 | 100 | 5 | Prefer `interface` over `type` for public APIs. |
20
+ | JavaScript | 1000 | 60 | 100 | 5 | Avoid `any`; use JSDoc when no TS. |
21
+ | Python | 800 | 50 | 80 | 5 | PEP 8 + Google docstrings. |
22
+ | Go | 800 | 60 | 120 | 4 | Errors as values; no panic in library code. |
23
+ | Java | 1500 | 40 | 100 | 5 | Google Java Style. |
24
+ | Kotlin | 1500 | 40 | 100 | 5 | KtLint defaults. |
25
+ | Rust | 1000 | 60 | 100 | 5 | `clippy::pedantic` recommended. |
26
+ | C / C++ | 1000 | 50 | 100 | 5 | Google C++ Style. |
27
+ | Other | 1000 | 60 | 100 | 5 | Generic fallback. |
28
+
29
+ ## Merge Rules
30
+
31
+ 1. **Detection threshold** — only languages with >= 10% of source files (after
32
+ exclusions) contribute. If no language clears 10%, use the `Other` row.
33
+ 2. **Numeric merge** — `min()` across every matching row, per column.
34
+ 3. **Note merge** — collect each matching row's `Notes` cell, dedupe by exact
35
+ string match, render as a bullet list. Example for TypeScript + Python:
36
+ - `- TypeScript: Prefer interface over type for public APIs.`
37
+ - `- Python: PEP 8 + Google docstrings.`
38
+ 4. **Fixed defaults (not in the table, applied unconditionally)** —
39
+ `MAX_CYCLOMATIC = 10`, `MAX_NESTING_DEPTH = 4`. These can still be
40
+ overridden by the user via the Custom preset.
41
+
42
+ ## Adding a Language
43
+
44
+ When extending this table, keep the column order identical and use the
45
+ strictest reasonable value for each cell so the `min()` merge stays
46
+ meaningful for polyglot repos.