oh-my-opencode 5.0.0-beta.37 → 5.0.0-beta.38

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 (67) hide show
  1. package/dist/cli/index.js +24 -15
  2. package/dist/cli-node/index.js +24 -15
  3. package/dist/features/background-agent/compaction-aware-message-resolver.d.ts +1 -0
  4. package/dist/hooks/compaction-context-injector/validated-model.d.ts +2 -0
  5. package/dist/index.js +36 -24
  6. package/dist/shared/compaction-agent-config-checkpoint.d.ts +1 -0
  7. package/package.json +13 -13
  8. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  9. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +10 -1
  10. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  11. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  12. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  13. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  14. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  15. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  16. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  17. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  18. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  19. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  20. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  21. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  22. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  23. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  24. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  25. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  26. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  27. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  28. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  29. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +2 -2
  30. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  31. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +32 -20
  32. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-artifacts.d.ts +3 -0
  33. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-artifacts.js +31 -29
  34. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.js +2 -2
  35. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  36. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  37. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +2 -0
  38. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-artifacts.ts +36 -35
  39. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate.ts +2 -1
  40. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate.test.ts +43 -3
  41. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  42. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  43. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  44. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  45. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  46. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  47. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  48. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  49. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  50. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  51. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  52. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  53. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  54. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  55. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  56. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  57. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-ulw-execute-continuation.json +1 -1
  58. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  59. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  60. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  61. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  62. package/packages/omo-codex/plugin/package-lock.json +12 -12
  63. package/packages/omo-codex/plugin/package.json +1 -1
  64. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +2 -0
  65. package/packages/omo-codex/scripts/install-config-autonomous-features.test.mjs +1 -1
  66. package/packages/omo-codex/scripts/install-config-autonomous.test.mjs +2 -1
  67. package/packages/omo-codex/scripts/install-dist/install-local.mjs +12 -3
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/ulw-execute-continuation/dist/cli.js\" hook stop",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 5.0.0-beta.37) Checking Ulw-Execute Continuation"
10
+ "statusMessage": "(OmO 5.0.0-beta.38) Checking Ulw-Execute Continuation"
11
11
  }
12
12
  ]
13
13
  }
@@ -19,7 +19,7 @@
19
19
  "type": "command",
20
20
  "command": "node \"${PLUGIN_ROOT}/components/ulw-execute-continuation/dist/cli.js\" hook subagent-stop",
21
21
  "timeout": 10,
22
- "statusMessage": "(OmO 5.0.0-beta.37) Checking Ulw-Execute Continuation"
22
+ "statusMessage": "(OmO 5.0.0-beta.38) Checking Ulw-Execute Continuation"
23
23
  }
24
24
  ]
25
25
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-ulw-execute-continuation",
3
- "version": "5.0.0-beta.37",
3
+ "version": "5.0.0-beta.38",
4
4
  "description": "Codex Stop hook continuation injector for omo-codex ulw-execute plans.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",
@@ -768,34 +768,46 @@ function literal(value, expected, field) {
768
768
  }
769
769
 
770
770
  // components/ulw-loop/src/quality-gate-artifacts.ts
771
+ var SUPPORTED_SURFACES = ["cli", "http", "tmux", "browser", "gui", "data"];
772
+ var SUPPORTED_KINDS = [
773
+ "cli-transcript",
774
+ "log",
775
+ "screenshot",
776
+ "image",
777
+ "http-dump",
778
+ "data-diff"
779
+ ];
780
+ var COMPATIBLE_KINDS = {
781
+ cli: ["cli-transcript", "log"],
782
+ tmux: ["cli-transcript", "log"],
783
+ http: ["http-dump"],
784
+ browser: ["screenshot", "image"],
785
+ gui: ["screenshot", "image"],
786
+ data: ["data-diff"]
787
+ };
788
+ function isSupportedSurface(value) {
789
+ return SUPPORTED_SURFACES.some((surface) => surface === value);
790
+ }
791
+ function isSupportedKind(value) {
792
+ return SUPPORTED_KINDS.some((kind) => kind === value);
793
+ }
771
794
  function surfaceField(value, field) {
772
- if (value === "cli" || value === "http" || value === "tmux" || value === "browser" || value === "gui" || value === "data")
795
+ if (isSupportedSurface(value))
773
796
  return value;
774
- invalid(`${field} must be a supported manual QA surface.`, field);
797
+ invalid(`${field} must be a supported manual QA surface (${SUPPORTED_SURFACES.join(", ")}).`, field);
775
798
  return "cli";
776
799
  }
777
800
  function kindField(value, field) {
778
- if (value === "cli-transcript" || value === "log" || value === "screenshot" || value === "image" || value === "http-dump" || value === "data-diff")
801
+ if (isSupportedKind(value))
779
802
  return value;
780
- invalid(`${field} must be a supported artifact kind.`, field);
803
+ invalid(`${field} must be a supported artifact kind (${SUPPORTED_KINDS.join(", ")}); review/QA reports belong in codeReview.reportPath or gateReview.reportPath, not artifactRefs.`, field);
781
804
  return "log";
782
805
  }
806
+ function compatibleKindsFor(surface) {
807
+ return COMPATIBLE_KINDS[surface];
808
+ }
783
809
  function artifactCompatible(surface, kind) {
784
- switch (surface) {
785
- case "cli":
786
- case "tmux":
787
- return kind === "cli-transcript" || kind === "log";
788
- case "http":
789
- return kind === "http-dump";
790
- case "browser":
791
- case "gui":
792
- return kind === "screenshot" || kind === "image";
793
- case "data":
794
- return kind === "data-diff";
795
- default:
796
- invalid("manualQa.surfaceEvidence has an unsupported surface.", "manualQa.surfaceEvidence.surface");
797
- return false;
798
- }
810
+ return compatibleKindsFor(surface).includes(kind);
799
811
  }
800
812
  function checkFile(path, field, opts) {
801
813
  if (opts?.repoRoot === undefined || opts.fs === undefined || isPoisoned(field))
@@ -1098,7 +1110,7 @@ function parseSurfaceEvidence(value, byId) {
1098
1110
  if (isPoisoned(`manualQa.surfaceEvidence[${index}].surface`) || isPoisonedArtifactKind(artifact.id))
1099
1111
  continue;
1100
1112
  if (!artifactCompatible(surface, artifact.kind)) {
1101
- invalid(`manualQa.surfaceEvidence ${surface} artifact ${artifact.kind} is incompatible.`, "manualQa.surfaceEvidence");
1113
+ invalid(`manualQa.surfaceEvidence ${surface} artifact ${artifact.kind} is incompatible; surface "${surface}" accepts artifact kinds: ${compatibleKindsFor(surface).join(", ")}.`, "manualQa.surfaceEvidence");
1102
1114
  }
1103
1115
  }
1104
1116
  return {
@@ -1,7 +1,10 @@
1
1
  import type { ValidateQualityGateOptions } from "./quality-gate.js";
2
2
  import type { UlwLoopManualQaArtifactKind, UlwLoopManualQaArtifactRef, UlwLoopManualQaSurface } from "./types.js";
3
+ export declare const SUPPORTED_SURFACES: readonly UlwLoopManualQaSurface[];
4
+ export declare const SUPPORTED_KINDS: readonly UlwLoopManualQaArtifactKind[];
3
5
  export declare function surfaceField(value: unknown, field: string): UlwLoopManualQaSurface;
4
6
  export declare function kindField(value: unknown, field: string): UlwLoopManualQaArtifactKind;
7
+ export declare function compatibleKindsFor(surface: UlwLoopManualQaSurface): readonly UlwLoopManualQaArtifactKind[];
5
8
  export declare function artifactCompatible(surface: UlwLoopManualQaSurface, kind: UlwLoopManualQaArtifactKind): boolean;
6
9
  export declare function checkFile(path: string, field: string, opts?: ValidateQualityGateOptions): void;
7
10
  export declare function artifactMap(refs: readonly UlwLoopManualQaArtifactRef[]): Map<string, UlwLoopManualQaArtifactRef>;
@@ -1,44 +1,46 @@
1
1
  import { resolve } from "node:path";
2
2
  import { isWithinAttemptDir } from "./paths.js";
3
3
  import { invalid, isPoisoned, markPoisonedArtifactKind, section, stringArray, textField, } from "./quality-gate-fields.js";
4
+ export const SUPPORTED_SURFACES = ["cli", "http", "tmux", "browser", "gui", "data"];
5
+ export const SUPPORTED_KINDS = [
6
+ "cli-transcript",
7
+ "log",
8
+ "screenshot",
9
+ "image",
10
+ "http-dump",
11
+ "data-diff",
12
+ ];
13
+ const COMPATIBLE_KINDS = {
14
+ cli: ["cli-transcript", "log"],
15
+ tmux: ["cli-transcript", "log"],
16
+ http: ["http-dump"],
17
+ browser: ["screenshot", "image"],
18
+ gui: ["screenshot", "image"],
19
+ data: ["data-diff"],
20
+ };
21
+ function isSupportedSurface(value) {
22
+ return SUPPORTED_SURFACES.some((surface) => surface === value);
23
+ }
24
+ function isSupportedKind(value) {
25
+ return SUPPORTED_KINDS.some((kind) => kind === value);
26
+ }
4
27
  export function surfaceField(value, field) {
5
- if (value === "cli" ||
6
- value === "http" ||
7
- value === "tmux" ||
8
- value === "browser" ||
9
- value === "gui" ||
10
- value === "data")
28
+ if (isSupportedSurface(value))
11
29
  return value;
12
- invalid(`${field} must be a supported manual QA surface.`, field);
30
+ invalid(`${field} must be a supported manual QA surface (${SUPPORTED_SURFACES.join(", ")}).`, field);
13
31
  return "cli";
14
32
  }
15
33
  export function kindField(value, field) {
16
- if (value === "cli-transcript" ||
17
- value === "log" ||
18
- value === "screenshot" ||
19
- value === "image" ||
20
- value === "http-dump" ||
21
- value === "data-diff")
34
+ if (isSupportedKind(value))
22
35
  return value;
23
- invalid(`${field} must be a supported artifact kind.`, field);
36
+ invalid(`${field} must be a supported artifact kind (${SUPPORTED_KINDS.join(", ")}); review/QA reports belong in codeReview.reportPath or gateReview.reportPath, not artifactRefs.`, field);
24
37
  return "log";
25
38
  }
39
+ export function compatibleKindsFor(surface) {
40
+ return COMPATIBLE_KINDS[surface];
41
+ }
26
42
  export function artifactCompatible(surface, kind) {
27
- switch (surface) {
28
- case "cli":
29
- case "tmux":
30
- return kind === "cli-transcript" || kind === "log";
31
- case "http":
32
- return kind === "http-dump";
33
- case "browser":
34
- case "gui":
35
- return kind === "screenshot" || kind === "image";
36
- case "data":
37
- return kind === "data-diff";
38
- default:
39
- invalid("manualQa.surfaceEvidence has an unsupported surface.", "manualQa.surfaceEvidence.surface");
40
- return false;
41
- }
43
+ return compatibleKindsFor(surface).includes(kind);
42
44
  }
43
45
  export function checkFile(path, field, opts) {
44
46
  if (opts?.repoRoot === undefined || opts.fs === undefined || isPoisoned(field))
@@ -1,4 +1,4 @@
1
- import { artifactCompatible, artifactMap, checkFile, parseArtifactRefs, referencedArtifacts, surfaceField, } from "./quality-gate-artifacts.js";
1
+ import { artifactCompatible, artifactMap, checkFile, compatibleKindsFor, parseArtifactRefs, referencedArtifacts, surfaceField, } from "./quality-gate-artifacts.js";
2
2
  import { emptyBlockers, invalid, isPoisoned, isPoisonedArtifactKind, literal, numberField, section, stringArray, textField, withQualityGateCollector, } from "./quality-gate-fields.js";
3
3
  import { adversarialVerdict, codeQualityStatusField, passedVerdict } from "./quality-gate-verdicts.js";
4
4
  import { GATE_SECTION_BY_ACCEPTOR } from "./surface.js";
@@ -118,7 +118,7 @@ function parseSurfaceEvidence(value, byId) {
118
118
  if (isPoisoned(`manualQa.surfaceEvidence[${index}].surface`) || isPoisonedArtifactKind(artifact.id))
119
119
  continue;
120
120
  if (!artifactCompatible(surface, artifact.kind)) {
121
- invalid(`manualQa.surfaceEvidence ${surface} artifact ${artifact.kind} is incompatible.`, "manualQa.surfaceEvidence");
121
+ invalid(`manualQa.surfaceEvidence ${surface} artifact ${artifact.kind} is incompatible; surface "${surface}" accepts artifact kinds: ${compatibleKindsFor(surface).join(", ")}.`, "manualQa.surfaceEvidence");
122
122
  }
123
123
  }
124
124
  return {
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook user-prompt-submit --with-ultrawork",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 5.0.0-beta.37) Checking Ulw-Loop Steering"
10
+ "statusMessage": "(OmO 5.0.0-beta.38) Checking Ulw-Loop Steering"
11
11
  }
12
12
  ]
13
13
  }
@@ -20,7 +20,7 @@
20
20
  "type": "command",
21
21
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook pre-tool-use",
22
22
  "timeout": 5,
23
- "statusMessage": "(OmO 5.0.0-beta.37) Enforcing Unlimited Ulw-Loop Budget"
23
+ "statusMessage": "(OmO 5.0.0-beta.38) Enforcing Unlimited Ulw-Loop Budget"
24
24
  }
25
25
  ]
26
26
  },
@@ -31,7 +31,7 @@
31
31
  "type": "command",
32
32
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook pre-tool-use-spawn",
33
33
  "timeout": 5,
34
- "statusMessage": "(OmO 5.0.0-beta.37) Guarding Ulw-Loop Spawns"
34
+ "statusMessage": "(OmO 5.0.0-beta.38) Guarding Ulw-Loop Spawns"
35
35
  }
36
36
  ]
37
37
  }
@@ -43,7 +43,7 @@
43
43
  "type": "command",
44
44
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook stop",
45
45
  "timeout": 10,
46
- "statusMessage": "(OmO 5.0.0-beta.37) Checking Ulw-Loop Resume"
46
+ "statusMessage": "(OmO 5.0.0-beta.38) Checking Ulw-Loop Resume"
47
47
  }
48
48
  ]
49
49
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-ulw-loop",
3
- "version": "5.0.0-beta.37",
3
+ "version": "5.0.0-beta.38",
4
4
  "description": "Codex plugin: durable repo-native multi-goal orchestration with embedded success criteria and observable evidence audit.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",
@@ -210,6 +210,8 @@ Trigger only for the final aggregate goal after every criterion in every goal is
210
210
  ```sh
211
211
  omo-agent-toolkit ulw-loop checkpoint --goal-id <id> --status complete --evidence "<e2e evidence + manual QA notes>" --codex-goal-json <snapshot> --quality-gate-json <json-or-path> --json
212
212
  ```
213
+ `--quality-gate-json` shape. In `manualQa.artifactRefs`, `kind` must be one of `cli-transcript`, `log`, `screenshot`, `image`, `http-dump`, or `data-diff`; review and QA reports belong in `codeReview.reportPath` or `gateReview.reportPath`, not `artifactRefs`. `surfaceEvidence.surface` must be one of `cli`, `http`, `tmux`, `browser`, `gui`, or `data`. Compatibility is `cli`/`tmux` -> `cli-transcript`/`log`, `http` -> `http-dump`, `browser`/`gui` -> `screenshot`/`image`, and `data` -> `data-diff`.
214
+
213
215
  `--quality-gate-json` shape:
214
216
  ```json
215
217
  {
@@ -11,48 +11,49 @@ import {
11
11
  } from "./quality-gate-fields.js";
12
12
  import type { UlwLoopManualQaArtifactKind, UlwLoopManualQaArtifactRef, UlwLoopManualQaSurface } from "./types.js";
13
13
 
14
+ export const SUPPORTED_SURFACES: readonly UlwLoopManualQaSurface[] = ["cli", "http", "tmux", "browser", "gui", "data"];
15
+ export const SUPPORTED_KINDS: readonly UlwLoopManualQaArtifactKind[] = [
16
+ "cli-transcript",
17
+ "log",
18
+ "screenshot",
19
+ "image",
20
+ "http-dump",
21
+ "data-diff",
22
+ ];
23
+ const COMPATIBLE_KINDS: Readonly<Record<UlwLoopManualQaSurface, readonly UlwLoopManualQaArtifactKind[]>> = {
24
+ cli: ["cli-transcript", "log"],
25
+ tmux: ["cli-transcript", "log"],
26
+ http: ["http-dump"],
27
+ browser: ["screenshot", "image"],
28
+ gui: ["screenshot", "image"],
29
+ data: ["data-diff"],
30
+ };
31
+
32
+ function isSupportedSurface(value: unknown): value is UlwLoopManualQaSurface {
33
+ return SUPPORTED_SURFACES.some((surface) => surface === value);
34
+ }
35
+ function isSupportedKind(value: unknown): value is UlwLoopManualQaArtifactKind {
36
+ return SUPPORTED_KINDS.some((kind) => kind === value);
37
+ }
38
+
14
39
  export function surfaceField(value: unknown, field: string): UlwLoopManualQaSurface {
15
- if (
16
- value === "cli" ||
17
- value === "http" ||
18
- value === "tmux" ||
19
- value === "browser" ||
20
- value === "gui" ||
21
- value === "data"
22
- )
23
- return value;
24
- invalid(`${field} must be a supported manual QA surface.`, field);
40
+ if (isSupportedSurface(value)) return value;
41
+ invalid(`${field} must be a supported manual QA surface (${SUPPORTED_SURFACES.join(", ")}).`, field);
25
42
  return "cli";
26
43
  }
27
44
  export function kindField(value: unknown, field: string): UlwLoopManualQaArtifactKind {
28
- if (
29
- value === "cli-transcript" ||
30
- value === "log" ||
31
- value === "screenshot" ||
32
- value === "image" ||
33
- value === "http-dump" ||
34
- value === "data-diff"
35
- )
36
- return value;
37
- invalid(`${field} must be a supported artifact kind.`, field);
45
+ if (isSupportedKind(value)) return value;
46
+ invalid(
47
+ `${field} must be a supported artifact kind (${SUPPORTED_KINDS.join(", ")}); review/QA reports belong in codeReview.reportPath or gateReview.reportPath, not artifactRefs.`,
48
+ field,
49
+ );
38
50
  return "log";
39
51
  }
52
+ export function compatibleKindsFor(surface: UlwLoopManualQaSurface): readonly UlwLoopManualQaArtifactKind[] {
53
+ return COMPATIBLE_KINDS[surface];
54
+ }
40
55
  export function artifactCompatible(surface: UlwLoopManualQaSurface, kind: UlwLoopManualQaArtifactKind): boolean {
41
- switch (surface) {
42
- case "cli":
43
- case "tmux":
44
- return kind === "cli-transcript" || kind === "log";
45
- case "http":
46
- return kind === "http-dump";
47
- case "browser":
48
- case "gui":
49
- return kind === "screenshot" || kind === "image";
50
- case "data":
51
- return kind === "data-diff";
52
- default:
53
- invalid("manualQa.surfaceEvidence has an unsupported surface.", "manualQa.surfaceEvidence.surface");
54
- return false;
55
- }
56
+ return compatibleKindsFor(surface).includes(kind);
56
57
  }
57
58
  export function checkFile(path: string, field: string, opts?: ValidateQualityGateOptions): void {
58
59
  if (opts?.repoRoot === undefined || opts.fs === undefined || isPoisoned(field)) return;
@@ -2,6 +2,7 @@ import {
2
2
  artifactCompatible,
3
3
  artifactMap,
4
4
  checkFile,
5
+ compatibleKindsFor,
5
6
  parseArtifactRefs,
6
7
  referencedArtifacts,
7
8
  surfaceField,
@@ -169,7 +170,7 @@ function parseSurfaceEvidence(
169
170
  if (isPoisoned(`manualQa.surfaceEvidence[${index}].surface`) || isPoisonedArtifactKind(artifact.id)) continue;
170
171
  if (!artifactCompatible(surface, artifact.kind)) {
171
172
  invalid(
172
- `manualQa.surfaceEvidence ${surface} artifact ${artifact.kind} is incompatible.`,
173
+ `manualQa.surfaceEvidence ${surface} artifact ${artifact.kind} is incompatible; surface "${surface}" accepts artifact kinds: ${compatibleKindsFor(surface).join(", ")}.`,
173
174
  "manualQa.surfaceEvidence",
174
175
  );
175
176
  }
@@ -166,20 +166,60 @@ describe("validateQualityGate", () => {
166
166
  expect(error.message).toContain("missing-artifact");
167
167
  });
168
168
 
169
- it("#given incompatible surface artifact kind #when validated #then it rejects the gate", () => {
169
+ it("#given incompatible surface artifact kind #when validated #then it rejects the gate with compatible kinds", () => {
170
170
  // when
171
171
  const error = getQualityGateError(
172
172
  makeGate({
173
173
  manualQa: {
174
174
  ...VALID_GATE.manualQa,
175
- artifactRefs: [{ ...VALID_GATE.manualQa.artifactRefs[0], kind: "http-dump" }],
175
+ artifactRefs: [
176
+ { ...VALID_GATE.manualQa.artifactRefs[0], kind: "http-dump" },
177
+ VALID_GATE.manualQa.artifactRefs[1],
178
+ ],
176
179
  },
177
180
  }),
178
181
  );
179
182
 
180
183
  // then
181
184
  expect(error.code).toBe("ULW_LOOP_QUALITY_GATE_INVALID");
182
- expect(error.message).toContain("cli");
185
+ expect(error.message).toContain(
186
+ 'manualQa.surfaceEvidence cli artifact http-dump is incompatible; surface "cli" accepts artifact kinds: cli-transcript, log.',
187
+ );
188
+ });
189
+
190
+ it("#given an unsupported artifact kind #when validated #then it lists allowed kinds and report path guidance", () => {
191
+ const error = getQualityGateError(
192
+ makeGate({
193
+ manualQa: {
194
+ ...VALID_GATE.manualQa,
195
+ artifactRefs: [
196
+ { ...VALID_GATE.manualQa.artifactRefs[0], kind: "review-report" },
197
+ VALID_GATE.manualQa.artifactRefs[1],
198
+ ],
199
+ },
200
+ }),
201
+ );
202
+
203
+ expect(error.code).toBe("ULW_LOOP_QUALITY_GATE_INVALID");
204
+ expect(error.message).toContain(
205
+ "manualQa.artifactRefs[0].kind must be a supported artifact kind (cli-transcript, log, screenshot, image, http-dump, data-diff); review/QA reports belong in codeReview.reportPath or gateReview.reportPath, not artifactRefs.",
206
+ );
207
+ });
208
+
209
+ it("#given an unsupported manual QA surface #when validated #then it lists allowed surfaces", () => {
210
+ const error = getQualityGateError(
211
+ makeGate({
212
+ manualQa: {
213
+ ...VALID_GATE.manualQa,
214
+ surfaceEvidence: [{ ...VALID_GATE.manualQa.surfaceEvidence[0], surface: "terminal" }],
215
+ },
216
+ }),
217
+ );
218
+
219
+ expect(error.code).toBe("ULW_LOOP_QUALITY_GATE_INVALID");
220
+ expect(error.message).toContain(
221
+ "manualQa.surfaceEvidence[0].surface must be a supported manual QA surface (cli, http, tmux, browser, gui, data).",
222
+ );
183
223
  });
184
224
 
185
225
  it("#given placeholder evidence and artifact path #when validated #then it rejects placeholders", () => {
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/git-bash/dist/cli.js\" hook post-compact",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 5.0.0-beta.37) Resetting Git Bash MCP Reminder",
10
+ "statusMessage": "(OmO 5.0.0-beta.38) Resetting Git Bash MCP Reminder",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\git-bash\\dist\\cli.js\" hook post-compact"
12
12
  }
13
13
  ],
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/lsp/dist/cli.js\" hook post-compact",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 5.0.0-beta.37) Resetting LSP Diagnostics Cache",
10
+ "statusMessage": "(OmO 5.0.0-beta.38) Resetting LSP Diagnostics Cache",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\lsp\\dist\\cli.js\" hook post-compact"
12
12
  }
13
13
  ],
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/rules/dist/cli.js\" hook post-compact",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 5.0.0-beta.37) Resetting Project Rule Cache",
10
+ "statusMessage": "(OmO 5.0.0-beta.38) Resetting Project Rule Cache",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\rules\\dist\\cli.js\" hook post-compact"
12
12
  }
13
13
  ],
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/comment-checker/dist/cli.js\" hook post-tool-use",
9
9
  "timeout": 30,
10
- "statusMessage": "(OmO 5.0.0-beta.37) Checking Comments",
10
+ "statusMessage": "(OmO 5.0.0-beta.38) Checking Comments",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\comment-checker\\dist\\cli.js\" hook post-tool-use"
12
12
  }
13
13
  ],
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/lsp/dist/cli.js\" hook post-tool-use",
9
9
  "timeout": 60,
10
- "statusMessage": "(OmO 5.0.0-beta.37) Checking LSP Diagnostics",
10
+ "statusMessage": "(OmO 5.0.0-beta.38) Checking LSP Diagnostics",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\lsp\\dist\\cli.js\" hook post-tool-use"
12
12
  }
13
13
  ],
@@ -8,7 +8,7 @@
8
8
  "type": "command",
9
9
  "command": "node \"${PLUGIN_ROOT}/components/teammode/dist/cli.js\" hook post-tool-use",
10
10
  "timeout": 10,
11
- "statusMessage": "(OmO 5.0.0-beta.37) Checking Thread Title Hygiene",
11
+ "statusMessage": "(OmO 5.0.0-beta.38) Checking Thread Title Hygiene",
12
12
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\teammode\\dist\\cli.js\" hook post-tool-use"
13
13
  }
14
14
  ]
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/rules/dist/cli.js\" hook post-tool-use",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 5.0.0-beta.37) Matching Project Rules",
10
+ "statusMessage": "(OmO 5.0.0-beta.38) Matching Project Rules",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\rules\\dist\\cli.js\" hook post-tool-use"
12
12
  }
13
13
  ],
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/ulw-loop/dist/cli.js\" hook pre-tool-use",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 5.0.0-beta.37) Enforcing Unlimited Goal Budget",
10
+ "statusMessage": "(OmO 5.0.0-beta.38) Enforcing Unlimited Goal Budget",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ulw-loop\\dist\\cli.js\" hook pre-tool-use"
12
12
  }
13
13
  ],
@@ -8,7 +8,7 @@
8
8
  "type": "command",
9
9
  "command": "node \"${PLUGIN_ROOT}/components/ulw-loop/dist/cli.js\" hook pre-tool-use-spawn",
10
10
  "timeout": 5,
11
- "statusMessage": "(OmO 5.0.0-beta.37) Guarding Ulw-Loop Spawns",
11
+ "statusMessage": "(OmO 5.0.0-beta.38) Guarding Ulw-Loop Spawns",
12
12
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ulw-loop\\dist\\cli.js\" hook pre-tool-use-spawn"
13
13
  }
14
14
  ]
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/git-bash/dist/cli.js\" hook pre-tool-use",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 5.0.0-beta.37) Recommending Git Bash MCP",
10
+ "statusMessage": "(OmO 5.0.0-beta.38) Recommending Git Bash MCP",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\git-bash\\dist\\cli.js\" hook pre-tool-use"
12
12
  }
13
13
  ],
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/scripts/auto-update.mjs\" hook session-start",
9
9
  "timeout": 15,
10
- "statusMessage": "(OmO 5.0.0-beta.37) Checking Auto Update",
10
+ "statusMessage": "(OmO 5.0.0-beta.38) Checking Auto Update",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\scripts\\auto-update.mjs\" hook session-start"
12
12
  }
13
13
  ],
@@ -8,7 +8,7 @@
8
8
  "command": "node \"${PLUGIN_ROOT}/components/bootstrap/dist/cli.js\" hook session-start",
9
9
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\bootstrap.ps1\"",
10
10
  "timeout": 30,
11
- "statusMessage": "(OmO 5.0.0-beta.37) Checking Bootstrap Provisioning"
11
+ "statusMessage": "(OmO 5.0.0-beta.38) Checking Bootstrap Provisioning"
12
12
  }
13
13
  ]
14
14
  }
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/rules/dist/cli.js\" hook session-start",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 5.0.0-beta.37) Loading Project Rules",
10
+ "statusMessage": "(OmO 5.0.0-beta.38) Loading Project Rules",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\rules\\dist\\cli.js\" hook session-start"
12
12
  }
13
13
  ]
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/telemetry/dist/cli.js\" hook session-start",
9
9
  "timeout": 15,
10
- "statusMessage": "(OmO 5.0.0-beta.37) Recording Session Telemetry",
10
+ "statusMessage": "(OmO 5.0.0-beta.38) Recording Session Telemetry",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\telemetry\\dist\\cli.js\" hook session-start"
12
12
  }
13
13
  ]
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/ulw-execute-continuation/dist/cli.js\" hook stop",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 5.0.0-beta.37) Checking Ulw-Execute Continuation",
10
+ "statusMessage": "(OmO 5.0.0-beta.38) Checking Ulw-Execute Continuation",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ulw-execute-continuation\\dist\\cli.js\" hook stop"
12
12
  }
13
13
  ]
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/ulw-loop/dist/cli.js\" hook stop",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 5.0.0-beta.37) Checking Ulw-Loop Resume",
10
+ "statusMessage": "(OmO 5.0.0-beta.38) Checking Ulw-Loop Resume",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ulw-loop\\dist\\cli.js\" hook stop"
12
12
  }
13
13
  ]
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/ulw-execute-continuation/dist/cli.js\" hook subagent-stop",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 5.0.0-beta.37) Checking Ulw-Execute Continuation",
10
+ "statusMessage": "(OmO 5.0.0-beta.38) Checking Ulw-Execute Continuation",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ulw-execute-continuation\\dist\\cli.js\" hook subagent-stop"
12
12
  }
13
13
  ]
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/lazycodex-executor-verify/dist/cli.js\" hook subagent-stop",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 5.0.0-beta.37) Verifying LazyCodex Executor Evidence",
10
+ "statusMessage": "(OmO 5.0.0-beta.38) Verifying LazyCodex Executor Evidence",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\lazycodex-executor-verify\\dist\\cli.js\" hook subagent-stop"
12
12
  }
13
13
  ],
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/ultrawork/dist/cli.js\" hook user-prompt-submit",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 5.0.0-beta.37) Checking Ultrawork Trigger",
10
+ "statusMessage": "(OmO 5.0.0-beta.38) Checking Ultrawork Trigger",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ultrawork\\dist\\cli.js\" hook user-prompt-submit"
12
12
  }
13
13
  ]