@frankzhang2026/opencode-android-orchestrator 0.1.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 +92 -2
- package/LICENSE +21 -0
- package/README.md +402 -6
- package/THIRD_PARTY_NOTICES.md +119 -0
- package/dist/cli.js +360 -1
- package/dist/cli.js.map +1 -1
- package/dist/compatibility/hooks.d.ts +23 -0
- package/dist/compatibility/hooks.d.ts.map +1 -0
- package/dist/compatibility/hooks.js +44 -0
- package/dist/compatibility/hooks.js.map +1 -0
- package/dist/compatibility/versions.d.ts +19 -0
- package/dist/compatibility/versions.d.ts.map +1 -1
- package/dist/compatibility/versions.js +116 -0
- package/dist/compatibility/versions.js.map +1 -1
- package/dist/doctor/index.d.ts +36 -0
- package/dist/doctor/index.d.ts.map +1 -0
- package/dist/doctor/index.js +289 -0
- package/dist/doctor/index.js.map +1 -0
- package/dist/doctor/installation.d.ts +4 -0
- package/dist/doctor/installation.d.ts.map +1 -0
- package/dist/doctor/installation.js +497 -0
- package/dist/doctor/installation.js.map +1 -0
- package/dist/index.d.ts +13 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -2
- package/dist/index.js.map +1 -1
- package/dist/installer/adaptive-templates.d.ts +78 -0
- package/dist/installer/adaptive-templates.d.ts.map +1 -0
- package/dist/installer/adaptive-templates.js +233 -0
- package/dist/installer/adaptive-templates.js.map +1 -0
- package/dist/installer/agents-config.d.ts +19 -0
- package/dist/installer/agents-config.d.ts.map +1 -0
- package/dist/installer/agents-config.js +147 -0
- package/dist/installer/agents-config.js.map +1 -0
- package/dist/installer/android-project.d.ts +36 -0
- package/dist/installer/android-project.d.ts.map +1 -0
- package/dist/installer/android-project.js +418 -0
- package/dist/installer/android-project.js.map +1 -0
- package/dist/installer/index.d.ts +8 -0
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +8 -1
- package/dist/installer/index.js.map +1 -1
- package/dist/installer/init.d.ts +68 -0
- package/dist/installer/init.d.ts.map +1 -0
- package/dist/installer/init.js +398 -0
- package/dist/installer/init.js.map +1 -0
- package/dist/installer/install-manifest.d.ts +132 -0
- package/dist/installer/install-manifest.d.ts.map +1 -0
- package/dist/installer/install-manifest.js +1047 -0
- package/dist/installer/install-manifest.js.map +1 -0
- package/dist/installer/opencode-config.d.ts +32 -0
- package/dist/installer/opencode-config.d.ts.map +1 -0
- package/dist/installer/opencode-config.js +302 -0
- package/dist/installer/opencode-config.js.map +1 -0
- package/dist/installer/uninstall.d.ts +70 -0
- package/dist/installer/uninstall.d.ts.map +1 -0
- package/dist/installer/uninstall.js +770 -0
- package/dist/installer/uninstall.js.map +1 -0
- package/dist/installer/upgrade.d.ts +101 -0
- package/dist/installer/upgrade.d.ts.map +1 -0
- package/dist/installer/upgrade.js +1140 -0
- package/dist/installer/upgrade.js.map +1 -0
- package/dist/opencode-plugin.d.ts +2 -0
- package/dist/opencode-plugin.d.ts.map +1 -0
- package/dist/opencode-plugin.js +4 -0
- package/dist/opencode-plugin.js.map +1 -0
- package/dist/plugin/index.d.ts +7 -2
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +23 -6
- package/dist/plugin/index.js.map +1 -1
- package/dist/tools/index.d.ts +35 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +197 -1
- package/dist/tools/index.js.map +1 -1
- package/docs/MIGRATION.md +184 -0
- package/docs/SECURITY.md +219 -0
- package/docs/TROUBLESHOOTING.md +171 -0
- package/package.json +23 -5
- package/templates/.opencode/agents/scheduled-coder.md +115 -0
- package/templates/.opencode/agents/scheduled-planner.md +166 -0
- package/templates/.opencode/agents/scheduled-reviewer.md +88 -0
- package/templates/.opencode/commands/abort-task.md +20 -0
- package/templates/.opencode/commands/acceptance.md +20 -0
- package/templates/.opencode/commands/change.md +23 -0
- package/templates/.opencode/commands/resume-review.md +19 -0
- package/templates/.opencode/skills/scheduled-quality-coder/SKILL.md +93 -0
- package/templates/.opencode/skills/scheduled-quality-orchestrator/SKILL.md +216 -0
- package/templates/.opencode/skills/scheduled-quality-reviewer/SKILL.md +68 -0
- package/templates/AGENTS.md.fragment +19 -0
- package/templates/README.md +55 -9
- package/templates/automation/config.json +67 -0
- package/templates/automation/config.schema.json +194 -0
- package/templates/automation/task-contract.schema.json +92 -0
- package/templates/automation/tasks/TASK-TEMPLATE.json.example +56 -0
- package/templates/docs/plans/README.md +26 -0
- package/templates/installation-manifest.schema.json +201 -0
- package/templates/scripts/automation/abort-task.sh +171 -0
- package/templates/scripts/automation/accept-and-integrate.sh +263 -0
- package/templates/scripts/automation/acceptance-report.sh +132 -0
- package/templates/scripts/automation/approve-and-run.sh +175 -0
- package/templates/scripts/automation/begin-review.sh +18 -0
- package/templates/scripts/automation/block-task.sh +26 -0
- package/templates/scripts/automation/claim-task.sh +74 -0
- package/templates/scripts/automation/integration-scope-gate.sh +103 -0
- package/templates/scripts/automation/lib.sh +815 -0
- package/templates/scripts/automation/orchestrate-task.sh +119 -0
- package/templates/scripts/automation/preflight.sh +206 -0
- package/templates/scripts/automation/prepare-contract-review.sh +101 -0
- package/templates/scripts/automation/quality-gate.sh +72 -0
- package/templates/scripts/automation/queue-task.sh +35 -0
- package/templates/scripts/automation/record-red.sh +55 -0
- package/templates/scripts/automation/resume-review-fix.sh +32 -0
- package/templates/scripts/automation/resume-review.sh +120 -0
- package/templates/scripts/automation/scope-gate.sh +110 -0
- package/templates/scripts/automation/select-task.sh +34 -0
- package/templates/scripts/automation/shadow-run.sh +24 -0
- package/templates/scripts/automation/show-acceptance-review.sh +111 -0
- package/templates/scripts/automation/status.sh +125 -0
- package/templates/scripts/automation/submit-review.sh +73 -0
- package/templates/scripts/automation/tests/run-tests.sh +716 -0
- package/templates/scripts/automation/transition-state.sh +21 -0
- package/templates/scripts/automation/validate-contract.sh +98 -0
- package/templates/scripts/automation/verify-integration.sh +38 -0
- package/templates/scripts/automation/verify-task.sh +39 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scheduled-quality-reviewer
|
|
3
|
+
description: Use when an orchestrated read-only OpenCode reviewer must independently assess one sealed task in REVIEWING and submit a gated decision
|
|
4
|
+
compatibility: opencode
|
|
5
|
+
metadata:
|
|
6
|
+
audience: automation
|
|
7
|
+
workflow: scheduled-review
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Scheduled quality reviewer
|
|
11
|
+
|
|
12
|
+
Review exactly one task from a fresh session. The coder's summary is a claim,
|
|
13
|
+
not evidence. You have no repository write authority and must not fix the code
|
|
14
|
+
you review.
|
|
15
|
+
|
|
16
|
+
## Mandatory sequence
|
|
17
|
+
|
|
18
|
+
1. Load `verification-before-completion`.
|
|
19
|
+
2. Require exactly one task ID or the compatibility token
|
|
20
|
+
`NEXT_REVIEWING`. For the selector token, first run
|
|
21
|
+
`./scripts/automation/select-task.sh REVIEWING` and continue only if
|
|
22
|
+
exactly one task ID is returned. Then run
|
|
23
|
+
`./scripts/automation/status.sh <TASK-ID>`.
|
|
24
|
+
3. Continue only when state is `REVIEWING`; the orchestrator alone performs
|
|
25
|
+
the sealed handoff from `READY_FOR_REVIEW`.
|
|
26
|
+
4. The `status.sh` JSON already includes the approved contract, baseline
|
|
27
|
+
metadata, RED evidence, latest gate metadata, current diff SHA, and the
|
|
28
|
+
sealed-SHA comparison. Use that compact evidence object; do not try to read
|
|
29
|
+
the external shared evidence directory or search generated Gradle report
|
|
30
|
+
directories. Inspect the actual tracked product change with exactly
|
|
31
|
+
`git diff`. The plan and task contract remain uncommitted and are included
|
|
32
|
+
in the sealing scripts' full task SHA even when plain `git diff` does not
|
|
33
|
+
render those untracked files; their hashes are protected, and only product
|
|
34
|
+
paths count against `allowedPaths` and `maxChangedFiles`.
|
|
35
|
+
5. Check each acceptance criterion against observable behavior. Inspect for
|
|
36
|
+
regression risk, missing edge cases, out-of-scope changes, test deletion,
|
|
37
|
+
ignored tests, relaxed assertions, and implementation-shaped tests.
|
|
38
|
+
6. Decide independently:
|
|
39
|
+
|
|
40
|
+
- approve only when the diff is correct and evidence is sufficient;
|
|
41
|
+
- request changes for every material finding, with a concrete file/behavior
|
|
42
|
+
explanation.
|
|
43
|
+
7. Submit one decision as soon as the inspection supports it:
|
|
44
|
+
|
|
45
|
+
`./scripts/automation/submit-review.sh <TASK-ID> APPROVED <summary>`
|
|
46
|
+
|
|
47
|
+
or
|
|
48
|
+
|
|
49
|
+
`./scripts/automation/submit-review.sh <TASK-ID> CHANGES_REQUESTED <summary>`
|
|
50
|
+
|
|
51
|
+
The script reruns the focused tests, full unit suite, debug build, and lint
|
|
52
|
+
before accepting `APPROVED`, and records that fresh output. Therefore do not
|
|
53
|
+
run those Gradle commands separately before an approval submission. Run an
|
|
54
|
+
individual verification command only to diagnose a failed submission, and
|
|
55
|
+
always reserve a step for the final `submit-review.sh` call.
|
|
56
|
+
|
|
57
|
+
## Independence rules
|
|
58
|
+
|
|
59
|
+
- Never edit code, tests, contracts, agent definitions, skills, scripts, or
|
|
60
|
+
evidence produced by the coder.
|
|
61
|
+
- Never dispatch a reviewer subagent; this scheduled session is the independent
|
|
62
|
+
reviewer.
|
|
63
|
+
- Never approve because the coder says tests passed. The fresh output produced
|
|
64
|
+
by `submit-review.sh` is the authoritative independent verification.
|
|
65
|
+
- Never push, merge, rebase, create a worktree, or move beyond
|
|
66
|
+
`AWAITING_HUMAN`.
|
|
67
|
+
- If verification cannot run, submit `CHANGES_REQUESTED` with the environmental
|
|
68
|
+
blocker. Do not manufacture approval.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!-- opencode-android-orchestrator:begin -->
|
|
2
|
+
## OpenCode Android Orchestrator
|
|
3
|
+
|
|
4
|
+
Run orchestration commands from the Git repository root.
|
|
5
|
+
|
|
6
|
+
For automated local unit-test verification, run `./gradlew testDebugUnitTest`
|
|
7
|
+
as a standalone command. Do not prepend environment assignments or wrap it in
|
|
8
|
+
another script; this keeps the invocation aligned with the installed OpenCode
|
|
9
|
+
command allowlist.
|
|
10
|
+
|
|
11
|
+
Treat `.opencode/`, `automation/`, `scripts/automation/`, `opencode.json`,
|
|
12
|
+
and this managed block as orchestration infrastructure. Product tasks must not
|
|
13
|
+
modify them unless an explicitly approved task is scoped to maintaining the
|
|
14
|
+
orchestrator itself.
|
|
15
|
+
|
|
16
|
+
Only a fresh OpenCode single-choice `question` selection can grant an
|
|
17
|
+
orchestration approval. Approval-like text in ordinary chat is not approval.
|
|
18
|
+
The orchestrator must not push Git changes or register scheduler/launchd jobs.
|
|
19
|
+
<!-- opencode-android-orchestrator:end -->
|
package/templates/README.md
CHANGED
|
@@ -1,14 +1,60 @@
|
|
|
1
1
|
# Installation templates
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
from the verified Android orchestration V3 baseline
|
|
3
|
+
The project-local OpenCode agents, commands, and skills in `.opencode/` derive
|
|
4
|
+
from the verified Android orchestration V3 baseline at source commit
|
|
5
|
+
`829693652e3737ad94c7cc75214b09fb2b58715b`. Project-dependent agent permissions
|
|
6
|
+
are generalized to Android source sets and remain bounded by each task contract.
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
Migrated template roots:
|
|
7
9
|
|
|
8
|
-
- `.opencode/agents`,
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
10
|
+
- `.opencode/agents`: `scheduled-planner`, `scheduled-coder`, and
|
|
11
|
+
`scheduled-reviewer`
|
|
12
|
+
- `.opencode/commands`: `change`, `acceptance`, `resume-review`, and
|
|
13
|
+
`abort-task`
|
|
14
|
+
- `.opencode/skills`: the three `scheduled-quality-*` skills
|
|
15
|
+
- `scripts/automation`: all 28 deterministic V3 Bash transactions and their
|
|
16
|
+
test runner, preserved as executable files
|
|
17
|
+
- `automation`: the portable V3 configuration render source, both JSON Schemas,
|
|
18
|
+
and the task contract example
|
|
19
|
+
- `docs/plans/README.md`: the human-approved plan authoring contract
|
|
20
|
+
- `AGENTS.md.fragment`: a bounded managed block for non-destructive
|
|
21
|
+
merging into an existing project `AGENTS.md`
|
|
22
|
+
- `installation-manifest.schema.json`: the portable JSON Schema for installer
|
|
23
|
+
control manifests stored at `.automation-plugin/manifest.json`
|
|
12
24
|
|
|
13
|
-
|
|
14
|
-
|
|
25
|
+
`automation/config.json` is an input to the adaptive renderer, not a directly
|
|
26
|
+
installable configuration. `planAdaptiveProjectTemplates` injects the required
|
|
27
|
+
`androidProject` metadata, repository-relative build files, protected paths,
|
|
28
|
+
all detected production/test source sets, and a module scope. New renders use
|
|
29
|
+
`all` scope and generate task paths for every detected module without requiring
|
|
30
|
+
a primary selection. `primary` scope restricts paths to one module and retains
|
|
31
|
+
the ambiguity guard. The selected/default module still supplies the focused
|
|
32
|
+
test placeholder in both modes.
|
|
33
|
+
|
|
34
|
+
The legacy Scheduler field has been removed while Superpowers remains pinned.
|
|
35
|
+
The scope gates consume generated source-set arrays, and the Shell test fixture
|
|
36
|
+
uses a neutral custom module and package. No shipped template contains a local
|
|
37
|
+
absolute path or project-specific package name.
|
|
38
|
+
|
|
39
|
+
`planAgentsConfigMerge` appends this block without replacing existing project
|
|
40
|
+
instructions, preserves LF/CRLF style, is byte-idempotent, and rejects partial,
|
|
41
|
+
duplicate, or modified managed markers. `init` applies the result through the
|
|
42
|
+
same backup and manifest transaction as every other managed file.
|
|
43
|
+
|
|
44
|
+
Historical tasks, runtime evidence, backups, and Android product code are not
|
|
45
|
+
included.
|
|
46
|
+
|
|
47
|
+
`tests/template-migration.test.mjs` locks the migrated inventory, current
|
|
48
|
+
SHA-256 values, file modes, and portability constraints.
|
|
49
|
+
|
|
50
|
+
`tests/shell-template-migration.test.mjs` additionally locks the Shell file
|
|
51
|
+
inventory, current SHA-256 values, `0755` modes, Bash syntax, portability, and
|
|
52
|
+
no-push/no-publish/no-launchd constraints.
|
|
53
|
+
|
|
54
|
+
`tests/resource-template-migration.test.mjs` locks the five portable
|
|
55
|
+
infrastructure resources, validates their structural alignment, and verifies
|
|
56
|
+
that the AGENTS fragment has exactly one portable managed block.
|
|
57
|
+
|
|
58
|
+
`tests/install-manifest.test.mjs` validates the package-level installation
|
|
59
|
+
manifest Schema together with backup and recovery metadata generated by the
|
|
60
|
+
installer transaction layer.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 3,
|
|
3
|
+
"enabled": true,
|
|
4
|
+
"mode": "orchestrated",
|
|
5
|
+
"workspaceStrategy": "inPlaceExclusive",
|
|
6
|
+
"originalBranchDriftPolicy": "block",
|
|
7
|
+
"worktreeBase": "",
|
|
8
|
+
"maxFixLoops": 1,
|
|
9
|
+
"maxReviewCycles": 1,
|
|
10
|
+
"maxReviewerRestarts": 2,
|
|
11
|
+
"autoCleanupWorktrees": true,
|
|
12
|
+
"pushAfterAcceptance": false,
|
|
13
|
+
"approvalPhrases": {
|
|
14
|
+
"proposal": "批准方案,生成计划和任务合同。",
|
|
15
|
+
"contract": "合同已复核,批准自动执行到人工验收阶段。",
|
|
16
|
+
"acceptance": "验收通过,提交到原分支。",
|
|
17
|
+
"abort": "中止任务,封存修改并恢复原分支。"
|
|
18
|
+
},
|
|
19
|
+
"plugins": {
|
|
20
|
+
"superpowers": "superpowers@git+https://github.com/obra/superpowers.git#v6.2.0"
|
|
21
|
+
},
|
|
22
|
+
"requiredSkills": [
|
|
23
|
+
"brainstorming",
|
|
24
|
+
"writing-plans",
|
|
25
|
+
"scheduled-quality-orchestrator",
|
|
26
|
+
"scheduled-quality-coder",
|
|
27
|
+
"scheduled-quality-reviewer",
|
|
28
|
+
"test-driven-development",
|
|
29
|
+
"systematic-debugging",
|
|
30
|
+
"verification-before-completion"
|
|
31
|
+
],
|
|
32
|
+
"gradleVerification": {
|
|
33
|
+
"fullUnitTestTasks": [
|
|
34
|
+
"testDebugUnitTest"
|
|
35
|
+
],
|
|
36
|
+
"focusedTestTasks": [
|
|
37
|
+
"testDebugUnitTest"
|
|
38
|
+
],
|
|
39
|
+
"assembleTasks": [
|
|
40
|
+
"assembleDebug"
|
|
41
|
+
],
|
|
42
|
+
"lintTasks": [
|
|
43
|
+
"lint"
|
|
44
|
+
],
|
|
45
|
+
"deviceTestTasks": [
|
|
46
|
+
"connectedDebugAndroidTest"
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
"protectedPaths": [
|
|
50
|
+
".opencode/",
|
|
51
|
+
".automation-plugin/",
|
|
52
|
+
"automation/",
|
|
53
|
+
"scripts/automation/",
|
|
54
|
+
"opencode.json",
|
|
55
|
+
"opencode.jsonc",
|
|
56
|
+
"AGENTS.md",
|
|
57
|
+
"gradle/",
|
|
58
|
+
"gradlew",
|
|
59
|
+
"gradlew.bat",
|
|
60
|
+
"settings.gradle",
|
|
61
|
+
"settings.gradle.kts",
|
|
62
|
+
"build.gradle",
|
|
63
|
+
"build.gradle.kts",
|
|
64
|
+
"**/build.gradle",
|
|
65
|
+
"**/build.gradle.kts"
|
|
66
|
+
]
|
|
67
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "urn:frankzhang2026:opencode-android-orchestrator:automation-config:v3",
|
|
4
|
+
"title": "OpenCode task orchestration configuration",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"$defs": {
|
|
8
|
+
"repositoryPath": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"minLength": 1,
|
|
11
|
+
"pattern": "^(?!/)(?!\\.\\.(?:/|$))(?![A-Za-z]:[\\\\/]).+"
|
|
12
|
+
},
|
|
13
|
+
"nullableIdentifier": {
|
|
14
|
+
"type": ["string", "null"],
|
|
15
|
+
"minLength": 1
|
|
16
|
+
},
|
|
17
|
+
"gradleTask": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"minLength": 1,
|
|
20
|
+
"pattern": "^(?:[A-Za-z][A-Za-z0-9_.-]*|(?::[A-Za-z0-9_.-]+)+)$"
|
|
21
|
+
},
|
|
22
|
+
"gradleTaskList": {
|
|
23
|
+
"type": "array",
|
|
24
|
+
"minItems": 1,
|
|
25
|
+
"uniqueItems": true,
|
|
26
|
+
"items": { "$ref": "#/$defs/gradleTask" }
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"required": [
|
|
30
|
+
"schemaVersion",
|
|
31
|
+
"enabled",
|
|
32
|
+
"mode",
|
|
33
|
+
"workspaceStrategy",
|
|
34
|
+
"originalBranchDriftPolicy",
|
|
35
|
+
"worktreeBase",
|
|
36
|
+
"maxFixLoops",
|
|
37
|
+
"maxReviewCycles",
|
|
38
|
+
"maxReviewerRestarts",
|
|
39
|
+
"autoCleanupWorktrees",
|
|
40
|
+
"pushAfterAcceptance",
|
|
41
|
+
"approvalPhrases",
|
|
42
|
+
"plugins",
|
|
43
|
+
"requiredSkills",
|
|
44
|
+
"gradleVerification",
|
|
45
|
+
"androidProject",
|
|
46
|
+
"protectedPaths"
|
|
47
|
+
],
|
|
48
|
+
"properties": {
|
|
49
|
+
"schemaVersion": { "const": 3 },
|
|
50
|
+
"enabled": { "type": "boolean" },
|
|
51
|
+
"mode": { "enum": ["shadow", "orchestrated"] },
|
|
52
|
+
"workspaceStrategy": {
|
|
53
|
+
"enum": ["inPlaceExclusive", "isolatedWorktree"]
|
|
54
|
+
},
|
|
55
|
+
"originalBranchDriftPolicy": { "const": "block" },
|
|
56
|
+
"worktreeBase": { "type": "string" },
|
|
57
|
+
"maxFixLoops": { "type": "integer", "minimum": 0, "maximum": 1 },
|
|
58
|
+
"maxReviewCycles": { "type": "integer", "minimum": 0, "maximum": 2 },
|
|
59
|
+
"maxReviewerRestarts": { "type": "integer", "minimum": 0, "maximum": 3 },
|
|
60
|
+
"autoCleanupWorktrees": { "type": "boolean" },
|
|
61
|
+
"pushAfterAcceptance": { "const": false },
|
|
62
|
+
"approvalPhrases": {
|
|
63
|
+
"type": "object",
|
|
64
|
+
"additionalProperties": false,
|
|
65
|
+
"required": ["proposal", "contract", "acceptance", "abort"],
|
|
66
|
+
"properties": {
|
|
67
|
+
"proposal": { "type": "string", "minLength": 4 },
|
|
68
|
+
"contract": { "type": "string", "minLength": 4 },
|
|
69
|
+
"acceptance": { "type": "string", "minLength": 4 },
|
|
70
|
+
"abort": { "type": "string", "minLength": 4 }
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"plugins": {
|
|
74
|
+
"type": "object",
|
|
75
|
+
"additionalProperties": false,
|
|
76
|
+
"required": ["superpowers"],
|
|
77
|
+
"properties": {
|
|
78
|
+
"superpowers": { "type": "string", "minLength": 1 }
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"requiredSkills": {
|
|
82
|
+
"type": "array",
|
|
83
|
+
"minItems": 6,
|
|
84
|
+
"uniqueItems": true,
|
|
85
|
+
"items": { "type": "string", "minLength": 1 }
|
|
86
|
+
},
|
|
87
|
+
"gradleVerification": {
|
|
88
|
+
"type": "object",
|
|
89
|
+
"additionalProperties": false,
|
|
90
|
+
"required": [
|
|
91
|
+
"fullUnitTestTasks",
|
|
92
|
+
"focusedTestTasks",
|
|
93
|
+
"assembleTasks",
|
|
94
|
+
"lintTasks",
|
|
95
|
+
"deviceTestTasks"
|
|
96
|
+
],
|
|
97
|
+
"properties": {
|
|
98
|
+
"fullUnitTestTasks": { "$ref": "#/$defs/gradleTaskList" },
|
|
99
|
+
"focusedTestTasks": { "$ref": "#/$defs/gradleTaskList" },
|
|
100
|
+
"assembleTasks": { "$ref": "#/$defs/gradleTaskList" },
|
|
101
|
+
"lintTasks": { "$ref": "#/$defs/gradleTaskList" },
|
|
102
|
+
"deviceTestTasks": { "$ref": "#/$defs/gradleTaskList" }
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
"androidProject": {
|
|
106
|
+
"type": "object",
|
|
107
|
+
"additionalProperties": false,
|
|
108
|
+
"required": [
|
|
109
|
+
"name",
|
|
110
|
+
"gradleDsl",
|
|
111
|
+
"settingsFile",
|
|
112
|
+
"primaryModule",
|
|
113
|
+
"modules",
|
|
114
|
+
"productionPaths",
|
|
115
|
+
"testPaths"
|
|
116
|
+
],
|
|
117
|
+
"properties": {
|
|
118
|
+
"name": { "type": "string", "minLength": 1 },
|
|
119
|
+
"gradleDsl": { "enum": ["kotlin", "groovy", "mixed"] },
|
|
120
|
+
"settingsFile": { "$ref": "#/$defs/repositoryPath" },
|
|
121
|
+
"moduleScope": { "enum": ["all", "primary"] },
|
|
122
|
+
"primaryModule": {
|
|
123
|
+
"type": "string",
|
|
124
|
+
"pattern": "^:(?:[A-Za-z0-9_.-]+(?::[A-Za-z0-9_.-]+)*)?$"
|
|
125
|
+
},
|
|
126
|
+
"modules": {
|
|
127
|
+
"type": "array",
|
|
128
|
+
"minItems": 1,
|
|
129
|
+
"items": {
|
|
130
|
+
"type": "object",
|
|
131
|
+
"additionalProperties": false,
|
|
132
|
+
"required": [
|
|
133
|
+
"gradlePath",
|
|
134
|
+
"directory",
|
|
135
|
+
"buildFile",
|
|
136
|
+
"dsl",
|
|
137
|
+
"type",
|
|
138
|
+
"namespace",
|
|
139
|
+
"applicationId"
|
|
140
|
+
],
|
|
141
|
+
"properties": {
|
|
142
|
+
"gradlePath": {
|
|
143
|
+
"type": "string",
|
|
144
|
+
"pattern": "^:(?:[A-Za-z0-9_.-]+(?::[A-Za-z0-9_.-]+)*)?$"
|
|
145
|
+
},
|
|
146
|
+
"directory": { "$ref": "#/$defs/repositoryPath" },
|
|
147
|
+
"buildFile": { "$ref": "#/$defs/repositoryPath" },
|
|
148
|
+
"dsl": { "enum": ["kotlin", "groovy"] },
|
|
149
|
+
"type": {
|
|
150
|
+
"enum": [
|
|
151
|
+
"application",
|
|
152
|
+
"library",
|
|
153
|
+
"dynamic-feature",
|
|
154
|
+
"test",
|
|
155
|
+
"asset-pack"
|
|
156
|
+
]
|
|
157
|
+
},
|
|
158
|
+
"namespace": { "$ref": "#/$defs/nullableIdentifier" },
|
|
159
|
+
"applicationId": { "$ref": "#/$defs/nullableIdentifier" }
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
"productionPaths": {
|
|
164
|
+
"type": "array",
|
|
165
|
+
"minItems": 1,
|
|
166
|
+
"uniqueItems": true,
|
|
167
|
+
"items": {
|
|
168
|
+
"allOf": [
|
|
169
|
+
{ "$ref": "#/$defs/repositoryPath" },
|
|
170
|
+
{ "pattern": "(^|/)src/main/\\*\\*$" }
|
|
171
|
+
]
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
"testPaths": {
|
|
175
|
+
"type": "array",
|
|
176
|
+
"minItems": 1,
|
|
177
|
+
"uniqueItems": true,
|
|
178
|
+
"items": {
|
|
179
|
+
"allOf": [
|
|
180
|
+
{ "$ref": "#/$defs/repositoryPath" },
|
|
181
|
+
{ "pattern": "(^|/)src/(?:test|androidTest)/\\*\\*$" }
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
"protectedPaths": {
|
|
188
|
+
"type": "array",
|
|
189
|
+
"minItems": 1,
|
|
190
|
+
"uniqueItems": true,
|
|
191
|
+
"items": { "$ref": "#/$defs/repositoryPath" }
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "urn:frankzhang2026:opencode-android-orchestrator:task-contract:v1",
|
|
4
|
+
"title": "Scheduled coding task contract",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"$defs": {
|
|
8
|
+
"gradleTask": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"minLength": 1,
|
|
11
|
+
"pattern": "^(?:[A-Za-z][A-Za-z0-9_.-]*|(?::[A-Za-z0-9_.-]+)+)$"
|
|
12
|
+
},
|
|
13
|
+
"testFilter": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"minLength": 1,
|
|
16
|
+
"pattern": "^[A-Za-z0-9_.#$*-]+$"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"required": [
|
|
20
|
+
"schemaVersion",
|
|
21
|
+
"id",
|
|
22
|
+
"title",
|
|
23
|
+
"designApproved",
|
|
24
|
+
"planPath",
|
|
25
|
+
"ambiguityPolicy",
|
|
26
|
+
"maxFixLoops",
|
|
27
|
+
"maxChangedFiles",
|
|
28
|
+
"allowedPaths",
|
|
29
|
+
"forbiddenPaths",
|
|
30
|
+
"allowedSuperpowers",
|
|
31
|
+
"acceptanceCriteria",
|
|
32
|
+
"nonGoals",
|
|
33
|
+
"targetTests",
|
|
34
|
+
"deviceTestsRequired",
|
|
35
|
+
"testPolicy"
|
|
36
|
+
],
|
|
37
|
+
"properties": {
|
|
38
|
+
"schemaVersion": { "const": 1 },
|
|
39
|
+
"id": { "type": "string", "pattern": "^TASK-[A-Z0-9-]+$" },
|
|
40
|
+
"title": { "type": "string", "minLength": 1 },
|
|
41
|
+
"designApproved": { "const": true },
|
|
42
|
+
"planPath": { "type": "string", "minLength": 1 },
|
|
43
|
+
"ambiguityPolicy": { "const": "BLOCKED" },
|
|
44
|
+
"maxFixLoops": { "type": "integer", "minimum": 0, "maximum": 1 },
|
|
45
|
+
"maxChangedFiles": { "type": "integer", "minimum": 1, "maximum": 12 },
|
|
46
|
+
"allowedPaths": {
|
|
47
|
+
"type": "array",
|
|
48
|
+
"minItems": 1,
|
|
49
|
+
"items": { "type": "string", "minLength": 1 }
|
|
50
|
+
},
|
|
51
|
+
"forbiddenPaths": {
|
|
52
|
+
"type": "array",
|
|
53
|
+
"minItems": 1,
|
|
54
|
+
"items": { "type": "string", "minLength": 1 }
|
|
55
|
+
},
|
|
56
|
+
"allowedSuperpowers": {
|
|
57
|
+
"type": "array",
|
|
58
|
+
"const": [
|
|
59
|
+
"test-driven-development",
|
|
60
|
+
"systematic-debugging",
|
|
61
|
+
"verification-before-completion"
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
"acceptanceCriteria": {
|
|
65
|
+
"type": "array",
|
|
66
|
+
"minItems": 1,
|
|
67
|
+
"items": { "type": "string", "minLength": 1 }
|
|
68
|
+
},
|
|
69
|
+
"nonGoals": {
|
|
70
|
+
"type": "array",
|
|
71
|
+
"minItems": 1,
|
|
72
|
+
"items": { "type": "string", "minLength": 1 }
|
|
73
|
+
},
|
|
74
|
+
"targetTests": {
|
|
75
|
+
"type": "array",
|
|
76
|
+
"minItems": 1,
|
|
77
|
+
"uniqueItems": true,
|
|
78
|
+
"items": {
|
|
79
|
+
"type": "object",
|
|
80
|
+
"additionalProperties": false,
|
|
81
|
+
"required": ["gradleTask", "filter"],
|
|
82
|
+
"properties": {
|
|
83
|
+
"gradleTask": { "$ref": "#/$defs/gradleTask" },
|
|
84
|
+
"filter": { "$ref": "#/$defs/testFilter" }
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"deviceTestsRequired": { "type": "boolean" },
|
|
89
|
+
"testPolicy": { "enum": ["required", "not-required"] },
|
|
90
|
+
"testPolicyReason": { "type": "string" }
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"id": "TASK-EXAMPLE-001",
|
|
4
|
+
"title": "Replace with one small, observable behavior change",
|
|
5
|
+
"designApproved": true,
|
|
6
|
+
"planPath": "docs/plans/TASK-EXAMPLE-001.md",
|
|
7
|
+
"ambiguityPolicy": "BLOCKED",
|
|
8
|
+
"maxFixLoops": 1,
|
|
9
|
+
"maxChangedFiles": 4,
|
|
10
|
+
"allowedPaths": [
|
|
11
|
+
"**/src/main/**",
|
|
12
|
+
"**/src/test/**",
|
|
13
|
+
"**/src/androidTest/**"
|
|
14
|
+
],
|
|
15
|
+
"forbiddenPaths": [
|
|
16
|
+
".opencode/**",
|
|
17
|
+
".automation-plugin/**",
|
|
18
|
+
"automation/**",
|
|
19
|
+
"scripts/automation/**",
|
|
20
|
+
"opencode.json",
|
|
21
|
+
"opencode.jsonc",
|
|
22
|
+
"AGENTS.md",
|
|
23
|
+
"gradle/**",
|
|
24
|
+
"gradlew",
|
|
25
|
+
"gradlew.bat",
|
|
26
|
+
"settings.gradle",
|
|
27
|
+
"settings.gradle.kts",
|
|
28
|
+
"build.gradle",
|
|
29
|
+
"build.gradle.kts",
|
|
30
|
+
"**/build.gradle",
|
|
31
|
+
"**/build.gradle.kts"
|
|
32
|
+
],
|
|
33
|
+
"allowedSuperpowers": [
|
|
34
|
+
"test-driven-development",
|
|
35
|
+
"systematic-debugging",
|
|
36
|
+
"verification-before-completion"
|
|
37
|
+
],
|
|
38
|
+
"acceptanceCriteria": [
|
|
39
|
+
"Replace with an observable input/output or UI behavior",
|
|
40
|
+
"A focused test demonstrates the behavior and is captured RED before implementation",
|
|
41
|
+
"Unit tests, debug build, and lint all pass"
|
|
42
|
+
],
|
|
43
|
+
"nonGoals": [
|
|
44
|
+
"Do not refactor unrelated screens",
|
|
45
|
+
"Do not upgrade dependencies or Gradle configuration"
|
|
46
|
+
],
|
|
47
|
+
"targetTests": [
|
|
48
|
+
{
|
|
49
|
+
"gradleTask": "testDebugUnitTest",
|
|
50
|
+
"filter": "*ReplaceWithFocusedTest"
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"deviceTestsRequired": false,
|
|
54
|
+
"testPolicy": "required",
|
|
55
|
+
"testPolicyReason": "Behavior changes require a focused regression test"
|
|
56
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Human-approved automation plans
|
|
2
|
+
|
|
3
|
+
Every orchestrated coding contract must reference one plan in this directory.
|
|
4
|
+
Planning is interactive and happens before a task is approved for execution; unattended agents
|
|
5
|
+
must not create, broaden, or reinterpret these plans.
|
|
6
|
+
|
|
7
|
+
The normal entry point is a natural-language task description entered in an
|
|
8
|
+
interactive `scheduled-planner` OpenCode session. The planner must inspect the
|
|
9
|
+
repository, present the proposed scope and acceptance criteria, and receive
|
|
10
|
+
explicit human approval before it creates this plan and the matching JSON
|
|
11
|
+
contract.
|
|
12
|
+
|
|
13
|
+
A plan should contain:
|
|
14
|
+
|
|
15
|
+
- one observable behavior change;
|
|
16
|
+
- acceptance criteria and edge cases;
|
|
17
|
+
- allowed and forbidden repository paths;
|
|
18
|
+
- the focused test class/filter that will provide RED evidence;
|
|
19
|
+
- explicit non-goals;
|
|
20
|
+
- device/emulator requirements, if any;
|
|
21
|
+
- a dated human approval statement.
|
|
22
|
+
|
|
23
|
+
After proposal approval, Planner seals both artifacts in `CONTRACT_REVIEW`.
|
|
24
|
+
The matching contract belongs in `automation/tasks/TASK-<ID>.json`. A missing
|
|
25
|
+
plan, placeholder text, or mismatched task ID causes contract validation to
|
|
26
|
+
fail.
|