@frankzhang2026/opencode-android-orchestrator 1.0.1 → 1.0.2

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 CHANGED
@@ -1,7 +1,15 @@
1
1
  # Changelog
2
2
 
3
3
 
4
- ## 1.0.1 - Unreleased
4
+ ## 1.0.2 - 2026-09-15
5
+
6
+ - Accept queue-owned OpenCode shell commands that remain descendants of the
7
+ active Worker even when the tool runtime creates a separate process group.
8
+ - Keep run-id, queue-key and Worker ancestry checks so unrelated processes
9
+ cannot claim a queued task by copying its public run identifier.
10
+
11
+
12
+ ## 1.0.1 - 2026-09-15
5
13
 
6
14
  - Keep planning snapshots small in large repositories by returning only the
7
15
  stable branch and commit metadata from the initial snapshot call.
package/README.md CHANGED
@@ -30,7 +30,9 @@ fixed-directory tasks may use `autoCommit`. Optional isolated worktrees keep
30
30
  human acceptance while allowing independent tasks to proceed. Every queued
31
31
  execution requires build, fresh full unit tests and independent Review. All
32
32
  completion and recovery paths remain local and never push.
33
- Version `1.0.1` bounds Planner snapshot output for large repositories. The
33
+ Version `1.0.2` also allows queue-owned OpenCode shell commands to use a
34
+ separate process group while preserving Worker ancestry checks. Version `1.0.1`
35
+ bounds Planner snapshot output for large repositories. The
34
36
  initial snapshot returns only the target branch and fixed commit; path discovery
35
37
  and file content use bounded cursor pages tied to that commit.
36
38
 
@@ -69,9 +71,9 @@ project builds retain their configured cache behavior.
69
71
  ## Quick start
70
72
 
71
73
  ```sh
72
- npx @frankzhang2026/opencode-android-orchestrator@1.0.1 init .
74
+ npx @frankzhang2026/opencode-android-orchestrator@1.0.2 init .
73
75
  $EDITOR automation/automation-commit-prefix
74
- npx @frankzhang2026/opencode-android-orchestrator@1.0.1 doctor .
76
+ npx @frankzhang2026/opencode-android-orchestrator@1.0.2 doctor .
75
77
  opencode --agent scheduled-planner .
76
78
  ```
77
79
 
@@ -81,7 +83,7 @@ a task contract without selecting a primary module. To intentionally restrict
81
83
  generated contracts to one module, opt into primary-module scope:
82
84
 
83
85
  ```sh
84
- npx @frankzhang2026/opencode-android-orchestrator@1.0.1 init . \
86
+ npx @frankzhang2026/opencode-android-orchestrator@1.0.2 init . \
85
87
  --module-scope primary \
86
88
  --primary-module :mobile
87
89
  ```
@@ -109,7 +111,7 @@ For an existing manifest-managed installation whose generated module/task
109
111
  lists are incomplete, refresh all derived Gradle data in one upgrade:
110
112
 
111
113
  ```sh
112
- npx @frankzhang2026/opencode-android-orchestrator@1.0.1 upgrade . \
114
+ npx @frankzhang2026/opencode-android-orchestrator@1.0.2 upgrade . \
113
115
  --refresh-gradle-discovery
114
116
  ```
115
117
 
@@ -435,7 +437,7 @@ preparation alone as resource installation;
435
437
  ## Init
436
438
 
437
439
  ```sh
438
- npx @frankzhang2026/opencode-android-orchestrator@1.0.1 init .
440
+ npx @frankzhang2026/opencode-android-orchestrator@1.0.2 init .
439
441
  $EDITOR automation/automation-commit-prefix
440
442
  opencode --agent scheduled-planner .
441
443
  ```
@@ -1,8 +1,8 @@
1
1
  export declare const ORCHESTRATOR_PACKAGE_NAME = "@frankzhang2026/opencode-android-orchestrator";
2
- export declare const ORCHESTRATOR_PACKAGE_VERSION = "1.0.1";
3
- export declare const ORCHESTRATOR_PLUGIN_REFERENCE = "@frankzhang2026/opencode-android-orchestrator@1.0.1";
2
+ export declare const ORCHESTRATOR_PACKAGE_VERSION = "1.0.2";
3
+ export declare const ORCHESTRATOR_PLUGIN_REFERENCE = "@frankzhang2026/opencode-android-orchestrator@1.0.2";
4
4
  export declare const OPENCODE_CONFIG_SCHEMA_URL = "https://opencode.ai/config.json";
5
- export declare const REQUIRED_PLUGIN_REFERENCES: readonly ["@frankzhang2026/opencode-android-orchestrator@1.0.1"];
5
+ export declare const REQUIRED_PLUGIN_REFERENCES: readonly ["@frankzhang2026/opencode-android-orchestrator@1.0.2"];
6
6
  export type OpenCodeConfigMergeErrorCode = "AMBIGUOUS_CONFIG" | "CONFIG_NOT_FILE" | "CONFIG_READ_FAILED" | "CONFIG_SYMLINK" | "DUPLICATE_PLUGIN" | "DUPLICATE_PROPERTY" | "INVALID_JSONC" | "INVALID_PLUGIN_ENTRY" | "PLUGIN_NOT_ARRAY" | "PLUGIN_VERSION_CONFLICT" | "ROOT_NOT_OBJECT" | "TARGET_NOT_DIRECTORY";
7
7
  export declare class OpenCodeConfigMergeError extends Error {
8
8
  readonly code: OpenCodeConfigMergeErrorCode;
@@ -2,7 +2,7 @@ import { lstatSync, readFileSync, statSync } from "node:fs";
2
2
  import { join, resolve } from "node:path";
3
3
  import { applyEdits, findNodeAtLocation, getNodeValue, modify, parseTree, printParseErrorCode, } from "jsonc-parser";
4
4
  export const ORCHESTRATOR_PACKAGE_NAME = "@frankzhang2026/opencode-android-orchestrator";
5
- export const ORCHESTRATOR_PACKAGE_VERSION = "1.0.1";
5
+ export const ORCHESTRATOR_PACKAGE_VERSION = "1.0.2";
6
6
  export const ORCHESTRATOR_PLUGIN_REFERENCE = `${ORCHESTRATOR_PACKAGE_NAME}@${ORCHESTRATOR_PACKAGE_VERSION}`;
7
7
  export const OPENCODE_CONFIG_SCHEMA_URL = "https://opencode.ai/config.json";
8
8
  export const REQUIRED_PLUGIN_REFERENCES = [
package/docs/MIGRATION.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Migration guide
2
2
 
3
3
  This guide covers migration to
4
- `@frankzhang2026/opencode-android-orchestrator@1.0.1`. Pin the exact version and
4
+ `@frankzhang2026/opencode-android-orchestrator@1.0.2`. Pin the exact version and
5
5
  prove the migration in a disposable clone before changing a long-lived
6
6
  repository.
7
7
 
@@ -9,10 +9,10 @@ repository.
9
9
 
10
10
  | Current state | Correct command after release | Important distinction |
11
11
  | --- | --- | --- |
12
- | No orchestrator files or manifest | `npx @frankzhang2026/opencode-android-orchestrator@1.0.1 init .` | Normal new installation; all runtime-detected Android modules and registered debug verification tasks are discovered automatically. |
12
+ | No orchestrator files or manifest | `npx @frankzhang2026/opencode-android-orchestrator@1.0.2 init .` | Normal new installation; all runtime-detected Android modules and registered debug verification tasks are discovered automatically. |
13
13
  | Published `0.1.0` scaffold only | Remove any project-local `@0.1.0` plugin reference after review, then run `init`. | `0.1.0` did not create a usable managed installation and cannot be upgraded. |
14
14
  | `0.2.0` through `0.10.0` manifest-managed installation with intact managed/backup content | Run the `1.0.0` `upgrade`; add `--refresh-gradle-discovery` when generated module/task lists are incomplete. | Refresh replaces all derived module metadata, source paths, protected build files, and task allowlists from one Gradle runtime snapshot. Module scope, operator policies, user-owned AGENTS content, and an existing commit-prefix sidecar remain preserved. |
15
- | Healthy `1.0.0` installation | Stop the queue service, finish or abort retained workspaces, then run the fixed `1.0.1` `upgrade`. | Pending inbox contracts remain durable. Restart OpenCode so Planner loads the bounded snapshot actions. |
15
+ | Healthy `1.0.0` or `1.0.1` installation | Stop the queue service, finish or abort retained workspaces, then run the fixed `1.0.2` `upgrade`. | Pending inbox contracts remain durable. Version 1.0.2 keeps bounded snapshots and fixes task claiming when OpenCode gives tool commands a separate process group. |
16
16
  | Manually copied V3 files, no `.automation-plugin/manifest.json` | Finish active tasks, preserve historical evidence separately, then run `init`. | Exact files can be reused; differing managed files fail as conflicts. |
17
17
  | Healthy older manifest-managed installation | Run `doctor`, then the fixed target version's `upgrade`. | `upgrade` requires a valid installed manifest and intact original backups. |
18
18
  | Healthy current-version manifest | Run `doctor`; repeated `init` or same-version `upgrade` is verification-only and byte-idempotent. | Do not reinstall or delete the manifest. |
@@ -58,7 +58,7 @@ installation of `0.1.0` alone does not require project-file cleanup.
58
58
  After release, initialize with the fixed version:
59
59
 
60
60
  ```sh
61
- npx @frankzhang2026/opencode-android-orchestrator@1.0.1 init .
61
+ npx @frankzhang2026/opencode-android-orchestrator@1.0.2 init .
62
62
  ```
63
63
 
64
64
  New installations default to all-module scope, so multiple application modules
@@ -106,7 +106,7 @@ Use the lifecycle command selected by the active manifest:
106
106
 
107
107
  ```sh
108
108
  npx --yes --registry=https://registry.npmjs.org/ \
109
- @frankzhang2026/opencode-android-orchestrator@1.0.1 upgrade . --json
109
+ @frankzhang2026/opencode-android-orchestrator@1.0.2 upgrade . --json
110
110
  ```
111
111
 
112
112
  The command-level Registry option is useful when a company-wide npm Registry
@@ -136,7 +136,7 @@ computed includes dynamically or a company convention plugin applied
136
136
 
137
137
  ```sh
138
138
  npx --yes --registry=https://registry.npmjs.org/ \
139
- @frankzhang2026/opencode-android-orchestrator@1.0.1 upgrade . \
139
+ @frankzhang2026/opencode-android-orchestrator@1.0.2 upgrade . \
140
140
  --refresh-gradle-discovery --json
141
141
  ```
142
142
 
@@ -220,7 +220,7 @@ use the queue rather than the old direct Shell commands. See [Queue operation](Q
220
220
  Run all checks from the detected Git root:
221
221
 
222
222
  ```sh
223
- npx @frankzhang2026/opencode-android-orchestrator@1.0.1 doctor .
223
+ npx @frankzhang2026/opencode-android-orchestrator@1.0.2 doctor .
224
224
  opencode debug config
225
225
  opencode debug skill
226
226
  opencode debug agent scheduled-planner
package/docs/QUEUE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Queue and background execution
2
2
 
3
- Version `1.0.1` stores proposals and approved contracts under
3
+ Version `1.0.2` stores proposals and approved contracts under
4
4
  `<git-common-dir>/automation-runtime/inbox/queue.json`. A contract is runnable
5
5
  only after its full plan, version, digest, target branch and commit policy are
6
6
  approved and durably recorded. Planning reads a fixed `planningHead`, so another
@@ -42,6 +42,10 @@ dependency. Fixed workspaces remain occupied during failures and human waiting.
42
42
  The worker resolves the Android SDK from `ANDROID_HOME`, `ANDROID_SDK_ROOT`,
43
43
  then the source repository's `local.properties` and passes the resolved location
44
44
  to its shell and Gradle processes. Isolated worktrees do not copy that local file.
45
+ Every mutating task script binds the workspace queue key and run ID to the
46
+ active Worker. The script may share the Worker's process group or be a proven
47
+ descendant in a separate OpenCode tool process group; an unrelated process is
48
+ rejected even if it copies the visible run ID.
45
49
 
46
50
  ## Service and scheduling
47
51
 
package/docs/SECURITY.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Security model
2
2
 
3
3
  This document describes the security properties of
4
- `@frankzhang2026/opencode-android-orchestrator@1.0.1`. The lifecycle foundation
4
+ `@frankzhang2026/opencode-android-orchestrator@1.0.2`. The lifecycle foundation
5
5
  completed the real OpenCode `1.14.22` and `1.15.13` release matrix in `0.2.0`;
6
6
  `1.0.0` retains that compatibility boundary.
7
7
 
@@ -95,6 +95,14 @@ value is an integer from `120000` through `7200000` milliseconds, defaults to
95
95
  `1800000`, never shortens a larger caller timeout, and does not rewrite the
96
96
  command or authorize a state change.
97
97
 
98
+ Queued task scripts validate the sealed workspace queue key and run ID against
99
+ the active Worker. OpenCode tool shells are accepted only when they either
100
+ share that Worker's process group or remain provable descendants of its PID;
101
+ this supports PTY/sandbox process-group isolation without accepting an
102
+ unrelated process that merely copies the run ID. Recovery continues to retain
103
+ the execution slot while the recorded Worker or its original process group is
104
+ alive.
105
+
98
106
  The five namespaced bundled workflow skills are loaded from a fixed directory
99
107
  inside the installed npm package. The compatible `config` hook only appends
100
108
  that directory to `skills.paths`, and plugin startup verifies that every
@@ -1,7 +1,7 @@
1
1
  # Troubleshooting
2
2
 
3
3
  Use this guide for
4
- `@frankzhang2026/opencode-android-orchestrator@1.0.1`.
4
+ `@frankzhang2026/opencode-android-orchestrator@1.0.2`.
5
5
 
6
6
  ## Start with read-only evidence
7
7
 
@@ -11,7 +11,7 @@ From the repository root, capture:
11
11
  git status --short --branch
12
12
  git rev-parse HEAD
13
13
  opencode --version
14
- npx @frankzhang2026/opencode-android-orchestrator@1.0.1 doctor . --json
14
+ npx @frankzhang2026/opencode-android-orchestrator@1.0.2 doctor . --json
15
15
  ```
16
16
 
17
17
  If installation never completed, doctor will correctly report a missing or
@@ -39,9 +39,9 @@ command-scoped override:
39
39
 
40
40
  ```sh
41
41
  npm --registry=https://registry.npmjs.org/ view \
42
- @frankzhang2026/opencode-android-orchestrator@1.0.1 version
42
+ @frankzhang2026/opencode-android-orchestrator@1.0.2 version
43
43
  npx --yes --registry=https://registry.npmjs.org/ \
44
- @frankzhang2026/opencode-android-orchestrator@1.0.1 upgrade . --json
44
+ @frankzhang2026/opencode-android-orchestrator@1.0.2 upgrade . --json
45
45
  ```
46
46
 
47
47
  This leaves the company's saved npm configuration unchanged. Use the option
@@ -71,7 +71,8 @@ Git-backed Superpowers plugin at runtime.
71
71
  | Invalid `--long-command-timeout-ms` | The value is not an integer from `120000` through `7200000`. | Use the `1800000` ms default or pass an intentional bounded value to `init`/`upgrade`; do not edit the generated config directly. |
72
72
  | Android SDK failure | No valid explicit SDK, `ANDROID_HOME`, `ANDROID_SDK_ROOT`, or `local.properties` `sdk.dir` was found. | Configure one real SDK root containing `platforms/` and `build-tools/`. Do not publish `local.properties`. |
73
73
  | Missing `git`, `jq`, `rg`, `shasum`, or Java | Required deterministic command is unavailable on `PATH`. | Install or restore the missing command, record its version, and rerun the read-only checks. |
74
- | `Bundled Orchestrator skill is unavailable` | The installed `1.0.1` package is incomplete, damaged, or loaded from an unsupported partial copy. | Reinstall the exact package, inspect its `resources/third-party/superpowers-v6.2.0/skills/` entries, restart OpenCode, and rerun `opencode debug skill`. Do not add an external Superpowers plugin as a fallback. |
74
+ | `Bundled Orchestrator skill is unavailable` | The installed `1.0.2` package is incomplete, damaged, or loaded from an unsupported partial copy. | Reinstall the exact package, inspect its `resources/third-party/superpowers-v6.2.0/skills/` entries, restart OpenCode, and rerun `opencode debug skill`. Do not add an external Superpowers plugin as a fallback. |
75
+ | `current process does not own this task queue execution` immediately after Coder start on 1.0.1 | OpenCode created the tool shell in a separate process group, so 1.0.1 rejected a legitimate Worker descendant. | Upgrade to 1.0.2, restart OpenCode, then use the approved resume or abort workflow for the retained task. Do not edit the queue or lease files. |
75
76
  | The exact Superpowers v6.2.0 plugin remains after upgrade | That entry existed in the verified pre-install OpenCode file and is therefore user-owned. | Leave it in place or remove it as a separate reviewed configuration change. Upgrade only removes the old Orchestrator-managed entry. |
76
77
 
77
78
  Version `0.6.0` always passes `--no-configuration-cache` to its temporary
@@ -87,7 +88,7 @@ silence of `./gradlew tasks --all --console=plain | rg ...` in a large build.
87
88
  For an existing installation, run:
88
89
 
89
90
  ```sh
90
- npx @frankzhang2026/opencode-android-orchestrator@1.0.1 upgrade . \
91
+ npx @frankzhang2026/opencode-android-orchestrator@1.0.2 upgrade . \
91
92
  --refresh-gradle-discovery
92
93
  ```
93
94
 
@@ -96,7 +97,7 @@ least `1800000` milliseconds. A higher timeout already supplied by the caller
96
97
  is preserved; unrelated Bash commands are unchanged. To configure one hour,
97
98
  run `upgrade . --long-command-timeout-ms 3600000` on a healthy installation.
98
99
  If a command still reports `120000 ms`, confirm that the project manifest and
99
- OpenCode plugin reference are both `1.0.1`, restart the OpenCode session so the
100
+ OpenCode plugin reference are both `1.0.2`, restart the OpenCode session so the
100
101
  plugin reloads, and rerun doctor before attempting recovery.
101
102
 
102
103
  After installation, inspect OpenCode discovery separately:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frankzhang2026/opencode-android-orchestrator",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Reusable OpenCode orchestration for Android projects",
5
5
  "license": "MIT",
6
6
  "author": "frankzhang2026",
@@ -219,9 +219,28 @@ automation_workspace_path() {
219
219
  printf '%s/%s.json\n' "$AUTOMATION_WORKSPACES_DIR" "$task_id"
220
220
  }
221
221
 
222
+ automation_process_descends_from() {
223
+ local current_pid="$1"
224
+ local ancestor_pid="$2"
225
+ local parent_pid=""
226
+ local depth=0
227
+
228
+ [[ "$current_pid" =~ ^[0-9]+$ && "$ancestor_pid" =~ ^[0-9]+$ ]] || return 1
229
+ while (( depth < 128 )); do
230
+ [[ "$current_pid" == "$ancestor_pid" ]] && return 0
231
+ parent_pid="$(ps -o ppid= -p "$current_pid" 2>/dev/null | tr -d '[:space:]')"
232
+ [[ "$parent_pid" =~ ^[0-9]+$ ]] || return 1
233
+ (( parent_pid > 1 )) || return 1
234
+ [[ "$parent_pid" != "$current_pid" ]] || return 1
235
+ current_pid="$parent_pid"
236
+ depth=$((depth + 1))
237
+ done
238
+ return 1
239
+ }
240
+
222
241
  automation_require_queue_execution() {
223
242
  local task_id="$1"
224
- local workspace_file queue_key group
243
+ local workspace_file queue_key group worker_pid
225
244
  workspace_file="$(automation_workspace_path "$task_id")"
226
245
  [[ -f "$workspace_file" ]] || return 0
227
246
  queue_key="$(jq -r '.queueKey // empty' "$workspace_file")"
@@ -230,13 +249,21 @@ automation_require_queue_execution() {
230
249
  automation_die "queued tasks must use the repository queue for execution, integration and recovery"
231
250
  return 1
232
251
  }
252
+ if ! worker_pid="$(jq -er --arg key "$queue_key" --arg run "$AUTOMATION_QUEUE_RUN_ID" \
253
+ 'select(.active.key == $key and .active.id == $run) | .active.worker.pid' \
254
+ "$AUTOMATION_RUNTIME_ROOT/inbox/queue.json")"; then
255
+ automation_die "current process does not own this task queue execution"
256
+ return 1
257
+ fi
258
+ [[ "$worker_pid" =~ ^[0-9]+$ ]] || {
259
+ automation_die "current process does not own this task queue execution"
260
+ return 1
261
+ }
233
262
  group="$(ps -o pgid= -p "$$" | tr -d ' ')"
234
- jq -e --arg key "$queue_key" --arg run "$AUTOMATION_QUEUE_RUN_ID" --argjson group "$group" \
235
- '.active.key == $key and .active.id == $run and .active.worker.pid == $group' \
236
- "$AUTOMATION_RUNTIME_ROOT/inbox/queue.json" >/dev/null || {
237
- automation_die "current process does not own this task queue execution"
238
- return 1
239
- }
263
+ if [[ "$group" != "$worker_pid" ]] && ! automation_process_descends_from "$$" "$worker_pid"; then
264
+ automation_die "current process does not own this task queue execution"
265
+ return 1
266
+ fi
240
267
  }
241
268
 
242
269
  automation_workspace_strategy() {