scopecairn 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,22 @@
1
- # ScopeCairn
1
+ <p align="center">
2
+ <img src="assets/icon.png" alt="ScopeCairn Icon" width="140" height="140" style="border-radius: 32px;" />
3
+ </p>
4
+
5
+ <h1 align="center">ScopeCairn</h1>
6
+
7
+ <p align="center">
8
+ <strong>Local-first codebase intelligence &amp; task scope guard for AI coding agents.</strong><br>
9
+ <em>Understand before exploring. Retrieve before reading.</em>
10
+ </p>
11
+
12
+ <p align="center">
13
+ <a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%3E%3D20-22c55e.svg?style=flat-square" alt="Node.js version"></a>
14
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-6366f1.svg?style=flat-square" alt="License: MIT"></a>
15
+ <img src="https://img.shields.io/badge/local--first-100%25-00f0ff.svg?style=flat-square" alt="Local-First">
16
+ <img src="https://img.shields.io/badge/telemetry-zero-a855f7.svg?style=flat-square" alt="Zero Telemetry">
17
+ </p>
18
+
19
+ ---
2
20
 
3
21
  Local-first codebase intelligence layer for AI coding agents.
4
22
  Understand the codebase, then give the agent only what it needs:
@@ -58,6 +76,16 @@ No MCP server, no embeddings, no network calls, no telemetry.
58
76
  click-for-details side panel (callers, callees, centrality scores).
59
77
  Nodes sized by symbols/PageRank, colored by Louvain community.
60
78
  Pan, zoom, hover inspect. Double-click to open, no server.
79
+ - **Decision log** — `scopecairn decide "pakai X karena Y"` records an
80
+ architectural decision once; it is carried into every later
81
+ `context` call, so the agent stops re-litigating settled choices.
82
+ - **Definition of Done check** — `verify --dod` rates each DoD item and
83
+ is honest about what it cannot know: `pass` only for what the machine
84
+ verified (scope, index freshness), `warn`/`fail` where it has evidence,
85
+ `manual` for judgement calls. Never a fabricated "done".
86
+ - **Local usage report** — `status --usage` reads the local invocation
87
+ log: commands used, closed-loop rate (`scan` after a task), average
88
+ symbols per task. Local only, never leaves the machine.
61
89
  - **Graph export for external tools** — `scopecairn graph --export
62
90
  mermaid|graphml|dot|json` writes `.scopecairn/graph.<ext>` for PR
63
91
  diagrams (Mermaid), Gephi/Cytoscape (GraphML), Graphviz (DOT),
@@ -118,9 +146,10 @@ scopecairn scan # index repository (--rebuild, --cle
118
146
  scopecairn context "tambah fitur auth" # AI agent task context + scope
119
147
  scopecairn impact src/indexer.ts # blast radius & affected tests (--run-tests)
120
148
  scopecairn graph buildContext # inspect relations, path (--to), export (--export)
121
- scopecairn verify # pre-commit safety guard (--diff, --arch)
122
- scopecairn status # index statistics & health checks (--doctor, --html)
149
+ scopecairn verify --dod # pre-commit safety guard (--diff, --arch, --dod)
150
+ scopecairn status --usage # index statistics & health checks (--doctor, --html)
123
151
  scopecairn read symbol indexFileSymbols # symbol-level source excerpt
152
+ scopecairn decide "graf di SQLite, tanpa embedding" # catat keputusan arsitektur
124
153
  ```
125
154
 
126
155
  Per-agent installers (instead of `init --agents …`):
@@ -144,8 +173,8 @@ ScopeCairn organizes its capabilities into **6 core commands** aligned with code
144
173
  | `context "<task>"` | **AI Agent Context & Scope:** Main agent entry point with auto-refresh, task classification, relevant context, task scope, and Task Guard. Options: `--escalate`, `--mode NORMAL\|FAST\|SAFE\|AUDIT`, `--max-tokens N`, `--no-history`, `--with-diff`, `--json`. |
145
174
  | `impact <target>` | **Blast Radius & Test Selection:** Change impact analysis across direct, indirect, tests, UI components, and API clients. Options: `--run-tests` (run affected tests directly), `--tests` (list affected tests only), `--repos [list]` (cross-repo blast radius). |
146
175
  | `graph [symbol]` | **Knowledge Graph & Navigation:** Symbol relations, PageRank centrality, community clusters, and cycle status. Options: `--to <target>` (shortest multi-hop call path), `--export <fmt>` (`mermaid\|graphml\|dot\|json`). |
147
- | `verify` | **Pre-Commit Safety Guard:** Working tree check against protected files, task scope creep, and circular dependency regressions. Options: `--diff` (structural symbol-level diff vs HEAD), `--arch` (architectural layer rules), `--strict`, `--task <t>`. |
148
- | `status` | **Health & Diagnostics:** Index statistics and metadata. Options: `--doctor` (integration and adapter health check), `--verbose`, `--html` (generate local HTML dashboard). |
176
+ | `verify` | **Pre-Commit Safety Guard:** Working tree check against protected files, task scope creep, and circular dependency regressions. Options: `--diff` (structural symbol-level diff vs HEAD), `--arch` (architectural layer rules), `--dod` (Definition of Done: verified / warned / manual, never a claimed pass), `--strict`, `--task <t>`. |
177
+ | `status` | **Health & Diagnostics:** Index statistics and metadata. Options: `--doctor` (integration and adapter health check), `--usage` (local usage & compliance report), `--verbose`, `--html` (generate local HTML dashboard). |
149
178
 
150
179
  ### Helper & Setup Commands
151
180
 
@@ -153,6 +182,7 @@ ScopeCairn organizes its capabilities into **6 core commands** aligned with code
153
182
  | ------- | ----------- |
154
183
  | `init [path]` | Initial indexing + Skill, Workflow, detected agent skills (`--agents …\|all`). |
155
184
  | `read symbol <name>` | Symbol-level source excerpt (not whole files). |
185
+ | `decide "…"` | Record an architectural decision into `.scopecairn/decisions.md` (no argument: list them). Read back by `context`. |
156
186
  | `benchmark [--tune]` | Retrieval recall, irrelevant ratio, context reduction + weight tuning (dev-only, hidden from `--help`). |
157
187
  | `<agent> install` | Agent installers: `antigravity`, `claude`, `cursor`, `windsurf`, `copilot`, `kiro`, `opencode`. |
158
188
 
@@ -0,0 +1,137 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 260" width="100%" height="100%">
2
+ <defs>
3
+ <!-- Background Gradient -->
4
+ <linearGradient id="bannerBg" x1="0%" y1="0%" x2="100%" y2="100%">
5
+ <stop offset="0%" stop-color="#070A12" />
6
+ <stop offset="50%" stop-color="#0B101E" />
7
+ <stop offset="100%" stop-color="#05070D" />
8
+ </linearGradient>
9
+
10
+ <!-- Border Stroke -->
11
+ <linearGradient id="bannerBorder" x1="0%" y1="0%" x2="100%" y2="0%">
12
+ <stop offset="0%" stop-color="#00F0FF" stop-opacity="0.6" />
13
+ <stop offset="35%" stop-color="#6366F1" stop-opacity="0.3" />
14
+ <stop offset="70%" stop-color="#A855F7" stop-opacity="0.6" />
15
+ <stop offset="100%" stop-color="#00F0FF" stop-opacity="0.1" />
16
+ </linearGradient>
17
+
18
+ <!-- Text Title Gradient -->
19
+ <linearGradient id="titleGrad" x1="0%" y1="0%" x2="100%" y2="0%">
20
+ <stop offset="0%" stop-color="#38BDF8" />
21
+ <stop offset="45%" stop-color="#00F0FF" />
22
+ <stop offset="100%" stop-color="#C084FC" />
23
+ </linearGradient>
24
+
25
+ <!-- Glow Filter -->
26
+ <filter id="bannerGlow" x="-20%" y="-20%" width="140%" height="140%">
27
+ <feGaussianBlur stdDeviation="6" result="blur" />
28
+ <feMerge>
29
+ <feMergeNode in="blur" />
30
+ <feMergeNode in="SourceGraphic" />
31
+ </feMerge>
32
+ </filter>
33
+
34
+ <filter id="softGlow" x="-30%" y="-30%" width="160%" height="160%">
35
+ <feGaussianBlur stdDeviation="16" result="blur" />
36
+ </filter>
37
+ </defs>
38
+
39
+ <!-- Banner Outer Card -->
40
+ <rect x="2" y="2" width="956" height="256" rx="20" fill="url(#bannerBg)" stroke="url(#bannerBorder)" stroke-width="1.5" />
41
+
42
+ <!-- Background Decorative Grid Lines -->
43
+ <g stroke="#1E293B" stroke-width="0.7" opacity="0.35">
44
+ <line x1="0" y1="65" x2="960" y2="65" />
45
+ <line x1="0" y1="130" x2="960" y2="130" />
46
+ <line x1="0" y1="195" x2="960" y2="195" />
47
+ <line x1="240" y1="0" x2="240" y2="260" />
48
+ <line x1="480" y1="0" x2="480" y2="260" />
49
+ <line x1="720" y1="0" x2="720" y2="260" />
50
+ </g>
51
+
52
+ <!-- Ambient Glow Pods -->
53
+ <circle cx="140" cy="130" r="110" fill="#00F0FF" opacity="0.12" filter="url(#softGlow)" />
54
+ <circle cx="210" cy="90" r="80" fill="#8B5CF6" opacity="0.15" filter="url(#softGlow)" />
55
+
56
+ <!-- ==================== LEFT: EMBEDDED ICON ==================== -->
57
+ <g transform="translate(40, 20)">
58
+ <!-- Outer Scope Ring -->
59
+ <circle cx="110" cy="110" r="85" fill="none" stroke="#6366F1" stroke-width="1.2" stroke-dasharray="3 7" opacity="0.5" />
60
+ <circle cx="110" cy="110" r="68" fill="none" stroke="#00F0FF" stroke-width="1.8" opacity="0.8" filter="url(#bannerGlow)" />
61
+ <circle cx="110" cy="82" r="38" fill="none" stroke="#A855F7" stroke-width="2" opacity="0.85" filter="url(#bannerGlow)" />
62
+
63
+ <!-- Scope Crosshairs -->
64
+ <line x1="110" y1="18" x2="110" y2="52" stroke="#00F0FF" stroke-width="2" stroke-linecap="round" filter="url(#bannerGlow)" />
65
+ <line x1="110" y1="168" x2="110" y2="202" stroke="#00F0FF" stroke-width="2" stroke-linecap="round" filter="url(#bannerGlow)" />
66
+ <line x1="18" y1="110" x2="52" y2="110" stroke="#00F0FF" stroke-width="2" stroke-linecap="round" filter="url(#bannerGlow)" />
67
+ <line x1="168" y1="110" x2="202" y2="110" stroke="#00F0FF" stroke-width="2" stroke-linecap="round" filter="url(#bannerGlow)" />
68
+
69
+ <!-- Cairn Stones Stack -->
70
+ <!-- Base Stone -->
71
+ <polygon points="50,158 110,168 170,158 160,176 110,183 60,176" fill="#141E33" stroke="#334155" stroke-width="1" />
72
+ <polygon points="50,158 75,145 145,145 170,158 110,168" fill="#1E293B" stroke="#475569" stroke-width="1" />
73
+ <path d="M 60,176 L 110,183 L 160,176" fill="none" stroke="#00F0FF" stroke-width="1.8" opacity="0.7" filter="url(#bannerGlow)" />
74
+
75
+ <!-- Middle Stone -->
76
+ <polygon points="72,118 92,107 128,107 148,118 110,127" fill="#334155" stroke="#475569" stroke-width="1" />
77
+ <polygon points="72,118 110,127 110,143 78,134" fill="#1E293B" stroke="#334155" stroke-width="1" />
78
+ <polygon points="110,127 148,118 142,134 110,143" fill="#0F172A" stroke="#334155" stroke-width="1" />
79
+ <path d="M 78,134 L 110,143 L 142,134" fill="none" stroke="#A855F7" stroke-width="1.8" opacity="0.9" filter="url(#bannerGlow)" />
80
+
81
+ <!-- Apex Stone -->
82
+ <polygon points="110,60 88,94 110,100" fill="#334155" stroke="#475569" stroke-width="1" />
83
+ <polygon points="110,60 110,100 132,94" fill="#1E293B" stroke="#334155" stroke-width="1" />
84
+ <line x1="110" y1="60" x2="110" y2="100" stroke="#00F0FF" stroke-width="1.8" filter="url(#bannerGlow)" />
85
+ <circle cx="110" cy="82" r="3.5" fill="#FFFFFF" filter="url(#bannerGlow)" />
86
+ <circle cx="110" cy="82" r="1.8" fill="#00F0FF" />
87
+
88
+ <!-- Constellation Graph Node Accents -->
89
+ <circle cx="158" cy="85" r="3" fill="#00F0FF" filter="url(#bannerGlow)" />
90
+ <circle cx="62" cy="100" r="2.5" fill="#A855F7" />
91
+ </g>
92
+
93
+ <!-- ==================== RIGHT: BRAND IDENTITY ==================== -->
94
+ <g transform="translate(290, 48)">
95
+ <!-- Small Category Label -->
96
+ <text x="0" y="24" fill="#38BDF8" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif" font-size="12" font-weight="700" letter-spacing="3.5" opacity="0.9">LOCAL-FIRST AGENT INTELLIGENCE</text>
97
+
98
+ <!-- Main Title -->
99
+ <text x="0" y="74" fill="url(#titleGrad)" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif" font-size="44" font-weight="800" letter-spacing="-0.5">ScopeCairn</text>
100
+
101
+ <!-- Subtitle / Mission -->
102
+ <text x="0" y="108" fill="#94A3B8" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif" font-size="15" font-weight="400" letter-spacing="0.2">
103
+ Understand before exploring. Precise task scope &amp; codebase knowledge graph for AI coding agents.
104
+ </text>
105
+
106
+ <!-- Feature Badges / Pills -->
107
+ <g transform="translate(0, 134)">
108
+ <!-- Badge 1: Knowledge Graph -->
109
+ <g transform="translate(0, 0)">
110
+ <rect x="0" y="0" width="144" height="26" rx="13" fill="#0E1726" stroke="#00F0FF" stroke-opacity="0.4" stroke-width="1" />
111
+ <circle cx="13" cy="13" r="3.5" fill="#00F0FF" />
112
+ <text x="24" y="17" fill="#E2E8F0" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="11" font-weight="600">Knowledge Graph</text>
113
+ </g>
114
+
115
+ <!-- Badge 2: Scope Guard -->
116
+ <g transform="translate(154, 0)">
117
+ <rect x="0" y="0" width="138" height="26" rx="13" fill="#141126" stroke="#A855F7" stroke-opacity="0.4" stroke-width="1" />
118
+ <circle cx="13" cy="13" r="3.5" fill="#A855F7" />
119
+ <text x="24" y="17" fill="#E2E8F0" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="11" font-weight="600">Task Scope Guard</text>
120
+ </g>
121
+
122
+ <!-- Badge 3: Impact Analysis -->
123
+ <g transform="translate(302, 0)">
124
+ <rect x="0" y="0" width="134" height="26" rx="13" fill="#0C1B2A" stroke="#38BDF8" stroke-opacity="0.4" stroke-width="1" />
125
+ <circle cx="13" cy="13" r="3.5" fill="#38BDF8" />
126
+ <text x="24" y="17" fill="#E2E8F0" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="11" font-weight="600">Impact Analysis</text>
127
+ </g>
128
+
129
+ <!-- Badge 4: Zero Telemetry -->
130
+ <g transform="translate(446, 0)">
131
+ <rect x="0" y="0" width="134" height="26" rx="13" fill="#0B171B" stroke="#10B981" stroke-opacity="0.4" stroke-width="1" />
132
+ <circle cx="13" cy="13" r="3.5" fill="#10B981" />
133
+ <text x="24" y="17" fill="#E2E8F0" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="11" font-weight="600">Zero Telemetry</text>
134
+ </g>
135
+ </g>
136
+ </g>
137
+ </svg>
Binary file
Binary file
@@ -0,0 +1,210 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="100%" height="100%">
2
+ <defs>
3
+ <!-- Background Gradient -->
4
+ <radialGradient id="bgGlow" cx="50%" cy="45%" r="65%">
5
+ <stop offset="0%" stop-color="#141E33" />
6
+ <stop offset="60%" stop-color="#0B0F19" />
7
+ <stop offset="100%" stop-color="#05070D" />
8
+ </radialGradient>
9
+
10
+ <!-- Border Gradient -->
11
+ <linearGradient id="borderGrad" x1="0%" y1="0%" x2="100%" y2="100%">
12
+ <stop offset="0%" stop-color="#00F0FF" stop-opacity="0.8" />
13
+ <stop offset="50%" stop-color="#6366F1" stop-opacity="0.4" />
14
+ <stop offset="100%" stop-color="#A855F7" stop-opacity="0.8" />
15
+ </linearGradient>
16
+
17
+ <!-- Scope Laser Gradient -->
18
+ <linearGradient id="cyanLaser" x1="0%" y1="0%" x2="100%" y2="100%">
19
+ <stop offset="0%" stop-color="#38BDF8" />
20
+ <stop offset="50%" stop-color="#00F0FF" />
21
+ <stop offset="100%" stop-color="#0284C7" />
22
+ </linearGradient>
23
+
24
+ <linearGradient id="purpleLaser" x1="0%" y1="0%" x2="100%" y2="100%">
25
+ <stop offset="0%" stop-color="#C084FC" />
26
+ <stop offset="100%" stop-color="#7C3AED" />
27
+ </linearGradient>
28
+
29
+ <!-- Stone Obsidian Shading -->
30
+ <!-- Top Apex Stone -->
31
+ <linearGradient id="apexLeft" x1="30%" y1="0%" x2="70%" y2="100%">
32
+ <stop offset="0%" stop-color="#334155" />
33
+ <stop offset="100%" stop-color="#0F172A" />
34
+ </linearGradient>
35
+ <linearGradient id="apexRight" x1="70%" y1="0%" x2="30%" y2="100%">
36
+ <stop offset="0%" stop-color="#1E293B" />
37
+ <stop offset="100%" stop-color="#090D16" />
38
+ </linearGradient>
39
+ <linearGradient id="apexBottom" x1="50%" y1="0%" x2="50%" y2="100%">
40
+ <stop offset="0%" stop-color="#475569" />
41
+ <stop offset="100%" stop-color="#1E293B" />
42
+ </linearGradient>
43
+
44
+ <!-- Middle Stone -->
45
+ <linearGradient id="midTop" x1="20%" y1="0%" x2="80%" y2="100%">
46
+ <stop offset="0%" stop-color="#334155" />
47
+ <stop offset="100%" stop-color="#1E293B" />
48
+ </linearGradient>
49
+ <linearGradient id="midFront" x1="50%" y1="0%" x2="50%" y2="100%">
50
+ <stop offset="0%" stop-color="#1E293B" />
51
+ <stop offset="100%" stop-color="#0A0E17" />
52
+ </linearGradient>
53
+ <linearGradient id="midLeft" x1="0%" y1="50%" x2="100%" y2="50%">
54
+ <stop offset="0%" stop-color="#2D3748" />
55
+ <stop offset="100%" stop-color="#141A24" />
56
+ </linearGradient>
57
+
58
+ <!-- Base Stone -->
59
+ <linearGradient id="baseTop" x1="0%" y1="0%" x2="100%" y2="100%">
60
+ <stop offset="0%" stop-color="#334155" />
61
+ <stop offset="100%" stop-color="#1E293B" />
62
+ </linearGradient>
63
+ <linearGradient id="baseFront" x1="50%" y1="0%" x2="50%" y2="100%">
64
+ <stop offset="0%" stop-color="#1A2234" />
65
+ <stop offset="100%" stop-color="#080C14" />
66
+ </linearGradient>
67
+
68
+ <!-- Filters for Glow Effect -->
69
+ <filter id="laserGlow" x="-30%" y="-30%" width="160%" height="160%">
70
+ <feGaussianBlur stdDeviation="5" result="blur" />
71
+ <feMerge>
72
+ <feMergeNode in="blur" />
73
+ <feMergeNode in="blur" />
74
+ <feMergeNode in="SourceGraphic" />
75
+ </feMerge>
76
+ </filter>
77
+
78
+ <filter id="intenseGlow" x="-50%" y="-50%" width="200%" height="200%">
79
+ <feGaussianBlur stdDeviation="9" result="blur" />
80
+ <feMerge>
81
+ <feMergeNode in="blur" />
82
+ <feMergeNode in="SourceGraphic" />
83
+ </feMerge>
84
+ </filter>
85
+ </defs>
86
+
87
+ <!-- Container App Squircle (macOS / Modern Icon Standard) -->
88
+ <rect x="16" y="16" width="480" height="480" rx="108" fill="url(#bgGlow)" stroke="url(#borderGrad)" stroke-width="2.5" />
89
+
90
+ <!-- Ambient Internal Backdrop Glow -->
91
+ <circle cx="256" cy="240" r="140" fill="#00F0FF" opacity="0.07" filter="url(#intenseGlow)" />
92
+ <circle cx="256" cy="180" r="80" fill="#8B5CF6" opacity="0.12" filter="url(#intenseGlow)" />
93
+
94
+ <!-- Target Scope Reticle Elements -->
95
+ <!-- Outer Dotted Calibration Ring -->
96
+ <circle cx="256" cy="256" r="190" fill="none" stroke="#6366F1" stroke-width="1.5" stroke-dasharray="3 9" opacity="0.45" />
97
+
98
+ <!-- Scope HUD Corner Brackets -->
99
+ <g stroke="#00F0FF" stroke-width="2" fill="none" opacity="0.4">
100
+ <!-- Top-Left Bracket -->
101
+ <path d="M 80 120 L 80 80 L 120 80" />
102
+ <!-- Top-Right Bracket -->
103
+ <path d="M 392 80 L 432 80 L 432 120" />
104
+ <!-- Bottom-Left Bracket -->
105
+ <path d="M 80 392 L 80 432 L 120 432" />
106
+ <!-- Bottom-Right Bracket -->
107
+ <path d="M 432 392 L 432 432 L 392 432" />
108
+ </g>
109
+
110
+ <!-- Concentric Targeting Rings (Mid + Upper Focus) -->
111
+ <circle cx="256" cy="256" r="150" fill="none" stroke="#00F0FF" stroke-width="2" opacity="0.75" filter="url(#laserGlow)" />
112
+ <circle cx="256" cy="190" r="85" fill="none" stroke="#A855F7" stroke-width="2.5" opacity="0.8" filter="url(#laserGlow)" />
113
+ <circle cx="256" cy="190" r="48" fill="none" stroke="#00F0FF" stroke-width="1.8" opacity="0.9" />
114
+
115
+ <!-- Scope Reticle Crosshairs (Crosslines with precise gaps) -->
116
+ <!-- Main Vertical Scope Line -->
117
+ <line x1="256" y1="75" x2="256" y2="135" stroke="#00F0FF" stroke-width="2.5" stroke-linecap="round" filter="url(#laserGlow)" />
118
+ <line x1="256" y1="365" x2="256" y2="435" stroke="#00F0FF" stroke-width="2.5" stroke-linecap="round" filter="url(#laserGlow)" />
119
+ <line x1="256" y1="140" x2="256" y2="350" stroke="#00F0FF" stroke-width="1.2" stroke-dasharray="4 6" opacity="0.5" />
120
+
121
+ <!-- Main Horizontal Scope Line -->
122
+ <line x1="75" y1="256" x2="135" y2="256" stroke="#00F0FF" stroke-width="2.5" stroke-linecap="round" filter="url(#laserGlow)" />
123
+ <line x1="377" y1="256" x2="437" y2="256" stroke="#00F0FF" stroke-width="2.5" stroke-linecap="round" filter="url(#laserGlow)" />
124
+
125
+ <!-- Precision Sub-scope Crosshair at Apex Focal Center (256, 190) -->
126
+ <line x1="180" y1="190" x2="215" y2="190" stroke="#38BDF8" stroke-width="2" stroke-linecap="round" />
127
+ <line x1="297" y1="190" x2="332" y2="190" stroke="#38BDF8" stroke-width="2" stroke-linecap="round" />
128
+
129
+ <!-- ==================== THE CAIRN STONES ==================== -->
130
+
131
+ <!-- BASE STONE (Foundation / Repository Grounding) -->
132
+ <g id="base-stone">
133
+ <!-- Base Shadow / Glow Rim -->
134
+ <ellipse cx="256" cy="385" rx="145" ry="32" fill="#00F0FF" opacity="0.1" filter="url(#laserGlow)" />
135
+
136
+ <!-- Facets of Base Stone -->
137
+ <!-- Front Face -->
138
+ <polygon points="120,365 256,388 392,365 372,405 256,418 140,405" fill="url(#baseFront)" stroke="#1E293B" stroke-width="1" />
139
+ <!-- Top Face -->
140
+ <polygon points="120,365 170,335 342,335 392,365 256,388" fill="url(#baseTop)" stroke="#334155" stroke-width="1" />
141
+ <!-- Bottom Bevel Rim Highlight -->
142
+ <path d="M 140,405 L 256,418 L 372,405" fill="none" stroke="#00F0FF" stroke-width="2" opacity="0.65" filter="url(#laserGlow)" />
143
+
144
+ <!-- Codebase Knowledge Graph Circuit Trace on Base Stone -->
145
+ <path d="M 165,372 L 210,378 L 245,368 L 295,380 L 340,368" fill="none" stroke="#00F0FF" stroke-width="1.8" opacity="0.75" />
146
+ <circle cx="210" cy="378" r="3.5" fill="#00F0FF" filter="url(#laserGlow)" />
147
+ <circle cx="245" cy="368" r="3" fill="#A855F7" />
148
+ <circle cx="295" cy="380" r="3.5" fill="#00F0FF" filter="url(#laserGlow)" />
149
+ </g>
150
+
151
+ <!-- MIDDLE STONE (Task Context & Module Balance) -->
152
+ <g id="middle-stone">
153
+ <!-- Floating Shadow between base and middle -->
154
+ <ellipse cx="256" cy="318" rx="100" ry="16" fill="#000000" opacity="0.6" />
155
+
156
+ <!-- Facets of Middle Stone -->
157
+ <!-- Top Facet -->
158
+ <polygon points="170,270 215,245 297,245 342,270 256,290" fill="url(#midTop)" stroke="#475569" stroke-width="1" />
159
+ <!-- Left Facet -->
160
+ <polygon points="170,270 256,290 256,325 185,305" fill="url(#midLeft)" stroke="#1E293B" stroke-width="1" />
161
+ <!-- Right Facet -->
162
+ <polygon points="256,290 342,270 327,305 256,325" fill="url(#midFront)" stroke="#1E293B" stroke-width="1" />
163
+
164
+ <!-- Edge Neon Accent Highlight -->
165
+ <path d="M 170,270 L 256,290 L 342,270" fill="none" stroke="#818CF8" stroke-width="2" opacity="0.8" />
166
+ <path d="M 185,305 L 256,325 L 327,305" fill="none" stroke="#A855F7" stroke-width="2.2" opacity="0.85" filter="url(#laserGlow)" />
167
+
168
+ <!-- Graph Relation Line (Edge) -->
169
+ <path d="M 205,282 L 235,275 L 275,295 L 305,280" fill="none" stroke="#38BDF8" stroke-width="1.5" opacity="0.8" />
170
+ <circle cx="235" cy="275" r="3" fill="#38BDF8" filter="url(#laserGlow)" />
171
+ <circle cx="275" cy="295" r="3.5" fill="#C084FC" filter="url(#laserGlow)" />
172
+ </g>
173
+
174
+ <!-- APEX STONE (The Summit / Target Scope Focal Beacon) -->
175
+ <g id="apex-stone">
176
+ <!-- Hover Shadow -->
177
+ <ellipse cx="256" cy="235" rx="50" ry="10" fill="#000000" opacity="0.7" />
178
+
179
+ <!-- Facets of Apex Jewel / Pyramid Stone -->
180
+ <!-- Left Facet -->
181
+ <polygon points="256,140 205,215 256,228" fill="url(#apexLeft)" stroke="#475569" stroke-width="1" />
182
+ <!-- Right Facet -->
183
+ <polygon points="256,140 256,228 307,215" fill="url(#apexRight)" stroke="#334155" stroke-width="1" />
184
+ <!-- Top Ridge Line -->
185
+ <line x1="256" y1="140" x2="256" y2="228" stroke="#00F0FF" stroke-width="2" opacity="0.9" filter="url(#laserGlow)" />
186
+
187
+ <!-- Rim Accents -->
188
+ <path d="M 205,215 L 256,228 L 307,215" fill="none" stroke="#00F0FF" stroke-width="2.5" opacity="0.9" filter="url(#laserGlow)" />
189
+
190
+ <!-- Focal Center Reticle Core -->
191
+ <circle cx="256" cy="190" r="5" fill="#FFFFFF" filter="url(#intenseGlow)" />
192
+ <circle cx="256" cy="190" r="2.5" fill="#00F0FF" />
193
+ </g>
194
+
195
+ <!-- Constellation / Knowledge Graph Nodes floating around -->
196
+ <g id="graph-nodes">
197
+ <circle cx="370" cy="195" r="4" fill="#00F0FF" opacity="0.85" filter="url(#laserGlow)" />
198
+ <line x1="340" y1="210" x2="370" y2="195" stroke="#00F0FF" stroke-width="1" stroke-dasharray="2 3" opacity="0.5" />
199
+
200
+ <circle cx="140" cy="225" r="3.5" fill="#A855F7" opacity="0.85" filter="url(#laserGlow)" />
201
+ <line x1="170" y1="240" x2="140" y2="225" stroke="#A855F7" stroke-width="1" stroke-dasharray="2 3" opacity="0.5" />
202
+
203
+ <circle cx="345" cy="330" r="3.5" fill="#38BDF8" opacity="0.8" filter="url(#laserGlow)" />
204
+ <circle cx="165" cy="325" r="4" fill="#00F0FF" opacity="0.8" filter="url(#laserGlow)" />
205
+ </g>
206
+
207
+ <!-- Calibrated Boundary Angle Marks (Degree coordinates) -->
208
+ <text x="256" y="60" text-anchor="middle" fill="#00F0FF" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, monospace" font-size="11" font-weight="700" letter-spacing="3" opacity="0.75">SCOPE·CAIRN</text>
209
+ <text x="256" y="465" text-anchor="middle" fill="#818CF8" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, monospace" font-size="9" font-weight="600" letter-spacing="4" opacity="0.6">CODEBASE INTELLIGENCE</text>
210
+ </svg>
@@ -17,7 +17,7 @@ function loadDatabaseSync() {
17
17
  }
18
18
  var DATA_DIR_NAME = ".scopecairn";
19
19
  var DB_FILE_NAME = "scopecairn.db";
20
- var SCHEMA_VERSION = 7;
20
+ var SCHEMA_VERSION = 8;
21
21
  function dataDir(repoRoot) {
22
22
  return path.join(repoRoot, DATA_DIR_NAME);
23
23
  }
@@ -85,6 +85,17 @@ function openDb(repoRoot) {
85
85
  reason TEXT NOT NULL DEFAULT ''
86
86
  );
87
87
  CREATE INDEX IF NOT EXISTS idx_task_context_task ON task_context(task_id);
88
+ -- Scope yang DIRENDER ke agent (Required/Optional/Protected), disimpan
89
+ -- per task. Tanpa ini verify --task harus menghitung ulang scope dari
90
+ -- task string, dan hasilnya bisa berbeda dari yang benar-benar dilihat
91
+ -- agent (co-change history, --escalate, task SIMPLE) \u2192 false positive.
92
+ CREATE TABLE IF NOT EXISTS task_scope (
93
+ task_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
94
+ path TEXT NOT NULL,
95
+ tier TEXT NOT NULL,
96
+ PRIMARY KEY (task_id, path)
97
+ );
98
+ CREATE INDEX IF NOT EXISTS idx_task_scope_task ON task_scope(task_id);
88
99
  -- Fase 5: invocation log untuk compliance rate (AI-5, \xA718).
89
100
  CREATE TABLE IF NOT EXISTS invocations (
90
101
  id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -138,6 +149,15 @@ function openDb(repoRoot) {
138
149
  );
139
150
  CREATE INDEX IF NOT EXISTS idx_commit_files_sha ON commit_files(sha);
140
151
  CREATE INDEX IF NOT EXISTS idx_commit_files_path ON commit_files(path);
152
+ -- Cache fan-in (jumlah relasi masuk per simbol). Dipakai ranking
153
+ -- retrieval: tanpa cache, retrieve() menghitung ulang
154
+ -- GROUP BY target_id di seluruh tabel relationships pada SETIAP
155
+ -- pemanggilan \u2014 O(E) penuh, dan itu bottleneck utama di repo besar.
156
+ -- Dipopulate ulang di akhir scanRepository (satu lintasan GROUP BY).
157
+ CREATE TABLE IF NOT EXISTS fanin (
158
+ node_id INTEGER PRIMARY KEY,
159
+ n INTEGER NOT NULL
160
+ );
141
161
  CREATE VIRTUAL TABLE IF NOT EXISTS commit_fts USING fts5(
142
162
  sha UNINDEXED, subject, body, paths
143
163
  );
@@ -157,10 +177,17 @@ function openDb(repoRoot) {
157
177
  `UPDATE relationships SET evidence = 'INFERRED'
158
178
  WHERE relationship_type IN ('QUERIES','ROUTES_TO','TESTS') AND evidence = 'EXTRACTED'`
159
179
  );
160
- db.exec(
161
- `UPDATE relationships SET evidence = 'AMBIGUOUS'
162
- WHERE relationship_type = 'CALLS' AND confidence < 1.0 AND evidence = 'EXTRACTED'`
163
- );
180
+ const CALLS_BACKFILL_KEY = "migration_calls_evidence_v1";
181
+ const callsBackfilled = db.prepare(`SELECT value FROM meta WHERE key = ?`).get(CALLS_BACKFILL_KEY);
182
+ if (!callsBackfilled) {
183
+ db.exec(
184
+ `UPDATE relationships SET evidence = 'AMBIGUOUS'
185
+ WHERE relationship_type = 'CALLS' AND confidence < 1.0 AND evidence = 'EXTRACTED'`
186
+ );
187
+ db.prepare(`INSERT INTO meta(key, value) VALUES (?, '1') ON CONFLICT(key) DO NOTHING`).run(
188
+ CALLS_BACKFILL_KEY
189
+ );
190
+ }
164
191
  return db;
165
192
  }
166
193
  function hashContent(buf) {
@@ -295,54 +322,17 @@ function ensureProtectedFile(repoRoot) {
295
322
  }
296
323
  }
297
324
 
298
- // src/scope/scope.ts
299
- function computeScope(highFiles, mediumFiles, testFiles, patterns, historyOptional) {
300
- const required = [];
301
- const optional = [];
302
- const protectedFiles = [];
303
- const seen = /* @__PURE__ */ new Set();
304
- const place = (f) => {
305
- if (seen.has(f)) return;
306
- seen.add(f);
307
- if (isProtected(f, patterns)) protectedFiles.push(f);
308
- else if (highFiles.includes(f)) required.push(f);
309
- else optional.push(f);
310
- };
311
- for (const f of highFiles) place(f);
312
- for (const f of mediumFiles) place(f);
313
- for (const t of testFiles) {
314
- if (seen.has(t)) continue;
315
- seen.add(t);
316
- if (isProtected(t, patterns)) protectedFiles.push(t);
317
- else optional.push(t);
318
- }
319
- for (const h of historyOptional ?? []) {
320
- if (seen.has(h)) continue;
321
- seen.add(h);
322
- if (isProtected(h, patterns)) protectedFiles.push(h);
323
- else optional.push(h);
324
- }
325
- return { required, optional, protected: protectedFiles };
326
- }
327
- function scopeBlock(scope) {
328
- const fmt = (xs) => xs.length > 0 ? xs.join(", ") : "-";
329
- return `## Scope
330
- Required: ${fmt(scope.required)}
331
- Optional: ${fmt(scope.optional)}
332
- Protected: ${fmt(scope.protected)}
333
- `;
334
- }
335
-
336
325
  export {
337
326
  dataDir,
338
327
  dbPath,
339
328
  openDb,
340
329
  hashContent,
330
+ DEFAULT_PROTECTED_PATTERNS,
341
331
  matchPattern,
342
332
  loadProtectedPatterns,
343
333
  isProtected,
334
+ SECRET_PATTERNS,
335
+ isSecretFile,
344
336
  isIndexableMetaFile,
345
- ensureProtectedFile,
346
- computeScope,
347
- scopeBlock
337
+ ensureProtectedFile
348
338
  };
@@ -2,71 +2,10 @@
2
2
  import {
3
3
  logError
4
4
  } from "./chunk-OPA4TMAT.js";
5
-
6
- // src/retrieval/tokenize.ts
7
- var STOP = /* @__PURE__ */ new Set([
8
- "the",
9
- "a",
10
- "an",
11
- "of",
12
- "to",
13
- "in",
14
- "for",
15
- "on",
16
- "with",
17
- "and",
18
- "or",
19
- "src",
20
- "lib",
21
- "app",
22
- "test",
23
- "tests",
24
- "spec"
25
- ]);
26
- function stemVariants(t) {
27
- const out = /* @__PURE__ */ new Set([t]);
28
- if (t.endsWith("ies") && t.length > 4) out.add(t.slice(0, -3) + "y");
29
- else if (t.endsWith("es") && t.length > 4 && /(s|x|z|ch|sh)es$/.test(t)) out.add(t.slice(0, -2));
30
- else if (t.endsWith("s") && t.length > 3 && !t.endsWith("ss")) out.add(t.slice(0, -1));
31
- if (t.endsWith("ing") && t.length > 5) {
32
- const base = t.slice(0, -3);
33
- out.add(base);
34
- out.add(base + "e");
35
- }
36
- if (t.endsWith("ation") && t.length > 7) {
37
- const base = t.slice(0, -5);
38
- out.add(base);
39
- }
40
- return [...out];
41
- }
42
- var EXPLICIT_STEM = /* @__PURE__ */ new Map([
43
- ["configuration", "config"],
44
- ["configurations", "config"],
45
- ["configured", "config"],
46
- ["ranking", "rank"],
47
- ["ranked", "rank"],
48
- ["weights", "weight"],
49
- ["dependencies", "dependency"],
50
- ["dependency", "depend"],
51
- ["extraction", "extract"],
52
- ["extracted", "extract"]
53
- ]);
54
- function tokenizeIdentifier(raw) {
55
- const parts = raw.replace(/[\\/]/g, " ").replace(/[.:\-_"']/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").toLowerCase().split(/[^a-z0-9]+/g).filter((t) => t.length >= 2 && !STOP.has(t));
56
- const out = /* @__PURE__ */ new Set();
57
- for (const t of parts) {
58
- out.add(t);
59
- for (const v of stemVariants(t)) {
60
- if (v.length >= 2 && !STOP.has(v)) out.add(v);
61
- }
62
- const e = EXPLICIT_STEM.get(t);
63
- if (e && !STOP.has(e)) out.add(e);
64
- }
65
- return [...out];
66
- }
67
- function tokenizeTask(text) {
68
- return tokenizeIdentifier(text);
69
- }
5
+ import {
6
+ tokenizeIdentifier,
7
+ tokenizeTask
8
+ } from "./chunk-UVKHDHBU.js";
70
9
 
71
10
  // src/retrieval/history/index.ts
72
11
  function stripConventionalPrefix(subject) {
@@ -309,8 +248,6 @@ function leaveOneOut(db, shas, opts = {}) {
309
248
  }
310
249
 
311
250
  export {
312
- tokenizeIdentifier,
313
- tokenizeTask,
314
251
  syncCommitFts,
315
252
  HISTORY_HALF_LIFE_DAYS,
316
253
  HISTORY_MIN_SCORE,