@frankzhang2026/opencode-android-orchestrator 0.2.0 → 0.3.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/CHANGELOG.md +18 -1
- package/README.md +50 -39
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/dist/cli.js +127 -10
- package/dist/cli.js.map +1 -1
- package/dist/doctor/installation.d.ts.map +1 -1
- package/dist/doctor/installation.js +29 -4
- package/dist/doctor/installation.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/installer/adaptive-templates.d.ts +25 -3
- package/dist/installer/adaptive-templates.d.ts.map +1 -1
- package/dist/installer/adaptive-templates.js +75 -9
- package/dist/installer/adaptive-templates.js.map +1 -1
- package/dist/installer/index.d.ts +2 -2
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +2 -2
- package/dist/installer/index.js.map +1 -1
- package/dist/installer/init.d.ts +2 -1
- package/dist/installer/init.d.ts.map +1 -1
- package/dist/installer/init.js +10 -1
- package/dist/installer/init.js.map +1 -1
- package/dist/installer/opencode-config.d.ts +4 -3
- package/dist/installer/opencode-config.d.ts.map +1 -1
- package/dist/installer/opencode-config.js +10 -4
- package/dist/installer/opencode-config.js.map +1 -1
- package/dist/installer/upgrade.d.ts +5 -0
- package/dist/installer/upgrade.d.ts.map +1 -1
- package/dist/installer/upgrade.js +44 -10
- package/dist/installer/upgrade.js.map +1 -1
- package/docs/MIGRATION.md +23 -12
- package/docs/SECURITY.md +11 -4
- package/docs/TROUBLESHOOTING.md +5 -6
- package/package.json +1 -1
- package/templates/README.md +5 -2
- package/templates/automation/config.json +17 -0
- package/templates/automation/config.schema.json +31 -0
- package/templates/automation/task-contract.schema.json +22 -1
- package/templates/automation/tasks/TASK-TEMPLATE.json.example +4 -1
- package/templates/scripts/automation/claim-task.sh +6 -6
- package/templates/scripts/automation/lib.sh +118 -0
- package/templates/scripts/automation/preflight.sh +1 -1
- package/templates/scripts/automation/record-red.sh +7 -9
- package/templates/scripts/automation/show-acceptance-review.sh +1 -1
- package/templates/scripts/automation/tests/run-tests.sh +26 -9
- package/templates/scripts/automation/validate-contract.sh +16 -5
- package/templates/scripts/automation/verify-integration.sh +12 -11
- package/templates/scripts/automation/verify-task.sh +13 -28
|
@@ -137,10 +137,18 @@ jq -n '{
|
|
|
137
137
|
"systematic-debugging",
|
|
138
138
|
"verification-before-completion"
|
|
139
139
|
],
|
|
140
|
+
gradleVerification: {
|
|
141
|
+
fullUnitTestTasks: ["testDebugUnitTest"],
|
|
142
|
+
focusedTestTasks: ["testDebugUnitTest"],
|
|
143
|
+
assembleTasks: ["assembleDebug"],
|
|
144
|
+
lintTasks: ["lint"],
|
|
145
|
+
deviceTestTasks: ["connectedDebugAndroidTest"]
|
|
146
|
+
},
|
|
140
147
|
androidProject: {
|
|
141
148
|
name: "automation-shell-fixture",
|
|
142
149
|
gradleDsl: "kotlin",
|
|
143
150
|
settingsFile: "settings.gradle.kts",
|
|
151
|
+
moduleScope: "all",
|
|
144
152
|
primaryModule: ":mobile-client",
|
|
145
153
|
modules: [{
|
|
146
154
|
gradlePath: ":mobile-client",
|
|
@@ -217,7 +225,10 @@ jq -n '{
|
|
|
217
225
|
],
|
|
218
226
|
acceptanceCriteria: ["Greeting returns the approved value"],
|
|
219
227
|
nonGoals: ["No unrelated refactoring"],
|
|
220
|
-
targetTests: [
|
|
228
|
+
targetTests: [{
|
|
229
|
+
gradleTask: "testDebugUnitTest",
|
|
230
|
+
filter: "dev.example.orchestratorfixture.GreetingTest"
|
|
231
|
+
}],
|
|
221
232
|
deviceTestsRequired: false,
|
|
222
233
|
testPolicy: "required",
|
|
223
234
|
testPolicyReason: "The behavior requires a focused regression test"
|
|
@@ -273,11 +284,17 @@ pass 'illegal state transition is rejected'
|
|
|
273
284
|
run_fixture ./scripts/automation/claim-task.sh TASK-TEST-001 >/dev/null
|
|
274
285
|
[[ "$(jq -r '.state' "$runtime_root/state/TASK-TEST-001.json")" == "CODING" ]] || fail 'claim did not create CODING state'
|
|
275
286
|
[[ -f "$runtime_root/evidence/TASK-TEST-001/baseline.json" ]] || fail 'baseline metadata missing'
|
|
287
|
+
jq -e \
|
|
288
|
+
'.command == ["./gradlew", "testDebugUnitTest"]' \
|
|
289
|
+
"$runtime_root/evidence/TASK-TEST-001/baseline.json" >/dev/null || fail 'baseline command does not match the configured task matrix'
|
|
276
290
|
pass 'claim verifies workspace identity and records a green baseline'
|
|
277
291
|
|
|
278
292
|
printf '%s\n' 'class GreetingTest { fun expectedBehavior() = Unit }' > "$fixture/mobile-client/src/test/java/dev/example/orchestratorfixture/GreetingTest.kt"
|
|
279
293
|
run_fixture ./scripts/automation/record-red.sh TASK-TEST-001 'expected missing behavior' -- dev.example.orchestratorfixture.GreetingTest >/dev/null
|
|
280
294
|
[[ "$(jq -r '.exitCode' "$runtime_root/evidence/TASK-TEST-001/red.json")" -ne 0 ]] || fail 'RED evidence exit code was not captured'
|
|
295
|
+
jq -e \
|
|
296
|
+
'.command == ["./gradlew", "testDebugUnitTest", "--tests", "dev.example.orchestratorfixture.GreetingTest"]' \
|
|
297
|
+
"$runtime_root/evidence/TASK-TEST-001/red.json" >/dev/null || fail 'RED command does not bind the configured task and filter'
|
|
281
298
|
pass 'focused failing test records genuine RED evidence'
|
|
282
299
|
|
|
283
300
|
printf '%s\n' 'unsafe' > "$fixture/automation/forbidden-change.txt"
|
|
@@ -338,7 +355,7 @@ jq \
|
|
|
338
355
|
'.id = "TASK-TEST-002" |
|
|
339
356
|
.title = "Exercise the bounded verification failure loop" |
|
|
340
357
|
.planPath = "docs/plans/TASK-TEST-002.md" |
|
|
341
|
-
.targetTests = ["dev.example.orchestratorfixture.FailureLoopTest"]' \
|
|
358
|
+
.targetTests = [{gradleTask: "testDebugUnitTest", filter: "dev.example.orchestratorfixture.FailureLoopTest"}]' \
|
|
342
359
|
"$fixture/automation/tasks/TASK-TEST-001.json" \
|
|
343
360
|
> "$fixture/automation/tasks/TASK-TEST-002.json"
|
|
344
361
|
(
|
|
@@ -375,7 +392,7 @@ jq \
|
|
|
375
392
|
'.id = "TASK-TEST-003" |
|
|
376
393
|
.title = "Verify dirty worktree preflight blocking" |
|
|
377
394
|
.planPath = "docs/plans/TASK-TEST-003.md" |
|
|
378
|
-
.targetTests = ["dev.example.orchestratorfixture.PreflightBlockTest"]' \
|
|
395
|
+
.targetTests = [{gradleTask: "testDebugUnitTest", filter: "dev.example.orchestratorfixture.PreflightBlockTest"}]' \
|
|
379
396
|
"$fixture/automation/tasks/TASK-TEST-001.json" \
|
|
380
397
|
> "$fixture/automation/tasks/TASK-TEST-003.json"
|
|
381
398
|
(
|
|
@@ -402,7 +419,7 @@ jq \
|
|
|
402
419
|
'.id = "TASK-TEST-005" |
|
|
403
420
|
.title = "Exercise the bounded reviewer repair cycle" |
|
|
404
421
|
.planPath = "docs/plans/TASK-TEST-005.md" |
|
|
405
|
-
.targetTests = ["dev.example.orchestratorfixture.ReviewerFixTest"]' \
|
|
422
|
+
.targetTests = [{gradleTask: "testDebugUnitTest", filter: "dev.example.orchestratorfixture.ReviewerFixTest"}]' \
|
|
406
423
|
"$fixture/automation/tasks/TASK-TEST-001.json" \
|
|
407
424
|
> "$fixture/automation/tasks/TASK-TEST-005.json"
|
|
408
425
|
(
|
|
@@ -452,7 +469,7 @@ jq \
|
|
|
452
469
|
'.id = "TASK-TEST-004" |
|
|
453
470
|
.title = "Exercise in-place transactional integration" |
|
|
454
471
|
.planPath = "docs/plans/TASK-TEST-004.md" |
|
|
455
|
-
.targetTests = ["dev.example.orchestratorfixture.OrchestratedFlowTest"]' \
|
|
472
|
+
.targetTests = [{gradleTask: "testDebugUnitTest", filter: "dev.example.orchestratorfixture.OrchestratedFlowTest"}]' \
|
|
456
473
|
"$fixture/automation/tasks/TASK-TEST-001.json" \
|
|
457
474
|
> "$fixture/automation/tasks/TASK-TEST-004.json"
|
|
458
475
|
|
|
@@ -557,7 +574,7 @@ jq \
|
|
|
557
574
|
'.id = "TASK-TEST-008" |
|
|
558
575
|
.title = "Archive an interrupted in-place task" |
|
|
559
576
|
.planPath = "docs/plans/TASK-TEST-008.md" |
|
|
560
|
-
.targetTests = ["dev.example.orchestratorfixture.AbortArchiveTest"]' \
|
|
577
|
+
.targetTests = [{gradleTask: "testDebugUnitTest", filter: "dev.example.orchestratorfixture.AbortArchiveTest"}]' \
|
|
561
578
|
"$fixture/automation/tasks/TASK-TEST-001.json" \
|
|
562
579
|
> "$fixture/automation/tasks/TASK-TEST-008.json"
|
|
563
580
|
run_fixture ./scripts/automation/prepare-contract-review.sh TASK-TEST-008 '批准方案,生成计划和任务合同。' >/dev/null
|
|
@@ -586,7 +603,7 @@ jq \
|
|
|
586
603
|
'.id = "TASK-TEST-009" |
|
|
587
604
|
.title = "Abort before product editing" |
|
|
588
605
|
.planPath = "docs/plans/TASK-TEST-009.md" |
|
|
589
|
-
.targetTests = ["dev.example.orchestratorfixture.PlanningOnlyAbortTest"]' \
|
|
606
|
+
.targetTests = [{gradleTask: "testDebugUnitTest", filter: "dev.example.orchestratorfixture.PlanningOnlyAbortTest"}]' \
|
|
590
607
|
"$fixture/automation/tasks/TASK-TEST-001.json" \
|
|
591
608
|
> "$fixture/automation/tasks/TASK-TEST-009.json"
|
|
592
609
|
run_fixture ./scripts/automation/prepare-contract-review.sh TASK-TEST-009 '批准方案,生成计划和任务合同。' >/dev/null
|
|
@@ -611,7 +628,7 @@ jq \
|
|
|
611
628
|
'.id = "TASK-TEST-007" |
|
|
612
629
|
.title = "Keep optional isolated workspace support" |
|
|
613
630
|
.planPath = "docs/plans/TASK-TEST-007.md" |
|
|
614
|
-
.targetTests = ["dev.example.orchestratorfixture.IsolatedFlowTest"]' \
|
|
631
|
+
.targetTests = [{gradleTask: "testDebugUnitTest", filter: "dev.example.orchestratorfixture.IsolatedFlowTest"}]' \
|
|
615
632
|
"$fixture/automation/tasks/TASK-TEST-001.json" \
|
|
616
633
|
> "$fixture/automation/tasks/TASK-TEST-007.json"
|
|
617
634
|
run_fixture ./scripts/automation/prepare-contract-review.sh TASK-TEST-007 '批准方案,生成计划和任务合同。' >/dev/null
|
|
@@ -654,7 +671,7 @@ jq \
|
|
|
654
671
|
'.id = "TASK-TEST-006" |
|
|
655
672
|
.title = "Block an advanced original branch" |
|
|
656
673
|
.planPath = "docs/plans/TASK-TEST-006.md" |
|
|
657
|
-
.targetTests = ["dev.example.orchestratorfixture.AdvancedOriginalTest"]' \
|
|
674
|
+
.targetTests = [{gradleTask: "testDebugUnitTest", filter: "dev.example.orchestratorfixture.AdvancedOriginalTest"}]' \
|
|
658
675
|
"$fixture/automation/tasks/TASK-TEST-001.json" \
|
|
659
676
|
> "$fixture/automation/tasks/TASK-TEST-006.json"
|
|
660
677
|
run_fixture ./scripts/automation/prepare-contract-review.sh TASK-TEST-006 '批准方案,生成计划和任务合同。' >/dev/null
|
|
@@ -13,6 +13,7 @@ input="${1:-}"
|
|
|
13
13
|
[[ -n "$input" ]] || { usage; exit 2; }
|
|
14
14
|
automation_require_command jq
|
|
15
15
|
automation_require_layout
|
|
16
|
+
automation_validate_config
|
|
16
17
|
|
|
17
18
|
if [[ "$input" == */* || "$input" == *.json || "$input" == *.example ]]; then
|
|
18
19
|
contract="$input"
|
|
@@ -39,7 +40,12 @@ jq -e '
|
|
|
39
40
|
(.allowedSuperpowers == ["test-driven-development", "systematic-debugging", "verification-before-completion"]) and
|
|
40
41
|
(.acceptanceCriteria | type == "array" and length > 0) and
|
|
41
42
|
(.nonGoals | type == "array" and length > 0) and
|
|
42
|
-
(.targetTests | type == "array" and length > 0
|
|
43
|
+
(.targetTests | type == "array" and length > 0 and all(.[];
|
|
44
|
+
type == "object" and
|
|
45
|
+
keys == ["filter", "gradleTask"] and
|
|
46
|
+
(.gradleTask | type == "string" and test("^(?:[A-Za-z][A-Za-z0-9_.-]*|(?::[A-Za-z0-9_.-]+)+)$")) and
|
|
47
|
+
(.filter | type == "string" and test("^[A-Za-z0-9_.#$*-]+$")))) and
|
|
48
|
+
([.targetTests[].filter] | length == (unique | length)) and
|
|
43
49
|
(.deviceTestsRequired | type == "boolean") and
|
|
44
50
|
(.testPolicy == "required" or .testPolicy == "not-required") and
|
|
45
51
|
(if .testPolicy == "not-required" then (.testPolicyReason | type == "string" and length >= 20) else true end)
|
|
@@ -68,10 +74,15 @@ while IFS= read -r protected; do
|
|
|
68
74
|
fi
|
|
69
75
|
done < <(jq -r '.protectedPaths[]' "$AUTOMATION_CONFIG")
|
|
70
76
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
while IFS=$'\t' read -r gradle_task filter; do
|
|
78
|
+
automation_validate_gradle_task "$gradle_task"
|
|
79
|
+
automation_validate_test_filter "$filter"
|
|
80
|
+
jq -e \
|
|
81
|
+
--arg task "$gradle_task" \
|
|
82
|
+
'.gradleVerification.focusedTestTasks | index($task) != null' \
|
|
83
|
+
"$AUTOMATION_CONFIG" >/dev/null || \
|
|
84
|
+
automation_die "target test Gradle task is not allowed by automation/config.json: $gradle_task"
|
|
85
|
+
done < <(jq -r '.targetTests[] | [.gradleTask, .filter] | @tsv' "$contract")
|
|
75
86
|
|
|
76
87
|
if rg -n -i 'replace with|TASK-EXAMPLE|todo|tbd|placeholder' "$contract" >/dev/null; then
|
|
77
88
|
automation_die "contract still contains template placeholders"
|
|
@@ -12,26 +12,27 @@ head="${3:-}"
|
|
|
12
12
|
automation_validate_task_id "$task_id"
|
|
13
13
|
[[ "$(automation_read_state "$task_id")" == "INTEGRATING" ]] || automation_die "$task_id is not INTEGRATING"
|
|
14
14
|
contract="$(automation_contract_path "$task_id")"
|
|
15
|
+
"$SCRIPT_DIR/validate-contract.sh" "$task_id" >/dev/null
|
|
15
16
|
|
|
16
17
|
"$SCRIPT_DIR/integration-scope-gate.sh" "$task_id" "$base" "$head"
|
|
17
18
|
|
|
18
|
-
while IFS
|
|
19
|
-
automation_info "running integration focused test: $filter"
|
|
20
|
-
|
|
21
|
-
done < <(jq -r '.targetTests[]' "$contract")
|
|
19
|
+
while IFS=$'\t' read -r gradle_task filter; do
|
|
20
|
+
automation_info "running integration focused test ($gradle_task): $filter"
|
|
21
|
+
automation_run_focused_test "$gradle_task" "$filter" "$AUTOMATION_ROOT"
|
|
22
|
+
done < <(jq -r '.targetTests[] | [.gradleTask, .filter] | @tsv' "$contract")
|
|
22
23
|
|
|
23
24
|
automation_info "running integration full unit tests"
|
|
24
|
-
|
|
25
|
+
automation_run_gradle_group "fullUnitTestTasks" "$AUTOMATION_ROOT"
|
|
25
26
|
|
|
26
|
-
automation_info "
|
|
27
|
-
|
|
27
|
+
automation_info "running configured integration assemble tasks"
|
|
28
|
+
automation_run_gradle_group "assembleTasks" "$AUTOMATION_ROOT"
|
|
28
29
|
|
|
29
|
-
automation_info "running integration Android lint"
|
|
30
|
-
|
|
30
|
+
automation_info "running configured integration Android lint tasks"
|
|
31
|
+
automation_run_gradle_group "lintTasks" "$AUTOMATION_ROOT"
|
|
31
32
|
|
|
32
33
|
if [[ "$(jq -r '.deviceTestsRequired' "$contract")" == "true" ]]; then
|
|
33
|
-
automation_info "running integration
|
|
34
|
-
|
|
34
|
+
automation_info "running configured integration device tests"
|
|
35
|
+
automation_run_gradle_group "deviceTestTasks" "$AUTOMATION_ROOT"
|
|
35
36
|
fi
|
|
36
37
|
|
|
37
38
|
automation_info "integration candidate passed all deterministic verification"
|
|
@@ -17,38 +17,23 @@ evidence_dir="$(automation_evidence_path "$task_id")"
|
|
|
17
17
|
|
|
18
18
|
"$SCRIPT_DIR/scope-gate.sh" "$task_id"
|
|
19
19
|
|
|
20
|
-
while IFS
|
|
21
|
-
automation_info "running focused test: $filter"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
./gradlew testDebugUnitTest --tests "$filter"
|
|
25
|
-
)
|
|
26
|
-
done < <(jq -r '.targetTests[]' "$contract")
|
|
20
|
+
while IFS=$'\t' read -r gradle_task filter; do
|
|
21
|
+
automation_info "running focused test ($gradle_task): $filter"
|
|
22
|
+
automation_run_focused_test "$gradle_task" "$filter" "$AUTOMATION_ROOT"
|
|
23
|
+
done < <(jq -r '.targetTests[] | [.gradleTask, .filter] | @tsv' "$contract")
|
|
27
24
|
|
|
28
25
|
automation_info "running full unit tests"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
automation_info "
|
|
35
|
-
|
|
36
|
-
cd "$AUTOMATION_ROOT"
|
|
37
|
-
./gradlew assembleDebug
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
automation_info "running Android lint"
|
|
41
|
-
(
|
|
42
|
-
cd "$AUTOMATION_ROOT"
|
|
43
|
-
./gradlew lint
|
|
44
|
-
)
|
|
26
|
+
automation_run_gradle_group "fullUnitTestTasks" "$AUTOMATION_ROOT"
|
|
27
|
+
|
|
28
|
+
automation_info "running configured assemble tasks"
|
|
29
|
+
automation_run_gradle_group "assembleTasks" "$AUTOMATION_ROOT"
|
|
30
|
+
|
|
31
|
+
automation_info "running configured Android lint tasks"
|
|
32
|
+
automation_run_gradle_group "lintTasks" "$AUTOMATION_ROOT"
|
|
45
33
|
|
|
46
34
|
if [[ "$(jq -r '.deviceTestsRequired' "$contract")" == "true" ]]; then
|
|
47
|
-
automation_info "running
|
|
48
|
-
|
|
49
|
-
cd "$AUTOMATION_ROOT"
|
|
50
|
-
./gradlew connectedDebugAndroidTest
|
|
51
|
-
)
|
|
35
|
+
automation_info "running configured device tests"
|
|
36
|
+
automation_run_gradle_group "deviceTestTasks" "$AUTOMATION_ROOT"
|
|
52
37
|
fi
|
|
53
38
|
|
|
54
39
|
automation_info "all deterministic verification commands passed"
|