septum 0.1.4 → 0.1.6

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.
Files changed (70) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +105 -105
  3. package/bin/septum.ts +4 -4
  4. package/package.json +63 -63
  5. package/src/cli/commands/check.ts +161 -161
  6. package/src/cli/commands/hook.ts +216 -188
  7. package/src/cli/commands/ingest.ts +29 -29
  8. package/src/cli/commands/init.ts +213 -211
  9. package/src/cli/commands/locate.ts +61 -61
  10. package/src/cli/commands/query.ts +104 -64
  11. package/src/cli/commands/serve.ts +5 -5
  12. package/src/cli/commands/slice.ts +50 -48
  13. package/src/cli/commands/sync.ts +31 -31
  14. package/src/cli/index.ts +220 -210
  15. package/src/cli/templates/hooks.ts +75 -75
  16. package/src/cli/templates/rules.ts +50 -38
  17. package/src/cli/templates/skill.ts +65 -69
  18. package/src/core/boundary/evaluator.ts +429 -210
  19. package/src/core/config/loader.ts +117 -97
  20. package/src/core/config/schema.ts +39 -39
  21. package/src/core/database/client.ts +44 -44
  22. package/src/core/database/repositories/dependency.repository.ts +552 -349
  23. package/src/core/database/repositories/domain.repository.ts +275 -198
  24. package/src/core/database/repositories/file.repository.ts +117 -106
  25. package/src/core/database/repositories/meta.repository.ts +33 -33
  26. package/src/core/database/repositories/symbol.repository.ts +482 -443
  27. package/src/core/database/repository.ts +281 -260
  28. package/src/core/database/schema.ts +154 -153
  29. package/src/core/discovery/topology-detector.ts +486 -486
  30. package/src/core/ingestion/hasher.ts +5 -5
  31. package/src/core/ingestion/pipeline.ts +606 -535
  32. package/src/core/parser/boundary-tracker.ts +433 -288
  33. package/src/core/parser/extractors/base.ts +62 -62
  34. package/src/core/parser/extractors/blade.ts +158 -158
  35. package/src/core/parser/extractors/frontend.ts +147 -194
  36. package/src/core/parser/extractors/go.ts +408 -180
  37. package/src/core/parser/extractors/laravel-semantic.ts +1045 -901
  38. package/src/core/parser/extractors/mcp-cli-semantic.ts +328 -199
  39. package/src/core/parser/extractors/nestjs-semantic.ts +134 -119
  40. package/src/core/parser/extractors/php.ts +415 -153
  41. package/src/core/parser/extractors/python.ts +460 -228
  42. package/src/core/parser/extractors/registry.ts +70 -70
  43. package/src/core/parser/extractors/semantic-extractor.interface.ts +21 -21
  44. package/src/core/parser/extractors/typescript.ts +668 -181
  45. package/src/core/parser/tree-sitter.ts +41 -41
  46. package/src/core/parser/wasm-loader.ts +271 -0
  47. package/src/core/resolver/call-graph-tracer.ts +698 -668
  48. package/src/core/resolver/module-resolver.ts +479 -342
  49. package/src/core/resolver/path-resolver.ts +147 -147
  50. package/src/core/resolver/symbol-locator.ts +543 -543
  51. package/src/core/resolver/vertical-slice-tracer.ts +323 -285
  52. package/src/core/session/session-manager.ts +56 -56
  53. package/src/core/telemetry/telemetry.ts +86 -86
  54. package/src/core/topology/environment-detector.ts +109 -6
  55. package/src/index.ts +21 -21
  56. package/src/mcp/schemas.ts +695 -286
  57. package/src/mcp/server.ts +927 -716
  58. package/src/mcp/tools/check-boundary.ts +307 -152
  59. package/src/mcp/tools/get-domain-catalog.ts +155 -121
  60. package/src/mcp/tools/get-environment-topology.ts +3 -6
  61. package/src/mcp/tools/get-feature-context.ts +227 -116
  62. package/src/mcp/tools/get-symbol-hotspots.ts +54 -59
  63. package/src/mcp/tools/get-symbol-impact.ts +28 -26
  64. package/src/mcp/tools/get-symbol.ts +65 -63
  65. package/src/mcp/tools/locate-symbol.ts +169 -190
  66. package/src/mcp/tools/register-domain.ts +59 -64
  67. package/src/mcp/tools/register-feature.ts +91 -0
  68. package/src/mcp/tools/trace-vertical-slice.ts +74 -48
  69. package/src/types/index.ts +366 -315
  70. package/src/version.ts +3 -3
package/src/cli/index.ts CHANGED
@@ -1,210 +1,220 @@
1
- import { parseArgs } from "node:util";
2
- import { SessionManager } from "../core/session/session-manager.ts";
3
- import { SEPTUM_VERSION } from "../version.ts";
4
- import { handleCheckCommand } from "./commands/check.ts";
5
- import { handleHookCommand } from "./commands/hook.ts";
6
- import { handleIngestCommand } from "./commands/ingest.ts";
7
- import { handleInitCommand } from "./commands/init.ts";
8
- import { handleTopologyCommand } from "./commands/topology.ts";
9
- import { handleLocateCommand } from "./commands/locate.ts";
10
- import { handleQueryCommand } from "./commands/query.ts";
11
- import { handleServeCommand } from "./commands/serve.ts";
12
- import { handleSliceCommand } from "./commands/slice.ts";
13
- import { handleSyncCommand } from "./commands/sync.ts";
14
-
15
- export async function runCLI(argv: string[]): Promise<void> {
16
- let parsed;
17
- try {
18
- parsed = parseArgs({
19
- args: argv.slice(2),
20
- options: {
21
- help: { type: "boolean", short: "h" },
22
- version: { type: "boolean", short: "v" },
23
- force: { type: "boolean", short: "f" },
24
- json: { type: "boolean" },
25
- strict: { type: "boolean" },
26
- staged: { type: "boolean" },
27
- domain: { type: "string", short: "d" },
28
- archetype: { type: "string", short: "a" },
29
- feature: { type: "string" },
30
- },
31
- allowPositionals: true,
32
- strict: false,
33
- });
34
- } catch (err) {
35
- const message = err instanceof Error ? err.message : String(err);
36
- console.error(`\x1b[31m[Septum Error]\x1b[0m ${message}`);
37
- process.exit(1);
38
- }
39
-
40
- const { values: flags, positionals } = parsed;
41
- const command = positionals[0];
42
-
43
- if (flags.version || command === "version") {
44
- console.log(`Septum v${SEPTUM_VERSION}`);
45
- return;
46
- }
47
-
48
- if (flags.help || !command || command === "help") {
49
- printHelp();
50
- return;
51
- }
52
-
53
- try {
54
- switch (command) {
55
- case "init": {
56
- const force = Boolean(flags.force);
57
- await handleInitCommand(force);
58
- break;
59
- }
60
-
61
- case "ingest": {
62
- await handleIngestCommand();
63
- break;
64
- }
65
-
66
- case "sync": {
67
- const json = Boolean(flags.json);
68
- await handleSyncCommand({ json });
69
- break;
70
- }
71
-
72
- case "query": {
73
- const domainName = positionals[1];
74
- const archetype = typeof flags.archetype === "string" ? flags.archetype : undefined;
75
- const jsonOutput = Boolean(flags.json);
76
- await handleQueryCommand(domainName, archetype, jsonOutput);
77
- break;
78
- }
79
-
80
- case "locate": {
81
- const query = positionals[1];
82
- if (!query) {
83
- console.error("Usage: septum locate <symbol-or-error> [--domain <domain>] [--json]");
84
- process.exit(1);
85
- }
86
- const domain = typeof flags.domain === "string" ? flags.domain : undefined;
87
- const json = Boolean(flags.json);
88
- await handleLocateCommand(query, { domain, json });
89
- break;
90
- }
91
-
92
- case "slice": {
93
- const query = positionals[1];
94
- if (!query) {
95
- console.error("Usage: septum slice <route-or-intent> [--json]");
96
- process.exit(1);
97
- }
98
- const json = Boolean(flags.json);
99
- await handleSliceCommand(query, { json });
100
- break;
101
- }
102
-
103
- case "check": {
104
- const strict = Boolean(flags.strict);
105
- const staged = Boolean(flags.staged);
106
- const feature = typeof flags.feature === "string" ? flags.feature : undefined;
107
- await handleCheckCommand({ strict, staged, feature });
108
- break;
109
- }
110
-
111
- case "serve": {
112
- await handleServeCommand();
113
- break;
114
- }
115
-
116
- case "topology":
117
- case "env": {
118
- await handleTopologyCommand(positionals[1], positionals[2], positionals[3], positionals[4], positionals[5]);
119
- break;
120
- }
121
-
122
- case "feature": {
123
- const sub = positionals[1];
124
- if (sub === "clear") {
125
- const cleared = SessionManager.clearActiveSession(process.cwd());
126
- if (cleared) {
127
- console.log("✓ Active feature session successfully cleared.");
128
- } else {
129
- console.log("ℹ No active feature session found.");
130
- }
131
- } else if (sub === "status" || !sub) {
132
- const current = SessionManager.getActiveSession(process.cwd());
133
- if (current) {
134
- console.log(`\nActive Feature Session:`);
135
- console.log(`▶ Feature Key : ${current.feature_key}`);
136
- console.log(`▶ Domain : ${current.domain}`);
137
- console.log(`▶ Locked At : ${current.locked_at}`);
138
- console.log(`▶ Touchpoints : ${current.touchpoints.join(", ")}\n`);
139
- } else {
140
- console.log("ℹ No active feature session. All domain files accessible according to boundary rules.");
141
- }
142
- } else {
143
- console.error(`Unknown feature subcommand: '${sub}'. Use 'status' or 'clear'.`);
144
- process.exit(1);
145
- }
146
- break;
147
- }
148
-
149
- case "hook": {
150
- await handleHookCommand(argv.slice(2));
151
- break;
152
- }
153
-
154
- default: {
155
- console.error(`[Septum] Unknown command: '${command}'`);
156
- console.error("Run 'septum --help' for available commands.");
157
- process.exit(1);
158
- }
159
- }
160
- } catch (err) {
161
- const message = err instanceof Error ? err.message : String(err);
162
- console.error(`\x1b[31m[Septum Error]\x1b[0m ${message}`);
163
- process.exit(1);
164
- }
165
- }
166
-
167
- function printHelp(): void {
168
- console.log(`
169
- Septum — Deterministic Bounded-Context & Structural File Catalog
170
- Version: v${SEPTUM_VERSION}
171
-
172
- USAGE:
173
- septum <command> [options]
174
- septum [flags]
175
-
176
- COMMANDS:
177
- Catalog & Ingestion:
178
- init Initialize configuration, gitignore, pre-commit hook, and catalog
179
- Flags: -f, --force
180
- ingest Full AST scan and synchronization to SQLite database
181
- sync Incremental fast synchronization of modified files
182
- Flags: --json
183
-
184
- Structural Discovery:
185
- query [domain] Query structural catalog for a domain or whole project
186
- Flags: -a, --archetype <name>, --json
187
- locate <query> Locate symbol, class, interface, method, or error source
188
- Flags: -d, --domain <name>, --json
189
- slice <route|intent> Trace end-to-end vertical execution slice for route/intent
190
- Flags: --json
191
-
192
- Boundary & Enforcement:
193
- check Audit codebase for cross-domain boundary violations
194
- Flags: --strict, --staged, --feature <name>
195
- feature [status|clear] View or release active feature context session lock
196
- hook [subhook] Internal pre-tool guardrail hook (e.g. pre-write)
197
-
198
- Environment & Topology:
199
- topology [action] Inspect 6-layer environment topology & distributed nodes
200
- Subcommands: resolve <layer> <platform>, add-node, remove-node, clear
201
-
202
- Daemon & Protocol:
203
- serve Start Model Context Protocol (MCP) server over stdio
204
-
205
- GLOBAL FLAGS:
206
- -h, --help Show this help message
207
- -v, --version Show current version
208
- --json Output formatted JSON metrics / results
209
- `);
210
- }
1
+ import { parseArgs } from "node:util";
2
+ import { SessionManager } from "../core/session/session-manager.ts";
3
+ import { SEPTUM_VERSION } from "../version.ts";
4
+ import { handleCheckCommand } from "./commands/check.ts";
5
+ import { handleHookCommand } from "./commands/hook.ts";
6
+ import { handleIngestCommand } from "./commands/ingest.ts";
7
+ import { handleInitCommand } from "./commands/init.ts";
8
+ import { handleTopologyCommand } from "./commands/topology.ts";
9
+ import { handleLocateCommand } from "./commands/locate.ts";
10
+ import { handleQueryCommand } from "./commands/query.ts";
11
+ import { handleServeCommand } from "./commands/serve.ts";
12
+ import { handleSliceCommand } from "./commands/slice.ts";
13
+ import { handleSyncCommand } from "./commands/sync.ts";
14
+
15
+ export async function runCLI(argv: string[]): Promise<void> {
16
+ let parsed;
17
+ try {
18
+ parsed = parseArgs({
19
+ args: argv.slice(2),
20
+ options: {
21
+ help: { type: "boolean", short: "h" },
22
+ version: { type: "boolean", short: "v" },
23
+ force: { type: "boolean", short: "f" },
24
+ json: { type: "boolean" },
25
+ full: { type: "boolean" },
26
+ file: { type: "string" },
27
+ strict: { type: "boolean" },
28
+ staged: { type: "boolean" },
29
+ domain: { type: "string", short: "d" },
30
+ "max-depth": { type: "string" },
31
+ archetype: { type: "string", short: "a" },
32
+ feature: { type: "string" },
33
+ },
34
+ allowPositionals: true,
35
+ strict: false,
36
+ });
37
+ } catch (err) {
38
+ const message = err instanceof Error ? err.message : String(err);
39
+ console.error(`\x1b[31m[Septum Error]\x1b[0m ${message}`);
40
+ process.exit(1);
41
+ }
42
+
43
+ const { values: flags, positionals } = parsed;
44
+ const command = positionals[0];
45
+
46
+ if (flags.version || command === "version") {
47
+ console.log(`Septum v${SEPTUM_VERSION}`);
48
+ return;
49
+ }
50
+
51
+ if (flags.help || !command || command === "help") {
52
+ printHelp();
53
+ return;
54
+ }
55
+
56
+ try {
57
+ switch (command) {
58
+ case "init": {
59
+ const force = Boolean(flags.force);
60
+ await handleInitCommand(force);
61
+ break;
62
+ }
63
+
64
+ case "ingest": {
65
+ await handleIngestCommand();
66
+ break;
67
+ }
68
+
69
+ case "sync": {
70
+ const json = Boolean(flags.json);
71
+ await handleSyncCommand({ json });
72
+ break;
73
+ }
74
+
75
+ case "query": {
76
+ const domainName = positionals[1];
77
+ const archetype = typeof flags.archetype === "string" ? flags.archetype : undefined;
78
+ const jsonOutput = Boolean(flags.json);
79
+ const full = Boolean(flags.full);
80
+ const file = typeof flags.file === "string" ? flags.file : undefined;
81
+ await handleQueryCommand(domainName, archetype, { json: jsonOutput, full, file });
82
+ break;
83
+ }
84
+
85
+ case "locate": {
86
+ const query = positionals[1];
87
+ if (!query) {
88
+ console.error("Usage: septum locate <symbol-or-error> [--domain <domain>] [--json]");
89
+ process.exit(1);
90
+ }
91
+ const domain = typeof flags.domain === "string" ? flags.domain : undefined;
92
+ const json = Boolean(flags.json);
93
+ await handleLocateCommand(query, { domain, json });
94
+ break;
95
+ }
96
+
97
+ case "slice": {
98
+ const query = positionals[1];
99
+ if (!query) {
100
+ console.error("Usage: septum slice <route-or-intent> [-d|--max-depth <number>] [--json]");
101
+ process.exit(1);
102
+ }
103
+ const json = Boolean(flags.json);
104
+ const rawDepth = flags["max-depth"] ?? flags.domain;
105
+ const parsedDepth = rawDepth !== undefined ? Number(rawDepth) : 5;
106
+ const maxDepth = !Number.isNaN(parsedDepth)
107
+ ? Math.min(Math.max(Math.trunc(parsedDepth), 1), 8)
108
+ : 5;
109
+ await handleSliceCommand(query, { json, maxDepth });
110
+ break;
111
+ }
112
+
113
+ case "check": {
114
+ const strict = Boolean(flags.strict);
115
+ const staged = Boolean(flags.staged);
116
+ const feature = typeof flags.feature === "string" ? flags.feature : undefined;
117
+ await handleCheckCommand({ strict, staged, feature });
118
+ break;
119
+ }
120
+
121
+ case "serve": {
122
+ await handleServeCommand();
123
+ break;
124
+ }
125
+
126
+ case "topology":
127
+ case "env": {
128
+ await handleTopologyCommand(positionals[1], positionals[2], positionals[3], positionals[4], positionals[5]);
129
+ break;
130
+ }
131
+
132
+ case "feature": {
133
+ const sub = positionals[1];
134
+ if (sub === "clear") {
135
+ const cleared = SessionManager.clearActiveSession(process.cwd());
136
+ if (cleared) {
137
+ console.log("✓ Active feature session successfully cleared.");
138
+ } else {
139
+ console.log("ℹ No active feature session found.");
140
+ }
141
+ } else if (sub === "status" || !sub) {
142
+ const current = SessionManager.getActiveSession(process.cwd());
143
+ if (current) {
144
+ console.log(`\nActive Feature Session:`);
145
+ console.log(`▶ Feature Key : ${current.feature_key}`);
146
+ console.log(`▶ Domain : ${current.domain}`);
147
+ console.log(`▶ Locked At : ${current.locked_at}`);
148
+ console.log(`▶ Touchpoints : ${current.touchpoints.join(", ")}\n`);
149
+ } else {
150
+ console.log("ℹ No active feature session. All domain files accessible according to boundary rules.");
151
+ }
152
+ } else {
153
+ console.error(`Unknown feature subcommand: '${sub}'. Use 'status' or 'clear'.`);
154
+ process.exit(1);
155
+ }
156
+ break;
157
+ }
158
+
159
+ case "hook": {
160
+ await handleHookCommand(argv.slice(2));
161
+ break;
162
+ }
163
+
164
+ default: {
165
+ console.error(`[Septum] Unknown command: '${command}'`);
166
+ console.error("Run 'septum --help' for available commands.");
167
+ process.exit(1);
168
+ }
169
+ }
170
+ } catch (err) {
171
+ const message = err instanceof Error ? err.message : String(err);
172
+ console.error(`\x1b[31m[Septum Error]\x1b[0m ${message}`);
173
+ process.exit(1);
174
+ }
175
+ }
176
+
177
+ function printHelp(): void {
178
+ console.log(`
179
+ Septum — Deterministic Bounded-Context & Structural File Catalog
180
+ Version: v${SEPTUM_VERSION}
181
+
182
+ USAGE:
183
+ septum <command> [options]
184
+ septum [flags]
185
+
186
+ COMMANDS:
187
+ Catalog & Ingestion:
188
+ init Initialize configuration, gitignore, pre-commit hook, and catalog
189
+ Flags: -f, --force
190
+ ingest Full AST scan and synchronization to SQLite database
191
+ sync Incremental fast synchronization of modified files
192
+ Flags: --json
193
+
194
+ Structural Discovery:
195
+ query [domain] Query structural catalog for a domain or whole project
196
+ Flags: -a, --archetype <name>, --full, --file <filter>, --json
197
+ locate <query> Locate symbol, class, interface, method, or error source
198
+ Flags: -d, --domain <name>, --json
199
+ slice <route|intent> Trace end-to-end vertical execution slice for route/intent
200
+ Flags: -d, --max-depth <number>, --json
201
+
202
+ Boundary & Enforcement:
203
+ check Audit codebase for cross-domain boundary violations
204
+ Flags: --strict, --staged, --feature <name>
205
+ feature [status|clear] View or release active feature context session lock
206
+ hook [subhook] Internal pre-tool guardrail hook (e.g. pre-write)
207
+
208
+ Environment & Topology:
209
+ topology [action] Inspect 6-layer environment topology & distributed nodes
210
+ Subcommands: resolve <layer> <platform>, add-node, remove-node, clear
211
+
212
+ Daemon & Protocol:
213
+ serve Start Model Context Protocol (MCP) server over stdio
214
+
215
+ GLOBAL FLAGS:
216
+ -h, --help Show this help message
217
+ -v, --version Show current version
218
+ --json Output formatted JSON metrics / results
219
+ `);
220
+ }
@@ -1,75 +1,75 @@
1
- export const SEPTUM_HOOKS_CONFIG = {
2
- "septum-boundary-guard": {
3
- "PreToolUse": [
4
- {
5
- "matcher": "write_to_file|replace_file_content",
6
- "hooks": [
7
- {
8
- "type": "command",
9
- "command": "sh -c 'HOOK=\"$(git rev-parse --show-toplevel 2>/dev/null)/.agents/hooks/septum-pre-write.sh\"; if [ -f \"$HOOK\" ]; then exec \"$HOOK\"; else exit 0; fi'",
10
- "timeout": 10,
11
- },
12
- ],
13
- },
14
- ],
15
- "PostToolUse": [
16
- {
17
- "matcher": "write_to_file|replace_file_content",
18
- "hooks": [
19
- {
20
- "type": "command",
21
- "command": "sh -c 'HOOK=\"$(git rev-parse --show-toplevel 2>/dev/null)/.agents/hooks/septum-post-write.sh\"; if [ -f \"$HOOK\" ]; then exec \"$HOOK\"; else exit 0; fi'",
22
- "timeout": 15,
23
- },
24
- ],
25
- },
26
- ],
27
- },
28
- };
29
-
30
- export const SEPTUM_PRE_WRITE_SCRIPT = `#!/usr/bin/env sh
31
- # Septum 3-Gate Boundary Guard Pre-Write Hook
32
- # Intercepts write_to_file and replace_file_content before disk mutation
33
-
34
- ROOT_DIR="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
35
- if [ ! -f "$ROOT_DIR/.septum/septum.db" ]; then
36
- exit 0
37
- fi
38
-
39
- # Delegate directly to Septum's active 3-gate hook engine
40
- if command -v bun >/dev/null 2>&1 && [ -f "$ROOT_DIR/bin/septum.ts" ]; then
41
- exec bun run "$ROOT_DIR/bin/septum.ts" hook pre-write
42
- elif command -v septum >/dev/null 2>&1; then
43
- exec septum hook pre-write
44
- elif [ -f "$ROOT_DIR/node_modules/.bin/septum" ]; then
45
- exec "$ROOT_DIR/node_modules/.bin/septum" hook pre-write
46
- elif command -v bunx >/dev/null 2>&1; then
47
- exec bunx septum hook pre-write
48
- fi
49
-
50
- exit 0
51
- `;
52
-
53
- export const SEPTUM_POST_WRITE_SCRIPT = `#!/usr/bin/env sh
54
- # Septum Automated Incremental Post-Write Hook
55
- # Syncs modified AST into SQLite SSOT after file mutations
56
-
57
- ROOT_DIR="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
58
- if [ ! -f "$ROOT_DIR/.septum/septum.db" ]; then
59
- exit 0
60
- fi
61
-
62
- # Trigger background incremental sync
63
- if command -v bun >/dev/null 2>&1 && [ -f "$ROOT_DIR/bin/septum.ts" ]; then
64
- bun run "$ROOT_DIR/bin/septum.ts" sync --json >/dev/null 2>&1 &
65
- elif command -v septum >/dev/null 2>&1; then
66
- septum sync --json >/dev/null 2>&1 &
67
- elif [ -f "$ROOT_DIR/node_modules/.bin/septum" ]; then
68
- "$ROOT_DIR/node_modules/.bin/septum" sync --json >/dev/null 2>&1 &
69
- elif command -v bunx >/dev/null 2>&1; then
70
- bunx septum sync --json >/dev/null 2>&1 &
71
- fi
72
-
73
- exit 0
74
- `;
75
-
1
+ export const SEPTUM_HOOKS_CONFIG = {
2
+ "septum-boundary-guard": {
3
+ "PreToolUse": [
4
+ {
5
+ "matcher": "write_to_file|replace_file_content|multi_replace_file_content|Write|Edit|MultiEdit",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "sh -c 'HOOK=\"$(git rev-parse --show-toplevel 2>/dev/null)/.agents/hooks/septum-pre-write.sh\"; if [ -f \"$HOOK\" ]; then exec \"$HOOK\"; else exit 0; fi'",
10
+ "timeout": 10,
11
+ },
12
+ ],
13
+ },
14
+ ],
15
+ "PostToolUse": [
16
+ {
17
+ "matcher": "write_to_file|replace_file_content|multi_replace_file_content|Write|Edit|MultiEdit",
18
+ "hooks": [
19
+ {
20
+ "type": "command",
21
+ "command": "sh -c 'HOOK=\"$(git rev-parse --show-toplevel 2>/dev/null)/.agents/hooks/septum-post-write.sh\"; if [ -f \"$HOOK\" ]; then exec \"$HOOK\"; else exit 0; fi'",
22
+ "timeout": 15,
23
+ },
24
+ ],
25
+ },
26
+ ],
27
+ },
28
+ };
29
+
30
+ export const SEPTUM_PRE_WRITE_SCRIPT = `#!/usr/bin/env sh
31
+ # Septum 3-Gate Boundary Guard Pre-Write Hook
32
+ # Intercepts write_to_file and replace_file_content before disk mutation
33
+
34
+ ROOT_DIR="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
35
+ if [ ! -f "$ROOT_DIR/.septum/septum.db" ]; then
36
+ exit 0
37
+ fi
38
+
39
+ # Delegate directly to Septum's active 3-gate hook engine
40
+ if command -v bun >/dev/null 2>&1 && [ -f "$ROOT_DIR/bin/septum.ts" ]; then
41
+ exec bun run "$ROOT_DIR/bin/septum.ts" hook pre-write
42
+ elif command -v septum >/dev/null 2>&1; then
43
+ exec septum hook pre-write
44
+ elif [ -f "$ROOT_DIR/node_modules/.bin/septum" ]; then
45
+ exec "$ROOT_DIR/node_modules/.bin/septum" hook pre-write
46
+ elif command -v bunx >/dev/null 2>&1; then
47
+ exec bunx septum hook pre-write
48
+ fi
49
+
50
+ exit 0
51
+ `;
52
+
53
+ export const SEPTUM_POST_WRITE_SCRIPT = `#!/usr/bin/env sh
54
+ # Septum Automated Incremental Post-Write Hook
55
+ # Syncs modified AST into SQLite SSOT after file mutations
56
+
57
+ ROOT_DIR="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
58
+ if [ ! -f "$ROOT_DIR/.septum/septum.db" ]; then
59
+ exit 0
60
+ fi
61
+
62
+ # Trigger background incremental sync
63
+ if command -v bun >/dev/null 2>&1 && [ -f "$ROOT_DIR/bin/septum.ts" ]; then
64
+ bun run "$ROOT_DIR/bin/septum.ts" sync >/dev/null 2>&1 &
65
+ elif command -v septum >/dev/null 2>&1; then
66
+ septum sync >/dev/null 2>&1 &
67
+ elif [ -f "$ROOT_DIR/node_modules/.bin/septum" ]; then
68
+ "$ROOT_DIR/node_modules/.bin/septum" sync >/dev/null 2>&1 &
69
+ elif command -v bunx >/dev/null 2>&1; then
70
+ bunx septum sync >/dev/null 2>&1 &
71
+ fi
72
+
73
+ exit 0
74
+ `;
75
+