mstro-app 0.4.29 → 0.4.32

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.
Files changed (66) hide show
  1. package/dist/server/cli/headless/haiku-assessments.d.ts.map +1 -1
  2. package/dist/server/cli/headless/haiku-assessments.js +20 -28
  3. package/dist/server/cli/headless/haiku-assessments.js.map +1 -1
  4. package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
  5. package/dist/server/cli/headless/stall-assessor.js +17 -3
  6. package/dist/server/cli/headless/stall-assessor.js.map +1 -1
  7. package/dist/server/cli/prompt-builders.d.ts.map +1 -1
  8. package/dist/server/cli/prompt-builders.js +35 -19
  9. package/dist/server/cli/prompt-builders.js.map +1 -1
  10. package/dist/server/mcp/bouncer-haiku.d.ts.map +1 -1
  11. package/dist/server/mcp/bouncer-haiku.js +5 -30
  12. package/dist/server/mcp/bouncer-haiku.js.map +1 -1
  13. package/dist/server/mcp/security-analysis.d.ts.map +1 -1
  14. package/dist/server/mcp/security-analysis.js +19 -11
  15. package/dist/server/mcp/security-analysis.js.map +1 -1
  16. package/dist/server/services/deploy/headless-session-handler.d.ts.map +1 -1
  17. package/dist/server/services/deploy/headless-session-handler.js +61 -69
  18. package/dist/server/services/deploy/headless-session-handler.js.map +1 -1
  19. package/dist/server/services/pathUtils.d.ts.map +1 -1
  20. package/dist/server/services/pathUtils.js +46 -38
  21. package/dist/server/services/pathUtils.js.map +1 -1
  22. package/dist/server/services/plan/agent-loader.d.ts +20 -4
  23. package/dist/server/services/plan/agent-loader.d.ts.map +1 -1
  24. package/dist/server/services/plan/agent-loader.js +85 -16
  25. package/dist/server/services/plan/agent-loader.js.map +1 -1
  26. package/dist/server/services/plan/issue-retry.d.ts +0 -8
  27. package/dist/server/services/plan/issue-retry.d.ts.map +1 -1
  28. package/dist/server/services/plan/issue-retry.js +72 -63
  29. package/dist/server/services/plan/issue-retry.js.map +1 -1
  30. package/dist/server/services/plan/review-gate.js +16 -88
  31. package/dist/server/services/plan/review-gate.js.map +1 -1
  32. package/dist/server/services/websocket/git-handlers.d.ts.map +1 -1
  33. package/dist/server/services/websocket/git-handlers.js +6 -19
  34. package/dist/server/services/websocket/git-handlers.js.map +1 -1
  35. package/dist/server/services/websocket/git-pr-handlers.d.ts.map +1 -1
  36. package/dist/server/services/websocket/git-pr-handlers.js +5 -21
  37. package/dist/server/services/websocket/git-pr-handlers.js.map +1 -1
  38. package/dist/server/services/websocket/handlers/deploy-handlers.d.ts.map +1 -1
  39. package/dist/server/services/websocket/handlers/deploy-handlers.js +28 -33
  40. package/dist/server/services/websocket/handlers/deploy-handlers.js.map +1 -1
  41. package/dist/server/services/websocket/plan-board-handlers.d.ts.map +1 -1
  42. package/dist/server/services/websocket/plan-board-handlers.js +31 -25
  43. package/dist/server/services/websocket/plan-board-handlers.js.map +1 -1
  44. package/dist/server/services/websocket/quality-fix-agent.d.ts.map +1 -1
  45. package/dist/server/services/websocket/quality-fix-agent.js +11 -18
  46. package/dist/server/services/websocket/quality-fix-agent.js.map +1 -1
  47. package/dist/server/services/websocket/quality-review-agent.d.ts.map +1 -1
  48. package/dist/server/services/websocket/quality-review-agent.js +13 -150
  49. package/dist/server/services/websocket/quality-review-agent.js.map +1 -1
  50. package/package.json +1 -1
  51. package/server/cli/headless/haiku-assessments.ts +21 -28
  52. package/server/cli/headless/stall-assessor.ts +17 -3
  53. package/server/cli/prompt-builders.ts +34 -23
  54. package/server/mcp/bouncer-haiku.ts +5 -30
  55. package/server/mcp/security-analysis.ts +19 -12
  56. package/server/services/deploy/headless-session-handler.ts +75 -76
  57. package/server/services/pathUtils.ts +55 -42
  58. package/server/services/plan/agent-loader.ts +88 -15
  59. package/server/services/plan/issue-retry.ts +93 -68
  60. package/server/services/plan/review-gate.ts +13 -89
  61. package/server/services/websocket/git-handlers.ts +6 -18
  62. package/server/services/websocket/git-pr-handlers.ts +5 -20
  63. package/server/services/websocket/handlers/deploy-handlers.ts +34 -37
  64. package/server/services/websocket/plan-board-handlers.ts +36 -21
  65. package/server/services/websocket/quality-fix-agent.ts +10 -17
  66. package/server/services/websocket/quality-review-agent.ts +12 -149
@@ -68,6 +68,57 @@ function composePrompt(systemPrompt, userPrompt) {
68
68
  userPrompt,
69
69
  ].join('\n');
70
70
  }
71
+ // ========== Validation ==========
72
+ /** Validate request fields and deployment config. Returns an error or null if valid. */
73
+ function validateRequest(request, config) {
74
+ if (!request.prompt || request.prompt.trim().length === 0) {
75
+ return { code: 'INVALID_REQUEST', message: 'prompt is required and must not be empty.' };
76
+ }
77
+ if (!request.endUserId || request.endUserId.trim().length === 0) {
78
+ return { code: 'INVALID_REQUEST', message: 'endUserId is required.' };
79
+ }
80
+ if (!config.aiEnabled) {
81
+ return { code: 'AI_DISABLED', message: 'AI features are not enabled for this deployment.' };
82
+ }
83
+ if (!config.allowedAiCapabilities.includes('headless')) {
84
+ return {
85
+ code: 'CAPABILITY_DENIED',
86
+ message: "This deployment does not have the 'headless' AI capability enabled.",
87
+ };
88
+ }
89
+ return null;
90
+ }
91
+ /** Check estimated input tokens against the per-request cap. Returns an error or null. */
92
+ function checkTokenLimit(promptLength, maxTokensPerRequest) {
93
+ if (maxTokensPerRequest === null)
94
+ return null;
95
+ const estimatedInputTokens = Math.ceil(promptLength / 4);
96
+ if (estimatedInputTokens > maxTokensPerRequest) {
97
+ return {
98
+ code: 'RATE_LIMIT_EXCEEDED',
99
+ message: `Estimated input tokens (${estimatedInputTokens}) exceeds maxTokensPerRequest (${maxTokensPerRequest}). Shorten your prompt.`,
100
+ };
101
+ }
102
+ return null;
103
+ }
104
+ /** Emit health update and usage report callbacks after execution. */
105
+ function emitPostExecutionCallbacks(result, config, request, effectiveModel, callbacks) {
106
+ callbacks?.onUsageReport?.({
107
+ deploymentId: config.deploymentId,
108
+ endUserId: request.endUserId,
109
+ capability: 'headless',
110
+ tokensUsed: result.totalTokens,
111
+ model: effectiveModel,
112
+ durationMs: result.durationMs,
113
+ });
114
+ const healthStatus = detectAiHealthIssue(result.error);
115
+ if (healthStatus) {
116
+ callbacks?.onHealthUpdate?.({
117
+ deploymentId: config.deploymentId,
118
+ ...healthStatus,
119
+ });
120
+ }
121
+ }
71
122
  // ========== Handler ==========
72
123
  /**
73
124
  * Handle a headless session request for an end user.
@@ -80,55 +131,17 @@ function composePrompt(systemPrompt, userPrompt) {
80
131
  */
81
132
  export async function handleHeadlessSession(request, config, callbacks) {
82
133
  // ── Validate request ───────────────────────────────────────
83
- if (!request.prompt || request.prompt.trim().length === 0) {
84
- return {
85
- ok: false,
86
- error: { code: 'INVALID_REQUEST', message: 'prompt is required and must not be empty.' },
87
- };
88
- }
89
- if (!request.endUserId || request.endUserId.trim().length === 0) {
90
- return {
91
- ok: false,
92
- error: { code: 'INVALID_REQUEST', message: 'endUserId is required.' },
93
- };
94
- }
95
- // ── Validate AI is enabled ─────────────────────────────────
96
- if (!config.aiEnabled) {
97
- return {
98
- ok: false,
99
- error: { code: 'AI_DISABLED', message: 'AI features are not enabled for this deployment.' },
100
- };
101
- }
102
- // ── Validate headless capability ───────────────────────────
103
- if (!config.allowedAiCapabilities.includes('headless')) {
104
- return {
105
- ok: false,
106
- error: {
107
- code: 'CAPABILITY_DENIED',
108
- message: "This deployment does not have the 'headless' AI capability enabled.",
109
- },
110
- };
111
- }
134
+ const validationError = validateRequest(request, config);
135
+ if (validationError)
136
+ return { ok: false, error: validationError };
112
137
  // ── Rate limit checks ─────────────────────────────────────
113
138
  const rateLimitError = checkRateLimit(config);
114
- if (rateLimitError) {
139
+ if (rateLimitError)
115
140
  return { ok: false, error: rateLimitError };
116
- }
117
141
  // ── Token limit pre-check ─────────────────────────────────
118
- // Estimate input tokens from prompt length (~4 chars per token).
119
- // Reject if estimated input alone exceeds the cap.
120
- if (config.maxTokensPerRequest !== null) {
121
- const estimatedInputTokens = Math.ceil(request.prompt.length / 4);
122
- if (estimatedInputTokens > config.maxTokensPerRequest) {
123
- return {
124
- ok: false,
125
- error: {
126
- code: 'RATE_LIMIT_EXCEEDED',
127
- message: `Estimated input tokens (${estimatedInputTokens}) exceeds maxTokensPerRequest (${config.maxTokensPerRequest}). Shorten your prompt.`,
128
- },
129
- };
130
- }
131
- }
142
+ const tokenError = checkTokenLimit(request.prompt.length, config.maxTokensPerRequest);
143
+ if (tokenError)
144
+ return { ok: false, error: tokenError };
132
145
  // ── Compose prompt ─────────────────────────────────────────
133
146
  // Use per-request system prompt if provided, otherwise deployment default
134
147
  const effectiveSystemPrompt = request.systemPrompt ?? config.defaultSystemPrompt;
@@ -154,30 +167,9 @@ export async function handleHeadlessSession(request, config, callbacks) {
154
167
  ? invertAllowedTools(request.allowedTools)
155
168
  : undefined,
156
169
  });
157
- // Check token limit if configured
158
- if (config.maxTokensPerRequest !== null &&
159
- result.totalTokens > config.maxTokensPerRequest) {
160
- // Session already ran — log but don't fail the response.
161
- // The token overage is informational; the developer can use this
162
- // for billing or to tighten limits.
163
- }
164
- // Emit usage report after successful execution
165
- callbacks?.onUsageReport?.({
166
- deploymentId: config.deploymentId,
167
- endUserId: request.endUserId,
168
- capability: 'headless',
169
- tokensUsed: result.totalTokens,
170
- model: effectiveModel,
171
- durationMs: result.durationMs,
172
- });
173
- // Check for API key health issues from execution result
174
- const healthStatus = detectAiHealthIssue(result.error);
175
- if (healthStatus) {
176
- callbacks?.onHealthUpdate?.({
177
- deploymentId: config.deploymentId,
178
- ...healthStatus,
179
- });
180
- }
170
+ // Token overage is informational — session already ran, don't fail the response.
171
+ // The developer can use usage reports for billing or to tighten limits.
172
+ emitPostExecutionCallbacks(result, config, request, effectiveModel, callbacks);
181
173
  return { ok: true, result };
182
174
  }
183
175
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"headless-session-handler.js","sourceRoot":"","sources":["../../../../server/services/deploy/headless-session-handler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"headless-session-handler.js","sourceRoot":"","sources":["../../../../server/services/deploy/headless-session-handler.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"pathUtils.d.ts","sourceRoot":"","sources":["../../../server/services/pathUtils.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,oBAAoB,CAqFtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,iCAAiC,CAC/C,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB;IACD,KAAK,EAAE,OAAO,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CA0BA;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEhF;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAS/D"}
1
+ {"version":3,"file":"pathUtils.d.ts","sourceRoot":"","sources":["../../../server/services/pathUtils.ts"],"names":[],"mappings":"AA6DA,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,oBAAoB,CAkDtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,iCAAiC,CAC/C,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB;IACD,KAAK,EAAE,OAAO,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CA0BA;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEhF;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAS/D"}
@@ -8,6 +8,44 @@
8
8
  */
9
9
  import { existsSync, lstatSync, realpathSync } from 'node:fs';
10
10
  import { dirname, isAbsolute, normalize, relative, resolve } from 'node:path';
11
+ /** Append a trailing separator to a directory path if not already present. */
12
+ function ensureTrailingSep(dir) {
13
+ return dir.endsWith('/') ? dir : `${dir}/`;
14
+ }
15
+ /** Resolve symlinks for an existing path. Returns the real path if it's a symlink. */
16
+ function resolveExistingSymlink(resolvedPath) {
17
+ const stat = lstatSync(resolvedPath);
18
+ if (stat.isSymbolicLink()) {
19
+ return realpathSync(resolvedPath);
20
+ }
21
+ return resolvedPath;
22
+ }
23
+ /**
24
+ * Validate that the parent directory of a non-existent path hasn't escaped
25
+ * the working directory via symlink. Returns an error result or null if valid.
26
+ */
27
+ function validateParentSymlink(resolvedPath, normalizedWorkingDir, targetPath) {
28
+ const parentDir = dirname(resolvedPath);
29
+ if (!existsSync(parentDir))
30
+ return null;
31
+ const realParent = realpathSync(parentDir);
32
+ const parentWithSep = ensureTrailingSep(normalizedWorkingDir);
33
+ if (realParent !== normalizedWorkingDir && !realParent.startsWith(parentWithSep)) {
34
+ console.error(`[PathUtils] SECURITY: Symlink traversal in parent directory blocked. ` +
35
+ `Target: "${targetPath}", RealParent: "${realParent}", WorkingDir: "${normalizedWorkingDir}"`);
36
+ return {
37
+ valid: false,
38
+ resolvedPath: '',
39
+ error: 'Access denied: parent directory resolves outside working directory'
40
+ };
41
+ }
42
+ return null;
43
+ }
44
+ /** Check whether a resolved path is within the working directory boundary. */
45
+ function isPathWithinDir(resolvedPath, normalizedWorkingDir) {
46
+ return resolvedPath === normalizedWorkingDir ||
47
+ resolvedPath.startsWith(ensureTrailingSep(normalizedWorkingDir));
48
+ }
11
49
  /**
12
50
  * Validate that a path is within the allowed working directory.
13
51
  * Prevents path traversal attacks using .. or absolute paths.
@@ -21,54 +59,24 @@ export function validatePathWithinWorkingDir(targetPath, workingDir) {
21
59
  // Normalize the working directory to get canonical path
22
60
  const normalizedWorkingDir = resolve(workingDir);
23
61
  // Resolve the target path relative to working directory
24
- let resolvedPath;
25
- if (isAbsolute(targetPath)) {
26
- resolvedPath = resolve(targetPath);
27
- }
28
- else {
29
- resolvedPath = resolve(normalizedWorkingDir, targetPath);
30
- }
62
+ let resolvedPath = isAbsolute(targetPath)
63
+ ? resolve(targetPath)
64
+ : resolve(normalizedWorkingDir, targetPath);
31
65
  // Normalize to remove any .. or . segments
32
66
  resolvedPath = normalize(resolvedPath);
33
67
  // Resolve symlinks to prevent symlink-based path traversal.
34
68
  // A symlink at /project/link -> /etc/passwd would pass the string
35
69
  // check below but actually read outside the working directory.
36
- // For existing paths: resolve the full path via realpath.
37
- // For new paths (create operations): resolve the parent directory.
38
70
  if (existsSync(resolvedPath)) {
39
- // If the path itself is a symlink, resolve it to the real target
40
- const stat = lstatSync(resolvedPath);
41
- if (stat.isSymbolicLink()) {
42
- resolvedPath = realpathSync(resolvedPath);
43
- }
71
+ resolvedPath = resolveExistingSymlink(resolvedPath);
44
72
  }
45
73
  else {
46
74
  // Path doesn't exist yet (create operation) — validate the parent
47
- const parentDir = dirname(resolvedPath);
48
- if (existsSync(parentDir)) {
49
- const realParent = realpathSync(parentDir);
50
- const parentWithSep = normalizedWorkingDir.endsWith('/')
51
- ? normalizedWorkingDir
52
- : `${normalizedWorkingDir}/`;
53
- if (realParent !== normalizedWorkingDir && !realParent.startsWith(parentWithSep)) {
54
- console.error(`[PathUtils] SECURITY: Symlink traversal in parent directory blocked. ` +
55
- `Target: "${targetPath}", RealParent: "${realParent}", WorkingDir: "${normalizedWorkingDir}"`);
56
- return {
57
- valid: false,
58
- resolvedPath: '',
59
- error: 'Access denied: parent directory resolves outside working directory'
60
- };
61
- }
62
- }
75
+ const parentError = validateParentSymlink(resolvedPath, normalizedWorkingDir, targetPath);
76
+ if (parentError)
77
+ return parentError;
63
78
  }
64
- // Check if the resolved path starts with the working directory
65
- // Add trailing separator to prevent partial matches (e.g., /home/user vs /home/username)
66
- const workingDirWithSep = normalizedWorkingDir.endsWith('/')
67
- ? normalizedWorkingDir
68
- : `${normalizedWorkingDir}/`;
69
- const isWithinWorkingDir = resolvedPath === normalizedWorkingDir ||
70
- resolvedPath.startsWith(workingDirWithSep);
71
- if (!isWithinWorkingDir) {
79
+ if (!isPathWithinDir(resolvedPath, normalizedWorkingDir)) {
72
80
  // Log security violation for monitoring
73
81
  console.error(`[PathUtils] SECURITY: Path traversal attempt blocked. ` +
74
82
  `Target: "${targetPath}", Resolved: "${resolvedPath}", WorkingDir: "${normalizedWorkingDir}"`);
@@ -1 +1 @@
1
- {"version":3,"file":"pathUtils.js","sourceRoot":"","sources":["../../../server/services/pathUtils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pathUtils.js","sourceRoot":"","sources":["../../../server/services/pathUtils.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,26 @@
1
1
  /**
2
2
  * Load an agent prompt by name with layered resolution.
3
3
  *
4
- * @param agentName - The agent file name without extension (e.g., "review-code")
5
- * @param variables - Key-value map for {{variable}} substitution
6
- * @param boardDir - Optional board directory for board-level overrides
4
+ * @param agentName - The agent file name without extension (e.g., "review-code")
5
+ * @param variables - Key-value map for {{variable}} substitution
6
+ * @param boardDir - Optional board directory for board-level overrides
7
+ * @param workingDir - Optional working directory for project-level Skill resolution
7
8
  * @returns The interpolated prompt string, or null if no agent file found
8
9
  */
9
- export declare function loadAgentPrompt(agentName: string, variables: Record<string, string>, boardDir?: string | null): string | null;
10
+ export declare function loadAgentPrompt(agentName: string, variables: Record<string, string>, boardDir?: string | null, workingDir?: string | null): string | null;
11
+ /**
12
+ * Load a Skill template body by name, stripping frontmatter.
13
+ * Looks in {workingDir}/.claude/skills/{skillName}/SKILL.md first,
14
+ * then falls back to the system agents directory.
15
+ *
16
+ * @param skillName - The skill directory name (e.g., "code-review")
17
+ * @param workingDir - Working directory for project-level Skill resolution
18
+ * @returns Raw template body (no frontmatter), or null if not found
19
+ */
20
+ export declare function loadSkillTemplate(skillName: string, workingDir?: string): string | null;
21
+ /**
22
+ * Load a Skill template and interpolate variables.
23
+ * Convenience wrapper combining loadSkillTemplate + interpolation.
24
+ */
25
+ export declare function loadSkillPrompt(skillName: string, variables: Record<string, string>, workingDir?: string): string | null;
10
26
  //# sourceMappingURL=agent-loader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-loader.d.ts","sourceRoot":"","sources":["../../../../server/services/plan/agent-loader.ts"],"names":[],"mappings":"AAoCA;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACjC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GACvB,MAAM,GAAG,IAAI,CAwBf"}
1
+ {"version":3,"file":"agent-loader.d.ts","sourceRoot":"","sources":["../../../../server/services/plan/agent-loader.ts"],"names":[],"mappings":"AAgEA;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACjC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,EACxB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,GACzB,MAAM,GAAG,IAAI,CAoBf;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsBvF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACjC,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,GAAG,IAAI,CAIf"}
@@ -1,11 +1,12 @@
1
1
  // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
2
  // Licensed under the MIT License. See LICENSE file for details.
3
3
  /**
4
- * Agent Prompt Loader — loads review agent prompts from markdown files.
4
+ * Agent Prompt Loader — loads review agent prompts from Skills and markdown files.
5
5
  *
6
6
  * Resolution order (first match wins):
7
7
  * 1. Board-level override: {boardDir}/agents/{agentName}.md
8
- * 2. System default: cli/server/services/plan/agents/{agentName}.md
8
+ * 2. Project Skill: {workingDir}/.claude/skills/{agentName}/SKILL.md
9
+ * 3. System default: cli/server/services/plan/agents/{agentName}.md
9
10
  *
10
11
  * Files use YAML frontmatter + markdown body with {{variable}} placeholders.
11
12
  * Falls back to null when no file is found (caller should use hardcoded fallback).
@@ -30,36 +31,104 @@ function interpolate(template, variables) {
30
31
  return key in variables ? variables[key] : match;
31
32
  });
32
33
  }
34
+ /** Try to load and interpolate a prompt file. Returns null on failure. */
35
+ function tryLoadFile(filePath, variables) {
36
+ if (!existsSync(filePath))
37
+ return null;
38
+ try {
39
+ const raw = readFileSync(filePath, 'utf-8');
40
+ return interpolate(stripFrontmatter(raw), variables);
41
+ }
42
+ catch {
43
+ return null;
44
+ }
45
+ }
46
+ /**
47
+ * Resolve the project root by walking up from a directory looking for `.claude/skills/`.
48
+ * Returns the `.claude/skills/` path if found, or null.
49
+ */
50
+ function findSkillsDir(startDir) {
51
+ let dir = startDir;
52
+ for (let i = 0; i < 10; i++) {
53
+ const candidate = join(dir, '.claude', 'skills');
54
+ if (existsSync(candidate))
55
+ return candidate;
56
+ const parent = dirname(dir);
57
+ if (parent === dir)
58
+ break;
59
+ dir = parent;
60
+ }
61
+ return null;
62
+ }
33
63
  /**
34
64
  * Load an agent prompt by name with layered resolution.
35
65
  *
36
- * @param agentName - The agent file name without extension (e.g., "review-code")
37
- * @param variables - Key-value map for {{variable}} substitution
38
- * @param boardDir - Optional board directory for board-level overrides
66
+ * @param agentName - The agent file name without extension (e.g., "review-code")
67
+ * @param variables - Key-value map for {{variable}} substitution
68
+ * @param boardDir - Optional board directory for board-level overrides
69
+ * @param workingDir - Optional working directory for project-level Skill resolution
39
70
  * @returns The interpolated prompt string, or null if no agent file found
40
71
  */
41
- export function loadAgentPrompt(agentName, variables, boardDir) {
72
+ export function loadAgentPrompt(agentName, variables, boardDir, workingDir) {
42
73
  const fileName = `${agentName}.md`;
43
74
  // 1. Board-level override
44
75
  if (boardDir) {
45
- const boardAgentPath = join(boardDir, 'agents', fileName);
46
- if (existsSync(boardAgentPath)) {
47
- try {
48
- const raw = readFileSync(boardAgentPath, 'utf-8');
49
- return interpolate(stripFrontmatter(raw), variables);
76
+ const result = tryLoadFile(join(boardDir, 'agents', fileName), variables);
77
+ if (result)
78
+ return result;
79
+ }
80
+ // 2. Project Skill: {workingDir}/.claude/skills/{agentName}/SKILL.md
81
+ if (workingDir) {
82
+ const skillsDir = findSkillsDir(workingDir);
83
+ if (skillsDir) {
84
+ const result = tryLoadFile(join(skillsDir, agentName, 'SKILL.md'), variables);
85
+ if (result)
86
+ return result;
87
+ }
88
+ }
89
+ // 3. System default
90
+ return tryLoadFile(join(SYSTEM_AGENTS_DIR, fileName), variables);
91
+ }
92
+ /**
93
+ * Load a Skill template body by name, stripping frontmatter.
94
+ * Looks in {workingDir}/.claude/skills/{skillName}/SKILL.md first,
95
+ * then falls back to the system agents directory.
96
+ *
97
+ * @param skillName - The skill directory name (e.g., "code-review")
98
+ * @param workingDir - Working directory for project-level Skill resolution
99
+ * @returns Raw template body (no frontmatter), or null if not found
100
+ */
101
+ export function loadSkillTemplate(skillName, workingDir) {
102
+ if (workingDir) {
103
+ const skillsDir = findSkillsDir(workingDir);
104
+ if (skillsDir) {
105
+ const path = join(skillsDir, skillName, 'SKILL.md');
106
+ if (existsSync(path)) {
107
+ try {
108
+ return stripFrontmatter(readFileSync(path, 'utf-8'));
109
+ }
110
+ catch { /* fall through */ }
50
111
  }
51
- catch { /* fall through to system default */ }
52
112
  }
53
113
  }
54
- // 2. System default
55
- const systemPath = join(SYSTEM_AGENTS_DIR, fileName);
114
+ // Fallback: system agents directory
115
+ const systemPath = join(SYSTEM_AGENTS_DIR, `${skillName}.md`);
56
116
  if (existsSync(systemPath)) {
57
117
  try {
58
- const raw = readFileSync(systemPath, 'utf-8');
59
- return interpolate(stripFrontmatter(raw), variables);
118
+ return stripFrontmatter(readFileSync(systemPath, 'utf-8'));
60
119
  }
61
120
  catch { /* return null */ }
62
121
  }
63
122
  return null;
64
123
  }
124
+ /**
125
+ * Load a Skill template and interpolate variables.
126
+ * Convenience wrapper combining loadSkillTemplate + interpolation.
127
+ */
128
+ export function loadSkillPrompt(skillName, variables, workingDir) {
129
+ const template = loadSkillTemplate(skillName, workingDir);
130
+ if (!template)
131
+ return null;
132
+ return interpolate(template, variables);
133
+ }
65
134
  //# sourceMappingURL=agent-loader.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-loader.js","sourceRoot":"","sources":["../../../../server/services/plan/agent-loader.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,gEAAgE;AAEhE;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,iBAAiB,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAEpD,mFAAmF;AACnF,SAAS,gBAAgB,CAAC,OAAe;IACvC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACzC,IAAI,MAAM,KAAK,CAAC,CAAC;QAAE,OAAO,OAAO,CAAC;IAClC,OAAO,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;AAC/C,CAAC;AAED,+EAA+E;AAC/E,SAAS,WAAW,CAAC,QAAgB,EAAE,SAAiC;IACtE,OAAO,QAAQ,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,KAAK,EAAE,GAAW,EAAE,EAAE;QAC/D,OAAO,GAAG,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACnD,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC7B,SAAiB,EACjB,SAAiC,EACjC,QAAwB;IAExB,MAAM,QAAQ,GAAG,GAAG,SAAS,KAAK,CAAC;IAEnC,0BAA0B;IAC1B,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC1D,IAAI,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,YAAY,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;gBAClD,OAAO,WAAW,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC;YACvD,CAAC;YAAC,MAAM,CAAC,CAAC,oCAAoC,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,oBAAoB;IACpB,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC;IACrD,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAC9C,OAAO,WAAW,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAC/B,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"agent-loader.js","sourceRoot":"","sources":["../../../../server/services/plan/agent-loader.ts"],"names":[],"mappings":"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"}
@@ -15,13 +15,5 @@ export interface IssueRunnerConfig {
15
15
  /** Signal to abort execution — when aborted, kills the running HeadlessRunner */
16
16
  abortSignal?: AbortSignal;
17
17
  }
18
- /**
19
- * Execute a PM issue with retry logic.
20
- *
21
- * This wraps HeadlessRunner.run() with the same retry strategies as Chat view:
22
- * 1. Tool timeout → checkpoint recovery with accumulated results
23
- * 2. Signal crash → fresh start with preserved tool results
24
- * 3. Premature completion → resume session with "continue"
25
- */
26
18
  export declare function runIssueWithRetry(config: IssueRunnerConfig): Promise<SessionResult>;
27
19
  //# sourceMappingURL=issue-retry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"issue-retry.d.ts","sourceRoot":"","sources":["../../../../server/services/plan/issue-retry.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAuB,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAkCtF,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,0DAA0D;IAC1D,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,iFAAiF;IACjF,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC,CA8FzF"}
1
+ {"version":3,"file":"issue-retry.d.ts","sourceRoot":"","sources":["../../../../server/services/plan/issue-retry.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAuB,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAkCtF,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,0DAA0D;IAC1D,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,iFAAiF;IACjF,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAiGD,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC,CAgCzF"}