@frankzhang2026/opencode-android-orchestrator 1.0.4 → 1.1.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.
Files changed (107) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +79 -18
  3. package/dist/config/queue-policy.d.ts.map +1 -1
  4. package/dist/config/queue-policy.js +1 -2
  5. package/dist/config/queue-policy.js.map +1 -1
  6. package/dist/doctor/index.d.ts.map +1 -1
  7. package/dist/doctor/index.js +14 -3
  8. package/dist/doctor/index.js.map +1 -1
  9. package/dist/doctor/installation.d.ts +1 -1
  10. package/dist/doctor/installation.d.ts.map +1 -1
  11. package/dist/doctor/installation.js +10 -1
  12. package/dist/doctor/installation.js.map +1 -1
  13. package/dist/index.d.ts +1 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +1 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/installer/adaptive-templates.d.ts +4 -1
  18. package/dist/installer/adaptive-templates.d.ts.map +1 -1
  19. package/dist/installer/adaptive-templates.js +49 -13
  20. package/dist/installer/adaptive-templates.js.map +1 -1
  21. package/dist/installer/android-project.d.ts +3 -1
  22. package/dist/installer/android-project.d.ts.map +1 -1
  23. package/dist/installer/android-project.js.map +1 -1
  24. package/dist/installer/capabilities-script.d.ts +2 -0
  25. package/dist/installer/capabilities-script.d.ts.map +1 -0
  26. package/dist/installer/capabilities-script.js +77 -0
  27. package/dist/installer/capabilities-script.js.map +1 -0
  28. package/dist/installer/gradle-verification.d.ts.map +1 -1
  29. package/dist/installer/gradle-verification.js +13 -6
  30. package/dist/installer/gradle-verification.js.map +1 -1
  31. package/dist/installer/init.d.ts.map +1 -1
  32. package/dist/installer/init.js +2 -1
  33. package/dist/installer/init.js.map +1 -1
  34. package/dist/installer/opencode-config.d.ts +3 -3
  35. package/dist/installer/opencode-config.js +1 -1
  36. package/dist/installer/project-capabilities.d.ts +35 -0
  37. package/dist/installer/project-capabilities.d.ts.map +1 -0
  38. package/dist/installer/project-capabilities.js +82 -0
  39. package/dist/installer/project-capabilities.js.map +1 -0
  40. package/dist/installer/upgrade.d.ts.map +1 -1
  41. package/dist/installer/upgrade.js +9 -1
  42. package/dist/installer/upgrade.js.map +1 -1
  43. package/dist/queue/cli.d.ts.map +1 -1
  44. package/dist/queue/cli.js +32 -5
  45. package/dist/queue/cli.js.map +1 -1
  46. package/dist/queue/executor.d.ts +1 -0
  47. package/dist/queue/executor.d.ts.map +1 -1
  48. package/dist/queue/executor.js +155 -11
  49. package/dist/queue/executor.js.map +1 -1
  50. package/dist/queue/process-ownership.d.ts +12 -0
  51. package/dist/queue/process-ownership.d.ts.map +1 -0
  52. package/dist/queue/process-ownership.js +58 -0
  53. package/dist/queue/process-ownership.js.map +1 -0
  54. package/dist/queue/queue.d.ts +25 -1
  55. package/dist/queue/queue.d.ts.map +1 -1
  56. package/dist/queue/queue.js +152 -11
  57. package/dist/queue/queue.js.map +1 -1
  58. package/dist/queue/service.d.ts.map +1 -1
  59. package/dist/queue/service.js +19 -2
  60. package/dist/queue/service.js.map +1 -1
  61. package/dist/queue/storage.d.ts +3 -1
  62. package/dist/queue/storage.d.ts.map +1 -1
  63. package/dist/queue/storage.js +25 -15
  64. package/dist/queue/storage.js.map +1 -1
  65. package/dist/queue/supervision.d.ts +38 -0
  66. package/dist/queue/supervision.d.ts.map +1 -0
  67. package/dist/queue/supervision.js +247 -0
  68. package/dist/queue/supervision.js.map +1 -0
  69. package/dist/queue/tools.d.ts.map +1 -1
  70. package/dist/queue/tools.js +4 -2
  71. package/dist/queue/tools.js.map +1 -1
  72. package/docs/MIGRATION.md +110 -9
  73. package/docs/QUEUE.md +360 -6
  74. package/docs/SECURITY.md +5 -2
  75. package/docs/TROUBLESHOOTING.md +82 -8
  76. package/package.json +1 -1
  77. package/templates/.opencode/agents/scheduled-coder.md +22 -0
  78. package/templates/.opencode/agents/scheduled-planner.md +73 -2
  79. package/templates/.opencode/skills/scheduled-quality-coder/SKILL.md +34 -2
  80. package/templates/.opencode/skills/scheduled-quality-orchestrator/SKILL.md +65 -4
  81. package/templates/.opencode/skills/scheduled-quality-reviewer/SKILL.md +22 -0
  82. package/templates/AGENTS.md.fragment +10 -4
  83. package/templates/README.md +3 -1
  84. package/templates/automation/config.schema.json +212 -22
  85. package/templates/automation/task-contract.schema.json +617 -21
  86. package/templates/automation/tasks/TASK-TEMPLATE.json.example +31 -3
  87. package/templates/automation/verification/collect.init.gradle +98 -0
  88. package/templates/automation/verification/contract.cjs +93 -0
  89. package/templates/automation/verification/inventory.cjs +433 -0
  90. package/templates/automation/verification/project.cjs +172 -0
  91. package/templates/automation/verification/recovery.cjs +426 -0
  92. package/templates/scripts/automation/acceptance-report.sh +29 -0
  93. package/templates/scripts/automation/claim-task.sh +35 -2
  94. package/templates/scripts/automation/integration-scope-gate.sh +3 -3
  95. package/templates/scripts/automation/lib.sh +167 -17
  96. package/templates/scripts/automation/orchestrate-task.sh +7 -1
  97. package/templates/scripts/automation/preflight.sh +1 -2
  98. package/templates/scripts/automation/quality-gate.sh +10 -1
  99. package/templates/scripts/automation/record-red.sh +182 -32
  100. package/templates/scripts/automation/resume-task.sh +3 -0
  101. package/templates/scripts/automation/scope-gate.sh +4 -4
  102. package/templates/scripts/automation/show-acceptance-review.sh +8 -0
  103. package/templates/scripts/automation/status.sh +38 -0
  104. package/templates/scripts/automation/submit-review.sh +10 -1
  105. package/templates/scripts/automation/validate-contract.sh +56 -3
  106. package/templates/scripts/automation/verify-integration.sh +3 -0
  107. package/templates/scripts/automation/verify-task.sh +17 -0
@@ -21,6 +21,28 @@ workspace_json="$(if [[ -f "$workspace_file" ]]; then jq -c . "$workspace_file";
21
21
  origin_json="$(if [[ -f "$origin_file" ]]; then jq -c . "$origin_file"; else printf 'null'; fi)"
22
22
  baseline_json="$(if [[ -f "$evidence_dir/baseline.json" ]]; then jq -c . "$evidence_dir/baseline.json"; else printf 'null'; fi)"
23
23
  red_json="$(if [[ -f "$evidence_dir/red.json" ]]; then jq -c . "$evidence_dir/red.json"; else printf 'null'; fi)"
24
+ preflight_json="$(if [[ -f "$evidence_dir/test-preflight.json" ]]; then jq -c . "$evidence_dir/test-preflight.json"; else printf 'null'; fi)"
25
+ manifest_json="$(if [[ -f "$evidence_dir/test-manifest.json" ]]; then jq -c . "$evidence_dir/test-manifest.json"; else printf 'null'; fi)"
26
+ inventory_baseline_json="$(if [[ -f "$evidence_dir/baseline-inventory.json" ]]; then jq -c . "$evidence_dir/baseline-inventory.json"; else printf 'null'; fi)"
27
+ inventory_green_json="$(if [[ -f "$evidence_dir/green-inventory.json" ]]; then jq -c . "$evidence_dir/green-inventory.json"; else printf 'null'; fi)"
28
+ inventory_status_json="$(if [[ -f "$evidence_dir/inventory-status.json" ]]; then jq -c . "$evidence_dir/inventory-status.json"; else printf 'null'; fi)"
29
+ baseline_recovery_json="$(if [[ -f "$evidence_dir/baseline-recovery.json" ]]; then jq -c . "$evidence_dir/baseline-recovery.json"; else printf 'null'; fi)"
30
+ stage_recovery_json='{}'
31
+ for phase in red green review; do
32
+ if [[ -f "$evidence_dir/stage-recovery/$phase.json" ]]; then
33
+ stage_recovery_json="$(jq -nc --argjson current "$stage_recovery_json" --arg phase "$phase" \
34
+ --slurpfile record "$evidence_dir/stage-recovery/$phase.json" '$current + {($phase): $record[0]}')"
35
+ fi
36
+ done
37
+ supervision_json=null
38
+ if [[ -f "$AUTOMATION_RUNTIME_ROOT/inbox/queue.json" ]]; then
39
+ supervision_json="$(jq -c --arg task "$task_id" '
40
+ ([.items[]? | select(.taskId == $task)] | last | .key) as $key |
41
+ ([.runs[]?, .active] | map(select(.key == $key)) | last | .supervision) |
42
+ if . == null then null else {state, stage, deadline, stageDeadline, stopReason, termAt, killAt} end
43
+ ' "$AUTOMATION_RUNTIME_ROOT/inbox/queue.json")"
44
+ supervision_json="${supervision_json:-null}"
45
+ fi
24
46
  ready_json="$(if [[ -f "$evidence_dir/ready.json" ]]; then jq -c . "$evidence_dir/ready.json"; else printf 'null'; fi)"
25
47
  review_json="$(if [[ -f "$evidence_dir/review.json" ]]; then jq -c . "$evidence_dir/review.json"; else printf 'null'; fi)"
26
48
  gate_json=null
@@ -93,6 +115,14 @@ jq -n \
93
115
  --argjson origin "$origin_json" \
94
116
  --argjson baseline "$baseline_json" \
95
117
  --argjson red "$red_json" \
118
+ --argjson testPreflight "$preflight_json" \
119
+ --argjson testManifest "$manifest_json" \
120
+ --argjson baselineInventory "$inventory_baseline_json" \
121
+ --argjson greenInventory "$inventory_green_json" \
122
+ --argjson inventoryStatus "$inventory_status_json" \
123
+ --argjson baselineRecovery "$baseline_recovery_json" \
124
+ --argjson stageRecovery "$stage_recovery_json" \
125
+ --argjson workerSupervision "$supervision_json" \
96
126
  --argjson ready "$ready_json" \
97
127
  --argjson gate "$gate_json" \
98
128
  --argjson review "$review_json" \
@@ -118,6 +148,14 @@ jq -n \
118
148
  directory: $evidence,
119
149
  baseline: $baseline,
120
150
  red: $red,
151
+ testPreflight: $testPreflight,
152
+ testManifest: $testManifest,
153
+ baselineInventory: $baselineInventory,
154
+ greenInventory: $greenInventory,
155
+ inventoryStatus: $inventoryStatus,
156
+ baselineRecovery: $baselineRecovery,
157
+ stageRecovery: $stageRecovery,
158
+ workerSupervision: $workerSupervision,
121
159
  ready: $ready,
122
160
  latestGate: $gate,
123
161
  review: $review,
@@ -36,9 +36,18 @@ review_log="$evidence_dir/review-verification.log"
36
36
  verification_status=0
37
37
  if [[ "$decision" == "APPROVED" ]]; then
38
38
  set +e
39
- "$SCRIPT_DIR/verify-task.sh" "$task_id" 2>&1 | tee "$review_log"
39
+ contract="$(automation_contract_path "$task_id")"
40
+ if [[ "$(jq -r '.schemaVersion' "$contract")" -ge "7" ]]; then
41
+ node "$AUTOMATION_ROOT/automation/verification/recovery.cjs" --stage review "$contract" "$AUTOMATION_CONFIG" "$AUTOMATION_ROOT" "$evidence_dir" 2>&1 | tee "$review_log"
42
+ else
43
+ "$SCRIPT_DIR/verify-task.sh" "$task_id" 2>&1 | tee "$review_log"
44
+ fi
40
45
  verification_status=${PIPESTATUS[0]}
41
46
  set -e
47
+ if [[ "$(jq -r '.schemaVersion' "$contract")" -ge "7" && ( "$verification_status" -eq 75 || "$verification_status" -eq 76 ) ]]; then
48
+ automation_transition_state "$task_id" "REVIEWING" "BLOCKED" "reviewer" "independent verification stopped; inspect stage-recovery/review.json; no implementation change requested"
49
+ exit "$verification_status"
50
+ fi
42
51
  if [[ "$verification_status" -ne 0 ]]; then
43
52
  decision="CHANGES_REQUESTED"
44
53
  summary="Independent verification failed with exit $verification_status. $summary"
@@ -26,8 +26,12 @@ fi
26
26
  [[ -f "$contract" ]] || automation_die "contract not found: $contract"
27
27
  jq -e . "$contract" >/dev/null || automation_die "contract is not valid JSON: $contract"
28
28
 
29
+ if [[ "$(jq -r '.schemaVersion' "$contract")" -ge "4" ]]; then
30
+ node "$AUTOMATION_ROOT/automation/verification/contract.cjs" "$contract" "$AUTOMATION_CONFIG" || \
31
+ automation_die "V4/V5 contract validation failed"
32
+ else
29
33
  jq -e '
30
- (.schemaVersion == 1 or .schemaVersion == 2) and
34
+ (.schemaVersion == 1 or .schemaVersion == 2 or .schemaVersion == 3) and
31
35
  (.id | type == "string" and test("^TASK-[A-Z0-9-]+$")) and
32
36
  (.title | type == "string" and length > 0) and
33
37
  .designApproved == true and
@@ -53,11 +57,60 @@ jq -e '
53
57
  ([.targetTests[].filter] | length == (unique | length)) and
54
58
  (.deviceTestsRequired | type == "boolean") and
55
59
  (.testPolicy == "required" or .testPolicy == "not-required") and
56
- (if .testPolicy == "not-required" then (.testPolicyReason | type == "string" and length >= 20) else true end)
60
+ (if .testPolicy == "not-required" then (.testPolicyReason | type == "string" and length >= 20) else true end) and
61
+ (if .schemaVersion == 3 then
62
+ (.acceptanceCriteria | length) as $criterionCount |
63
+ (.targetTests | length) as $targetCount |
64
+ (.verification | type == "object" and
65
+ keys == ["cases", "maxPreparationFixes", "version"] and
66
+ .version == 1 and
67
+ (.maxPreparationFixes | type == "number" and floor == . and . >= 0 and . <= 1) and
68
+ (.cases | type == "array" and length > 0) and
69
+ ([.cases[].id] | length == (unique | length)) and
70
+ ([.cases[] | [.test.target, .test.className, .test.name] | @json] | length == (unique | length)) and
71
+ (any(.cases[]; .intent == "change")) and
72
+ all(.cases[];
73
+ type == "object" and
74
+ ([keys[]] - ["id", "criterion", "intent", "before", "after", "source", "test", "expectedFailure"] | length == 0) and
75
+ (.id | type == "string" and test("^[A-Z][A-Z0-9-]{2,63}$")) and
76
+ (.criterion | type == "number" and floor == . and . >= 1 and . <= $criterionCount) and
77
+ .after == "pass" and
78
+ (.test | type == "object" and keys == ["className", "name", "target"] and
79
+ (.target | type == "number" and floor == . and . >= 0 and . < $targetCount) and
80
+ (.className | type == "string" and length > 0) and
81
+ (.name | type == "string" and length > 0)) and
82
+ (if .intent == "preserve" then
83
+ .before == "pass" and
84
+ (.source == "existingTest" or .source == "baselineCapture" or .source == "measuredFact") and
85
+ (has("expectedFailure") | not)
86
+ elif .intent == "change" then
87
+ .before == "fail" and .source == "userRequirement" and
88
+ (.expectedFailure | type == "object" and
89
+ ([keys[]] - ["type", "messageIncludes", "origin"] | length == 0) and
90
+ (.type | type == "string" and length > 0) and
91
+ (.origin | type == "string" and length >= 12) and
92
+ (if has("messageIncludes") then (.messageIncludes | type == "string" and length >= 3) else true end))
93
+ elif .intent == "observe" then
94
+ .before == "observe" and
95
+ (.source == "userRequirement" or .source == "existingTest" or .source == "baselineCapture" or .source == "measuredFact") and
96
+ (if has("expectedFailure") then
97
+ (.expectedFailure | type == "object" and
98
+ ([keys[]] - ["type", "messageIncludes", "origin"] | length == 0) and
99
+ (.type | type == "string" and length > 0) and
100
+ (.origin | type == "string" and length >= 12) and
101
+ (if has("messageIncludes") then (.messageIncludes | type == "string" and length >= 3) else true end))
102
+ else true end)
103
+ else false end)))
104
+ else true end)
57
105
  ' "$contract" >/dev/null || automation_die "contract is missing required fields or violates limits"
106
+ fi
58
107
 
59
108
  task_id="$(jq -r '.id' "$contract")"
60
109
  automation_validate_task_id "$task_id"
110
+ if [[ "$(jq -r '.deviceTestsRequired' "$contract")" == "true" ]]; then
111
+ jq -e '.gradleVerification.deviceTestTasks | length > 0' "$AUTOMATION_CONFIG" >/dev/null || \
112
+ automation_die "Device tests are required by this contract but no device test tasks are available"
113
+ fi
61
114
 
62
115
  if [[ "$contract" == "$AUTOMATION_TASKS_DIR/"* ]]; then
63
116
  expected_contract="$(automation_contract_path "$task_id")"
@@ -89,7 +142,7 @@ while IFS=$'\t' read -r gradle_task filter; do
89
142
  automation_die "target test Gradle task is not allowed by automation/config.json: $gradle_task"
90
143
  done < <(jq -r '.targetTests[] | [.gradleTask, .filter] | @tsv' "$contract")
91
144
 
92
- if rg -n -i 'replace with|TASK-EXAMPLE|todo|tbd|placeholder' "$contract" >/dev/null; then
145
+ if [[ "$(jq -r '.schemaVersion' "$contract")" -lt "4" ]] && rg -n -i 'replace with|TASK-EXAMPLE|todo|tbd|placeholder' "$contract" >/dev/null; then
93
146
  automation_die "contract still contains template placeholders"
94
147
  fi
95
148
 
@@ -28,4 +28,7 @@ if [[ "$(jq -r '.deviceTestsRequired' "$contract")" == "true" ]]; then
28
28
  automation_run_gradle_group "deviceTestTasks" "$AUTOMATION_ROOT"
29
29
  fi
30
30
 
31
+ if [[ "$(jq -r '.schemaVersion' "$contract")" -ge "4" ]]; then
32
+ automation_run_inventory check "$task_id"
33
+ fi
31
34
  automation_info "integration candidate passed all deterministic verification"
@@ -15,6 +15,20 @@ evidence_dir="$(automation_evidence_path "$task_id")"
15
15
  [[ -f "$evidence_dir/baseline.json" ]] || { automation_die "baseline evidence is missing"; exit 41; }
16
16
  [[ -f "$evidence_dir/red.json" ]] || { automation_die "RED evidence is missing"; exit 41; }
17
17
 
18
+ contract_schema="$(jq -er '.schemaVersion' "$contract")"
19
+ if [[ "$contract_schema" == "3" ]]; then
20
+ preflight_meta="$evidence_dir/test-preflight.json"
21
+ manifest_meta="$evidence_dir/test-manifest.json"
22
+ red_meta="$evidence_dir/red.json"
23
+ [[ -f "$preflight_meta" && -f "$manifest_meta" ]] || { automation_die "structured RED evidence is incomplete"; exit 41; }
24
+ [[ "$(jq -er '.valid' "$preflight_meta")" == "true" ]] || { automation_die "structured RED preflight was not valid"; exit 41; }
25
+ [[ "$(jq -er '.contractSha256' "$red_meta")" == "$(automation_file_sha256 "$contract")" ]] || { automation_die "RED contract binding changed"; exit 41; }
26
+ [[ "$(jq -er '.baselineHead' "$red_meta")" == "$(jq -er '.head' "$evidence_dir/baseline.json")" ]] || { automation_die "RED baseline binding changed"; exit 41; }
27
+ [[ "$(jq -er '.testDiffSha256' "$red_meta")" == "$(automation_test_diff_sha "$task_id" "$AUTOMATION_ROOT")" ]] || { automation_die "tests changed after structured RED"; exit 41; }
28
+ [[ "$(jq -er '.preflightSha256' "$red_meta")" == "$(automation_file_sha256 "$preflight_meta")" ]] || { automation_die "RED preflight evidence changed"; exit 41; }
29
+ [[ "$(jq -er '.manifestSha256' "$red_meta")" == "$(automation_file_sha256 "$manifest_meta")" ]] || { automation_die "RED test manifest changed"; exit 41; }
30
+ fi
31
+
18
32
  "$SCRIPT_DIR/scope-gate.sh" "$task_id"
19
33
 
20
34
  automation_run_configured_unit_tests "$contract" "$AUTOMATION_ROOT"
@@ -30,6 +44,9 @@ if [[ "$(jq -r '.deviceTestsRequired' "$contract")" == "true" ]]; then
30
44
  fi
31
45
 
32
46
  automation_info "all deterministic verification commands passed"
47
+ if [[ "$contract_schema" -ge "4" ]]; then
48
+ automation_run_inventory check "$task_id"
49
+ fi
33
50
  if [[ -n "${AUTOMATION_QUEUE_RUN_ID:-}" ]]; then
34
51
  [[ -n "${AUTOMATION_FULL_TEST_LOG:-}" ]] || automation_die "fresh full unit-test evidence is missing"
35
52
  jq -n \