@neurcode-ai/cli 0.9.31 → 0.9.33

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 (63) hide show
  1. package/README.md +22 -0
  2. package/dist/commands/apply.d.ts.map +1 -1
  3. package/dist/commands/apply.js +45 -3
  4. package/dist/commands/apply.js.map +1 -1
  5. package/dist/commands/map.d.ts.map +1 -1
  6. package/dist/commands/map.js +78 -1
  7. package/dist/commands/map.js.map +1 -1
  8. package/dist/commands/plan-slo.d.ts +7 -0
  9. package/dist/commands/plan-slo.d.ts.map +1 -0
  10. package/dist/commands/plan-slo.js +205 -0
  11. package/dist/commands/plan-slo.js.map +1 -0
  12. package/dist/commands/plan.d.ts.map +1 -1
  13. package/dist/commands/plan.js +665 -29
  14. package/dist/commands/plan.js.map +1 -1
  15. package/dist/commands/repo.d.ts +3 -0
  16. package/dist/commands/repo.d.ts.map +1 -0
  17. package/dist/commands/repo.js +166 -0
  18. package/dist/commands/repo.js.map +1 -0
  19. package/dist/commands/session.js +2 -2
  20. package/dist/commands/session.js.map +1 -1
  21. package/dist/commands/ship.d.ts.map +1 -1
  22. package/dist/commands/ship.js +29 -0
  23. package/dist/commands/ship.js.map +1 -1
  24. package/dist/commands/verify.d.ts.map +1 -1
  25. package/dist/commands/verify.js +261 -9
  26. package/dist/commands/verify.js.map +1 -1
  27. package/dist/index.js +17 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/services/mapper/ProjectScanner.d.ts +76 -2
  30. package/dist/services/mapper/ProjectScanner.d.ts.map +1 -1
  31. package/dist/services/mapper/ProjectScanner.js +545 -40
  32. package/dist/services/mapper/ProjectScanner.js.map +1 -1
  33. package/dist/services/security/SecurityGuard.d.ts +21 -2
  34. package/dist/services/security/SecurityGuard.d.ts.map +1 -1
  35. package/dist/services/security/SecurityGuard.js +130 -27
  36. package/dist/services/security/SecurityGuard.js.map +1 -1
  37. package/dist/utils/ROILogger.js +1 -1
  38. package/dist/utils/ROILogger.js.map +1 -1
  39. package/dist/utils/gitignore.d.ts.map +1 -1
  40. package/dist/utils/gitignore.js +7 -21
  41. package/dist/utils/gitignore.js.map +1 -1
  42. package/dist/utils/governance.d.ts +2 -0
  43. package/dist/utils/governance.d.ts.map +1 -1
  44. package/dist/utils/governance.js +2 -0
  45. package/dist/utils/governance.js.map +1 -1
  46. package/dist/utils/plan-slo.d.ts +73 -0
  47. package/dist/utils/plan-slo.d.ts.map +1 -0
  48. package/dist/utils/plan-slo.js +271 -0
  49. package/dist/utils/plan-slo.js.map +1 -0
  50. package/dist/utils/project-root.d.ts +5 -4
  51. package/dist/utils/project-root.d.ts.map +1 -1
  52. package/dist/utils/project-root.js +82 -7
  53. package/dist/utils/project-root.js.map +1 -1
  54. package/dist/utils/repo-links.d.ts +17 -0
  55. package/dist/utils/repo-links.d.ts.map +1 -0
  56. package/dist/utils/repo-links.js +136 -0
  57. package/dist/utils/repo-links.js.map +1 -0
  58. package/package.json +13 -12
  59. package/LICENSE +0 -201
  60. package/dist/critical_violation.d.ts +0 -2
  61. package/dist/critical_violation.d.ts.map +0 -1
  62. package/dist/critical_violation.js +0 -12
  63. package/dist/critical_violation.js.map +0 -1
@@ -0,0 +1,73 @@
1
+ export type PlanSloIntentMode = 'implementation' | 'analysis';
2
+ export type PlanSloCoverageLevel = 'high' | 'medium' | 'low';
3
+ export type PlanSloCoverageStatus = 'sufficient' | 'warning' | 'insufficient';
4
+ export type PlanSloEscalationPolicyReason = 'enabled' | 'env_disabled' | 'canary_excluded' | 'kill_switch_cooldown';
5
+ export interface PlanSloEvent {
6
+ schemaVersion: 1;
7
+ timestamp: string;
8
+ intentMode: PlanSloIntentMode;
9
+ cached: boolean;
10
+ success: boolean;
11
+ exitCode: number;
12
+ elapsedMs: number;
13
+ rssKb: number;
14
+ coverageScore: number | null;
15
+ coverageLevel: PlanSloCoverageLevel | null;
16
+ coverageStatus: PlanSloCoverageStatus | null;
17
+ adaptiveEscalationTriggered: boolean;
18
+ adaptiveEscalationReason: string | null;
19
+ adaptiveEscalationDeepenedFiles: number;
20
+ escalationPolicyEnabled: boolean | null;
21
+ escalationPolicyReason: PlanSloEscalationPolicyReason | null;
22
+ escalationCanaryPercent: number | null;
23
+ escalationCanaryBucket: number | null;
24
+ escalationKillSwitchTripped: boolean;
25
+ escalationKillSwitchCooldownUntil: string | null;
26
+ fileTreeCount: number | null;
27
+ filesUsedForGeneration: number | null;
28
+ }
29
+ export interface PlanSloEventInput {
30
+ timestamp?: string;
31
+ intentMode: PlanSloIntentMode;
32
+ cached: boolean;
33
+ success: boolean;
34
+ exitCode: number;
35
+ elapsedMs: number;
36
+ rssKb: number;
37
+ coverageScore?: number | null;
38
+ coverageLevel?: PlanSloCoverageLevel | null;
39
+ coverageStatus?: PlanSloCoverageStatus | null;
40
+ adaptiveEscalationTriggered?: boolean;
41
+ adaptiveEscalationReason?: string | null;
42
+ adaptiveEscalationDeepenedFiles?: number;
43
+ escalationPolicyEnabled?: boolean | null;
44
+ escalationPolicyReason?: PlanSloEscalationPolicyReason | null;
45
+ escalationCanaryPercent?: number | null;
46
+ escalationCanaryBucket?: number | null;
47
+ escalationKillSwitchTripped?: boolean;
48
+ escalationKillSwitchCooldownUntil?: string | null;
49
+ fileTreeCount?: number | null;
50
+ filesUsedForGeneration?: number | null;
51
+ }
52
+ export interface PlanEscalationGuardState {
53
+ version: 1;
54
+ updatedAt: string;
55
+ consecutiveBreaches: number;
56
+ lastBreachAt?: string;
57
+ lastReason?: string;
58
+ cooldownUntil?: string;
59
+ }
60
+ export interface PlanEscalationGuardSnapshot {
61
+ path: string;
62
+ present: boolean;
63
+ cooldownActive: boolean;
64
+ cooldownUntil: string | null;
65
+ state: PlanEscalationGuardState | null;
66
+ }
67
+ export declare function getPlanSloLogPath(projectRoot: string): string;
68
+ export declare function getPlanEscalationGuardPath(projectRoot: string): string;
69
+ export declare function prunePlanSloLog(projectRoot: string, nowMs?: number): void;
70
+ export declare function appendPlanSloEvent(projectRoot: string, input: PlanSloEventInput): PlanSloEvent;
71
+ export declare function readPlanSloEvents(projectRoot: string): PlanSloEvent[];
72
+ export declare function readPlanEscalationGuardSnapshot(projectRoot: string, nowMs?: number): PlanEscalationGuardSnapshot;
73
+ //# sourceMappingURL=plan-slo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-slo.d.ts","sourceRoot":"","sources":["../../src/utils/plan-slo.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,iBAAiB,GAAG,gBAAgB,GAAG,UAAU,CAAC;AAC9D,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAC7D,MAAM,MAAM,qBAAqB,GAAG,YAAY,GAAG,SAAS,GAAG,cAAc,CAAC;AAC9E,MAAM,MAAM,6BAA6B,GACrC,SAAS,GACT,cAAc,GACd,iBAAiB,GACjB,sBAAsB,CAAC;AAE3B,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,CAAC,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC3C,cAAc,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAC7C,2BAA2B,EAAE,OAAO,CAAC;IACrC,wBAAwB,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,+BAA+B,EAAE,MAAM,CAAC;IACxC,uBAAuB,EAAE,OAAO,GAAG,IAAI,CAAC;IACxC,sBAAsB,EAAE,6BAA6B,GAAG,IAAI,CAAC;IAC7D,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,2BAA2B,EAAE,OAAO,CAAC;IACrC,iCAAiC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjD,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC5C,cAAc,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAC9C,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,wBAAwB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,+BAA+B,CAAC,EAAE,MAAM,CAAC;IACzC,uBAAuB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACzC,sBAAsB,CAAC,EAAE,6BAA6B,GAAG,IAAI,CAAC;IAC9D,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,sBAAsB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,iCAAiC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClD,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,sBAAsB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,wBAAwB,GAAG,IAAI,CAAC;CACxC;AA8GD,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,GAAE,MAAmB,GAAG,IAAI,CAwDrF;AAED,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,YAAY,CAkC9F;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,YAAY,EAAE,CAoBrE;AAED,wBAAgB,+BAA+B,CAC7C,WAAW,EAAE,MAAM,EACnB,KAAK,GAAE,MAAmB,GACzB,2BAA2B,CA2C7B"}
@@ -0,0 +1,271 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPlanSloLogPath = getPlanSloLogPath;
4
+ exports.getPlanEscalationGuardPath = getPlanEscalationGuardPath;
5
+ exports.prunePlanSloLog = prunePlanSloLog;
6
+ exports.appendPlanSloEvent = appendPlanSloEvent;
7
+ exports.readPlanSloEvents = readPlanSloEvents;
8
+ exports.readPlanEscalationGuardSnapshot = readPlanEscalationGuardSnapshot;
9
+ const fs_1 = require("fs");
10
+ const path_1 = require("path");
11
+ const PLAN_SLO_LOG_FILENAME = 'plan-slo.jsonl';
12
+ const ESCALATION_GUARD_FILENAME = 'asset-map-escalation-guard.json';
13
+ const DEFAULT_PLAN_SLO_LOG_MAX_EVENTS = 2000;
14
+ const DEFAULT_PLAN_SLO_LOG_MAX_DAYS = 30;
15
+ function toFiniteInteger(value, fallback) {
16
+ if (!Number.isFinite(value))
17
+ return fallback;
18
+ return Math.max(0, Math.floor(value));
19
+ }
20
+ function toNullableFiniteInteger(value) {
21
+ if (typeof value !== 'number' || !Number.isFinite(value))
22
+ return null;
23
+ return Math.max(0, Math.floor(value));
24
+ }
25
+ function toNullableString(value) {
26
+ return typeof value === 'string' && value.trim().length > 0 ? value : null;
27
+ }
28
+ function toNullableBoolean(value) {
29
+ if (typeof value === 'boolean')
30
+ return value;
31
+ return null;
32
+ }
33
+ function parseNonNegativeInt(raw) {
34
+ if (!raw || !raw.trim())
35
+ return null;
36
+ const parsed = Number(raw);
37
+ if (!Number.isFinite(parsed) || parsed < 0)
38
+ return null;
39
+ return Math.floor(parsed);
40
+ }
41
+ function resolvePlanSloMaxEvents() {
42
+ const parsed = parseNonNegativeInt(process.env.NEURCODE_PLAN_SLO_LOG_MAX_EVENTS);
43
+ return parsed === null ? DEFAULT_PLAN_SLO_LOG_MAX_EVENTS : parsed;
44
+ }
45
+ function resolvePlanSloMaxDays() {
46
+ const parsed = parseNonNegativeInt(process.env.NEURCODE_PLAN_SLO_LOG_MAX_DAYS);
47
+ return parsed === null ? DEFAULT_PLAN_SLO_LOG_MAX_DAYS : parsed;
48
+ }
49
+ function parseEventLine(line) {
50
+ if (!line.trim())
51
+ return null;
52
+ let parsed;
53
+ try {
54
+ parsed = JSON.parse(line);
55
+ }
56
+ catch {
57
+ return null;
58
+ }
59
+ if (!parsed || typeof parsed !== 'object')
60
+ return null;
61
+ const data = parsed;
62
+ if (data.schemaVersion !== 1)
63
+ return null;
64
+ if (typeof data.timestamp !== 'string')
65
+ return null;
66
+ if (data.intentMode !== 'implementation' && data.intentMode !== 'analysis')
67
+ return null;
68
+ if (typeof data.cached !== 'boolean')
69
+ return null;
70
+ if (typeof data.success !== 'boolean')
71
+ return null;
72
+ if (typeof data.exitCode !== 'number')
73
+ return null;
74
+ if (typeof data.elapsedMs !== 'number')
75
+ return null;
76
+ if (typeof data.rssKb !== 'number')
77
+ return null;
78
+ const coverageLevelValue = data.coverageLevel;
79
+ const coverageLevel = coverageLevelValue === 'high' || coverageLevelValue === 'medium' || coverageLevelValue === 'low'
80
+ ? coverageLevelValue
81
+ : null;
82
+ const coverageStatusValue = data.coverageStatus;
83
+ const coverageStatus = coverageStatusValue === 'sufficient' || coverageStatusValue === 'warning' || coverageStatusValue === 'insufficient'
84
+ ? coverageStatusValue
85
+ : null;
86
+ const escalationPolicyReasonValue = data.escalationPolicyReason;
87
+ const escalationPolicyReason = escalationPolicyReasonValue === 'enabled' ||
88
+ escalationPolicyReasonValue === 'env_disabled' ||
89
+ escalationPolicyReasonValue === 'canary_excluded' ||
90
+ escalationPolicyReasonValue === 'kill_switch_cooldown'
91
+ ? escalationPolicyReasonValue
92
+ : null;
93
+ return {
94
+ schemaVersion: 1,
95
+ timestamp: data.timestamp,
96
+ intentMode: data.intentMode,
97
+ cached: data.cached,
98
+ success: data.success,
99
+ exitCode: toFiniteInteger(data.exitCode, 0),
100
+ elapsedMs: toFiniteInteger(data.elapsedMs, 0),
101
+ rssKb: toFiniteInteger(data.rssKb, 0),
102
+ coverageScore: toNullableFiniteInteger(data.coverageScore),
103
+ coverageLevel,
104
+ coverageStatus,
105
+ adaptiveEscalationTriggered: data.adaptiveEscalationTriggered === true,
106
+ adaptiveEscalationReason: toNullableString(data.adaptiveEscalationReason),
107
+ adaptiveEscalationDeepenedFiles: toFiniteInteger(typeof data.adaptiveEscalationDeepenedFiles === 'number' ? data.adaptiveEscalationDeepenedFiles : 0, 0),
108
+ escalationPolicyEnabled: toNullableBoolean(data.escalationPolicyEnabled),
109
+ escalationPolicyReason,
110
+ escalationCanaryPercent: toNullableFiniteInteger(data.escalationCanaryPercent),
111
+ escalationCanaryBucket: toNullableFiniteInteger(data.escalationCanaryBucket),
112
+ escalationKillSwitchTripped: data.escalationKillSwitchTripped === true,
113
+ escalationKillSwitchCooldownUntil: toNullableString(data.escalationKillSwitchCooldownUntil),
114
+ fileTreeCount: toNullableFiniteInteger(data.fileTreeCount),
115
+ filesUsedForGeneration: toNullableFiniteInteger(data.filesUsedForGeneration),
116
+ };
117
+ }
118
+ function getPlanSloLogPath(projectRoot) {
119
+ return (0, path_1.join)(projectRoot, '.neurcode', PLAN_SLO_LOG_FILENAME);
120
+ }
121
+ function getPlanEscalationGuardPath(projectRoot) {
122
+ return (0, path_1.join)(projectRoot, '.neurcode', ESCALATION_GUARD_FILENAME);
123
+ }
124
+ function prunePlanSloLog(projectRoot, nowMs = Date.now()) {
125
+ const maxEvents = resolvePlanSloMaxEvents();
126
+ const maxDays = resolvePlanSloMaxDays();
127
+ if (maxEvents === 0 && maxDays === 0) {
128
+ return;
129
+ }
130
+ const sloPath = getPlanSloLogPath(projectRoot);
131
+ if (!(0, fs_1.existsSync)(sloPath)) {
132
+ return;
133
+ }
134
+ let raw;
135
+ try {
136
+ raw = (0, fs_1.readFileSync)(sloPath, 'utf-8');
137
+ }
138
+ catch {
139
+ return;
140
+ }
141
+ if (!raw.trim()) {
142
+ return;
143
+ }
144
+ const cutoffMs = maxDays > 0 ? nowMs - maxDays * 24 * 60 * 60 * 1000 : null;
145
+ const lines = raw.split('\n').map((line) => line.trim()).filter(Boolean);
146
+ const retained = [];
147
+ let changed = false;
148
+ for (const line of lines) {
149
+ const parsed = parseEventLine(line);
150
+ if (!parsed) {
151
+ changed = true;
152
+ continue;
153
+ }
154
+ if (cutoffMs !== null) {
155
+ const timestampMs = Date.parse(parsed.timestamp);
156
+ if (Number.isFinite(timestampMs) && timestampMs < cutoffMs) {
157
+ changed = true;
158
+ continue;
159
+ }
160
+ }
161
+ retained.push(JSON.stringify(parsed));
162
+ }
163
+ if (maxEvents > 0 && retained.length > maxEvents) {
164
+ retained.splice(0, retained.length - maxEvents);
165
+ changed = true;
166
+ }
167
+ if (!changed && retained.length === lines.length) {
168
+ return;
169
+ }
170
+ const nextContent = retained.length > 0 ? `${retained.join('\n')}\n` : '';
171
+ (0, fs_1.writeFileSync)(sloPath, nextContent, 'utf-8');
172
+ }
173
+ function appendPlanSloEvent(projectRoot, input) {
174
+ const event = {
175
+ schemaVersion: 1,
176
+ timestamp: input.timestamp || new Date().toISOString(),
177
+ intentMode: input.intentMode,
178
+ cached: input.cached === true,
179
+ success: input.success === true,
180
+ exitCode: toFiniteInteger(input.exitCode, 1),
181
+ elapsedMs: toFiniteInteger(input.elapsedMs, 0),
182
+ rssKb: toFiniteInteger(input.rssKb, 0),
183
+ coverageScore: toNullableFiniteInteger(input.coverageScore),
184
+ coverageLevel: input.coverageLevel || null,
185
+ coverageStatus: input.coverageStatus || null,
186
+ adaptiveEscalationTriggered: input.adaptiveEscalationTriggered === true,
187
+ adaptiveEscalationReason: input.adaptiveEscalationReason || null,
188
+ adaptiveEscalationDeepenedFiles: toFiniteInteger(input.adaptiveEscalationDeepenedFiles || 0, 0),
189
+ escalationPolicyEnabled: typeof input.escalationPolicyEnabled === 'boolean' ? input.escalationPolicyEnabled : null,
190
+ escalationPolicyReason: input.escalationPolicyReason || null,
191
+ escalationCanaryPercent: toNullableFiniteInteger(input.escalationCanaryPercent),
192
+ escalationCanaryBucket: toNullableFiniteInteger(input.escalationCanaryBucket),
193
+ escalationKillSwitchTripped: input.escalationKillSwitchTripped === true,
194
+ escalationKillSwitchCooldownUntil: input.escalationKillSwitchCooldownUntil || null,
195
+ fileTreeCount: toNullableFiniteInteger(input.fileTreeCount),
196
+ filesUsedForGeneration: toNullableFiniteInteger(input.filesUsedForGeneration),
197
+ };
198
+ const sloPath = getPlanSloLogPath(projectRoot);
199
+ const sloDir = (0, path_1.join)(projectRoot, '.neurcode');
200
+ if (!(0, fs_1.existsSync)(sloDir)) {
201
+ (0, fs_1.mkdirSync)(sloDir, { recursive: true });
202
+ }
203
+ (0, fs_1.appendFileSync)(sloPath, JSON.stringify(event) + '\n', 'utf-8');
204
+ prunePlanSloLog(projectRoot);
205
+ return event;
206
+ }
207
+ function readPlanSloEvents(projectRoot) {
208
+ const pathValue = getPlanSloLogPath(projectRoot);
209
+ if (!(0, fs_1.existsSync)(pathValue)) {
210
+ return [];
211
+ }
212
+ try {
213
+ const raw = (0, fs_1.readFileSync)(pathValue, 'utf-8');
214
+ const lines = raw.split('\n');
215
+ const events = [];
216
+ for (const line of lines) {
217
+ const parsed = parseEventLine(line);
218
+ if (parsed) {
219
+ events.push(parsed);
220
+ }
221
+ }
222
+ return events;
223
+ }
224
+ catch {
225
+ return [];
226
+ }
227
+ }
228
+ function readPlanEscalationGuardSnapshot(projectRoot, nowMs = Date.now()) {
229
+ const pathValue = getPlanEscalationGuardPath(projectRoot);
230
+ if (!(0, fs_1.existsSync)(pathValue)) {
231
+ return {
232
+ path: pathValue,
233
+ present: false,
234
+ cooldownActive: false,
235
+ cooldownUntil: null,
236
+ state: null,
237
+ };
238
+ }
239
+ try {
240
+ const raw = JSON.parse((0, fs_1.readFileSync)(pathValue, 'utf-8'));
241
+ const state = {
242
+ version: 1,
243
+ updatedAt: typeof raw.updatedAt === 'string' ? raw.updatedAt : new Date(0).toISOString(),
244
+ consecutiveBreaches: typeof raw.consecutiveBreaches === 'number' && Number.isFinite(raw.consecutiveBreaches) && raw.consecutiveBreaches > 0
245
+ ? Math.floor(raw.consecutiveBreaches)
246
+ : 0,
247
+ lastBreachAt: typeof raw.lastBreachAt === 'string' ? raw.lastBreachAt : undefined,
248
+ lastReason: typeof raw.lastReason === 'string' ? raw.lastReason : undefined,
249
+ cooldownUntil: typeof raw.cooldownUntil === 'string' ? raw.cooldownUntil : undefined,
250
+ };
251
+ const cooldownUntilMs = state.cooldownUntil ? Date.parse(state.cooldownUntil) : NaN;
252
+ const cooldownActive = Number.isFinite(cooldownUntilMs) && cooldownUntilMs > nowMs;
253
+ return {
254
+ path: pathValue,
255
+ present: true,
256
+ cooldownActive,
257
+ cooldownUntil: state.cooldownUntil || null,
258
+ state,
259
+ };
260
+ }
261
+ catch {
262
+ return {
263
+ path: pathValue,
264
+ present: false,
265
+ cooldownActive: false,
266
+ cooldownUntil: null,
267
+ state: null,
268
+ };
269
+ }
270
+ }
271
+ //# sourceMappingURL=plan-slo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-slo.js","sourceRoot":"","sources":["../../src/utils/plan-slo.ts"],"names":[],"mappings":"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"}
@@ -9,10 +9,11 @@
9
9
  * - Walk up from the current working directory and pick the nearest ancestor
10
10
  * that contains `.neurcode/config.json` (linked project marker).
11
11
  * - Also treat legacy `neurcode.config.json` as a marker for older setups.
12
- * - If nothing is found, fall back to the starting directory (preserves current behavior).
13
- *
14
- * Note: We intentionally do NOT fall back to git root here. Linking a subdirectory
15
- * (monorepo package) should remain possible without surprises.
12
+ * - If the current directory is inside a git repository, do not search above
13
+ * that repository root. This prevents accidental cross-repo leakage.
14
+ * - Cross-repo root overrides are denied by default, but can be explicitly
15
+ * allowed via `.neurcode/repo-links.json` (`neurcode repo link ...`).
16
+ * - If nothing is found, fall back to the starting directory.
16
17
  */
17
18
  export declare function resolveNeurcodeProjectRoot(startDir?: string): string;
18
19
  //# sourceMappingURL=project-root.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"project-root.d.ts","sourceRoot":"","sources":["../../src/utils/project-root.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,wBAAgB,0BAA0B,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAyBnF"}
1
+ {"version":3,"file":"project-root.d.ts","sourceRoot":"","sources":["../../src/utils/project-root.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAgDH,wBAAgB,0BAA0B,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,CA8DnF"}
@@ -10,35 +10,110 @@
10
10
  * - Walk up from the current working directory and pick the nearest ancestor
11
11
  * that contains `.neurcode/config.json` (linked project marker).
12
12
  * - Also treat legacy `neurcode.config.json` as a marker for older setups.
13
- * - If nothing is found, fall back to the starting directory (preserves current behavior).
14
- *
15
- * Note: We intentionally do NOT fall back to git root here. Linking a subdirectory
16
- * (monorepo package) should remain possible without surprises.
13
+ * - If the current directory is inside a git repository, do not search above
14
+ * that repository root. This prevents accidental cross-repo leakage.
15
+ * - Cross-repo root overrides are denied by default, but can be explicitly
16
+ * allowed via `.neurcode/repo-links.json` (`neurcode repo link ...`).
17
+ * - If nothing is found, fall back to the starting directory.
17
18
  */
18
19
  Object.defineProperty(exports, "__esModule", { value: true });
19
20
  exports.resolveNeurcodeProjectRoot = resolveNeurcodeProjectRoot;
21
+ const child_process_1 = require("child_process");
20
22
  const fs_1 = require("fs");
21
23
  const path_1 = require("path");
24
+ const repo_links_1 = require("./repo-links");
25
+ function canonicalizePath(pathValue) {
26
+ try {
27
+ return (0, fs_1.realpathSync)(pathValue);
28
+ }
29
+ catch {
30
+ return (0, path_1.resolve)(pathValue);
31
+ }
32
+ }
33
+ function getGitRoot(startDir) {
34
+ try {
35
+ const output = (0, child_process_1.execSync)('git rev-parse --show-toplevel', {
36
+ cwd: startDir,
37
+ encoding: 'utf-8',
38
+ stdio: ['ignore', 'pipe', 'ignore'],
39
+ }).trim();
40
+ return output ? canonicalizePath(output) : null;
41
+ }
42
+ catch {
43
+ return null;
44
+ }
45
+ }
46
+ function isPathWithin(parent, candidate) {
47
+ const rel = (0, path_1.relative)(parent, candidate);
48
+ return rel === '' || (!rel.startsWith('..') && !(0, path_1.isAbsolute)(rel));
49
+ }
50
+ function findNearestRepoLinksRoot(startDir, boundary) {
51
+ let dir = startDir;
52
+ while (true) {
53
+ const linksPath = (0, path_1.join)(dir, '.neurcode', 'repo-links.json');
54
+ if ((0, fs_1.existsSync)(linksPath)) {
55
+ return dir;
56
+ }
57
+ if (boundary && dir === boundary)
58
+ break;
59
+ const parent = (0, path_1.dirname)(dir);
60
+ if (parent === dir)
61
+ break;
62
+ dir = parent;
63
+ }
64
+ return null;
65
+ }
22
66
  function resolveNeurcodeProjectRoot(startDir = process.cwd()) {
67
+ const resolvedStart = canonicalizePath(startDir);
68
+ const gitRoot = getGitRoot(resolvedStart);
69
+ const homeDir = canonicalizePath(process.env.HOME || process.env.USERPROFILE || resolvedStart);
23
70
  const override = process.env.NEURCODE_PROJECT_ROOT || process.env.NEURCODE_ROOT;
24
71
  if (override && override.trim()) {
25
- return (0, path_1.resolve)(override.trim());
72
+ const overridePath = canonicalizePath(override.trim());
73
+ if (gitRoot &&
74
+ !isPathWithin(gitRoot, overridePath) &&
75
+ process.env.NEURCODE_ALLOW_CROSS_REPO_ROOT !== '1') {
76
+ const linksRoot = findNearestRepoLinksRoot(resolvedStart, gitRoot);
77
+ const explicitlyLinked = linksRoot
78
+ ? (0, repo_links_1.isRepoPathExplicitlyLinked)(linksRoot, overridePath)
79
+ : false;
80
+ if (explicitlyLinked) {
81
+ return overridePath;
82
+ }
83
+ // Ignore invalid cross-repo override and continue with normal root resolution.
84
+ }
85
+ else {
86
+ return overridePath;
87
+ }
26
88
  }
27
- let dir = (0, path_1.resolve)(startDir);
89
+ let dir = resolvedStart;
90
+ const boundary = gitRoot || null;
28
91
  while (true) {
29
92
  const neurcodeConfig = (0, path_1.join)(dir, '.neurcode', 'config.json');
30
93
  if ((0, fs_1.existsSync)(neurcodeConfig)) {
94
+ if (dir === homeDir &&
95
+ dir !== resolvedStart &&
96
+ process.env.NEURCODE_ALLOW_HOME_ROOT !== '1') {
97
+ return resolvedStart;
98
+ }
31
99
  return dir;
32
100
  }
33
101
  const legacyLocalConfig = (0, path_1.join)(dir, 'neurcode.config.json');
34
102
  if ((0, fs_1.existsSync)(legacyLocalConfig)) {
103
+ if (dir === homeDir &&
104
+ dir !== resolvedStart &&
105
+ process.env.NEURCODE_ALLOW_HOME_ROOT !== '1') {
106
+ return resolvedStart;
107
+ }
35
108
  return dir;
36
109
  }
110
+ if (boundary && dir === boundary)
111
+ break;
37
112
  const parent = (0, path_1.dirname)(dir);
38
113
  if (parent === dir)
39
114
  break;
40
115
  dir = parent;
41
116
  }
42
- return (0, path_1.resolve)(startDir);
117
+ return resolvedStart;
43
118
  }
44
119
  //# sourceMappingURL=project-root.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"project-root.js","sourceRoot":"","sources":["../../src/utils/project-root.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AAKH,gEAyBC;AA5BD,2BAAgC;AAChC,+BAA8C;AAE9C,SAAgB,0BAA0B,CAAC,WAAmB,OAAO,CAAC,GAAG,EAAE;IACzE,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAChF,IAAI,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;QAChC,OAAO,IAAA,cAAO,EAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,IAAI,GAAG,GAAG,IAAA,cAAO,EAAC,QAAQ,CAAC,CAAC;IAE5B,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,cAAc,GAAG,IAAA,WAAI,EAAC,GAAG,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;QAC7D,IAAI,IAAA,eAAU,EAAC,cAAc,CAAC,EAAE,CAAC;YAC/B,OAAO,GAAG,CAAC;QACb,CAAC;QAED,MAAM,iBAAiB,GAAG,IAAA,WAAI,EAAC,GAAG,EAAE,sBAAsB,CAAC,CAAC;QAC5D,IAAI,IAAA,eAAU,EAAC,iBAAiB,CAAC,EAAE,CAAC;YAClC,OAAO,GAAG,CAAC;QACb,CAAC;QAED,MAAM,MAAM,GAAG,IAAA,cAAO,EAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM;QAC1B,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;IAED,OAAO,IAAA,cAAO,EAAC,QAAQ,CAAC,CAAC;AAC3B,CAAC"}
1
+ {"version":3,"file":"project-root.js","sourceRoot":"","sources":["../../src/utils/project-root.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export interface RepoLinkEntry {
2
+ alias: string;
3
+ path: string;
4
+ linkedAt: string;
5
+ }
6
+ export declare function canonicalizeRepoPath(pathValue: string): string;
7
+ export declare function getRepoLinksPath(projectRoot: string): string;
8
+ export declare function loadRepoLinks(projectRoot: string): RepoLinkEntry[];
9
+ export declare function saveRepoLinks(projectRoot: string, links: RepoLinkEntry[]): void;
10
+ export declare function upsertRepoLink(projectRoot: string, input: {
11
+ path: string;
12
+ alias?: string;
13
+ }): RepoLinkEntry;
14
+ export declare function removeRepoLink(projectRoot: string, aliasOrPath: string): RepoLinkEntry | null;
15
+ export declare function findRepoLink(projectRoot: string, aliasOrPath: string): RepoLinkEntry | null;
16
+ export declare function isRepoPathExplicitlyLinked(projectRoot: string, candidatePath: string): boolean;
17
+ //# sourceMappingURL=repo-links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo-links.d.ts","sourceRoot":"","sources":["../../src/utils/repo-links.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAUD,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAM9D;AA8BD,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,EAAE,CAoBlE;AAED,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,IAAI,CAY/E;AAED,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE;IACL,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GACA,aAAa,CAoBf;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAmB7F;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAS3F;AAED,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAS9F"}