@magic-ingredients/tiny-brain-local 0.20.0 ā 0.21.0
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/core/mcp-server.d.ts.map +1 -1
- package/dist/core/mcp-server.js +12 -8
- package/dist/core/repo-registration.d.ts +30 -0
- package/dist/core/repo-registration.d.ts.map +1 -0
- package/dist/core/repo-registration.js +34 -0
- package/dist/prompts/persona/persona.prompt.js +1 -1
- package/dist/prompts/planning/planning.prompt.d.ts +0 -8
- package/dist/prompts/planning/planning.prompt.d.ts.map +1 -1
- package/dist/prompts/planning/planning.prompt.js +0 -193
- package/dist/prompts/prompt-registry.d.ts.map +1 -1
- package/dist/prompts/prompt-registry.js +0 -2
- package/dist/services/analyse-service.d.ts +15 -29
- package/dist/services/analyse-service.d.ts.map +1 -1
- package/dist/services/analyse-service.js +99 -236
- package/dist/services/dashboard-launcher.service.d.ts +1 -0
- package/dist/services/dashboard-launcher.service.d.ts.map +1 -1
- package/dist/services/dashboard-launcher.service.js +4 -0
- package/dist/services/repo-service.d.ts +5 -0
- package/dist/services/repo-service.d.ts.map +1 -1
- package/dist/services/repo-service.js +67 -42
- package/dist/storage/local-filesystem-adapter.d.ts.map +1 -1
- package/dist/storage/local-filesystem-adapter.js +0 -3
- package/dist/tools/dashboard/dashboard.tool.d.ts +15 -0
- package/dist/tools/dashboard/dashboard.tool.d.ts.map +1 -0
- package/dist/tools/dashboard/dashboard.tool.js +81 -0
- package/dist/tools/plan/plan.tool.d.ts +0 -1
- package/dist/tools/plan/plan.tool.d.ts.map +1 -1
- package/dist/tools/plan/plan.tool.js +10 -56
- package/dist/tools/quality/quality.tool.js +1 -1
- package/dist/tools/recommendations/recommendations.tool.d.ts +13 -0
- package/dist/tools/recommendations/recommendations.tool.d.ts.map +1 -0
- package/dist/tools/recommendations/recommendations.tool.js +178 -0
- package/dist/tools/tool-registry.d.ts.map +1 -1
- package/dist/tools/tool-registry.js +8 -0
- package/dist/types/local-context.d.ts +2 -0
- package/dist/types/local-context.d.ts.map +1 -1
- package/package.json +4 -10
|
@@ -4,12 +4,12 @@
|
|
|
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, AgentsMdService, } from '@magic-ingredients/tiny-brain-core';
|
|
7
|
+
import { analyseRepository, formatTechStackChanges, detectTechStackChanges, ConfigService, ConfigSetupService, RepoConfigService, LibraryClient, TechContextService, AgentsMdService, RecommendationService, } 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';
|
|
11
11
|
import { existsSync } from 'fs';
|
|
12
|
-
import {
|
|
12
|
+
import { readFile, readdir, writeFile } from 'fs/promises';
|
|
13
13
|
import { getPackageVersion } from '../utils/package-version.js';
|
|
14
14
|
/**
|
|
15
15
|
* Service for managing repository analysis
|
|
@@ -21,12 +21,14 @@ export class AnalyseService {
|
|
|
21
21
|
libraryClient;
|
|
22
22
|
configService;
|
|
23
23
|
techContextService;
|
|
24
|
+
recommendationService;
|
|
24
25
|
constructor(context) {
|
|
25
26
|
this.context = context;
|
|
26
27
|
this.configService = new ConfigService(context);
|
|
27
28
|
this.repoService = new RepoService(context);
|
|
28
29
|
this.libraryClient = new LibraryClient();
|
|
29
30
|
this.techContextService = new TechContextService(process.cwd());
|
|
31
|
+
this.recommendationService = new RecommendationService(process.cwd());
|
|
30
32
|
}
|
|
31
33
|
/**
|
|
32
34
|
* Perform repository analysis with unified behavior for initialized/uninitialized repos
|
|
@@ -38,15 +40,14 @@ export class AnalyseService {
|
|
|
38
40
|
this.context.logger.info(`Repository analysis complete: ${currentAnalysis.languages.join(', ')}`);
|
|
39
41
|
// Register repository in dashboard
|
|
40
42
|
await this.registerRepository();
|
|
41
|
-
//
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
const gitHooksInstalled =
|
|
48
|
-
|
|
49
|
-
const skillPermissionsAdded = await this.injectSkillPermissions();
|
|
43
|
+
// Perform config setup (directories, hooks, permissions, CLAUDE.md)
|
|
44
|
+
const configSetupResult = await this.performConfigSetup();
|
|
45
|
+
const prdInitialized = configSetupResult?.prdInitialized ?? false;
|
|
46
|
+
const adrInitialized = configSetupResult?.adrInitialized ?? false;
|
|
47
|
+
const qualityInitialized = configSetupResult?.qualityInitialized ?? false;
|
|
48
|
+
const fixesInitialized = configSetupResult?.fixesInitialized ?? false;
|
|
49
|
+
const gitHooksInstalled = configSetupResult?.gitHooksInstalled ?? false;
|
|
50
|
+
const skillPermissionsAdded = configSetupResult?.skillPermissionsAdded ?? [];
|
|
50
51
|
// Check if stack has changed using hash-based comparison
|
|
51
52
|
const analysisInput = {
|
|
52
53
|
languages: currentAnalysis.languages,
|
|
@@ -80,6 +81,11 @@ export class AnalyseService {
|
|
|
80
81
|
if (!dryRun) {
|
|
81
82
|
writtenTechContexts = await this.fetchAndWriteTechContexts(currentAnalysis);
|
|
82
83
|
}
|
|
84
|
+
// Fetch and write recommendations from TBR
|
|
85
|
+
let recommendations = [];
|
|
86
|
+
if (!dryRun) {
|
|
87
|
+
recommendations = await this.fetchAndWriteRecommendations(currentAnalysis);
|
|
88
|
+
}
|
|
83
89
|
// Get enableAgenticCoding preference and sync tech agents
|
|
84
90
|
// When enabled, copies tech contexts from .tiny-brain/tech/ to .claude/agents/
|
|
85
91
|
const enableAgentic = await this.configService.isAgenticCodingEnabled();
|
|
@@ -92,10 +98,6 @@ export class AnalyseService {
|
|
|
92
98
|
if (!dryRun && manageAgentsMd) {
|
|
93
99
|
agentsMdStatus = await this.generateAgentsMd(currentAnalysis);
|
|
94
100
|
}
|
|
95
|
-
// Write workflow sections to CLAUDE.md based on config flags (SDD, TDD)
|
|
96
|
-
if (!dryRun) {
|
|
97
|
-
await this.repoService.writeWorkflowSections({ contextPath });
|
|
98
|
-
}
|
|
99
101
|
// Check context block version (for backwards compatibility during migration)
|
|
100
102
|
const currentVersion = getPackageVersion();
|
|
101
103
|
const existingContent = await this.repoService.readRepoBlockFromContextFile(contextPath);
|
|
@@ -120,6 +122,7 @@ export class AnalyseService {
|
|
|
120
122
|
skillPermissionsAdded: skillPermissionsAdded.length > 0 ? skillPermissionsAdded : undefined,
|
|
121
123
|
writtenTechContexts,
|
|
122
124
|
agentsMdStatus,
|
|
125
|
+
recommendations,
|
|
123
126
|
};
|
|
124
127
|
}
|
|
125
128
|
if (!stackChanged) {
|
|
@@ -141,6 +144,7 @@ export class AnalyseService {
|
|
|
141
144
|
skillPermissionsAdded: skillPermissionsAdded.length > 0 ? skillPermissionsAdded : undefined,
|
|
142
145
|
writtenTechContexts,
|
|
143
146
|
agentsMdStatus,
|
|
147
|
+
recommendations,
|
|
144
148
|
};
|
|
145
149
|
}
|
|
146
150
|
// Changes detected - compute diff for display purposes
|
|
@@ -180,6 +184,7 @@ export class AnalyseService {
|
|
|
180
184
|
skillPermissionsAdded: skillPermissionsAdded.length > 0 ? skillPermissionsAdded : undefined,
|
|
181
185
|
writtenTechContexts,
|
|
182
186
|
agentsMdStatus,
|
|
187
|
+
recommendations,
|
|
183
188
|
};
|
|
184
189
|
}
|
|
185
190
|
/**
|
|
@@ -319,239 +324,52 @@ export class AnalyseService {
|
|
|
319
324
|
}
|
|
320
325
|
}
|
|
321
326
|
/**
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
|
|
325
|
-
async initializePrdDirectory() {
|
|
326
|
-
try {
|
|
327
|
-
const enableSDD = await this.configService.isSDDEnabled();
|
|
328
|
-
if (!enableSDD) {
|
|
329
|
-
this.context.logger.debug('SDD disabled, skipping PRD directory initialization');
|
|
330
|
-
return false;
|
|
331
|
-
}
|
|
332
|
-
const repoRoot = process.cwd();
|
|
333
|
-
const prdDir = join(repoRoot, 'docs', 'prd');
|
|
334
|
-
if (existsSync(prdDir)) {
|
|
335
|
-
return false; // Already exists
|
|
336
|
-
}
|
|
337
|
-
await mkdir(prdDir, { recursive: true });
|
|
338
|
-
this.context.logger.info('ā
Created docs/prd/ directory');
|
|
339
|
-
return true;
|
|
340
|
-
}
|
|
341
|
-
catch (error) {
|
|
342
|
-
this.context.logger.warn(`Failed to initialize PRD directory: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
343
|
-
return false;
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* Initialize ADR directory structure
|
|
348
|
-
* @returns true if directory was created
|
|
327
|
+
* Perform config setup using core ConfigSetupService.
|
|
328
|
+
* Delegates directory initialization, git hooks, skill permissions, and CLAUDE.md
|
|
329
|
+
* context block writing to the shared service.
|
|
349
330
|
*/
|
|
350
|
-
async
|
|
331
|
+
async performConfigSetup() {
|
|
351
332
|
try {
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
return
|
|
365
|
-
}
|
|
366
|
-
catch (error) {
|
|
367
|
-
this.context.logger.warn(`Failed to initialize ADR directory: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
368
|
-
return false;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
|
-
* Initialize Quality directory structure
|
|
373
|
-
* @returns true if directory was created
|
|
374
|
-
*/
|
|
375
|
-
async initializeQualityDirectory() {
|
|
376
|
-
try {
|
|
377
|
-
const enableQuality = await this.configService.isQualityEnabled();
|
|
378
|
-
if (!enableQuality) {
|
|
379
|
-
this.context.logger.debug('Quality disabled, skipping Quality directory initialization');
|
|
380
|
-
return false;
|
|
381
|
-
}
|
|
382
|
-
const repoRoot = process.cwd();
|
|
383
|
-
const qualityDir = join(repoRoot, 'docs', 'quality');
|
|
384
|
-
if (existsSync(qualityDir)) {
|
|
385
|
-
return false; // Already exists
|
|
386
|
-
}
|
|
387
|
-
await mkdir(qualityDir, { recursive: true });
|
|
388
|
-
this.context.logger.info('ā
Created docs/quality/ directory');
|
|
389
|
-
return true;
|
|
390
|
-
}
|
|
391
|
-
catch (error) {
|
|
392
|
-
this.context.logger.warn(`Failed to initialize Quality directory: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
393
|
-
return false;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
/**
|
|
397
|
-
* Initialize fixes tracking directory
|
|
398
|
-
* @returns true if directory was created
|
|
399
|
-
*/
|
|
400
|
-
async initializeFixesDirectory() {
|
|
401
|
-
try {
|
|
402
|
-
const enableSDD = await this.configService.isSDDEnabled();
|
|
403
|
-
if (!enableSDD) {
|
|
404
|
-
this.context.logger.debug('SDD disabled, skipping fixes directory initialization');
|
|
405
|
-
return false;
|
|
406
|
-
}
|
|
407
|
-
const repoRoot = process.cwd();
|
|
408
|
-
const fixesDir = join(repoRoot, '.tiny-brain', 'fixes');
|
|
409
|
-
if (existsSync(fixesDir)) {
|
|
410
|
-
return false; // Already exists
|
|
411
|
-
}
|
|
412
|
-
await mkdir(fixesDir, { recursive: true });
|
|
413
|
-
this.context.logger.info('ā
Created .tiny-brain/fixes/ directory');
|
|
414
|
-
return true;
|
|
333
|
+
const hooksSourceDir = this.resolveHooksDir();
|
|
334
|
+
const version = getPackageVersion();
|
|
335
|
+
const configSetup = new ConfigSetupService({
|
|
336
|
+
repoPath: process.cwd(),
|
|
337
|
+
version,
|
|
338
|
+
hooksSourceDir,
|
|
339
|
+
logger: {
|
|
340
|
+
info: (msg) => this.context.logger.info(msg),
|
|
341
|
+
debug: (msg) => this.context.logger.debug(msg),
|
|
342
|
+
warn: (msg) => this.context.logger.warn(msg),
|
|
343
|
+
},
|
|
344
|
+
});
|
|
345
|
+
return await configSetup.performSetup();
|
|
415
346
|
}
|
|
416
347
|
catch (error) {
|
|
417
|
-
this.context.logger.warn(`
|
|
418
|
-
return
|
|
348
|
+
this.context.logger.warn(`Config setup failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
349
|
+
return undefined;
|
|
419
350
|
}
|
|
420
351
|
}
|
|
421
352
|
/**
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
*
|
|
353
|
+
* Resolve hooks template directory from the core package.
|
|
354
|
+
* Tries the core package's templates first (monorepo layout), then falls back
|
|
355
|
+
* to the MCP package's own templates for backward compatibility.
|
|
425
356
|
*/
|
|
426
|
-
|
|
357
|
+
resolveHooksDir() {
|
|
427
358
|
try {
|
|
428
|
-
const repoRoot = process.cwd();
|
|
429
|
-
const gitHooksDir = join(repoRoot, '.git', 'hooks');
|
|
430
|
-
// Check if .git directory exists (is this a git repo?)
|
|
431
|
-
if (!existsSync(join(repoRoot, '.git'))) {
|
|
432
|
-
this.context.logger.debug('Not a git repository, skipping git hooks initialization');
|
|
433
|
-
return false;
|
|
434
|
-
}
|
|
435
|
-
// Find the source hook templates in the installed package
|
|
436
359
|
const __filename = fileURLToPath(import.meta.url);
|
|
437
360
|
const __dirname = dirname(__filename);
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
if (
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
const hooks = ['commit-msg', 'post-commit', 'pre-commit'];
|
|
448
|
-
let anyInstalled = false;
|
|
449
|
-
for (const hookName of hooks) {
|
|
450
|
-
const srcHook = join(srcHooksDir, hookName);
|
|
451
|
-
const destHook = join(gitHooksDir, hookName);
|
|
452
|
-
// Skip if source doesn't exist
|
|
453
|
-
if (!existsSync(srcHook)) {
|
|
454
|
-
continue;
|
|
455
|
-
}
|
|
456
|
-
// Skip if hook already exists (don't overwrite user customizations)
|
|
457
|
-
if (existsSync(destHook)) {
|
|
458
|
-
// Check if it's our hook by looking for our signature comment
|
|
459
|
-
try {
|
|
460
|
-
const existingContent = await readFile(destHook, 'utf-8');
|
|
461
|
-
if (!existingContent.includes('Installed by: tiny-brain')) {
|
|
462
|
-
this.context.logger.debug(`Skipping ${hookName} - custom hook already exists`);
|
|
463
|
-
continue;
|
|
464
|
-
}
|
|
465
|
-
// Our hook already installed, check if source is newer
|
|
466
|
-
const srcStat = await stat(srcHook);
|
|
467
|
-
const destStat = await stat(destHook);
|
|
468
|
-
if (srcStat.mtime <= destStat.mtime) {
|
|
469
|
-
continue; // Already up to date
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
catch {
|
|
473
|
-
continue; // Can't read, skip
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
// Copy hook
|
|
477
|
-
await copyFile(srcHook, destHook);
|
|
478
|
-
// Make executable (755)
|
|
479
|
-
await chmod(destHook, 0o755);
|
|
480
|
-
anyInstalled = true;
|
|
481
|
-
this.context.logger.info(`ā
Installed git hook: ${hookName}`);
|
|
482
|
-
}
|
|
483
|
-
if (anyInstalled) {
|
|
484
|
-
this.context.logger.info('Git hooks initialized in .git/hooks/');
|
|
485
|
-
}
|
|
486
|
-
return anyInstalled;
|
|
487
|
-
}
|
|
488
|
-
catch (error) {
|
|
489
|
-
this.context.logger.warn(`Failed to initialize git hooks: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
490
|
-
return false;
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
/**
|
|
494
|
-
* Inject skill permissions into .claude/settings.json
|
|
495
|
-
* These permissions allow skills to read/write to specific directories without prompts
|
|
496
|
-
* @returns Array of permissions that were added (empty if none added)
|
|
497
|
-
*/
|
|
498
|
-
async injectSkillPermissions() {
|
|
499
|
-
const SKILL_PERMISSIONS = [
|
|
500
|
-
'Write(.tiny-brain/**)',
|
|
501
|
-
'Write(docs/prd/**)',
|
|
502
|
-
'Write(docs/adr/**)',
|
|
503
|
-
'Write(docs/quality/**)',
|
|
504
|
-
'Read(.tiny-brain/**)',
|
|
505
|
-
'Read(docs/prd/**)',
|
|
506
|
-
'Read(docs/adr/**)',
|
|
507
|
-
'Read(docs/quality/**)',
|
|
508
|
-
'Read(.claude/skills/**/templates/**)',
|
|
509
|
-
];
|
|
510
|
-
try {
|
|
511
|
-
const repoRoot = process.cwd();
|
|
512
|
-
const settingsDir = join(repoRoot, '.claude');
|
|
513
|
-
const settingsPath = join(settingsDir, 'settings.json');
|
|
514
|
-
// Ensure .claude directory exists
|
|
515
|
-
await mkdir(settingsDir, { recursive: true });
|
|
516
|
-
// Read existing settings or start with empty object
|
|
517
|
-
let settings = {};
|
|
518
|
-
if (existsSync(settingsPath)) {
|
|
519
|
-
try {
|
|
520
|
-
const content = await readFile(settingsPath, 'utf-8');
|
|
521
|
-
settings = JSON.parse(content);
|
|
522
|
-
}
|
|
523
|
-
catch {
|
|
524
|
-
this.context.logger.warn('Failed to parse existing settings.json, will create new one');
|
|
525
|
-
settings = {};
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
// Ensure permissions.allow array exists
|
|
529
|
-
if (!settings.permissions) {
|
|
530
|
-
settings.permissions = {};
|
|
531
|
-
}
|
|
532
|
-
const permissions = settings.permissions;
|
|
533
|
-
if (!Array.isArray(permissions.allow)) {
|
|
534
|
-
permissions.allow = [];
|
|
535
|
-
}
|
|
536
|
-
const allowList = permissions.allow;
|
|
537
|
-
// Add missing permissions
|
|
538
|
-
const addedPermissions = [];
|
|
539
|
-
for (const perm of SKILL_PERMISSIONS) {
|
|
540
|
-
if (!allowList.includes(perm)) {
|
|
541
|
-
allowList.push(perm);
|
|
542
|
-
addedPermissions.push(perm);
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
// Only write if we added new permissions
|
|
546
|
-
if (addedPermissions.length > 0) {
|
|
547
|
-
await writeFile(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
|
|
548
|
-
this.context.logger.info(`Added ${addedPermissions.length} skill permissions to .claude/settings.json`);
|
|
549
|
-
}
|
|
550
|
-
return addedPermissions;
|
|
361
|
+
// First try: core package's templates (via monorepo workspace link)
|
|
362
|
+
const coreHooksDir = join(__dirname, '..', '..', '..', 'tiny-brain-core', 'templates', 'hooks');
|
|
363
|
+
if (existsSync(coreHooksDir))
|
|
364
|
+
return coreHooksDir;
|
|
365
|
+
// Second try: the MCP package's own templates (backward compatibility)
|
|
366
|
+
const mcpHooksDir = join(__dirname, '..', '..', 'templates', 'hooks');
|
|
367
|
+
if (existsSync(mcpHooksDir))
|
|
368
|
+
return mcpHooksDir;
|
|
369
|
+
return undefined;
|
|
551
370
|
}
|
|
552
|
-
catch
|
|
553
|
-
|
|
554
|
-
return [];
|
|
371
|
+
catch {
|
|
372
|
+
return undefined;
|
|
555
373
|
}
|
|
556
374
|
}
|
|
557
375
|
/**
|
|
@@ -585,6 +403,30 @@ export class AnalyseService {
|
|
|
585
403
|
return [];
|
|
586
404
|
}
|
|
587
405
|
}
|
|
406
|
+
/**
|
|
407
|
+
* Fetch recommendations from TBR and write them via RecommendationService
|
|
408
|
+
*/
|
|
409
|
+
async fetchAndWriteRecommendations(analysis) {
|
|
410
|
+
try {
|
|
411
|
+
const localContext = this.context;
|
|
412
|
+
if (!localContext.authToken?.token) {
|
|
413
|
+
this.context.logger.debug('No auth token available for recommendations API call');
|
|
414
|
+
return [];
|
|
415
|
+
}
|
|
416
|
+
const response = await this.libraryClient.getRecommendations(analysis, localContext.authToken.token);
|
|
417
|
+
if (!response?.recommendations || response.recommendations.length === 0) {
|
|
418
|
+
this.context.logger.debug('No recommendations returned from TBR');
|
|
419
|
+
return [];
|
|
420
|
+
}
|
|
421
|
+
await this.recommendationService.writeRecommendations(response.recommendations, response.fetchedAt);
|
|
422
|
+
this.context.logger.info(`Fetched ${response.recommendations.length} recommendation(s) from TBR`);
|
|
423
|
+
return response.recommendations;
|
|
424
|
+
}
|
|
425
|
+
catch (error) {
|
|
426
|
+
this.context.logger.warn(`Failed to fetch recommendations from TBR: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
427
|
+
return [];
|
|
428
|
+
}
|
|
429
|
+
}
|
|
588
430
|
/**
|
|
589
431
|
* Format analysis output for display
|
|
590
432
|
*/
|
|
@@ -704,6 +546,27 @@ export class AnalyseService {
|
|
|
704
546
|
: 'Up to date';
|
|
705
547
|
lines.push(`\nAGENTS.md: ${statusLabel}`);
|
|
706
548
|
}
|
|
549
|
+
// Recommendations section (shown when recommendations exist)
|
|
550
|
+
if (result.recommendations && result.recommendations.length > 0) {
|
|
551
|
+
lines.push('\nšÆ Recommendations:');
|
|
552
|
+
const groupLabels = { skill: 'Skills', agent: 'Agents', hook: 'Hooks' };
|
|
553
|
+
const grouped = new Map();
|
|
554
|
+
for (const rec of result.recommendations) {
|
|
555
|
+
const existing = grouped.get(rec.type) ?? [];
|
|
556
|
+
grouped.set(rec.type, [...existing, rec]);
|
|
557
|
+
}
|
|
558
|
+
for (const [type, label] of Object.entries(groupLabels)) {
|
|
559
|
+
const recs = grouped.get(type);
|
|
560
|
+
if (recs && recs.length > 0) {
|
|
561
|
+
lines.push(`\n ${label}:`);
|
|
562
|
+
for (const rec of recs) {
|
|
563
|
+
lines.push(` ⢠${rec.name} ā ${rec.description}`);
|
|
564
|
+
lines.push(` Reason: ${rec.reason}`);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
lines.push('\n Use `recommendations operation=accept` to install');
|
|
569
|
+
}
|
|
707
570
|
return lines.join('\n');
|
|
708
571
|
}
|
|
709
572
|
/**
|
|
@@ -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;
|
|
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"}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import type { RequestContext } from '../types/request-context.js';
|
|
9
9
|
export interface WriteWorkflowSectionsOptions {
|
|
10
10
|
contextPath?: string;
|
|
11
|
+
isMonorepo?: boolean;
|
|
11
12
|
}
|
|
12
13
|
/**
|
|
13
14
|
* Service for repository context operations
|
|
@@ -75,6 +76,10 @@ export declare class RepoService {
|
|
|
75
76
|
* Format the Progress Tracking Auto-Commit Configuration section
|
|
76
77
|
*/
|
|
77
78
|
private formatProgressTrackingSection;
|
|
79
|
+
/**
|
|
80
|
+
* Format the Worktree Merge Workflow section
|
|
81
|
+
*/
|
|
82
|
+
private formatWorktreeMergeSection;
|
|
78
83
|
/**
|
|
79
84
|
* Format the Operational Tracking Directory section
|
|
80
85
|
*/
|
|
@@ -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;
|
|
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;IACrB,UAAU,CAAC,EAAE,OAAO,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;IAkGtF;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IA6BhC;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAgGlC;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA4ChC;;OAEG;IACH,OAAO,CAAC,6BAA6B;IAiErC;;OAEG;IACH,OAAO,CAAC,0BAA0B;IA6BlC;;OAEG;IACH,OAAO,CAAC,gCAAgC;CAyCzC"}
|