@dzhechkov/harness-core 0.3.9 → 0.3.11
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/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/pretrain.d.ts +33 -0
- package/dist/pretrain.d.ts.map +1 -0
- package/dist/pretrain.js +241 -0
- package/dist/pretrain.js.map +1 -0
- package/dist/setup.d.ts +40 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +150 -0
- package/dist/setup.js.map +1 -0
- package/package.json +3 -3
- package/src/index.ts +4 -0
- package/src/pretrain.ts +281 -0
- package/src/setup.ts +177 -0
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,10 @@ export type { SyncUpstreamReport, UpstreamCheckResult, SourcesManifest, SourcePa
|
|
|
17
17
|
export { benchmarkSkill, benchmarkSkills, compareSkills } from './benchmark.js';
|
|
18
18
|
export { buildRegistry, searchRegistry, filterByCategory } from './registry.js';
|
|
19
19
|
export { recommend } from './recommend.js';
|
|
20
|
+
export { pretrain } from './pretrain.js';
|
|
21
|
+
export { runSetup } from './setup.js';
|
|
22
|
+
export type { SetupOptions, SetupResult, SetupStep } from './setup.js';
|
|
23
|
+
export type { PretrainResult, DetectedTech } from './pretrain.js';
|
|
20
24
|
export type { RecommendationReport, SkillRecommendation } from './recommend.js';
|
|
21
25
|
export { discoverPackages, publishPackages } from './publish.js';
|
|
22
26
|
export { fetchAllDownloads } from './downloads.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,yDAAyD;AACzD,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAE5C,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAClH,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACtH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAChE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAChF,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,yDAAyD;AACzD,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAE5C,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAClH,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACtH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClE,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAChE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAChF,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,8 @@ export { checkUpstream, checkAllUpstream, discoverSourcePackages, loadSourcesMan
|
|
|
15
15
|
export { benchmarkSkill, benchmarkSkills, compareSkills } from './benchmark.js';
|
|
16
16
|
export { buildRegistry, searchRegistry, filterByCategory } from './registry.js';
|
|
17
17
|
export { recommend } from './recommend.js';
|
|
18
|
+
export { pretrain } from './pretrain.js';
|
|
19
|
+
export { runSetup } from './setup.js';
|
|
18
20
|
export { discoverPackages, publishPackages } from './publish.js';
|
|
19
21
|
export { fetchAllDownloads } from './downloads.js';
|
|
20
22
|
export { discoverInstalled, checkUpgrades } from './upgrade.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,yDAAyD;AACzD,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC;AAE5C,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAElH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,yDAAyD;AACzD,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC;AAE5C,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAElH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItC,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pretrain — bootstrap intelligence by analyzing the target project.
|
|
3
|
+
*
|
|
4
|
+
* Scans the project's file structure, package.json, and tech stack to
|
|
5
|
+
* automatically recommend the right skills and presets. Runs during
|
|
6
|
+
* `dz init --pretrain` to eliminate manual preset selection.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
/** Detected technology in the project. */
|
|
11
|
+
export interface DetectedTech {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly category: string;
|
|
14
|
+
readonly confidence: number;
|
|
15
|
+
readonly source: string;
|
|
16
|
+
}
|
|
17
|
+
/** Pretrain analysis result. */
|
|
18
|
+
export interface PretrainResult {
|
|
19
|
+
readonly projectName: string;
|
|
20
|
+
readonly techs: readonly DetectedTech[];
|
|
21
|
+
readonly recommendedPresets: readonly string[];
|
|
22
|
+
readonly recommendedSkills: readonly string[];
|
|
23
|
+
readonly projectType: string;
|
|
24
|
+
readonly hasTests: boolean;
|
|
25
|
+
readonly hasDocker: boolean;
|
|
26
|
+
readonly hasCI: boolean;
|
|
27
|
+
readonly hasTerraform: boolean;
|
|
28
|
+
readonly hasKubernetes: boolean;
|
|
29
|
+
readonly packageCount: number;
|
|
30
|
+
}
|
|
31
|
+
/** Run pretrain analysis on a project. */
|
|
32
|
+
export declare function pretrain(projectRoot: string): PretrainResult;
|
|
33
|
+
//# sourceMappingURL=pretrain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pretrain.d.ts","sourceRoot":"","sources":["../src/pretrain.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,0CAA0C;AAC1C,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,gCAAgC;AAChC,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IACxC,QAAQ,CAAC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/C,QAAQ,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AA8KD,0CAA0C;AAC1C,wBAAgB,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,CAuE5D"}
|
package/dist/pretrain.js
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pretrain — bootstrap intelligence by analyzing the target project.
|
|
3
|
+
*
|
|
4
|
+
* Scans the project's file structure, package.json, and tech stack to
|
|
5
|
+
* automatically recommend the right skills and presets. Runs during
|
|
6
|
+
* `dz init --pretrain` to eliminate manual preset selection.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
/** Tech detection rules: file/pattern → tech. */
|
|
13
|
+
const DETECTORS = [
|
|
14
|
+
// Languages/Frameworks
|
|
15
|
+
{ glob: 'package.json', tech: 'node.js', category: 'runtime' },
|
|
16
|
+
{ glob: 'tsconfig.json', tech: 'typescript', category: 'language' },
|
|
17
|
+
{ glob: 'requirements.txt', tech: 'python', category: 'runtime' },
|
|
18
|
+
{ glob: 'pyproject.toml', tech: 'python', category: 'runtime' },
|
|
19
|
+
{ glob: 'go.mod', tech: 'go', category: 'runtime' },
|
|
20
|
+
{ glob: 'Cargo.toml', tech: 'rust', category: 'runtime' },
|
|
21
|
+
{ glob: 'Gemfile', tech: 'ruby', category: 'runtime' },
|
|
22
|
+
// Frontend
|
|
23
|
+
{ glob: 'next.config', tech: 'next.js', category: 'frontend' },
|
|
24
|
+
{ glob: 'vite.config', tech: 'vite', category: 'frontend' },
|
|
25
|
+
{ glob: 'tailwind.config', tech: 'tailwind', category: 'frontend' },
|
|
26
|
+
// Databases
|
|
27
|
+
{ glob: 'prisma', tech: 'prisma', category: 'database' },
|
|
28
|
+
{ glob: 'drizzle.config', tech: 'drizzle', category: 'database' },
|
|
29
|
+
{ glob: 'knexfile', tech: 'knex', category: 'database' },
|
|
30
|
+
// Infrastructure
|
|
31
|
+
{ glob: 'Dockerfile', tech: 'docker', category: 'infra' },
|
|
32
|
+
{ glob: 'docker-compose', tech: 'docker-compose', category: 'infra' },
|
|
33
|
+
{ glob: '.github/workflows', tech: 'github-actions', category: 'ci' },
|
|
34
|
+
{ glob: '.gitlab-ci.yml', tech: 'gitlab-ci', category: 'ci' },
|
|
35
|
+
{ glob: 'terraform', tech: 'terraform', category: 'iac' },
|
|
36
|
+
{ glob: '.tf', tech: 'terraform', category: 'iac' },
|
|
37
|
+
{ glob: 'k8s', tech: 'kubernetes', category: 'infra' },
|
|
38
|
+
{ glob: 'helm', tech: 'helm', category: 'infra' },
|
|
39
|
+
{ glob: 'nginx.conf', tech: 'nginx', category: 'infra' },
|
|
40
|
+
// Testing
|
|
41
|
+
{ glob: 'vitest.config', tech: 'vitest', category: 'testing' },
|
|
42
|
+
{ glob: 'jest.config', tech: 'jest', category: 'testing' },
|
|
43
|
+
{ glob: 'playwright.config', tech: 'playwright', category: 'testing' },
|
|
44
|
+
{ glob: 'cypress.config', tech: 'cypress', category: 'testing' },
|
|
45
|
+
{ glob: '.stryker', tech: 'stryker', category: 'testing' },
|
|
46
|
+
// Data
|
|
47
|
+
{ glob: 'dbt_project.yml', tech: 'dbt', category: 'data' },
|
|
48
|
+
{ glob: 'airflow', tech: 'airflow', category: 'data' },
|
|
49
|
+
// API
|
|
50
|
+
{ glob: 'openapi', tech: 'openapi', category: 'api' },
|
|
51
|
+
{ glob: 'swagger', tech: 'swagger', category: 'api' },
|
|
52
|
+
{ glob: '.graphql', tech: 'graphql', category: 'api' },
|
|
53
|
+
{ glob: 'schema.graphql', tech: 'graphql', category: 'api' },
|
|
54
|
+
// Cache/Queue
|
|
55
|
+
{ glob: 'redis', tech: 'redis', category: 'cache' },
|
|
56
|
+
// Knowledge
|
|
57
|
+
{ glob: '.obsidian', tech: 'obsidian', category: 'knowledge' },
|
|
58
|
+
];
|
|
59
|
+
/** Map tech categories to recommended skills. */
|
|
60
|
+
const CATEGORY_TO_SKILLS = {
|
|
61
|
+
'runtime': ['debugging', 'test-writer', 'pr-review'],
|
|
62
|
+
'language': ['test-writer', 'pr-review'],
|
|
63
|
+
'frontend': ['frontend-implementation', 'playwright-testing'],
|
|
64
|
+
'database': ['database-review', 'database-migration'],
|
|
65
|
+
'infra': ['docker-compose', 'kubernetes', 'nginx-config'],
|
|
66
|
+
'ci': ['ci-fix', 'github-actions'],
|
|
67
|
+
'iac': ['terraform'],
|
|
68
|
+
'testing': ['test-writer', 'playwright-testing'],
|
|
69
|
+
'data': ['data-pipeline'],
|
|
70
|
+
'api': ['api-design', 'graphql-schema'],
|
|
71
|
+
'cache': ['redis-patterns'],
|
|
72
|
+
'knowledge': ['obsidian'],
|
|
73
|
+
};
|
|
74
|
+
/** Map detected skills to presets. */
|
|
75
|
+
const SKILL_TO_PRESET = {
|
|
76
|
+
'pr-review': 'devops', 'security-audit': 'devops', 'test-writer': 'devops',
|
|
77
|
+
'ci-fix': 'devops', 'terraform': 'devops', 'kubernetes': 'devops',
|
|
78
|
+
'docker-compose': 'devops', 'api-design': 'devops', 'debugging': 'devops',
|
|
79
|
+
'database-review': 'devops', 'database-migration': 'devops',
|
|
80
|
+
'github-actions': 'devops', 'nginx-config': 'devops', 'redis-patterns': 'devops',
|
|
81
|
+
'graphql-schema': 'devops', 'playwright-testing': 'devops',
|
|
82
|
+
'data-pipeline': 'devops', 'incident-response': 'devops',
|
|
83
|
+
'frontend-implementation': 'devops', 'monorepo-management': 'devops',
|
|
84
|
+
'brave-search': 'mcp', 'gmail': 'mcp', 'notion': 'mcp', 'obsidian': 'mcp',
|
|
85
|
+
'git-mcp': 'mcp', 'context7': 'mcp',
|
|
86
|
+
};
|
|
87
|
+
/** Scan project directory for files matching detectors. */
|
|
88
|
+
function scanProject(projectRoot) {
|
|
89
|
+
const techs = [];
|
|
90
|
+
const seen = new Set();
|
|
91
|
+
// Check top-level files
|
|
92
|
+
let entries = [];
|
|
93
|
+
try {
|
|
94
|
+
entries = readdirSync(projectRoot).map((e) => e.toLowerCase());
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
for (const detector of DETECTORS) {
|
|
100
|
+
const globLower = detector.glob.toLowerCase();
|
|
101
|
+
const match = entries.some((e) => e.includes(globLower));
|
|
102
|
+
if (match && !seen.has(detector.tech)) {
|
|
103
|
+
seen.add(detector.tech);
|
|
104
|
+
techs.push({
|
|
105
|
+
name: detector.tech,
|
|
106
|
+
category: detector.category,
|
|
107
|
+
confidence: 0.9,
|
|
108
|
+
source: detector.glob,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Check subdirectories (1 level deep)
|
|
113
|
+
for (const entry of entries) {
|
|
114
|
+
const subPath = join(projectRoot, entry);
|
|
115
|
+
try {
|
|
116
|
+
const subEntries = readdirSync(subPath).map((e) => e.toLowerCase());
|
|
117
|
+
for (const detector of DETECTORS) {
|
|
118
|
+
const globLower = detector.glob.toLowerCase();
|
|
119
|
+
if (subEntries.some((e) => e.includes(globLower)) && !seen.has(detector.tech)) {
|
|
120
|
+
seen.add(detector.tech);
|
|
121
|
+
techs.push({
|
|
122
|
+
name: detector.tech,
|
|
123
|
+
category: detector.category,
|
|
124
|
+
confidence: 0.7,
|
|
125
|
+
source: `${entry}/${detector.glob}`,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch { /* not a directory or no access */ }
|
|
131
|
+
}
|
|
132
|
+
// Parse package.json for deps
|
|
133
|
+
const pkgPath = join(projectRoot, 'package.json');
|
|
134
|
+
if (existsSync(pkgPath)) {
|
|
135
|
+
try {
|
|
136
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
137
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
138
|
+
const depNames = Object.keys(allDeps).map((d) => d.toLowerCase());
|
|
139
|
+
const depDetectors = [
|
|
140
|
+
['next', 'next.js', 'frontend'],
|
|
141
|
+
['react', 'react', 'frontend'],
|
|
142
|
+
['vue', 'vue', 'frontend'],
|
|
143
|
+
['express', 'express', 'api'],
|
|
144
|
+
['fastify', 'fastify', 'api'],
|
|
145
|
+
['prisma', 'prisma', 'database'],
|
|
146
|
+
['drizzle-orm', 'drizzle', 'database'],
|
|
147
|
+
['redis', 'redis', 'cache'],
|
|
148
|
+
['ioredis', 'redis', 'cache'],
|
|
149
|
+
['bullmq', 'bullmq', 'queue'],
|
|
150
|
+
['graphql', 'graphql', 'api'],
|
|
151
|
+
['playwright', 'playwright', 'testing'],
|
|
152
|
+
['vitest', 'vitest', 'testing'],
|
|
153
|
+
['jest', 'jest', 'testing'],
|
|
154
|
+
];
|
|
155
|
+
for (const [dep, tech, category] of depDetectors) {
|
|
156
|
+
if (depNames.some((d) => d.includes(dep)) && !seen.has(tech)) {
|
|
157
|
+
seen.add(tech);
|
|
158
|
+
techs.push({ name: tech, category, confidence: 0.8, source: `package.json dep: ${dep}` });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch { /* invalid JSON */ }
|
|
163
|
+
}
|
|
164
|
+
return techs.sort((a, b) => b.confidence - a.confidence);
|
|
165
|
+
}
|
|
166
|
+
/** Run pretrain analysis on a project. */
|
|
167
|
+
export function pretrain(projectRoot) {
|
|
168
|
+
const techs = scanProject(projectRoot);
|
|
169
|
+
// Determine recommended skills from detected techs
|
|
170
|
+
const skillSet = new Set();
|
|
171
|
+
// Always recommend core skills
|
|
172
|
+
skillSet.add('pr-review');
|
|
173
|
+
skillSet.add('security-audit');
|
|
174
|
+
skillSet.add('debugging');
|
|
175
|
+
for (const tech of techs) {
|
|
176
|
+
const skills = CATEGORY_TO_SKILLS[tech.category] ?? [];
|
|
177
|
+
for (const s of skills)
|
|
178
|
+
skillSet.add(s);
|
|
179
|
+
}
|
|
180
|
+
const recommendedSkills = [...skillSet].sort();
|
|
181
|
+
// Determine recommended presets
|
|
182
|
+
const presetCounts = new Map();
|
|
183
|
+
for (const skill of recommendedSkills) {
|
|
184
|
+
const preset = SKILL_TO_PRESET[skill];
|
|
185
|
+
if (preset)
|
|
186
|
+
presetCounts.set(preset, (presetCounts.get(preset) ?? 0) + 1);
|
|
187
|
+
}
|
|
188
|
+
const recommendedPresets = [...presetCounts.entries()]
|
|
189
|
+
.sort((a, b) => b[1] - a[1])
|
|
190
|
+
.map(([name]) => name);
|
|
191
|
+
// Detect project type
|
|
192
|
+
const categories = new Set(techs.map((t) => t.category));
|
|
193
|
+
let projectType = 'generic';
|
|
194
|
+
if (categories.has('frontend') && categories.has('api'))
|
|
195
|
+
projectType = 'fullstack';
|
|
196
|
+
else if (categories.has('frontend'))
|
|
197
|
+
projectType = 'frontend';
|
|
198
|
+
else if (categories.has('api'))
|
|
199
|
+
projectType = 'backend';
|
|
200
|
+
else if (categories.has('data'))
|
|
201
|
+
projectType = 'data-engineering';
|
|
202
|
+
else if (categories.has('iac'))
|
|
203
|
+
projectType = 'infrastructure';
|
|
204
|
+
// Detect package count (monorepo check)
|
|
205
|
+
let packageCount = 1;
|
|
206
|
+
const pkgPath = join(projectRoot, 'pnpm-workspace.yaml');
|
|
207
|
+
if (existsSync(pkgPath)) {
|
|
208
|
+
try {
|
|
209
|
+
const dirs = readdirSync(join(projectRoot, 'packages'), { withFileTypes: true })
|
|
210
|
+
.filter((e) => e.isDirectory());
|
|
211
|
+
packageCount = dirs.length;
|
|
212
|
+
if (packageCount > 3)
|
|
213
|
+
skillSet.add('monorepo-management');
|
|
214
|
+
}
|
|
215
|
+
catch { /* no packages dir */ }
|
|
216
|
+
}
|
|
217
|
+
// Get project name
|
|
218
|
+
let projectName = 'unknown';
|
|
219
|
+
const rootPkg = join(projectRoot, 'package.json');
|
|
220
|
+
if (existsSync(rootPkg)) {
|
|
221
|
+
try {
|
|
222
|
+
const pkg = JSON.parse(readFileSync(rootPkg, 'utf-8'));
|
|
223
|
+
projectName = pkg.name ?? 'unknown';
|
|
224
|
+
}
|
|
225
|
+
catch { /* */ }
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
projectName,
|
|
229
|
+
techs,
|
|
230
|
+
recommendedPresets,
|
|
231
|
+
recommendedSkills: [...skillSet].sort(),
|
|
232
|
+
projectType,
|
|
233
|
+
hasTests: techs.some((t) => t.category === 'testing'),
|
|
234
|
+
hasDocker: techs.some((t) => t.name === 'docker' || t.name === 'docker-compose'),
|
|
235
|
+
hasCI: techs.some((t) => t.category === 'ci'),
|
|
236
|
+
hasTerraform: techs.some((t) => t.name === 'terraform'),
|
|
237
|
+
hasKubernetes: techs.some((t) => t.name === 'kubernetes' || t.name === 'helm'),
|
|
238
|
+
packageCount,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=pretrain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pretrain.js","sourceRoot":"","sources":["../src/pretrain.ts"],"names":[],"mappings":"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"}
|
package/dist/setup.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Full environment setup — skills + hooks + memory + pretrain.
|
|
3
|
+
*
|
|
4
|
+
* Unlike `dz init` (skills only), `dz setup` configures the complete
|
|
5
|
+
* self-learning environment:
|
|
6
|
+
* 1. Skills installation (via init)
|
|
7
|
+
* 2. Claude Code hooks (session-start/end for memory)
|
|
8
|
+
* 3. Memory database initialization (.dz/memory.db)
|
|
9
|
+
* 4. Pretrain (project analysis → auto-recommend)
|
|
10
|
+
*
|
|
11
|
+
* All operations are additive — never overwrites existing files.
|
|
12
|
+
*
|
|
13
|
+
* @packageDocumentation
|
|
14
|
+
*/
|
|
15
|
+
/** Setup options. */
|
|
16
|
+
export interface SetupOptions {
|
|
17
|
+
readonly projectRoot: string;
|
|
18
|
+
readonly target: string;
|
|
19
|
+
readonly preset?: string | undefined;
|
|
20
|
+
readonly noHooks?: boolean | undefined;
|
|
21
|
+
readonly noMemory?: boolean | undefined;
|
|
22
|
+
readonly noPretrain?: boolean | undefined;
|
|
23
|
+
readonly force?: boolean | undefined;
|
|
24
|
+
}
|
|
25
|
+
/** Setup result. */
|
|
26
|
+
export interface SetupResult {
|
|
27
|
+
readonly steps: readonly SetupStep[];
|
|
28
|
+
readonly totalSteps: number;
|
|
29
|
+
readonly completed: number;
|
|
30
|
+
readonly skipped: number;
|
|
31
|
+
}
|
|
32
|
+
/** A single setup step. */
|
|
33
|
+
export interface SetupStep {
|
|
34
|
+
readonly name: string;
|
|
35
|
+
readonly status: 'done' | 'skipped' | 'error';
|
|
36
|
+
readonly detail: string;
|
|
37
|
+
}
|
|
38
|
+
/** Run full environment setup. */
|
|
39
|
+
export declare function runSetup(opts: SetupOptions): SetupResult;
|
|
40
|
+
//# sourceMappingURL=setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,qBAAqB;AACrB,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACtC;AAED,oBAAoB;AACpB,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,2BAA2B;AAC3B,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;IAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AA2CD,kCAAkC;AAClC,wBAAgB,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,WAAW,CA0FxD"}
|
package/dist/setup.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Full environment setup — skills + hooks + memory + pretrain.
|
|
3
|
+
*
|
|
4
|
+
* Unlike `dz init` (skills only), `dz setup` configures the complete
|
|
5
|
+
* self-learning environment:
|
|
6
|
+
* 1. Skills installation (via init)
|
|
7
|
+
* 2. Claude Code hooks (session-start/end for memory)
|
|
8
|
+
* 3. Memory database initialization (.dz/memory.db)
|
|
9
|
+
* 4. Pretrain (project analysis → auto-recommend)
|
|
10
|
+
*
|
|
11
|
+
* All operations are additive — never overwrites existing files.
|
|
12
|
+
*
|
|
13
|
+
* @packageDocumentation
|
|
14
|
+
*/
|
|
15
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs';
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
/** Generate Claude Code hooks configuration for self-learning. */
|
|
18
|
+
function generateHooksConfig(projectRoot) {
|
|
19
|
+
const dzDir = join(projectRoot, '.dz');
|
|
20
|
+
return JSON.stringify({
|
|
21
|
+
hooks: {
|
|
22
|
+
SessionStart: [{
|
|
23
|
+
type: 'command',
|
|
24
|
+
command: `node -e "const fs=require('fs');const p='${dzDir}/memory.db';const d=new Date().toISOString();fs.appendFileSync('${dzDir}/sessions.jsonl',JSON.stringify({event:'start',ts:d})+'\\n')"`,
|
|
25
|
+
}],
|
|
26
|
+
SessionEnd: [{
|
|
27
|
+
type: 'command',
|
|
28
|
+
command: `node -e "const fs=require('fs');const d=new Date().toISOString();fs.appendFileSync('${dzDir}/sessions.jsonl',JSON.stringify({event:'end',ts:d})+'\\n')"`,
|
|
29
|
+
}],
|
|
30
|
+
},
|
|
31
|
+
}, null, 2);
|
|
32
|
+
}
|
|
33
|
+
/** Generate .dz/config.json with learning settings. */
|
|
34
|
+
function generateDzConfig(target, preset) {
|
|
35
|
+
return JSON.stringify({
|
|
36
|
+
version: '1.0.0',
|
|
37
|
+
target,
|
|
38
|
+
preset: preset ?? null,
|
|
39
|
+
learning: {
|
|
40
|
+
enabled: true,
|
|
41
|
+
sessionTracking: true,
|
|
42
|
+
patternConsolidation: true,
|
|
43
|
+
retentionDays: 90,
|
|
44
|
+
},
|
|
45
|
+
memory: {
|
|
46
|
+
backend: 'jsonl',
|
|
47
|
+
path: '.dz/sessions.jsonl',
|
|
48
|
+
maxSizeMb: 10,
|
|
49
|
+
},
|
|
50
|
+
hooks: {
|
|
51
|
+
sessionStart: true,
|
|
52
|
+
sessionEnd: true,
|
|
53
|
+
},
|
|
54
|
+
}, null, 2);
|
|
55
|
+
}
|
|
56
|
+
/** Run full environment setup. */
|
|
57
|
+
export function runSetup(opts) {
|
|
58
|
+
const steps = [];
|
|
59
|
+
const dzDir = join(opts.projectRoot, '.dz');
|
|
60
|
+
// Step 1: Create .dz directory
|
|
61
|
+
if (!existsSync(dzDir)) {
|
|
62
|
+
mkdirSync(dzDir, { recursive: true });
|
|
63
|
+
steps.push({ name: 'Create .dz directory', status: 'done', detail: dzDir });
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
steps.push({ name: 'Create .dz directory', status: 'skipped', detail: 'already exists' });
|
|
67
|
+
}
|
|
68
|
+
// Step 2: Write .dz/config.json
|
|
69
|
+
const configPath = join(dzDir, 'config.json');
|
|
70
|
+
if (!existsSync(configPath) || opts.force) {
|
|
71
|
+
writeFileSync(configPath, generateDzConfig(opts.target, opts.preset));
|
|
72
|
+
steps.push({ name: 'Write .dz/config.json', status: 'done', detail: 'learning + memory config' });
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
steps.push({ name: 'Write .dz/config.json', status: 'skipped', detail: 'already exists (use --force)' });
|
|
76
|
+
}
|
|
77
|
+
// Step 3: Initialize session log
|
|
78
|
+
const sessionsPath = join(dzDir, 'sessions.jsonl');
|
|
79
|
+
if (!existsSync(sessionsPath)) {
|
|
80
|
+
writeFileSync(sessionsPath, '');
|
|
81
|
+
steps.push({ name: 'Initialize sessions.jsonl', status: 'done', detail: 'session tracking ready' });
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
steps.push({ name: 'Initialize sessions.jsonl', status: 'skipped', detail: 'already exists' });
|
|
85
|
+
}
|
|
86
|
+
// Step 4: Initialize patterns store
|
|
87
|
+
const patternsPath = join(dzDir, 'patterns.jsonl');
|
|
88
|
+
if (!existsSync(patternsPath)) {
|
|
89
|
+
writeFileSync(patternsPath, '');
|
|
90
|
+
steps.push({ name: 'Initialize patterns.jsonl', status: 'done', detail: 'pattern learning ready' });
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
steps.push({ name: 'Initialize patterns.jsonl', status: 'skipped', detail: 'already exists' });
|
|
94
|
+
}
|
|
95
|
+
// Step 5: Configure hooks (write to .claude/settings.json)
|
|
96
|
+
if (!opts.noHooks) {
|
|
97
|
+
const settingsDir = join(opts.projectRoot, '.claude');
|
|
98
|
+
const settingsPath = join(settingsDir, 'settings.json');
|
|
99
|
+
if (!existsSync(settingsPath) || opts.force) {
|
|
100
|
+
mkdirSync(settingsDir, { recursive: true });
|
|
101
|
+
writeFileSync(settingsPath, generateHooksConfig(opts.projectRoot));
|
|
102
|
+
steps.push({ name: 'Configure hooks', status: 'done', detail: 'session-start + session-end hooks' });
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// Merge hooks into existing settings
|
|
106
|
+
try {
|
|
107
|
+
const existing = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
|
108
|
+
if (!existing['hooks']) {
|
|
109
|
+
const hooks = JSON.parse(generateHooksConfig(opts.projectRoot));
|
|
110
|
+
existing['hooks'] = hooks.hooks;
|
|
111
|
+
writeFileSync(settingsPath, JSON.stringify(existing, null, 2));
|
|
112
|
+
steps.push({ name: 'Configure hooks', status: 'done', detail: 'merged into existing settings' });
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
steps.push({ name: 'Configure hooks', status: 'skipped', detail: 'hooks already configured' });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
steps.push({ name: 'Configure hooks', status: 'skipped', detail: 'could not parse existing settings' });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
steps.push({ name: 'Configure hooks', status: 'skipped', detail: '--no-hooks' });
|
|
125
|
+
}
|
|
126
|
+
// Step 6: Update .gitignore
|
|
127
|
+
const gitignorePath = join(opts.projectRoot, '.gitignore');
|
|
128
|
+
const dzIgnoreEntry = '\n# DZ Harness learning data\n.dz/sessions.jsonl\n.dz/patterns.jsonl\n';
|
|
129
|
+
if (existsSync(gitignorePath)) {
|
|
130
|
+
const content = readFileSync(gitignorePath, 'utf-8');
|
|
131
|
+
if (!content.includes('.dz/sessions.jsonl')) {
|
|
132
|
+
writeFileSync(gitignorePath, content + dzIgnoreEntry);
|
|
133
|
+
steps.push({ name: 'Update .gitignore', status: 'done', detail: 'added .dz/sessions.jsonl + patterns.jsonl' });
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
steps.push({ name: 'Update .gitignore', status: 'skipped', detail: 'already ignoring .dz data' });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
writeFileSync(gitignorePath, dzIgnoreEntry);
|
|
141
|
+
steps.push({ name: 'Create .gitignore', status: 'done', detail: 'with .dz entries' });
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
steps,
|
|
145
|
+
totalSteps: steps.length,
|
|
146
|
+
completed: steps.filter((s) => s.status === 'done').length,
|
|
147
|
+
skipped: steps.filter((s) => s.status === 'skipped').length,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dzhechkov/harness-core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.11",
|
|
4
4
|
"description": "Shared harness logic - skill loading, additive apply, and the init/sync/verify/doctor operations.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"yaml": "^2.0.0",
|
|
28
|
+
"@dzhechkov/adapter-claude": "0.2.0",
|
|
29
|
+
"@dzhechkov/adapter-opencode": "0.2.0",
|
|
28
30
|
"@dzhechkov/adapter-codex": "0.2.0",
|
|
29
31
|
"@dzhechkov/adapter-hermes": "0.2.0",
|
|
30
|
-
"@dzhechkov/adapter-claude": "0.2.0",
|
|
31
32
|
"@dzhechkov/adapter-openclaude": "0.1.0",
|
|
32
|
-
"@dzhechkov/adapter-opencode": "0.2.0",
|
|
33
33
|
"@dzhechkov/core": "0.2.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
package/src/index.ts
CHANGED
|
@@ -19,6 +19,10 @@ export type { SyncUpstreamReport, UpstreamCheckResult, SourcesManifest, SourcePa
|
|
|
19
19
|
export { benchmarkSkill, benchmarkSkills, compareSkills } from './benchmark.js';
|
|
20
20
|
export { buildRegistry, searchRegistry, filterByCategory } from './registry.js';
|
|
21
21
|
export { recommend } from './recommend.js';
|
|
22
|
+
export { pretrain } from './pretrain.js';
|
|
23
|
+
export { runSetup } from './setup.js';
|
|
24
|
+
export type { SetupOptions, SetupResult, SetupStep } from './setup.js';
|
|
25
|
+
export type { PretrainResult, DetectedTech } from './pretrain.js';
|
|
22
26
|
export type { RecommendationReport, SkillRecommendation } from './recommend.js';
|
|
23
27
|
export { discoverPackages, publishPackages } from './publish.js';
|
|
24
28
|
export { fetchAllDownloads } from './downloads.js';
|
package/src/pretrain.ts
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pretrain — bootstrap intelligence by analyzing the target project.
|
|
3
|
+
*
|
|
4
|
+
* Scans the project's file structure, package.json, and tech stack to
|
|
5
|
+
* automatically recommend the right skills and presets. Runs during
|
|
6
|
+
* `dz init --pretrain` to eliminate manual preset selection.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
|
|
14
|
+
/** Detected technology in the project. */
|
|
15
|
+
export interface DetectedTech {
|
|
16
|
+
readonly name: string;
|
|
17
|
+
readonly category: string;
|
|
18
|
+
readonly confidence: number;
|
|
19
|
+
readonly source: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Pretrain analysis result. */
|
|
23
|
+
export interface PretrainResult {
|
|
24
|
+
readonly projectName: string;
|
|
25
|
+
readonly techs: readonly DetectedTech[];
|
|
26
|
+
readonly recommendedPresets: readonly string[];
|
|
27
|
+
readonly recommendedSkills: readonly string[];
|
|
28
|
+
readonly projectType: string;
|
|
29
|
+
readonly hasTests: boolean;
|
|
30
|
+
readonly hasDocker: boolean;
|
|
31
|
+
readonly hasCI: boolean;
|
|
32
|
+
readonly hasTerraform: boolean;
|
|
33
|
+
readonly hasKubernetes: boolean;
|
|
34
|
+
readonly packageCount: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Tech detection rules: file/pattern → tech. */
|
|
38
|
+
const DETECTORS: { glob: string; tech: string; category: string }[] = [
|
|
39
|
+
// Languages/Frameworks
|
|
40
|
+
{ glob: 'package.json', tech: 'node.js', category: 'runtime' },
|
|
41
|
+
{ glob: 'tsconfig.json', tech: 'typescript', category: 'language' },
|
|
42
|
+
{ glob: 'requirements.txt', tech: 'python', category: 'runtime' },
|
|
43
|
+
{ glob: 'pyproject.toml', tech: 'python', category: 'runtime' },
|
|
44
|
+
{ glob: 'go.mod', tech: 'go', category: 'runtime' },
|
|
45
|
+
{ glob: 'Cargo.toml', tech: 'rust', category: 'runtime' },
|
|
46
|
+
{ glob: 'Gemfile', tech: 'ruby', category: 'runtime' },
|
|
47
|
+
|
|
48
|
+
// Frontend
|
|
49
|
+
{ glob: 'next.config', tech: 'next.js', category: 'frontend' },
|
|
50
|
+
{ glob: 'vite.config', tech: 'vite', category: 'frontend' },
|
|
51
|
+
{ glob: 'tailwind.config', tech: 'tailwind', category: 'frontend' },
|
|
52
|
+
|
|
53
|
+
// Databases
|
|
54
|
+
{ glob: 'prisma', tech: 'prisma', category: 'database' },
|
|
55
|
+
{ glob: 'drizzle.config', tech: 'drizzle', category: 'database' },
|
|
56
|
+
{ glob: 'knexfile', tech: 'knex', category: 'database' },
|
|
57
|
+
|
|
58
|
+
// Infrastructure
|
|
59
|
+
{ glob: 'Dockerfile', tech: 'docker', category: 'infra' },
|
|
60
|
+
{ glob: 'docker-compose', tech: 'docker-compose', category: 'infra' },
|
|
61
|
+
{ glob: '.github/workflows', tech: 'github-actions', category: 'ci' },
|
|
62
|
+
{ glob: '.gitlab-ci.yml', tech: 'gitlab-ci', category: 'ci' },
|
|
63
|
+
{ glob: 'terraform', tech: 'terraform', category: 'iac' },
|
|
64
|
+
{ glob: '.tf', tech: 'terraform', category: 'iac' },
|
|
65
|
+
{ glob: 'k8s', tech: 'kubernetes', category: 'infra' },
|
|
66
|
+
{ glob: 'helm', tech: 'helm', category: 'infra' },
|
|
67
|
+
{ glob: 'nginx.conf', tech: 'nginx', category: 'infra' },
|
|
68
|
+
|
|
69
|
+
// Testing
|
|
70
|
+
{ glob: 'vitest.config', tech: 'vitest', category: 'testing' },
|
|
71
|
+
{ glob: 'jest.config', tech: 'jest', category: 'testing' },
|
|
72
|
+
{ glob: 'playwright.config', tech: 'playwright', category: 'testing' },
|
|
73
|
+
{ glob: 'cypress.config', tech: 'cypress', category: 'testing' },
|
|
74
|
+
{ glob: '.stryker', tech: 'stryker', category: 'testing' },
|
|
75
|
+
|
|
76
|
+
// Data
|
|
77
|
+
{ glob: 'dbt_project.yml', tech: 'dbt', category: 'data' },
|
|
78
|
+
{ glob: 'airflow', tech: 'airflow', category: 'data' },
|
|
79
|
+
|
|
80
|
+
// API
|
|
81
|
+
{ glob: 'openapi', tech: 'openapi', category: 'api' },
|
|
82
|
+
{ glob: 'swagger', tech: 'swagger', category: 'api' },
|
|
83
|
+
{ glob: '.graphql', tech: 'graphql', category: 'api' },
|
|
84
|
+
{ glob: 'schema.graphql', tech: 'graphql', category: 'api' },
|
|
85
|
+
|
|
86
|
+
// Cache/Queue
|
|
87
|
+
{ glob: 'redis', tech: 'redis', category: 'cache' },
|
|
88
|
+
|
|
89
|
+
// Knowledge
|
|
90
|
+
{ glob: '.obsidian', tech: 'obsidian', category: 'knowledge' },
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
/** Map tech categories to recommended skills. */
|
|
94
|
+
const CATEGORY_TO_SKILLS: Record<string, string[]> = {
|
|
95
|
+
'runtime': ['debugging', 'test-writer', 'pr-review'],
|
|
96
|
+
'language': ['test-writer', 'pr-review'],
|
|
97
|
+
'frontend': ['frontend-implementation', 'playwright-testing'],
|
|
98
|
+
'database': ['database-review', 'database-migration'],
|
|
99
|
+
'infra': ['docker-compose', 'kubernetes', 'nginx-config'],
|
|
100
|
+
'ci': ['ci-fix', 'github-actions'],
|
|
101
|
+
'iac': ['terraform'],
|
|
102
|
+
'testing': ['test-writer', 'playwright-testing'],
|
|
103
|
+
'data': ['data-pipeline'],
|
|
104
|
+
'api': ['api-design', 'graphql-schema'],
|
|
105
|
+
'cache': ['redis-patterns'],
|
|
106
|
+
'knowledge': ['obsidian'],
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/** Map detected skills to presets. */
|
|
110
|
+
const SKILL_TO_PRESET: Record<string, string> = {
|
|
111
|
+
'pr-review': 'devops', 'security-audit': 'devops', 'test-writer': 'devops',
|
|
112
|
+
'ci-fix': 'devops', 'terraform': 'devops', 'kubernetes': 'devops',
|
|
113
|
+
'docker-compose': 'devops', 'api-design': 'devops', 'debugging': 'devops',
|
|
114
|
+
'database-review': 'devops', 'database-migration': 'devops',
|
|
115
|
+
'github-actions': 'devops', 'nginx-config': 'devops', 'redis-patterns': 'devops',
|
|
116
|
+
'graphql-schema': 'devops', 'playwright-testing': 'devops',
|
|
117
|
+
'data-pipeline': 'devops', 'incident-response': 'devops',
|
|
118
|
+
'frontend-implementation': 'devops', 'monorepo-management': 'devops',
|
|
119
|
+
'brave-search': 'mcp', 'gmail': 'mcp', 'notion': 'mcp', 'obsidian': 'mcp',
|
|
120
|
+
'git-mcp': 'mcp', 'context7': 'mcp',
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/** Scan project directory for files matching detectors. */
|
|
124
|
+
function scanProject(projectRoot: string): DetectedTech[] {
|
|
125
|
+
const techs: DetectedTech[] = [];
|
|
126
|
+
const seen = new Set<string>();
|
|
127
|
+
|
|
128
|
+
// Check top-level files
|
|
129
|
+
let entries: string[] = [];
|
|
130
|
+
try {
|
|
131
|
+
entries = readdirSync(projectRoot).map((e) => e.toLowerCase());
|
|
132
|
+
} catch { return []; }
|
|
133
|
+
|
|
134
|
+
for (const detector of DETECTORS) {
|
|
135
|
+
const globLower = detector.glob.toLowerCase();
|
|
136
|
+
const match = entries.some((e) => e.includes(globLower));
|
|
137
|
+
if (match && !seen.has(detector.tech)) {
|
|
138
|
+
seen.add(detector.tech);
|
|
139
|
+
techs.push({
|
|
140
|
+
name: detector.tech,
|
|
141
|
+
category: detector.category,
|
|
142
|
+
confidence: 0.9,
|
|
143
|
+
source: detector.glob,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Check subdirectories (1 level deep)
|
|
149
|
+
for (const entry of entries) {
|
|
150
|
+
const subPath = join(projectRoot, entry);
|
|
151
|
+
try {
|
|
152
|
+
const subEntries = readdirSync(subPath).map((e) => e.toLowerCase());
|
|
153
|
+
for (const detector of DETECTORS) {
|
|
154
|
+
const globLower = detector.glob.toLowerCase();
|
|
155
|
+
if (subEntries.some((e) => e.includes(globLower)) && !seen.has(detector.tech)) {
|
|
156
|
+
seen.add(detector.tech);
|
|
157
|
+
techs.push({
|
|
158
|
+
name: detector.tech,
|
|
159
|
+
category: detector.category,
|
|
160
|
+
confidence: 0.7,
|
|
161
|
+
source: `${entry}/${detector.glob}`,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
} catch { /* not a directory or no access */ }
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Parse package.json for deps
|
|
169
|
+
const pkgPath = join(projectRoot, 'package.json');
|
|
170
|
+
if (existsSync(pkgPath)) {
|
|
171
|
+
try {
|
|
172
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as {
|
|
173
|
+
name?: string;
|
|
174
|
+
dependencies?: Record<string, string>;
|
|
175
|
+
devDependencies?: Record<string, string>;
|
|
176
|
+
};
|
|
177
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
178
|
+
const depNames = Object.keys(allDeps).map((d) => d.toLowerCase());
|
|
179
|
+
|
|
180
|
+
const depDetectors: [string, string, string][] = [
|
|
181
|
+
['next', 'next.js', 'frontend'],
|
|
182
|
+
['react', 'react', 'frontend'],
|
|
183
|
+
['vue', 'vue', 'frontend'],
|
|
184
|
+
['express', 'express', 'api'],
|
|
185
|
+
['fastify', 'fastify', 'api'],
|
|
186
|
+
['prisma', 'prisma', 'database'],
|
|
187
|
+
['drizzle-orm', 'drizzle', 'database'],
|
|
188
|
+
['redis', 'redis', 'cache'],
|
|
189
|
+
['ioredis', 'redis', 'cache'],
|
|
190
|
+
['bullmq', 'bullmq', 'queue'],
|
|
191
|
+
['graphql', 'graphql', 'api'],
|
|
192
|
+
['playwright', 'playwright', 'testing'],
|
|
193
|
+
['vitest', 'vitest', 'testing'],
|
|
194
|
+
['jest', 'jest', 'testing'],
|
|
195
|
+
];
|
|
196
|
+
|
|
197
|
+
for (const [dep, tech, category] of depDetectors) {
|
|
198
|
+
if (depNames.some((d) => d.includes(dep)) && !seen.has(tech)) {
|
|
199
|
+
seen.add(tech);
|
|
200
|
+
techs.push({ name: tech, category, confidence: 0.8, source: `package.json dep: ${dep}` });
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
} catch { /* invalid JSON */ }
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return techs.sort((a, b) => b.confidence - a.confidence);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** Run pretrain analysis on a project. */
|
|
210
|
+
export function pretrain(projectRoot: string): PretrainResult {
|
|
211
|
+
const techs = scanProject(projectRoot);
|
|
212
|
+
|
|
213
|
+
// Determine recommended skills from detected techs
|
|
214
|
+
const skillSet = new Set<string>();
|
|
215
|
+
// Always recommend core skills
|
|
216
|
+
skillSet.add('pr-review');
|
|
217
|
+
skillSet.add('security-audit');
|
|
218
|
+
skillSet.add('debugging');
|
|
219
|
+
|
|
220
|
+
for (const tech of techs) {
|
|
221
|
+
const skills = CATEGORY_TO_SKILLS[tech.category] ?? [];
|
|
222
|
+
for (const s of skills) skillSet.add(s);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const recommendedSkills = [...skillSet].sort();
|
|
226
|
+
|
|
227
|
+
// Determine recommended presets
|
|
228
|
+
const presetCounts = new Map<string, number>();
|
|
229
|
+
for (const skill of recommendedSkills) {
|
|
230
|
+
const preset = SKILL_TO_PRESET[skill];
|
|
231
|
+
if (preset) presetCounts.set(preset, (presetCounts.get(preset) ?? 0) + 1);
|
|
232
|
+
}
|
|
233
|
+
const recommendedPresets = [...presetCounts.entries()]
|
|
234
|
+
.sort((a, b) => b[1] - a[1])
|
|
235
|
+
.map(([name]) => name);
|
|
236
|
+
|
|
237
|
+
// Detect project type
|
|
238
|
+
const categories = new Set(techs.map((t) => t.category));
|
|
239
|
+
let projectType = 'generic';
|
|
240
|
+
if (categories.has('frontend') && categories.has('api')) projectType = 'fullstack';
|
|
241
|
+
else if (categories.has('frontend')) projectType = 'frontend';
|
|
242
|
+
else if (categories.has('api')) projectType = 'backend';
|
|
243
|
+
else if (categories.has('data')) projectType = 'data-engineering';
|
|
244
|
+
else if (categories.has('iac')) projectType = 'infrastructure';
|
|
245
|
+
|
|
246
|
+
// Detect package count (monorepo check)
|
|
247
|
+
let packageCount = 1;
|
|
248
|
+
const pkgPath = join(projectRoot, 'pnpm-workspace.yaml');
|
|
249
|
+
if (existsSync(pkgPath)) {
|
|
250
|
+
try {
|
|
251
|
+
const dirs = readdirSync(join(projectRoot, 'packages'), { withFileTypes: true })
|
|
252
|
+
.filter((e) => e.isDirectory());
|
|
253
|
+
packageCount = dirs.length;
|
|
254
|
+
if (packageCount > 3) skillSet.add('monorepo-management');
|
|
255
|
+
} catch { /* no packages dir */ }
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Get project name
|
|
259
|
+
let projectName = 'unknown';
|
|
260
|
+
const rootPkg = join(projectRoot, 'package.json');
|
|
261
|
+
if (existsSync(rootPkg)) {
|
|
262
|
+
try {
|
|
263
|
+
const pkg = JSON.parse(readFileSync(rootPkg, 'utf-8')) as { name?: string };
|
|
264
|
+
projectName = pkg.name ?? 'unknown';
|
|
265
|
+
} catch { /* */ }
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
projectName,
|
|
270
|
+
techs,
|
|
271
|
+
recommendedPresets,
|
|
272
|
+
recommendedSkills: [...skillSet].sort(),
|
|
273
|
+
projectType,
|
|
274
|
+
hasTests: techs.some((t) => t.category === 'testing'),
|
|
275
|
+
hasDocker: techs.some((t) => t.name === 'docker' || t.name === 'docker-compose'),
|
|
276
|
+
hasCI: techs.some((t) => t.category === 'ci'),
|
|
277
|
+
hasTerraform: techs.some((t) => t.name === 'terraform'),
|
|
278
|
+
hasKubernetes: techs.some((t) => t.name === 'kubernetes' || t.name === 'helm'),
|
|
279
|
+
packageCount,
|
|
280
|
+
};
|
|
281
|
+
}
|
package/src/setup.ts
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Full environment setup — skills + hooks + memory + pretrain.
|
|
3
|
+
*
|
|
4
|
+
* Unlike `dz init` (skills only), `dz setup` configures the complete
|
|
5
|
+
* self-learning environment:
|
|
6
|
+
* 1. Skills installation (via init)
|
|
7
|
+
* 2. Claude Code hooks (session-start/end for memory)
|
|
8
|
+
* 3. Memory database initialization (.dz/memory.db)
|
|
9
|
+
* 4. Pretrain (project analysis → auto-recommend)
|
|
10
|
+
*
|
|
11
|
+
* All operations are additive — never overwrites existing files.
|
|
12
|
+
*
|
|
13
|
+
* @packageDocumentation
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs';
|
|
17
|
+
import { join } from 'node:path';
|
|
18
|
+
|
|
19
|
+
/** Setup options. */
|
|
20
|
+
export interface SetupOptions {
|
|
21
|
+
readonly projectRoot: string;
|
|
22
|
+
readonly target: string;
|
|
23
|
+
readonly preset?: string | undefined;
|
|
24
|
+
readonly noHooks?: boolean | undefined;
|
|
25
|
+
readonly noMemory?: boolean | undefined;
|
|
26
|
+
readonly noPretrain?: boolean | undefined;
|
|
27
|
+
readonly force?: boolean | undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Setup result. */
|
|
31
|
+
export interface SetupResult {
|
|
32
|
+
readonly steps: readonly SetupStep[];
|
|
33
|
+
readonly totalSteps: number;
|
|
34
|
+
readonly completed: number;
|
|
35
|
+
readonly skipped: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** A single setup step. */
|
|
39
|
+
export interface SetupStep {
|
|
40
|
+
readonly name: string;
|
|
41
|
+
readonly status: 'done' | 'skipped' | 'error';
|
|
42
|
+
readonly detail: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Generate Claude Code hooks configuration for self-learning. */
|
|
46
|
+
function generateHooksConfig(projectRoot: string): string {
|
|
47
|
+
const dzDir = join(projectRoot, '.dz');
|
|
48
|
+
return JSON.stringify({
|
|
49
|
+
hooks: {
|
|
50
|
+
SessionStart: [{
|
|
51
|
+
type: 'command',
|
|
52
|
+
command: `node -e "const fs=require('fs');const p='${dzDir}/memory.db';const d=new Date().toISOString();fs.appendFileSync('${dzDir}/sessions.jsonl',JSON.stringify({event:'start',ts:d})+'\\n')"`,
|
|
53
|
+
}],
|
|
54
|
+
SessionEnd: [{
|
|
55
|
+
type: 'command',
|
|
56
|
+
command: `node -e "const fs=require('fs');const d=new Date().toISOString();fs.appendFileSync('${dzDir}/sessions.jsonl',JSON.stringify({event:'end',ts:d})+'\\n')"`,
|
|
57
|
+
}],
|
|
58
|
+
},
|
|
59
|
+
}, null, 2);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Generate .dz/config.json with learning settings. */
|
|
63
|
+
function generateDzConfig(target: string, preset: string | undefined): string {
|
|
64
|
+
return JSON.stringify({
|
|
65
|
+
version: '1.0.0',
|
|
66
|
+
target,
|
|
67
|
+
preset: preset ?? null,
|
|
68
|
+
learning: {
|
|
69
|
+
enabled: true,
|
|
70
|
+
sessionTracking: true,
|
|
71
|
+
patternConsolidation: true,
|
|
72
|
+
retentionDays: 90,
|
|
73
|
+
},
|
|
74
|
+
memory: {
|
|
75
|
+
backend: 'jsonl',
|
|
76
|
+
path: '.dz/sessions.jsonl',
|
|
77
|
+
maxSizeMb: 10,
|
|
78
|
+
},
|
|
79
|
+
hooks: {
|
|
80
|
+
sessionStart: true,
|
|
81
|
+
sessionEnd: true,
|
|
82
|
+
},
|
|
83
|
+
}, null, 2);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Run full environment setup. */
|
|
87
|
+
export function runSetup(opts: SetupOptions): SetupResult {
|
|
88
|
+
const steps: SetupStep[] = [];
|
|
89
|
+
const dzDir = join(opts.projectRoot, '.dz');
|
|
90
|
+
|
|
91
|
+
// Step 1: Create .dz directory
|
|
92
|
+
if (!existsSync(dzDir)) {
|
|
93
|
+
mkdirSync(dzDir, { recursive: true });
|
|
94
|
+
steps.push({ name: 'Create .dz directory', status: 'done', detail: dzDir });
|
|
95
|
+
} else {
|
|
96
|
+
steps.push({ name: 'Create .dz directory', status: 'skipped', detail: 'already exists' });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Step 2: Write .dz/config.json
|
|
100
|
+
const configPath = join(dzDir, 'config.json');
|
|
101
|
+
if (!existsSync(configPath) || opts.force) {
|
|
102
|
+
writeFileSync(configPath, generateDzConfig(opts.target, opts.preset));
|
|
103
|
+
steps.push({ name: 'Write .dz/config.json', status: 'done', detail: 'learning + memory config' });
|
|
104
|
+
} else {
|
|
105
|
+
steps.push({ name: 'Write .dz/config.json', status: 'skipped', detail: 'already exists (use --force)' });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Step 3: Initialize session log
|
|
109
|
+
const sessionsPath = join(dzDir, 'sessions.jsonl');
|
|
110
|
+
if (!existsSync(sessionsPath)) {
|
|
111
|
+
writeFileSync(sessionsPath, '');
|
|
112
|
+
steps.push({ name: 'Initialize sessions.jsonl', status: 'done', detail: 'session tracking ready' });
|
|
113
|
+
} else {
|
|
114
|
+
steps.push({ name: 'Initialize sessions.jsonl', status: 'skipped', detail: 'already exists' });
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Step 4: Initialize patterns store
|
|
118
|
+
const patternsPath = join(dzDir, 'patterns.jsonl');
|
|
119
|
+
if (!existsSync(patternsPath)) {
|
|
120
|
+
writeFileSync(patternsPath, '');
|
|
121
|
+
steps.push({ name: 'Initialize patterns.jsonl', status: 'done', detail: 'pattern learning ready' });
|
|
122
|
+
} else {
|
|
123
|
+
steps.push({ name: 'Initialize patterns.jsonl', status: 'skipped', detail: 'already exists' });
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Step 5: Configure hooks (write to .claude/settings.json)
|
|
127
|
+
if (!opts.noHooks) {
|
|
128
|
+
const settingsDir = join(opts.projectRoot, '.claude');
|
|
129
|
+
const settingsPath = join(settingsDir, 'settings.json');
|
|
130
|
+
|
|
131
|
+
if (!existsSync(settingsPath) || opts.force) {
|
|
132
|
+
mkdirSync(settingsDir, { recursive: true });
|
|
133
|
+
writeFileSync(settingsPath, generateHooksConfig(opts.projectRoot));
|
|
134
|
+
steps.push({ name: 'Configure hooks', status: 'done', detail: 'session-start + session-end hooks' });
|
|
135
|
+
} else {
|
|
136
|
+
// Merge hooks into existing settings
|
|
137
|
+
try {
|
|
138
|
+
const existing = JSON.parse(readFileSync(settingsPath, 'utf-8')) as Record<string, unknown>;
|
|
139
|
+
if (!existing['hooks']) {
|
|
140
|
+
const hooks = JSON.parse(generateHooksConfig(opts.projectRoot));
|
|
141
|
+
existing['hooks'] = hooks.hooks;
|
|
142
|
+
writeFileSync(settingsPath, JSON.stringify(existing, null, 2));
|
|
143
|
+
steps.push({ name: 'Configure hooks', status: 'done', detail: 'merged into existing settings' });
|
|
144
|
+
} else {
|
|
145
|
+
steps.push({ name: 'Configure hooks', status: 'skipped', detail: 'hooks already configured' });
|
|
146
|
+
}
|
|
147
|
+
} catch {
|
|
148
|
+
steps.push({ name: 'Configure hooks', status: 'skipped', detail: 'could not parse existing settings' });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
steps.push({ name: 'Configure hooks', status: 'skipped', detail: '--no-hooks' });
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Step 6: Update .gitignore
|
|
156
|
+
const gitignorePath = join(opts.projectRoot, '.gitignore');
|
|
157
|
+
const dzIgnoreEntry = '\n# DZ Harness learning data\n.dz/sessions.jsonl\n.dz/patterns.jsonl\n';
|
|
158
|
+
if (existsSync(gitignorePath)) {
|
|
159
|
+
const content = readFileSync(gitignorePath, 'utf-8');
|
|
160
|
+
if (!content.includes('.dz/sessions.jsonl')) {
|
|
161
|
+
writeFileSync(gitignorePath, content + dzIgnoreEntry);
|
|
162
|
+
steps.push({ name: 'Update .gitignore', status: 'done', detail: 'added .dz/sessions.jsonl + patterns.jsonl' });
|
|
163
|
+
} else {
|
|
164
|
+
steps.push({ name: 'Update .gitignore', status: 'skipped', detail: 'already ignoring .dz data' });
|
|
165
|
+
}
|
|
166
|
+
} else {
|
|
167
|
+
writeFileSync(gitignorePath, dzIgnoreEntry);
|
|
168
|
+
steps.push({ name: 'Create .gitignore', status: 'done', detail: 'with .dz entries' });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
steps,
|
|
173
|
+
totalSteps: steps.length,
|
|
174
|
+
completed: steps.filter((s) => s.status === 'done').length,
|
|
175
|
+
skipped: steps.filter((s) => s.status === 'skipped').length,
|
|
176
|
+
};
|
|
177
|
+
}
|