@magic-ingredients/tiny-brain-local 0.19.1 → 0.20.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":"mcp-server.d.ts","sourceRoot":"","sources":["../../src/core/mcp-server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA0BH,OAAO,KAAK,EAA4B,QAAQ,EAAkC,MAAM,oCAAoC,CAAC;AAE7H,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAQ5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,2CAA2C,CAAC;AAE9E;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,OAAO,CAAC,EAAE;QACR,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IAEF,KAAK,CAAC,EAAE;QACN,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,QAAQ,CAAC;KACrB,CAAC;CACH;AAED;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,aAAa,CAAiC;IACtD,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,sBAAsB,CAA0D;IACxF,OAAO,CAAC,mBAAmB,CAA2G;IACtI,OAAO,CAAC,UAAU,CAA6E;IAC/F,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,SAAS,CAAC,CAAY;IAC9B,OAAO,CAAC,gBAAgB,CAAC,CAAmB;gBAEhC,MAAM,GAAE,SAAc;IAwFlC,OAAO,CAAC,aAAa;IAarB;;OAEG;IACH,SAAS,IAAI,SAAS;IAItB;;OAEG;IACH,mBAAmB,IAAI,gBAAgB,GAAG,SAAS;IAInD;;OAEG;IACH,oBAAoB,IAAI,iBAAiB,GAAG,IAAI;IAIhD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAsBjC;;;;;;;OAOG;YACW,sBAAsB;IA+DpC;;OAEG;YACW,iBAAiB;IAW/B;;;OAGG;YACW,oBAAoB;IA6BlC;;OAEG;YACW,oBAAoB;IAkHlC;;;;;;OAMG;YACW,yBAAyB;IA+CvC;;OAEG;YACW,kBAAkB;IAsBhC;;OAEG;YACW,wBAAwB;IA8BtC;;OAEG;YACW,mBAAmB;IA8BjC;;OAEG;IACG,OAAO,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5C;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YAiBjB,eAAe;YAMf,cAAc;YA+Fd,iBAAiB;YAMjB,eAAe;YAqEf,iBAAiB;IAS/B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAoB7B;;OAEG;IACH,OAAO,CAAC,oBAAoB;CAkD7B"}
1
+ {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../../src/core/mcp-server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA0BH,OAAO,KAAK,EAA4B,QAAQ,EAAkC,MAAM,oCAAoC,CAAC;AAE7H,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAQ5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,2CAA2C,CAAC;AAE9E;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,OAAO,CAAC,EAAE;QACR,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IAEF,KAAK,CAAC,EAAE;QACN,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,QAAQ,CAAC;KACrB,CAAC;CACH;AAED;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,aAAa,CAAiC;IACtD,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,sBAAsB,CAA0D;IACxF,OAAO,CAAC,mBAAmB,CAA2G;IACtI,OAAO,CAAC,UAAU,CAA6E;IAC/F,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,SAAS,CAAC,CAAY;IAC9B,OAAO,CAAC,gBAAgB,CAAC,CAAmB;gBAEhC,MAAM,GAAE,SAAc;IAwFlC,OAAO,CAAC,aAAa;IAarB;;OAEG;IACH,SAAS,IAAI,SAAS;IAItB;;OAEG;IACH,mBAAmB,IAAI,gBAAgB,GAAG,SAAS;IAInD;;OAEG;IACH,oBAAoB,IAAI,iBAAiB,GAAG,IAAI;IAIhD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAsBjC;;;;;;;OAOG;YACW,sBAAsB;IA+DpC;;OAEG;YACW,iBAAiB;IAW/B;;;OAGG;YACW,oBAAoB;IA6BlC;;OAEG;YACW,oBAAoB;IAwGlC;;;;;;OAMG;YACW,yBAAyB;IA+CvC;;OAEG;YACW,kBAAkB;IAsBhC;;OAEG;YACW,wBAAwB;IA8BtC;;OAEG;YACW,mBAAmB;IA8BjC;;OAEG;IACG,OAAO,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5C;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YAiBjB,eAAe;YAMf,cAAc;YAgGd,iBAAiB;YAMjB,eAAe;YAqEf,iBAAiB;IAS/B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAoB7B;;OAEG;IACH,OAAO,CAAC,oBAAoB;CAkD7B"}
@@ -8,7 +8,7 @@ import { existsSync, cpSync, readdirSync, readFileSync, writeFileSync, mkdirSync
8
8
  import { execSync } from 'child_process';
9
9
  import { Server as McpServer } from '@modelcontextprotocol/sdk/server/index.js';
10
10
  import { ListToolsRequestSchema, CallToolRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, SetLevelRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
11
- import { isDevelopment as checkIsDevelopment } from '@magic-ingredients/tiny-brain-core';
11
+ import { isDevelopment as checkIsDevelopment, detectClaudeCliStatus } from '@magic-ingredients/tiny-brain-core';
12
12
  import { AuthTokenService } from '../services/remote/auth-token-service.js';
13
13
  import { CredentialStorageService } from '../services/credential-storage.service.js';
14
14
  import { SystemPersonaService } from '../services/remote/system-persona-service.js';
@@ -276,12 +276,11 @@ export class MCPServer {
276
276
  hasClientSecret: !!this.config.account?.clientSecret,
277
277
  configKeys: Object.keys(this.config)
278
278
  });
279
- // Create credential service to check for credentials and LLM API key
279
+ // Create credential service to check for credentials
280
280
  const credentialService = new CredentialStorageService();
281
- // Check LLM API key availability (for dashboard to disable/enable skill invocation buttons)
282
- const hasLlmApiKey = await credentialService.hasLlmApiKey();
283
- // Create getter function for the actual API key (for skill invocation)
284
- const getLlmApiKey = () => credentialService.getLlmApiKey();
281
+ // Check Claude CLI availability (for dashboard to disable/enable skill invocation buttons)
282
+ const cliStatus = await detectClaudeCliStatus(this.logger);
283
+ const hasClaudeCli = cliStatus.authenticated;
285
284
  // Check for remote auth credentials
286
285
  if (!this.config.account?.clientId || !this.config.account?.clientSecret) {
287
286
  this.logger.info('No remote credentials configured in MCP config, checking tiny-brain CLI config...');
@@ -298,13 +297,11 @@ export class MCPServer {
298
297
  }
299
298
  else {
300
299
  this.logger.info('No credentials found in CLI config either, running in local-only mode');
301
- // Still set libraryAuth with hasLlmApiKey for dashboard
302
300
  this.baseContext.libraryAuth = {
303
301
  clientId: undefined,
304
302
  hasStoredSecret: false,
305
- hasLlmApiKey,
303
+ hasClaudeCli,
306
304
  token: undefined,
307
- getLlmApiKey
308
305
  };
309
306
  return;
310
307
  }
@@ -312,13 +309,11 @@ export class MCPServer {
312
309
  catch (error) {
313
310
  this.logger.warn('Error reading CLI config:', error);
314
311
  this.logger.info('Running in local-only mode');
315
- // Still set libraryAuth with hasLlmApiKey for dashboard
316
312
  this.baseContext.libraryAuth = {
317
313
  clientId: undefined,
318
314
  hasStoredSecret: false,
319
- hasLlmApiKey,
315
+ hasClaudeCli,
320
316
  token: undefined,
321
- getLlmApiKey
322
317
  };
323
318
  return;
324
319
  }
@@ -343,9 +338,8 @@ export class MCPServer {
343
338
  this.baseContext.libraryAuth = {
344
339
  clientId: this.config.account?.clientId,
345
340
  hasStoredSecret: true,
346
- hasLlmApiKey,
341
+ hasClaudeCli,
347
342
  token: token.token,
348
- getLlmApiKey
349
343
  };
350
344
  }
351
345
  else {
@@ -356,22 +350,19 @@ export class MCPServer {
356
350
  this.baseContext.libraryAuth = {
357
351
  clientId: this.config.account?.clientId,
358
352
  hasStoredSecret: !!this.config.account?.clientSecret,
359
- hasLlmApiKey,
353
+ hasClaudeCli,
360
354
  token: undefined,
361
- getLlmApiKey
362
355
  };
363
356
  }
364
357
  }
365
358
  catch (error) {
366
359
  this.logger.error('Unexpected error during remote authentication', error);
367
360
  // Continue in local mode - don't fail the entire initialization
368
- // Still set libraryAuth with hasLlmApiKey for dashboard
369
361
  this.baseContext.libraryAuth = {
370
362
  clientId: this.config.account?.clientId,
371
363
  hasStoredSecret: !!this.config.account?.clientSecret,
372
- hasLlmApiKey,
364
+ hasClaudeCli,
373
365
  token: undefined,
374
- getLlmApiKey
375
366
  };
376
367
  }
377
368
  }
@@ -558,6 +549,7 @@ export class MCPServer {
558
549
  activePersona,
559
550
  authToken: this.authToken,
560
551
  config: this.config,
552
+ dashboardLauncher: this.dashboardLauncher ?? undefined,
561
553
  updateActivePersona: (persona) => {
562
554
  const newPersonaId = persona?.id;
563
555
  this.activePersona = newPersonaId;
@@ -29,6 +29,7 @@ export interface AnalyseResult {
29
29
  };
30
30
  skillPermissionsAdded?: string[];
31
31
  writtenTechContexts?: string[];
32
+ agentsMdStatus?: 'created' | 'updated' | 'up-to-date';
32
33
  }
33
34
  /**
34
35
  * Service for managing repository analysis
@@ -45,6 +46,20 @@ export declare class AnalyseService {
45
46
  * Perform repository analysis with unified behavior for initialized/uninitialized repos
46
47
  */
47
48
  performAnalysis(options?: AnalyseOptions): Promise<AnalyseResult>;
49
+ /**
50
+ * Generate AGENTS.md file in the repository root
51
+ * For monorepos, also generates per-package AGENTS.md files
52
+ * Uses AgentsMdService from tiny-brain-core
53
+ */
54
+ private generateAgentsMd;
55
+ /**
56
+ * Read package.json from each workspace directory to collect names and descriptions
57
+ */
58
+ private collectPackageDescriptions;
59
+ /**
60
+ * Generate AGENTS.md for each workspace package in a monorepo
61
+ */
62
+ private generatePerPackageAgentsMd;
48
63
  /**
49
64
  * Register repository in dashboard for visibility
50
65
  * Called after successful analysis regardless of invocation method
@@ -95,6 +110,10 @@ export declare class AnalyseService {
95
110
  * Format analysis output for display
96
111
  */
97
112
  formatAnalysisOutput(result: AnalyseResult): string;
113
+ /**
114
+ * Append rich metadata sections to output lines
115
+ */
116
+ private appendRichMetadataOutput;
98
117
  /**
99
118
  * Compare two tech stacks and return differences
100
119
  * Handles null previous analysis (first run)
@@ -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,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"}
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,EAQnB,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;IAC/B,cAAc,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,CAAC;CACvD;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;IAyK3E;;;;OAIG;YACW,gBAAgB;IAmD9B;;OAEG;YACW,0BAA0B;IAyBxC;;OAEG;YACW,0BAA0B;IA+BxC;;;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;IAgInD;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA2ChC;;;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,7 +4,7 @@
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, LibraryClient, TechContextService, } from '@magic-ingredients/tiny-brain-core';
7
+ import { analyseRepository, formatTechStackChanges, detectTechStackChanges, ConfigService, RepoConfigService, LibraryClient, TechContextService, AgentsMdService, } from '@magic-ingredients/tiny-brain-core';
8
8
  import { RepoService } from './repo-service.js';
9
9
  import { fileURLToPath } from 'url';
10
10
  import { dirname, join } from 'path';
@@ -60,6 +60,13 @@ export class AnalyseService {
60
60
  primaryLanguage: currentAnalysis.primaryLanguage,
61
61
  documentationPattern: currentAnalysis.documentationPattern,
62
62
  documentationLocations: currentAnalysis.documentationLocations,
63
+ // Rich metadata
64
+ packageManager: currentAnalysis.packageManager,
65
+ scripts: currentAnalysis.scripts,
66
+ linting: currentAnalysis.linting,
67
+ monorepo: currentAnalysis.monorepo,
68
+ projectName: currentAnalysis.projectName,
69
+ sourceDirectories: currentAnalysis.sourceDirectories,
63
70
  };
64
71
  const stackChanged = await this.techContextService.hasStackChanged(analysisInput);
65
72
  const existingAnalysis = await this.techContextService.readAnalysis();
@@ -79,6 +86,12 @@ export class AnalyseService {
79
86
  if (!dryRun) {
80
87
  await this.techContextService.syncAgents(enableAgentic);
81
88
  }
89
+ // Generate AGENTS.md (if config allows)
90
+ let agentsMdStatus;
91
+ const manageAgentsMd = await this.configService.isManageAgentsMdEnabled();
92
+ if (!dryRun && manageAgentsMd) {
93
+ agentsMdStatus = await this.generateAgentsMd(currentAnalysis);
94
+ }
82
95
  // Write workflow sections to CLAUDE.md based on config flags (SDD, TDD)
83
96
  if (!dryRun) {
84
97
  await this.repoService.writeWorkflowSections({ contextPath });
@@ -105,7 +118,8 @@ export class AnalyseService {
105
118
  contextBlockVersion,
106
119
  contextBlockUpdated,
107
120
  skillPermissionsAdded: skillPermissionsAdded.length > 0 ? skillPermissionsAdded : undefined,
108
- writtenTechContexts
121
+ writtenTechContexts,
122
+ agentsMdStatus,
109
123
  };
110
124
  }
111
125
  if (!stackChanged) {
@@ -125,7 +139,8 @@ export class AnalyseService {
125
139
  contextBlockVersion,
126
140
  contextBlockUpdated,
127
141
  skillPermissionsAdded: skillPermissionsAdded.length > 0 ? skillPermissionsAdded : undefined,
128
- writtenTechContexts
142
+ writtenTechContexts,
143
+ agentsMdStatus,
129
144
  };
130
145
  }
131
146
  // Changes detected - compute diff for display purposes
@@ -163,9 +178,108 @@ export class AnalyseService {
163
178
  techStackRemoved: techStackDiff.removed
164
179
  },
165
180
  skillPermissionsAdded: skillPermissionsAdded.length > 0 ? skillPermissionsAdded : undefined,
166
- writtenTechContexts
181
+ writtenTechContexts,
182
+ agentsMdStatus,
167
183
  };
168
184
  }
185
+ /**
186
+ * Generate AGENTS.md file in the repository root
187
+ * For monorepos, also generates per-package AGENTS.md files
188
+ * Uses AgentsMdService from tiny-brain-core
189
+ */
190
+ async generateAgentsMd(analysis) {
191
+ const repoRoot = process.cwd();
192
+ const agentsMdService = new AgentsMdService(repoRoot);
193
+ const agentsMdPath = join(repoRoot, 'AGENTS.md');
194
+ // Read existing AGENTS.md if present
195
+ let existingContent;
196
+ try {
197
+ existingContent = await readFile(agentsMdPath, 'utf-8');
198
+ }
199
+ catch {
200
+ // File doesn't exist
201
+ }
202
+ // Extract README excerpt
203
+ const readmeExcerpt = await agentsMdService.extractReadmeExcerpt();
204
+ // Collect package descriptions for monorepo
205
+ let packageDescriptions;
206
+ if (analysis.monorepo?.packages && analysis.monorepo.packages.length > 0) {
207
+ packageDescriptions = await this.collectPackageDescriptions(repoRoot, analysis.monorepo.packages);
208
+ }
209
+ // Generate root content
210
+ const result = await agentsMdService.generateContent({
211
+ analysis,
212
+ readmeExcerpt,
213
+ repoPath: repoRoot,
214
+ existingContent,
215
+ packageDescriptions,
216
+ });
217
+ if (!existingContent) {
218
+ await writeFile(agentsMdPath, result.content, 'utf-8');
219
+ this.context.logger.info('Created AGENTS.md');
220
+ }
221
+ else if (!result.contentChanged) {
222
+ this.context.logger.info('AGENTS.md is up to date');
223
+ }
224
+ else {
225
+ await writeFile(agentsMdPath, result.content, 'utf-8');
226
+ this.context.logger.info('Updated AGENTS.md');
227
+ }
228
+ // Generate per-package AGENTS.md for monorepo
229
+ if (analysis.monorepo?.packages && analysis.monorepo.packages.length > 0) {
230
+ await this.generatePerPackageAgentsMd(repoRoot, analysis, agentsMdService);
231
+ }
232
+ if (!existingContent)
233
+ return 'created';
234
+ if (!result.contentChanged)
235
+ return 'up-to-date';
236
+ return 'updated';
237
+ }
238
+ /**
239
+ * Read package.json from each workspace directory to collect names and descriptions
240
+ */
241
+ async collectPackageDescriptions(repoRoot, packages) {
242
+ const descriptions = [];
243
+ for (const pkgPath of packages) {
244
+ const fullPath = join(repoRoot, pkgPath);
245
+ const pkgJsonPath = join(fullPath, 'package.json');
246
+ try {
247
+ const raw = await readFile(pkgJsonPath, 'utf-8');
248
+ const pkgJson = JSON.parse(raw);
249
+ descriptions.push({
250
+ name: pkgJson.name,
251
+ path: pkgPath,
252
+ description: pkgJson.description,
253
+ });
254
+ }
255
+ catch {
256
+ descriptions.push({ path: pkgPath });
257
+ }
258
+ }
259
+ return descriptions;
260
+ }
261
+ /**
262
+ * Generate AGENTS.md for each workspace package in a monorepo
263
+ */
264
+ async generatePerPackageAgentsMd(repoRoot, analysis, agentsMdService) {
265
+ const packages = analysis.monorepo?.packages ?? [];
266
+ for (const pkgPath of packages) {
267
+ const fullPkgPath = join(repoRoot, pkgPath);
268
+ const pkgAgentsMdPath = join(fullPkgPath, 'AGENTS.md');
269
+ let existingPkgContent;
270
+ try {
271
+ existingPkgContent = await readFile(pkgAgentsMdPath, 'utf-8');
272
+ }
273
+ catch {
274
+ // File doesn't exist
275
+ }
276
+ const pkgResult = await agentsMdService.generatePackageContent(fullPkgPath, analysis, existingPkgContent);
277
+ if (!existingPkgContent || pkgResult.contentChanged) {
278
+ await writeFile(pkgAgentsMdPath, pkgResult.content, 'utf-8');
279
+ this.context.logger.debug(`Wrote AGENTS.md for ${pkgPath}`);
280
+ }
281
+ }
282
+ }
169
283
  /**
170
284
  * Register repository in dashboard for visibility
171
285
  * Called after successful analysis regardless of invocation method
@@ -506,6 +620,9 @@ export class AnalyseService {
506
620
  lines.push(` Frameworks: ${result.analysis.frameworks.join(', ')}`);
507
621
  lines.push(` Build Tools: ${result.analysis.buildTools.join(', ')}`);
508
622
  lines.push(` Testing Tools: ${result.analysis.testingTools.join(', ')}`);
623
+ if (result.analysis.packageManager) {
624
+ lines.push(` Package Manager: ${result.analysis.packageManager}`);
625
+ }
509
626
  if (result.analysis.documentationPattern) {
510
627
  lines.push(`\n📚 Documentation: ${result.analysis.documentationPattern}`);
511
628
  if (result.analysis.documentationLocations) {
@@ -578,8 +695,64 @@ export class AnalyseService {
578
695
  lines.push(' None');
579
696
  }
580
697
  }
698
+ // Rich metadata sections (shown in all cases when data exists)
699
+ this.appendRichMetadataOutput(lines, result.analysis);
700
+ // AGENTS.md status (shown in all cases)
701
+ if (result.agentsMdStatus) {
702
+ const statusLabel = result.agentsMdStatus === 'created' ? 'Created'
703
+ : result.agentsMdStatus === 'updated' ? 'Updated'
704
+ : 'Up to date';
705
+ lines.push(`\nAGENTS.md: ${statusLabel}`);
706
+ }
581
707
  return lines.join('\n');
582
708
  }
709
+ /**
710
+ * Append rich metadata sections to output lines
711
+ */
712
+ appendRichMetadataOutput(lines, analysis) {
713
+ // Package manager (shown when not already in tech stack section)
714
+ if (analysis.packageManager) {
715
+ lines.push(`\n Package Manager: ${analysis.packageManager}`);
716
+ }
717
+ // Commands section
718
+ const scripts = analysis.scripts;
719
+ if (scripts && (scripts.test?.command || scripts.build?.command || scripts.dev?.command || scripts.lint?.command || scripts.e2e?.command)) {
720
+ lines.push('\n📋 Commands:');
721
+ if (scripts.test?.command)
722
+ lines.push(` Test: ${scripts.test.command}`);
723
+ if (scripts.build?.command)
724
+ lines.push(` Build: ${scripts.build.command}`);
725
+ if (scripts.dev?.command)
726
+ lines.push(` Dev: ${scripts.dev.command}`);
727
+ if (scripts.lint?.command)
728
+ lines.push(` Lint: ${scripts.lint.command}`);
729
+ if (scripts.e2e?.command)
730
+ lines.push(` E2E: ${scripts.e2e.command}`);
731
+ }
732
+ // Linting section
733
+ if (analysis.linting) {
734
+ lines.push('\n🔍 Linting:');
735
+ if (analysis.linting.tool) {
736
+ lines.push(` Tool: ${analysis.linting.tool}`);
737
+ }
738
+ if (analysis.linting.plugins && analysis.linting.plugins.length > 0) {
739
+ lines.push(` Plugins: ${analysis.linting.plugins.join(', ')}`);
740
+ }
741
+ }
742
+ // Monorepo section
743
+ if (analysis.monorepo) {
744
+ lines.push('\n📦 Monorepo:');
745
+ if (analysis.monorepo.tool) {
746
+ lines.push(` Tool: ${analysis.monorepo.tool}`);
747
+ }
748
+ if (analysis.monorepo.packages && analysis.monorepo.packages.length > 0) {
749
+ lines.push(' Packages:');
750
+ for (const pkg of analysis.monorepo.packages) {
751
+ lines.push(` - ${pkg}`);
752
+ }
753
+ }
754
+ }
755
+ }
583
756
  /**
584
757
  * Compare two tech stacks and return differences
585
758
  * Handles null previous analysis (first run)
@@ -15,6 +15,7 @@ export declare class DashboardLauncher {
15
15
  private server;
16
16
  start(context: RequestContext, options?: DashboardOptions): Promise<DashboardStartResult>;
17
17
  stop(): Promise<void>;
18
+ restart(context: RequestContext, options?: DashboardOptions): Promise<DashboardStartResult>;
18
19
  isRunning(): boolean;
19
20
  }
20
21
  //# sourceMappingURL=dashboard-launcher.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-launcher.service.d.ts","sourceRoot":"","sources":["../../src/services/dashboard-launcher.service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAIlE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAa;IAErB,KAAK,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAc7F,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAO3B,SAAS,IAAI,OAAO;CAGrB"}
1
+ {"version":3,"file":"dashboard-launcher.service.d.ts","sourceRoot":"","sources":["../../src/services/dashboard-launcher.service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAIlE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAa;IAErB,KAAK,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAc7F,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAOrB,OAAO,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAKrG,SAAS,IAAI,OAAO;CAGrB"}
@@ -23,6 +23,10 @@ export class DashboardLauncher {
23
23
  this.server = null;
24
24
  }
25
25
  }
26
+ async restart(context, options = {}) {
27
+ await this.stop();
28
+ return this.start(context, options);
29
+ }
26
30
  isRunning() {
27
31
  return this.server !== null;
28
32
  }
@@ -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;IA6FtF;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAyBhC;;OAEG;IACH,OAAO,CAAC,0BAA0B;IA4GlC;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAoChC;;OAEG;IACH,OAAO,CAAC,6BAA6B;IAwErC;;OAEG;IACH,OAAO,CAAC,gCAAgC;CAyCzC"}
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;IA6FtF;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IA0BhC;;OAEG;IACH,OAAO,CAAC,0BAA0B;IA6GlC;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAoChC;;OAEG;IACH,OAAO,CAAC,6BAA6B;IAwErC;;OAEG;IACH,OAAO,CAAC,gCAAgC;CAyCzC"}
@@ -229,7 +229,8 @@ export class RepoService {
229
229
  formatRepoContextSection(enableAgenticCoding) {
230
230
  let content = `## Repository Context
231
231
 
232
- Before starting work, read \`.tiny-brain/analysis.json\` for the detected tech stack, test patterns, and documentation locations.
232
+ Before starting work, read \`AGENTS.md\` for comprehensive project context (tech stack, commands, structure).
233
+ Also read \`.tiny-brain/analysis.json\` for detailed detection data and test patterns.
233
234
 
234
235
  `;
235
236
  if (enableAgenticCoding) {
@@ -292,6 +293,7 @@ Description of changes...
292
293
  | \`fix:\` | Bug fixes | Yes |
293
294
  | \`refactor:\` | Code improvement | Yes |
294
295
  | \`chore:\` | Maintenance (untracked) | No |
296
+ | \`untracked:\` | Work not related to any PRD or Fix | No |
295
297
 
296
298
  **WARNING:** The commit-msg hook will reject commits missing required headers.
297
299
 
@@ -0,0 +1,14 @@
1
+ import { type ToolArguments, type ToolResult } from '../index.js';
2
+ import type { RequestContext } from '../../types/request-context.js';
3
+ import type { Tool as MCPTool } from '@modelcontextprotocol/sdk/types.js';
4
+ /**
5
+ * Dashboard Tool - Restart the dashboard server
6
+ *
7
+ * Developer maintenance tool for force-reloading the dashboard,
8
+ * e.g. after rebuilding packages.
9
+ */
10
+ export declare class DashboardTool {
11
+ static getToolDefinition(): MCPTool;
12
+ static execute(_args: ToolArguments, context: RequestContext): Promise<ToolResult>;
13
+ }
14
+ //# sourceMappingURL=dashboard.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.tool.d.ts","sourceRoot":"","sources":["../../../src/tools/dashboard/dashboard.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0C,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAC1G,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAErE,OAAO,KAAK,EAAE,IAAI,IAAI,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAE1E;;;;;GAKG;AACH,qBAAa,aAAa;IACxB,MAAM,CAAC,iBAAiB,IAAI,OAAO;WAatB,OAAO,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC;CAiBzF"}
@@ -0,0 +1,34 @@
1
+ import { createErrorResult, createSuccessResult } from '../index.js';
2
+ /**
3
+ * Dashboard Tool - Restart the dashboard server
4
+ *
5
+ * Developer maintenance tool for force-reloading the dashboard,
6
+ * e.g. after rebuilding packages.
7
+ */
8
+ export class DashboardTool {
9
+ static getToolDefinition() {
10
+ return {
11
+ name: 'dev_restart_dashboard',
12
+ description: 'Restart the dashboard server. Developer maintenance tool — only needed to force a reload of the dashboard (e.g. after rebuilding packages).',
13
+ inputSchema: {
14
+ type: 'object',
15
+ properties: {},
16
+ required: [],
17
+ },
18
+ };
19
+ }
20
+ static async execute(_args, context) {
21
+ const localContext = context;
22
+ const launcher = localContext.dashboardLauncher;
23
+ if (!launcher) {
24
+ return createErrorResult('Dashboard launcher is not available. The dashboard may not have been started.');
25
+ }
26
+ try {
27
+ const result = await launcher.restart(context, {});
28
+ return createSuccessResult(`Dashboard restarted successfully at ${result.url}`);
29
+ }
30
+ catch (error) {
31
+ return createErrorResult(`Failed to restart dashboard: ${error instanceof Error ? error.message : 'Unknown error'}`);
32
+ }
33
+ }
34
+ }
@@ -500,8 +500,8 @@ export class AsTool {
500
500
  if (libraryAuth?.token) {
501
501
  formatted += ` 🔑 Connected to Tiny Brain Remote\n`;
502
502
  }
503
- if (libraryAuth?.hasLlmApiKey) {
504
- formatted += ` 🔑 LLM API key configured\n`;
503
+ if (libraryAuth?.hasClaudeCli) {
504
+ formatted += ` 🤖 Claude CLI authenticated\n`;
505
505
  }
506
506
  // Only show pre-flight and agent-first workflow if agents are installed
507
507
  if (hasAgents) {
@@ -22,6 +22,7 @@ export declare class QualityTool {
22
22
  private static handleDetectAnalyzers;
23
23
  private static handleRunAnalyzers;
24
24
  private static handleAssembleRun;
25
+ private static handleImplementPlan;
25
26
  private static handleMergeResults;
26
27
  }
27
28
  //# sourceMappingURL=quality.tool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"quality.tool.d.ts","sourceRoot":"","sources":["../../../src/tools/quality/quality.tool.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,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;AAyDrE;;GAEG;AACH,qBAAa,WAAW;IACtB,MAAM,CAAC,iBAAiB,IAAI,OAAO;WA+KtB,OAAO,CAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,UAAU,CAAC;mBA8CD,UAAU;mBAqCV,aAAa;mBA2Bb,aAAa;mBA2Eb,aAAa;mBAsEb,UAAU;mBA0CV,iBAAiB;mBAgEjB,qBAAqB;mBA6BrB,kBAAkB;mBA+ClB,iBAAiB;IA8CtC,OAAO,CAAC,MAAM,CAAC,kBAAkB;CAoBlC"}
1
+ {"version":3,"file":"quality.tool.d.ts","sourceRoot":"","sources":["../../../src/tools/quality/quality.tool.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,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;AA0DrE;;GAEG;AACH,qBAAa,WAAW;IACtB,MAAM,CAAC,iBAAiB,IAAI,OAAO;WAiLtB,OAAO,CAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,UAAU,CAAC;mBAgDD,UAAU;mBAqCV,aAAa;mBA2Bb,aAAa;mBA2Eb,aAAa;mBAsEb,UAAU;mBA0CV,iBAAiB;mBAgEjB,qBAAqB;mBA6BrB,kBAAkB;mBAgDlB,iBAAiB;mBAmDjB,mBAAmB;IAiDxC,OAAO,CAAC,MAAM,CAAC,kBAAkB;CAoBlC"}
@@ -15,7 +15,8 @@ import { QualityService, AnalyzerDetectionService, AnalyzerExecutorService, Asse
15
15
  const QualityArgsSchema = z.object({
16
16
  operation: z.enum([
17
17
  'save', 'history', 'details', 'compare', 'plan', 'plan-details',
18
- 'detect-analyzers', 'run-analyzers', 'merge-results', 'assemble-run',
18
+ 'detect-analysers', 'run-analysers', 'merge-results', 'assemble-run',
19
+ 'implement-plan',
19
20
  ]),
20
21
  // For 'save' operation
21
22
  score: z.number().min(0).max(100).optional(),
@@ -63,10 +64,11 @@ Persists and retrieves quality analysis results. Analysis is performed by agents
63
64
  • compare: Compare two runs to see new, resolved, and persistent issues
64
65
  • plan: Generate a Quality Improvement Plan from a saved run
65
66
  • plan-details: Retrieve a saved Quality Improvement Plan by ID
66
- • detect-analyzers: Scan repo for configured static analyzers
67
- • run-analyzers: Execute detected analyzers and return normalized issues
67
+ • detect-analysers: Scan repo for configured static analyzers
68
+ • run-analysers: Execute detected analyzers and return normalized issues
68
69
  • merge-results: Merge analyzer + LLM issues with deduplication
69
70
  • assemble-run: Read all intermediate files, merge, score, and save final report
71
+ • implement-plan: Generate fix documents from a saved Quality Improvement Plan
70
72
 
71
73
  💡 WORKFLOW:
72
74
  1. Quality-coordinator agent performs analysis
@@ -81,7 +83,8 @@ Persists and retrieves quality analysis results. Analysis is performed by agents
81
83
  type: 'string',
82
84
  enum: [
83
85
  'save', 'history', 'details', 'compare', 'plan', 'plan-details',
84
- 'detect-analyzers', 'run-analyzers', 'merge-results', 'assemble-run',
86
+ 'detect-analysers', 'run-analysers', 'merge-results', 'assemble-run',
87
+ 'implement-plan',
85
88
  ],
86
89
  description: 'The quality operation to perform',
87
90
  },
@@ -164,7 +167,7 @@ Persists and retrieves quality analysis results. Analysis is performed by agents
164
167
  // For 'details' operation
165
168
  runId: {
166
169
  type: 'string',
167
- description: 'Run ID to get details for (required for details)',
170
+ description: 'Run ID (required for details, assemble-run; optional for run-analysers to reuse Phase 1 directory)',
168
171
  },
169
172
  // For 'compare' operation
170
173
  baseRunId: {
@@ -244,14 +247,16 @@ Persists and retrieves quality analysis results. Analysis is performed by agents
244
247
  return await QualityTool.handlePlan(validatedArgs, service);
245
248
  case 'plan-details':
246
249
  return await QualityTool.handlePlanDetails(validatedArgs, context.repositoryRoot);
247
- case 'detect-analyzers':
250
+ case 'detect-analysers':
248
251
  return await QualityTool.handleDetectAnalyzers(context.repositoryRoot);
249
- case 'run-analyzers':
250
- return await QualityTool.handleRunAnalyzers(context.repositoryRoot);
252
+ case 'run-analysers':
253
+ return await QualityTool.handleRunAnalyzers(validatedArgs, context.repositoryRoot);
251
254
  case 'merge-results':
252
255
  return QualityTool.handleMergeResults(validatedArgs);
253
256
  case 'assemble-run':
254
257
  return await QualityTool.handleAssembleRun(validatedArgs, context.repositoryRoot);
258
+ case 'implement-plan':
259
+ return await QualityTool.handleImplementPlan(validatedArgs, service);
255
260
  default:
256
261
  return createErrorResult(`Unknown operation: ${validatedArgs.operation}`);
257
262
  }
@@ -527,8 +532,8 @@ Persists and retrieves quality analysis results. Analysis is performed by agents
527
532
  lines.push(JSON.stringify(analyzers, null, 2));
528
533
  return createSuccessResult(lines.join('\n'));
529
534
  }
530
- static async handleRunAnalyzers(repositoryRoot) {
531
- const runId = generateRunId();
535
+ static async handleRunAnalyzers(args, repositoryRoot) {
536
+ const runId = args.runId ?? generateRunId();
532
537
  const runDir = path.join(repositoryRoot, 'docs', 'quality', 'runs', runIdToPath(runId));
533
538
  const outputPath = path.join(runDir, 'analysis.json');
534
539
  const outputDir = path.join(runDir, 'analysers');
@@ -576,6 +581,10 @@ Persists and retrieves quality analysis results. Analysis is performed by agents
576
581
  `🔍 Issues: ${result.issueCount}`,
577
582
  `📁 File: ${result.filePath}`,
578
583
  ];
584
+ if (result.planId) {
585
+ lines.push(`📋 Plan: ${result.planId}`);
586
+ lines.push(`📁 Plan File: ${result.planFilePath}`);
587
+ }
579
588
  if (result.incremental) {
580
589
  lines.push('');
581
590
  lines.push('### Incremental Analysis');
@@ -598,6 +607,43 @@ Persists and retrieves quality analysis results. Analysis is performed by agents
598
607
  }
599
608
  return createSuccessResult(lines.join('\n'));
600
609
  }
610
+ static async handleImplementPlan(args, service) {
611
+ if (!args.planId) {
612
+ return createErrorResult('planId is required for implement-plan operation');
613
+ }
614
+ const plan = await service.loadImprovementPlan(args.planId);
615
+ if (!plan) {
616
+ return createErrorResult(`Improvement plan not found: ${args.planId}`);
617
+ }
618
+ const run = await service.getRunDetails(plan.sourceRunId);
619
+ if (!run) {
620
+ return createErrorResult(`Source quality run not found: ${plan.sourceRunId}`);
621
+ }
622
+ const fixIds = await service.generateFixesFromPlan(plan, run.issues);
623
+ if (fixIds.length === 0) {
624
+ return createSuccessResult('No initiatives found in plan. No fix documents created.');
625
+ }
626
+ const lines = [
627
+ `Created ${fixIds.length} fix document(s) from Quality Improvement Plan ${args.planId}`,
628
+ '',
629
+ '## Fixes Created',
630
+ '',
631
+ '| Fix ID | File |',
632
+ '|--------|------|',
633
+ ];
634
+ for (const fixId of fixIds) {
635
+ lines.push(`| ${fixId} | .tiny-brain/fixes/${fixId}.md |`);
636
+ }
637
+ lines.push('');
638
+ lines.push('## Next Steps');
639
+ lines.push('');
640
+ for (const fixId of fixIds) {
641
+ lines.push(`1. Run \`npx tiny-brain sync-file .tiny-brain/fixes/${fixId}.md\``);
642
+ }
643
+ lines.push('2. Start working on fixes using the /fix workflow');
644
+ lines.push('3. Track progress in the dashboard');
645
+ return createSuccessResult(lines.join('\n'));
646
+ }
601
647
  static handleMergeResults(args) {
602
648
  const analyzerIssues = args.analyzerIssues ?? [];
603
649
  const llmIssues = args.llmIssues ?? [];
@@ -1 +1 @@
1
- {"version":3,"file":"tool-registry.d.ts","sourceRoot":"","sources":["../../src/tools/tool-registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH,OAAO,KAAK,EAAE,IAAI,IAAI,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,qBAAa,YAAY;IACvB;;OAEG;IACH,MAAM,CAAC,QAAQ,IAAI,OAAO,EAAE;IAoC5B;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;CAmB9D;AAGD,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,8BAAqC,CAAC;AAChF,eAAO,MAAM,eAAe,gBAAyD,CAAC"}
1
+ {"version":3,"file":"tool-registry.d.ts","sourceRoot":"","sources":["../../src/tools/tool-registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAeH,OAAO,KAAK,EAAE,IAAI,IAAI,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,qBAAa,YAAY;IACvB;;OAEG;IACH,MAAM,CAAC,QAAQ,IAAI,OAAO,EAAE;IAuC5B;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;CAoB9D;AAGD,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,8BAAqC,CAAC;AAChF,eAAO,MAAM,eAAe,gBAAyD,CAAC"}
@@ -15,6 +15,7 @@ import { StrategyTool } from './strategy/strategy.tool.js';
15
15
  import { AnalyseTool } from './analyse.tool.js';
16
16
  import { QualityTool } from './quality/quality.tool.js';
17
17
  import { ConfigTool } from './config/config.tool.js';
18
+ import { DashboardTool } from './dashboard/dashboard.tool.js';
18
19
  export class ToolRegistry {
19
20
  /**
20
21
  * Get all available tool definitions from all tools
@@ -36,6 +37,8 @@ export class ToolRegistry {
36
37
  QualityTool.getToolDefinition(),
37
38
  // Config tool - manages preferences with reactive agent sync
38
39
  ConfigTool.getToolDefinition(),
40
+ // Dashboard tool - restart dashboard server (dev maintenance)
41
+ DashboardTool.getToolDefinition(),
39
42
  // Response tools (disabled for later release)
40
43
  // AnalyseRequestTool.getToolDefinition(),
41
44
  // ValidateResponseTool.getToolDefinition(),
@@ -63,6 +66,7 @@ export class ToolRegistry {
63
66
  update: UpdateTool,
64
67
  quality: QualityTool,
65
68
  config: ConfigTool,
69
+ dev_restart_dashboard: DashboardTool,
66
70
  };
67
71
  return toolMap[name];
68
72
  }
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import type { RequestContext } from '@magic-ingredients/tiny-brain-core';
7
7
  import type { AuthToken } from '../services/remote/auth-token-service.js';
8
+ import type { DashboardLauncher } from '../services/dashboard-launcher.service.js';
8
9
  export interface LocalRequestContext extends RequestContext {
9
10
  authToken?: AuthToken;
10
11
  config?: {
@@ -13,5 +14,6 @@ export interface LocalRequestContext extends RequestContext {
13
14
  clientSecret?: string;
14
15
  };
15
16
  };
17
+ dashboardLauncher?: DashboardLauncher;
16
18
  }
17
19
  //# sourceMappingURL=local-context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"local-context.d.ts","sourceRoot":"","sources":["../../src/types/local-context.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0CAA0C,CAAC;AAE1E,MAAM,WAAW,mBAAoB,SAAQ,cAAc;IAEzD,SAAS,CAAC,EAAE,SAAS,CAAC;IAGtB,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE;YACR,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,YAAY,CAAC,EAAE,MAAM,CAAC;SACvB,CAAC;KACH,CAAC;CACH"}
1
+ {"version":3,"file":"local-context.d.ts","sourceRoot":"","sources":["../../src/types/local-context.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0CAA0C,CAAC;AAC1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2CAA2C,CAAC;AAEnF,MAAM,WAAW,mBAAoB,SAAQ,cAAc;IAEzD,SAAS,CAAC,EAAE,SAAS,CAAC;IAGtB,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE;YACR,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,YAAY,CAAC,EAAE,MAAM,CAAC;SACvB,CAAC;KACH,CAAC;IAGF,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magic-ingredients/tiny-brain-local",
3
- "version": "0.19.1",
3
+ "version": "0.20.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.19.1",
34
+ "@magic-ingredients/tiny-brain-core": "^0.20.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",