patchwork-os 0.2.0-beta.2 → 0.2.0-beta.3
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/README.bridge.md +5 -5
- package/README.md +156 -12
- package/dist/activityLog.d.ts +6 -0
- package/dist/activityLog.js +8 -0
- package/dist/activityLog.js.map +1 -1
- package/dist/analyticsPrefs.d.ts +35 -2
- package/dist/analyticsPrefs.js +120 -21
- package/dist/analyticsPrefs.js.map +1 -1
- package/dist/analyticsSend.js +5 -1
- package/dist/analyticsSend.js.map +1 -1
- package/dist/bridge.d.ts +2 -0
- package/dist/bridge.js +111 -7
- package/dist/bridge.js.map +1 -1
- package/dist/bridgeLockDiscovery.d.ts +27 -1
- package/dist/bridgeLockDiscovery.js +37 -11
- package/dist/bridgeLockDiscovery.js.map +1 -1
- package/dist/commands/patchworkInit.d.ts +5 -0
- package/dist/commands/patchworkInit.js +86 -7
- package/dist/commands/patchworkInit.js.map +1 -1
- package/dist/commands/recipe.d.ts +51 -0
- package/dist/commands/recipe.js +353 -2
- package/dist/commands/recipe.js.map +1 -1
- package/dist/commands/recipeInstall.js +6 -3
- package/dist/commands/recipeInstall.js.map +1 -1
- package/dist/commands/task.js +2 -2
- package/dist/commands/task.js.map +1 -1
- package/dist/config.d.ts +9 -2
- package/dist/config.js +35 -17
- package/dist/config.js.map +1 -1
- package/dist/connectors/tokenStorage.js +46 -10
- package/dist/connectors/tokenStorage.js.map +1 -1
- package/dist/featureFlags.d.ts +76 -0
- package/dist/featureFlags.js +166 -2
- package/dist/featureFlags.js.map +1 -1
- package/dist/index.js +765 -69
- package/dist/index.js.map +1 -1
- package/dist/lockfile.js +4 -1
- package/dist/lockfile.js.map +1 -1
- package/dist/patchworkConfig.js +5 -0
- package/dist/patchworkConfig.js.map +1 -1
- package/dist/recipeOrchestration.js +35 -1
- package/dist/recipeOrchestration.js.map +1 -1
- package/dist/recipeRoutes.d.ts +36 -0
- package/dist/recipeRoutes.js +231 -32
- package/dist/recipeRoutes.js.map +1 -1
- package/dist/recipes/agentExecutor.d.ts +25 -5
- package/dist/recipes/agentExecutor.js.map +1 -1
- package/dist/recipes/chainedRunner.js +16 -2
- package/dist/recipes/chainedRunner.js.map +1 -1
- package/dist/recipes/connectorPreflight.d.ts +53 -0
- package/dist/recipes/connectorPreflight.js +79 -0
- package/dist/recipes/connectorPreflight.js.map +1 -0
- package/dist/recipes/githubInstallSource.d.ts +62 -0
- package/dist/recipes/githubInstallSource.js +125 -0
- package/dist/recipes/githubInstallSource.js.map +1 -0
- package/dist/recipes/haltCategory.d.ts +80 -0
- package/dist/recipes/haltCategory.js +125 -0
- package/dist/recipes/haltCategory.js.map +1 -0
- package/dist/recipes/idempotencyKey.d.ts +126 -0
- package/dist/recipes/idempotencyKey.js +298 -0
- package/dist/recipes/idempotencyKey.js.map +1 -0
- package/dist/recipes/judgeSummary.d.ts +50 -0
- package/dist/recipes/judgeSummary.js +47 -0
- package/dist/recipes/judgeSummary.js.map +1 -0
- package/dist/recipes/judgeVerdict.d.ts +48 -0
- package/dist/recipes/judgeVerdict.js +174 -0
- package/dist/recipes/judgeVerdict.js.map +1 -0
- package/dist/recipes/migrations/index.d.ts +9 -0
- package/dist/recipes/migrations/index.js +133 -0
- package/dist/recipes/migrations/index.js.map +1 -1
- package/dist/recipes/runBudget.d.ts +70 -0
- package/dist/recipes/runBudget.js +109 -0
- package/dist/recipes/runBudget.js.map +1 -0
- package/dist/recipes/scheduler.js +1 -1
- package/dist/recipes/scheduler.js.map +1 -1
- package/dist/recipes/schema.d.ts +30 -0
- package/dist/recipes/toolRegistry.js +19 -0
- package/dist/recipes/toolRegistry.js.map +1 -1
- package/dist/recipes/tools/http.d.ts +10 -0
- package/dist/recipes/tools/http.js +176 -0
- package/dist/recipes/tools/http.js.map +1 -0
- package/dist/recipes/tools/index.d.ts +1 -0
- package/dist/recipes/tools/index.js +1 -0
- package/dist/recipes/tools/index.js.map +1 -1
- package/dist/recipes/validation.js +1 -1
- package/dist/recipes/validation.js.map +1 -1
- package/dist/recipes/yamlRunner.d.ts +71 -7
- package/dist/recipes/yamlRunner.js +156 -22
- package/dist/recipes/yamlRunner.js.map +1 -1
- package/dist/runLog.d.ts +28 -0
- package/dist/runLog.js +5 -0
- package/dist/runLog.js.map +1 -1
- package/dist/server.d.ts +65 -0
- package/dist/server.js +302 -3
- package/dist/server.js.map +1 -1
- package/dist/streamableHttp.js +17 -6
- package/dist/streamableHttp.js.map +1 -1
- package/dist/tools/bridgeDoctor.js +6 -2
- package/dist/tools/bridgeDoctor.js.map +1 -1
- package/dist/tools/ccRoutines.d.ts +221 -0
- package/dist/tools/ccRoutines.js +264 -0
- package/dist/tools/ccRoutines.js.map +1 -0
- package/dist/tools/getCodeCoverage.js +7 -3
- package/dist/tools/getCodeCoverage.js.map +1 -1
- package/dist/tools/index.js +6 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/recentTracesDigest.js +56 -11
- package/dist/tools/recentTracesDigest.js.map +1 -1
- package/dist/tools/testRunners/vitestJest.js +3 -1
- package/dist/tools/testRunners/vitestJest.js.map +1 -1
- package/dist/tools/utils.js +6 -3
- package/dist/tools/utils.js.map +1 -1
- package/package.json +17 -6
- package/scripts/postinstall.mjs +27 -0
- package/scripts/smoke/run-all.mjs +162 -0
- package/scripts/start-all.mjs +513 -0
- package/scripts/start-all.ps1 +209 -0
- package/scripts/start-all.sh +73 -17
- package/scripts/start-orchestrator.ps1 +158 -0
- package/scripts/start-remote.mjs +122 -0
- package/templates/automation-policies/recipe-authoring.json +1 -1
- package/templates/automation-policies/security-first.json +1 -1
- package/templates/automation-policies/strict-lint.json +1 -1
- package/templates/automation-policies/test-driven.json +1 -1
- package/templates/automation-policy.example.json +1 -1
- package/templates/co.patchwork-os.bridge.plist +1 -1
- package/templates/recipes/approval-queue-ui-test.yaml +1 -1
- package/templates/recipes/ctx-loop-test.yaml +1 -1
- package/templates/recipes/webhook/apple-watch-health-log.yaml +145 -0
- package/dist/commands/marketplace.d.ts +0 -16
- package/dist/commands/marketplace.js +0 -32
- package/dist/commands/marketplace.js.map +0 -1
- package/dist/recipes/legacyRecipeCompat.d.ts +0 -10
- package/dist/recipes/legacyRecipeCompat.js +0 -131
- package/dist/recipes/legacyRecipeCompat.js.map +0 -1
package/dist/featureFlags.d.ts
CHANGED
|
@@ -51,8 +51,53 @@ export declare function _resetEnvLockForTesting(): void;
|
|
|
51
51
|
* 3. Default value from registration
|
|
52
52
|
*/
|
|
53
53
|
export declare function isEnabled(flagId: string): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Returns true when the given kill-switch flag is **env-locked** — i.e. its
|
|
56
|
+
* value was frozen at startup from a `PATCHWORK_FLAG_<ID>` environment
|
|
57
|
+
* variable and any subsequent `setFlag()` call will be silently overridden
|
|
58
|
+
* by `isEnabled()`.
|
|
59
|
+
*
|
|
60
|
+
* Used by the `/kill-switch` endpoint (issue #422) to surface a 409
|
|
61
|
+
* Conflict instead of returning 200 OK for a setFlag that won't stick,
|
|
62
|
+
* and by the dashboard to render the toggle as disabled (with a tooltip
|
|
63
|
+
* naming which direction was sysadmin-locked) when this returns true.
|
|
64
|
+
*
|
|
65
|
+
* Returns false for non-kill-switch flags (they read env dynamically and
|
|
66
|
+
* are never "locked"), for unknown flags, and when `lockKillSwitchEnv()`
|
|
67
|
+
* has not yet been called.
|
|
68
|
+
*/
|
|
69
|
+
export declare function isEnvLockedFor(flagId: string): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Returns the frozen env-locked value for a kill-switch flag (`true` /
|
|
72
|
+
* `false`), or `null` if not env-locked.
|
|
73
|
+
*
|
|
74
|
+
* Used by the dashboard tooltip so the disabled-state can read "env-locked
|
|
75
|
+
* to **on**" vs "env-locked to **off**" — both directions are policy-locked,
|
|
76
|
+
* but the user should know which.
|
|
77
|
+
*/
|
|
78
|
+
export declare function getEnvLockedValue(flagId: string): boolean | null;
|
|
79
|
+
/**
|
|
80
|
+
* Thrown by `setFlag` when a kill-switch flag is env-locked (its value was
|
|
81
|
+
* frozen at startup via `PATCHWORK_FLAG_<ID>`) and the caller attempts to
|
|
82
|
+
* mutate it. The `/kill-switch` POST handler catches this and returns a
|
|
83
|
+
* structured 409 Conflict so the CLI / dashboard can distinguish
|
|
84
|
+
* "policy-locked" from "bad request" (issue #422, pitfall I9).
|
|
85
|
+
*
|
|
86
|
+
* `frozenValue` is the locked direction — callers can surface
|
|
87
|
+
* "env-locked to on" vs "env-locked to off" in error messages.
|
|
88
|
+
*/
|
|
89
|
+
export declare class EnvLockedFlagError extends Error {
|
|
90
|
+
readonly flagId: string;
|
|
91
|
+
readonly frozenValue: boolean;
|
|
92
|
+
constructor(flagId: string, frozenValue: boolean);
|
|
93
|
+
}
|
|
54
94
|
/**
|
|
55
95
|
* Set a flag value (persists to config file if persist=true).
|
|
96
|
+
*
|
|
97
|
+
* Throws `EnvLockedFlagError` if the flag is a kill-switch flag that has been
|
|
98
|
+
* frozen by `lockKillSwitchEnv()` — a sysadmin env-var override takes
|
|
99
|
+
* precedence over runtime mutation. The `/kill-switch` POST handler catches
|
|
100
|
+
* this and returns 409 (pitfall I9 from issue #422).
|
|
56
101
|
*/
|
|
57
102
|
export declare function setFlag(flagId: string, value: boolean, persist?: boolean): void;
|
|
58
103
|
/**
|
|
@@ -69,11 +114,42 @@ export declare function loadFlags(): void;
|
|
|
69
114
|
export declare const KILL_SWITCH_WRITES = "kill-switch.writes";
|
|
70
115
|
/** Enable recipe lint with schema validation (A1) */
|
|
71
116
|
export declare const FLAG_SCHEMA_LINT = "ui.schema-lint";
|
|
117
|
+
/**
|
|
118
|
+
* Watch the flags.json file for cross-process changes. When another
|
|
119
|
+
* process (typically the `patchwork kill-switch` CLI in its fallback
|
|
120
|
+
* fs-write path, or a sibling bridge in a multi-bridge deployment)
|
|
121
|
+
* writes to flags.json, this watcher reloads the in-memory FLAG_VALUES
|
|
122
|
+
* so the running bridge picks up the new state without a restart.
|
|
123
|
+
*
|
|
124
|
+
* v2-S1 + v2-B2 from #422. Closes the "no bridge reachable → CLI
|
|
125
|
+
* silent fallback → recipes keep writing" gap that motivated the
|
|
126
|
+
* redesign — even when the CLI's HTTP path fails and it falls back
|
|
127
|
+
* to writing the file directly, the running bridge still sees the
|
|
128
|
+
* change.
|
|
129
|
+
*
|
|
130
|
+
* **Env-lock interaction:** if `lockKillSwitchEnv()` already froze a
|
|
131
|
+
* kill-switch value from `PATCHWORK_FLAG_*`, the file-watch flow
|
|
132
|
+
* still updates FLAG_VALUES, but `isEnabled` continues reading from
|
|
133
|
+
* the frozen snapshot for that flag (existing behavior at L117-121).
|
|
134
|
+
* The env-lock is the source of truth — file changes can't override
|
|
135
|
+
* a sysadmin-mandated kill-switch state. This is the correct policy.
|
|
136
|
+
*
|
|
137
|
+
* Modeled on `src/pluginWatcher.ts`: directory-watch + filename
|
|
138
|
+
* filter + 100ms debounce so coalesced events (rename+create+change
|
|
139
|
+
* on most filesystems) don't trigger N reloads. Returns a close
|
|
140
|
+
* handle. Tolerates the file or directory not yet existing.
|
|
141
|
+
*/
|
|
142
|
+
export declare function watchFlags(): () => void;
|
|
72
143
|
/**
|
|
73
144
|
* Check if write operations are globally disabled.
|
|
74
145
|
*/
|
|
75
146
|
export declare function isWriteKillSwitchActive(): boolean;
|
|
76
147
|
/**
|
|
77
148
|
* Assert write is allowed — throws if kill switch is active.
|
|
149
|
+
*
|
|
150
|
+
* The thrown error carries `code: "kill_switch_blocked"` so the recipe
|
|
151
|
+
* runner can categorise the resulting halt as `kill_switch` (rather than
|
|
152
|
+
* a generic `tool_threw`) and the dashboard pill row can flag it
|
|
153
|
+
* distinctly from real tool failures.
|
|
78
154
|
*/
|
|
79
155
|
export declare function assertWriteAllowed(operation: string): void;
|
package/dist/featureFlags.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - Kill switch for write-tier operations
|
|
8
8
|
* - Per-feature opt-in with default-off safety
|
|
9
9
|
*/
|
|
10
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
10
|
+
import { existsSync, mkdirSync, readFileSync, watch, writeFileSync, } from "node:fs";
|
|
11
11
|
import os from "node:os";
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
/** Flag registry — all known flags */
|
|
@@ -101,13 +101,85 @@ export function isEnabled(flagId) {
|
|
|
101
101
|
// Unknown flag — default to false (safe)
|
|
102
102
|
return false;
|
|
103
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Returns true when the given kill-switch flag is **env-locked** — i.e. its
|
|
106
|
+
* value was frozen at startup from a `PATCHWORK_FLAG_<ID>` environment
|
|
107
|
+
* variable and any subsequent `setFlag()` call will be silently overridden
|
|
108
|
+
* by `isEnabled()`.
|
|
109
|
+
*
|
|
110
|
+
* Used by the `/kill-switch` endpoint (issue #422) to surface a 409
|
|
111
|
+
* Conflict instead of returning 200 OK for a setFlag that won't stick,
|
|
112
|
+
* and by the dashboard to render the toggle as disabled (with a tooltip
|
|
113
|
+
* naming which direction was sysadmin-locked) when this returns true.
|
|
114
|
+
*
|
|
115
|
+
* Returns false for non-kill-switch flags (they read env dynamically and
|
|
116
|
+
* are never "locked"), for unknown flags, and when `lockKillSwitchEnv()`
|
|
117
|
+
* has not yet been called.
|
|
118
|
+
*/
|
|
119
|
+
export function isEnvLockedFor(flagId) {
|
|
120
|
+
if (!envLocked)
|
|
121
|
+
return false;
|
|
122
|
+
const flag = FLAG_REGISTRY.get(flagId);
|
|
123
|
+
if (!flag?.isKillSwitch)
|
|
124
|
+
return false;
|
|
125
|
+
return FROZEN_KILL_SWITCH_ENV.get(flagId) !== undefined;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Returns the frozen env-locked value for a kill-switch flag (`true` /
|
|
129
|
+
* `false`), or `null` if not env-locked.
|
|
130
|
+
*
|
|
131
|
+
* Used by the dashboard tooltip so the disabled-state can read "env-locked
|
|
132
|
+
* to **on**" vs "env-locked to **off**" — both directions are policy-locked,
|
|
133
|
+
* but the user should know which.
|
|
134
|
+
*/
|
|
135
|
+
export function getEnvLockedValue(flagId) {
|
|
136
|
+
if (!isEnvLockedFor(flagId))
|
|
137
|
+
return null;
|
|
138
|
+
const frozen = FROZEN_KILL_SWITCH_ENV.get(flagId);
|
|
139
|
+
return frozen === undefined ? null : frozen;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Thrown by `setFlag` when a kill-switch flag is env-locked (its value was
|
|
143
|
+
* frozen at startup via `PATCHWORK_FLAG_<ID>`) and the caller attempts to
|
|
144
|
+
* mutate it. The `/kill-switch` POST handler catches this and returns a
|
|
145
|
+
* structured 409 Conflict so the CLI / dashboard can distinguish
|
|
146
|
+
* "policy-locked" from "bad request" (issue #422, pitfall I9).
|
|
147
|
+
*
|
|
148
|
+
* `frozenValue` is the locked direction — callers can surface
|
|
149
|
+
* "env-locked to on" vs "env-locked to off" in error messages.
|
|
150
|
+
*/
|
|
151
|
+
export class EnvLockedFlagError extends Error {
|
|
152
|
+
flagId;
|
|
153
|
+
frozenValue;
|
|
154
|
+
constructor(flagId, frozenValue) {
|
|
155
|
+
super(`Feature flag "${flagId}" is env-locked to ${frozenValue ? "true" : "false"} ` +
|
|
156
|
+
`(set at startup via PATCHWORK_FLAG_${flagId.replace(/[.-]/g, "_").toUpperCase()}). ` +
|
|
157
|
+
`Unset the environment variable to allow runtime mutation.`);
|
|
158
|
+
this.name = "EnvLockedFlagError";
|
|
159
|
+
this.flagId = flagId;
|
|
160
|
+
this.frozenValue = frozenValue;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
104
163
|
/**
|
|
105
164
|
* Set a flag value (persists to config file if persist=true).
|
|
165
|
+
*
|
|
166
|
+
* Throws `EnvLockedFlagError` if the flag is a kill-switch flag that has been
|
|
167
|
+
* frozen by `lockKillSwitchEnv()` — a sysadmin env-var override takes
|
|
168
|
+
* precedence over runtime mutation. The `/kill-switch` POST handler catches
|
|
169
|
+
* this and returns 409 (pitfall I9 from issue #422).
|
|
106
170
|
*/
|
|
107
171
|
export function setFlag(flagId, value, persist = false) {
|
|
108
172
|
if (!FLAG_REGISTRY.has(flagId)) {
|
|
109
173
|
throw new Error(`Unknown feature flag: "${flagId}"`);
|
|
110
174
|
}
|
|
175
|
+
// v2-I9: kill-switch flags that were env-locked at startup must not be
|
|
176
|
+
// silently overridden — throw so callers (the /kill-switch handler) can
|
|
177
|
+
// surface a structured 409 instead of returning 200 for a mutation that
|
|
178
|
+
// won't take effect.
|
|
179
|
+
if (isEnvLockedFor(flagId)) {
|
|
180
|
+
const frozen = FROZEN_KILL_SWITCH_ENV.get(flagId);
|
|
181
|
+
throw new EnvLockedFlagError(flagId, frozen === true);
|
|
182
|
+
}
|
|
111
183
|
FLAG_VALUES.set(flagId, value);
|
|
112
184
|
if (persist) {
|
|
113
185
|
persistFlags();
|
|
@@ -187,6 +259,91 @@ registerFlag({
|
|
|
187
259
|
});
|
|
188
260
|
// Load persisted flags on module init
|
|
189
261
|
loadFlags();
|
|
262
|
+
/**
|
|
263
|
+
* Watch the flags.json file for cross-process changes. When another
|
|
264
|
+
* process (typically the `patchwork kill-switch` CLI in its fallback
|
|
265
|
+
* fs-write path, or a sibling bridge in a multi-bridge deployment)
|
|
266
|
+
* writes to flags.json, this watcher reloads the in-memory FLAG_VALUES
|
|
267
|
+
* so the running bridge picks up the new state without a restart.
|
|
268
|
+
*
|
|
269
|
+
* v2-S1 + v2-B2 from #422. Closes the "no bridge reachable → CLI
|
|
270
|
+
* silent fallback → recipes keep writing" gap that motivated the
|
|
271
|
+
* redesign — even when the CLI's HTTP path fails and it falls back
|
|
272
|
+
* to writing the file directly, the running bridge still sees the
|
|
273
|
+
* change.
|
|
274
|
+
*
|
|
275
|
+
* **Env-lock interaction:** if `lockKillSwitchEnv()` already froze a
|
|
276
|
+
* kill-switch value from `PATCHWORK_FLAG_*`, the file-watch flow
|
|
277
|
+
* still updates FLAG_VALUES, but `isEnabled` continues reading from
|
|
278
|
+
* the frozen snapshot for that flag (existing behavior at L117-121).
|
|
279
|
+
* The env-lock is the source of truth — file changes can't override
|
|
280
|
+
* a sysadmin-mandated kill-switch state. This is the correct policy.
|
|
281
|
+
*
|
|
282
|
+
* Modeled on `src/pluginWatcher.ts`: directory-watch + filename
|
|
283
|
+
* filter + 100ms debounce so coalesced events (rename+create+change
|
|
284
|
+
* on most filesystems) don't trigger N reloads. Returns a close
|
|
285
|
+
* handle. Tolerates the file or directory not yet existing.
|
|
286
|
+
*/
|
|
287
|
+
export function watchFlags() {
|
|
288
|
+
const flagsPath = getFlagsPath();
|
|
289
|
+
const flagsDir = join(flagsPath, "..");
|
|
290
|
+
const flagsFile = "flags.json";
|
|
291
|
+
let debounceTimer = null;
|
|
292
|
+
let watcher = null;
|
|
293
|
+
let stopped = false;
|
|
294
|
+
const reload = () => {
|
|
295
|
+
if (debounceTimer)
|
|
296
|
+
clearTimeout(debounceTimer);
|
|
297
|
+
debounceTimer = setTimeout(() => {
|
|
298
|
+
debounceTimer = null;
|
|
299
|
+
if (stopped)
|
|
300
|
+
return;
|
|
301
|
+
try {
|
|
302
|
+
loadFlags();
|
|
303
|
+
}
|
|
304
|
+
catch {
|
|
305
|
+
// loadFlags has its own try/catch for parse errors;
|
|
306
|
+
// this catch is belt-and-suspenders for fs errors.
|
|
307
|
+
}
|
|
308
|
+
}, 100);
|
|
309
|
+
};
|
|
310
|
+
try {
|
|
311
|
+
// Watch the directory rather than the file directly — flags.json
|
|
312
|
+
// may not exist yet when watch is established, and editors / atomic
|
|
313
|
+
// writes (rename-into-place) lose direct file watches.
|
|
314
|
+
watcher = watch(flagsDir, { recursive: false }, (_event, filename) => {
|
|
315
|
+
if (stopped)
|
|
316
|
+
return;
|
|
317
|
+
// filename may be null on some platforms; reload on null to be safe.
|
|
318
|
+
if (!filename || filename === flagsFile) {
|
|
319
|
+
reload();
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
// Directory doesn't exist yet — the user hasn't engaged any flags.
|
|
325
|
+
// No-op; first `persistFlags()` creates the dir and from then on
|
|
326
|
+
// the watcher won't fire. This is acceptable for an emergency-stop
|
|
327
|
+
// flag because the file will exist as soon as anyone toggles via
|
|
328
|
+
// /kill-switch (which calls setFlag(..., persist=true)).
|
|
329
|
+
}
|
|
330
|
+
return () => {
|
|
331
|
+
stopped = true;
|
|
332
|
+
if (debounceTimer) {
|
|
333
|
+
clearTimeout(debounceTimer);
|
|
334
|
+
debounceTimer = null;
|
|
335
|
+
}
|
|
336
|
+
if (watcher) {
|
|
337
|
+
try {
|
|
338
|
+
watcher.close();
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
341
|
+
/* ignore */
|
|
342
|
+
}
|
|
343
|
+
watcher = null;
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
}
|
|
190
347
|
// ============================================================================
|
|
191
348
|
// Kill Switch Helpers
|
|
192
349
|
// ============================================================================
|
|
@@ -198,11 +355,18 @@ export function isWriteKillSwitchActive() {
|
|
|
198
355
|
}
|
|
199
356
|
/**
|
|
200
357
|
* Assert write is allowed — throws if kill switch is active.
|
|
358
|
+
*
|
|
359
|
+
* The thrown error carries `code: "kill_switch_blocked"` so the recipe
|
|
360
|
+
* runner can categorise the resulting halt as `kill_switch` (rather than
|
|
361
|
+
* a generic `tool_threw`) and the dashboard pill row can flag it
|
|
362
|
+
* distinctly from real tool failures.
|
|
201
363
|
*/
|
|
202
364
|
export function assertWriteAllowed(operation) {
|
|
203
365
|
if (isWriteKillSwitchActive()) {
|
|
204
|
-
|
|
366
|
+
const err = new Error(`Write operation blocked by kill switch: ${operation}. ` +
|
|
205
367
|
`Unset PATCHWORK_FLAG_KILL_SWITCH_WRITES or set kill-switch.writes=false to restore.`);
|
|
368
|
+
err.code = "kill_switch_blocked";
|
|
369
|
+
throw err;
|
|
206
370
|
}
|
|
207
371
|
}
|
|
208
372
|
//# sourceMappingURL=featureFlags.js.map
|
package/dist/featureFlags.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"featureFlags.js","sourceRoot":"","sources":["../src/featureFlags.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"featureFlags.js","sourceRoot":"","sources":["../src/featureFlags.ts"],"names":[],"mappings":"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"}
|