@ddtcorex/dsh-maestro-review 0.5.1 → 0.6.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.
@@ -7,6 +7,17 @@
7
7
  # printed "Scope: all 2 workspace projects" and resolved relative to `../..`
8
8
  # without this file present).
9
9
  packages: []
10
+ # Postinstall scripts required at runtime (node-pty/subprocess-local spawn
11
+ # agents, koffi/protobufjs/genai serve model IO). Exact versions pinned in
12
+ # pnpm-lock.yaml; review on every profile dep bump.
13
+ allowBuilds:
14
+ '@deepseek-ai/dsh-subprocess-local': true
15
+ '@google/genai': true
16
+ koffi: true
17
+ node-pty: true
18
+ protobufjs: true
10
19
  minimumReleaseAgeExclude:
11
20
  - '@ddtcorex/dsh-maestro-review@0.3.1'
12
21
  - '@ddtcorex/maestro-skills@2.11.0'
22
+ - '@ddtcorex/dsh-maestro-review@0.5.1'
23
+ - '@ddtcorex/maestro-skills@2.11.1'
@@ -234,6 +234,22 @@ export function getTurnErrorMessage(handle: unknown): string | undefined {
234
234
  }
235
235
  }
236
236
 
237
+ /**
238
+ * A turn can go idle without ever calling a tool when the model provider
239
+ * itself rejects the request (auth/billing/rate-limit) — `whenIdleWithTimeout`
240
+ * only guards against a hang, not this. Left unchecked, the reviewer's
241
+ * missing-skill-profile check and the auditor's empty-output path both treat
242
+ * this the same as "the agent just didn't call anything", misreporting a
243
+ * provider outage as a maestro-skills installation problem (or, for the
244
+ * auditor, as a silent clean pass). Surface the real turn error immediately.
245
+ */
246
+ export function assertTurnSucceeded(handle: unknown): void {
247
+ const turnMsg = getTurnErrorMessage(handle)
248
+ if (turnMsg !== undefined) {
249
+ throw new Error(`Review turn failed before completing: ${turnMsg}`)
250
+ }
251
+ }
252
+
237
253
  /**
238
254
  * Resolve the model to use for an automated review. Priority: per-project
239
255
  * override > global reviewModel (Maestro Settings) > row-config reviewModel
@@ -1081,6 +1097,7 @@ export function apply(ctx: Context, config: Config): void {
1081
1097
  source: { kind: 'user' },
1082
1098
  }))
1083
1099
  await whenIdleWithTimeout(handle, effectiveAgentTimeoutMs)
1100
+ assertTurnSucceeded(handle)
1084
1101
  if (reviewProfile !== undefined && (reviewerContext === undefined || loadedReviewProfile(reviewerContext) !== reviewProfile)) {
1085
1102
  throw new Error(`reviewer did not successfully load the required ${reviewProfile} review skill profile; no findings were posted`)
1086
1103
  }
@@ -1178,6 +1195,7 @@ export function apply(ctx: Context, config: Config): void {
1178
1195
  const prompt = buildAuditorPrompt({ staticOnly: opts?.staticOnly === true })
1179
1196
  handle.agent.followup(createUserMessage({ content: [{ type: 'text', text: prompt }], source: { kind: 'user' } }))
1180
1197
  await whenIdleWithTimeout(handle, effectiveAgentTimeoutMs)
1198
+ assertTurnSucceeded(handle)
1181
1199
  const output = auditorOutputFromSession(handle.agent.session)
1182
1200
  const text = output.map(block => ('text' in block ? block.text : '')).join('')
1183
1201
  return `## Maestro Performance Audit\n\n${text}`
@@ -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:latest"
6
+ REVIEWER_IMAGE: "ddtcorex/maestro-reviewer:0.1.0"
7
7
  # Or use $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA when building the image in the same project
8
8
 
9
9
  review:
@@ -42,18 +42,21 @@ review:
42
42
  # the run would "complete" without ever posting. A human-tied PAT needs yearly
43
43
  # rotation; prefer a bot/group token where the instance allows creating one.
44
44
  # MAESTRO_GITLAB_TOKEN (api scope) — required
45
- # Route selection is key-based (entrypoint.sh swaps the baked settings variant):
46
- # OPENCODE_GO_API_KEY → opencode profile (default, host mirror; serves opencode-go
47
- # AND deepseek-official-via-zen). Set alone, or with DEEPSEEK_API_KEY (opencode wins).
48
- # DEEPSEEK_API_KEY → deepseek profile ONLY when OPENCODE_GO_API_KEY is absent
49
- # (deepseek-official straight from api.deepseek.com — needs a LIVE deepseek.com key).
45
+ # Model route selection — deepseek is the sole baked default; set
46
+ # REVIEW_LLM_API_KEY to overlay any OpenAI-compatible endpoint instead:
47
+ # DEEPSEEK_API_KEY (required unless using the route below) — deepseek-official
48
+ # straight from api.deepseek.com.
49
+ # REVIEW_LLM_API_KEY / REVIEW_LLM_BASE_URL / REVIEW_LLM_MODEL — bring-your-own
50
+ # OpenAI-compatible endpoint (self-hosted, Azure OpenAI, OpenRouter, a
51
+ # private gateway, ...). All three required together; the job fails closed
52
+ # if REVIEW_LLM_API_KEY is set without the other two. Optional
53
+ # REVIEW_LLM_API selects the wire protocol (openai-completions [default]
54
+ # or openai-responses).
50
55
  # TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID (optional)
51
- # Opencode model (optional, one variable — default muse-spark-1.3-contributor):
52
- # OPENCODE_MODEL: "muse-spark-1.3-contributor"
53
- # Model pin (optional, as a pair — unset both for the host-mirrored default
54
- # = opencode-go/muse-spark-1.3-contributor, baked in docker/ci-settings.yaml):
55
- # REVIEW_MODEL_PROVIDER: "opencode-go" # or "deepseek-official"
56
- # REVIEW_MODEL: "muse-spark-1.3-contributor" # e.g. deepseek-v4-flash (deepseek-official via zen)
56
+ # Model pin (optional, as a pair — unset both for the active route's default
57
+ # model, baked in docker/ci-settings.*.yaml):
58
+ # REVIEW_MODEL_PROVIDER: "deepseek-official" # or "custom-openai"
59
+ # REVIEW_MODEL: "deepseek-v4-flash" # the active route's model id
57
60
  # Only the provider's key is needed — no settings mount required. ID without
58
61
  # provider fails the review with a provider error (not silently the wrong
59
62
  # model); provider without ID is ignored.