patchwork-os 0.2.0-beta.13.canary.300 → 0.2.0-beta.13.canary.301

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/dist/index.js CHANGED
@@ -161,6 +161,7 @@ const KNOWN_SUBCOMMANDS = [
161
161
  "shadow-scan",
162
162
  "workers",
163
163
  "approvals",
164
+ "gate",
164
165
  ];
165
166
  const __invokedSubcommand = (() => {
166
167
  const sub = process.argv[2];
@@ -3937,6 +3938,63 @@ if (process.argv[2] === "approvals") {
3937
3938
  }
3938
3939
  })();
3939
3940
  }
3941
+ // Handle gate subcommand — "why did the worker allow/gate THIS action" over
3942
+ // the local Decision Record (worker_gate_decisions.jsonl). Reads the log
3943
+ // directly (like `workers shadow` / `approvals`); no bridge round-trip needed
3944
+ // since the record is a local file, not live state.
3945
+ if (process.argv[2] === "gate") {
3946
+ const args = process.argv.slice(3);
3947
+ const sub = args[0];
3948
+ if (sub !== "explain" ||
3949
+ args.includes("--help") ||
3950
+ args.includes("-h") ||
3951
+ args.length < 3) {
3952
+ process.stdout.write("Usage: patchwork gate explain <workerId> <classKey> [--limit N] [--json]\n\n" +
3953
+ "Explain the worker-autonomy gate's most recent decision(s) for a given\n" +
3954
+ "worker × action-class, from the local Decision Record\n" +
3955
+ "(~/.patchwork/worker_gate_decisions.jsonl) — no bridge required.\n\n" +
3956
+ ' <classKey> e.g. "issue:compensable:high" (domain:reversibility:blastTier)\n' +
3957
+ " --limit N show the N most recent decisions (default 1)\n" +
3958
+ " --json emit raw JSON (for scripting)\n");
3959
+ process.exit(sub === "explain" ? 1 : 0);
3960
+ }
3961
+ (async () => {
3962
+ try {
3963
+ // Length checked above (args.length < 3 short-circuits to usage), so
3964
+ // args[1]/[2] are present here — noUncheckedIndexedAccess just can't see
3965
+ // across the `if` block above.
3966
+ const workerId = args[1];
3967
+ const classKey = args[2];
3968
+ const limitIdx = args.indexOf("--limit");
3969
+ const limit = limitIdx >= 0 && limitIdx + 1 < args.length
3970
+ ? Number.parseInt(args[limitIdx + 1], 10)
3971
+ : 1;
3972
+ if (!Number.isFinite(limit) || limit < 1) {
3973
+ process.stderr.write("Error: --limit must be a positive integer\n");
3974
+ process.exit(1);
3975
+ }
3976
+ const { WorkerGateDecisionLog, formatGateDecisionHistory } = await import("./workerGateDecisionLog.js");
3977
+ const patchworkDir = process.env.PATCHWORK_HOME ?? path.join(os.homedir(), ".patchwork");
3978
+ const log = new WorkerGateDecisionLog({ dir: patchworkDir });
3979
+ const decisions = log.query({ workerId, classKey, limit });
3980
+ if (args.includes("--json")) {
3981
+ process.stdout.write(`${JSON.stringify(decisions, null, 2)}\n`);
3982
+ process.exit(0);
3983
+ }
3984
+ if (decisions.length === 0) {
3985
+ process.stdout.write(`No gate decisions found for worker "${workerId}" on class "${classKey}".\n` +
3986
+ "Either the worker hasn't acted on this class yet, or worker.autonomy is off.\n");
3987
+ process.exit(0);
3988
+ }
3989
+ process.stdout.write(`${formatGateDecisionHistory(decisions)}\n`);
3990
+ process.exit(0);
3991
+ }
3992
+ catch (err) {
3993
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}\n`);
3994
+ process.exit(1);
3995
+ }
3996
+ })();
3997
+ }
3940
3998
  // Handle launchd subcommand — install/uninstall macOS LaunchAgent for auto-start
3941
3999
  if (process.argv[2] === "launchd") {
3942
4000
  const sub = process.argv[3];