@nepopsx/cli 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/configuration.d.ts +9 -0
- package/dist/agents/configuration.d.ts.map +1 -0
- package/dist/agents/configuration.js +57 -0
- package/dist/agents/configuration.js.map +1 -0
- package/dist/agents/remote-config.d.ts +30 -0
- package/dist/agents/remote-config.d.ts.map +1 -0
- package/dist/agents/remote-config.js +102 -0
- package/dist/agents/remote-config.js.map +1 -0
- package/dist/commands/activate.d.ts.map +1 -1
- package/dist/commands/activate.js +4 -3
- package/dist/commands/activate.js.map +1 -1
- package/dist/commands/decode.js +2 -2
- package/dist/commands/decode.js.map +1 -1
- package/dist/commands/doctor.js +16 -16
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +353 -18
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/install.d.ts +1 -0
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +253 -25
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/login.d.ts +6 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +108 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/push-learnings.d.ts +14 -0
- package/dist/commands/push-learnings.d.ts.map +1 -0
- package/dist/commands/push-learnings.js +186 -0
- package/dist/commands/push-learnings.js.map +1 -0
- package/dist/commands/scan.d.ts +2 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +520 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/sync.d.ts +2 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +203 -234
- package/dist/commands/sync.js.map +1 -1
- package/dist/config/api-config.d.ts.map +1 -1
- package/dist/config/api-config.js +4 -0
- package/dist/config/api-config.js.map +1 -1
- package/dist/constants.d.ts +7 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +7 -0
- package/dist/constants.js.map +1 -0
- package/dist/customs/instructions.d.ts +3 -0
- package/dist/customs/instructions.d.ts.map +1 -0
- package/dist/customs/instructions.js +51 -0
- package/dist/customs/instructions.js.map +1 -0
- package/dist/enrichment/confirm.d.ts +17 -0
- package/dist/enrichment/confirm.d.ts.map +1 -0
- package/dist/enrichment/confirm.js +44 -0
- package/dist/enrichment/confirm.js.map +1 -0
- package/dist/enrichment/state.d.ts +8 -0
- package/dist/enrichment/state.d.ts.map +1 -0
- package/dist/enrichment/state.js +107 -0
- package/dist/enrichment/state.js.map +1 -0
- package/dist/enrichment/types.d.ts +13 -0
- package/dist/enrichment/types.d.ts.map +1 -0
- package/dist/enrichment/types.js +2 -0
- package/dist/enrichment/types.js.map +1 -0
- package/dist/enrichment/workflow.d.ts +35 -0
- package/dist/enrichment/workflow.d.ts.map +1 -0
- package/dist/enrichment/workflow.js +305 -0
- package/dist/enrichment/workflow.js.map +1 -0
- package/dist/generator/builtin-templates.d.ts +2 -1
- package/dist/generator/builtin-templates.d.ts.map +1 -1
- package/dist/generator/builtin-templates.js +161 -2
- package/dist/generator/builtin-templates.js.map +1 -1
- package/dist/generator/package-renderer.d.ts +29 -0
- package/dist/generator/package-renderer.d.ts.map +1 -0
- package/dist/generator/package-renderer.js +123 -0
- package/dist/generator/package-renderer.js.map +1 -0
- package/dist/generator/render.d.ts +14 -63
- package/dist/generator/render.d.ts.map +1 -1
- package/dist/generator/render.js +30 -176
- package/dist/generator/render.js.map +1 -1
- package/dist/index.js +42 -2
- package/dist/index.js.map +1 -1
- package/dist/licensing/installer.d.ts +51 -0
- package/dist/licensing/installer.d.ts.map +1 -0
- package/dist/licensing/installer.js +112 -0
- package/dist/licensing/installer.js.map +1 -0
- package/dist/licensing/license-manager.d.ts +6 -0
- package/dist/licensing/license-manager.d.ts.map +1 -1
- package/dist/licensing/license-manager.js +12 -35
- package/dist/licensing/license-manager.js.map +1 -1
- package/dist/licensing/template-fetch.d.ts +3 -2
- package/dist/licensing/template-fetch.d.ts.map +1 -1
- package/dist/licensing/template-fetch.js +10 -41
- package/dist/licensing/template-fetch.js.map +1 -1
- package/dist/scan/__tests__/context-gatherer.test.d.ts +2 -0
- package/dist/scan/__tests__/context-gatherer.test.d.ts.map +1 -0
- package/dist/scan/__tests__/context-gatherer.test.js +111 -0
- package/dist/scan/__tests__/context-gatherer.test.js.map +1 -0
- package/dist/scan/__tests__/merge.test.d.ts +2 -0
- package/dist/scan/__tests__/merge.test.d.ts.map +1 -0
- package/dist/scan/__tests__/merge.test.js +163 -0
- package/dist/scan/__tests__/merge.test.js.map +1 -0
- package/dist/scan/auto-bootstrap.d.ts +3 -0
- package/dist/scan/auto-bootstrap.d.ts.map +1 -0
- package/dist/scan/auto-bootstrap.js +30 -0
- package/dist/scan/auto-bootstrap.js.map +1 -0
- package/dist/scan/config.d.ts +24 -0
- package/dist/scan/config.d.ts.map +1 -0
- package/dist/scan/config.js +77 -0
- package/dist/scan/config.js.map +1 -0
- package/dist/scan/context/gatherer.d.ts +13 -0
- package/dist/scan/context/gatherer.d.ts.map +1 -0
- package/dist/scan/context/gatherer.js +97 -0
- package/dist/scan/context/gatherer.js.map +1 -0
- package/dist/scan/context/gitignore.d.ts +9 -0
- package/dist/scan/context/gitignore.d.ts.map +1 -0
- package/dist/scan/context/gitignore.js +50 -0
- package/dist/scan/context/gitignore.js.map +1 -0
- package/dist/scan/context/patterns.d.ts +14 -0
- package/dist/scan/context/patterns.d.ts.map +1 -0
- package/dist/scan/context/patterns.js +159 -0
- package/dist/scan/context/patterns.js.map +1 -0
- package/dist/scan/customs/writer.d.ts +6 -0
- package/dist/scan/customs/writer.d.ts.map +1 -0
- package/dist/scan/customs/writer.js +149 -0
- package/dist/scan/customs/writer.js.map +1 -0
- package/dist/scan/llm/anthropic.d.ts +11 -0
- package/dist/scan/llm/anthropic.d.ts.map +1 -0
- package/dist/scan/llm/anthropic.js +89 -0
- package/dist/scan/llm/anthropic.js.map +1 -0
- package/dist/scan/llm/factory.d.ts +4 -0
- package/dist/scan/llm/factory.d.ts.map +1 -0
- package/dist/scan/llm/factory.js +20 -0
- package/dist/scan/llm/factory.js.map +1 -0
- package/dist/scan/llm/ollama.d.ts +11 -0
- package/dist/scan/llm/ollama.d.ts.map +1 -0
- package/dist/scan/llm/ollama.js +64 -0
- package/dist/scan/llm/ollama.js.map +1 -0
- package/dist/scan/llm/openai.d.ts +12 -0
- package/dist/scan/llm/openai.d.ts.map +1 -0
- package/dist/scan/llm/openai.js +78 -0
- package/dist/scan/llm/openai.js.map +1 -0
- package/dist/scan/llm/types.d.ts +23 -0
- package/dist/scan/llm/types.d.ts.map +1 -0
- package/dist/scan/llm/types.js +3 -0
- package/dist/scan/llm/types.js.map +1 -0
- package/dist/scan/merge/diff-display.d.ts +11 -0
- package/dist/scan/merge/diff-display.d.ts.map +1 -0
- package/dist/scan/merge/diff-display.js +72 -0
- package/dist/scan/merge/diff-display.js.map +1 -0
- package/dist/scan/prompt/agent.d.ts +23 -0
- package/dist/scan/prompt/agent.d.ts.map +1 -0
- package/dist/scan/prompt/agent.js +95 -0
- package/dist/scan/prompt/agent.js.map +1 -0
- package/dist/scan/prompt/builder.d.ts +16 -0
- package/dist/scan/prompt/builder.d.ts.map +1 -0
- package/dist/scan/prompt/builder.js +64 -0
- package/dist/scan/prompt/builder.js.map +1 -0
- package/dist/scan/prompt/schema.d.ts +7 -0
- package/dist/scan/prompt/schema.d.ts.map +1 -0
- package/dist/scan/prompt/schema.js +52 -0
- package/dist/scan/prompt/schema.js.map +1 -0
- package/dist/security/scanner.d.ts +3 -40
- package/dist/security/scanner.d.ts.map +1 -1
- package/dist/security/scanner.js +3 -169
- package/dist/security/scanner.js.map +1 -1
- package/dist/utils/fetch.d.ts +9 -0
- package/dist/utils/fetch.d.ts.map +1 -0
- package/dist/utils/fetch.js +18 -0
- package/dist/utils/fetch.js.map +1 -0
- package/package.json +15 -12
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// @nepopsx/cli — Merge logic tests (re-exported from core)
|
|
2
|
+
// These tests exercise the mergeWorkspaceConfig function via the scan pipeline.
|
|
3
|
+
import { strict as assert } from 'node:assert';
|
|
4
|
+
import { describe, it } from 'node:test';
|
|
5
|
+
import { mergeWorkspaceConfig } from '@nepopsx/core';
|
|
6
|
+
const BASE_CONFIG = {
|
|
7
|
+
version: 1,
|
|
8
|
+
workspace: { name: 'test-workspace' },
|
|
9
|
+
services: [
|
|
10
|
+
{
|
|
11
|
+
name: 'api',
|
|
12
|
+
path: './api',
|
|
13
|
+
language: 'typescript',
|
|
14
|
+
framework: 'nestjs',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: 'web',
|
|
18
|
+
path: './web',
|
|
19
|
+
language: 'typescript',
|
|
20
|
+
framework: 'nextjs',
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
};
|
|
24
|
+
describe('mergeWorkspaceConfig', () => {
|
|
25
|
+
it('empty field gets filled from scan result', () => {
|
|
26
|
+
const scan = {
|
|
27
|
+
services: [
|
|
28
|
+
{
|
|
29
|
+
service_name: 'api',
|
|
30
|
+
description: 'REST API service',
|
|
31
|
+
confidence: { description: 'high' },
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
const { updated, changedFields } = mergeWorkspaceConfig(BASE_CONFIG, scan, null);
|
|
36
|
+
assert.equal(updated.services[0].description, 'REST API service');
|
|
37
|
+
assert.ok(changedFields.includes('services.api.description'));
|
|
38
|
+
});
|
|
39
|
+
it('user-provenance field gets suggestion, not overwrite', () => {
|
|
40
|
+
const scan = {
|
|
41
|
+
services: [
|
|
42
|
+
{
|
|
43
|
+
service_name: 'api',
|
|
44
|
+
description: 'LLM-suggested description',
|
|
45
|
+
confidence: { description: 'high' },
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
const state = {
|
|
50
|
+
version: 1,
|
|
51
|
+
lastRunAt: new Date().toISOString(),
|
|
52
|
+
provider: 'openai',
|
|
53
|
+
model: 'gpt-4o',
|
|
54
|
+
fields: {
|
|
55
|
+
'services.api.description': 'user',
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
const config = {
|
|
59
|
+
...BASE_CONFIG,
|
|
60
|
+
services: [
|
|
61
|
+
{ ...BASE_CONFIG.services[0], description: 'My custom description' },
|
|
62
|
+
BASE_CONFIG.services[1],
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
const { updated, suggestions, changedFields } = mergeWorkspaceConfig(config, scan, state);
|
|
66
|
+
assert.equal(updated.services[0].description, 'My custom description');
|
|
67
|
+
assert.ok(!changedFields.includes('services.api.description'));
|
|
68
|
+
assert.ok(suggestions.some((s) => s.path === 'services.api.description'));
|
|
69
|
+
assert.equal(suggestions.find((s) => s.path === 'services.api.description')?.suggestedValue, 'LLM-suggested description');
|
|
70
|
+
});
|
|
71
|
+
it('scan-provenance field gets updated with new value', () => {
|
|
72
|
+
const scan = {
|
|
73
|
+
services: [
|
|
74
|
+
{
|
|
75
|
+
service_name: 'api',
|
|
76
|
+
description: 'Updated description from scan',
|
|
77
|
+
confidence: { description: 'high' },
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
const state = {
|
|
82
|
+
version: 1,
|
|
83
|
+
lastRunAt: new Date().toISOString(),
|
|
84
|
+
provider: 'openai',
|
|
85
|
+
model: 'gpt-4o',
|
|
86
|
+
fields: {
|
|
87
|
+
'services.api.description': 'scan',
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
const config = {
|
|
91
|
+
...BASE_CONFIG,
|
|
92
|
+
services: [
|
|
93
|
+
{ ...BASE_CONFIG.services[0], description: 'Previous scan description' },
|
|
94
|
+
BASE_CONFIG.services[1],
|
|
95
|
+
],
|
|
96
|
+
};
|
|
97
|
+
const { updated, changedFields } = mergeWorkspaceConfig(config, scan, state);
|
|
98
|
+
assert.equal(updated.services[0].description, 'Updated description from scan');
|
|
99
|
+
assert.ok(changedFields.includes('services.api.description'));
|
|
100
|
+
});
|
|
101
|
+
it('commands are only filled when absent', () => {
|
|
102
|
+
const scan = {
|
|
103
|
+
services: [
|
|
104
|
+
{
|
|
105
|
+
service_name: 'api',
|
|
106
|
+
commands: { dev: 'pnpm dev', build: 'pnpm build', test: 'pnpm test' },
|
|
107
|
+
confidence: {},
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
};
|
|
111
|
+
const config = {
|
|
112
|
+
...BASE_CONFIG,
|
|
113
|
+
services: [
|
|
114
|
+
{ ...BASE_CONFIG.services[0], commands: { dev: 'npm run dev' } },
|
|
115
|
+
BASE_CONFIG.services[1],
|
|
116
|
+
],
|
|
117
|
+
};
|
|
118
|
+
const { updated, suggestions } = mergeWorkspaceConfig(config, scan, null);
|
|
119
|
+
// dev was set by user — should not overwrite
|
|
120
|
+
assert.equal(updated.services[0].commands?.dev, 'npm run dev');
|
|
121
|
+
// build was absent — should fill
|
|
122
|
+
assert.equal(updated.services[0].commands?.build, 'pnpm build');
|
|
123
|
+
// User-set dev should appear as suggestion
|
|
124
|
+
assert.ok(suggestions.some((s) => s.path.endsWith('commands.dev')));
|
|
125
|
+
});
|
|
126
|
+
it('database type-fallback applies when exactly one DB of that type exists', () => {
|
|
127
|
+
const config = {
|
|
128
|
+
...BASE_CONFIG,
|
|
129
|
+
databases: [{ name: 'main-db', type: 'postgresql' }],
|
|
130
|
+
};
|
|
131
|
+
const scan = {
|
|
132
|
+
services: [{ service_name: 'api', confidence: {} }],
|
|
133
|
+
cross_service: {
|
|
134
|
+
databases: [{ name: 'renamed-pg', type: 'postgresql', description: 'Main database' }],
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
// When exactly one PostgreSQL db exists, type-fallback matches it
|
|
138
|
+
const { updated } = mergeWorkspaceConfig(config, scan, null);
|
|
139
|
+
// The existing DB should get the description merged
|
|
140
|
+
const mainDb = updated.databases?.find((d) => d.name === 'main-db');
|
|
141
|
+
assert.ok(mainDb, 'original DB preserved');
|
|
142
|
+
assert.equal(mainDb?.description, 'Main database');
|
|
143
|
+
});
|
|
144
|
+
it('database type-fallback rejected when two DBs share the same type', () => {
|
|
145
|
+
const config = {
|
|
146
|
+
...BASE_CONFIG,
|
|
147
|
+
databases: [
|
|
148
|
+
{ name: 'db-a', type: 'postgresql' },
|
|
149
|
+
{ name: 'db-b', type: 'postgresql' },
|
|
150
|
+
],
|
|
151
|
+
};
|
|
152
|
+
const scan = {
|
|
153
|
+
services: [{ service_name: 'api', confidence: {} }],
|
|
154
|
+
cross_service: {
|
|
155
|
+
databases: [{ name: 'some-pg', type: 'postgresql', description: 'ambiguous' }],
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
// Two PostgreSQL dbs — no type fallback, new DB should be added
|
|
159
|
+
const { updated } = mergeWorkspaceConfig(config, scan, null);
|
|
160
|
+
assert.ok(updated.databases?.length === 3, 'new DB added since no unique type match');
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
//# sourceMappingURL=merge.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.test.js","sourceRoot":"","sources":["../../../src/scan/__tests__/merge.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-bootstrap.d.ts","sourceRoot":"","sources":["../../src/scan/auto-bootstrap.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAczE,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,GAAG,IAAI,GACtB,OAAO,CAAC,OAAO,CAAC,CAwBlB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { TIER_LIMITS, readScanState } from '@nepopsx/core';
|
|
3
|
+
import { scanCommand } from '../commands/scan.js';
|
|
4
|
+
const AUTO_SCAN_MAX_AGE_DAYS = 7;
|
|
5
|
+
function getScanAgeDays(lastRunAt) {
|
|
6
|
+
const lastRun = new Date(lastRunAt).getTime();
|
|
7
|
+
if (Number.isNaN(lastRun)) {
|
|
8
|
+
return Number.POSITIVE_INFINITY;
|
|
9
|
+
}
|
|
10
|
+
return (Date.now() - lastRun) / (1000 * 60 * 60 * 24);
|
|
11
|
+
}
|
|
12
|
+
export async function ensureFreshWorkspaceScan(rootDir, license) {
|
|
13
|
+
if (!license || !TIER_LIMITS[license.tier].scan_allowed) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
const scanState = readScanState(rootDir);
|
|
17
|
+
if (!scanState) {
|
|
18
|
+
console.log(chalk.yellow('\nNo scan state found. Running required bootstrap scan before backend sync...'));
|
|
19
|
+
await scanCommand({ yes: true, resume: true });
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
const ageDays = getScanAgeDays(scanState.lastRunAt);
|
|
23
|
+
if (ageDays <= AUTO_SCAN_MAX_AGE_DAYS) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
console.log(chalk.yellow(`\nScan state is stale (${Math.floor(ageDays)} day(s) old). Running required refresh scan before backend sync...`));
|
|
27
|
+
await scanCommand({ yes: true, resume: true });
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=auto-bootstrap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-bootstrap.js","sourceRoot":"","sources":["../../src/scan/auto-bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAgB,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAEjC,SAAS,cAAc,CAAC,SAAiB;IACvC,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;IAC9C,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1B,OAAO,MAAM,CAAC,iBAAiB,CAAC;IAClC,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,OAAe,EACf,OAAuB;IAEvB,IAAI,CAAC,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,CAAC;QACxD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,SAAS,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACzC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,+EAA+E,CAAC,CAAC,CAAC;QAC3G,MAAM,WAAW,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,OAAO,GAAG,cAAc,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACpD,IAAI,OAAO,IAAI,sBAAsB,EAAE,CAAC;QACtC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CACV,0BAA0B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,oEAAoE,CAClH,CACF,CAAC;IACF,MAAM,WAAW,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ProviderName } from './llm/types.js';
|
|
2
|
+
export interface ResolvedScanConfig {
|
|
3
|
+
provider: ProviderName;
|
|
4
|
+
model: string;
|
|
5
|
+
/** API key — resolved from env only, never persisted */
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
/** Custom endpoint for ollama or compatible providers */
|
|
8
|
+
endpoint?: string;
|
|
9
|
+
/** Per-service token budget */
|
|
10
|
+
budget: number;
|
|
11
|
+
/** Total context budget for agent mode */
|
|
12
|
+
agentBudget: number;
|
|
13
|
+
/** Concurrent service analysis */
|
|
14
|
+
parallel: number;
|
|
15
|
+
customs: boolean;
|
|
16
|
+
dryRun: boolean;
|
|
17
|
+
verbose: boolean;
|
|
18
|
+
yes: boolean;
|
|
19
|
+
/** Service name filter (undefined = all services) */
|
|
20
|
+
services?: string[];
|
|
21
|
+
resume: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare function resolveScanConfig(flags: Record<string, unknown>, cwd?: string): Promise<ResolvedScanConfig>;
|
|
24
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/scan/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,YAAY,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,OAAO,CAAC;IACb,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;CACjB;AAkCD,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,kBAAkB,CAAC,CA0D7B"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// @nepopsx/cli — Provider config resolution for scan command
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
function readConfigFile(cwd) {
|
|
5
|
+
const configPath = join(cwd, '.nepopsx', 'config.json');
|
|
6
|
+
if (!existsSync(configPath))
|
|
7
|
+
return {};
|
|
8
|
+
try {
|
|
9
|
+
const raw = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
10
|
+
return (raw.scan ?? {});
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return {};
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const PROVIDER_DEFAULTS = {
|
|
17
|
+
openai: 'gpt-4o',
|
|
18
|
+
anthropic: 'claude-3-5-sonnet-20241022',
|
|
19
|
+
ollama: 'llama3.2',
|
|
20
|
+
compatible: 'gpt-4o',
|
|
21
|
+
};
|
|
22
|
+
function parseIntSafe(value, fallback) {
|
|
23
|
+
const n = parseInt(String(value ?? fallback), 10);
|
|
24
|
+
return isNaN(n) ? fallback : n;
|
|
25
|
+
}
|
|
26
|
+
export async function resolveScanConfig(flags, cwd = process.cwd()) {
|
|
27
|
+
const fileConf = readConfigFile(cwd);
|
|
28
|
+
// Resolve provider: CLI flags > env > config file > default (ollama)
|
|
29
|
+
const providerRaw = flags.provider ??
|
|
30
|
+
process.env.NEPOPSX_LLM_PROVIDER ??
|
|
31
|
+
fileConf.provider ??
|
|
32
|
+
'ollama';
|
|
33
|
+
const provider = providerRaw;
|
|
34
|
+
// Resolve model: CLI flags > env > config file > provider default
|
|
35
|
+
const model = flags.model ??
|
|
36
|
+
process.env.NEPOPSX_LLM_MODEL ??
|
|
37
|
+
fileConf.model ??
|
|
38
|
+
PROVIDER_DEFAULTS[provider] ??
|
|
39
|
+
'gpt-4o';
|
|
40
|
+
// Resolve API key from env only — never from config file (C3)
|
|
41
|
+
let apiKey;
|
|
42
|
+
if (provider === 'openai' || provider === 'compatible') {
|
|
43
|
+
apiKey =
|
|
44
|
+
flags.apiKey ??
|
|
45
|
+
process.env.OPENAI_API_KEY ??
|
|
46
|
+
process.env.NEPOPSX_LLM_API_KEY;
|
|
47
|
+
}
|
|
48
|
+
else if (provider === 'anthropic') {
|
|
49
|
+
apiKey =
|
|
50
|
+
flags.apiKey ??
|
|
51
|
+
process.env.ANTHROPIC_API_KEY ??
|
|
52
|
+
process.env.NEPOPSX_LLM_API_KEY;
|
|
53
|
+
}
|
|
54
|
+
const endpoint = flags.endpoint ?? fileConf.endpoint;
|
|
55
|
+
const budget = parseIntSafe(flags.budget ?? fileConf.budget, 30_000);
|
|
56
|
+
const agentBudget = parseIntSafe(flags.agentBudget ?? fileConf.agentBudget, 60_000);
|
|
57
|
+
const parallel = parseIntSafe(flags.parallel ?? fileConf.parallel, 1);
|
|
58
|
+
return {
|
|
59
|
+
provider,
|
|
60
|
+
model,
|
|
61
|
+
apiKey,
|
|
62
|
+
endpoint,
|
|
63
|
+
budget,
|
|
64
|
+
agentBudget,
|
|
65
|
+
parallel,
|
|
66
|
+
customs: Boolean(flags.customs),
|
|
67
|
+
dryRun: Boolean(flags.dryRun),
|
|
68
|
+
verbose: Boolean(flags.verbose),
|
|
69
|
+
yes: Boolean(flags.yes),
|
|
70
|
+
// Empty array (Commander default when --service not passed) means "all services"
|
|
71
|
+
services: Array.isArray(flags.service) && flags.service.length > 0
|
|
72
|
+
? flags.service
|
|
73
|
+
: undefined,
|
|
74
|
+
resume: Boolean(flags.resume),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/scan/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface FileContext {
|
|
2
|
+
/** relativePath → content */
|
|
3
|
+
files: Map<string, string>;
|
|
4
|
+
totalTokens: number;
|
|
5
|
+
/** Files skipped due to budget overflow (for --verbose logging) */
|
|
6
|
+
skippedFiles: string[];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Gather high-signal files from a service directory, respecting a token budget.
|
|
10
|
+
* Uses stat-first estimation to avoid reading files that would exceed budget.
|
|
11
|
+
*/
|
|
12
|
+
export declare function gatherContext(servicePath: string, framework: string | undefined, budget: number, ignoreFilter?: (path: string) => boolean): Promise<FileContext>;
|
|
13
|
+
//# sourceMappingURL=gatherer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gatherer.d.ts","sourceRoot":"","sources":["../../../src/scan/context/gatherer.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,WAAW;IAC1B,6BAA6B;IAC7B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AA0BD;;;GAGG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GACvC,OAAO,CAAC,WAAW,CAAC,CAuEtB"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// @nepopsx/cli — Stat-first context gatherer with tiered budget enforcement
|
|
2
|
+
import { statSync } from 'node:fs';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { glob } from 'glob';
|
|
6
|
+
import { getPatternsForFramework } from './patterns.js';
|
|
7
|
+
import { loadIgnoreFilter } from './gitignore.js';
|
|
8
|
+
/** Estimate tokens from file size before reading */
|
|
9
|
+
function estimateTokensFromSize(bytes) {
|
|
10
|
+
return Math.ceil(bytes / 3);
|
|
11
|
+
}
|
|
12
|
+
/** Count actual tokens after reading */
|
|
13
|
+
function countTokens(content) {
|
|
14
|
+
return Math.ceil(content.length / 3.5);
|
|
15
|
+
}
|
|
16
|
+
async function globSafe(pattern, cwd) {
|
|
17
|
+
try {
|
|
18
|
+
return await glob(pattern, { cwd, nodir: true, dot: false });
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Gather high-signal files from a service directory, respecting a token budget.
|
|
26
|
+
* Uses stat-first estimation to avoid reading files that would exceed budget.
|
|
27
|
+
*/
|
|
28
|
+
export async function gatherContext(servicePath, framework, budget, ignoreFilter) {
|
|
29
|
+
const filter = ignoreFilter ?? loadIgnoreFilter(servicePath);
|
|
30
|
+
const patterns = getPatternsForFramework(framework);
|
|
31
|
+
const files = new Map();
|
|
32
|
+
const skippedFiles = [];
|
|
33
|
+
let totalTokens = 0;
|
|
34
|
+
async function processPatterns(globs, maxFiles) {
|
|
35
|
+
// Collect all matching paths
|
|
36
|
+
const matchedPaths = new Set();
|
|
37
|
+
for (const pattern of globs) {
|
|
38
|
+
const matches = await globSafe(pattern, servicePath);
|
|
39
|
+
for (const m of matches) {
|
|
40
|
+
matchedPaths.add(m);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Stat-first: estimate tokens for all matched files before reading any
|
|
44
|
+
const candidates = [];
|
|
45
|
+
for (const relPath of matchedPaths) {
|
|
46
|
+
if (files.has(relPath))
|
|
47
|
+
continue; // already included
|
|
48
|
+
if (filter(relPath))
|
|
49
|
+
continue; // gitignored
|
|
50
|
+
const absPath = join(servicePath, relPath);
|
|
51
|
+
try {
|
|
52
|
+
const stats = statSync(absPath);
|
|
53
|
+
if (!stats.isFile())
|
|
54
|
+
continue;
|
|
55
|
+
const estimatedTokens = estimateTokensFromSize(stats.size);
|
|
56
|
+
candidates.push({ absPath, relPath, estimatedTokens });
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// File may have disappeared between glob and stat
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Sort by path depth ascending, then by estimated size ascending
|
|
63
|
+
candidates.sort((a, b) => {
|
|
64
|
+
const depthA = a.relPath.split('/').length;
|
|
65
|
+
const depthB = b.relPath.split('/').length;
|
|
66
|
+
return depthA !== depthB ? depthA - depthB : a.estimatedTokens - b.estimatedTokens;
|
|
67
|
+
});
|
|
68
|
+
// Apply maxFiles limit for tier3
|
|
69
|
+
const limited = maxFiles !== undefined ? candidates.slice(0, maxFiles) : candidates;
|
|
70
|
+
// Read files that fit within remaining budget
|
|
71
|
+
for (const candidate of limited) {
|
|
72
|
+
if (totalTokens + candidate.estimatedTokens > budget) {
|
|
73
|
+
skippedFiles.push(candidate.relPath);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const content = await readFile(candidate.absPath, 'utf-8');
|
|
78
|
+
const actualTokens = countTokens(content);
|
|
79
|
+
if (totalTokens + actualTokens > budget) {
|
|
80
|
+
skippedFiles.push(candidate.relPath);
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
files.set(candidate.relPath, content);
|
|
84
|
+
totalTokens += actualTokens;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// Skip unreadable files
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Process tiers in priority order
|
|
92
|
+
await processPatterns(patterns.tier1);
|
|
93
|
+
await processPatterns(patterns.tier2);
|
|
94
|
+
await processPatterns(patterns.tier3, 3);
|
|
95
|
+
return { files, totalTokens, skippedFiles };
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=gatherer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gatherer.js","sourceRoot":"","sources":["../../../src/scan/context/gatherer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a filter function for a service directory using .gitignore rules.
|
|
3
|
+
* Falls back to default exclusions if no .gitignore exists.
|
|
4
|
+
*
|
|
5
|
+
* @param serviceDir Absolute path to the service root directory
|
|
6
|
+
* @returns A function: (relativePath: string) => boolean — true if path should be ignored
|
|
7
|
+
*/
|
|
8
|
+
export declare function loadIgnoreFilter(serviceDir: string): (path: string) => boolean;
|
|
9
|
+
//# sourceMappingURL=gitignore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitignore.d.ts","sourceRoot":"","sources":["../../../src/scan/context/gitignore.ts"],"names":[],"mappings":"AAqBA;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAuB9E"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// @nepopsx/cli — .gitignore parsing using the `ignore` package
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import ignore from 'ignore';
|
|
5
|
+
const DEFAULT_EXCLUDES = [
|
|
6
|
+
'node_modules',
|
|
7
|
+
'dist',
|
|
8
|
+
'.git',
|
|
9
|
+
'__pycache__',
|
|
10
|
+
'vendor',
|
|
11
|
+
'build',
|
|
12
|
+
'.next',
|
|
13
|
+
'.nuxt',
|
|
14
|
+
'coverage',
|
|
15
|
+
'target',
|
|
16
|
+
'.cache',
|
|
17
|
+
'.turbo',
|
|
18
|
+
'*.log',
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Create a filter function for a service directory using .gitignore rules.
|
|
22
|
+
* Falls back to default exclusions if no .gitignore exists.
|
|
23
|
+
*
|
|
24
|
+
* @param serviceDir Absolute path to the service root directory
|
|
25
|
+
* @returns A function: (relativePath: string) => boolean — true if path should be ignored
|
|
26
|
+
*/
|
|
27
|
+
export function loadIgnoreFilter(serviceDir) {
|
|
28
|
+
const ig = ignore();
|
|
29
|
+
// Add default exclusions
|
|
30
|
+
ig.add(DEFAULT_EXCLUDES);
|
|
31
|
+
// Add .gitignore if it exists
|
|
32
|
+
const gitignorePath = join(serviceDir, '.gitignore');
|
|
33
|
+
if (existsSync(gitignorePath)) {
|
|
34
|
+
try {
|
|
35
|
+
const content = readFileSync(gitignorePath, 'utf-8');
|
|
36
|
+
ig.add(content);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Silently ignore read errors
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return (relPath) => {
|
|
43
|
+
// The `ignore` package requires paths without leading slashes
|
|
44
|
+
const normalized = relPath.startsWith('/') ? relPath.slice(1) : relPath;
|
|
45
|
+
if (!normalized)
|
|
46
|
+
return false;
|
|
47
|
+
return ig.ignores(normalized);
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=gitignore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitignore.js","sourceRoot":"","sources":["../../../src/scan/context/gitignore.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,gBAAgB,GAAG;IACvB,cAAc;IACd,MAAM;IACN,MAAM;IACN,aAAa;IACb,QAAQ;IACR,OAAO;IACP,OAAO;IACP,OAAO;IACP,UAAU;IACV,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,OAAO;CACR,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAkB;IACjD,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IAEpB,yBAAyB;IACzB,EAAE,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAEzB,8BAA8B;IAC9B,MAAM,aAAa,GAAG,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IACrD,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;YACrD,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC;YACP,8BAA8B;QAChC,CAAC;IACH,CAAC;IAED,OAAO,CAAC,OAAe,EAAE,EAAE;QACzB,8DAA8D;QAC9D,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QACxE,IAAI,CAAC,UAAU;YAAE,OAAO,KAAK,CAAC;QAC9B,OAAO,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface TieredPatterns {
|
|
2
|
+
/** Always include — entry points, config files, manifests */
|
|
3
|
+
tier1: string[];
|
|
4
|
+
/** Include if budget allows — key modules, route definitions */
|
|
5
|
+
tier2: string[];
|
|
6
|
+
/** Sample if budget allows — representative implementation files (max 3) */
|
|
7
|
+
tier3: string[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Get tiered file patterns for a given framework.
|
|
11
|
+
* The returned patterns are merged with the base patterns.
|
|
12
|
+
*/
|
|
13
|
+
export declare function getPatternsForFramework(framework: string | undefined): TieredPatterns;
|
|
14
|
+
//# sourceMappingURL=patterns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../../src/scan/context/patterns.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,gEAAgE;IAChE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,4EAA4E;IAC5E,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAoJD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,CASrF"}
|