@ddtcorex/dsh-maestro-review 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/lib/config-store.d.ts.map +1 -1
  2. package/lib/config-store.js.map +1 -1
  3. package/lib/events.d.ts.map +1 -1
  4. package/lib/events.js.map +1 -1
  5. package/lib/git-worktree-tool.d.ts.map +1 -1
  6. package/lib/git-worktree-tool.js.map +1 -1
  7. package/lib/gitlab-client.d.ts.map +1 -1
  8. package/lib/gitlab-client.js.map +1 -1
  9. package/lib/govard-audit-lint-tool.d.ts.map +1 -1
  10. package/lib/govard-audit-lint-tool.js +42 -12
  11. package/lib/govard-audit-lint-tool.js.map +1 -1
  12. package/lib/govard-tool.d.ts.map +1 -1
  13. package/lib/govard-tool.js.map +1 -1
  14. package/lib/hyva-csp-scan-tool.d.ts.map +1 -1
  15. package/lib/hyva-csp-scan-tool.js.map +1 -1
  16. package/lib/hyva-theme-inspect-tool.d.ts.map +1 -1
  17. package/lib/hyva-theme-inspect-tool.js.map +1 -1
  18. package/lib/incremental.d.ts.map +1 -1
  19. package/lib/incremental.js.map +1 -1
  20. package/lib/index.d.ts.map +1 -1
  21. package/lib/index.js.map +1 -1
  22. package/lib/layout-xml-tool.d.ts.map +1 -1
  23. package/lib/layout-xml-tool.js.map +1 -1
  24. package/lib/module-check-tool.d.ts.map +1 -1
  25. package/lib/module-check-tool.js.map +1 -1
  26. package/lib/notify.d.ts.map +1 -1
  27. package/lib/notify.js.map +1 -1
  28. package/lib/orchestrator.d.ts +1 -0
  29. package/lib/orchestrator.d.ts.map +1 -1
  30. package/lib/orchestrator.js +81 -22
  31. package/lib/orchestrator.js.map +1 -1
  32. package/lib/perf-log-stats-tool.d.ts.map +1 -1
  33. package/lib/perf-log-stats-tool.js.map +1 -1
  34. package/lib/phtml-escape-scan-tool.d.ts.map +1 -1
  35. package/lib/phtml-escape-scan-tool.js.map +1 -1
  36. package/lib/plan-track-tool.d.ts.map +1 -1
  37. package/lib/plan-track-tool.js.map +1 -1
  38. package/lib/providers/github.stub.d.ts.map +1 -1
  39. package/lib/providers/github.stub.js.map +1 -1
  40. package/lib/providers/gitlab.d.ts +1 -1
  41. package/lib/providers/gitlab.d.ts.map +1 -1
  42. package/lib/providers/gitlab.js +24 -28
  43. package/lib/providers/gitlab.js.map +1 -1
  44. package/lib/providers/interface.d.ts.map +1 -1
  45. package/lib/providers/interface.js.map +1 -1
  46. package/lib/review-findings-tool.d.ts.map +1 -1
  47. package/lib/review-findings-tool.js.map +1 -1
  48. package/lib/review-history.d.ts.map +1 -1
  49. package/lib/review-history.js +19 -1
  50. package/lib/review-history.js.map +1 -1
  51. package/lib/review-intake.d.ts.map +1 -1
  52. package/lib/review-intake.js.map +1 -1
  53. package/lib/review-signals.d.ts.map +1 -1
  54. package/lib/review-signals.js.map +1 -1
  55. package/lib/scope-split-tool.d.ts.map +1 -1
  56. package/lib/scope-split-tool.js.map +1 -1
  57. package/lib/search-tool.d.ts.map +1 -1
  58. package/lib/search-tool.js.map +1 -1
  59. package/lib/secure-compare.d.ts.map +1 -1
  60. package/lib/secure-compare.js.map +1 -1
  61. package/lib/settings-rpc.d.ts.map +1 -1
  62. package/lib/settings-rpc.js.map +1 -1
  63. package/lib/skills-tool.d.ts +2 -2
  64. package/lib/skills-tool.d.ts.map +1 -1
  65. package/lib/skills-tool.js +17 -2
  66. package/lib/skills-tool.js.map +1 -1
  67. package/lib/tdd-evidence-tool.d.ts.map +1 -1
  68. package/lib/tdd-evidence-tool.js.map +1 -1
  69. package/lib/tool-policy.d.ts.map +1 -1
  70. package/lib/tool-policy.js.map +1 -1
  71. package/lib/workspace-tool.d.ts.map +1 -1
  72. package/lib/workspace-tool.js.map +1 -1
  73. package/package.json +3 -4
  74. package/src/{augment.d.ts → host/augment.d.ts} +1 -2
  75. package/src/{govard-audit-lint-tool.ts → host/govard-audit-lint-tool.ts} +38 -12
  76. package/src/{orchestrator.ts → host/orchestrator.ts} +73 -21
  77. package/src/{providers → host/providers}/gitlab.ts +26 -74
  78. package/src/{review-history.ts → host/review-history.ts} +19 -1
  79. package/src/{settings-rpc.ts → host/settings-rpc.ts} +1 -1
  80. package/src/{skills-tool.ts → host/skills-tool.ts} +18 -3
  81. package/lib/gitlab-webhook.d.ts +0 -17
  82. package/lib/gitlab-webhook.d.ts.map +0 -1
  83. package/lib/gitlab-webhook.js +0 -144
  84. package/lib/gitlab-webhook.js.map +0 -1
  85. package/src/gitlab-webhook.ts +0 -166
  86. /package/src/{config-store.ts → host/config-store.ts} +0 -0
  87. /package/src/{events.ts → host/events.ts} +0 -0
  88. /package/src/{git-worktree-tool.ts → host/git-worktree-tool.ts} +0 -0
  89. /package/src/{gitlab-client.ts → host/gitlab-client.ts} +0 -0
  90. /package/src/{govard-tool.ts → host/govard-tool.ts} +0 -0
  91. /package/src/{hyva-csp-scan-tool.ts → host/hyva-csp-scan-tool.ts} +0 -0
  92. /package/src/{hyva-theme-inspect-tool.ts → host/hyva-theme-inspect-tool.ts} +0 -0
  93. /package/src/{incremental.ts → host/incremental.ts} +0 -0
  94. /package/src/{index.ts → host/index.ts} +0 -0
  95. /package/src/{layout-xml-tool.ts → host/layout-xml-tool.ts} +0 -0
  96. /package/src/{module-check-tool.ts → host/module-check-tool.ts} +0 -0
  97. /package/src/{notify.ts → host/notify.ts} +0 -0
  98. /package/src/{perf-log-stats-tool.ts → host/perf-log-stats-tool.ts} +0 -0
  99. /package/src/{phtml-escape-scan-tool.ts → host/phtml-escape-scan-tool.ts} +0 -0
  100. /package/src/{plan-track-tool.ts → host/plan-track-tool.ts} +0 -0
  101. /package/src/{providers → host/providers}/github.stub.ts +0 -0
  102. /package/src/{providers → host/providers}/interface.ts +0 -0
  103. /package/src/{review-findings-tool.ts → host/review-findings-tool.ts} +0 -0
  104. /package/src/{review-intake.ts → host/review-intake.ts} +0 -0
  105. /package/src/{review-signals.ts → host/review-signals.ts} +0 -0
  106. /package/src/{scope-split-tool.ts → host/scope-split-tool.ts} +0 -0
  107. /package/src/{search-tool.ts → host/search-tool.ts} +0 -0
  108. /package/src/{secure-compare.ts → host/secure-compare.ts} +0 -0
  109. /package/src/{tdd-evidence-tool.ts → host/tdd-evidence-tool.ts} +0 -0
  110. /package/src/{tool-policy.ts → host/tool-policy.ts} +0 -0
  111. /package/src/{workspace-tool.ts → host/workspace-tool.ts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-tool.js","sourceRoot":"","sources":["../src/workspace-tool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workspace-tool.js","sourceRoot":"","sources":["../src/host/workspace-tool.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ddtcorex/dsh-maestro-review",
3
3
  "private": false,
4
- "version": "0.1.1",
4
+ "version": "0.2.1",
5
5
  "description": "Maestro Review — pluggable ReviewProvider (GitLab/GitHub) + orchestrator for automated MR review",
6
6
  "type": "module",
7
7
  "main": "./lib/index.js",
@@ -20,11 +20,11 @@
20
20
  ],
21
21
  "peerDependencies": {
22
22
  "@deepseek-ai/cordis": "^4.0.1",
23
- "@deepseek-ai/dsh-client-connection": "^0.1.1-rc.2"
23
+ "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.6 || >=0.1.1-rc.0 <0.2.0"
24
24
  },
25
25
  "dependencies": {
26
26
  "@deepseek-ai/schemastery": "^3.0.0",
27
- "@ddtcorex/dsh-maestro-config-lib": "^0.1.1"
27
+ "@ddtcorex/dsh-maestro-config-lib": "^0.1.2"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@deepseek-ai/cordis": "^4.0.1",
@@ -34,7 +34,6 @@
34
34
  "@deepseek-ai/dsh-agent": "0.1.0-rc.8",
35
35
  "@deepseek-ai/dsh-agent-default-model": "0.1.0-rc.8",
36
36
  "@deepseek-ai/dsh-agent-presets": "0.1.0-rc.8",
37
- "@deepseek-ai/dsh-host-apiproxy": "0.1.0-rc.8",
38
37
  "@deepseek-ai/dsh-llm": "0.1.0-rc.8",
39
38
  "@deepseek-ai/dsh-session": "0.1.0-rc.8",
40
39
  "@deepseek-ai/dsh-session-title": "0.1.0-rc.8",
@@ -1,10 +1,9 @@
1
1
  import type { ModelSelection } from '@deepseek-ai/dsh-agent'
2
2
 
3
3
  declare module '@deepseek-ai/dsh-host-webserver' {}
4
- declare module '@deepseek-ai/dsh-client-connection' {}
5
4
  declare module '@deepseek-ai/dsh-client-ui-slots' {}
6
5
  declare module '@deepseek-ai/dsh-client-ui-settings' {}
7
- declare module '@deepseek-ai/dsh-host-apiproxy/api' {
6
+ declare module '@deepseek-ai/dsh-client-connection' {
8
7
  export type RpcResult<T> = { ok: true; value: T } | { ok: false; error: any }
9
8
  export type RpcErrorDetailsMap = { 'bad-request': { issues: any[] } }
10
9
  }
@@ -40,7 +40,9 @@ async function isInsideRoot(r:string,t:string):Promise<boolean>{
40
40
  export function cleanJson(raw:string):string{
41
41
  return raw.replace(/\n\s*ERROR audit run.*$/s, '').replace(/\s{2,}ERROR audit run.*$/s, '').trimEnd()
42
42
  }
43
- const DEFAULT_TIMEOUT=120000
43
+ // Govard 1.67 auto timeout: 90s-30m framework-aware (15m floor for wordpress/magento2 → 22.5m auto)
44
+ // Keep kill timeout above the largest auto value so the outer watchdog doesn't cancel a valid auto run.
45
+ const DEFAULT_TIMEOUT=900_000
44
46
 
45
47
  function run(cmd:string, args:string[], cwd:string, timeoutMs:number):Promise<{code:number|null, stdout:string, stderr:string, timedOut:boolean}>{
46
48
  return new Promise((resolvePromise)=>{
@@ -60,7 +62,7 @@ export function apply(ctx:Context, config:{rootPath?:string, timeoutMs?:number}=
60
62
  const defaultTimeout=config.timeoutMs ?? DEFAULT_TIMEOUT
61
63
  ctx.effect(()=>ctx.tools.register(defineTool({
62
64
  name:'govard_audit_lint',
63
- description:'Run govard audit --checks lint --format json and return structured phpcs/phpstan results. Use before hand-parsing text.',
65
+ description:'Run govard audit --checks lint --format json and return structured phpcs/phpstan results. Use before hand-parsing text. Govard 1.67+ uses --timeout auto (framework-aware 90s-30m, 22.5m for wordpress/magento2) by default.',
64
66
  parameters:{
65
67
  worktreePath:{type:'string'},
66
68
  checks:{type:'array', items:{type:'string'}},
@@ -68,6 +70,11 @@ export function apply(ctx:Context, config:{rootPath?:string, timeoutMs?:number}=
68
70
  phpVersions:{type:'array', items:{type:'string'}},
69
71
  noLintResultCache:{type:'boolean'},
70
72
  timeoutMs:{type:'number'},
73
+ // New in 1.67/2.7: framework-aware timeout and native lint provider
74
+ timeout:{type:'string', description:'Govard --timeout (e.g. auto, 300s, 15m, 0 for no timeout). Default auto.'},
75
+ lintProvider:{type:'string', description:'--lint-provider (govard or external). Default govard.'},
76
+ scope:{type:'string', enum:['project','diff']},
77
+ base:{type:'string', description:'--base ref for diff scope'},
71
78
  },
72
79
  output:{
73
80
  schema:{
@@ -80,6 +87,10 @@ export function apply(ctx:Context, config:{rootPath?:string, timeoutMs?:number}=
80
87
  lint:{type:'object', required:true, additionalProperties:true},
81
88
  summary:{type:'object', required:true, additionalProperties:true},
82
89
  rawJson:{type:'object', required:true, additionalProperties:true},
90
+ errors:{type:'array', items:{type:'object', additionalProperties:true}},
91
+ diagnostics:{type:'string'},
92
+ sessionId:{type:'string'},
93
+ runId:{type:'string'},
83
94
  }
84
95
  },
85
96
  render:(_a,v:{ok:boolean})=>[{type:'text', text: v.ok? 'audit lint passed':'audit lint failed'}],
@@ -91,15 +102,28 @@ export function apply(ctx:Context, config:{rootPath?:string, timeoutMs?:number}=
91
102
  const checkPath= rawPath ?? ''
92
103
  if(checkPath!=='' && !(await isInsideRoot(root, checkPath))) return {text:`Path "${checkPath}" escapes the workspace root.`, truncated:false} as never
93
104
  const timeoutMs=(args as {timeoutMs?:number}).timeoutMs ?? defaultTimeout
94
- if(timeoutMs<5000 || timeoutMs>300000) return {text:'timeoutMs out of range 5000-300000', truncated:false} as never
105
+ if(timeoutMs<5000 || timeoutMs>1_800_000) return {text:'timeoutMs out of range 5000-1800000 (5s-30m). Use --timeout auto for framework-aware estimation.', truncated:false} as never
95
106
 
96
- const cliArgs=['audit','run','--checks','lint','--format','json']
107
+ const a = args as {checks?:string[]; mode?:string; scope?:string; base?:string; phpVersions?:string[]; noLintResultCache?:boolean; timeout?:string; lintProvider?:string}
108
+ const checks = a.checks && a.checks.length ? a.checks.join(',') : 'lint'
109
+ const mode = a.mode ?? 'auto'
110
+ const scope = a.scope
111
+ const base = a.base
112
+ const phpVersionsArg = a.phpVersions
113
+ const noLintResultCache = a.noLintResultCache
114
+ const timeout = a.timeout ?? 'auto'
115
+ const lintProvider = a.lintProvider ?? 'govard'
116
+ const cliArgs=['audit','run','--checks',checks,'--format','json','--mode',mode,'--timeout',timeout,'--lint-provider',lintProvider]
117
+ if(scope) cliArgs.push('--scope', scope)
118
+ if(base) cliArgs.push('--base', base)
119
+ if(phpVersionsArg && phpVersionsArg.length) cliArgs.push('--php', phpVersionsArg.join(','))
120
+ if(noLintResultCache) cliArgs.push('--no-lint-result-cache')
97
121
  const result=await run('govard', cliArgs, worktreePath, timeoutMs)
98
122
  if(result.timedOut){
99
- return {ok:false, exitCode:result.code, timedOut:true, worktreePath, lint:{phpcs:{violations:[]}, phpstan:{errors:[]}, pubMediaGuard:{violations:[]}}, summary:{status:null, phpVersions:[], matrixComplete:false, findingCount:0, truncated:false}, rawJson:null, errors:[{code:'timeout', message:`timed out after ${timeoutMs}ms` }], diagnostics:result.stderr.slice(0,4000)} as never
123
+ return {ok:false, exitCode: result.code ?? 124, timedOut:true, worktreePath, lint:{phpcs:{violations:[]}, phpstan:{errors:[]}, pubMediaGuard:{violations:[]}}, summary:{status:null, phpVersions:[], matrixComplete:false, findingCount:0, truncated:false}, rawJson:{}, errors:[{code:'timeout', message:`timed out after ${timeoutMs}ms` }], diagnostics:result.stderr.slice(0,4000)} as never
100
124
  }
101
125
  if(result.code===null && result.stderr.includes('ENOENT')){
102
- return {ok:false, exitCode:null, timedOut:false, worktreePath, lint:{phpcs:{violations:[]}, phpstan:{errors:[]}, pubMediaGuard:{violations:[]}}, summary:{status:null, phpVersions:[], matrixComplete:false, findingCount:0, truncated:false}, rawJson:null, errors:[{code:'govard_not_found', message:'govard binary not found'}], diagnostics:result.stderr.slice(0,4000)} as never
126
+ return {ok:false, exitCode:127, timedOut:false, worktreePath, lint:{phpcs:{violations:[]}, phpstan:{errors:[]}, pubMediaGuard:{violations:[]}}, summary:{status:null, phpVersions:[], matrixComplete:false, findingCount:0, truncated:false}, rawJson:{}, errors:[{code:'govard_not_found', message:'govard binary not found'}], diagnostics:result.stderr.slice(0,4000)} as never
103
127
  }
104
128
  const cleaned=cleanJson(result.stdout)
105
129
  let parsed:any=null
@@ -113,7 +137,7 @@ export function apply(ctx:Context, config:{rootPath?:string, timeoutMs?:number}=
113
137
  }
114
138
  }
115
139
  if(!parsed){
116
- return {ok:false, exitCode:result.code, timedOut:false, worktreePath, lint:{phpcs:{violations:[]}, phpstan:{errors:[]}, pubMediaGuard:{violations:[]}}, summary:{status:null, phpVersions:[], matrixComplete:false, findingCount:0, truncated:false}, rawJson:null, errors:[{code:'parse_error', message:'stdout not JSON'}], diagnostics:(cleaned+result.stderr).slice(0,4000)} as never
140
+ return {ok:false, exitCode: result.code ?? 1, timedOut:false, worktreePath, lint:{phpcs:{violations:[]}, phpstan:{errors:[]}, pubMediaGuard:{violations:[]}}, summary:{status:null, phpVersions:[], matrixComplete:false, findingCount:0, truncated:false}, rawJson:{}, errors:[{code:'parse_error', message:'stdout not JSON'}], diagnostics:(cleaned+result.stderr).slice(0,4000)} as never
117
141
  }
118
142
  const findings:Array<any>=parsed.findings ?? parsed.evidence?.php_results?.flatMap((r:any)=>r.findings) ?? []
119
143
  const phpcsViolations:any[]=[]
@@ -129,18 +153,20 @@ export function apply(ctx:Context, config:{rootPath?:string, timeoutMs?:number}=
129
153
  const status=parsed.status ?? (result.code===0?'passed':'failed')
130
154
  const phpVersions=parsed.php_versions ?? parsed.phpVersions ?? []
131
155
  const findingCount=findings.length
156
+ const sessionId = parsed.session_id ?? parsed.sessionId ?? undefined
157
+ const runId = parsed.run_id ?? parsed.runId ?? undefined
132
158
  return {
133
159
  ok: result.code===0,
134
- exitCode: result.code,
160
+ exitCode: result.code ?? 0,
135
161
  timedOut:false,
136
162
  worktreePath,
137
- sessionId: parsed.session_id ?? parsed.sessionId ?? null,
138
- runId: parsed.run_id ?? parsed.runId ?? null,
139
- rawJson: parsed,
163
+ ...(sessionId ? { sessionId: String(sessionId) } : {}),
164
+ ...(runId ? { runId: String(runId) } : {}),
165
+ rawJson: parsed as Record<string, unknown>,
140
166
  summary:{status, phpVersions, matrixComplete:true, findingCount, truncated: findingCount>100},
141
167
  lint:{phpcs:{violations:phpcsViolations}, phpstan:{errors:phpstanErrors}, pubMediaGuard:{violations:pubMediaViolations}},
142
168
  errors:[],
143
- diagnostics: result.stderr.slice(0,4000) || null,
169
+ diagnostics: result.stderr.slice(0,4000),
144
170
  } as never
145
171
  }
146
172
  })))
@@ -146,7 +146,7 @@ export const Config: z<Config> = z.object({
146
146
  projectMappings: z.array(z.object({
147
147
  projectPath: z.string().required(),
148
148
  localRepoPath: z.string().required(),
149
- reviewProfile: z.union([z.const('magento2'), z.const('generic')]).default('magento2'),
149
+ reviewProfile: z.union([z.const('magento2'), z.const('laravel'), z.const('symfony'), z.const('wordpress'), z.const('generic')]).default('magento2'),
150
150
  })).required(),
151
151
  gitlabBaseUrl: z.string().required(),
152
152
  gitlabToken: z.string().role('secret'),
@@ -325,15 +325,22 @@ export async function postReviewFindings(findings: ReviewFinding[], config: Gitl
325
325
  throw new Error(`cannot post inline finding at ${finding.path}:${finding.line}: GitLab did not return this file's complete diff`)
326
326
  }
327
327
  const linePosition = diffPositionForNewLine(change.diff, finding.line)
328
- if (linePosition === undefined) throw new Error(`cannot post inline finding at ${finding.path}:${finding.line}: line is not in the current MR diff`)
329
- response = await fetcher(`${apiBase}/discussions`, {
330
- method: 'POST', headers,
331
- body: JSON.stringify({ body: finding.body, position: {
332
- position_type: 'text', ...snapshot.diffRefs, old_path: change.old_path, new_path: change.new_path,
333
- ...linePosition.oldLine === undefined ? {} : { old_line: linePosition.oldLine },
334
- ...linePosition.newLine === undefined ? {} : { new_line: linePosition.newLine },
335
- } }),
336
- })
328
+ if (linePosition === undefined) {
329
+ // Line not in diff — fallback to MR note so finding is not silently lost.
330
+ response = await fetcher(`${apiBase}/notes`, {
331
+ method: 'POST', headers,
332
+ body: JSON.stringify({ body: `**Inline fallback — \`${finding.path}:${finding.line}\` line is not in current MR diff**\n\n${finding.body}` }),
333
+ })
334
+ } else {
335
+ response = await fetcher(`${apiBase}/discussions`, {
336
+ method: 'POST', headers,
337
+ body: JSON.stringify({ body: finding.body, position: {
338
+ position_type: 'text', ...snapshot.diffRefs, old_path: change.old_path, new_path: change.new_path,
339
+ ...linePosition.oldLine === undefined ? {} : { old_line: linePosition.oldLine },
340
+ ...linePosition.newLine === undefined ? {} : { new_line: linePosition.newLine },
341
+ } }),
342
+ })
343
+ }
337
344
  }
338
345
  if (!response.ok) throw new Error(`GitLab API error ${response.status}: ${await response.text()}`)
339
346
  }
@@ -490,6 +497,21 @@ function assertSafeBranchName(sourceBranch: string): void {
490
497
  }
491
498
  }
492
499
 
500
+ export function isBranchNotFoundError(err: unknown): boolean {
501
+ const rawStderr = (err as { stderr?: unknown })?.stderr
502
+ const rawMsg = (err as { message?: unknown })?.message
503
+ const toText = (v: unknown): string => {
504
+ if (typeof v === 'string') return v
505
+ if (v instanceof Uint8Array || (typeof Buffer !== 'undefined' && Buffer.isBuffer(v as unknown))) return Buffer.from(v as Uint8Array).toString('utf8')
506
+ if (typeof v === 'object' && v !== null && 'toString' in v) try { return String(v) } catch {}
507
+ return ''
508
+ }
509
+ const stderrText = toText(rawStderr)
510
+ const msgText = toText(rawMsg)
511
+ const text = stderrText !== '' ? stderrText : msgText !== '' ? msgText : String(err ?? '')
512
+ return text.includes("couldn't find remote ref") || text.includes('could not find remote branch') || text.includes('unknown revision or path')
513
+ }
514
+
493
515
  /**
494
516
  * Keep a Govard audit worktree isolated from the developer's primary checkout.
495
517
  * Without this local override, both checkouts inherit the same `project_name`
@@ -503,7 +525,17 @@ export function govardWorktreeOverride(projectId: number, mrIid: number, keySuff
503
525
  export async function ensureWorktree(localRepoPath: string, sourceBranch: string, projectId: number, mrIid: number, keySuffix?: string): Promise<string> {
504
526
  assertSafeBranchName(sourceBranch)
505
527
  const worktreePath = join('/tmp', `maestro-mr-${projectId}-${mrIid}${keySuffix === undefined ? '' : `-${keySuffix}`}`)
506
- await execFileAsync('git', ['fetch', '--', 'origin', sourceBranch], { cwd: localRepoPath, timeout: GIT_TIMEOUT_MS })
528
+ try {
529
+ await execFileAsync('git', ['fetch', '--', 'origin', sourceBranch], { cwd: localRepoPath, timeout: GIT_TIMEOUT_MS })
530
+ } catch (err) {
531
+ if (isBranchNotFoundError(err)) {
532
+ const e = new Error(`branch not found on origin: ${sourceBranch}`)
533
+ ;(e as unknown as { code: string }).code = 'BRANCH_NOT_FOUND'
534
+ ;(e as unknown as { cause: unknown }).cause = err
535
+ throw e
536
+ }
537
+ throw err
538
+ }
507
539
  // A host restart can interrupt an active review before its `finally` cleanup.
508
540
  // Recover only this deterministic Maestro-owned path so the next delivery can
509
541
  // retry; an unrelated worktree is never targeted.
@@ -824,16 +856,36 @@ export function apply(ctx: Context, config: Config): void {
824
856
  await signals?.finish('completed')
825
857
  return
826
858
  }
827
- const fullBody = await runReviewAndAudit(payload, {
828
- localRepoPath: mapping.localRepoPath,
829
- ensureWorktree,
830
- removeWorktree,
831
- runReviewer: (worktreePath, p) => runReviewer(worktreePath, p, resolved, mapping.reviewProfile ?? 'magento2', reviewModelSelection, incrementalBlock),
832
- runAuditor: (worktreePath, p) => runAuditor(worktreePath, p, resolved, reviewModelSelection),
833
- postComment,
834
- replyToDiscussion,
835
- writeFailedReport,
836
- })
859
+ let fullBody: string
860
+ try {
861
+ fullBody = await runReviewAndAudit(payload, {
862
+ localRepoPath: mapping.localRepoPath,
863
+ ensureWorktree,
864
+ removeWorktree,
865
+ runReviewer: (worktreePath, p) => runReviewer(worktreePath, p, resolved, mapping.reviewProfile ?? 'magento2', reviewModelSelection, incrementalBlock),
866
+ runAuditor: (worktreePath, p) => runAuditor(worktreePath, p, resolved, reviewModelSelection),
867
+ postComment,
868
+ replyToDiscussion,
869
+ writeFailedReport,
870
+ })
871
+ } catch (err) {
872
+ const isBranchNotFound = (err as { code?: string })?.code === 'BRANCH_NOT_FOUND' || isBranchNotFoundError(err)
873
+ if (isBranchNotFound) {
874
+ const diffBody = await runDiffOnlyReview(payload, {
875
+ runReviewer: (p) => runReviewer(undefined, p, resolved, undefined, reviewModelSelection, incrementalBlock),
876
+ postComment,
877
+ replyToDiscussion,
878
+ writeFailedReport,
879
+ })
880
+ const summary = summarize(diffBody)
881
+ const branchNote = `fallback diff-only: branch ${payload.sourceBranch} not found on origin — ${summary ?? ''}`.trim()
882
+ await recordReviewFinish(historyId, { status: 'completed', summary: branchNote })
883
+ notifyTelegram('completed', branchNote)
884
+ await signals?.finish('completed')
885
+ return
886
+ }
887
+ throw err
888
+ }
837
889
  await recordReviewFinish(historyId, { status: 'completed', summary: summarize(fullBody) })
838
890
  notifyTelegram('completed', summarize(fullBody))
839
891
  await signals?.finish('completed')
@@ -1,4 +1,4 @@
1
- import { createServer, type IncomingMessage } from 'node:http'
1
+ import type { IncomingMessage, ServerResponse } from 'node:http'
2
2
  import type { Context } from '@deepseek-ai/cordis'
3
3
  import z from '@deepseek-ai/schemastery'
4
4
  import { loadUserConfig } from '../config-store.js'
@@ -8,15 +8,13 @@ import { routeGitlabReviewRequest } from '../review-intake.js'
8
8
  import type { ReviewProvider, ReviewRequest } from './interface.js'
9
9
 
10
10
  export const name = 'maestro-review-webhook'
11
+ export const inject = ['webServer'] as const
11
12
 
12
13
  export interface Config {
13
- port: number
14
14
  botUsername?: string
15
15
  secret?: string
16
16
  }
17
-
18
17
  export const Config: z<Config> = z.object({
19
- port: z.natural().max(65535).required(),
20
18
  botUsername: z.string(),
21
19
  secret: z.string().role('secret'),
22
20
  })
@@ -108,83 +106,37 @@ export function apply(ctx: Context, config: Config): void {
108
106
  const userConfig = await loadUserConfig()
109
107
  const expected = userConfig.webhookSecret ?? config.secret
110
108
  if (expected === undefined) {
111
- if (!warnedUnconfigured) {
112
- warnedUnconfigured = true
113
- console.error('maestro-review-webhook: no webhook secret configured — set one in Maestro Settings or MAESTRO_GITLAB_WEBHOOK_SECRET; rejecting all requests until then')
114
- }
109
+ if (!warnedUnconfigured) { warnedUnconfigured = true; console.error('maestro-review-webhook: no webhook secret configured — set one in Maestro Settings or MAESTRO_GITLAB_WEBHOOK_SECRET; rejecting all requests until then') }
115
110
  return false
116
111
  }
117
112
  return secretsMatch(headerValue, expected)
118
113
  }
119
-
120
- const server = createServer((req, res) => {
121
- if (req.method !== 'POST') {
122
- res.writeHead(404).end()
123
- return
124
- }
125
- void requestAuthorized(req.headers['x-gitlab-token']).then(async (authorized) => {
126
- if (!authorized) {
127
- res.writeHead(401).end()
128
- return
129
- }
130
- readBody(req).then(async (raw) => {
131
- if (raw === undefined) {
132
- res.writeHead(413).end()
133
- return
134
- }
135
- if (req.url === '/hooks/gitlab-mr/trigger') {
136
- let parsed: unknown
137
- try {
138
- parsed = JSON.parse(raw)
139
- } catch {
140
- res.writeHead(400).end()
141
- return
142
- }
143
- if (!isValidMrOpenedPayload(parsed)) {
144
- res.writeHead(400).end()
145
- return
146
- }
147
- const request: OrchestratorReviewRequest = {
148
- ...parsed,
149
- trigger: 'mention',
150
- mode: 'quick',
151
- scope: { kind: 'mr' },
152
- }
153
- ctx.emit('maestro/review-request', request)
154
- res.writeHead(200).end()
155
- return
156
- }
157
-
158
- if (req.url !== '/hooks/gitlab-mr') {
159
- res.writeHead(404).end()
160
- return
161
- }
162
- let body: GitlabMrWebhookBody
163
- try {
164
- body = JSON.parse(raw)
165
- } catch {
166
- res.writeHead(400).end()
167
- return
114
+ function makeHandler(expectedPath: string) {
115
+ return (req: IncomingMessage, res: ServerResponse) => {
116
+ if (req.method !== 'POST') { res.writeHead(404).end(); return }
117
+ if (req.url !== expectedPath) { res.writeHead(404).end(); return }
118
+ void requestAuthorized(req.headers['x-gitlab-token']).then(async (authorized) => {
119
+ if (!authorized) { res.writeHead(401).end(); return }
120
+ const raw = await readBody(req)
121
+ if (raw === undefined) { res.writeHead(413).end(); return }
122
+ if (expectedPath === '/hooks/gitlab-mr/trigger') {
123
+ let parsed: unknown; try { parsed = JSON.parse(raw) } catch { res.writeHead(400).end(); return }
124
+ if (!isValidMrOpenedPayload(parsed)) { res.writeHead(400).end(); return }
125
+ const request: OrchestratorReviewRequest = { ...(parsed as any), trigger: 'mention', mode: 'quick', scope: { kind: 'mr' } }
126
+ ctx.emit('maestro/review-request', request); res.writeHead(200).end(); return
168
127
  }
128
+ let body: GitlabMrWebhookBody; try { body = JSON.parse(raw) } catch { res.writeHead(400).end(); return }
169
129
  const userConfig = await loadUserConfig()
170
- if ((body.object_kind === 'merge_request' || body.object_kind === 'note') && !hasValidGitlabMrIdentity(body)) {
171
- res.writeHead(400).end()
172
- return
173
- }
174
- const request = routeGitlabReviewRequest(
175
- body,
176
- userConfig.botUsername ?? config.botUsername ?? 'maestro',
177
- { pushEnabled: userConfig.autoRereviewOnPush === true },
178
- )
130
+ if ((body.object_kind === 'merge_request' || body.object_kind === 'note') && !hasValidGitlabMrIdentity(body)) { res.writeHead(400).end(); return }
131
+ const request = routeGitlabReviewRequest(body, userConfig.botUsername ?? config.botUsername ?? 'maestro', { pushEnabled: userConfig.autoRereviewOnPush === true })
179
132
  if (request !== undefined) ctx.emit('maestro/review-request', request)
180
133
  res.writeHead(200).end()
181
134
  })
182
- })
183
- })
184
-
185
- server.listen(config.port)
186
-
187
- ctx.effect(() => async () => {
188
- await new Promise<void>((resolve) => { server.close(() => resolve()) })
189
- }, 'gitlab-webhook teardown')
135
+ }
136
+ }
137
+ const h1 = makeHandler('/hooks/gitlab-mr')
138
+ const h2 = makeHandler('/hooks/gitlab-mr/trigger')
139
+ const dispose1 = (ctx as any).webServer.register({ kind: 'exact', path: '/hooks/gitlab-mr', handler: h1 })
140
+ const dispose2 = (ctx as any).webServer.register({ kind: 'exact', path: '/hooks/gitlab-mr/trigger', handler: h2 })
141
+ ctx.effect(() => () => { dispose1(); dispose2() }, 'gitlab-webhook teardown')
190
142
  }
@@ -21,6 +21,7 @@ export interface ReviewHistoryEntry {
21
21
  }
22
22
 
23
23
  const HISTORY_CAP = 100
24
+ const STALE_RUNNING_MS = 2 * 60 * 60_000 // 2h — host restart can leave running without finish
24
25
 
25
26
  export function historyPath(dshHome?: string): string {
26
27
  const home = dshHome ?? process.env.DSH_HOME ?? join(homedir(), '.dsh')
@@ -47,9 +48,24 @@ async function writeAll(entries: ReviewHistoryEntry[], dshHome?: string): Promis
47
48
  await chmod(path, 0o600)
48
49
  }
49
50
 
51
+ function failStaleRunning(entries: ReviewHistoryEntry[]): boolean {
52
+ let mutated = false
53
+ const now = Date.now()
54
+ for (const e of entries) {
55
+ if (e.status === 'running' && now - e.startedAt > STALE_RUNNING_MS) {
56
+ e.status = 'failed'
57
+ e.error = e.error ?? 'auto-failed: stale running review (host restart or crash)'
58
+ e.finishedAt = e.finishedAt ?? now
59
+ mutated = true
60
+ }
61
+ }
62
+ return mutated
63
+ }
64
+
50
65
  /** Prepend a running entry; the oldest entries fall off past `HISTORY_CAP`. */
51
66
  export async function recordReviewStart(entry: Omit<ReviewHistoryEntry, 'status'>, dshHome?: string): Promise<void> {
52
67
  const all = await readAll(dshHome)
68
+ if (failStaleRunning(all)) await writeAll(all, dshHome)
53
69
  all.unshift({ ...entry, status: 'running' })
54
70
  await writeAll(all.slice(0, HISTORY_CAP), dshHome)
55
71
  }
@@ -91,9 +107,11 @@ export async function lastCompletedReview(projectId: number, mrIid: number, dshH
91
107
  */
92
108
  export async function pruneHistory(retentionDays: number, dshHome?: string): Promise<void> {
93
109
  if (!Number.isFinite(retentionDays) || retentionDays <= 0) return
110
+ const all = await readAll(dshHome)
111
+ failStaleRunning(all)
94
112
  const cutoff = Date.now() - retentionDays * DAY_MS
95
113
  const kept: ReviewHistoryEntry[] = []
96
- for (const entry of await readAll(dshHome)) {
114
+ for (const entry of all) {
97
115
  if ((entry.finishedAt ?? entry.startedAt) < cutoff) continue
98
116
  kept.push(entry)
99
117
  }
@@ -1,6 +1,6 @@
1
1
  import type { Context } from '@deepseek-ai/cordis'
2
2
  import type {} from '@deepseek-ai/dsh-client-connection'
3
- import type { RpcErrorDetailsMap, RpcResult } from '@deepseek-ai/dsh-host-apiproxy/api'
3
+ import type { RpcErrorDetailsMap, RpcResult } from '@deepseek-ai/dsh-client-connection'
4
4
  import { existsSync, statSync } from 'node:fs'
5
5
  import { loadUserConfig, saveUserConfig, type MaestroUserConfig } from './config-store.js'
6
6
  import { listReviews } from './review-history.js'
@@ -5,7 +5,7 @@ import type {} from '@deepseek-ai/dsh-agent'
5
5
  export const name = 'maestro-skills-tool'
6
6
  export const inject = ['skills', 'tools']
7
7
 
8
- export type ReviewSkillProfile = 'magento2' | 'generic'
8
+ export type ReviewSkillProfile = 'magento2' | 'laravel' | 'symfony' | 'wordpress' | 'generic'
9
9
 
10
10
  /**
11
11
  * Exact skill names rather than a fuzzy search: a review must not silently
@@ -25,11 +25,26 @@ export const REVIEW_PROFILE_SKILLS: Record<ReviewSkillProfile, readonly string[]
25
25
  'magento2-security-scan',
26
26
  'magento2-performance-audit',
27
27
  ],
28
+ laravel: [
29
+ 'govard-toolbox',
30
+ 'govard-laravel',
31
+ 'php-dev-core',
32
+ ],
33
+ symfony: [
34
+ 'govard-toolbox',
35
+ 'govard-symfony',
36
+ 'php-dev-core',
37
+ ],
38
+ wordpress: [
39
+ 'govard-toolbox',
40
+ 'govard-wordpress',
41
+ 'php-dev-core',
42
+ ],
28
43
  /** Diff review against general best practices; no project skill set required. */
29
44
  generic: [],
30
45
  }
31
46
 
32
- export const MAESTRO_SKILLS_INSTALL_COMMAND = 'curl -fsSL https://raw.githubusercontent.com/ddtcorex/maestro-skills/master/install.sh | bash -s -- --scope personal --target dsh --skills govard-toolbox,govard-magento,magento2-dev-core,magento2-frontend-dev,magento2-hyva-dev,magento2-code-review,magento2-linter,magento2-security-scan,magento2-performance-audit -y'
47
+ export const MAESTRO_SKILLS_INSTALL_COMMAND = 'curl -fsSL https://raw.githubusercontent.com/ddtcorex/maestro-skills/master/install.sh | bash -s -- --scope personal --target dsh --skills govard-toolbox,govard-magento,govard-laravel,govard-symfony,govard-wordpress,php-dev-core,magento2-dev-core,magento2-frontend-dev,magento2-hyva-dev,magento2-code-review,magento2-linter,magento2-security-scan,magento2-performance-audit -y'
33
48
 
34
49
  // This is deliberately process-local and keyed by the reviewer Agent object,
35
50
  // which every Cordis child context inherits. Preset mounting inserts child
@@ -139,7 +154,7 @@ export function apply(ctx: Context): void {
139
154
  name: 'maestro_load_review_profile',
140
155
  description: 'Load the complete, exact skill set required for a configured review profile. Fails if any required skill is unavailable.',
141
156
  parameters: {
142
- profile: { type: 'string', required: true, description: 'Review profile configured for the project. Supported: "magento2" (full Magento skill set), "generic" (no skills required).' },
157
+ profile: { type: 'string', required: true, description: 'Review profile configured for the project. Supported: "magento2" (full Magento skill set), "laravel" (Govard Laravel + PHP), "symfony" (Govard Symfony + PHP), "wordpress" (Govard WordPress + PHP), "generic" (no skills required).' },
143
158
  },
144
159
  output: {
145
160
  schema: {
@@ -1,17 +0,0 @@
1
- import type { Context } from '@deepseek-ai/cordis';
2
- import z from '@deepseek-ai/schemastery';
3
- export declare const name = "maestro-gitlab-webhook";
4
- export interface Config {
5
- port: number;
6
- /** Username of the GitLab service account used for reviewer assignments. */
7
- botUsername?: string;
8
- /**
9
- * Fallback when Maestro Settings has no webhook secret; optional so a
10
- * deployment that configures everything through Settings boots without env
11
- * vars. With neither source set, every request is rejected (fail closed).
12
- */
13
- secret?: string;
14
- }
15
- export declare const Config: z<Config>;
16
- export declare function apply(ctx: Context, config: Config): void;
17
- //# sourceMappingURL=gitlab-webhook.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"gitlab-webhook.d.ts","sourceRoot":"","sources":["../src/gitlab-webhook.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAMxC,eAAO,MAAM,IAAI,2BAA2B,CAAA;AAE5C,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,eAAO,MAAM,MAAM,EAAE,CAAC,CAAC,MAAM,CAI3B,CAAA;AAkDF,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAyFxD"}