septum 0.1.7 → 0.1.8
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.md +36 -55
- package/package.json +3 -2
- package/src/cli/commands/check.ts +2 -0
- package/src/cli/commands/hook.ts +59 -12
- package/src/cli/commands/init.ts +440 -121
- package/src/cli/commands/sync.ts +27 -17
- package/src/cli/commands/topology.ts +89 -47
- package/src/cli/index.ts +5 -67
- package/src/cli/scaffold/harness-config.ts +697 -0
- package/src/cli/templates/hooks.ts +6 -6
- package/src/cli/templates/rules.ts +8 -8
- package/src/cli/templates/skill.ts +11 -18
- package/src/cli/ui/prompts.ts +122 -0
- package/src/core/boundary/staged-auditor.ts +5 -2
- package/src/core/database/client.ts +8 -0
- package/src/core/database/repositories/dependency.repository.ts +77 -13
- package/src/core/database/repositories/domain.repository.ts +86 -33
- package/src/core/database/repositories/symbol.repository.ts +128 -117
- package/src/core/database/repository.ts +17 -5
- package/src/core/database/schema.ts +1 -1
- package/src/core/discovery/topology-detector.ts +71 -19
- package/src/core/ingestion/pipeline.ts +228 -94
- package/src/core/parser/extractors/laravel-semantic.ts +9 -8
- package/src/core/parser/extractors/mcp-cli-semantic.ts +56 -16
- package/src/core/parser/extractors/nestjs-semantic.ts +3 -2
- package/src/core/parser/schema/providers/laravel-migration-provider.ts +4 -3
- package/src/core/parser/schema/providers/prisma-schema-provider.ts +2 -1
- package/src/core/resolver/call-graph-tracer.ts +4 -3
- package/src/core/resolver/path-resolver.ts +57 -4
- package/src/core/resources/ignore.ts +35 -0
- package/src/core/resources/limits.ts +14 -0
- package/src/core/resources/source-files.ts +62 -0
- package/src/core/resources/work-queue.ts +74 -0
- package/src/core/session/session-manager.ts +19 -6
- package/src/core/telemetry/telemetry.ts +12 -1
- package/src/core/topology/environment-detector.ts +21 -11
- package/src/mcp/schemas.ts +381 -8
- package/src/mcp/server.ts +321 -535
- package/src/mcp/tools/boundary.ts +17 -0
- package/src/mcp/tools/check-boundary.ts +83 -11
- package/src/mcp/tools/domain.ts +40 -0
- package/src/mcp/tools/feature.ts +67 -0
- package/src/mcp/tools/get-domain-catalog.ts +9 -6
- package/src/mcp/tools/get-environment-topology.ts +2 -2
- package/src/mcp/tools/get-feature-context.ts +9 -12
- package/src/mcp/tools/get-symbol-impact.ts +5 -2
- package/src/mcp/tools/get-symbol.ts +2 -1
- package/src/mcp/tools/locate-symbol.ts +3 -3
- package/src/mcp/tools/register-domain.ts +25 -9
- package/src/mcp/tools/register-feature.ts +34 -17
- package/src/mcp/tools/slice.ts +15 -0
- package/src/mcp/tools/symbol.ts +82 -0
- package/src/mcp/workspace-manager.ts +159 -0
- package/src/mcp/workspace-watcher.ts +202 -0
- package/src/types/index.ts +1 -0
- package/src/cli/commands/ingest.ts +0 -29
- package/src/cli/commands/locate.ts +0 -61
- package/src/cli/commands/query.ts +0 -104
- package/src/cli/commands/slice.ts +0 -50
package/src/cli/commands/sync.ts
CHANGED
|
@@ -1,31 +1,41 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
1
2
|
import { ConfigLoader } from "../../core/config/loader.ts";
|
|
2
3
|
import { SeptumDatabase } from "../../core/database/client.ts";
|
|
3
4
|
import { SeptumRepository } from "../../core/database/repository.ts";
|
|
4
5
|
import { IngestionPipeline } from "../../core/ingestion/pipeline.ts";
|
|
6
|
+
import { resolveWorkspaceRoot } from "../../core/resolver/path-resolver.ts";
|
|
5
7
|
|
|
6
8
|
export interface SyncCommandOptions {
|
|
7
9
|
json?: boolean;
|
|
10
|
+
workspaceRoot?: string;
|
|
11
|
+
dbPath?: string;
|
|
8
12
|
}
|
|
9
13
|
|
|
10
14
|
export async function handleSyncCommand(options: SyncCommandOptions = {}): Promise<void> {
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
+
const root = options.workspaceRoot || resolveWorkspaceRoot();
|
|
16
|
+
const config = ConfigLoader.load(options.dbPath, root);
|
|
17
|
+
const resolvedDbPath = options.dbPath
|
|
18
|
+
? (path.isAbsolute(options.dbPath) ? options.dbPath : path.join(root, options.dbPath))
|
|
19
|
+
: (path.isAbsolute(config.settings.db_path) ? config.settings.db_path : path.join(root, config.settings.db_path));
|
|
20
|
+
const db = new SeptumDatabase(resolvedDbPath);
|
|
21
|
+
try {
|
|
22
|
+
const repo = new SeptumRepository(db.raw);
|
|
23
|
+
const pipeline = new IngestionPipeline(repo, root);
|
|
15
24
|
|
|
16
|
-
|
|
25
|
+
const metrics = await pipeline.run(config);
|
|
17
26
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
if (options.json) {
|
|
28
|
+
console.log(JSON.stringify(metrics, null, 2));
|
|
29
|
+
} else {
|
|
30
|
+
console.log(
|
|
31
|
+
`[Septum Sync] Ingested in ${metrics.duration_ms.toFixed(0)}ms: ` +
|
|
32
|
+
`${metrics.files_updated} updated/added, ` +
|
|
33
|
+
`${metrics.files_skipped} unchanged, ` +
|
|
34
|
+
`${metrics.symbols_indexed} symbols, ` +
|
|
35
|
+
`${metrics.dependencies_indexed} deps.`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
} finally {
|
|
39
|
+
db.close();
|
|
28
40
|
}
|
|
29
|
-
|
|
30
|
-
db.close();
|
|
31
41
|
}
|
|
@@ -1,62 +1,103 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
1
2
|
import { SeptumDatabase } from "../../core/database/client.ts";
|
|
2
3
|
import { SeptumRepository } from "../../core/database/repository.ts";
|
|
3
4
|
import { EnvironmentDetector } from "../../core/topology/environment-detector.ts";
|
|
4
5
|
import type { EnvironmentLayer, TopologyNode } from "../../core/topology/types.ts";
|
|
5
6
|
|
|
7
|
+
const VALID_LAYERS = new Set<EnvironmentLayer>([
|
|
8
|
+
"edge",
|
|
9
|
+
"gateway",
|
|
10
|
+
"host",
|
|
11
|
+
"runtime",
|
|
12
|
+
"storage",
|
|
13
|
+
"telemetry",
|
|
14
|
+
]);
|
|
15
|
+
|
|
6
16
|
export async function handleTopologyCommand(
|
|
7
17
|
subcommand?: string,
|
|
8
18
|
arg1?: string,
|
|
9
19
|
arg2?: string,
|
|
10
20
|
arg3?: string,
|
|
11
|
-
arg4?: string
|
|
21
|
+
arg4?: string,
|
|
22
|
+
workspaceRoot?: string
|
|
12
23
|
): Promise<void> {
|
|
13
|
-
const
|
|
14
|
-
const db = new SeptumDatabase();
|
|
15
|
-
const repo = new SeptumRepository(db.raw);
|
|
24
|
+
const normalizedSub = subcommand?.trim().toLowerCase();
|
|
16
25
|
|
|
17
|
-
if (
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
// Fix: Preserve existing constraints instead of overwriting with empty array
|
|
21
|
-
const existing = repo.environment.getLayer(layer);
|
|
22
|
-
repo.environment.saveLayer({
|
|
23
|
-
layer,
|
|
24
|
-
platform,
|
|
25
|
-
canonical_tag: EnvironmentDetector.matchCanonicalTag(platform),
|
|
26
|
-
status: "VERIFIED",
|
|
27
|
-
detected_from: ["CLI Manual Resolution"],
|
|
28
|
-
constraints: existing?.constraints && existing.constraints.length > 0 ? existing.constraints : [
|
|
29
|
-
`Configured manually as '${platform}'.`
|
|
30
|
-
],
|
|
31
|
-
});
|
|
32
|
-
console.log(`[Septum Topology] Layer '${layer}' successfully verified as '${platform}' in SQLite SSOT.\n`);
|
|
33
|
-
} else if (subcommand === "add-node" && arg1 && arg2 && arg3) {
|
|
34
|
-
const nodeId = arg1;
|
|
35
|
-
const layer = arg2.toLowerCase() as EnvironmentLayer;
|
|
36
|
-
const platform = arg3;
|
|
37
|
-
const domainOrIp = arg4;
|
|
26
|
+
if (normalizedSub && normalizedSub !== "resolve" && normalizedSub !== "add-node" && normalizedSub !== "remove-node" && normalizedSub !== "clear") {
|
|
27
|
+
throw new Error(`Unknown topology subcommand: '${subcommand}'. Valid subcommands: resolve, add-node, remove-node, clear.`);
|
|
28
|
+
}
|
|
38
29
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
layer
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
} else if (
|
|
56
|
-
|
|
57
|
-
|
|
30
|
+
if (normalizedSub === "resolve") {
|
|
31
|
+
if (!arg1 || !arg2) {
|
|
32
|
+
throw new Error("Missing required arguments for 'topology resolve'. Usage: septum topology resolve <layer> <platform>");
|
|
33
|
+
}
|
|
34
|
+
const layerCandidate = arg1.trim().toLowerCase() as EnvironmentLayer;
|
|
35
|
+
if (!VALID_LAYERS.has(layerCandidate)) {
|
|
36
|
+
throw new Error(`Invalid environment layer '${arg1}'. Valid layers: ${Array.from(VALID_LAYERS).join(", ")}`);
|
|
37
|
+
}
|
|
38
|
+
} else if (normalizedSub === "add-node") {
|
|
39
|
+
if (!arg1 || !arg2 || !arg3) {
|
|
40
|
+
throw new Error("Missing required arguments for 'topology add-node'. Usage: septum topology add-node <id> <layer> <platform> [domain_or_ip]");
|
|
41
|
+
}
|
|
42
|
+
const layerCandidate = arg2.trim().toLowerCase() as EnvironmentLayer;
|
|
43
|
+
if (!VALID_LAYERS.has(layerCandidate)) {
|
|
44
|
+
throw new Error(`Invalid environment layer '${arg2}'. Valid layers: ${Array.from(VALID_LAYERS).join(", ")}`);
|
|
45
|
+
}
|
|
46
|
+
} else if (normalizedSub === "remove-node") {
|
|
47
|
+
if (!arg1) {
|
|
48
|
+
throw new Error("Missing required argument for 'topology remove-node'. Usage: septum topology remove-node <id>");
|
|
49
|
+
}
|
|
58
50
|
}
|
|
59
51
|
|
|
52
|
+
const cwd = workspaceRoot || process.cwd();
|
|
53
|
+
const dbPath = workspaceRoot ? join(workspaceRoot, ".septum/septum.db") : undefined;
|
|
54
|
+
const db = new SeptumDatabase(dbPath);
|
|
55
|
+
const repo = new SeptumRepository(db.raw);
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
if (normalizedSub === "resolve" && arg1 && arg2) {
|
|
59
|
+
const layer = arg1.trim().toLowerCase() as EnvironmentLayer;
|
|
60
|
+
const platform = arg2;
|
|
61
|
+
// Fix: Preserve existing constraints instead of overwriting with empty array
|
|
62
|
+
const existing = repo.environment.getLayer(layer);
|
|
63
|
+
repo.environment.saveLayer({
|
|
64
|
+
layer,
|
|
65
|
+
platform,
|
|
66
|
+
canonical_tag: EnvironmentDetector.matchCanonicalTag(platform),
|
|
67
|
+
status: "VERIFIED",
|
|
68
|
+
detected_from: ["CLI Manual Resolution"],
|
|
69
|
+
constraints: existing?.constraints && existing.constraints.length > 0 ? existing.constraints : [
|
|
70
|
+
`Configured manually as '${platform}'.`
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
console.log(`[Septum Topology] Layer '${layer}' successfully verified as '${platform}' in SQLite SSOT.\n`);
|
|
74
|
+
} else if (normalizedSub === "add-node" && arg1 && arg2 && arg3) {
|
|
75
|
+
const nodeId = arg1;
|
|
76
|
+
const layer = arg2.trim().toLowerCase() as EnvironmentLayer;
|
|
77
|
+
const platform = arg3;
|
|
78
|
+
const domainOrIp = arg4;
|
|
79
|
+
|
|
80
|
+
const node: TopologyNode = {
|
|
81
|
+
id: nodeId,
|
|
82
|
+
layer,
|
|
83
|
+
name: nodeId,
|
|
84
|
+
platform,
|
|
85
|
+
canonical_tag: EnvironmentDetector.matchCanonicalTag(platform),
|
|
86
|
+
domain_or_ip: domainOrIp,
|
|
87
|
+
status: "VERIFIED",
|
|
88
|
+
detected_from: ["CLI Manual Node Resolution"],
|
|
89
|
+
constraints: [`Node added manually with platform '${platform}'.`],
|
|
90
|
+
};
|
|
91
|
+
repo.environment.saveNode(node);
|
|
92
|
+
console.log(`[Septum Topology] Node '${nodeId}' (${layer.toUpperCase()}) added to distributed topology graph.\n`);
|
|
93
|
+
} else if (normalizedSub === "remove-node" && arg1) {
|
|
94
|
+
repo.environment.deleteNode(arg1);
|
|
95
|
+
console.log(`[Septum Topology] Node '${arg1}' removed from distributed topology graph.\n`);
|
|
96
|
+
} else if (normalizedSub === "clear") {
|
|
97
|
+
repo.environment.clearAll();
|
|
98
|
+
console.log("[Septum Topology] Cleared environment topology and nodes in SQLite SSOT.\n");
|
|
99
|
+
}
|
|
100
|
+
|
|
60
101
|
const topology = EnvironmentDetector.detect(cwd, repo);
|
|
61
102
|
|
|
62
103
|
console.log("================================================================================");
|
|
@@ -113,7 +154,8 @@ export async function handleTopologyCommand(
|
|
|
113
154
|
console.log(" septum topology add-node host:vps-worker host \"Ubuntu 24.04 (Dedicated Worker)\" 10.0.0.6");
|
|
114
155
|
}
|
|
115
156
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
157
|
+
console.log("================================================================================\n");
|
|
158
|
+
} finally {
|
|
159
|
+
db.close();
|
|
160
|
+
}
|
|
119
161
|
}
|
package/src/cli/index.ts
CHANGED
|
@@ -3,13 +3,9 @@ import { SessionManager } from "../core/session/session-manager.ts";
|
|
|
3
3
|
import { SEPTUM_VERSION } from "../version.ts";
|
|
4
4
|
import { handleCheckCommand } from "./commands/check.ts";
|
|
5
5
|
import { handleHookCommand } from "./commands/hook.ts";
|
|
6
|
-
import { handleIngestCommand } from "./commands/ingest.ts";
|
|
7
6
|
import { handleInitCommand } from "./commands/init.ts";
|
|
8
7
|
import { handleTopologyCommand } from "./commands/topology.ts";
|
|
9
|
-
import { handleLocateCommand } from "./commands/locate.ts";
|
|
10
|
-
import { handleQueryCommand } from "./commands/query.ts";
|
|
11
8
|
import { handleServeCommand } from "./commands/serve.ts";
|
|
12
|
-
import { handleSliceCommand } from "./commands/slice.ts";
|
|
13
9
|
import { handleSyncCommand } from "./commands/sync.ts";
|
|
14
10
|
|
|
15
11
|
export async function runCLI(argv: string[]): Promise<void> {
|
|
@@ -22,13 +18,8 @@ export async function runCLI(argv: string[]): Promise<void> {
|
|
|
22
18
|
version: { type: "boolean", short: "v" },
|
|
23
19
|
force: { type: "boolean", short: "f" },
|
|
24
20
|
json: { type: "boolean" },
|
|
25
|
-
full: { type: "boolean" },
|
|
26
|
-
file: { type: "string" },
|
|
27
21
|
strict: { type: "boolean" },
|
|
28
22
|
staged: { type: "boolean" },
|
|
29
|
-
domain: { type: "string", short: "d" },
|
|
30
|
-
"max-depth": { type: "string" },
|
|
31
|
-
archetype: { type: "string", short: "a" },
|
|
32
23
|
feature: { type: "string" },
|
|
33
24
|
},
|
|
34
25
|
allowPositionals: true,
|
|
@@ -61,55 +52,12 @@ export async function runCLI(argv: string[]): Promise<void> {
|
|
|
61
52
|
break;
|
|
62
53
|
}
|
|
63
54
|
|
|
64
|
-
case "ingest": {
|
|
65
|
-
await handleIngestCommand();
|
|
66
|
-
break;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
55
|
case "sync": {
|
|
70
56
|
const json = Boolean(flags.json);
|
|
71
57
|
await handleSyncCommand({ json });
|
|
72
58
|
break;
|
|
73
59
|
}
|
|
74
60
|
|
|
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
61
|
case "check": {
|
|
114
62
|
const strict = Boolean(flags.strict);
|
|
115
63
|
const staged = Boolean(flags.staged);
|
|
@@ -184,30 +132,21 @@ USAGE:
|
|
|
184
132
|
septum [flags]
|
|
185
133
|
|
|
186
134
|
COMMANDS:
|
|
187
|
-
|
|
135
|
+
Core Lifecycle & Indexing:
|
|
188
136
|
init Initialize configuration, gitignore, pre-commit hook, and catalog
|
|
189
|
-
Flags: -f, --force
|
|
190
|
-
|
|
191
|
-
sync Incremental fast synchronization of modified files
|
|
137
|
+
Flags: -f, --force (regenerate Septum-owned hooks & harness artifacts; preserves DB, domain policies, and user hooks)
|
|
138
|
+
sync Codebase AST synchronization and catalog update (full or incremental)
|
|
192
139
|
Flags: --json
|
|
193
140
|
|
|
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
141
|
Boundary & Enforcement:
|
|
203
142
|
check Audit codebase for cross-domain boundary violations
|
|
204
|
-
Flags: --strict, --staged, --feature <name
|
|
143
|
+
Flags: --strict, --staged, --feature <name>, --json
|
|
205
144
|
feature [status|clear] View or release active feature context session lock
|
|
206
145
|
Flags: --force (explicit recovery of another owner's session)
|
|
207
146
|
hook [subhook] Internal pre-tool guardrail hook (e.g. pre-write)
|
|
208
147
|
|
|
209
148
|
Environment & Topology:
|
|
210
|
-
topology [action]
|
|
149
|
+
topology, env [action] Inspect 6-layer environment topology & distributed nodes
|
|
211
150
|
Subcommands: resolve <layer> <platform>, add-node, remove-node, clear
|
|
212
151
|
|
|
213
152
|
Daemon & Protocol:
|
|
@@ -216,6 +155,5 @@ COMMANDS:
|
|
|
216
155
|
GLOBAL FLAGS:
|
|
217
156
|
-h, --help Show this help message
|
|
218
157
|
-v, --version Show current version
|
|
219
|
-
--json Output formatted JSON metrics / results
|
|
220
158
|
`);
|
|
221
159
|
}
|