@fusengine/harness 0.1.1 → 0.1.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/dist/adapters/claude/index.d.mts +1 -35
- package/dist/adapters/claude/index.mjs +1 -65
- package/dist/adapters/cline/index.mjs +1 -24
- package/dist/adapters/codex/index.d.mts +2 -0
- package/dist/adapters/codex/index.mjs +2 -0
- package/dist/adapters/cursor/index.mjs +1 -36
- package/dist/adapters/gemini/index.mjs +1 -24
- package/dist/cache/index.d.mts +1 -29
- package/dist/cache/index.mjs +1 -109
- package/dist/cache-DbPSJ9bC.mjs +110 -0
- package/dist/claude-DbzjbxmO.mjs +66 -0
- package/dist/cli/bin.mjs +84 -10
- package/dist/cline-BxslHtBG.mjs +25 -0
- package/dist/config/index.d.mts +1 -36
- package/dist/config/index.mjs +1 -18
- package/dist/config-BG55s6HZ.mjs +20 -0
- package/dist/cursor-Bh7eh9y_.mjs +37 -0
- package/dist/detect/index.d.mts +1 -30
- package/dist/detect/index.mjs +2 -81
- package/dist/detect-la_KkjCS.mjs +1 -0
- package/dist/doc-helpers-Dd_x1-tZ.mjs +42 -0
- package/dist/freshness/index.d.mts +1 -12
- package/dist/freshness/index.mjs +2 -63
- package/dist/freshness-BK9Xg6oG.mjs +23 -0
- package/dist/gemini-SrK_fFAr.mjs +25 -0
- package/dist/harness-C8Nxxyn_.mjs +83 -0
- package/dist/harness-DwJskkz_.d.mts +31 -0
- package/dist/index-B-z0CCiU.d.mts +37 -0
- package/dist/index-B3Ve_bBu.d.mts +30 -0
- package/dist/index-BEM-mQMC.d.mts +30 -0
- package/dist/index-BKZ67WMa.d.mts +1 -0
- package/dist/index-BOBXQ91y.d.mts +12 -0
- package/dist/index-BVVgDSdq.d.mts +1 -0
- package/dist/index-BWK8slRi.d.mts +84 -0
- package/dist/index-BXBWKbL8.d.mts +114 -0
- package/dist/index-C1vLIMwN.d.mts +20 -0
- package/dist/index-C2Lz-cwJ.d.mts +21 -0
- package/dist/index-CPoF_hLP.d.mts +59 -0
- package/dist/index-FrWgmkbP.d.mts +36 -0
- package/dist/index.d.mts +12 -11
- package/dist/index.mjs +11 -12
- package/dist/init/index.d.mts +34 -0
- package/dist/init/index.mjs +2 -0
- package/dist/memory/index.d.mts +1 -29
- package/dist/memory/index.mjs +1 -93
- package/dist/memory-BVNt4Ary.mjs +94 -0
- package/dist/policy/index.d.mts +2 -80
- package/dist/policy/index.mjs +2 -33
- package/dist/policy-DMpyaPZ_.mjs +68 -0
- package/dist/prompt/index.mjs +1 -0
- package/dist/prompt-la_KkjCS.mjs +1 -0
- package/dist/refs/index.d.mts +2 -43
- package/dist/refs/index.mjs +2 -69
- package/dist/refs-la_KkjCS.mjs +1 -0
- package/dist/router-Dj3AfgBE.mjs +70 -0
- package/dist/run-Cc98348q.mjs +94 -0
- package/dist/state/index.d.mts +1 -58
- package/dist/state/index.mjs +1 -103
- package/dist/state-Bc4wdnCG.mjs +104 -0
- package/dist/statusline/index.d.mts +1 -83
- package/dist/statusline/index.mjs +1 -147
- package/dist/statusline-D87eUNXl.mjs +148 -0
- package/dist/types-CY5qT2X1.d.mts +26 -0
- package/dist/util/index.d.mts +1 -19
- package/dist/util/index.mjs +1 -0
- package/dist/util-la_KkjCS.mjs +1 -0
- package/package.json +5 -3
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
//#region src/statusline/constants.d.ts
|
|
2
|
+
/** Time interval constants (ms). */
|
|
3
|
+
declare const TIME_INTERVALS: {
|
|
4
|
+
readonly MINUTE_MS: 60_000;
|
|
5
|
+
readonly HOUR_MS: 3_600_000;
|
|
6
|
+
};
|
|
7
|
+
/** Percentage thresholds for progressive coloring. */
|
|
8
|
+
declare const COLOR_THRESHOLDS: {
|
|
9
|
+
readonly WARNING: 70;
|
|
10
|
+
readonly CRITICAL: 90;
|
|
11
|
+
};
|
|
12
|
+
/** Fill/empty glyphs per progress-bar style. */
|
|
13
|
+
declare const PROGRESS_CHARS: {
|
|
14
|
+
readonly blocks: {
|
|
15
|
+
readonly fill: "█";
|
|
16
|
+
readonly empty: "░";
|
|
17
|
+
};
|
|
18
|
+
readonly bars: {
|
|
19
|
+
readonly fill: "▰";
|
|
20
|
+
readonly empty: "▱";
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
/** Defaults for {@link generateProgressBar}. */
|
|
24
|
+
declare const PROGRESS_BAR_DEFAULTS: {
|
|
25
|
+
readonly STYLE: "blocks";
|
|
26
|
+
readonly LENGTH: 10;
|
|
27
|
+
};
|
|
28
|
+
/** 9 gradient blocks from empty to full. */
|
|
29
|
+
declare const GRADIENT_BLOCKS: readonly [" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█"];
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/statusline/colors.d.ts
|
|
32
|
+
/** A text-decorating function. */
|
|
33
|
+
type ColorFn = (text: string) => string;
|
|
34
|
+
/** Forced ANSI palette (every entry is a colorizer, plus reset + support flag). */
|
|
35
|
+
interface Palette {
|
|
36
|
+
blue: ColorFn;
|
|
37
|
+
cyan: ColorFn;
|
|
38
|
+
green: ColorFn;
|
|
39
|
+
yellow: ColorFn;
|
|
40
|
+
red: ColorFn;
|
|
41
|
+
magenta: ColorFn;
|
|
42
|
+
white: ColorFn;
|
|
43
|
+
gray: ColorFn;
|
|
44
|
+
purple: ColorFn;
|
|
45
|
+
orange: ColorFn;
|
|
46
|
+
brightRed: ColorFn;
|
|
47
|
+
brightYellow: ColorFn;
|
|
48
|
+
brightGreen: ColorFn;
|
|
49
|
+
bold: ColorFn;
|
|
50
|
+
dim: ColorFn;
|
|
51
|
+
reset: string;
|
|
52
|
+
isSupported: boolean;
|
|
53
|
+
}
|
|
54
|
+
/** Forced ANSI color helpers (ignore TTY detection). */
|
|
55
|
+
declare const colors: Palette;
|
|
56
|
+
/** Color `text` by threshold: green < WARNING <= yellow < CRITICAL <= red. */
|
|
57
|
+
declare function progressiveColor(value: number, text: string): string;
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/statusline/formatters.d.ts
|
|
60
|
+
/** Format a path: truncated (default), full, relative (~), or basename. */
|
|
61
|
+
declare function formatPath(path: string, style?: "truncated" | "full" | "relative" | "basename"): string;
|
|
62
|
+
/** Basename of a path. */
|
|
63
|
+
declare function formatBasename(path: string): string;
|
|
64
|
+
/** Humanize a remaining duration in ms (e.g. "2h - 5m"). */
|
|
65
|
+
declare function formatTimeLeft(ms: number): string;
|
|
66
|
+
/** Format a token count as "12K" (or "12.3K" with decimals). */
|
|
67
|
+
declare function formatTokens(tokens: number, showDecimals?: boolean): string;
|
|
68
|
+
/** Format a cost as "$1.23". */
|
|
69
|
+
declare function formatCost(cost: number, decimals?: number): string;
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/statusline/progress-bar.d.ts
|
|
72
|
+
/** Options for {@link generateProgressBar}. */
|
|
73
|
+
interface ProgressBarOptions {
|
|
74
|
+
style?: keyof typeof PROGRESS_CHARS;
|
|
75
|
+
length?: number;
|
|
76
|
+
useProgressiveColor?: boolean;
|
|
77
|
+
showPercentage?: boolean;
|
|
78
|
+
}
|
|
79
|
+
/** Render a fill/empty progress bar. */
|
|
80
|
+
declare function generateProgressBar(percentage: number, options?: ProgressBarOptions): string;
|
|
81
|
+
/** Render a fine-grained gradient bar (sub-block resolution). */
|
|
82
|
+
declare function generateGradientBar(percentage: number, length?: number): string;
|
|
83
|
+
//#endregion
|
|
84
|
+
export { TIME_INTERVALS as _, formatCost as a, formatTokens as c, colors as d, progressiveColor as f, PROGRESS_CHARS as g, PROGRESS_BAR_DEFAULTS as h, formatBasename as i, ColorFn as l, GRADIENT_BLOCKS as m, generateGradientBar as n, formatPath as o, COLOR_THRESHOLDS as p, generateProgressBar as r, formatTimeLeft as s, ProgressBarOptions as t, Palette as u };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { t as Prompt } from "./types-D56jSgD9.mjs";
|
|
2
|
+
import { t as AuthEntry } from "./doc-helpers-CG1nuf-c.mjs";
|
|
3
|
+
import { t as RefMeta } from "./types-CY5qT2X1.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/policy/detect-project.d.ts
|
|
6
|
+
/** Project types detected from filesystem indicators. */
|
|
7
|
+
type ProjectType = "nextjs" | "nuxt" | "angular" | "svelte" | "vue" | "react" | "tailwind" | "laravel" | "rails" | "django" | "python" | "go" | "rust" | "swift" | "java" | "scala" | "elixir" | "ruby" | "generic";
|
|
8
|
+
/** Keywords that signal a development task (APEX trigger). */
|
|
9
|
+
declare const DEV_KEYWORDS: RegExp;
|
|
10
|
+
/** True when the prompt invokes the /apex command. */
|
|
11
|
+
declare function isApexCommand(prompt: string): boolean;
|
|
12
|
+
/** Detect the project type by scanning config files in `dir`. */
|
|
13
|
+
declare function detectProjectType(dir: string): ProjectType;
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/policy/detect-framework.d.ts
|
|
16
|
+
/**
|
|
17
|
+
* Detect the framework from a file path extension + content patterns.
|
|
18
|
+
* Aligned with the fusengine require-solid-read detection (distinct from
|
|
19
|
+
* {@link detectProjectType}, which scans config files on disk).
|
|
20
|
+
*/
|
|
21
|
+
declare function detectFramework(filePath: string, content: string): string;
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/policy/file-size.d.ts
|
|
24
|
+
/** Verdict from {@link evaluateFileSize}. */
|
|
25
|
+
interface FileSizeVerdict {
|
|
26
|
+
ok: boolean;
|
|
27
|
+
lines: number;
|
|
28
|
+
max: number;
|
|
29
|
+
message: string | null;
|
|
30
|
+
}
|
|
31
|
+
/** Count lines in file content (empty string = 0). */
|
|
32
|
+
declare function countLines(content: string): number;
|
|
33
|
+
/**
|
|
34
|
+
* Evaluate a file's line count against the SOLID limit.
|
|
35
|
+
* @param lines - the file's line count
|
|
36
|
+
* @param max - the limit (defaults to `resolveMaxLines()`)
|
|
37
|
+
*/
|
|
38
|
+
declare function evaluateFileSize(lines: number, max?: number): FileSizeVerdict;
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/policy/patterns.d.ts
|
|
41
|
+
/**
|
|
42
|
+
* Guard pattern data, ported verbatim from the fusengine git/install guards.
|
|
43
|
+
* Note (faithful): `git push.*--force` also matches `--force-with-lease` —
|
|
44
|
+
* preserved from the source guard.
|
|
45
|
+
*/
|
|
46
|
+
/** Destructive git operations to block outright. */
|
|
47
|
+
declare const GIT_BLOCKED: ReadonlyArray<RegExp>;
|
|
48
|
+
/** Git operations that warrant a confirmation prompt. */
|
|
49
|
+
declare const GIT_ASK: ReadonlyArray<RegExp>;
|
|
50
|
+
/** System-level package installs (need confirmation). */
|
|
51
|
+
declare const SYSTEM_INSTALL: ReadonlyArray<RegExp>;
|
|
52
|
+
/** Project-level package installs. */
|
|
53
|
+
declare const PROJECT_INSTALL: ReadonlyArray<RegExp>;
|
|
54
|
+
/** True when `cmd` matches any pattern in `patterns`. */
|
|
55
|
+
declare function matchPatterns(cmd: string, patterns: ReadonlyArray<RegExp>): boolean;
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/policy/evaluate.d.ts
|
|
58
|
+
/** Harness-agnostic input to {@link evaluate}. */
|
|
59
|
+
interface PolicyContext {
|
|
60
|
+
/** Tool name (e.g. "Write", "Edit", "Bash"). */
|
|
61
|
+
tool: string;
|
|
62
|
+
filePath?: string;
|
|
63
|
+
content?: string;
|
|
64
|
+
command?: string;
|
|
65
|
+
/** Optional override for the SOLID max-lines limit. */
|
|
66
|
+
maxLines?: number;
|
|
67
|
+
}
|
|
68
|
+
/** Harness-agnostic policy decision (+ a portable prompt for adapters to render). */
|
|
69
|
+
interface PolicyResult {
|
|
70
|
+
decision: "allow" | "deny" | "warn";
|
|
71
|
+
message: string | null;
|
|
72
|
+
prompt?: Prompt;
|
|
73
|
+
meta?: Record<string, unknown>;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Evaluate a single tool-use against the bundled policies, returning a pure
|
|
77
|
+
* decision plus a portable {@link Prompt}. Adapters translate the prompt into
|
|
78
|
+
* their harness's native response (Claude `permissionDecision`, etc.).
|
|
79
|
+
*/
|
|
80
|
+
declare function evaluate(ctx: PolicyContext): PolicyResult;
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/policy/apex.d.ts
|
|
83
|
+
/**
|
|
84
|
+
* Session context for the stateful APEX gates. The harness adapter supplies this
|
|
85
|
+
* (the package owns the gate LOGIC; recording the session activity is the
|
|
86
|
+
* adapter's tracking layer).
|
|
87
|
+
*/
|
|
88
|
+
interface ApexContext {
|
|
89
|
+
sessionId: string;
|
|
90
|
+
framework: string;
|
|
91
|
+
filePath: string;
|
|
92
|
+
content: string;
|
|
93
|
+
/** Doc-consultation authorizations from session state (Context7/Exa). */
|
|
94
|
+
authorizations?: Record<string, AuthEntry>;
|
|
95
|
+
/** Available SOLID references for the framework's skill. */
|
|
96
|
+
refs?: RefMeta[];
|
|
97
|
+
/** Absolute paths of SOLID refs already read this session. */
|
|
98
|
+
refsRead?: string[];
|
|
99
|
+
}
|
|
100
|
+
/** A single APEX gate: returns a blocking {@link Prompt}, or null to pass. */
|
|
101
|
+
type ApexGate = (ctx: ApexContext) => Prompt | null;
|
|
102
|
+
/** Gate: Context7 + Exa must have been consulted this session. */
|
|
103
|
+
declare const docConsultedGate: ApexGate;
|
|
104
|
+
/** Gate: the routed SOLID references for this edit must have been read. */
|
|
105
|
+
declare const solidReadGate: ApexGate;
|
|
106
|
+
/** Default APEX gate chain. */
|
|
107
|
+
declare const APEX_GATES: ReadonlyArray<ApexGate>;
|
|
108
|
+
/**
|
|
109
|
+
* Run the APEX gates (chain-of-responsibility): the first failing gate's prompt
|
|
110
|
+
* wins; null means every gate passed (allow).
|
|
111
|
+
*/
|
|
112
|
+
declare function evaluateApex(ctx: ApexContext, gates?: ReadonlyArray<ApexGate>): Prompt | null;
|
|
113
|
+
//#endregion
|
|
114
|
+
export { isApexCommand as S, evaluateFileSize as _, evaluateApex as a, ProjectType as b, PolicyResult as c, GIT_BLOCKED as d, PROJECT_INSTALL as f, countLines as g, FileSizeVerdict as h, docConsultedGate as i, evaluate as l, matchPatterns as m, ApexContext as n, solidReadGate as o, SYSTEM_INSTALL as p, ApexGate as r, PolicyContext as s, APEX_GATES as t, GIT_ASK as u, detectFramework as v, detectProjectType as x, DEV_KEYWORDS as y };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/util/compact-json.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Compact JSON serializer for cache/state files.
|
|
4
|
+
* Top-level keys are indented one per line; nested objects/arrays render inline.
|
|
5
|
+
* Behaviour preserved from the fusengine hooks.
|
|
6
|
+
*/
|
|
7
|
+
declare function compactJson(data: unknown): string;
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/util/project-root.d.ts
|
|
10
|
+
/** True for a source-code file outside generated/vendored directories. */
|
|
11
|
+
declare function isCodeFile(p: string): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Resolve the project root, preferring the repo boundary (`.git`) over a
|
|
14
|
+
* nested `package.json` — avoids false roots in monorepos. Null if none found.
|
|
15
|
+
*/
|
|
16
|
+
declare function projectRootOrNull(dir: string): string | null;
|
|
17
|
+
/** Like {@link projectRootOrNull} but falls back to `process.cwd()`. */
|
|
18
|
+
declare function projectRoot(dir: string): string;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { compactJson as i, projectRoot as n, projectRootOrNull as r, isCodeFile as t };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { n as RouteResult, r as ScoredRef, t as RefMeta } from "./types-CY5qT2X1.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/refs/frontmatter.d.ts
|
|
4
|
+
/** Extract frontmatter key/value pairs from markdown content (quotes stripped). */
|
|
5
|
+
declare function parseFrontmatter(content: string): Record<string, string>;
|
|
6
|
+
/** Convert a simple glob (`**`, `*`) to an anchored RegExp. */
|
|
7
|
+
declare function globToRe(g: string): RegExp;
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/refs/router.d.ts
|
|
10
|
+
/**
|
|
11
|
+
* Score references against a file edit (pure):
|
|
12
|
+
* +10 per `applies-to` glob match, +5 per `trigger-on-edit` fragment, +1 per keyword.
|
|
13
|
+
*/
|
|
14
|
+
declare function scoreReferences(refs: RefMeta[], filePath: string, content: string): ScoredRef[];
|
|
15
|
+
/**
|
|
16
|
+
* Route references for a file edit: top-2 required + next-2 optional, ensuring a
|
|
17
|
+
* `principle` and a `template` appear in the top 4. Returns null when nothing scores.
|
|
18
|
+
*/
|
|
19
|
+
declare function routeReferences(refs: RefMeta[], filePath: string, content: string, skillPath?: string): RouteResult | null;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { parseFrontmatter as i, scoreReferences as n, globToRe as r, routeReferences as t };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { t as AuthEntry } from "./doc-helpers-CG1nuf-c.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/state/lock.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Acquire a directory-based lock (atomic `mkdir`, EEXIST = already held) with a timeout.
|
|
6
|
+
* @returns a release function, or null if the lock could not be acquired in time.
|
|
7
|
+
*/
|
|
8
|
+
declare function acquireLock(lockDir: string, timeoutMs?: number): Promise<(() => Promise<void>) | null>;
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/state/apex-state.d.ts
|
|
11
|
+
declare const DEFAULT_STATE: {
|
|
12
|
+
$schema: string;
|
|
13
|
+
description: string;
|
|
14
|
+
target: Record<string, string>;
|
|
15
|
+
authorizations: Record<string, AuthEntry & {
|
|
16
|
+
doc_consulted?: string;
|
|
17
|
+
}>;
|
|
18
|
+
};
|
|
19
|
+
/** APEX state shape. */
|
|
20
|
+
type ApexState = typeof DEFAULT_STATE;
|
|
21
|
+
/** APEX state directory under a home dir. */
|
|
22
|
+
declare function apexStateDir(home?: string): string;
|
|
23
|
+
/** Daily state file path: `<home>/.claude/logs/00-apex/<YYYY-MM-DD>-state.json`. */
|
|
24
|
+
declare function stateFilePath(home?: string, today?: string): string;
|
|
25
|
+
/** Ensure the state directory exists and return its path. */
|
|
26
|
+
declare function ensureStateDir(home?: string): Promise<string>;
|
|
27
|
+
/** Load APEX state, or a fresh default. */
|
|
28
|
+
declare function loadState(path: string): Promise<ApexState>;
|
|
29
|
+
/** Save APEX state. */
|
|
30
|
+
declare function saveState(path: string, state: ApexState): Promise<void>;
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/state/task-helpers.d.ts
|
|
33
|
+
/** A task entry in task.json. */
|
|
34
|
+
interface ApexTask {
|
|
35
|
+
subject: string;
|
|
36
|
+
description: string;
|
|
37
|
+
status: string;
|
|
38
|
+
phase: string;
|
|
39
|
+
started_at?: string;
|
|
40
|
+
completed_at?: string;
|
|
41
|
+
created_at?: string;
|
|
42
|
+
doc_consulted: Record<string, unknown>;
|
|
43
|
+
files_modified: string[];
|
|
44
|
+
blockedBy?: string[];
|
|
45
|
+
}
|
|
46
|
+
/** Structure of `.claude/apex/task.json`. */
|
|
47
|
+
interface ApexTaskFile {
|
|
48
|
+
current_task: string;
|
|
49
|
+
created_at: string;
|
|
50
|
+
tasks: Record<string, ApexTask>;
|
|
51
|
+
}
|
|
52
|
+
/** Add a new pending task. */
|
|
53
|
+
declare function taskCreate(file: string, id: string, subject: string, desc: string): Promise<void>;
|
|
54
|
+
/** Mark a task in_progress (creating a stub if absent). */
|
|
55
|
+
declare function taskStart(file: string, id: string, subject?: string, desc?: string, blocked?: string): Promise<void>;
|
|
56
|
+
/** Mark a task completed. */
|
|
57
|
+
declare function taskComplete(file: string, id: string): Promise<void>;
|
|
58
|
+
//#endregion
|
|
59
|
+
export { taskStart as a, ensureStateDir as c, stateFilePath as d, acquireLock as f, taskCreate as i, loadState as l, ApexTaskFile as n, ApexState as o, taskComplete as r, apexStateDir as s, ApexTask as t, saveState as u };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { t as Prompt } from "./types-D56jSgD9.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/adapters/claude/index.d.ts
|
|
4
|
+
/** Subset of the Claude Code hook stdin payload we consume. */
|
|
5
|
+
interface ClaudeHookInput {
|
|
6
|
+
hook_event_name?: string;
|
|
7
|
+
tool_name?: string;
|
|
8
|
+
tool_input?: {
|
|
9
|
+
file_path?: string;
|
|
10
|
+
content?: string;
|
|
11
|
+
new_string?: string;
|
|
12
|
+
command?: string;
|
|
13
|
+
};
|
|
14
|
+
cwd?: string;
|
|
15
|
+
}
|
|
16
|
+
/** Read & parse the Claude hook payload from stdin (empty object on bad input). */
|
|
17
|
+
declare function readClaudeInput(): Promise<ClaudeHookInput>;
|
|
18
|
+
/** A `deny` hook response for a given event. */
|
|
19
|
+
declare function denyResponse(event: string, reason: string): string;
|
|
20
|
+
/** An `additionalContext` injection response. */
|
|
21
|
+
declare function contextResponse(event: string, text: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Render a portable {@link Prompt} as a Claude Code hook response:
|
|
24
|
+
* `block` → `permissionDecision: deny`, `ask` → `permissionDecision: ask`
|
|
25
|
+
* (interactive confirm), `inform` → `additionalContext`.
|
|
26
|
+
*/
|
|
27
|
+
declare function toClaudeResponse(event: string, prompt: Prompt): string;
|
|
28
|
+
/**
|
|
29
|
+
* Run the bundled policy over a Claude payload and return the native response
|
|
30
|
+
* string (deny/ask/additionalContext), or null to allow.
|
|
31
|
+
*/
|
|
32
|
+
declare function guard(input: ClaudeHookInput): string | null;
|
|
33
|
+
/** @deprecated use {@link guard}. Kept for back-compat. */
|
|
34
|
+
declare const fileSizeGuard: typeof guard;
|
|
35
|
+
//#endregion
|
|
36
|
+
export { guard as a, fileSizeGuard as i, contextResponse as n, readClaudeInput as o, denyResponse as r, toClaudeResponse as s, ClaudeHookInput as t };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { n as PromptKind, r as formatPrompt, t as Prompt } from "./types-D56jSgD9.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { a as compactMarkdown, i as summarizeIndex, n as IndexSummary, o as jaccardSimilar, r as loadIndex, s as queryHash, t as extractText } from "./index-B3Ve_bBu.mjs";
|
|
3
|
+
import { a as DEFAULT_TTL_SEC, c as ttlLabel, i as splitTarget, l as parseEnvInt, n as MAX_LINES_ENV_KEY, o as TTL_ENV_KEY, r as resolveMaxLines, s as resolveTtlSec, t as DEFAULT_MAX_LINES } from "./index-B-z0CCiU.mjs";
|
|
4
|
+
import { a as detectHarness, i as HarnessVia, n as HarnessInfo, o as detectMode, r as HarnessMode, s as modeFor, t as HarnessId } from "./harness-DwJskkz_.mjs";
|
|
5
5
|
import { a as isDocConsulted, i as formatDocSatisfactionStatus, n as DocSatisfactionStatus, o as resolveSessions, r as formatDocDeny, t as AuthEntry } from "./doc-helpers-CG1nuf-c.mjs";
|
|
6
|
-
import { incrementTrivialEditCounter } from "./
|
|
7
|
-
import { compactJson,
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
6
|
+
import { t as incrementTrivialEditCounter } from "./index-BOBXQ91y.mjs";
|
|
7
|
+
import { i as compactJson, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./index-C1vLIMwN.mjs";
|
|
8
|
+
import { S as isApexCommand, _ as evaluateFileSize, a as evaluateApex, b as ProjectType, c as PolicyResult, d as GIT_BLOCKED, f as PROJECT_INSTALL, g as countLines, h as FileSizeVerdict, i as docConsultedGate, l as evaluate, m as matchPatterns, n as ApexContext, o as solidReadGate, p as SYSTEM_INSTALL, r as ApexGate, s as PolicyContext, t as APEX_GATES, u as GIT_ASK, v as detectFramework, x as detectProjectType, y as DEV_KEYWORDS } from "./index-BXBWKbL8.mjs";
|
|
9
|
+
import { n as RouteResult, r as ScoredRef, t as RefMeta } from "./types-CY5qT2X1.mjs";
|
|
10
|
+
import { a as ReminderState, c as setStateField, i as registryFile, l as stateFileFor, n as addRoot, o as nowStamp, r as readRoots, s as readState, t as ensureMemoryGitignore, u as throttleMs } from "./index-BEM-mQMC.mjs";
|
|
11
|
+
import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "./index-C2Lz-cwJ.mjs";
|
|
12
|
+
import { a as taskStart, c as ensureStateDir, d as stateFilePath, f as acquireLock, i as taskCreate, l as loadState, n as ApexTaskFile, o as ApexState, r as taskComplete, s as apexStateDir, t as ApexTask, u as saveState } from "./index-CPoF_hLP.mjs";
|
|
13
|
+
import { _ as TIME_INTERVALS, a as formatCost, c as formatTokens, d as colors, f as progressiveColor, g as PROGRESS_CHARS, h as PROGRESS_BAR_DEFAULTS, i as formatBasename, l as ColorFn, m as GRADIENT_BLOCKS, n as generateGradientBar, o as formatPath, p as COLOR_THRESHOLDS, r as generateProgressBar, s as formatTimeLeft, t as ProgressBarOptions, u as Palette } from "./index-BWK8slRi.mjs";
|
|
14
|
+
export { APEX_GATES, ApexContext, ApexGate, ApexState, ApexTask, ApexTaskFile, AuthEntry, COLOR_THRESHOLDS, ColorFn, DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, DEV_KEYWORDS, DocSatisfactionStatus, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, GRADIENT_BLOCKS, HarnessId, HarnessInfo, HarnessMode, HarnessVia, IndexSummary, MAX_LINES_ENV_KEY, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INSTALL, Palette, PolicyContext, PolicyResult, ProgressBarOptions, ProjectType, Prompt, PromptKind, RefMeta, ReminderState, RouteResult, SYSTEM_INSTALL, ScoredRef, TIME_INTERVALS, TTL_ENV_KEY, acquireLock, addRoot, apexStateDir, colors, compactJson, compactMarkdown, countLines, detectFramework, detectHarness, detectMode, detectProjectType, docConsultedGate, ensureMemoryGitignore, ensureStateDir, evaluate, evaluateApex, evaluateFileSize, extractText, formatBasename, formatCost, formatDocDeny, formatDocSatisfactionStatus, formatPath, formatPrompt, formatTimeLeft, formatTokens, generateGradientBar, generateProgressBar, globToRe, incrementTrivialEditCounter, isApexCommand, isCodeFile, isDocConsulted, jaccardSimilar, loadIndex, loadState, matchPatterns, modeFor, nowStamp, parseEnvInt, parseFrontmatter, progressiveColor, projectRoot, projectRootOrNull, queryHash, readRoots, readState, registryFile, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, saveState, scoreReferences, setStateField, solidReadGate, splitTarget, stateFileFor, stateFilePath, summarizeIndex, taskComplete, taskCreate, taskStart, throttleMs, ttlLabel };
|
package/dist/index.mjs
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { a as parseEnvInt, i as splitTarget, n as MAX_LINES_ENV_KEY, r as resolveMaxLines, t as DEFAULT_MAX_LINES } from "./limits-CHn8AIL1.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { i as ttlLabel, n as TTL_ENV_KEY, r as resolveTtlSec, t as DEFAULT_TTL_SEC } from "./config-BG55s6HZ.mjs";
|
|
3
3
|
import { t as compactJson } from "./compact-json-DK2nX-MK.mjs";
|
|
4
4
|
import { n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./project-root-C4ks_q1G.mjs";
|
|
5
|
-
import "./
|
|
6
|
-
import {
|
|
5
|
+
import { n as detectMode, r as modeFor, t as detectHarness } from "./harness-C8Nxxyn_.mjs";
|
|
6
|
+
import { a as DEV_KEYWORDS, i as solidReadGate, n as docConsultedGate, o as detectProjectType, r as evaluateApex, s as isApexCommand, t as APEX_GATES } from "./policy-DMpyaPZ_.mjs";
|
|
7
7
|
import { a as SYSTEM_INSTALL, c as evaluateFileSize, i as PROJECT_INSTALL, l as detectFramework, n as GIT_ASK, o as matchPatterns, r as GIT_BLOCKED, s as countLines, t as evaluate } from "./evaluate-CsYyUucy.mjs";
|
|
8
|
-
import {
|
|
8
|
+
import { i as resolveSessions, n as formatDocSatisfactionStatus, r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-Dd_x1-tZ.mjs";
|
|
9
|
+
import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "./router-Dj3AfgBE.mjs";
|
|
9
10
|
import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
|
|
10
|
-
import "./
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
import { COLOR_THRESHOLDS, GRADIENT_BLOCKS, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, TIME_INTERVALS, colors, formatBasename, formatCost, formatPath, formatTimeLeft, formatTokens, generateGradientBar, generateProgressBar, progressiveColor } from "./statusline/index.mjs";
|
|
17
|
-
export { COLOR_THRESHOLDS, DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, DEV_KEYWORDS, GIT_ASK, GIT_BLOCKED, GRADIENT_BLOCKS, MAX_LINES_ENV_KEY, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INSTALL, SYSTEM_INSTALL, TIME_INTERVALS, TTL_ENV_KEY, acquireLock, addRoot, apexStateDir, colors, compactJson, compactMarkdown, countLines, detectFramework, detectHarness, detectMode, detectProjectType, ensureMemoryGitignore, ensureStateDir, evaluate, evaluateFileSize, extractText, formatBasename, formatCost, formatDocDeny, formatDocSatisfactionStatus, formatPath, formatPrompt, formatTimeLeft, formatTokens, generateGradientBar, generateProgressBar, globToRe, incrementTrivialEditCounter, isApexCommand, isCodeFile, isDocConsulted, jaccardSimilar, loadIndex, loadState, matchPatterns, modeFor, nowStamp, parseEnvInt, parseFrontmatter, progressiveColor, projectRoot, projectRootOrNull, queryHash, readRoots, readState, registryFile, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, saveState, scoreReferences, setStateField, splitTarget, stateFileFor, stateFilePath, summarizeIndex, taskComplete, taskCreate, taskStart, throttleMs, ttlLabel };
|
|
11
|
+
import { a as readState, c as throttleMs, i as nowStamp, l as ensureMemoryGitignore, n as readRoots, o as setStateField, r as registryFile, s as stateFileFor, t as addRoot } from "./memory-BVNt4Ary.mjs";
|
|
12
|
+
import { a as jaccardSimilar, i as compactMarkdown, n as loadIndex, o as queryHash, r as summarizeIndex, t as extractText } from "./cache-DbPSJ9bC.mjs";
|
|
13
|
+
import { t as incrementTrivialEditCounter } from "./freshness-BK9Xg6oG.mjs";
|
|
14
|
+
import { a as ensureStateDir, c as stateFilePath, i as apexStateDir, l as acquireLock, n as taskCreate, o as loadState, r as taskStart, s as saveState, t as taskComplete } from "./state-Bc4wdnCG.mjs";
|
|
15
|
+
import { a as formatPath, c as colors, d as GRADIENT_BLOCKS, f as PROGRESS_BAR_DEFAULTS, i as formatCost, l as progressiveColor, m as TIME_INTERVALS, n as generateProgressBar, o as formatTimeLeft, p as PROGRESS_CHARS, r as formatBasename, s as formatTokens, t as generateGradientBar, u as COLOR_THRESHOLDS } from "./statusline-D87eUNXl.mjs";
|
|
16
|
+
export { APEX_GATES, COLOR_THRESHOLDS, DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, DEV_KEYWORDS, GIT_ASK, GIT_BLOCKED, GRADIENT_BLOCKS, MAX_LINES_ENV_KEY, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INSTALL, SYSTEM_INSTALL, TIME_INTERVALS, TTL_ENV_KEY, acquireLock, addRoot, apexStateDir, colors, compactJson, compactMarkdown, countLines, detectFramework, detectHarness, detectMode, detectProjectType, docConsultedGate, ensureMemoryGitignore, ensureStateDir, evaluate, evaluateApex, evaluateFileSize, extractText, formatBasename, formatCost, formatDocDeny, formatDocSatisfactionStatus, formatPath, formatPrompt, formatTimeLeft, formatTokens, generateGradientBar, generateProgressBar, globToRe, incrementTrivialEditCounter, isApexCommand, isCodeFile, isDocConsulted, jaccardSimilar, loadIndex, loadState, matchPatterns, modeFor, nowStamp, parseEnvInt, parseFrontmatter, progressiveColor, projectRoot, projectRootOrNull, queryHash, readRoots, readState, registryFile, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, saveState, scoreReferences, setStateField, solidReadGate, splitTarget, stateFileFor, stateFilePath, summarizeIndex, taskComplete, taskCreate, taskStart, throttleMs, ttlLabel };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { t as HarnessId } from "../harness-DwJskkz_.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/init/templates.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Wiring file templates per harness, to register `harness hook <id>` as a
|
|
6
|
+
* tool-use hook. Formats verified against each harness's 2026 hook docs.
|
|
7
|
+
*/
|
|
8
|
+
/** A file to write during `harness init`. */
|
|
9
|
+
interface InitFile {
|
|
10
|
+
path: string;
|
|
11
|
+
content: string;
|
|
12
|
+
executable?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/** Claude Code: PreToolUse(Write|Edit) -> command. Target: `.claude/settings.json`. */
|
|
15
|
+
declare function claudeInit(command: string): InitFile;
|
|
16
|
+
/** Codex CLI: `.codex/hooks.json` — PreToolUse (Claude-compatible shape). */
|
|
17
|
+
declare function codexInit(command: string): InitFile;
|
|
18
|
+
/** Cursor: `.cursor/hooks.json` (version 1) — shell + file-edit hooks. */
|
|
19
|
+
declare function cursorInit(command: string): InitFile;
|
|
20
|
+
/** Gemini CLI: `.gemini/settings.json` — BeforeTool, timeout in ms. */
|
|
21
|
+
declare function geminiInit(command: string): InitFile;
|
|
22
|
+
/** Cline: an executable `.clinerules/hooks/PreToolUse` that pipes stdin to the command. */
|
|
23
|
+
declare function clineInit(command: string): InitFile;
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/init/run.d.ts
|
|
26
|
+
/**
|
|
27
|
+
* Build the wiring file for a harness, or null when it has no hook integration
|
|
28
|
+
* (cli-mode harnesses use `harness check` in a pre-commit step instead).
|
|
29
|
+
*/
|
|
30
|
+
declare function initFor(id: HarnessId, command?: string): InitFile | null;
|
|
31
|
+
/** Write an {@link InitFile} under `root` (creates dirs; `chmod +x` when executable). */
|
|
32
|
+
declare function writeInitFile(root: string, file: InitFile): string;
|
|
33
|
+
//#endregion
|
|
34
|
+
export { InitFile, claudeInit, clineInit, codexInit, cursorInit, geminiInit, initFor, writeInitFile };
|
package/dist/memory/index.d.mts
CHANGED
|
@@ -1,30 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
/** Per-project reminder throttle state, stored at `<root>/MEMORY/state.json`. */
|
|
3
|
-
interface ReminderState {
|
|
4
|
-
lastRemindedAt: number;
|
|
5
|
-
lastCodeEditAt: number;
|
|
6
|
-
}
|
|
7
|
-
/** Absolute path of the per-project throttle state file. */
|
|
8
|
-
declare function stateFileFor(root: string): string;
|
|
9
|
-
/** Read both throttle timestamps; missing/corrupt fields default to 0. */
|
|
10
|
-
declare function readState(file: string): ReminderState;
|
|
11
|
-
/** Persist one field without clobbering the other (read-modify-write). */
|
|
12
|
-
declare function setStateField(file: string, key: keyof ReminderState, value: number): void;
|
|
13
|
-
/** Local wall-clock timestamp for a lesson bullet: `YYYY-MM-DD HH:MM`. */
|
|
14
|
-
declare function nowStamp(): string;
|
|
15
|
-
/** Throttle window (ms) from `FUSE_LESSONS_THROTTLE_MIN` (default 5 min). */
|
|
16
|
-
declare function throttleMs(env?: Record<string, string | undefined>): number;
|
|
17
|
-
//#endregion
|
|
18
|
-
//#region src/memory/registry.d.ts
|
|
19
|
-
/** Absolute path of the global roots registry, or null when home is unusable. */
|
|
20
|
-
declare function registryFile(home?: string | undefined): string | null;
|
|
21
|
-
/** Read the registered project roots (deduplicated string entries only). */
|
|
22
|
-
declare function readRoots(home?: string): string[];
|
|
23
|
-
/** Register a project root once (deduplicated, read-modify-write, non-throwing). */
|
|
24
|
-
declare function addRoot(root: string, home?: string): void;
|
|
25
|
-
//#endregion
|
|
26
|
-
//#region src/memory/gitignore.d.ts
|
|
27
|
-
/** Ensure `<memoryDir>/.gitignore` ignores the machine-local `state.json`. */
|
|
28
|
-
declare function ensureMemoryGitignore(memoryDir: string): void;
|
|
29
|
-
//#endregion
|
|
1
|
+
import { a as ReminderState, c as setStateField, i as registryFile, l as stateFileFor, n as addRoot, o as nowStamp, r as readRoots, s as readState, t as ensureMemoryGitignore, u as throttleMs } from "../index-BEM-mQMC.mjs";
|
|
30
2
|
export { ReminderState, addRoot, ensureMemoryGitignore, nowStamp, readRoots, readState, registryFile, setStateField, stateFileFor, throttleMs };
|
package/dist/memory/index.mjs
CHANGED
|
@@ -1,94 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { dirname } from "node:path";
|
|
3
|
-
//#region src/memory/gitignore.ts
|
|
4
|
-
/** Ensure `<memoryDir>/.gitignore` ignores the machine-local `state.json`. */
|
|
5
|
-
function ensureMemoryGitignore(memoryDir) {
|
|
6
|
-
const file = `${memoryDir}/.gitignore`;
|
|
7
|
-
try {
|
|
8
|
-
const existing = existsSync(file) ? readFileSync(file, "utf8") : "";
|
|
9
|
-
if (/^state\.json$/m.test(existing)) return;
|
|
10
|
-
writeFileSync(file, existing.trim() ? `${existing.trimEnd()}\nstate.json\n` : "state.json\n");
|
|
11
|
-
} catch {}
|
|
12
|
-
}
|
|
13
|
-
//#endregion
|
|
14
|
-
//#region src/memory/state.ts
|
|
15
|
-
/** Absolute path of the per-project throttle state file. */
|
|
16
|
-
function stateFileFor(root) {
|
|
17
|
-
return `${root}/MEMORY/state.json`;
|
|
18
|
-
}
|
|
19
|
-
function num(v) {
|
|
20
|
-
return typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
21
|
-
}
|
|
22
|
-
/** Read both throttle timestamps; missing/corrupt fields default to 0. */
|
|
23
|
-
function readState(file) {
|
|
24
|
-
try {
|
|
25
|
-
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
26
|
-
return {
|
|
27
|
-
lastRemindedAt: num(parsed?.lastRemindedAt),
|
|
28
|
-
lastCodeEditAt: num(parsed?.lastCodeEditAt)
|
|
29
|
-
};
|
|
30
|
-
} catch {
|
|
31
|
-
return {
|
|
32
|
-
lastRemindedAt: 0,
|
|
33
|
-
lastCodeEditAt: 0
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
/** Persist one field without clobbering the other (read-modify-write). */
|
|
38
|
-
function setStateField(file, key, value) {
|
|
39
|
-
const next = {
|
|
40
|
-
...readState(file),
|
|
41
|
-
[key]: value
|
|
42
|
-
};
|
|
43
|
-
const dir = dirname(file);
|
|
44
|
-
mkdirSync(dir, { recursive: true });
|
|
45
|
-
ensureMemoryGitignore(dir);
|
|
46
|
-
writeFileSync(file, JSON.stringify(next));
|
|
47
|
-
}
|
|
48
|
-
/** Local wall-clock timestamp for a lesson bullet: `YYYY-MM-DD HH:MM`. */
|
|
49
|
-
function nowStamp() {
|
|
50
|
-
const d = /* @__PURE__ */ new Date();
|
|
51
|
-
const p = (n) => String(n).padStart(2, "0");
|
|
52
|
-
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`;
|
|
53
|
-
}
|
|
54
|
-
/** Throttle window (ms) from `FUSE_LESSONS_THROTTLE_MIN` (default 5 min). */
|
|
55
|
-
function throttleMs(env = process.env) {
|
|
56
|
-
const raw = env.FUSE_LESSONS_THROTTLE_MIN?.trim();
|
|
57
|
-
const min = raw ? Number(raw) : 5;
|
|
58
|
-
return (Number.isFinite(min) ? Math.max(0, min) : 5) * 6e4;
|
|
59
|
-
}
|
|
60
|
-
//#endregion
|
|
61
|
-
//#region src/memory/registry.ts
|
|
62
|
-
/** Registry path relative to the home dir. */
|
|
63
|
-
const SUBPATH = ".claude/fusengine-cache/lessons/roots.json";
|
|
64
|
-
/** Absolute path of the global roots registry, or null when home is unusable. */
|
|
65
|
-
function registryFile(home = process.env.HOME) {
|
|
66
|
-
const h = home?.trim();
|
|
67
|
-
if (!h || !h.startsWith("/")) return null;
|
|
68
|
-
return `${h}/${SUBPATH}`;
|
|
69
|
-
}
|
|
70
|
-
/** Read the registered project roots (deduplicated string entries only). */
|
|
71
|
-
function readRoots(home) {
|
|
72
|
-
const file = registryFile(home);
|
|
73
|
-
if (!file) return [];
|
|
74
|
-
try {
|
|
75
|
-
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
76
|
-
return Array.isArray(parsed) ? parsed.filter((e) => typeof e === "string") : [];
|
|
77
|
-
} catch {
|
|
78
|
-
return [];
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
/** Register a project root once (deduplicated, read-modify-write, non-throwing). */
|
|
82
|
-
function addRoot(root, home) {
|
|
83
|
-
const file = registryFile(home);
|
|
84
|
-
if (!file) return;
|
|
85
|
-
try {
|
|
86
|
-
const roots = new Set(readRoots(home));
|
|
87
|
-
if (roots.has(root)) return;
|
|
88
|
-
roots.add(root);
|
|
89
|
-
mkdirSync(dirname(file), { recursive: true });
|
|
90
|
-
writeFileSync(file, JSON.stringify([...roots]));
|
|
91
|
-
} catch {}
|
|
92
|
-
}
|
|
93
|
-
//#endregion
|
|
1
|
+
import { a as readState, c as throttleMs, i as nowStamp, l as ensureMemoryGitignore, n as readRoots, o as setStateField, r as registryFile, s as stateFileFor, t as addRoot } from "../memory-BVNt4Ary.mjs";
|
|
94
2
|
export { addRoot, ensureMemoryGitignore, nowStamp, readRoots, readState, registryFile, setStateField, stateFileFor, throttleMs };
|