mstro-app 0.4.29 → 0.4.33
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/server/cli/headless/haiku-assessments.d.ts.map +1 -1
- package/dist/server/cli/headless/haiku-assessments.js +20 -28
- package/dist/server/cli/headless/haiku-assessments.js.map +1 -1
- package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
- package/dist/server/cli/headless/stall-assessor.js +17 -3
- package/dist/server/cli/headless/stall-assessor.js.map +1 -1
- package/dist/server/cli/improvisation-retry.d.ts.map +1 -1
- package/dist/server/cli/improvisation-retry.js +18 -1
- package/dist/server/cli/improvisation-retry.js.map +1 -1
- package/dist/server/cli/improvisation-session-manager.d.ts +5 -0
- package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
- package/dist/server/cli/improvisation-session-manager.js +41 -1
- package/dist/server/cli/improvisation-session-manager.js.map +1 -1
- package/dist/server/cli/prompt-builders.d.ts.map +1 -1
- package/dist/server/cli/prompt-builders.js +35 -19
- package/dist/server/cli/prompt-builders.js.map +1 -1
- package/dist/server/mcp/bouncer-haiku.d.ts.map +1 -1
- package/dist/server/mcp/bouncer-haiku.js +5 -30
- package/dist/server/mcp/bouncer-haiku.js.map +1 -1
- package/dist/server/mcp/security-analysis.d.ts.map +1 -1
- package/dist/server/mcp/security-analysis.js +19 -11
- package/dist/server/mcp/security-analysis.js.map +1 -1
- package/dist/server/services/deploy/headless-session-handler.d.ts.map +1 -1
- package/dist/server/services/deploy/headless-session-handler.js +61 -69
- package/dist/server/services/deploy/headless-session-handler.js.map +1 -1
- package/dist/server/services/files.d.ts.map +1 -1
- package/dist/server/services/files.js +6 -2
- package/dist/server/services/files.js.map +1 -1
- package/dist/server/services/pathUtils.d.ts.map +1 -1
- package/dist/server/services/pathUtils.js +46 -38
- package/dist/server/services/pathUtils.js.map +1 -1
- package/dist/server/services/plan/agent-loader.d.ts +20 -4
- package/dist/server/services/plan/agent-loader.d.ts.map +1 -1
- package/dist/server/services/plan/agent-loader.js +69 -16
- package/dist/server/services/plan/agent-loader.js.map +1 -1
- package/dist/server/services/plan/issue-retry.d.ts +0 -8
- package/dist/server/services/plan/issue-retry.d.ts.map +1 -1
- package/dist/server/services/plan/issue-retry.js +72 -63
- package/dist/server/services/plan/issue-retry.js.map +1 -1
- package/dist/server/services/plan/review-gate.js +16 -88
- package/dist/server/services/plan/review-gate.js.map +1 -1
- package/dist/server/services/websocket/file-explorer-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/file-explorer-handlers.js +23 -2
- package/dist/server/services/websocket/file-explorer-handlers.js.map +1 -1
- package/dist/server/services/websocket/git-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/git-handlers.js +21 -19
- package/dist/server/services/websocket/git-handlers.js.map +1 -1
- package/dist/server/services/websocket/git-pr-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/git-pr-handlers.js +5 -21
- package/dist/server/services/websocket/git-pr-handlers.js.map +1 -1
- package/dist/server/services/websocket/handler.d.ts +2 -0
- package/dist/server/services/websocket/handler.d.ts.map +1 -1
- package/dist/server/services/websocket/handler.js +36 -18
- package/dist/server/services/websocket/handler.js.map +1 -1
- package/dist/server/services/websocket/handlers/deploy-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/handlers/deploy-handlers.js +28 -33
- package/dist/server/services/websocket/handlers/deploy-handlers.js.map +1 -1
- package/dist/server/services/websocket/plan-board-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/plan-board-handlers.js +31 -25
- package/dist/server/services/websocket/plan-board-handlers.js.map +1 -1
- package/dist/server/services/websocket/quality-fix-agent.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-fix-agent.js +11 -18
- package/dist/server/services/websocket/quality-fix-agent.js.map +1 -1
- package/dist/server/services/websocket/quality-review-agent.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-review-agent.js +13 -150
- package/dist/server/services/websocket/quality-review-agent.js.map +1 -1
- package/dist/server/services/websocket/session-history.d.ts.map +1 -1
- package/dist/server/services/websocket/session-history.js +10 -8
- package/dist/server/services/websocket/session-history.js.map +1 -1
- package/dist/server/services/websocket/skill-handlers.d.ts +4 -0
- package/dist/server/services/websocket/skill-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/skill-handlers.js +93 -0
- package/dist/server/services/websocket/skill-handlers.js.map +1 -0
- package/dist/server/services/websocket/types.d.ts +8 -2
- package/dist/server/services/websocket/types.d.ts.map +1 -1
- package/dist/server/utils/paths.d.ts +4 -0
- package/dist/server/utils/paths.d.ts.map +1 -1
- package/dist/server/utils/paths.js +18 -1
- package/dist/server/utils/paths.js.map +1 -1
- package/package.json +1 -1
- package/server/cli/headless/haiku-assessments.ts +21 -28
- package/server/cli/headless/stall-assessor.ts +17 -3
- package/server/cli/improvisation-retry.ts +19 -1
- package/server/cli/improvisation-session-manager.ts +44 -1
- package/server/cli/prompt-builders.ts +34 -23
- package/server/mcp/bouncer-haiku.ts +5 -30
- package/server/mcp/security-analysis.ts +19 -12
- package/server/services/deploy/headless-session-handler.ts +75 -76
- package/server/services/files.ts +7 -2
- package/server/services/pathUtils.ts +55 -42
- package/server/services/plan/agent-loader.ts +73 -15
- package/server/services/plan/issue-retry.ts +93 -68
- package/server/services/plan/review-gate.ts +13 -89
- package/server/services/websocket/file-explorer-handlers.ts +23 -2
- package/server/services/websocket/git-handlers.ts +23 -18
- package/server/services/websocket/git-pr-handlers.ts +5 -20
- package/server/services/websocket/handler.ts +35 -16
- package/server/services/websocket/handlers/deploy-handlers.ts +34 -37
- package/server/services/websocket/plan-board-handlers.ts +36 -21
- package/server/services/websocket/quality-fix-agent.ts +10 -17
- package/server/services/websocket/quality-review-agent.ts +12 -149
- package/server/services/websocket/session-history.ts +10 -8
- package/server/services/websocket/skill-handlers.ts +90 -0
- package/server/services/websocket/types.ts +13 -2
- package/server/utils/paths.ts +17 -1
|
@@ -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
|
-
|
|
26
|
-
|
|
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
|
-
|
|
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
|
|
48
|
-
if (
|
|
49
|
-
|
|
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
|
-
|
|
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":"AAAA,8DAA8D;AAC9D,gEAAgE;AAEhE;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
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
|
|
5
|
-
* @param variables
|
|
6
|
-
* @param boardDir
|
|
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":"
|
|
1
|
+
{"version":3,"file":"agent-loader.d.ts","sourceRoot":"","sources":["../../../../server/services/plan/agent-loader.ts"],"names":[],"mappings":"AAiDA;;;;;;;;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.
|
|
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).
|
|
@@ -13,6 +14,7 @@
|
|
|
13
14
|
import { existsSync, readFileSync } from 'node:fs';
|
|
14
15
|
import { dirname, join } from 'node:path';
|
|
15
16
|
import { fileURLToPath } from 'node:url';
|
|
17
|
+
import { findSkillsDir } from '../../utils/paths.js';
|
|
16
18
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
17
19
|
const SYSTEM_AGENTS_DIR = join(__dirname, 'agents');
|
|
18
20
|
/** Strip YAML frontmatter (--- ... ---) from markdown, returning just the body. */
|
|
@@ -30,36 +32,87 @@ function interpolate(template, variables) {
|
|
|
30
32
|
return key in variables ? variables[key] : match;
|
|
31
33
|
});
|
|
32
34
|
}
|
|
35
|
+
/** Try to load and interpolate a prompt file. Returns null on failure. */
|
|
36
|
+
function tryLoadFile(filePath, variables) {
|
|
37
|
+
if (!existsSync(filePath))
|
|
38
|
+
return null;
|
|
39
|
+
try {
|
|
40
|
+
const raw = readFileSync(filePath, 'utf-8');
|
|
41
|
+
return interpolate(stripFrontmatter(raw), variables);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
33
47
|
/**
|
|
34
48
|
* Load an agent prompt by name with layered resolution.
|
|
35
49
|
*
|
|
36
|
-
* @param agentName
|
|
37
|
-
* @param variables
|
|
38
|
-
* @param boardDir
|
|
50
|
+
* @param agentName - The agent file name without extension (e.g., "review-code")
|
|
51
|
+
* @param variables - Key-value map for {{variable}} substitution
|
|
52
|
+
* @param boardDir - Optional board directory for board-level overrides
|
|
53
|
+
* @param workingDir - Optional working directory for project-level Skill resolution
|
|
39
54
|
* @returns The interpolated prompt string, or null if no agent file found
|
|
40
55
|
*/
|
|
41
|
-
export function loadAgentPrompt(agentName, variables, boardDir) {
|
|
56
|
+
export function loadAgentPrompt(agentName, variables, boardDir, workingDir) {
|
|
42
57
|
const fileName = `${agentName}.md`;
|
|
43
58
|
// 1. Board-level override
|
|
44
59
|
if (boardDir) {
|
|
45
|
-
const
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
60
|
+
const result = tryLoadFile(join(boardDir, 'agents', fileName), variables);
|
|
61
|
+
if (result)
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
// 2. Project Skill: {workingDir}/.claude/skills/{agentName}/SKILL.md
|
|
65
|
+
if (workingDir) {
|
|
66
|
+
const skillsDir = findSkillsDir(workingDir);
|
|
67
|
+
if (skillsDir) {
|
|
68
|
+
const result = tryLoadFile(join(skillsDir, agentName, 'SKILL.md'), variables);
|
|
69
|
+
if (result)
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// 3. System default
|
|
74
|
+
return tryLoadFile(join(SYSTEM_AGENTS_DIR, fileName), variables);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Load a Skill template body by name, stripping frontmatter.
|
|
78
|
+
* Looks in {workingDir}/.claude/skills/{skillName}/SKILL.md first,
|
|
79
|
+
* then falls back to the system agents directory.
|
|
80
|
+
*
|
|
81
|
+
* @param skillName - The skill directory name (e.g., "code-review")
|
|
82
|
+
* @param workingDir - Working directory for project-level Skill resolution
|
|
83
|
+
* @returns Raw template body (no frontmatter), or null if not found
|
|
84
|
+
*/
|
|
85
|
+
export function loadSkillTemplate(skillName, workingDir) {
|
|
86
|
+
if (workingDir) {
|
|
87
|
+
const skillsDir = findSkillsDir(workingDir);
|
|
88
|
+
if (skillsDir) {
|
|
89
|
+
const path = join(skillsDir, skillName, 'SKILL.md');
|
|
90
|
+
if (existsSync(path)) {
|
|
91
|
+
try {
|
|
92
|
+
return stripFrontmatter(readFileSync(path, 'utf-8'));
|
|
93
|
+
}
|
|
94
|
+
catch { /* fall through */ }
|
|
50
95
|
}
|
|
51
|
-
catch { /* fall through to system default */ }
|
|
52
96
|
}
|
|
53
97
|
}
|
|
54
|
-
//
|
|
55
|
-
const systemPath = join(SYSTEM_AGENTS_DIR,
|
|
98
|
+
// Fallback: system agents directory
|
|
99
|
+
const systemPath = join(SYSTEM_AGENTS_DIR, `${skillName}.md`);
|
|
56
100
|
if (existsSync(systemPath)) {
|
|
57
101
|
try {
|
|
58
|
-
|
|
59
|
-
return interpolate(stripFrontmatter(raw), variables);
|
|
102
|
+
return stripFrontmatter(readFileSync(systemPath, 'utf-8'));
|
|
60
103
|
}
|
|
61
104
|
catch { /* return null */ }
|
|
62
105
|
}
|
|
63
106
|
return null;
|
|
64
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Load a Skill template and interpolate variables.
|
|
110
|
+
* Convenience wrapper combining loadSkillTemplate + interpolation.
|
|
111
|
+
*/
|
|
112
|
+
export function loadSkillPrompt(skillName, variables, workingDir) {
|
|
113
|
+
const template = loadSkillTemplate(skillName, workingDir);
|
|
114
|
+
if (!template)
|
|
115
|
+
return null;
|
|
116
|
+
return interpolate(template, variables);
|
|
117
|
+
}
|
|
65
118
|
//# 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
|
|
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;
|
|
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"}
|
|
@@ -28,6 +28,70 @@ const MAX_ACCUMULATED_RESULTS = 50;
|
|
|
28
28
|
* 2. Signal crash → fresh start with preserved tool results
|
|
29
29
|
* 3. Premature completion → resume session with "continue"
|
|
30
30
|
*/
|
|
31
|
+
/** Build the default "aborted" fallback result. */
|
|
32
|
+
function abortedResult(bestResult) {
|
|
33
|
+
return bestResult ?? {
|
|
34
|
+
completed: false, needsHandoff: false, totalTokens: 0, sessionId: '',
|
|
35
|
+
error: 'Execution stopped by user',
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** Create a HeadlessRunner configured for the current retry iteration. */
|
|
39
|
+
function createRunner(config, state, useResume, resumeSessionId) {
|
|
40
|
+
return new HeadlessRunner({
|
|
41
|
+
workingDir: config.workingDir,
|
|
42
|
+
directPrompt: state.currentPrompt,
|
|
43
|
+
stallWarningMs: config.stallWarningMs,
|
|
44
|
+
stallKillMs: config.stallKillMs,
|
|
45
|
+
stallHardCapMs: config.stallHardCapMs,
|
|
46
|
+
stallMaxExtensions: config.stallMaxExtensions,
|
|
47
|
+
verbose: true,
|
|
48
|
+
continueSession: useResume,
|
|
49
|
+
claudeSessionId: resumeSessionId,
|
|
50
|
+
outputCallback: config.outputCallback,
|
|
51
|
+
onToolTimeout: (cp) => {
|
|
52
|
+
state.checkpoint = cp;
|
|
53
|
+
},
|
|
54
|
+
extraEnv: config.extraEnv,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/** Wire the abort signal to clean up the runner. Returns a cleanup function. */
|
|
58
|
+
function wireAbortSignal(runner, abortSignal) {
|
|
59
|
+
if (!abortSignal)
|
|
60
|
+
return null;
|
|
61
|
+
const abortHandler = () => { runner.cleanup(); };
|
|
62
|
+
abortSignal.addEventListener('abort', abortHandler, { once: true });
|
|
63
|
+
return () => abortSignal.removeEventListener('abort', abortHandler);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Run a single iteration: spawn runner, await result, evaluate retry.
|
|
67
|
+
* Returns { result, shouldRetry } — caller loops while shouldRetry is true.
|
|
68
|
+
* Returns null if aborted (caller should return abortedResult).
|
|
69
|
+
*/
|
|
70
|
+
async function runSingleAttempt(config, state) {
|
|
71
|
+
state.checkpoint = null;
|
|
72
|
+
const useResume = !!state.lastSessionId;
|
|
73
|
+
const resumeSessionId = state.lastSessionId;
|
|
74
|
+
state.lastSessionId = undefined;
|
|
75
|
+
const runner = createRunner(config, state, useResume, resumeSessionId);
|
|
76
|
+
if (config.abortSignal?.aborted) {
|
|
77
|
+
runner.cleanup();
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const removeAbortListener = wireAbortSignal(runner, config.abortSignal);
|
|
81
|
+
const result = await runner.run();
|
|
82
|
+
removeAbortListener?.();
|
|
83
|
+
if (config.abortSignal?.aborted)
|
|
84
|
+
return null;
|
|
85
|
+
// Track best result for fallback selection
|
|
86
|
+
if (!state.bestResult || scoreResult(result) > scoreResult(state.bestResult)) {
|
|
87
|
+
state.bestResult = result;
|
|
88
|
+
}
|
|
89
|
+
// Evaluate retry strategies in priority order
|
|
90
|
+
const shouldRetry = tryToolTimeoutRetry(state, result, config) ||
|
|
91
|
+
trySignalCrashRetry(state, result, config) ||
|
|
92
|
+
await tryPrematureCompletionRetry(state, result, config);
|
|
93
|
+
return { result, shouldRetry };
|
|
94
|
+
}
|
|
31
95
|
export async function runIssueWithRetry(config) {
|
|
32
96
|
const state = {
|
|
33
97
|
currentPrompt: config.prompt,
|
|
@@ -40,70 +104,15 @@ export async function runIssueWithRetry(config) {
|
|
|
40
104
|
};
|
|
41
105
|
let result;
|
|
42
106
|
while (state.retryNumber <= MAX_ISSUE_RETRIES) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
// Clear checkpoint from prior iteration
|
|
51
|
-
state.checkpoint = null;
|
|
52
|
-
// Determine resume strategy
|
|
53
|
-
const useResume = !!state.lastSessionId;
|
|
54
|
-
const resumeSessionId = state.lastSessionId;
|
|
55
|
-
state.lastSessionId = undefined;
|
|
56
|
-
const runner = new HeadlessRunner({
|
|
57
|
-
workingDir: config.workingDir,
|
|
58
|
-
directPrompt: state.currentPrompt,
|
|
59
|
-
stallWarningMs: config.stallWarningMs,
|
|
60
|
-
stallKillMs: config.stallKillMs,
|
|
61
|
-
stallHardCapMs: config.stallHardCapMs,
|
|
62
|
-
stallMaxExtensions: config.stallMaxExtensions,
|
|
63
|
-
verbose: true,
|
|
64
|
-
continueSession: useResume,
|
|
65
|
-
claudeSessionId: resumeSessionId,
|
|
66
|
-
outputCallback: config.outputCallback,
|
|
67
|
-
onToolTimeout: (cp) => {
|
|
68
|
-
state.checkpoint = cp;
|
|
69
|
-
},
|
|
70
|
-
extraEnv: config.extraEnv,
|
|
71
|
-
});
|
|
72
|
-
// Wire abort signal to kill the runner's processes
|
|
73
|
-
const abortHandler = () => { runner.cleanup(); };
|
|
74
|
-
if (config.abortSignal) {
|
|
75
|
-
if (config.abortSignal.aborted) {
|
|
76
|
-
runner.cleanup();
|
|
77
|
-
return state.bestResult ?? {
|
|
78
|
-
completed: false, needsHandoff: false, totalTokens: 0, sessionId: '',
|
|
79
|
-
error: 'Execution stopped by user',
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
config.abortSignal.addEventListener('abort', abortHandler, { once: true });
|
|
83
|
-
}
|
|
84
|
-
result = await runner.run();
|
|
85
|
-
// Clean up abort listener
|
|
86
|
-
config.abortSignal?.removeEventListener('abort', abortHandler);
|
|
87
|
-
// If aborted during run, return immediately
|
|
88
|
-
if (config.abortSignal?.aborted) {
|
|
89
|
-
return state.bestResult ?? result ?? {
|
|
90
|
-
completed: false, needsHandoff: false, totalTokens: 0, sessionId: '',
|
|
91
|
-
error: 'Execution stopped by user',
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
// Track best result for fallback selection
|
|
95
|
-
if (!state.bestResult || scoreResult(result) > scoreResult(state.bestResult)) {
|
|
96
|
-
state.bestResult = result;
|
|
107
|
+
if (config.abortSignal?.aborted)
|
|
108
|
+
return abortedResult(state.bestResult);
|
|
109
|
+
const attempt = await runSingleAttempt(config, state);
|
|
110
|
+
if (!attempt) {
|
|
111
|
+
return state.bestResult ?? result ?? abortedResult(null);
|
|
97
112
|
}
|
|
98
|
-
|
|
99
|
-
if (
|
|
100
|
-
|
|
101
|
-
if (trySignalCrashRetry(state, result, config))
|
|
102
|
-
continue;
|
|
103
|
-
if (await tryPrematureCompletionRetry(state, result, config))
|
|
104
|
-
continue;
|
|
105
|
-
// No retry needed — break out
|
|
106
|
-
break;
|
|
113
|
+
result = attempt.result;
|
|
114
|
+
if (!attempt.shouldRetry)
|
|
115
|
+
break;
|
|
107
116
|
}
|
|
108
117
|
return result ?? state.bestResult ?? {
|
|
109
118
|
completed: false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue-retry.js","sourceRoot":"","sources":["../../../../server/services/plan/issue-retry.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,gEAAgE;AAEhE;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,uCAAuC,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAEjF,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,8BAA8B,GAC/B,MAAM,8BAA8B,CAAC;AAEtC,kGAAkG;AAClG,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAE5B,2DAA2D;AAC3D,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAwCnC;;;;;;;GAOG;AACH,
|
|
1
|
+
{"version":3,"file":"issue-retry.js","sourceRoot":"","sources":["../../../../server/services/plan/issue-retry.ts"],"names":[],"mappings":"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"}
|