@ddtcorex/dsh-maestro-review 0.8.1 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -2
- package/lib/orchestrator.d.ts.map +1 -1
- package/lib/orchestrator.js +3 -2
- package/lib/orchestrator.js.map +1 -1
- package/lib/settings-rpc.js +1 -1
- package/lib/settings-rpc.js.map +1 -1
- package/lib/skill-provider.d.ts.map +1 -1
- package/lib/skill-provider.js +5 -2
- package/lib/skill-provider.js.map +1 -1
- package/lib/source.d.ts +23 -0
- package/lib/source.d.ts.map +1 -0
- package/lib/source.js +16 -0
- package/lib/source.js.map +1 -0
- package/package.json +18 -13
- package/presets/maestro-auditor.patch.yml +51 -0
- package/presets/maestro-reviewer.patch.yml +55 -0
- package/profiles/reviewer-ci/cordis.patch.yml +11 -6
- package/profiles/reviewer-ci/package.json +3 -3
- package/profiles/reviewer-ci/pnpm-lock.yaml +4933 -4406
- package/profiles/reviewer-ci/pnpm-workspace.yaml +17 -44
- package/skills/dsh-native-tools/SKILL.md +1 -1
- package/src/host/augment.d.ts +4 -2
- package/src/host/orchestrator.ts +4 -3
- package/src/host/settings-rpc.ts +1 -1
- package/src/host/skill-provider.ts +5 -2
- package/src/host/source.ts +26 -0
- package/templates/reviewer-project.gitlab-ci.yml +1 -1
- package/presets/maestro-auditor/agent.cordis.yml +0 -35
- package/presets/maestro-auditor/preset.yml +0 -2
- package/presets/maestro-reviewer/agent.cordis.yml +0 -39
- package/presets/maestro-reviewer/preset.yml +0 -2
|
@@ -7,46 +7,17 @@
|
|
|
7
7
|
# printed "Scope: all 2 workspace projects" and resolved relative to `../..`
|
|
8
8
|
# without this file present).
|
|
9
9
|
packages: []
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
# /entrypoint.sh` with real credentials; GITLAB_HOST must be the bare
|
|
22
|
-
# hostname, no `https://` prefix — ci-trigger.ts prepends the scheme itself).
|
|
23
|
-
# pnpm reads `overrides:` here, NOT from package.json, on pnpm 11 (see the
|
|
24
|
-
# dsh-invariants override above/below for the same gotcha in the sibling
|
|
25
|
-
# workspace). Every package below is confirmed to publish a 0.1.5-rc.2.
|
|
26
|
-
overrides:
|
|
27
|
-
'@deepseek-ai/dsh-attachment': 0.1.5-rc.2
|
|
28
|
-
'@deepseek-ai/dsh-session-persistence': 0.1.5-rc.2
|
|
29
|
-
'@deepseek-ai/dsh-fs': 0.1.5-rc.2
|
|
30
|
-
'@deepseek-ai/dsh-code-runtime': 0.1.5-rc.2
|
|
31
|
-
'@deepseek-ai/dsh-compaction': 0.1.5-rc.2
|
|
32
|
-
'@deepseek-ai/dsh-settings': 0.1.5-rc.2
|
|
33
|
-
'@deepseek-ai/dsh-hook-protocol': 0.1.5-rc.2
|
|
34
|
-
'@deepseek-ai/dsh-jobs': 0.1.5-rc.2
|
|
35
|
-
'@deepseek-ai/dsh-sandbox': 0.1.5-rc.2
|
|
36
|
-
'@deepseek-ai/dsh-session-query': 0.1.5-rc.2
|
|
37
|
-
'@deepseek-ai/dsh-util-time': 0.1.5-rc.2
|
|
38
|
-
'@deepseek-ai/dsh-shell': 0.1.5-rc.2
|
|
39
|
-
'@deepseek-ai/dsh-sdk-protocol': 0.1.5-rc.2
|
|
40
|
-
'@deepseek-ai/dsh-anonymous-user-id': 0.1.5-rc.2
|
|
41
|
-
'@deepseek-ai/dsh-output-retention': 0.1.5-rc.2
|
|
42
|
-
'@deepseek-ai/dsh-spill': 0.1.5-rc.2
|
|
43
|
-
'@deepseek-ai/dsh-workflow': 0.1.5-rc.2
|
|
44
|
-
'@deepseek-ai/dsh-util-workspace-path': 0.1.5-rc.2
|
|
45
|
-
'@deepseek-ai/dsh-bash-local': 0.1.5-rc.2
|
|
46
|
-
'@deepseek-ai/dsh-authorization': 0.1.5-rc.2
|
|
47
|
-
'@deepseek-ai/dsh-session-telemetry': 0.1.5-rc.2
|
|
48
|
-
'@deepseek-ai/dsh-session-title-llm': 0.1.5-rc.2
|
|
49
|
-
'@deepseek-ai/dsh-subagent-in-process-driver': 0.1.5-rc.2
|
|
10
|
+
# No `overrides:` block on the 0.1.7-rc.1 line, deliberately. The 0.1.5-rc.2
|
|
11
|
+
# profile needed one because those packages declared loose ranges, so ~23 of
|
|
12
|
+
# their transitive deps resolved back to the older 0.1.2-rc.1 — silent at
|
|
13
|
+
# install time (a peer warning only), fatal at boot: a newer consumer
|
|
14
|
+
# ESM-imported a symbol the older peer's build never exported (e.g.
|
|
15
|
+
# dsh-session-persistence-jsonl@0.1.5-rc.2 importing SessionAlreadyExistsError
|
|
16
|
+
# from dsh-session-persistence@0.1.2-rc.1), crashing the whole plugin tree with
|
|
17
|
+
# exit 1. Every `@deepseek-ai/dsh-*` package on the alpha.2 line pins its own
|
|
18
|
+
# graph exactly, so the same install needs no forcing (verified 2026-09-23:
|
|
19
|
+
# 281 @deepseek-ai packages installed, zero duplicate package names, one
|
|
20
|
+
# cordis@4.0.4 that satisfies the plugin's `~4.0.4` peer).
|
|
50
21
|
# Postinstall scripts required at runtime (node-pty/subprocess-local spawn
|
|
51
22
|
# agents, koffi/protobufjs/genai serve model IO). Exact versions pinned in
|
|
52
23
|
# pnpm-lock.yaml; review on every profile dep bump.
|
|
@@ -56,8 +27,10 @@ allowBuilds:
|
|
|
56
27
|
koffi: true
|
|
57
28
|
node-pty: true
|
|
58
29
|
protobufjs: true
|
|
30
|
+
# pnpm keeps only the FIRST entry per package name, so bumping our own
|
|
31
|
+
# release means REPLACING its entry — appending the newer version leaves it
|
|
32
|
+
# shadowed by the stale one and the 24h age gate keeps rejecting it (observed
|
|
33
|
+
# 2026-09-18). The Docker build additionally passes
|
|
34
|
+
# --config.minimumReleaseAge=0.
|
|
59
35
|
minimumReleaseAgeExclude:
|
|
60
|
-
- '@ddtcorex/dsh-maestro-review@0.
|
|
61
|
-
- '@ddtcorex/maestro-skills@2.11.0'
|
|
62
|
-
- '@ddtcorex/dsh-maestro-review@0.5.1'
|
|
63
|
-
- '@ddtcorex/maestro-skills@2.11.1'
|
|
36
|
+
- '@ddtcorex/dsh-maestro-review@0.9.0'
|
|
@@ -35,7 +35,7 @@ harness-neutral words — announce, dispatch a subagent, ask your partner. On DS
|
|
|
35
35
|
| Write / edit files | `write`, `edit` (read before edit) |
|
|
36
36
|
| Run shell commands, tests, git | `bash`; background via `run_in_background: true`, collect with `job_output`, stop with `job_kill` |
|
|
37
37
|
| Search the web | `web_search` |
|
|
38
|
-
| Look at an image file | `read_image`
|
|
38
|
+
| Look at an image file | `read_image` |
|
|
39
39
|
| Ensure an isolated workspace | `git_worktree {op:'inspect', worktreePath}` → {exists,branch,headSha,isClean,isWorktree} (`worktreePath` is required on every op) |
|
|
40
40
|
| Create a worktree | `git_worktree {op:'create', worktreePath, branch, base?}` → {created,headSha} |
|
|
41
41
|
| Clean up a worktree | `git_worktree {op:'remove', worktreePath}` → {removed,dirtyFiles} |
|
package/src/host/augment.d.ts
CHANGED
|
@@ -16,7 +16,10 @@ import '@deepseek-ai/cordis'
|
|
|
16
16
|
declare module '@deepseek-ai/cordis' {
|
|
17
17
|
interface Context {
|
|
18
18
|
webServer: { port: number; register: any }
|
|
19
|
-
|
|
19
|
+
// `handle` takes exactly (channel, handler): the Host never read an
|
|
20
|
+
// `{ authority: 'loopback' }` third argument, so this shape must not
|
|
21
|
+
// advertise one (dropped at the call site in #129).
|
|
22
|
+
connection: { rpc: { handle: (channel: string, handler: any) => () => void; call: any } }
|
|
20
23
|
maestroTunnel: {
|
|
21
24
|
status(): any
|
|
22
25
|
start(): Promise<any>
|
|
@@ -42,7 +45,6 @@ declare module '@deepseek-ai/cordis' {
|
|
|
42
45
|
agentDefaultModel: {
|
|
43
46
|
currentSelection(): ModelSelection
|
|
44
47
|
}
|
|
45
|
-
agentPresets: { mount(agentCtx: Context, id: string): Promise<unknown> | unknown }
|
|
46
48
|
sessionTitle: { rename(session: unknown, title: string): Promise<unknown> | unknown }
|
|
47
49
|
/** Current agent identity inside an agent-scoped context (WeakMap key). */
|
|
48
50
|
agent?: object
|
package/src/host/orchestrator.ts
CHANGED
|
@@ -13,7 +13,7 @@ import { finalAssistantOutput } from '@deepseek-ai/dsh-subagent'
|
|
|
13
13
|
import type { AgentHandle } from '@deepseek-ai/dsh-agent'
|
|
14
14
|
import { installModelSelection } from '@deepseek-ai/dsh-agent'
|
|
15
15
|
import type { ModelSelection } from '@deepseek-ai/dsh-agent'
|
|
16
|
-
import type {} from '@deepseek-ai/dsh-agent-
|
|
16
|
+
import type {} from '@deepseek-ai/dsh-agent-preset-registry'
|
|
17
17
|
import type {} from '@deepseek-ai/dsh-agent-default-model'
|
|
18
18
|
import type {} from '@deepseek-ai/dsh-session-title'
|
|
19
19
|
import * as GovardTool from './govard-tool.js'
|
|
@@ -39,6 +39,7 @@ import { reviewDigestText, type NotifierLike } from './notify.js'
|
|
|
39
39
|
import { loadedReviewProfile, type ReviewSkillProfile } from './skills-tool.js'
|
|
40
40
|
import type { ReviewProvider } from './providers/interface.js'
|
|
41
41
|
import { gitlabProvider } from './providers/gitlab.js'
|
|
42
|
+
import { REVIEW_SOURCE_KIND } from './source.js'
|
|
42
43
|
import './events.js'
|
|
43
44
|
import { gitlabAuthHeaders } from './gitlab-auth.js'
|
|
44
45
|
import { reviewMarker, resolveFlow, type ReviewFlow } from './review-marker.js'
|
|
@@ -1167,7 +1168,7 @@ export function apply(ctx: Context, config: Config): void {
|
|
|
1167
1168
|
if (incrementalBlock !== undefined) scopePrompt = `${incrementalBlock}\n\n${scopePrompt}`
|
|
1168
1169
|
handle.agent.followup(createUserMessage({
|
|
1169
1170
|
content: [{ type: 'text', text: scopePrompt }],
|
|
1170
|
-
source: { kind:
|
|
1171
|
+
source: { kind: REVIEW_SOURCE_KIND },
|
|
1171
1172
|
}))
|
|
1172
1173
|
await whenIdleWithTimeout(handle, effectiveAgentTimeoutMs)
|
|
1173
1174
|
assertTurnSucceededOrSalvage(handle, capturedFindings.length > 0, 'reviewer')
|
|
@@ -1266,7 +1267,7 @@ export function apply(ctx: Context, config: Config): void {
|
|
|
1266
1267
|
ctx.sessionTitle.rename(handle.agent.session, `Maestro Auditor — MR !${payload.mrIid} (${payload.projectPath})`)
|
|
1267
1268
|
try {
|
|
1268
1269
|
const prompt = buildAuditorPrompt({ staticOnly: opts?.staticOnly === true })
|
|
1269
|
-
handle.agent.followup(createUserMessage({ content: [{ type: 'text', text: prompt }], source: { kind:
|
|
1270
|
+
handle.agent.followup(createUserMessage({ content: [{ type: 'text', text: prompt }], source: { kind: REVIEW_SOURCE_KIND } }))
|
|
1270
1271
|
await whenIdleWithTimeout(handle, effectiveAgentTimeoutMs)
|
|
1271
1272
|
const output = auditorOutputFromSession(handle.agent.session)
|
|
1272
1273
|
const text = output.map(block => ('text' in block ? block.text : '')).join('')
|
package/src/host/settings-rpc.ts
CHANGED
|
@@ -288,7 +288,7 @@ export function apply(ctx: Context): void {
|
|
|
288
288
|
}
|
|
289
289
|
return fail(`Unknown endpoint: ${endpoint}`)
|
|
290
290
|
}
|
|
291
|
-
const disposeRpc = ctx.connection.rpc.handle(MAESTRO_RPC_CHANNEL, handler
|
|
291
|
+
const disposeRpc = ctx.connection.rpc.handle(MAESTRO_RPC_CHANNEL, handler)
|
|
292
292
|
|
|
293
293
|
ctx.effect(() => () => { disposeRpc(); }, 'maestro-settings-rpc teardown')
|
|
294
294
|
}
|
|
@@ -26,9 +26,12 @@ export function resolveSkillsDir(fromDir: string): string {
|
|
|
26
26
|
|
|
27
27
|
/** Minimal frontmatter reader for our own SKILL.md — enough for the provider contract. */
|
|
28
28
|
function parseFrontmatter(raw: string): { name: string; description: string; body: string } {
|
|
29
|
-
|
|
29
|
+
// `\r?\n` on both delimiters and on the line split: a SKILL.md checked out
|
|
30
|
+
// with CRLF (git core.autocrlf, a Windows editor) otherwise parses to an
|
|
31
|
+
// empty description with no error at all.
|
|
32
|
+
const m = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/)
|
|
30
33
|
if (!m) return { name: SKILL_NAME, description: '', body: raw }
|
|
31
|
-
const fm = m[1].split(
|
|
34
|
+
const fm = m[1].split(/\r?\n/).reduce<Record<string, string>>((acc, line) => {
|
|
32
35
|
const kv = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/)
|
|
33
36
|
if (kv) acc[kv[1]] = kv[2].replace(/^["']|["']$/g, '')
|
|
34
37
|
return acc
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The producer-owned source kind this plugin stamps on every message it injects
|
|
3
|
+
* into a review session.
|
|
4
|
+
*
|
|
5
|
+
* Session format v4 requires the producer to name itself (`plugin:<package>`)
|
|
6
|
+
* and rejects the retired bare `kind: 'plugin'`. `kind: 'user'` is admissible
|
|
7
|
+
* but false: these prompts are machine-initiated, and consumers classify a turn
|
|
8
|
+
* by this kind — dsh-maestro-memory's write guard documents that
|
|
9
|
+
* plugin-initiated turns carry no per-turn write duty.
|
|
10
|
+
*
|
|
11
|
+
* The reviewer and auditor sessions keep their own explicit
|
|
12
|
+
* `sessionTitle.rename(...)`: the harness only auto-titles a `kind: 'user'`
|
|
13
|
+
* message, so a plugin-attributed prompt feeds no title.
|
|
14
|
+
*/
|
|
15
|
+
export const REVIEW_SOURCE_KIND = 'plugin:@ddtcorex/dsh-maestro-review'
|
|
16
|
+
|
|
17
|
+
// `MessageSourceMap` is the harness's merge-extensible sum type: each producer
|
|
18
|
+
// declares its own kind in its own module (see `goal-round-driver` and
|
|
19
|
+
// `schedule`), and there is deliberately no shared catch-all kind to reuse.
|
|
20
|
+
import type {} from '@deepseek-ai/dsh-llm'
|
|
21
|
+
|
|
22
|
+
declare module '@deepseek-ai/dsh-llm' {
|
|
23
|
+
interface MessageSourceMap {
|
|
24
|
+
'plugin:@ddtcorex/dsh-maestro-review': { readonly kind: 'plugin:@ddtcorex/dsh-maestro-review' }
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -3,7 +3,7 @@ stages: [review]
|
|
|
3
3
|
|
|
4
4
|
variables:
|
|
5
5
|
# Image registry — pin the SHA for reproducibility
|
|
6
|
-
REVIEWER_IMAGE: "ddtcorex/maestro-reviewer:0.
|
|
6
|
+
REVIEWER_IMAGE: "ddtcorex/maestro-reviewer:0.10.0"
|
|
7
7
|
# Or use $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA when building the image in the same project
|
|
8
8
|
|
|
9
9
|
review:
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
- id: persona
|
|
2
|
-
name: '@deepseek-ai/dsh-persona'
|
|
3
|
-
config:
|
|
4
|
-
# The working directory varies per session, so it belongs in the suffix: the
|
|
5
|
-
# prefix is the model-stable part of the prompt that stays cacheable. The row
|
|
6
|
-
# must restate the suffix because an empty one shadows the deployment's away.
|
|
7
|
-
suffix: Your working directory is {{cwd}}.
|
|
8
|
-
prefix: |
|
|
9
|
-
You are Maestro Auditor, a Performance Architect. Workflow:
|
|
10
|
-
1. Call govard_env_up to bring up the merge request's Magento 2 environment.
|
|
11
|
-
2. Call govard_shell to run the test suite (e.g. "vendor/bin/phpunit") and any profiling commands.
|
|
12
|
-
3. Analyze the output for regressions, N+1 queries, or memory issues.
|
|
13
|
-
4. Call govard_env_down to tear the environment down.
|
|
14
|
-
5. Output a Markdown report. Do not call gitlab_post_mr_comment yourself — the orchestrator posts the combined report.
|
|
15
|
-
|
|
16
|
-
# Delegation tools: the providers live in the Profile
|
|
17
|
-
# (`subagent-codex` + `subagent-claude-code` rows), so a deployment without
|
|
18
|
-
# those bundles gets inert rows — `tool-subagent` registers no tool until its
|
|
19
|
-
# provider appears — rather than a failed mount. One-shot rows: a review
|
|
20
|
-
# delegates a bounded task and collects the result.
|
|
21
|
-
- id: tool-subagent-codex
|
|
22
|
-
name: '@deepseek-ai/dsh-tool-subagent'
|
|
23
|
-
config:
|
|
24
|
-
provider: codex
|
|
25
|
-
toolName: subagent_codex
|
|
26
|
-
backgroundMode: one-shot
|
|
27
|
-
maxDepth: provider-managed
|
|
28
|
-
|
|
29
|
-
- id: tool-subagent-claude-code
|
|
30
|
-
name: '@deepseek-ai/dsh-tool-subagent'
|
|
31
|
-
config:
|
|
32
|
-
provider: claude-code
|
|
33
|
-
toolName: subagent_claude_code
|
|
34
|
-
backgroundMode: one-shot
|
|
35
|
-
maxDepth: provider-managed
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
- id: persona
|
|
2
|
-
name: '@deepseek-ai/dsh-persona'
|
|
3
|
-
config:
|
|
4
|
-
# The working directory varies per session, so it belongs in the suffix: the
|
|
5
|
-
# prefix is the model-stable part of the prompt that stays cacheable. The row
|
|
6
|
-
# must restate the suffix because an empty one shadows the deployment's away.
|
|
7
|
-
suffix: Your working directory is {{cwd}}.
|
|
8
|
-
prefix: |
|
|
9
|
-
You are Maestro Reviewer, an AI Tech Lead. Workflow:
|
|
10
|
-
1. If the review request names a profile, call maestro_load_review_profile with that profile before inspecting code — it fails closed if the required skill set is incomplete. For a diff-only review with no local checkout or Magento environment, skip this step: there is no profile to load, and the diff is all the context you need.
|
|
11
|
-
2. Call gitlab_list_own_review_threads to see which findings you already raised on this merge request.
|
|
12
|
-
3. Call gitlab_get_mr_diff to read the current diff.
|
|
13
|
-
4. For each existing thread whose file/line was touched by the new commits, decide whether it still applies, looks fixed, or needs a different comment — reply to it (status: "reply"). Never resolve a thread yourself.
|
|
14
|
-
5. For genuinely new issues with no existing thread, prepare a new inline comment (status: "new").
|
|
15
|
-
6. Call report_review_findings exactly once with your complete list of findings, then stop. Do not call gitlab_post_mr_comment, gitlab_post_inline_comment, or gitlab_reply_to_thread yourself — the orchestrator posts them from your report_review_findings call.
|
|
16
|
-
|
|
17
|
-
- id: skills-tool
|
|
18
|
-
name: '@ddtcorex/dsh-maestro-review/lib/skills-tool.js'
|
|
19
|
-
|
|
20
|
-
# Delegation tools: the providers live in the Profile
|
|
21
|
-
# (`subagent-codex` + `subagent-claude-code` rows), so a deployment without
|
|
22
|
-
# those bundles gets inert rows — `tool-subagent` registers no tool until its
|
|
23
|
-
# provider appears — rather than a failed mount. One-shot rows: a review
|
|
24
|
-
# delegates a bounded task and collects the result.
|
|
25
|
-
- id: tool-subagent-codex
|
|
26
|
-
name: '@deepseek-ai/dsh-tool-subagent'
|
|
27
|
-
config:
|
|
28
|
-
provider: codex
|
|
29
|
-
toolName: subagent_codex
|
|
30
|
-
backgroundMode: one-shot
|
|
31
|
-
maxDepth: provider-managed
|
|
32
|
-
|
|
33
|
-
- id: tool-subagent-claude-code
|
|
34
|
-
name: '@deepseek-ai/dsh-tool-subagent'
|
|
35
|
-
config:
|
|
36
|
-
provider: claude-code
|
|
37
|
-
toolName: subagent_claude_code
|
|
38
|
-
backgroundMode: one-shot
|
|
39
|
-
maxDepth: provider-managed
|