@magic-ingredients/tiny-brain-local 0.18.0 → 0.18.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"analyse-service.d.ts","sourceRoot":"","sources":["../../src/services/analyse-service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,aAAa,EAInB,MAAM,oCAAoC,CAAC;AAW5C,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAGD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,YAAY,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,OAAO,CAAC,EAAE;QACR,cAAc,EAAE,MAAM,EAAE,CAAC;QACzB,gBAAgB,EAAE,MAAM,EAAE,CAAC;KAC5B,CAAC;IACF,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC;AAGD;;;GAGG;AACH,qBAAa,cAAc;IAMb,OAAO,CAAC,OAAO;IAL3B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,kBAAkB,CAAqB;gBAE3B,OAAO,EAAE,cAAc;IAO3C;;OAEG;IACG,eAAe,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,aAAa,CAAC;IAwJ3E;;;OAGG;YACW,kBAAkB;IAoBhC;;OAEG;YACW,eAAe;IAc7B;;;OAGG;YACW,sBAAsB;IAwBpC;;;OAGG;YACW,sBAAsB;IAwBpC;;;OAGG;YACW,0BAA0B;IAwBxC;;;OAGG;YACW,wBAAwB;IAwBtC;;;;OAIG;YACW,kBAAkB;IA+EhC;;;;OAIG;YACW,sBAAsB;IAiEpC;;;OAGG;YACW,yBAAyB;IAkCvC;;OAEG;IACH,oBAAoB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IAiHnD;;;OAGG;IACH,iBAAiB,CAAC,gBAAgB,EAAE,YAAY,GAAG,IAAI,EAAE,eAAe,EAAE,YAAY,GAAG,aAAa;IA8BtG;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAY5B;;;;;OAKG;IACH,OAAO,CAAC,eAAe;CAWxB"}
1
+ {"version":3,"file":"analyse-service.d.ts","sourceRoot":"","sources":["../../src/services/analyse-service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,aAAa,EAMnB,MAAM,oCAAoC,CAAC;AAS5C,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAGD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,YAAY,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,OAAO,CAAC,EAAE;QACR,cAAc,EAAE,MAAM,EAAE,CAAC;QACzB,gBAAgB,EAAE,MAAM,EAAE,CAAC;KAC5B,CAAC;IACF,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC;AAGD;;;GAGG;AACH,qBAAa,cAAc;IAMb,OAAO,CAAC,OAAO;IAL3B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,kBAAkB,CAAqB;gBAE3B,OAAO,EAAE,cAAc;IAO3C;;OAEG;IACG,eAAe,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,aAAa,CAAC;IAwJ3E;;;OAGG;YACW,kBAAkB;IAoBhC;;OAEG;YACW,eAAe;IAc7B;;;OAGG;YACW,sBAAsB;IAwBpC;;;OAGG;YACW,sBAAsB;IAwBpC;;;OAGG;YACW,0BAA0B;IAwBxC;;;OAGG;YACW,wBAAwB;IAwBtC;;;;OAIG;YACW,kBAAkB;IA+EhC;;;;OAIG;YACW,sBAAsB;IAiEpC;;;OAGG;YACW,yBAAyB;IAkCvC;;OAEG;IACH,oBAAoB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IAiHnD;;;OAGG;IACH,iBAAiB,CAAC,gBAAgB,EAAE,YAAY,GAAG,IAAI,EAAE,eAAe,EAAE,YAAY,GAAG,aAAa;IA8BtG;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAY5B;;;;;OAKG;IACH,OAAO,CAAC,eAAe;CAWxB"}
@@ -4,10 +4,8 @@
4
4
  * Handles repository tech stack analysis.
5
5
  * Focused solely on analysis - no context file management.
6
6
  */
7
- import { analyseRepository, formatTechStackChanges, detectTechStackChanges, ConfigService, RepoConfigService } from '@magic-ingredients/tiny-brain-core';
7
+ import { analyseRepository, formatTechStackChanges, detectTechStackChanges, ConfigService, RepoConfigService, LibraryClient, TechContextService, } from '@magic-ingredients/tiny-brain-core';
8
8
  import { RepoService } from './repo-service.js';
9
- import { LibraryClient } from '@magic-ingredients/tiny-brain-core';
10
- import { TechContextService } from './tech-context-service.js';
11
9
  import { fileURLToPath } from 'url';
12
10
  import { dirname, join } from 'path';
13
11
  import { existsSync } from 'fs';
@@ -1 +1 @@
1
- {"version":3,"file":"repo-service.d.ts","sourceRoot":"","sources":["../../src/services/repo-service.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAIlE,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,qBAAa,WAAW;IAMV,OAAO,CAAC,OAAO;IAL3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAA2B;IACnE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAyB;IAE/D,OAAO,CAAC,aAAa,CAAgB;gBAEjB,OAAO,EAAE,cAAc;IAS3C;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAQzB;;OAEG;IACG,4BAA4B,CAChC,eAAe,GAAE,MAAoB,GACpC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAmCzB;;;;OAIG;IACH,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAOvD;;OAEG;IACH,cAAc,IAAI,OAAO;IAUzB;;;OAGG;IACG,uBAAuB,IAAI,OAAO,CAAC,OAAO,CAAC;IAcjD;;OAEG;IACH,kBAAkB,IAAI,MAAM;IAa5B;;;;;;;;OAQG;IACG,qBAAqB,CAAC,OAAO,GAAE,4BAAiC,GAAG,OAAO,CAAC,IAAI,CAAC;IAwFtF;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAkGlC;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAoChC;;OAEG;IACH,OAAO,CAAC,6BAA6B;IAwErC;;OAEG;IACH,OAAO,CAAC,gCAAgC;CAqCzC"}
1
+ {"version":3,"file":"repo-service.d.ts","sourceRoot":"","sources":["../../src/services/repo-service.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAIlE,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,qBAAa,WAAW;IAMV,OAAO,CAAC,OAAO;IAL3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAA2B;IACnE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAyB;IAE/D,OAAO,CAAC,aAAa,CAAgB;gBAEjB,OAAO,EAAE,cAAc;IAS3C;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAQzB;;OAEG;IACG,4BAA4B,CAChC,eAAe,GAAE,MAAoB,GACpC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAmCzB;;;;OAIG;IACH,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAOvD;;OAEG;IACH,cAAc,IAAI,OAAO;IAUzB;;;OAGG;IACG,uBAAuB,IAAI,OAAO,CAAC,OAAO,CAAC;IAcjD;;OAEG;IACH,kBAAkB,IAAI,MAAM;IAa5B;;;;;;;;OAQG;IACG,qBAAqB,CAAC,OAAO,GAAE,4BAAiC,GAAG,OAAO,CAAC,IAAI,CAAC;IAwFtF;;OAEG;IACH,OAAO,CAAC,0BAA0B;IA4GlC;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAoChC;;OAEG;IACH,OAAO,CAAC,6BAA6B;IAwErC;;OAEG;IACH,OAAO,CAAC,gCAAgC;CAqCzC"}
@@ -229,7 +229,7 @@ export class RepoService {
229
229
  **BEFORE EVERY COMMIT**, check if you're working on tracked work:
230
230
 
231
231
  1. **Active PRDs?** Check \`.tiny-brain/progress/\` for \`in_progress\` status
232
- 2. **Open Fixes?** Check \`.tiny-brain/fixes/progress.json\` for \`investigating\` or \`in_progress\` status
232
+ 2. **Open Fixes?** Check \`.tiny-brain/fixes/progress.json\` for \`documented\` or \`in_progress\` status
233
233
 
234
234
  **If YES, you MUST include tracking headers or the commit will be REJECTED.**
235
235
 
@@ -265,42 +265,53 @@ Description of changes...
265
265
 
266
266
  **WARNING:** The commit-msg hook will reject commits missing required headers.
267
267
 
268
- ### CRITICAL: Update Markdown After Successful Commits
269
-
270
- **IMMEDIATELY after your commit is accepted**, you MUST update the source markdown file. This is NOT optional.
268
+ ### Updating Markdown After Commits
271
269
 
272
270
  **For PRD tasks:**
273
271
  1. Open the feature file: \`docs/prd/{prd-id}/features/{feature-id}.md\`
274
- 2. Find the task checkbox and update it:
275
- \`\`\`
276
- Before: - [ ] Task description
277
- After: - [x] Task description ({short-sha})
272
+ 2. Update the task with status and commitSha:
273
+ \`\`\`markdown
274
+ ### 1. Task description
275
+ status: completed
276
+ commitSha: abc1234
278
277
  \`\`\`
279
- 3. Add implementation notes below the task if helpful
280
- 4. If ALL tasks in the feature are complete, mark the feature complete in the PRD file
281
- - The feature file's frontmatter contains \`prd: {prd-id}\` - use this to find \`docs/prd/{prd-id}/prd.md\`
278
+ 3. Run: \`npx tiny-brain sync-file docs/prd/{prd-id}/features/{feature-id}.md\`
279
+ 4. If ALL tasks in the feature are complete, update the PRD status
280
+
281
+ ### Fix Status Workflow
282
+
283
+ Fix documents have three statuses: \`documented\` → \`in_progress\` → \`resolved\`
282
284
 
283
- **For Fix tasks:**
285
+ **When starting work on a fix:**
284
286
  1. Open the fix file: \`.tiny-brain/fixes/{fix-id}.md\`
285
- 2. **Update EACH task** with its resolution:
286
- - Set the task's \`commitSha\` field in \`.tiny-brain/fixes/progress.json\`
287
- - Set the task's \`status\` to \`"completed"\`
288
- - If one commit addresses multiple tasks, use the same SHA for all
289
- - Mark tasks as \`(superseded)\` if no longer needed
290
- - **Show the user a task status table** after updating, e.g.:
291
- | Task | Description | Status | commitSha |
292
- |------|-------------|--------|-----------|
293
- | 1 | Write failing test | completed | abc1234 |
294
- | 2 | Implement fix | completed | abc1234 |
295
- | 3 | Skipped task | superseded | - |
296
- 3. **ONLY set \`status: resolved\`** when ALL tasks are accounted for:
297
- - 100% of tasks must have either a commit SHA or be marked superseded
298
- - A fix with 5 tasks could be: 3 completed + 2 superseded = resolved
287
+ 2. Update frontmatter: \`status: in_progress\`
288
+ 3. Run: \`npx tiny-brain sync-file .tiny-brain/fixes/{fix-id}.md\`
289
+
290
+ **After each commit:**
291
+ 1. Update the completed task(s) in the markdown:
292
+ \`\`\`markdown
293
+ ### 1. Task description
294
+ status: completed
295
+ commitSha: abc1234
296
+ \`\`\`
297
+ 2. If one commit addresses multiple tasks, use the same commitSha for all of them
298
+ 3. If a task is no longer needed (work done elsewhere or obsolete), mark it superseded:
299
+ \`\`\`markdown
300
+ ### 3. Obsolete task
301
+ status: superseded
302
+ commitSha: null
303
+ \`\`\`
304
+ 4. Run: \`npx tiny-brain sync-file .tiny-brain/fixes/{fix-id}.md\`
305
+
306
+ **When all tasks are complete:**
307
+ 1. **ONLY set \`status: resolved\`** when ALL tasks are accounted for:
308
+ - 100% of tasks must have either \`status: completed\` (with commitSha) or \`status: superseded\`
309
+ - Example: A fix with 5 tasks could be: 3 completed + 2 superseded = resolved
299
310
  - A fix with incomplete tasks stays \`in_progress\`
300
- 4. When fully resolved, update YAML frontmatter:
311
+ 2. Update YAML frontmatter:
301
312
  - Set \`status: resolved\`
302
313
  - Set \`resolved: YYYY-MM-DDTHH:mm:ss.sssZ\` (ISO timestamp)
303
- - Add \`resolution\` object with \`rootCause\`, \`fix\` (array), and \`filesModified\` (array):
314
+ - Add \`resolution\` object:
304
315
  \`\`\`yaml
305
316
  resolution:
306
317
  rootCause: Brief description of what caused the issue
@@ -311,10 +322,9 @@ Description of changes...
311
322
  - path/to/file1.ts
312
323
  - path/to/file2.ts
313
324
  \`\`\`
325
+ 3. Run: \`npx tiny-brain sync-file .tiny-brain/fixes/{fix-id}.md\`
314
326
 
315
- **The sync-progress hook will automatically sync your changes to progress.json, preserving task commit history.**
316
-
317
- **Failure to update markdown files is a workflow violation.**
327
+ **Note:** The markdown file is the source of truth. The \`sync-file\` command updates \`progress.json\` from the markdown.
318
328
 
319
329
  `;
320
330
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.tool.d.ts","sourceRoot":"","sources":["../../../src/tools/config/config.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAA0C,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,IAAI,IAAI,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAWrE,qBAAa,UAAU;IACrB,MAAM,CAAC,iBAAiB,IAAI,OAAO;WA4DtB,OAAO,CAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,UAAU,CAAC;mBA6BD,UAAU;mBAwCV,SAAS;mBAoCT,iBAAiB;mBAgEjB,SAAS;mBAuDT,WAAW;CAqBjC"}
1
+ {"version":3,"file":"config.tool.d.ts","sourceRoot":"","sources":["../../../src/tools/config/config.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAA0C,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,IAAI,IAAI,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAUrE,qBAAa,UAAU;IACrB,MAAM,CAAC,iBAAiB,IAAI,OAAO;WA4DtB,OAAO,CAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,UAAU,CAAC;mBA6BD,UAAU;mBAwCV,SAAS;mBAoCT,iBAAiB;mBAgEjB,SAAS;mBAuDT,WAAW;CAqBjC"}
@@ -1,7 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import { createSuccessResult, createErrorResult } from '../index.js';
3
- import { ConfigService } from '@magic-ingredients/tiny-brain-core';
4
- import { TechContextService } from '../../services/tech-context-service.js';
3
+ import { ConfigService, TechContextService } from '@magic-ingredients/tiny-brain-core';
5
4
  const ConfigArgsSchema = z.object({
6
5
  operation: z.enum(['list', 'get', 'show-sources', 'set', 'reset']),
7
6
  key: z.string().optional(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magic-ingredients/tiny-brain-local",
3
- "version": "0.18.0",
3
+ "version": "0.18.1",
4
4
  "description": "MCP server for Tiny Brain AI assistant",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -31,7 +31,7 @@
31
31
  "dxt:init": "cd dxt && dxt init"
32
32
  },
33
33
  "dependencies": {
34
- "@magic-ingredients/tiny-brain-core": "^0.18.0",
34
+ "@magic-ingredients/tiny-brain-core": "^0.18.1",
35
35
  "@magic-ingredients/tiny-brain-dashboard": "file:../tiny-brain-dashboard",
36
36
  "@modelcontextprotocol/sdk": "^1.0.6",
37
37
  "chalk": "^5.3.0",
@@ -1,106 +0,0 @@
1
- /**
2
- * Tech Context Service
3
- *
4
- * Manages reading and writing of tech context files:
5
- * - .tiny-brain/analysis.json - repo analysis data
6
- * - .tiny-brain/tech/*.md - per-tech expertise files
7
- * - .tiny-brain/tech/config.json - agent mode configuration
8
- * - .claude/agents/tech-*.md - tech agent files (when enableAgentic=true)
9
- */
10
- import type { RepoAnalysisFile, TechExpertiseFrontmatter, TechExpertiseFile, TechConfig } from '@magic-ingredients/tiny-brain-core';
11
- /** Input analysis data from repository analysis */
12
- export interface AnalysisInput {
13
- languages: string[];
14
- frameworks: string[];
15
- testingTools: string[];
16
- buildTools: string[];
17
- hasTests: boolean;
18
- testFileCount: number;
19
- testPatterns: string[];
20
- isPolyglot?: boolean;
21
- primaryLanguage?: string;
22
- documentationPattern?: 'single-readme' | 'folder-readmes' | 'docs-folder' | 'mixed';
23
- documentationLocations?: string[];
24
- }
25
- export declare class TechContextService {
26
- private readonly tinyBrainDir;
27
- private readonly techDir;
28
- private readonly agentsDir;
29
- constructor(repoPath: string);
30
- /** Get the .tiny-brain directory path */
31
- getTinyBrainDir(): string;
32
- /** Get the .tiny-brain/tech directory path */
33
- getTechDir(): string;
34
- /** Get the .claude/agents directory path */
35
- getAgentsDir(): string;
36
- /** Ensure required directories exist */
37
- ensureDirectories(): Promise<void>;
38
- /**
39
- * Write analysis data to .tiny-brain/analysis.json
40
- */
41
- writeAnalysis(analysis: AnalysisInput): Promise<void>;
42
- /**
43
- * Write a tech expertise file with YAML frontmatter
44
- */
45
- writeTechFile(name: string, frontmatter: TechExpertiseFrontmatter, content: string): Promise<void>;
46
- /**
47
- * Write raw markdown content to a tech file
48
- * Used when receiving complete markdown from TBR API
49
- */
50
- writeTechFileRaw(name: string, content: string): Promise<void>;
51
- /**
52
- * Read analysis data from .tiny-brain/analysis.json
53
- */
54
- readAnalysis(): Promise<RepoAnalysisFile | null>;
55
- /**
56
- * Read all tech expertise files from .tiny-brain/tech/
57
- */
58
- readTechFiles(): Promise<TechExpertiseFile[]>;
59
- /**
60
- * Get tech files that match a given file path based on filePatterns
61
- */
62
- getTechForFile(filePath: string): Promise<TechExpertiseFile[]>;
63
- /**
64
- * Check if the tech stack has changed compared to previous analysis
65
- */
66
- hasStackChanged(analysis: AnalysisInput): Promise<boolean>;
67
- /**
68
- * Write config to .tiny-brain/tech/config.json
69
- */
70
- writeConfig(config: Omit<TechConfig, 'lastSynced'>): Promise<void>;
71
- /**
72
- * Read config from .tiny-brain/tech/config.json
73
- */
74
- readConfig(): Promise<TechConfig>;
75
- /**
76
- * Install tech agents to .claude/agents/
77
- * Converts tech context files into proper Claude Code sub-agents with:
78
- * - name: tech-{name} (matches subagent_type="tech-react")
79
- * - description: for Claude Code auto-delegation
80
- * - Sub-agent invocation context
81
- */
82
- installTechAgents(): Promise<void>;
83
- /**
84
- * Remove only tech-*.md files from .claude/agents/
85
- */
86
- removeTechAgents(): Promise<void>;
87
- /**
88
- * Sync agents based on enableAgentic preference
89
- */
90
- syncAgents(enableAgentic: boolean): Promise<void>;
91
- /**
92
- * Get versions of all local tech context files
93
- * @returns Map of tech name → version
94
- */
95
- getLocalTechVersions(): Promise<Map<string, string>>;
96
- /**
97
- * Compare versions to determine if TBS version is newer
98
- * @returns true if tbsVersion is newer than localVersion
99
- */
100
- shouldUpdateTech(localVersion: string, tbsVersion: string): boolean;
101
- /**
102
- * Parse YAML frontmatter from a markdown file
103
- */
104
- private parseFrontmatter;
105
- }
106
- //# sourceMappingURL=tech-context-service.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tech-context-service.d.ts","sourceRoot":"","sources":["../../src/services/tech-context-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EACV,gBAAgB,EAGhB,wBAAwB,EACxB,iBAAiB,EACjB,UAAU,EACX,MAAM,oCAAoC,CAAC;AAE5C,mDAAmD;AACnD,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oBAAoB,CAAC,EAAE,eAAe,GAAG,gBAAgB,GAAG,aAAa,GAAG,OAAO,CAAC;IACpF,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;CACnC;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,QAAQ,EAAE,MAAM;IAM5B,yCAAyC;IACzC,eAAe,IAAI,MAAM;IAIzB,8CAA8C;IAC9C,UAAU,IAAI,MAAM;IAIpB,4CAA4C;IAC5C,YAAY,IAAI,MAAM;IAItB,wCAAwC;IAClC,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAKxC;;OAEG;IACG,aAAa,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAoC3D;;OAEG;IACG,aAAa,CACjB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,wBAAwB,EACrC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC;IAmBhB;;;OAGG;IACG,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMpE;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAWtD;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;IA0BnD;;OAEG;IACG,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAwBpE;;OAEG;IACG,eAAe,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;IA4BhE;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAYxE;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC;IAWvC;;;;;;OAMG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAkCxC;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAcvC;;OAEG;IACG,UAAU,CAAC,aAAa,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAUvD;;;OAGG;IACG,oBAAoB,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAW1D;;;OAGG;IACH,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO;IAsBnE;;OAEG;IACH,OAAO,CAAC,gBAAgB;CA+CzB"}
@@ -1,365 +0,0 @@
1
- /**
2
- * Tech Context Service
3
- *
4
- * Manages reading and writing of tech context files:
5
- * - .tiny-brain/analysis.json - repo analysis data
6
- * - .tiny-brain/tech/*.md - per-tech expertise files
7
- * - .tiny-brain/tech/config.json - agent mode configuration
8
- * - .claude/agents/tech-*.md - tech agent files (when enableAgentic=true)
9
- */
10
- import { promises as fs } from 'fs';
11
- import path from 'path';
12
- import crypto from 'crypto';
13
- import minimatch from 'minimatch';
14
- export class TechContextService {
15
- tinyBrainDir;
16
- techDir;
17
- agentsDir;
18
- constructor(repoPath) {
19
- this.tinyBrainDir = path.join(repoPath, '.tiny-brain');
20
- this.techDir = path.join(this.tinyBrainDir, 'tech');
21
- this.agentsDir = path.join(repoPath, '.claude', 'agents');
22
- }
23
- /** Get the .tiny-brain directory path */
24
- getTinyBrainDir() {
25
- return this.tinyBrainDir;
26
- }
27
- /** Get the .tiny-brain/tech directory path */
28
- getTechDir() {
29
- return this.techDir;
30
- }
31
- /** Get the .claude/agents directory path */
32
- getAgentsDir() {
33
- return this.agentsDir;
34
- }
35
- /** Ensure required directories exist */
36
- async ensureDirectories() {
37
- await fs.mkdir(this.tinyBrainDir, { recursive: true });
38
- await fs.mkdir(this.techDir, { recursive: true });
39
- }
40
- /**
41
- * Write analysis data to .tiny-brain/analysis.json
42
- */
43
- async writeAnalysis(analysis) {
44
- await this.ensureDirectories();
45
- const stack = {
46
- languages: analysis.languages,
47
- frameworks: analysis.frameworks,
48
- testing: analysis.testingTools,
49
- build: analysis.buildTools,
50
- };
51
- const analysisData = {
52
- hasTests: analysis.hasTests,
53
- testFileCount: analysis.testFileCount,
54
- testPatterns: analysis.testPatterns,
55
- isPolyglot: analysis.isPolyglot ?? false,
56
- primaryLanguage: analysis.primaryLanguage ?? analysis.languages[0] ?? 'unknown',
57
- documentationPattern: analysis.documentationPattern,
58
- documentationLocations: analysis.documentationLocations,
59
- };
60
- // Generate hash from stable analysis input
61
- const hashInput = JSON.stringify({ stack, analysis: analysisData });
62
- const analysisHash = crypto.createHash('sha256').update(hashInput).digest('hex');
63
- const file = {
64
- version: '1.0',
65
- detectedAt: new Date().toISOString(),
66
- analysisHash,
67
- stack,
68
- analysis: analysisData,
69
- };
70
- const filePath = path.join(this.tinyBrainDir, 'analysis.json');
71
- await fs.writeFile(filePath, JSON.stringify(file, null, 2), 'utf-8');
72
- }
73
- /**
74
- * Write a tech expertise file with YAML frontmatter
75
- */
76
- async writeTechFile(name, frontmatter, content) {
77
- await this.ensureDirectories();
78
- const yamlFrontmatter = [
79
- '---',
80
- `name: ${frontmatter.name}`,
81
- `version: ${frontmatter.version}`,
82
- `domain: ${frontmatter.domain}`,
83
- `filePatterns:`,
84
- ...frontmatter.filePatterns.map(p => ` - "${p}"`),
85
- frontmatter.description ? `description: "${frontmatter.description}"` : null,
86
- '---',
87
- ].filter(Boolean).join('\n');
88
- const fileContent = `${yamlFrontmatter}\n\n${content}`;
89
- const filePath = path.join(this.techDir, `${name}.md`);
90
- await fs.writeFile(filePath, fileContent, 'utf-8');
91
- }
92
- /**
93
- * Write raw markdown content to a tech file
94
- * Used when receiving complete markdown from TBR API
95
- */
96
- async writeTechFileRaw(name, content) {
97
- await this.ensureDirectories();
98
- const filePath = path.join(this.techDir, `${name}.md`);
99
- await fs.writeFile(filePath, content, 'utf-8');
100
- }
101
- /**
102
- * Read analysis data from .tiny-brain/analysis.json
103
- */
104
- async readAnalysis() {
105
- const filePath = path.join(this.tinyBrainDir, 'analysis.json');
106
- try {
107
- const content = await fs.readFile(filePath, 'utf-8');
108
- return JSON.parse(content);
109
- }
110
- catch {
111
- return null;
112
- }
113
- }
114
- /**
115
- * Read all tech expertise files from .tiny-brain/tech/
116
- */
117
- async readTechFiles() {
118
- try {
119
- const files = await fs.readdir(this.techDir);
120
- const techFiles = [];
121
- for (const file of files) {
122
- if (!file.endsWith('.md'))
123
- continue;
124
- const filePath = path.join(this.techDir, file);
125
- const content = await fs.readFile(filePath, 'utf-8');
126
- const parsed = this.parseFrontmatter(content);
127
- if (parsed) {
128
- techFiles.push({
129
- ...parsed,
130
- filePath,
131
- });
132
- }
133
- }
134
- return techFiles;
135
- }
136
- catch {
137
- return [];
138
- }
139
- }
140
- /**
141
- * Get tech files that match a given file path based on filePatterns
142
- */
143
- async getTechForFile(filePath) {
144
- const techFiles = await this.readTechFiles();
145
- const matches = [];
146
- const basename = path.basename(filePath);
147
- for (const techFile of techFiles) {
148
- for (const pattern of techFile.frontmatter.filePatterns) {
149
- // Check multiple matching strategies:
150
- // 1. Full path glob match
151
- // 2. Basename match (for patterns like *.tsx)
152
- // 3. Directory prefix match (for patterns like components/)
153
- if (minimatch(filePath, pattern) ||
154
- minimatch(basename, pattern) ||
155
- minimatch(filePath, `**/${pattern}`) ||
156
- filePath.includes(pattern.replace(/\/$/, ''))) {
157
- matches.push(techFile);
158
- break; // Don't add same file multiple times
159
- }
160
- }
161
- }
162
- return matches;
163
- }
164
- /**
165
- * Check if the tech stack has changed compared to previous analysis
166
- */
167
- async hasStackChanged(analysis) {
168
- const existing = await this.readAnalysis();
169
- if (!existing)
170
- return true;
171
- // Generate hash for new analysis using same logic as writeAnalysis
172
- const stack = {
173
- languages: analysis.languages,
174
- frameworks: analysis.frameworks,
175
- testing: analysis.testingTools,
176
- build: analysis.buildTools,
177
- };
178
- const analysisData = {
179
- hasTests: analysis.hasTests,
180
- testFileCount: analysis.testFileCount,
181
- testPatterns: analysis.testPatterns,
182
- isPolyglot: analysis.isPolyglot ?? false,
183
- primaryLanguage: analysis.primaryLanguage ?? analysis.languages[0] ?? 'unknown',
184
- documentationPattern: analysis.documentationPattern,
185
- documentationLocations: analysis.documentationLocations,
186
- };
187
- const hashInput = JSON.stringify({ stack, analysis: analysisData });
188
- const newHash = crypto.createHash('sha256').update(hashInput).digest('hex');
189
- return newHash !== existing.analysisHash;
190
- }
191
- /**
192
- * Write config to .tiny-brain/tech/config.json
193
- */
194
- async writeConfig(config) {
195
- await this.ensureDirectories();
196
- const fullConfig = {
197
- ...config,
198
- lastSynced: new Date().toISOString(),
199
- };
200
- const filePath = path.join(this.techDir, 'config.json');
201
- await fs.writeFile(filePath, JSON.stringify(fullConfig, null, 2), 'utf-8');
202
- }
203
- /**
204
- * Read config from .tiny-brain/tech/config.json
205
- */
206
- async readConfig() {
207
- const filePath = path.join(this.techDir, 'config.json');
208
- try {
209
- const content = await fs.readFile(filePath, 'utf-8');
210
- return JSON.parse(content);
211
- }
212
- catch {
213
- return { useAgents: false };
214
- }
215
- }
216
- /**
217
- * Install tech agents to .claude/agents/
218
- * Converts tech context files into proper Claude Code sub-agents with:
219
- * - name: tech-{name} (matches subagent_type="tech-react")
220
- * - description: for Claude Code auto-delegation
221
- * - Sub-agent invocation context
222
- */
223
- async installTechAgents() {
224
- await fs.mkdir(this.agentsDir, { recursive: true });
225
- const techFiles = await this.readTechFiles();
226
- for (const techFile of techFiles) {
227
- const name = techFile.frontmatter.name;
228
- const agentFileName = `tech-${name}.md`;
229
- const agentPath = path.join(this.agentsDir, agentFileName);
230
- // Build description from frontmatter or generate default
231
- const description = techFile.frontmatter.description
232
- || `${name} development specialist. Use for ${techFile.frontmatter.domain} tasks involving ${name}.`;
233
- // Create agent file with proper Claude Code sub-agent format
234
- const agentContent = `---
235
- name: tech-${name}
236
- description: ${description}
237
- version: ${techFile.frontmatter.version}
238
- domain: ${techFile.frontmatter.domain}
239
- ---
240
-
241
- # ${name} Sub-Agent
242
-
243
- You are a specialized ${name} development agent invoked by the developer agent. Apply the expertise and patterns below to the task you've been given.
244
-
245
- ## Tech Expertise
246
-
247
- ${techFile.content}`;
248
- await fs.writeFile(agentPath, agentContent, 'utf-8');
249
- }
250
- }
251
- /**
252
- * Remove only tech-*.md files from .claude/agents/
253
- */
254
- async removeTechAgents() {
255
- try {
256
- const files = await fs.readdir(this.agentsDir);
257
- for (const file of files) {
258
- if (file.startsWith('tech-') && file.endsWith('.md')) {
259
- await fs.unlink(path.join(this.agentsDir, file));
260
- }
261
- }
262
- }
263
- catch {
264
- // Directory may not exist, ignore
265
- }
266
- }
267
- /**
268
- * Sync agents based on enableAgentic preference
269
- */
270
- async syncAgents(enableAgentic) {
271
- await this.writeConfig({ useAgents: enableAgentic });
272
- if (enableAgentic) {
273
- await this.installTechAgents();
274
- }
275
- else {
276
- await this.removeTechAgents();
277
- }
278
- }
279
- /**
280
- * Get versions of all local tech context files
281
- * @returns Map of tech name → version
282
- */
283
- async getLocalTechVersions() {
284
- const techFiles = await this.readTechFiles();
285
- const versions = new Map();
286
- for (const file of techFiles) {
287
- versions.set(file.frontmatter.name, file.frontmatter.version);
288
- }
289
- return versions;
290
- }
291
- /**
292
- * Compare versions to determine if TBS version is newer
293
- * @returns true if tbsVersion is newer than localVersion
294
- */
295
- shouldUpdateTech(localVersion, tbsVersion) {
296
- const parseVersion = (v) => {
297
- return v.split('.').map(s => parseInt(s, 10) || 0);
298
- };
299
- const local = parseVersion(localVersion);
300
- const tbs = parseVersion(tbsVersion);
301
- // Pad arrays to same length
302
- const maxLen = Math.max(local.length, tbs.length);
303
- while (local.length < maxLen)
304
- local.push(0);
305
- while (tbs.length < maxLen)
306
- tbs.push(0);
307
- // Compare each segment
308
- for (let i = 0; i < maxLen; i++) {
309
- if (tbs[i] > local[i])
310
- return true;
311
- if (tbs[i] < local[i])
312
- return false;
313
- }
314
- return false; // Versions are equal
315
- }
316
- /**
317
- * Parse YAML frontmatter from a markdown file
318
- */
319
- parseFrontmatter(content) {
320
- const match = content.match(/^---\n([\s\S]*?)\n---\n\n?([\s\S]*)$/);
321
- if (!match)
322
- return null;
323
- const yamlContent = match[1];
324
- const markdownContent = match[2];
325
- // Simple YAML parsing for our known structure
326
- const frontmatter = {};
327
- const lines = yamlContent.split('\n');
328
- let currentKey = '';
329
- let filePatterns = [];
330
- for (const line of lines) {
331
- const keyMatch = line.match(/^(\w+):\s*(.*)$/);
332
- if (keyMatch) {
333
- currentKey = keyMatch[1];
334
- const value = keyMatch[2].replace(/^["']|["']$/g, '');
335
- if (currentKey === 'filePatterns') {
336
- filePatterns = [];
337
- }
338
- else if (currentKey === 'name') {
339
- frontmatter.name = value;
340
- }
341
- else if (currentKey === 'version') {
342
- frontmatter.version = value;
343
- }
344
- else if (currentKey === 'domain') {
345
- frontmatter.domain = value;
346
- }
347
- else if (currentKey === 'description') {
348
- frontmatter.description = value;
349
- }
350
- }
351
- else if (currentKey === 'filePatterns' && line.trim().startsWith('-')) {
352
- const pattern = line.trim().replace(/^-\s*/, '').replace(/^["']|["']$/g, '');
353
- filePatterns.push(pattern);
354
- }
355
- }
356
- frontmatter.filePatterns = filePatterns;
357
- if (!frontmatter.name || !frontmatter.version || !frontmatter.domain) {
358
- return null;
359
- }
360
- return {
361
- frontmatter: frontmatter,
362
- content: markdownContent,
363
- };
364
- }
365
- }