@magic-ingredients/tiny-brain-local 0.21.3 → 0.22.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 +3 -5
- package/dist/core/mcp-server.d.ts.map +1 -1
- package/dist/core/mcp-server.js +17 -38
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/prompts/rules/rules.prompt.d.ts.map +1 -1
- package/dist/prompts/rules/rules.prompt.js +1 -7
- package/dist/services/analyse-service.js +1 -1
- package/dist/services/credential-storage.service.d.ts +5 -44
- package/dist/services/credential-storage.service.d.ts.map +1 -1
- package/dist/services/credential-storage.service.js +4 -197
- package/dist/services/remote/auth-token-service.d.ts +10 -47
- package/dist/services/remote/auth-token-service.d.ts.map +1 -1
- package/dist/services/remote/auth-token-service.js +13 -188
- package/dist/services/repo-service.d.ts.map +1 -1
- package/dist/services/repo-service.js +3 -0
- package/dist/tools/config/config.tool.d.ts.map +1 -1
- package/dist/tools/config/config.tool.js +18 -0
- package/dist/tools/persona/as.tool.d.ts +0 -12
- package/dist/tools/persona/as.tool.d.ts.map +1 -1
- package/dist/tools/persona/as.tool.js +13 -199
- package/dist/tools/plan/plan.tool.d.ts.map +1 -1
- package/dist/tools/plan/plan.tool.js +26 -38
- package/dist/tools/quality/quality.tool.js +4 -4
- package/dist/tools/recommendations/recommendations.tool.d.ts.map +1 -1
- package/dist/tools/recommendations/recommendations.tool.js +11 -1
- package/dist/tools/tool-registry.d.ts.map +1 -1
- package/dist/tools/tool-registry.js +0 -4
- package/dist/types/local-context.d.ts +0 -2
- package/dist/types/local-context.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/services/dashboard-launcher.service.d.ts +0 -21
- package/dist/services/dashboard-launcher.service.d.ts.map +0 -1
- package/dist/services/dashboard-launcher.service.js +0 -33
- package/dist/tools/dashboard/dashboard.tool.d.ts +0 -15
- package/dist/tools/dashboard/dashboard.tool.d.ts.map +0 -1
- package/dist/tools/dashboard/dashboard.tool.js +0 -81
|
@@ -1,194 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Auth Token Service
|
|
2
|
+
* Auth Token Service (re-exported from core)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* This module re-exports the core AuthTokenService and adapts
|
|
5
|
+
* it for MCP usage with MCPConfig.
|
|
5
6
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
import { AuthTokenService as CoreAuthTokenService } from '@magic-ingredients/tiny-brain-core';
|
|
8
|
+
/**
|
|
9
|
+
* MCP-specific AuthTokenService that accepts MCPConfig
|
|
10
|
+
* and extracts credentials from config.account
|
|
11
|
+
*/
|
|
12
|
+
export class AuthTokenService extends CoreAuthTokenService {
|
|
12
13
|
constructor(context, config) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
// Debug logging
|
|
18
|
-
this.log('debug', '[AuthTokenService] Constructor initialized', {
|
|
19
|
-
baseUrl: this.baseUrl,
|
|
20
|
-
fromEnv: !!process.env.TBS_URL,
|
|
21
|
-
hasConfig: !!config,
|
|
22
|
-
hasAccountConfig: !!config?.account
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Validate that credentials are properly configured
|
|
27
|
-
*/
|
|
28
|
-
validateCredentials() {
|
|
29
|
-
// Check if config exists
|
|
30
|
-
if (!this.config) {
|
|
31
|
-
return {
|
|
32
|
-
isValid: false,
|
|
33
|
-
error: 'No configuration provided'
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
// Check if account section exists
|
|
37
|
-
if (!this.config.account) {
|
|
38
|
-
return {
|
|
39
|
-
isValid: false,
|
|
40
|
-
error: 'No account configuration found'
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
const { clientId, clientSecret } = this.config.account;
|
|
44
|
-
// Check if clientId exists and is non-empty
|
|
45
|
-
if (!clientId || clientId.trim() === '') {
|
|
46
|
-
return {
|
|
47
|
-
isValid: false,
|
|
48
|
-
error: 'Client ID is missing or empty'
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
// Check if clientSecret exists and is non-empty
|
|
52
|
-
if (!clientSecret || clientSecret.trim() === '') {
|
|
53
|
-
return {
|
|
54
|
-
isValid: false,
|
|
55
|
-
error: 'Client secret is missing or empty'
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
// Valid credentials found
|
|
59
|
-
return {
|
|
60
|
-
isValid: true,
|
|
61
|
-
clientId,
|
|
62
|
-
clientSecret
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Connect to the auth service and obtain a token
|
|
67
|
-
* Assumes credentials have been validated
|
|
68
|
-
*/
|
|
69
|
-
async connectToAuthService(clientId, clientSecret) {
|
|
70
|
-
try {
|
|
71
|
-
this.log('debug', 'Attempting to connect to tiny-brain service', {
|
|
72
|
-
url: this.baseUrl,
|
|
73
|
-
clientId: clientId.substring(0, 4) + '***' // Log partial ID for debugging
|
|
74
|
-
});
|
|
75
|
-
// Create Basic Auth credentials
|
|
76
|
-
const authCredentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
|
|
77
|
-
// Attempt to get auth token from TBS using Basic Auth
|
|
78
|
-
const response = await fetch(`${this.baseUrl}/api/auth/token`, {
|
|
79
|
-
method: 'POST',
|
|
80
|
-
headers: {
|
|
81
|
-
'Authorization': `Basic ${authCredentials}`,
|
|
82
|
-
'Content-Type': 'application/json',
|
|
83
|
-
},
|
|
84
|
-
// Add timeout
|
|
85
|
-
signal: AbortSignal.timeout(10000) // 10 second timeout
|
|
86
|
-
});
|
|
87
|
-
if (!response.ok) {
|
|
88
|
-
this.log('warn', 'Authentication failed', {
|
|
89
|
-
status: response.status,
|
|
90
|
-
statusText: response.statusText
|
|
91
|
-
});
|
|
92
|
-
// Provide specific error messages
|
|
93
|
-
if (response.status === 401) {
|
|
94
|
-
this.log('error', 'Invalid credentials - please check your clientId and clientSecret');
|
|
95
|
-
}
|
|
96
|
-
else if (response.status === 403) {
|
|
97
|
-
this.log('error', 'Access forbidden - your account may be suspended');
|
|
98
|
-
}
|
|
99
|
-
else if (response.status >= 500) {
|
|
100
|
-
this.log('error', 'Tiny-brain service is temporarily unavailable');
|
|
101
|
-
}
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
const tokenData = await response.json();
|
|
105
|
-
// Validate token response
|
|
106
|
-
if (!tokenData.access_token || !tokenData.expires_in) {
|
|
107
|
-
this.log('error', 'Invalid token response from auth service');
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
// Store token with expiry
|
|
111
|
-
this.authToken = {
|
|
112
|
-
token: tokenData.access_token,
|
|
113
|
-
expiresIn: tokenData.expires_in,
|
|
114
|
-
expiresAt: new Date(Date.now() + tokenData.expires_in * 1000)
|
|
115
|
-
};
|
|
116
|
-
this.log('info', 'Successfully authenticated with tiny-brain service', {
|
|
117
|
-
expiresIn: tokenData.expires_in,
|
|
118
|
-
userId: tokenData.user_id
|
|
119
|
-
});
|
|
120
|
-
return this.authToken;
|
|
121
|
-
}
|
|
122
|
-
catch (error) {
|
|
123
|
-
// Handle different error types
|
|
124
|
-
if (error instanceof Error) {
|
|
125
|
-
if (error.name === 'AbortError') {
|
|
126
|
-
this.log('error', 'Connection timeout - tiny-brain service took too long to respond');
|
|
127
|
-
}
|
|
128
|
-
else if (error.message.includes('fetch')) {
|
|
129
|
-
this.log('error', 'Network error - unable to reach tiny-brain service');
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
this.log('error', 'Failed to connect to auth service', error);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
else {
|
|
136
|
-
this.log('error', 'Unknown error during authentication', error);
|
|
137
|
-
}
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Main authentication flow - validate and connect if valid
|
|
143
|
-
*/
|
|
144
|
-
async authenticate() {
|
|
145
|
-
// First validate credentials
|
|
146
|
-
const validation = this.validateCredentials();
|
|
147
|
-
if (!validation.isValid) {
|
|
148
|
-
this.log('info', 'Skipping authentication: ' + validation.error);
|
|
149
|
-
return null;
|
|
150
|
-
}
|
|
151
|
-
// Credentials are valid, attempt to connect
|
|
152
|
-
this.log('info', 'Valid credentials found, attempting authentication');
|
|
153
|
-
// We know these are defined when isValid is true, use type assertion
|
|
154
|
-
return await this.connectToAuthService(validation.clientId, validation.clientSecret);
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* Get auth headers for API requests
|
|
158
|
-
*/
|
|
159
|
-
getAuthHeaders() {
|
|
160
|
-
if (!this.authToken) {
|
|
161
|
-
return null;
|
|
162
|
-
}
|
|
163
|
-
// Check if token is expired
|
|
164
|
-
if (this.authToken.expiresAt && this.authToken.expiresAt < new Date()) {
|
|
165
|
-
this.log('debug', 'Auth token expired');
|
|
166
|
-
this.authToken = null;
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
169
|
-
return {
|
|
170
|
-
'Authorization': `Bearer ${this.authToken.token}`,
|
|
171
|
-
'Content-Type': 'application/json'
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* Check if currently authenticated
|
|
176
|
-
*/
|
|
177
|
-
isAuthenticated() {
|
|
178
|
-
return !!(this.authToken &&
|
|
179
|
-
(!this.authToken.expiresAt || this.authToken.expiresAt > new Date()));
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Clear authentication
|
|
183
|
-
*/
|
|
184
|
-
clearAuth() {
|
|
185
|
-
this.authToken = null;
|
|
186
|
-
this.log('debug', 'Authentication cleared');
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Get current token (for debugging/testing)
|
|
190
|
-
*/
|
|
191
|
-
getToken() {
|
|
192
|
-
return this.authToken;
|
|
14
|
+
const credentials = config?.account
|
|
15
|
+
? { clientId: config.account.clientId, clientSecret: config.account.clientSecret }
|
|
16
|
+
: undefined;
|
|
17
|
+
super(context, credentials);
|
|
193
18
|
}
|
|
194
19
|
}
|
|
@@ -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;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;
|
|
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;IA6ChC;;OAEG;IACH,OAAO,CAAC,6BAA6B;IAiErC;;OAEG;IACH,OAAO,CAAC,0BAA0B;IA6BlC;;OAEG;IACH,OAAO,CAAC,gCAAgC;CAyCzC"}
|
|
@@ -366,6 +366,9 @@ IMPORTANT: This repository follows strict Test-Driven Development (TDD) with a 3
|
|
|
366
366
|
1. **Red Phase** (\`test:\` or \`test(scope):\` commits):
|
|
367
367
|
- **CRITICAL — you MUST run before writing tests:**
|
|
368
368
|
\`npx tiny-brain task-start --task '...' [--fix ID | --prd ID --feature ID]\`
|
|
369
|
+
- For tasks that don't need tests (config, shell scripts, docs, templates), skip RED:
|
|
370
|
+
\`npx tiny-brain task-start --task '...' [--fix ID | --prd ID --feature ID] --phase green\`
|
|
371
|
+
This sets \`testCommitSha: 'skipped'\` and goes straight to Green phase.
|
|
369
372
|
- Write failing tests first
|
|
370
373
|
- Tests SHOULD fail (that's the point!)
|
|
371
374
|
- Use: \`git commit -m "test: ..."\` or \`git commit -m "test(api): ..."\`
|
|
@@ -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;AAUrE,qBAAa,UAAU;IACrB,MAAM,CAAC,iBAAiB,IAAI,OAAO;
|
|
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;WAkEtB,OAAO,CAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,UAAU,CAAC;mBA6BD,UAAU;mBA8CV,SAAS;mBAoCT,iBAAiB;mBAsEjB,SAAS;mBAuDT,WAAW;CAqBjC"}
|
|
@@ -24,10 +24,16 @@ export class ConfigTool {
|
|
|
24
24
|
|
|
25
25
|
📊 PREFERENCES:
|
|
26
26
|
• autoCommitProgress - Auto-commit progress.json changes
|
|
27
|
+
• autoArchive - Auto-archive completed PRDs and resolved fixes during sync
|
|
27
28
|
• enableAgenticCoding - Enable AI-driven development mode
|
|
28
29
|
• enableSDD - Enable Suggestion-Driven Development
|
|
29
30
|
• enableTDD - Enable Test-Driven Development
|
|
31
|
+
• combineRedGreenCommits - Combine red+green into a single feat: commit
|
|
32
|
+
• enableAdversarial - Enable adversarial review phase in TDD pipeline
|
|
30
33
|
• enableADR - Enable Architecture Decision Records
|
|
34
|
+
• enableQuality - Enable Quality Analysis
|
|
35
|
+
• manageAgentsMd - Manage AGENTS.md file during analyse
|
|
36
|
+
• defaultPersona - Default persona to activate at session start
|
|
31
37
|
• docsDirectory - Documentation directory path
|
|
32
38
|
• adrDirectory - ADR directory path
|
|
33
39
|
• prdDirectory - PRD directory path
|
|
@@ -102,10 +108,16 @@ export class ConfigTool {
|
|
|
102
108
|
'',
|
|
103
109
|
'## Feature Flags',
|
|
104
110
|
`- **autoCommitProgress**: ${repo.autoCommitProgress}`,
|
|
111
|
+
`- **autoArchive**: ${repo.autoArchive}`,
|
|
105
112
|
`- **enableAgenticCoding**: ${repo.enableAgenticCoding}`,
|
|
106
113
|
`- **enableSDD**: ${repo.enableSDD}`,
|
|
107
114
|
`- **enableTDD**: ${repo.enableTDD}`,
|
|
115
|
+
`- **combineRedGreenCommits**: ${repo.combineRedGreenCommits}`,
|
|
116
|
+
`- **enableAdversarial**: ${repo.enableAdversarial}`,
|
|
108
117
|
`- **enableADR**: ${repo.enableADR}`,
|
|
118
|
+
`- **enableQuality**: ${repo.enableQuality}`,
|
|
119
|
+
`- **manageAgentsMd**: ${repo.manageAgentsMd}`,
|
|
120
|
+
`- **defaultPersona**: ${repo.defaultPersona}`,
|
|
109
121
|
'',
|
|
110
122
|
'## Directory Paths',
|
|
111
123
|
`- **docsDirectory**: \`${repo.directories.docs}\``,
|
|
@@ -188,10 +200,16 @@ export class ConfigTool {
|
|
|
188
200
|
'',
|
|
189
201
|
'## Feature Flags',
|
|
190
202
|
`- **autoCommitProgress**: ${merged.repo.autoCommitProgress} _(${getSource('autoCommitProgress')})_`,
|
|
203
|
+
`- **autoArchive**: ${merged.repo.autoArchive} _(${getSource('autoArchive')})_`,
|
|
191
204
|
`- **enableAgenticCoding**: ${merged.repo.enableAgenticCoding} _(${getSource('enableAgenticCoding')})_`,
|
|
192
205
|
`- **enableSDD**: ${merged.repo.enableSDD} _(${getSource('enableSDD')})_`,
|
|
193
206
|
`- **enableTDD**: ${merged.repo.enableTDD} _(${getSource('enableTDD')})_`,
|
|
207
|
+
`- **combineRedGreenCommits**: ${merged.repo.combineRedGreenCommits} _(${getSource('combineRedGreenCommits')})_`,
|
|
208
|
+
`- **enableAdversarial**: ${merged.repo.enableAdversarial} _(${getSource('enableAdversarial')})_`,
|
|
194
209
|
`- **enableADR**: ${merged.repo.enableADR} _(${getSource('enableADR')})_`,
|
|
210
|
+
`- **enableQuality**: ${merged.repo.enableQuality} _(${getSource('enableQuality')})_`,
|
|
211
|
+
`- **manageAgentsMd**: ${merged.repo.manageAgentsMd} _(${getSource('manageAgentsMd')})_`,
|
|
212
|
+
`- **defaultPersona**: ${merged.repo.defaultPersona} _(${getSource('defaultPersona')})_`,
|
|
195
213
|
'',
|
|
196
214
|
'## Directory Paths',
|
|
197
215
|
`- **docsDirectory**: \`${merged.repo.directories.docs}\` _(${getDirSource('docs')})_`,
|
|
@@ -37,18 +37,6 @@ export declare class AsTool {
|
|
|
37
37
|
* Check if agents are installed by checking the platform-specific agents directory
|
|
38
38
|
*/
|
|
39
39
|
private static checkHasAgents;
|
|
40
|
-
/**
|
|
41
|
-
* Resolve feature flags from ConfigService
|
|
42
|
-
*/
|
|
43
|
-
private static resolveFeatureFlags;
|
|
44
|
-
/**
|
|
45
|
-
* Build persona response data structure
|
|
46
|
-
*/
|
|
47
|
-
private static buildResponse;
|
|
48
|
-
/**
|
|
49
|
-
* Format the persona response as human-readable markdown with enforced workflow
|
|
50
|
-
*/
|
|
51
|
-
private static formatResponse;
|
|
52
40
|
/**
|
|
53
41
|
* Handle renaming an existing persona
|
|
54
42
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"as.tool.d.ts","sourceRoot":"","sources":["../../../src/tools/persona/as.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACrF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"as.tool.d.ts","sourceRoot":"","sources":["../../../src/tools/persona/as.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACrF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAWrE,OAAO,EAAE,IAAI,IAAI,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAYrE;;;;;;;;;GASG;AACH,qBAAa,MAAM;IACjB,MAAM,CAAC,iBAAiB,IAAI,OAAO;IAqDnC;;OAEG;WACU,OAAO,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC;IA4BvF;;OAEG;mBACkB,wBAAwB;IAsE7C;;OAEG;mBACkB,mBAAmB;IA8ExC;;OAEG;mBACkB,oBAAoB;IAsGzC;;OAEG;mBACkB,eAAe;IAsBpC;;OAEG;mBACkB,cAAc;IAYnC;;OAEG;mBACkB,mBAAmB;mBA4DnB,qBAAqB;CAsC3C"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { createErrorResult } from '../index.js';
|
|
3
|
-
import { createDefaultProfile,
|
|
3
|
+
import { createDefaultProfile, LibraryClient, parsePersonaMarkdown, buildPersonaContext, formatPersonaContext, resolveFeatureFlags, } from '@magic-ingredients/tiny-brain-core';
|
|
4
4
|
import { PersonaService } from '../../services/persona-service.js';
|
|
5
5
|
import { RepoService } from '../../services/repo-service.js';
|
|
6
6
|
import { AgentService } from '../../services/agent-service.js';
|
|
@@ -143,15 +143,15 @@ export class AsTool {
|
|
|
143
143
|
const agentService = new AgentService(context);
|
|
144
144
|
const formatter = agentService.getDefaultFormatter();
|
|
145
145
|
const contextFilePath = formatter.getRepoContextFilePath();
|
|
146
|
-
const response = await
|
|
146
|
+
const response = await buildPersonaContext(context, parsedPersona);
|
|
147
147
|
const [hasAgents, featureFlags] = await Promise.all([
|
|
148
148
|
AsTool.checkHasAgents(context, contextFilePath),
|
|
149
|
-
|
|
149
|
+
resolveFeatureFlags(context),
|
|
150
150
|
]);
|
|
151
151
|
return {
|
|
152
152
|
content: [{
|
|
153
153
|
type: 'text',
|
|
154
|
-
text:
|
|
154
|
+
text: formatPersonaContext(response, contextFilePath, hasAgents, featureFlags, context.libraryAuth),
|
|
155
155
|
}],
|
|
156
156
|
isError: false,
|
|
157
157
|
};
|
|
@@ -200,15 +200,15 @@ export class AsTool {
|
|
|
200
200
|
const contextFilePath = formatter?.getRepoContextFilePath();
|
|
201
201
|
// Activate persona and return response with updated context
|
|
202
202
|
const updatedContext = await AsTool.activatePersona(personaName, profile, context);
|
|
203
|
-
const response = await
|
|
203
|
+
const response = await buildPersonaContext(updatedContext, parsedPersona);
|
|
204
204
|
const [hasAgents, featureFlags] = await Promise.all([
|
|
205
205
|
AsTool.checkHasAgents(updatedContext, contextFilePath),
|
|
206
|
-
|
|
206
|
+
resolveFeatureFlags(updatedContext),
|
|
207
207
|
]);
|
|
208
208
|
return {
|
|
209
209
|
content: [{
|
|
210
210
|
type: 'text',
|
|
211
|
-
text:
|
|
211
|
+
text: formatPersonaContext(response, contextFilePath, hasAgents, featureFlags, updatedContext.libraryAuth),
|
|
212
212
|
}],
|
|
213
213
|
isError: false,
|
|
214
214
|
};
|
|
@@ -282,15 +282,15 @@ export class AsTool {
|
|
|
282
282
|
const formatter = agentService.getDefaultFormatter();
|
|
283
283
|
const contextFilePath = formatter?.getRepoContextFilePath();
|
|
284
284
|
// Step 8: Build and return response
|
|
285
|
-
const response = await
|
|
285
|
+
const response = await buildPersonaContext(updatedContext, parsedPersona);
|
|
286
286
|
const [hasAgents, featureFlags] = await Promise.all([
|
|
287
287
|
AsTool.checkHasAgents(updatedContext, contextFilePath),
|
|
288
|
-
|
|
288
|
+
resolveFeatureFlags(updatedContext),
|
|
289
289
|
]);
|
|
290
290
|
return {
|
|
291
291
|
content: [{
|
|
292
292
|
type: 'text',
|
|
293
|
-
text:
|
|
293
|
+
text: formatPersonaContext(response, contextFilePath, hasAgents, featureFlags, updatedContext.libraryAuth) + needsInitMessage,
|
|
294
294
|
}],
|
|
295
295
|
isError: false,
|
|
296
296
|
};
|
|
@@ -333,192 +333,6 @@ export class AsTool {
|
|
|
333
333
|
return false;
|
|
334
334
|
}
|
|
335
335
|
}
|
|
336
|
-
/**
|
|
337
|
-
* Resolve feature flags from ConfigService
|
|
338
|
-
*/
|
|
339
|
-
static async resolveFeatureFlags(context) {
|
|
340
|
-
try {
|
|
341
|
-
const configService = new ConfigService(context);
|
|
342
|
-
const [sddEnabled, tddEnabled, adrEnabled, agenticCodingEnabled] = await Promise.all([
|
|
343
|
-
configService.isSDDEnabled(),
|
|
344
|
-
configService.isTDDEnabled(),
|
|
345
|
-
configService.isADREnabled(),
|
|
346
|
-
configService.isAgenticCodingEnabled(),
|
|
347
|
-
]);
|
|
348
|
-
return { sddEnabled, tddEnabled, adrEnabled, agenticCodingEnabled };
|
|
349
|
-
}
|
|
350
|
-
catch {
|
|
351
|
-
return { sddEnabled: false, tddEnabled: false, adrEnabled: false, agenticCodingEnabled: false };
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
/**
|
|
355
|
-
* Build persona response data structure
|
|
356
|
-
*/
|
|
357
|
-
static async buildResponse(context, parsedPersona, _contextFilePath // Used in formatResponse, not here
|
|
358
|
-
) {
|
|
359
|
-
const rulesService = new RulesService(context);
|
|
360
|
-
const planningService = new PlanningService(context);
|
|
361
|
-
// Get additional rules from rules service
|
|
362
|
-
const allRules = await rulesService.getAllRules(parsedPersona.name);
|
|
363
|
-
const additionalUserRules = allRules?.rules || [];
|
|
364
|
-
// Get active plan if any
|
|
365
|
-
let activePlan = null;
|
|
366
|
-
try {
|
|
367
|
-
activePlan = await planningService.getActivePlan();
|
|
368
|
-
}
|
|
369
|
-
catch {
|
|
370
|
-
context.logger.debug('No active persona for plan lookup');
|
|
371
|
-
}
|
|
372
|
-
// Note: contextFilePath is passed but not used here since we removed AGENT USAGE INSTRUCTIONS
|
|
373
|
-
// It's used later in formatResponse to add the reminder to re-read CLAUDE.md
|
|
374
|
-
const response = {
|
|
375
|
-
PERSONA: {
|
|
376
|
-
name: parsedPersona.name,
|
|
377
|
-
"GOLDEN RULES": additionalUserRules,
|
|
378
|
-
"USER RULES": parsedPersona.user?.rules || [],
|
|
379
|
-
"USER DETAILS": parsedPersona.user?.details || {},
|
|
380
|
-
"SYSTEM RULES": parsedPersona.system?.rules || [],
|
|
381
|
-
"SYSTEM DETAILS": parsedPersona.system?.details || {}
|
|
382
|
-
}
|
|
383
|
-
};
|
|
384
|
-
if (activePlan) {
|
|
385
|
-
// Extract just the first line or a short summary of the plan
|
|
386
|
-
let goalSummary = '';
|
|
387
|
-
if (activePlan.overview) {
|
|
388
|
-
const lines = activePlan.overview.split('\n').filter(l => l.trim());
|
|
389
|
-
goalSummary = lines[0] || activePlan.title;
|
|
390
|
-
// Truncate if still too long
|
|
391
|
-
if (goalSummary.length > 200) {
|
|
392
|
-
goalSummary = goalSummary.substring(0, 197) + '...';
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
else {
|
|
396
|
-
goalSummary = activePlan.title;
|
|
397
|
-
}
|
|
398
|
-
response.ACTIVE_PLAN = {
|
|
399
|
-
id: activePlan.id,
|
|
400
|
-
title: activePlan.title,
|
|
401
|
-
goal: goalSummary,
|
|
402
|
-
current_phase: activePlan.currentState?.featureTitle || '',
|
|
403
|
-
next_actions: activePlan.currentState?.nextAction ? [activePlan.currentState.nextAction.description] : [],
|
|
404
|
-
blockers: activePlan.metadata?.blockers?.map((b) => b.description)
|
|
405
|
-
};
|
|
406
|
-
}
|
|
407
|
-
return response;
|
|
408
|
-
}
|
|
409
|
-
/**
|
|
410
|
-
* Format the persona response as human-readable markdown with enforced workflow
|
|
411
|
-
*/
|
|
412
|
-
static formatResponse(response, contextFilePath, hasAgents, featureFlags, libraryAuth) {
|
|
413
|
-
let formatted = `# THIS IS YOUR CONTEXT FOR THIS SESSION - YOU MUST USE IT\n\n`;
|
|
414
|
-
formatted += `IMPORTANT: USER RULES and USER DETAILS ALWAYS take precedence over SYSTEM RULES and SYSTEM DETAILS. When there are conflicts, follow the user's preferences.\n\n`;
|
|
415
|
-
formatted += `## PERSONA: ${response.PERSONA.name}\n\n`;
|
|
416
|
-
// Golden Rules
|
|
417
|
-
if (response.PERSONA["GOLDEN RULES"] && response.PERSONA["GOLDEN RULES"].length > 0) {
|
|
418
|
-
formatted += `### GOLDEN RULES\n`;
|
|
419
|
-
response.PERSONA["GOLDEN RULES"].forEach(rule => {
|
|
420
|
-
formatted += `- ${rule}\n`;
|
|
421
|
-
});
|
|
422
|
-
formatted += '\n';
|
|
423
|
-
}
|
|
424
|
-
// User Rules
|
|
425
|
-
if (response.PERSONA["USER RULES"] && response.PERSONA["USER RULES"].length > 0) {
|
|
426
|
-
formatted += `### USER RULES\n`;
|
|
427
|
-
response.PERSONA["USER RULES"].forEach(rule => {
|
|
428
|
-
formatted += `- ${rule}\n`;
|
|
429
|
-
});
|
|
430
|
-
formatted += '\n';
|
|
431
|
-
}
|
|
432
|
-
// User Details
|
|
433
|
-
const userDetails = response.PERSONA["USER DETAILS"];
|
|
434
|
-
if (userDetails && Object.keys(userDetails).length > 0) {
|
|
435
|
-
formatted += `### USER DETAILS\n`;
|
|
436
|
-
Object.entries(userDetails).forEach(([key, value]) => {
|
|
437
|
-
formatted += `#### ${key}\n${value}\n\n`;
|
|
438
|
-
});
|
|
439
|
-
}
|
|
440
|
-
// System Rules
|
|
441
|
-
if (response.PERSONA["SYSTEM RULES"] && response.PERSONA["SYSTEM RULES"].length > 0) {
|
|
442
|
-
formatted += `### SYSTEM RULES\n`;
|
|
443
|
-
response.PERSONA["SYSTEM RULES"].forEach(rule => {
|
|
444
|
-
formatted += `- ${rule}\n`;
|
|
445
|
-
});
|
|
446
|
-
formatted += '\n';
|
|
447
|
-
}
|
|
448
|
-
// System Details
|
|
449
|
-
const systemDetails = response.PERSONA["SYSTEM DETAILS"];
|
|
450
|
-
if (systemDetails && Object.keys(systemDetails).length > 0) {
|
|
451
|
-
formatted += `### SYSTEM DETAILS\n`;
|
|
452
|
-
Object.entries(systemDetails).forEach(([key, value]) => {
|
|
453
|
-
formatted += `#### ${key}\n${value}\n\n`;
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
|
-
// Active Plan - Keep it concise
|
|
457
|
-
if (response.ACTIVE_PLAN) {
|
|
458
|
-
formatted += `### ACTIVE PLAN\n`;
|
|
459
|
-
formatted += `**${response.ACTIVE_PLAN.title}**\n`;
|
|
460
|
-
if (response.ACTIVE_PLAN.goal && response.ACTIVE_PLAN.goal !== response.ACTIVE_PLAN.title) {
|
|
461
|
-
formatted += `${response.ACTIVE_PLAN.goal}\n`;
|
|
462
|
-
}
|
|
463
|
-
formatted += `\n`;
|
|
464
|
-
formatted += `- Current Phase: ${response.ACTIVE_PLAN.current_phase || 'Not specified'}\n`;
|
|
465
|
-
if (response.ACTIVE_PLAN.next_actions && response.ACTIVE_PLAN.next_actions.length > 0) {
|
|
466
|
-
formatted += `- Next Action: ${response.ACTIVE_PLAN.next_actions[0]}\n`;
|
|
467
|
-
}
|
|
468
|
-
if (response.ACTIVE_PLAN.blockers && response.ACTIVE_PLAN.blockers.length > 0) {
|
|
469
|
-
formatted += `- Blockers: ${response.ACTIVE_PLAN.blockers.length} active\n`;
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
// REFLECTION REQUIREMENT
|
|
473
|
-
formatted += `\n## 🔍 MANDATORY REFLECTION - AFTER EVERY TOOL USE\n\n`;
|
|
474
|
-
formatted += `After using ANY tool, you MUST ask yourself:\n`;
|
|
475
|
-
formatted += `- Was this the right phase for this action?\n`;
|
|
476
|
-
formatted += `- Should I have used a specialized agent instead?\n`;
|
|
477
|
-
formatted += `- Am I following the checklist workflow?\n`;
|
|
478
|
-
formatted += `- Does this align with the user's actual request?\n\n`;
|
|
479
|
-
// Add reminder to re-read context file if in a repo with agents installed
|
|
480
|
-
if (contextFilePath) {
|
|
481
|
-
formatted += `---\n\n`;
|
|
482
|
-
formatted += `**⚡ AGENT ORCHESTRATION REQUIRED**\n\n`;
|
|
483
|
-
formatted += `**RE-READ ${contextFilePath} to understand available agents for this repository.**\n`;
|
|
484
|
-
formatted += `**DEFAULT BEHAVIOR**: Use Task tool with specialized agents\n`;
|
|
485
|
-
formatted += `**EXCEPTION**: Only skip agents if you can explicitly justify why none apply\n\n`;
|
|
486
|
-
formatted += `**MANDATORY CONFIRMATION:** When ready to proceed, you MUST respond with exactly this format (copy it exactly, do not modify):\n\n`;
|
|
487
|
-
formatted += `\`\`\`\n`;
|
|
488
|
-
formatted += ` 🧠 tiny brain\n\n`;
|
|
489
|
-
formatted += ` ✅ Received context for persona\n`;
|
|
490
|
-
formatted += ` ✅ Re-read ${contextFilePath}\n`;
|
|
491
|
-
if (featureFlags?.sddEnabled) {
|
|
492
|
-
formatted += ` ✅ Enabled Spec Driven Design workflow with Test Driven Development\n`;
|
|
493
|
-
}
|
|
494
|
-
if (featureFlags?.adrEnabled) {
|
|
495
|
-
formatted += ` ✅ Enabled Architecture Decision Records\n`;
|
|
496
|
-
}
|
|
497
|
-
if (featureFlags?.agenticCodingEnabled) {
|
|
498
|
-
formatted += ` ✅ Enabled agentic coding\n`;
|
|
499
|
-
}
|
|
500
|
-
if (libraryAuth?.token) {
|
|
501
|
-
formatted += ` 🔑 Connected to Tiny Brain Remote\n`;
|
|
502
|
-
}
|
|
503
|
-
if (libraryAuth?.hasClaudeCli) {
|
|
504
|
-
formatted += ` 🤖 Claude CLI authenticated\n`;
|
|
505
|
-
}
|
|
506
|
-
// Only show pre-flight and agent-first workflow if agents are installed
|
|
507
|
-
if (hasAgents) {
|
|
508
|
-
formatted += ` ✅ Completed pre-flight checklist\n`;
|
|
509
|
-
formatted += ` ✅ Ready for agent-first workflow\n`;
|
|
510
|
-
}
|
|
511
|
-
formatted += `\`\`\`\n\n`;
|
|
512
|
-
formatted += `I've switched to your **${response.PERSONA.name}** persona.\n\n`;
|
|
513
|
-
formatted += `🧠 Dashboard available at: [http://localhost:8765](http://localhost:8765)\n`;
|
|
514
|
-
}
|
|
515
|
-
else {
|
|
516
|
-
// Add persona switch confirmation message when no context file
|
|
517
|
-
formatted += `I've switched to your **${response.PERSONA.name}** persona.\n\n`;
|
|
518
|
-
formatted += `🧠 Dashboard available at: [http://localhost:8765](http://localhost:8765)\n`;
|
|
519
|
-
}
|
|
520
|
-
return formatted;
|
|
521
|
-
}
|
|
522
336
|
/**
|
|
523
337
|
* Handle renaming an existing persona
|
|
524
338
|
*/
|
|
@@ -546,15 +360,15 @@ export class AsTool {
|
|
|
546
360
|
const updatedContext = await AsTool.activatePersona(newName, profile, context);
|
|
547
361
|
context.logger.info(`Renamed persona '${oldName}' to '${newName}'`);
|
|
548
362
|
// Return response showing the renamed persona is now active with updated context
|
|
549
|
-
const response = await
|
|
363
|
+
const response = await buildPersonaContext(updatedContext, parsedPersona);
|
|
550
364
|
const [hasAgents, featureFlags] = await Promise.all([
|
|
551
365
|
AsTool.checkHasAgents(updatedContext, contextFilePath),
|
|
552
|
-
|
|
366
|
+
resolveFeatureFlags(updatedContext),
|
|
553
367
|
]);
|
|
554
368
|
return {
|
|
555
369
|
content: [{
|
|
556
370
|
type: 'text',
|
|
557
|
-
text:
|
|
371
|
+
text: formatPersonaContext(response, contextFilePath, hasAgents, featureFlags, updatedContext.libraryAuth),
|
|
558
372
|
}],
|
|
559
373
|
isError: false,
|
|
560
374
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.tool.d.ts","sourceRoot":"","sources":["../../../src/tools/plan/plan.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;AAsLrE,qBAAa,QAAQ;IACnB,MAAM,CAAC,iBAAiB,IAAI,OAAO;WAgLtB,OAAO,CAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,UAAU,CAAC;mBAyED,YAAY;mBA+LZ,aAAa;mBAyCb,eAAe;mBA0Df,YAAY;mBA+CZ,YAAY;mBAsDZ,YAAY;mBAiCZ,UAAU;mBA2DV,oBAAoB;
|
|
1
|
+
{"version":3,"file":"plan.tool.d.ts","sourceRoot":"","sources":["../../../src/tools/plan/plan.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;AAsLrE,qBAAa,QAAQ;IACnB,MAAM,CAAC,iBAAiB,IAAI,OAAO;WAgLtB,OAAO,CAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,UAAU,CAAC;mBAyED,YAAY;mBA+LZ,aAAa;mBAyCb,eAAe;mBA0Df,YAAY;mBA+CZ,YAAY;mBAsDZ,YAAY;mBAiCZ,UAAU;mBA2DV,oBAAoB;mBAsBpB,mBAAmB;mBAkBnB,qBAAqB;mBA4CrB,SAAS;mBAgGT,eAAe;IAuFpC;;OAEG;mBACkB,UAAU;CA2DhC"}
|