@dv.nghiem/flowdeck 0.3.0 → 0.3.1
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/hooks/approval-hook.d.ts +6 -0
- package/dist/hooks/approval-hook.d.ts.map +1 -1
- package/dist/hooks/guard-rails.d.ts +0 -8
- package/dist/hooks/guard-rails.d.ts.map +1 -1
- package/dist/hooks/patch-trust.d.ts.map +1 -1
- package/dist/hooks/tool-guard.d.ts +1 -0
- package/dist/hooks/tool-guard.d.ts.map +1 -1
- package/dist/index.js +21 -10
- package/dist/services/policy-compiler.d.ts.map +1 -1
- package/docs/configuration.md +4 -0
- package/package.json +1 -1
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Approval Hook
|
|
3
|
+
* Intercepts write/edit operations on sensitive files and blocks them
|
|
4
|
+
* unless a recent approval exists. Throws to block (per OpenCode hook contract).
|
|
5
|
+
* To enable: set FLOWDECK_APPROVAL_HOOK_ENABLED=on. Default is OFF.
|
|
6
|
+
*/
|
|
1
7
|
export declare function approvalHook(context: {
|
|
2
8
|
directory?: string;
|
|
3
9
|
}, toolInput: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-hook.d.ts","sourceRoot":"","sources":["../../src/hooks/approval-hook.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"approval-hook.d.ts","sourceRoot":"","sources":["../../src/hooks/approval-hook.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,wBAAsB,YAAY,CAChC,OAAO,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,EAC/B,SAAS,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAC3C,MAAM,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GACzC,OAAO,CAAC,IAAI,CAAC,CAkCf"}
|
|
@@ -12,14 +12,6 @@ export type ExecutionMode = "auto" | "guarded" | "review-only";
|
|
|
12
12
|
export declare function resolveExecutionMode(configPath: string, trustScore: number | null, // 0–100, null = unknown
|
|
13
13
|
volatility?: string): ExecutionMode;
|
|
14
14
|
export type Severity = "warn" | "block" | null;
|
|
15
|
-
/**
|
|
16
|
-
* HOOK-03: Guard rails enforcement
|
|
17
|
-
* Warns on write/edit tools during setup phase (plan_confirmed=false).
|
|
18
|
-
* Blocks on write/edit tools during execution phase (plan_confirmed=true).
|
|
19
|
-
* Checks .codebase/ existence per proposal spec line 412.
|
|
20
|
-
* Detects bash build/deploy commands per proposal spec line 416.
|
|
21
|
-
* Respects guard_enforcement override in config.json.
|
|
22
|
-
*/
|
|
23
15
|
export declare function guardRailsHook(ctx: {
|
|
24
16
|
directory: string;
|
|
25
17
|
}, input: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guard-rails.d.ts","sourceRoot":"","sources":["../../src/hooks/guard-rails.ts"],"names":[],"mappings":"AASA;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,aAAa,CAAA;AAE9D;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GAAG,IAAI,EAAG,wBAAwB;AACpD,UAAU,CAAC,EAAE,MAAM,GAClB,aAAa,CAkBf;AAgBD,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"guard-rails.d.ts","sourceRoot":"","sources":["../../src/hooks/guard-rails.ts"],"names":[],"mappings":"AASA;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,aAAa,CAAA;AAE9D;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GAAG,IAAI,EAAG,wBAAwB;AACpD,UAAU,CAAC,EAAE,MAAM,GAClB,aAAa,CAkBf;AAgBD,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAA;AAa9C,wBAAsB,cAAc,CAClC,GAAG,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EAC1B,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EACvB,OAAO,EAAE,GAAG,GACX,OAAO,CAAC,IAAI,CAAC,CAgEf;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ,CAWjF;AAMD,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAS3D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patch-trust.d.ts","sourceRoot":"","sources":["../../src/hooks/patch-trust.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAYH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,iBAAiB,GAAG,WAAW,CAAA;AAEnE,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,YAAY,CAAA;IACrB,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AA0BD,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,UAAU,CA4B5F;AAED,wBAAsB,cAAc,CAClC,GAAG,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EAC1B,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EACvB,MAAM,EAAE;IAAE,IAAI,EAAE,GAAG,CAAA;CAAE,GACpB,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"patch-trust.d.ts","sourceRoot":"","sources":["../../src/hooks/patch-trust.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAYH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,iBAAiB,GAAG,WAAW,CAAA;AAEnE,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,YAAY,CAAA;IACrB,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AA0BD,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,UAAU,CA4B5F;AAED,wBAAsB,cAAc,CAClC,GAAG,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EAC1B,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EACvB,MAAM,EAAE;IAAE,IAAI,EAAE,GAAG,CAAA;CAAE,GACpB,OAAO,CAAC,IAAI,CAAC,CAoBf"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Pattern matching on tool arguments to prevent destructive commands.
|
|
4
4
|
* D-04: pure string.includes() matching, no path filtering, no regex/glob.
|
|
5
5
|
* Also enforces architectural constraints from .codebase/CONSTRAINTS.md.
|
|
6
|
+
* To enable: set FLOWDECK_TOOL_GUARD_ENABLED=on. Default is OFF.
|
|
6
7
|
*/
|
|
7
8
|
export type BlockReason = string | null;
|
|
8
9
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-guard.d.ts","sourceRoot":"","sources":["../../src/hooks/tool-guard.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tool-guard.d.ts","sourceRoot":"","sources":["../../src/hooks/tool-guard.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAeH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,IAAI,CAAA;AAEvC;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,WAAW,CAsC9D;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,WAAW,CAepF;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,CAYpE;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EAC1B,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EACvB,MAAM,EAAE;IAAE,IAAI,EAAE,GAAG,CAAA;CAAE,GACpB,OAAO,CAAC,IAAI,CAAC,CA4Bf"}
|
package/dist/index.js
CHANGED
|
@@ -1887,7 +1887,10 @@ var BUILD_DEPLOY_PATTERNS = [
|
|
|
1887
1887
|
"rails deploy",
|
|
1888
1888
|
"rake deploy"
|
|
1889
1889
|
];
|
|
1890
|
+
var ENABLED = process.env.FLOWDECK_GUARD_RAILS_ENABLED === "on";
|
|
1890
1891
|
async function guardRailsHook(ctx, input, _output) {
|
|
1892
|
+
if (!ENABLED)
|
|
1893
|
+
return;
|
|
1891
1894
|
const dir = ctx.directory;
|
|
1892
1895
|
const planningDirPath = join14(dir, PLANNING_DIR2);
|
|
1893
1896
|
const codebaseDirectory = codebaseDir(dir);
|
|
@@ -1918,11 +1921,10 @@ async function guardRailsHook(ctx, input, _output) {
|
|
|
1918
1921
|
if (effectiveSeverity === null)
|
|
1919
1922
|
return;
|
|
1920
1923
|
if (effectiveSeverity === "warn") {
|
|
1921
|
-
const warning = getWarningMessage(
|
|
1924
|
+
const warning = getWarningMessage(planningDirPath);
|
|
1922
1925
|
throw new Error(`[flowdeck] WARNING: ${warning}`);
|
|
1923
|
-
return;
|
|
1924
1926
|
}
|
|
1925
|
-
const blockMessage = getBlockMessage(
|
|
1927
|
+
const blockMessage = getBlockMessage(planningDirPath);
|
|
1926
1928
|
throw new Error(`[flowdeck] BLOCK: ${blockMessage}`);
|
|
1927
1929
|
}
|
|
1928
1930
|
if (input.tool === "bash") {
|
|
@@ -1930,7 +1932,6 @@ async function guardRailsHook(ctx, input, _output) {
|
|
|
1930
1932
|
for (const pattern of BUILD_DEPLOY_PATTERNS) {
|
|
1931
1933
|
if (cmd.includes(pattern)) {
|
|
1932
1934
|
if (!getPlanConfirmed(statePath2)) {
|
|
1933
|
-
const msg = "Build/deploy command detected but plan is not confirmed. Run /plan first.";
|
|
1934
1935
|
throw new Error(`[flowdeck] WARNING: Build/deploy command detected but plan is not confirmed. Run /plan first.`);
|
|
1935
1936
|
}
|
|
1936
1937
|
break;
|
|
@@ -1967,14 +1968,14 @@ function getPlanConfirmed(statePath2) {
|
|
|
1967
1968
|
return false;
|
|
1968
1969
|
}
|
|
1969
1970
|
}
|
|
1970
|
-
function getWarningMessage(
|
|
1971
|
-
if (!existsSync14(join14(
|
|
1971
|
+
function getWarningMessage(planningDir2) {
|
|
1972
|
+
if (!existsSync14(join14(planningDir2, STATE_FILE2))) {
|
|
1972
1973
|
return "No .planning/ found. Run /new-project first.";
|
|
1973
1974
|
}
|
|
1974
1975
|
return "Plan not confirmed. Run /plan and confirm to enable execution.";
|
|
1975
1976
|
}
|
|
1976
|
-
function getBlockMessage(
|
|
1977
|
-
if (!existsSync14(join14(
|
|
1977
|
+
function getBlockMessage(planningDir2) {
|
|
1978
|
+
if (!existsSync14(join14(planningDir2, STATE_FILE2))) {
|
|
1978
1979
|
return "No .planning/ found. Run /new-project first.";
|
|
1979
1980
|
}
|
|
1980
1981
|
return "Plan not confirmed. Run /plan and confirm to enable execution.";
|
|
@@ -1983,6 +1984,7 @@ function getBlockMessage(statePath2, planningDir3) {
|
|
|
1983
1984
|
// src/hooks/tool-guard.ts
|
|
1984
1985
|
import { existsSync as existsSync15, readFileSync as readFileSync14 } from "fs";
|
|
1985
1986
|
import { join as join15 } from "path";
|
|
1987
|
+
var IS_ENABLED = () => process.env.FLOWDECK_TOOL_GUARD_ENABLED === "on";
|
|
1986
1988
|
var BLOCKED_PATTERNS = {
|
|
1987
1989
|
read: [".env", ".pem", ".key", ".secret"],
|
|
1988
1990
|
write: ["node_modules"],
|
|
@@ -2056,6 +2058,8 @@ function checkPhaseEnforcement(directory) {
|
|
|
2056
2058
|
return null;
|
|
2057
2059
|
}
|
|
2058
2060
|
async function toolGuardHook(ctx, input, output) {
|
|
2061
|
+
if (!IS_ENABLED())
|
|
2062
|
+
return;
|
|
2059
2063
|
if (input.tool !== "bash" && input.tool !== "read" && input.tool !== "write" && input.tool !== "edit") {
|
|
2060
2064
|
return;
|
|
2061
2065
|
}
|
|
@@ -2079,11 +2083,11 @@ async function toolGuardHook(ctx, input, output) {
|
|
|
2079
2083
|
// src/hooks/session-start.ts
|
|
2080
2084
|
import { existsSync as existsSync16, readFileSync as readFileSync15 } from "fs";
|
|
2081
2085
|
async function sessionStartHook(ctx) {
|
|
2082
|
-
const
|
|
2086
|
+
const planningDir2 = ctx.directory + "/.planning";
|
|
2083
2087
|
const codebaseDirectory = codebaseDir(ctx.directory);
|
|
2084
2088
|
const workspaceRoot = findWorkspaceRoot(ctx.directory);
|
|
2085
2089
|
const config = workspaceRoot ? getWorkspaceConfig(ctx.directory) : null;
|
|
2086
|
-
if (!existsSync16(
|
|
2090
|
+
if (!existsSync16(planningDir2)) {
|
|
2087
2091
|
return {
|
|
2088
2092
|
flowdeck_phase: null,
|
|
2089
2093
|
flowdeck_status: "no_plan",
|
|
@@ -2276,6 +2280,10 @@ async function patchTrustHook(ctx, input, output) {
|
|
|
2276
2280
|
return;
|
|
2277
2281
|
const trust = scorePatch(ctx.directory, filePath, content);
|
|
2278
2282
|
if (trust.verdict === "high-risk") {
|
|
2283
|
+
const highRiskEnabled = process.env.FLOWDECK_PATCH_TRUST_HIGH_RISK_ENABLED;
|
|
2284
|
+
if (highRiskEnabled !== "true" && highRiskEnabled !== "1") {
|
|
2285
|
+
return;
|
|
2286
|
+
}
|
|
2279
2287
|
throw new Error(`[flowdeck] PATCH-TRUST HIGH-RISK (score=${trust.score}): ${filePath}
|
|
2280
2288
|
Signals: ${trust.signals.join("; ")}
|
|
2281
2289
|
This edit requires explicit human review before applying.`);
|
|
@@ -2420,8 +2428,11 @@ function checkApproval(dir, file_path, command) {
|
|
|
2420
2428
|
}
|
|
2421
2429
|
|
|
2422
2430
|
// src/hooks/approval-hook.ts
|
|
2431
|
+
var ENABLED2 = process.env.FLOWDECK_APPROVAL_HOOK_ENABLED === "on";
|
|
2423
2432
|
var WRITE_TOOLS = new Set(["write_file", "edit_file", "create_file", "apply_patch", "str_replace_editor", "write"]);
|
|
2424
2433
|
async function approvalHook(context, toolInput, output) {
|
|
2434
|
+
if (!ENABLED2)
|
|
2435
|
+
return;
|
|
2425
2436
|
const dir = context.directory ?? process.cwd();
|
|
2426
2437
|
const tool17 = toolInput.name ?? toolInput.tool ?? "";
|
|
2427
2438
|
if (!WRITE_TOOLS.has(tool17))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy-compiler.d.ts","sourceRoot":"","sources":["../../src/services/policy-compiler.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAA;CAC3B;AAiCD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,eAAe,EAAE,CA8BnF;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,SAAS,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;CAClB;
|
|
1
|
+
{"version":3,"file":"policy-compiler.d.ts","sourceRoot":"","sources":["../../src/services/policy-compiler.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAA;CAC3B;AAiCD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,eAAe,EAAE,CA8BnF;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,SAAS,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;CAClB;AA+FD,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,EAAE,EACxB,UAAU,CAAC,EAAE,MAAM,GAClB,cAAc,GAAG,IAAI,CAmBvB;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,eAAe,EAAE,GAAG,MAAM,CAUtE"}
|
package/docs/configuration.md
CHANGED
|
@@ -269,6 +269,10 @@ These are enabled by default. If you have API keys (e.g., `CONTEXT7_API_KEY`, `E
|
|
|
269
269
|
| `FLOWDECK_CONTEXT_LIMIT` | `200000` | Token limit used by the Context Window Monitor to warn when context usage exceeds 70% |
|
|
270
270
|
| `FLOWDECK_DISABLE_MCP` | (empty) | Comma-separated list of remote MCPs to disable. Valid options: `context7`, `websearch`, `grep_app` |
|
|
271
271
|
| `FLOWDECK_ORCHESTRATOR_GUARD` | `off` | Enable the orchestrator guard hook. When `on`, the orchestrator session cannot use write/bash tools directly and must delegate all implementation work. |
|
|
272
|
+
| `FLOWDECK_PATCH_TRUST_HIGH_RISK_ENABLED` | `off` | Enable blocking of high-risk AI-generated edits (score < 40). When `true` or `1`, the patch trust hook blocks edits flagged as high-risk. When `false`, `0`, or unset (default), high-risk edits are allowed without blocking. |
|
|
273
|
+
| `FLOWDECK_GUARD_RAILS_ENABLED` | `off` | Enable the guard rails hook. When `on`, write/edit tools are warned/blocked based on plan confirmation state, .codebase/ existence, and execution mode. |
|
|
274
|
+
| `FLOWDECK_TOOL_GUARD_ENABLED` | `off` | Enable the tool guard hook. When `on`, blocks dangerous bash commands (rm -rf), access to secret files (.env, .pem, .key), writes to node_modules, arch-constraint violations, and premature phase writes. |
|
|
275
|
+
| `FLOWDECK_APPROVAL_HOOK_ENABLED` | `off` | Enable the approval hook. When `on`, blocks write/edit on sensitive files (auth/payment/secrets/infra) unless a recent approval exists. |
|
|
272
276
|
| `TELEMETRY_ENABLED` | `false` | Enable telemetry events from hooks. When `true`, events are written to `.codebase/TELEMETRY.jsonl`. |
|
|
273
277
|
|
|
274
278
|
---
|