@rkarim08/sia 1.0.0
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/.claude-plugin/marketplace.json +35 -0
- package/.claude-plugin/plugin.json +27 -0
- package/.mcp.json +13 -0
- package/CLAUDE.md +226 -0
- package/LICENSE +202 -0
- package/PLUGIN_README.md +253 -0
- package/README.md +1013 -0
- package/agents/sia-changelog-writer.md +89 -0
- package/agents/sia-code-reviewer.md +86 -0
- package/agents/sia-conflict-resolver.md +100 -0
- package/agents/sia-convention-enforcer.md +69 -0
- package/agents/sia-debug.md +106 -0
- package/agents/sia-decision-reviewer.md +101 -0
- package/agents/sia-dependency-tracker.md +80 -0
- package/agents/sia-explain.md +126 -0
- package/agents/sia-feature.md +116 -0
- package/agents/sia-knowledge-capture.md +117 -0
- package/agents/sia-lead-architecture-advisor.md +93 -0
- package/agents/sia-lead-team-health.md +107 -0
- package/agents/sia-migration.md +100 -0
- package/agents/sia-onboarding.md +115 -0
- package/agents/sia-orientation.md +99 -0
- package/agents/sia-pm-briefing.md +106 -0
- package/agents/sia-pm-risk-advisor.md +82 -0
- package/agents/sia-qa-analyst.md +116 -0
- package/agents/sia-qa-regression-map.md +94 -0
- package/agents/sia-refactor.md +115 -0
- package/agents/sia-regression.md +112 -0
- package/agents/sia-security-audit.md +125 -0
- package/agents/sia-test-advisor.md +91 -0
- package/hooks/hooks.json +98 -0
- package/migrations/bridge/001_initial.sql +34 -0
- package/migrations/episodic/001_initial.sql +35 -0
- package/migrations/meta/001_initial.sql +68 -0
- package/migrations/semantic/001_initial.sql +292 -0
- package/migrations/semantic/002_ontology.sql +89 -0
- package/migrations/semantic/003_freshness.sql +63 -0
- package/migrations/semantic/004_v5_unified_schema.sql +194 -0
- package/migrations/semantic/005_backfill_event_kinds.sql +8 -0
- package/migrations/semantic/006_tree_sitter.sql +6 -0
- package/migrations/semantic/007_branch_snapshots.sql +22 -0
- package/package.json +110 -0
- package/scripts/branch-switch.sh +13 -0
- package/scripts/build-wasm-grammars.sh +81 -0
- package/scripts/post-compact.sh +8 -0
- package/scripts/post-tool-use.sh +10 -0
- package/scripts/pre-compact.sh +8 -0
- package/scripts/session-end.sh +8 -0
- package/scripts/session-start.sh +8 -0
- package/scripts/start-mcp.ts +45 -0
- package/scripts/stop-hook.sh +8 -0
- package/scripts/user-prompt-submit.sh +8 -0
- package/scripts/viz-server.ts +152 -0
- package/skills/sia-brainstorm/SKILL.md +156 -0
- package/skills/sia-brainstorm/scripts/frame-template.html +214 -0
- package/skills/sia-brainstorm/scripts/helper.js +95 -0
- package/skills/sia-brainstorm/scripts/server.cjs +338 -0
- package/skills/sia-brainstorm/scripts/start-server.sh +153 -0
- package/skills/sia-brainstorm/scripts/stop-server.sh +55 -0
- package/skills/sia-brainstorm/spec-document-reviewer-prompt.md +49 -0
- package/skills/sia-brainstorm/visual-companion.md +286 -0
- package/skills/sia-capture/SKILL.md +64 -0
- package/skills/sia-compare/SKILL.md +33 -0
- package/skills/sia-conflicts/SKILL.md +38 -0
- package/skills/sia-debug-workflow/SKILL.md +120 -0
- package/skills/sia-debug-workflow/root-cause-tracing.md +70 -0
- package/skills/sia-debug-workflow/scripts/find-polluter.sh +64 -0
- package/skills/sia-debug-workflow/temporal-investigation.md +72 -0
- package/skills/sia-digest/SKILL.md +23 -0
- package/skills/sia-dispatch/SKILL.md +69 -0
- package/skills/sia-dispatch/agent-task-template.md +99 -0
- package/skills/sia-doctor/SKILL.md +39 -0
- package/skills/sia-execute/SKILL.md +70 -0
- package/skills/sia-execute-plan/SKILL.md +85 -0
- package/skills/sia-export-import/SKILL.md +49 -0
- package/skills/sia-export-knowledge/SKILL.md +46 -0
- package/skills/sia-finish/SKILL.md +100 -0
- package/skills/sia-finish/pr-summary-template.md +54 -0
- package/skills/sia-freshness/SKILL.md +38 -0
- package/skills/sia-history/SKILL.md +42 -0
- package/skills/sia-impact/SKILL.md +70 -0
- package/skills/sia-index/SKILL.md +54 -0
- package/skills/sia-install/SKILL.md +39 -0
- package/skills/sia-lead-compliance/SKILL.md +16 -0
- package/skills/sia-lead-drift-report/SKILL.md +16 -0
- package/skills/sia-lead-knowledge-map/SKILL.md +16 -0
- package/skills/sia-learn/SKILL.md +58 -0
- package/skills/sia-plan/SKILL.md +68 -0
- package/skills/sia-plan/plan-reviewer-prompt.md +63 -0
- package/skills/sia-playbooks/SKILL.md +29 -0
- package/skills/sia-playbooks/reference-feature.md +100 -0
- package/skills/sia-playbooks/reference-flagging.md +50 -0
- package/skills/sia-playbooks/reference-orientation.md +92 -0
- package/skills/sia-playbooks/reference-regression.md +115 -0
- package/skills/sia-playbooks/reference-review.md +64 -0
- package/skills/sia-playbooks/reference-tools.md +239 -0
- package/skills/sia-pm-decision-log/SKILL.md +28 -0
- package/skills/sia-pm-risk-dashboard/SKILL.md +24 -0
- package/skills/sia-pm-sprint-summary/SKILL.md +27 -0
- package/skills/sia-prune/SKILL.md +45 -0
- package/skills/sia-qa-coverage/SKILL.md +28 -0
- package/skills/sia-qa-flaky/SKILL.md +20 -0
- package/skills/sia-qa-report/SKILL.md +26 -0
- package/skills/sia-reindex/SKILL.md +30 -0
- package/skills/sia-review-respond/SKILL.md +88 -0
- package/skills/sia-review-respond/pushback-patterns.md +90 -0
- package/skills/sia-search/SKILL.md +47 -0
- package/skills/sia-setup/SKILL.md +82 -0
- package/skills/sia-setup/setup-checklist.md +97 -0
- package/skills/sia-stats/SKILL.md +36 -0
- package/skills/sia-status/SKILL.md +44 -0
- package/skills/sia-sync/SKILL.md +46 -0
- package/skills/sia-team/SKILL.md +64 -0
- package/skills/sia-test/SKILL.md +92 -0
- package/skills/sia-test/testing-anti-patterns.md +104 -0
- package/skills/sia-tour/SKILL.md +29 -0
- package/skills/sia-upgrade/SKILL.md +43 -0
- package/skills/sia-verify/SKILL.md +81 -0
- package/skills/sia-visualize/SKILL.md +28 -0
- package/skills/sia-visualize-live/SKILL.md +55 -0
- package/skills/sia-visualize-live/scripts/graph-template.html +389 -0
- package/skills/sia-visualize-live/scripts/start-visualizer.sh +161 -0
- package/skills/sia-visualize-live/scripts/stop-visualizer.sh +55 -0
- package/skills/sia-visualize-live/scripts/visualizer-server.cjs +264 -0
- package/skills/sia-workspace/SKILL.md +57 -0
- package/src/agent/claude-md-template-flagging.md +219 -0
- package/src/agent/claude-md-template.md +213 -0
- package/src/agent/modules/sia-feature.md +100 -0
- package/src/agent/modules/sia-flagging.md +50 -0
- package/src/agent/modules/sia-orientation.md +92 -0
- package/src/agent/modules/sia-regression.md +115 -0
- package/src/agent/modules/sia-review.md +64 -0
- package/src/agent/modules/sia-tools.md +239 -0
- package/src/ast/extractors/c-include.ts +189 -0
- package/src/ast/extractors/csharp-project.ts +260 -0
- package/src/ast/extractors/prisma-schema.ts +44 -0
- package/src/ast/extractors/project-manifest.ts +111 -0
- package/src/ast/extractors/sql-schema.ts +67 -0
- package/src/ast/extractors/tier-a.ts +423 -0
- package/src/ast/extractors/tier-b.ts +289 -0
- package/src/ast/extractors/tier-dispatch.ts +247 -0
- package/src/ast/index-worker.ts +108 -0
- package/src/ast/indexer.ts +484 -0
- package/src/ast/languages.ts +408 -0
- package/src/ast/pagerank-builder.ts +125 -0
- package/src/ast/path-utils.ts +137 -0
- package/src/ast/tree-sitter/backends/native.ts +57 -0
- package/src/ast/tree-sitter/backends/wasm.ts +39 -0
- package/src/ast/tree-sitter/call-walker.ts +44 -0
- package/src/ast/tree-sitter/edit-computer.ts +55 -0
- package/src/ast/tree-sitter/query-runner.ts +46 -0
- package/src/ast/tree-sitter/service.ts +174 -0
- package/src/ast/tree-sitter/tree-cache.ts +39 -0
- package/src/ast/tree-sitter/types.ts +79 -0
- package/src/ast/watcher.ts +322 -0
- package/src/capture/chunker.ts +169 -0
- package/src/capture/consolidate.ts +127 -0
- package/src/capture/edge-inferrer.ts +161 -0
- package/src/capture/embedder.ts +166 -0
- package/src/capture/embedding-cache.ts +73 -0
- package/src/capture/flag-processor.ts +64 -0
- package/src/capture/hook.ts +67 -0
- package/src/capture/pipeline.ts +450 -0
- package/src/capture/prompts/consolidate.ts +25 -0
- package/src/capture/prompts/edge-infer.ts +29 -0
- package/src/capture/prompts/extract-flagged.ts +36 -0
- package/src/capture/prompts/extract.ts +42 -0
- package/src/capture/tokenizer.ts +147 -0
- package/src/capture/track-a-ast.ts +93 -0
- package/src/capture/track-b-llm.ts +149 -0
- package/src/capture/types.ts +64 -0
- package/src/cli/commands/community.ts +137 -0
- package/src/cli/commands/compare.ts +123 -0
- package/src/cli/commands/conflicts.ts +41 -0
- package/src/cli/commands/digest.ts +197 -0
- package/src/cli/commands/disable-flagging.ts +34 -0
- package/src/cli/commands/doctor.ts +240 -0
- package/src/cli/commands/download-model.ts +161 -0
- package/src/cli/commands/enable-flagging.ts +34 -0
- package/src/cli/commands/export-knowledge.ts +208 -0
- package/src/cli/commands/export.ts +85 -0
- package/src/cli/commands/freshness.ts +164 -0
- package/src/cli/commands/graph.ts +51 -0
- package/src/cli/commands/history.ts +139 -0
- package/src/cli/commands/import.ts +335 -0
- package/src/cli/commands/install.ts +156 -0
- package/src/cli/commands/lead-report.ts +241 -0
- package/src/cli/commands/learn.ts +321 -0
- package/src/cli/commands/pm-report.ts +413 -0
- package/src/cli/commands/prune.ts +75 -0
- package/src/cli/commands/qa-report.ts +278 -0
- package/src/cli/commands/reindex.ts +104 -0
- package/src/cli/commands/rollback.ts +70 -0
- package/src/cli/commands/search.ts +103 -0
- package/src/cli/commands/server.ts +91 -0
- package/src/cli/commands/share.ts +33 -0
- package/src/cli/commands/stats.ts +79 -0
- package/src/cli/commands/status.ts +176 -0
- package/src/cli/commands/sync.ts +96 -0
- package/src/cli/commands/team.ts +118 -0
- package/src/cli/commands/tour.ts +157 -0
- package/src/cli/commands/visualize-live.ts +162 -0
- package/src/cli/commands/workspace.ts +117 -0
- package/src/cli/index.ts +424 -0
- package/src/cli/learn-progress.ts +87 -0
- package/src/community/detection-bridge.ts +344 -0
- package/src/community/leiden.ts +462 -0
- package/src/community/raptor.ts +210 -0
- package/src/community/scheduler.ts +74 -0
- package/src/community/summarize.ts +115 -0
- package/src/decay/archiver.ts +73 -0
- package/src/decay/bridge-orphan-cleanup.ts +212 -0
- package/src/decay/consolidation-sweep.ts +112 -0
- package/src/decay/decay.ts +116 -0
- package/src/decay/deep-validator.ts +62 -0
- package/src/decay/episodic-promoter.ts +132 -0
- package/src/decay/maintenance-scheduler.ts +326 -0
- package/src/decay/scheduler.ts +6 -0
- package/src/decay/session-sweeper.ts +79 -0
- package/src/decay/types.ts +17 -0
- package/src/freshness/confidence-decay.ts +122 -0
- package/src/freshness/cuckoo-filter.ts +176 -0
- package/src/freshness/deep-validation.ts +345 -0
- package/src/freshness/dirty-tracker.ts +237 -0
- package/src/freshness/file-watcher-layer.ts +119 -0
- package/src/freshness/firewall.ts +64 -0
- package/src/freshness/git-reconcile-layer.ts +161 -0
- package/src/freshness/inverted-index.ts +158 -0
- package/src/freshness/stale-read-layer.ts +222 -0
- package/src/graph/audit.ts +69 -0
- package/src/graph/bridge-db.ts +141 -0
- package/src/graph/communities.ts +195 -0
- package/src/graph/db-interface.ts +259 -0
- package/src/graph/edges.ts +163 -0
- package/src/graph/entities.ts +327 -0
- package/src/graph/episodic-db.ts +113 -0
- package/src/graph/flags.ts +31 -0
- package/src/graph/meta-db.ts +200 -0
- package/src/graph/semantic-db.ts +101 -0
- package/src/graph/session-resume.ts +56 -0
- package/src/graph/snapshots.ts +342 -0
- package/src/graph/staging.ts +151 -0
- package/src/graph/types.ts +128 -0
- package/src/hooks/adapters/claude-code.ts +21 -0
- package/src/hooks/adapters/cline.ts +43 -0
- package/src/hooks/adapters/cursor.ts +65 -0
- package/src/hooks/adapters/generic.ts +12 -0
- package/src/hooks/agent-detect.ts +34 -0
- package/src/hooks/claude-md-directives.ts +32 -0
- package/src/hooks/event-router.ts +182 -0
- package/src/hooks/extractors/pattern-detector.ts +111 -0
- package/src/hooks/handlers/post-compact.ts +30 -0
- package/src/hooks/handlers/post-tool-use.ts +403 -0
- package/src/hooks/handlers/pre-compact.ts +100 -0
- package/src/hooks/handlers/session-end.ts +47 -0
- package/src/hooks/handlers/session-start.ts +154 -0
- package/src/hooks/handlers/stop.ts +128 -0
- package/src/hooks/handlers/user-prompt-submit.ts +68 -0
- package/src/hooks/plugin-branch-switch.ts +68 -0
- package/src/hooks/plugin-common.ts +47 -0
- package/src/hooks/plugin-post-compact.ts +28 -0
- package/src/hooks/plugin-post-tool-use.ts +38 -0
- package/src/hooks/plugin-pre-compact.ts +37 -0
- package/src/hooks/plugin-session-end.ts +37 -0
- package/src/hooks/plugin-session-start.ts +75 -0
- package/src/hooks/plugin-stop.ts +61 -0
- package/src/hooks/plugin-user-prompt-submit.ts +47 -0
- package/src/hooks/types.ts +43 -0
- package/src/knowledge/discovery.ts +238 -0
- package/src/knowledge/external-refs.ts +98 -0
- package/src/knowledge/freshness.ts +221 -0
- package/src/knowledge/ingest.ts +330 -0
- package/src/knowledge/markdown-export.ts +229 -0
- package/src/knowledge/markdown-import.ts +359 -0
- package/src/knowledge/patterns.ts +74 -0
- package/src/knowledge/templates.ts +307 -0
- package/src/llm/ai-sdk-adapter.ts +46 -0
- package/src/llm/config.ts +88 -0
- package/src/llm/cost-tracker.ts +110 -0
- package/src/llm/prompts/extraction.ts +55 -0
- package/src/llm/prompts/summarization.ts +36 -0
- package/src/llm/prompts/validation.ts +37 -0
- package/src/llm/provider-registry.ts +68 -0
- package/src/llm/reliability.ts +179 -0
- package/src/llm/schemas.ts +52 -0
- package/src/mcp/freshness-annotator.ts +69 -0
- package/src/mcp/server.ts +949 -0
- package/src/mcp/tools/sia-ast-query.ts +225 -0
- package/src/mcp/tools/sia-at-time.ts +151 -0
- package/src/mcp/tools/sia-backlinks.ts +87 -0
- package/src/mcp/tools/sia-batch-execute.ts +169 -0
- package/src/mcp/tools/sia-by-file.ts +89 -0
- package/src/mcp/tools/sia-community.ts +113 -0
- package/src/mcp/tools/sia-doctor.ts +73 -0
- package/src/mcp/tools/sia-execute-file.ts +122 -0
- package/src/mcp/tools/sia-execute.ts +104 -0
- package/src/mcp/tools/sia-expand.ts +158 -0
- package/src/mcp/tools/sia-fetch-and-index.ts +241 -0
- package/src/mcp/tools/sia-flag.ts +65 -0
- package/src/mcp/tools/sia-index.ts +111 -0
- package/src/mcp/tools/sia-note.ts +134 -0
- package/src/mcp/tools/sia-search.ts +105 -0
- package/src/mcp/tools/sia-stats.ts +63 -0
- package/src/mcp/tools/sia-sync-status.ts +44 -0
- package/src/mcp/tools/sia-upgrade.ts +247 -0
- package/src/mcp/truncate.ts +231 -0
- package/src/native/bridge.ts +167 -0
- package/src/native/fallback-ast-diff.ts +144 -0
- package/src/native/fallback-graph.ts +325 -0
- package/src/ontology/constraints.ts +56 -0
- package/src/ontology/errors.ts +8 -0
- package/src/ontology/middleware.ts +266 -0
- package/src/retrieval/bm25-search.ts +151 -0
- package/src/retrieval/context-assembly.ts +76 -0
- package/src/retrieval/graph-traversal.ts +168 -0
- package/src/retrieval/pagerank.ts +40 -0
- package/src/retrieval/query-classifier.ts +106 -0
- package/src/retrieval/reranker.ts +156 -0
- package/src/retrieval/search.ts +236 -0
- package/src/retrieval/throttle.ts +102 -0
- package/src/retrieval/vector-search.ts +203 -0
- package/src/retrieval/workspace-search.ts +130 -0
- package/src/sandbox/context-mode.ts +285 -0
- package/src/sandbox/credential-pass.ts +55 -0
- package/src/sandbox/executor.ts +235 -0
- package/src/security/pattern-detector.ts +127 -0
- package/src/security/rule-of-two.ts +50 -0
- package/src/security/sanitize.ts +46 -0
- package/src/security/semantic-consistency.ts +93 -0
- package/src/security/staging-promoter.ts +154 -0
- package/src/shared/config.ts +302 -0
- package/src/shared/diagnostics.ts +210 -0
- package/src/shared/errors.ts +48 -0
- package/src/shared/git-utils.ts +143 -0
- package/src/shared/llm-client.ts +120 -0
- package/src/shared/logger.ts +99 -0
- package/src/shared/types.ts +79 -0
- package/src/sync/client.ts +43 -0
- package/src/sync/conflict.ts +106 -0
- package/src/sync/dedup.ts +183 -0
- package/src/sync/hlc.ts +117 -0
- package/src/sync/keychain.ts +144 -0
- package/src/sync/pull.ts +232 -0
- package/src/sync/push.ts +131 -0
- package/src/types/chokidar.d.ts +23 -0
- package/src/visualization/graph-renderer.ts +312 -0
- package/src/visualization/subgraph-extract.ts +208 -0
- package/src/visualization/views/community-clusters.ts +246 -0
- package/src/visualization/views/dependency-map.ts +189 -0
- package/src/visualization/views/graph-explorer.ts +364 -0
- package/src/visualization/views/timeline.ts +247 -0
- package/src/workspace/api-contracts.ts +226 -0
- package/src/workspace/cross-repo.ts +61 -0
- package/src/workspace/detector.ts +190 -0
- package/src/workspace/manifest.ts +141 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
// Module: sia-ast-query — MCP tool handler for tree-sitter AST queries
|
|
2
|
+
//
|
|
3
|
+
// Parses a file with tree-sitter and runs a query (symbols, imports, calls)
|
|
4
|
+
// against the AST. Returns structured results with bounded output.
|
|
5
|
+
|
|
6
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
7
|
+
import { dirname, join, resolve } from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { getLanguageForFile, resolveLanguageConfig } from "@/ast/languages";
|
|
10
|
+
import { TreeSitterService } from "@/ast/tree-sitter/service";
|
|
11
|
+
import type { SiaQueryMatch } from "@/ast/tree-sitter/types";
|
|
12
|
+
import type { TreeSitterConfig } from "@/shared/config";
|
|
13
|
+
|
|
14
|
+
export interface SiaAstQueryInput {
|
|
15
|
+
file_path: string;
|
|
16
|
+
query_type: "symbols" | "imports" | "calls";
|
|
17
|
+
max_results?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface AstSymbol {
|
|
21
|
+
name: string;
|
|
22
|
+
kind: string;
|
|
23
|
+
line: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface SiaAstQueryResult {
|
|
27
|
+
file_path: string;
|
|
28
|
+
language?: string;
|
|
29
|
+
symbols?: AstSymbol[];
|
|
30
|
+
imports?: string[];
|
|
31
|
+
calls?: string[];
|
|
32
|
+
error?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const MAX_RESULTS = 100;
|
|
36
|
+
// Resolve grammars relative to the package root, not process.cwd()
|
|
37
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
38
|
+
const GRAMMARS_DIR = join(__dirname, "../../..", "grammars", "queries");
|
|
39
|
+
|
|
40
|
+
const DEFAULT_TS_CONFIG: TreeSitterConfig = {
|
|
41
|
+
enabled: true,
|
|
42
|
+
preferNative: true,
|
|
43
|
+
parseTimeoutMs: 5000,
|
|
44
|
+
maxCachedTrees: 50,
|
|
45
|
+
wasmDir: "",
|
|
46
|
+
queryDir: "",
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Singleton service — avoids re-initialization on every call
|
|
50
|
+
let serviceInstance: TreeSitterService | null = null;
|
|
51
|
+
|
|
52
|
+
async function getService(): Promise<TreeSitterService> {
|
|
53
|
+
if (!serviceInstance) {
|
|
54
|
+
serviceInstance = new TreeSitterService(DEFAULT_TS_CONFIG);
|
|
55
|
+
await serviceInstance.initialize();
|
|
56
|
+
}
|
|
57
|
+
return serviceInstance;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Dispose the singleton service and allow re-initialization on next call. */
|
|
61
|
+
export function resetAstQueryService(): void {
|
|
62
|
+
if (serviceInstance) {
|
|
63
|
+
serviceInstance.dispose();
|
|
64
|
+
serviceInstance = null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Extract symbols from query matches. Symbols have @name and @kind captures.
|
|
70
|
+
*/
|
|
71
|
+
export function extractSymbols(matches: SiaQueryMatch[], maxResults: number): AstSymbol[] {
|
|
72
|
+
const symbols: AstSymbol[] = [];
|
|
73
|
+
for (const match of matches) {
|
|
74
|
+
if (symbols.length >= maxResults) break;
|
|
75
|
+
|
|
76
|
+
let name = "";
|
|
77
|
+
let kind = "";
|
|
78
|
+
let line = 0;
|
|
79
|
+
|
|
80
|
+
for (const cap of match.captures) {
|
|
81
|
+
if (cap.name === "name") {
|
|
82
|
+
name = cap.text;
|
|
83
|
+
line = cap.startPosition.row + 1;
|
|
84
|
+
} else if (cap.name === "kind" || cap.name === "definition") {
|
|
85
|
+
kind = cap.text;
|
|
86
|
+
line = line || cap.startPosition.row + 1;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Fall back to the first capture if no @name
|
|
91
|
+
if (!name && match.captures.length > 0) {
|
|
92
|
+
const first = match.captures[0];
|
|
93
|
+
name = first.text;
|
|
94
|
+
line = first.startPosition.row + 1;
|
|
95
|
+
kind = first.name;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (name) {
|
|
99
|
+
symbols.push({ name, kind, line });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return symbols;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Extract import paths from query matches. Imports have @source captures.
|
|
107
|
+
*/
|
|
108
|
+
export function extractImports(matches: SiaQueryMatch[], maxResults: number): string[] {
|
|
109
|
+
const imports: string[] = [];
|
|
110
|
+
for (const match of matches) {
|
|
111
|
+
if (imports.length >= maxResults) break;
|
|
112
|
+
|
|
113
|
+
for (const cap of match.captures) {
|
|
114
|
+
if (cap.name === "source" || cap.name === "path" || cap.name === "import") {
|
|
115
|
+
// Strip quotes from import paths
|
|
116
|
+
const cleaned = cap.text.replace(/^["']|["']$/g, "");
|
|
117
|
+
if (cleaned && !imports.includes(cleaned)) {
|
|
118
|
+
imports.push(cleaned);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return imports;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Extract call targets from query matches.
|
|
128
|
+
*/
|
|
129
|
+
export function extractCalls(matches: SiaQueryMatch[], maxResults: number): string[] {
|
|
130
|
+
const calls: string[] = [];
|
|
131
|
+
for (const match of matches) {
|
|
132
|
+
if (calls.length >= maxResults) break;
|
|
133
|
+
|
|
134
|
+
for (const cap of match.captures) {
|
|
135
|
+
if (cap.name === "name" || cap.name === "call" || cap.name === "function") {
|
|
136
|
+
if (cap.text && !calls.includes(cap.text)) {
|
|
137
|
+
calls.push(cap.text);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return calls;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Parse a file with tree-sitter and extract structured AST data.
|
|
147
|
+
*/
|
|
148
|
+
export async function handleSiaAstQuery(input: SiaAstQueryInput): Promise<SiaAstQueryResult> {
|
|
149
|
+
const cwd = process.cwd();
|
|
150
|
+
const filePath = resolve(cwd, input.file_path);
|
|
151
|
+
const maxResults = input.max_results ?? MAX_RESULTS;
|
|
152
|
+
|
|
153
|
+
// Prevent path traversal outside the project directory
|
|
154
|
+
if (!filePath.startsWith(`${cwd}/`) && filePath !== cwd) {
|
|
155
|
+
return { file_path: input.file_path, error: "Path must be within the project directory" };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!existsSync(filePath)) {
|
|
159
|
+
return { file_path: input.file_path, error: `File not found: ${input.file_path}` };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const langConfig = getLanguageForFile(input.file_path);
|
|
163
|
+
if (!langConfig) {
|
|
164
|
+
return { file_path: input.file_path, error: `Unsupported language for: ${input.file_path}` };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Check that the query file exists for this language + query type
|
|
168
|
+
const resolved = resolveLanguageConfig(langConfig);
|
|
169
|
+
const queryPath = join(GRAMMARS_DIR, resolved.queryDir, `${input.query_type}.scm`);
|
|
170
|
+
if (!existsSync(queryPath)) {
|
|
171
|
+
return {
|
|
172
|
+
file_path: input.file_path,
|
|
173
|
+
language: langConfig.name,
|
|
174
|
+
error: `No ${input.query_type} query available for ${langConfig.name}`,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
const service = await getService();
|
|
180
|
+
if (service.backend === "unavailable") {
|
|
181
|
+
return {
|
|
182
|
+
file_path: input.file_path,
|
|
183
|
+
language: langConfig.name,
|
|
184
|
+
error: "Tree-sitter not available (neither native nor WASM backend loaded)",
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const source = readFileSync(filePath, "utf-8");
|
|
189
|
+
const tree = await service.parse(source, langConfig.name);
|
|
190
|
+
if (!tree) {
|
|
191
|
+
return {
|
|
192
|
+
file_path: input.file_path,
|
|
193
|
+
language: langConfig.name,
|
|
194
|
+
error: `Failed to parse ${input.file_path}`,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const matches = service.query(tree, queryPath);
|
|
199
|
+
|
|
200
|
+
const result: SiaAstQueryResult = {
|
|
201
|
+
file_path: input.file_path,
|
|
202
|
+
language: langConfig.name,
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
switch (input.query_type) {
|
|
206
|
+
case "symbols":
|
|
207
|
+
result.symbols = extractSymbols(matches, maxResults);
|
|
208
|
+
break;
|
|
209
|
+
case "imports":
|
|
210
|
+
result.imports = extractImports(matches, maxResults);
|
|
211
|
+
break;
|
|
212
|
+
case "calls":
|
|
213
|
+
result.calls = extractCalls(matches, maxResults);
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return result;
|
|
218
|
+
} catch (err) {
|
|
219
|
+
return {
|
|
220
|
+
file_path: input.file_path,
|
|
221
|
+
language: langConfig.name,
|
|
222
|
+
error: `AST parse error: ${err instanceof Error ? err.message : String(err)}`,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// Module: sia-at-time — Bi-temporal query: entities and edges as-of a point in time
|
|
2
|
+
|
|
3
|
+
import type { z } from "zod";
|
|
4
|
+
import type { SiaDb } from "@/graph/db-interface";
|
|
5
|
+
import type { EdgeRow } from "@/graph/edges";
|
|
6
|
+
import type { Entity } from "@/graph/entities";
|
|
7
|
+
import type { SiaAtTimeInput as SiaAtTimeInputSchema } from "@/mcp/server";
|
|
8
|
+
|
|
9
|
+
export type SiaAtTimeInput = z.infer<typeof SiaAtTimeInputSchema>;
|
|
10
|
+
|
|
11
|
+
export interface SiaTemporalResult {
|
|
12
|
+
entities: Entity[];
|
|
13
|
+
invalidated_entities: Entity[];
|
|
14
|
+
invalidated_count: number;
|
|
15
|
+
edges: EdgeRow[];
|
|
16
|
+
edge_count: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Parse an `as_of` string into Unix milliseconds.
|
|
21
|
+
*
|
|
22
|
+
* Supports:
|
|
23
|
+
* - ISO 8601 strings (anything `new Date()` can parse)
|
|
24
|
+
* - Relative strings like "7 days ago", "3 months ago", "1 year ago"
|
|
25
|
+
*/
|
|
26
|
+
export function parseAsOf(asOf: string): number {
|
|
27
|
+
const relativePattern = /^(\d+)\s+(days?|weeks?|months?|years?)\s+ago$/i;
|
|
28
|
+
const match = asOf.trim().match(relativePattern);
|
|
29
|
+
|
|
30
|
+
if (match) {
|
|
31
|
+
const amount = Number.parseInt(match[1], 10);
|
|
32
|
+
const unit = match[2].toLowerCase().replace(/s$/, "");
|
|
33
|
+
const now = Date.now();
|
|
34
|
+
|
|
35
|
+
switch (unit) {
|
|
36
|
+
case "day":
|
|
37
|
+
return now - amount * 24 * 60 * 60 * 1000;
|
|
38
|
+
case "week":
|
|
39
|
+
return now - amount * 7 * 24 * 60 * 60 * 1000;
|
|
40
|
+
case "month":
|
|
41
|
+
return now - amount * 30 * 24 * 60 * 60 * 1000;
|
|
42
|
+
case "year":
|
|
43
|
+
return now - amount * 365 * 24 * 60 * 60 * 1000;
|
|
44
|
+
default:
|
|
45
|
+
throw new Error(`Unknown relative time unit: ${unit}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const parsed = new Date(asOf).getTime();
|
|
50
|
+
if (Number.isNaN(parsed)) {
|
|
51
|
+
throw new Error(`Cannot parse as_of timestamp: ${asOf}`);
|
|
52
|
+
}
|
|
53
|
+
return parsed;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Query the knowledge graph at a specific point in time.
|
|
58
|
+
*
|
|
59
|
+
* Returns entities that were active at `as_of`, entities that had been
|
|
60
|
+
* invalidated by that time, and edges that were active at that time.
|
|
61
|
+
*/
|
|
62
|
+
export async function handleSiaAtTime(
|
|
63
|
+
db: SiaDb,
|
|
64
|
+
input: SiaAtTimeInput,
|
|
65
|
+
): Promise<SiaTemporalResult> {
|
|
66
|
+
const asOfMs = parseAsOf(input.as_of);
|
|
67
|
+
const rawLimit = input.limit ?? 20;
|
|
68
|
+
const limit = Math.min(Math.max(rawLimit, 1), 50);
|
|
69
|
+
|
|
70
|
+
// --- Build WHERE filters for entity_types and tags ---
|
|
71
|
+
const entityFilters: string[] = [];
|
|
72
|
+
const entityParams: unknown[] = [];
|
|
73
|
+
|
|
74
|
+
if (input.entity_types && input.entity_types.length > 0) {
|
|
75
|
+
const placeholders = input.entity_types.map(() => "?").join(", ");
|
|
76
|
+
entityFilters.push(`type IN (${placeholders})`);
|
|
77
|
+
entityParams.push(...input.entity_types);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (input.tags && input.tags.length > 0) {
|
|
81
|
+
// Match any entity whose JSON tags array contains at least one of the requested tags.
|
|
82
|
+
// tags is stored as a JSON string array, e.g. '["auth","api"]'.
|
|
83
|
+
const tagClauses = input.tags.map(() => "tags LIKE ?");
|
|
84
|
+
entityFilters.push(`(${tagClauses.join(" OR ")})`);
|
|
85
|
+
for (const tag of input.tags) {
|
|
86
|
+
entityParams.push(`%${tag}%`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const extraWhere = entityFilters.length > 0 ? ` AND ${entityFilters.join(" AND ")}` : "";
|
|
91
|
+
|
|
92
|
+
// --- Active entities at as_of ---
|
|
93
|
+
const activeQuery = `
|
|
94
|
+
SELECT * FROM graph_nodes
|
|
95
|
+
WHERE (t_valid_from IS NULL OR t_valid_from <= ?)
|
|
96
|
+
AND (t_valid_until IS NULL OR t_valid_until > ?)
|
|
97
|
+
AND archived_at IS NULL
|
|
98
|
+
${extraWhere}
|
|
99
|
+
LIMIT ?
|
|
100
|
+
`;
|
|
101
|
+
const activeParams = [asOfMs, asOfMs, ...entityParams, limit];
|
|
102
|
+
const activeResult = await db.execute(activeQuery, activeParams);
|
|
103
|
+
const entities = activeResult.rows as unknown as Entity[];
|
|
104
|
+
|
|
105
|
+
// --- Invalidated entities: those whose t_valid_until <= as_of ---
|
|
106
|
+
const invalidatedCountQuery = `
|
|
107
|
+
SELECT COUNT(*) AS cnt FROM graph_nodes
|
|
108
|
+
WHERE t_valid_until IS NOT NULL AND t_valid_until <= ?
|
|
109
|
+
${extraWhere}
|
|
110
|
+
`;
|
|
111
|
+
const invalidatedCountParams = [asOfMs, ...entityParams];
|
|
112
|
+
const countResult = await db.execute(invalidatedCountQuery, invalidatedCountParams);
|
|
113
|
+
const invalidatedCount = (countResult.rows[0] as { cnt: number }).cnt;
|
|
114
|
+
|
|
115
|
+
const invalidatedQuery = `
|
|
116
|
+
SELECT * FROM graph_nodes
|
|
117
|
+
WHERE t_valid_until IS NOT NULL AND t_valid_until <= ?
|
|
118
|
+
${extraWhere}
|
|
119
|
+
ORDER BY t_valid_until DESC
|
|
120
|
+
LIMIT ?
|
|
121
|
+
`;
|
|
122
|
+
const invalidatedParams = [asOfMs, ...entityParams, limit];
|
|
123
|
+
const invalidatedResult = await db.execute(invalidatedQuery, invalidatedParams);
|
|
124
|
+
const invalidatedEntities = invalidatedResult.rows as unknown as Entity[];
|
|
125
|
+
|
|
126
|
+
// --- Edges active at as_of (global, not per-entity), capped at 50 ---
|
|
127
|
+
const edgesCountQuery = `
|
|
128
|
+
SELECT COUNT(*) AS cnt FROM graph_edges
|
|
129
|
+
WHERE (t_valid_from IS NULL OR t_valid_from <= ?)
|
|
130
|
+
AND (t_valid_until IS NULL OR t_valid_until > ?)
|
|
131
|
+
`;
|
|
132
|
+
const edgesCountResult = await db.execute(edgesCountQuery, [asOfMs, asOfMs]);
|
|
133
|
+
const edgeCount = (edgesCountResult.rows[0] as { cnt: number }).cnt;
|
|
134
|
+
|
|
135
|
+
const edgesQuery = `
|
|
136
|
+
SELECT * FROM graph_edges
|
|
137
|
+
WHERE (t_valid_from IS NULL OR t_valid_from <= ?)
|
|
138
|
+
AND (t_valid_until IS NULL OR t_valid_until > ?)
|
|
139
|
+
LIMIT 50
|
|
140
|
+
`;
|
|
141
|
+
const edgesResult = await db.execute(edgesQuery, [asOfMs, asOfMs]);
|
|
142
|
+
const edges = edgesResult.rows as unknown as EdgeRow[];
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
entities,
|
|
146
|
+
invalidated_entities: invalidatedEntities,
|
|
147
|
+
invalidated_count: invalidatedCount,
|
|
148
|
+
edges,
|
|
149
|
+
edge_count: edgeCount,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Module: sia-backlinks — Backlink traversal for knowledge graph nodes
|
|
2
|
+
|
|
3
|
+
import type { SiaDb } from "@/graph/db-interface";
|
|
4
|
+
|
|
5
|
+
export interface SiaBacklinksInput {
|
|
6
|
+
node_id: string;
|
|
7
|
+
edge_types?: string[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface BacklinkEntry {
|
|
11
|
+
id: string;
|
|
12
|
+
type: string;
|
|
13
|
+
name: string;
|
|
14
|
+
summary: string;
|
|
15
|
+
importance: number;
|
|
16
|
+
edge_type: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface SiaBacklinksResult {
|
|
20
|
+
target_id: string;
|
|
21
|
+
backlinks: Record<string, BacklinkEntry[]>; // grouped by edge_type
|
|
22
|
+
total_count: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Find all active incoming edges to a given node, grouped by edge type.
|
|
27
|
+
* Returns entities that reference the target node via active edges.
|
|
28
|
+
*
|
|
29
|
+
* Only considers edges where t_valid_until IS NULL (active edges) and
|
|
30
|
+
* source entities that are neither invalidated nor archived.
|
|
31
|
+
*/
|
|
32
|
+
export async function handleSiaBacklinks(
|
|
33
|
+
db: SiaDb,
|
|
34
|
+
input: SiaBacklinksInput,
|
|
35
|
+
): Promise<SiaBacklinksResult> {
|
|
36
|
+
const params: unknown[] = [input.node_id];
|
|
37
|
+
|
|
38
|
+
let edgeTypeFilter = "";
|
|
39
|
+
if (input.edge_types && input.edge_types.length > 0) {
|
|
40
|
+
const placeholders = input.edge_types.map(() => "?").join(", ");
|
|
41
|
+
edgeTypeFilter = `AND e.type IN (${placeholders})`;
|
|
42
|
+
params.push(...input.edge_types);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const sql = `
|
|
46
|
+
SELECT
|
|
47
|
+
e.type AS edge_type,
|
|
48
|
+
ent.id, ent.type, ent.name, ent.summary, ent.importance
|
|
49
|
+
FROM graph_edges e
|
|
50
|
+
JOIN graph_nodes ent ON ent.id = e.from_id
|
|
51
|
+
WHERE e.to_id = ?
|
|
52
|
+
AND e.t_valid_until IS NULL
|
|
53
|
+
AND ent.t_valid_until IS NULL
|
|
54
|
+
AND ent.archived_at IS NULL
|
|
55
|
+
${edgeTypeFilter}
|
|
56
|
+
ORDER BY e.type, ent.importance DESC
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
const result = await db.execute(sql, params);
|
|
60
|
+
|
|
61
|
+
const backlinks: Record<string, BacklinkEntry[]> = {};
|
|
62
|
+
let totalCount = 0;
|
|
63
|
+
|
|
64
|
+
for (const row of result.rows) {
|
|
65
|
+
const edgeType = row.edge_type as string;
|
|
66
|
+
const entry: BacklinkEntry = {
|
|
67
|
+
id: row.id as string,
|
|
68
|
+
type: row.type as string,
|
|
69
|
+
name: row.name as string,
|
|
70
|
+
summary: row.summary as string,
|
|
71
|
+
importance: row.importance as number,
|
|
72
|
+
edge_type: edgeType,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
if (!backlinks[edgeType]) {
|
|
76
|
+
backlinks[edgeType] = [];
|
|
77
|
+
}
|
|
78
|
+
backlinks[edgeType].push(entry);
|
|
79
|
+
totalCount++;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
target_id: input.node_id,
|
|
84
|
+
backlinks,
|
|
85
|
+
total_count: totalCount,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// Module: sia-batch-execute — Execute multiple operations in one call with precedes edges
|
|
2
|
+
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import type { Embedder } from "@/capture/embedder";
|
|
6
|
+
import type { SiaDb } from "@/graph/db-interface";
|
|
7
|
+
import { insertEdge } from "@/graph/edges";
|
|
8
|
+
import type { ProgressiveThrottle } from "@/retrieval/throttle";
|
|
9
|
+
import { buildSandboxEnv } from "@/sandbox/credential-pass";
|
|
10
|
+
import { executeSubprocess } from "@/sandbox/executor";
|
|
11
|
+
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Input / Output types
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
const BatchOperation = z.union([
|
|
17
|
+
z.object({
|
|
18
|
+
type: z.literal("execute"),
|
|
19
|
+
code: z.string(),
|
|
20
|
+
language: z.string().optional(),
|
|
21
|
+
timeout: z.number().optional(),
|
|
22
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
23
|
+
}),
|
|
24
|
+
z.object({
|
|
25
|
+
type: z.literal("search"),
|
|
26
|
+
query: z.string(),
|
|
27
|
+
}),
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
export const SiaBatchExecuteInput = z.object({
|
|
31
|
+
operations: z.array(BatchOperation),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export interface OperationResult {
|
|
35
|
+
index: number;
|
|
36
|
+
type: string;
|
|
37
|
+
stdout?: string;
|
|
38
|
+
stderr?: string;
|
|
39
|
+
exitCode?: number | null;
|
|
40
|
+
error?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface SiaBatchExecuteResult {
|
|
44
|
+
results: OperationResult[];
|
|
45
|
+
eventNodeIds: string[];
|
|
46
|
+
contextSavings: number;
|
|
47
|
+
error?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const BATCH_MAX = 20;
|
|
51
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
52
|
+
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
// handleSiaBatchExecute
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
export async function handleSiaBatchExecute(
|
|
58
|
+
db: SiaDb,
|
|
59
|
+
input: z.infer<typeof SiaBatchExecuteInput>,
|
|
60
|
+
_embedder: Embedder,
|
|
61
|
+
throttle: ProgressiveThrottle,
|
|
62
|
+
sessionId: string,
|
|
63
|
+
config?: { timeoutPerOp?: number },
|
|
64
|
+
): Promise<SiaBatchExecuteResult> {
|
|
65
|
+
const { operations } = input;
|
|
66
|
+
|
|
67
|
+
// 1. Enforce batch size cap
|
|
68
|
+
if (operations.length > BATCH_MAX) {
|
|
69
|
+
return {
|
|
70
|
+
results: [],
|
|
71
|
+
eventNodeIds: [],
|
|
72
|
+
contextSavings: 0,
|
|
73
|
+
error: `Batch size ${operations.length} exceeds maximum of ${BATCH_MAX}`,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const timeoutPerOp = config?.timeoutPerOp ?? DEFAULT_TIMEOUT_MS;
|
|
78
|
+
const results: OperationResult[] = [];
|
|
79
|
+
const eventNodeIds: string[] = [];
|
|
80
|
+
const now = Date.now();
|
|
81
|
+
const nowStr = String(now);
|
|
82
|
+
|
|
83
|
+
// 2. Process each operation sequentially
|
|
84
|
+
for (let i = 0; i < operations.length; i++) {
|
|
85
|
+
const op = operations[i];
|
|
86
|
+
let opResult: OperationResult;
|
|
87
|
+
|
|
88
|
+
if (op.type === "execute") {
|
|
89
|
+
// Increment throttle counter for this execute op
|
|
90
|
+
await throttle.check(sessionId, "sia_execute");
|
|
91
|
+
|
|
92
|
+
const env = buildSandboxEnv(op.env);
|
|
93
|
+
try {
|
|
94
|
+
const subprocess = await executeSubprocess({
|
|
95
|
+
language: op.language,
|
|
96
|
+
code: op.code,
|
|
97
|
+
timeout: op.timeout ?? timeoutPerOp,
|
|
98
|
+
env,
|
|
99
|
+
});
|
|
100
|
+
opResult = {
|
|
101
|
+
index: i,
|
|
102
|
+
type: "execute",
|
|
103
|
+
stdout: subprocess.stdout,
|
|
104
|
+
stderr: subprocess.stderr || undefined,
|
|
105
|
+
exitCode: subprocess.exitCode,
|
|
106
|
+
};
|
|
107
|
+
} catch (err) {
|
|
108
|
+
opResult = {
|
|
109
|
+
index: i,
|
|
110
|
+
type: "execute",
|
|
111
|
+
error: err instanceof Error ? err.message : String(err),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
} else if (op.type === "search") {
|
|
115
|
+
opResult = {
|
|
116
|
+
index: i,
|
|
117
|
+
type: "search",
|
|
118
|
+
error: "Search not yet wired",
|
|
119
|
+
};
|
|
120
|
+
} else {
|
|
121
|
+
opResult = {
|
|
122
|
+
index: i,
|
|
123
|
+
type: (op as { type: string }).type,
|
|
124
|
+
error: "Invalid operation",
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
results.push(opResult);
|
|
129
|
+
|
|
130
|
+
// 3. Create an EventNode for this operation
|
|
131
|
+
try {
|
|
132
|
+
const nodeId = randomUUID();
|
|
133
|
+
await db.execute(
|
|
134
|
+
`INSERT INTO graph_nodes (id, type, name, summary, content, trust_tier, confidence, base_confidence, importance, base_importance, access_count, edge_count, tags, file_paths, t_created, t_valid_from, created_by, created_at, last_accessed)
|
|
135
|
+
VALUES (?, 'EventNode', ?, ?, ?, 3, 0.8, 0.8, 0.5, 0.5, 0, 0, '[]', '[]', ?, ?, 'sia-batch-execute', ?, ?)`,
|
|
136
|
+
[
|
|
137
|
+
nodeId,
|
|
138
|
+
`batch-op-${sessionId}-${i}`,
|
|
139
|
+
`Batch operation ${i} (${op.type})`,
|
|
140
|
+
JSON.stringify(opResult),
|
|
141
|
+
nowStr,
|
|
142
|
+
nowStr,
|
|
143
|
+
nowStr,
|
|
144
|
+
nowStr,
|
|
145
|
+
],
|
|
146
|
+
);
|
|
147
|
+
eventNodeIds.push(nodeId);
|
|
148
|
+
if (i > 0 && eventNodeIds[i - 1]) {
|
|
149
|
+
await insertEdge(db, {
|
|
150
|
+
from_id: eventNodeIds[i - 1],
|
|
151
|
+
to_id: nodeId,
|
|
152
|
+
type: "precedes",
|
|
153
|
+
weight: 1.0,
|
|
154
|
+
confidence: 1.0,
|
|
155
|
+
trust_tier: 3,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
} catch (dbErr) {
|
|
159
|
+
// Record failed but execution result is still valid
|
|
160
|
+
console.error("[sia-batch] EventNode creation failed:", (dbErr as Error).message);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
results,
|
|
166
|
+
eventNodeIds,
|
|
167
|
+
contextSavings: 0,
|
|
168
|
+
};
|
|
169
|
+
}
|