@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,450 @@
|
|
|
1
|
+
// Module: pipeline — End-to-end capture pipeline orchestration
|
|
2
|
+
//
|
|
3
|
+
// Wires together: chunker -> Track A + Track B -> consolidation -> edge inference -> flag processing.
|
|
4
|
+
// Includes circuit breaker for consolidation failures and global timeout.
|
|
5
|
+
|
|
6
|
+
import { randomUUID } from "node:crypto";
|
|
7
|
+
import { chunkPayload } from "@/capture/chunker";
|
|
8
|
+
import { consolidate } from "@/capture/consolidate";
|
|
9
|
+
import { inferEdges } from "@/capture/edge-inferrer";
|
|
10
|
+
import { processFlags } from "@/capture/flag-processor";
|
|
11
|
+
import { resolveRepoHash } from "@/capture/hook";
|
|
12
|
+
import { extractTrackA } from "@/capture/track-a-ast";
|
|
13
|
+
import { extractTrackB } from "@/capture/track-b-llm";
|
|
14
|
+
import type {
|
|
15
|
+
CandidateFact,
|
|
16
|
+
ConsolidationResult,
|
|
17
|
+
HookPayload,
|
|
18
|
+
PipelineResult,
|
|
19
|
+
} from "@/capture/types";
|
|
20
|
+
import { writeAuditEntry } from "@/graph/audit";
|
|
21
|
+
import { insertCrossRepoEdge, openBridgeDb } from "@/graph/bridge-db";
|
|
22
|
+
import type { SiaDb } from "@/graph/db-interface";
|
|
23
|
+
import { insertEntity, updateEntity } from "@/graph/entities";
|
|
24
|
+
import { openEpisodicDb, openGraphDb } from "@/graph/semantic-db";
|
|
25
|
+
import { insertStagedFact } from "@/graph/staging";
|
|
26
|
+
import { getConfig, type SiaConfig } from "@/shared/config";
|
|
27
|
+
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Types
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
export interface PipelineOpts {
|
|
33
|
+
siaHome?: string;
|
|
34
|
+
config?: SiaConfig;
|
|
35
|
+
/** Optional meta.db handle for sharing rules enforcement. */
|
|
36
|
+
metaDb?: SiaDb;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Circuit breaker — module-level state
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
let failureCount = 0;
|
|
44
|
+
let breakerActiveUntil = 0;
|
|
45
|
+
|
|
46
|
+
/** Reset the circuit breaker (for testing). */
|
|
47
|
+
export function resetCircuitBreaker(): void {
|
|
48
|
+
failureCount = 0;
|
|
49
|
+
breakerActiveUntil = 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function isCircuitBreakerActive(): boolean {
|
|
53
|
+
if (Date.now() > breakerActiveUntil && breakerActiveUntil > 0) {
|
|
54
|
+
// Breaker expired — reset
|
|
55
|
+
failureCount = 0;
|
|
56
|
+
breakerActiveUntil = 0;
|
|
57
|
+
}
|
|
58
|
+
return Date.now() < breakerActiveUntil;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Cross-repo detection
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Scan candidates for workspace:* npm imports or TypeScript project references.
|
|
67
|
+
* When metaDb is provided, looks up api_contracts where the current repo is the consumer
|
|
68
|
+
* and writes depends_on edges to bridge.db for matching patterns.
|
|
69
|
+
* Returns the number of cross-repo edges written (0 if no metaDb provided).
|
|
70
|
+
*/
|
|
71
|
+
export async function detectCrossRepoEdges(
|
|
72
|
+
_graphDb: SiaDb,
|
|
73
|
+
bridgeDb: SiaDb,
|
|
74
|
+
candidates: CandidateFact[],
|
|
75
|
+
repoHash: string,
|
|
76
|
+
metaDb?: SiaDb,
|
|
77
|
+
): Promise<number> {
|
|
78
|
+
if (!metaDb) {
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Find candidates that match cross-repo patterns
|
|
83
|
+
const matchingCandidates: CandidateFact[] = [];
|
|
84
|
+
for (const candidate of candidates) {
|
|
85
|
+
if (/"workspace:\*"/.test(candidate.content) || /"references":/.test(candidate.content)) {
|
|
86
|
+
matchingCandidates.push(candidate);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (matchingCandidates.length === 0) {
|
|
91
|
+
return 0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Look up api_contracts where this repo is the consumer
|
|
95
|
+
const { rows: contracts } = await metaDb.execute(
|
|
96
|
+
"SELECT id, provider_repo_id, consumer_repo_id, contract_type FROM api_contracts WHERE consumer_repo_id = ?",
|
|
97
|
+
[repoHash],
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
if (contracts.length === 0) {
|
|
101
|
+
return 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Write a depends_on edge for each (matching candidate, contract) pair
|
|
105
|
+
let edgesWritten = 0;
|
|
106
|
+
for (const candidate of matchingCandidates) {
|
|
107
|
+
for (const contract of contracts) {
|
|
108
|
+
const providerRepoId = contract.provider_repo_id as string;
|
|
109
|
+
await insertCrossRepoEdge(bridgeDb, {
|
|
110
|
+
source_repo_id: repoHash,
|
|
111
|
+
source_entity_id: candidate.name,
|
|
112
|
+
target_repo_id: providerRepoId,
|
|
113
|
+
target_entity_id: providerRepoId,
|
|
114
|
+
type: "depends_on",
|
|
115
|
+
trust_tier: 2,
|
|
116
|
+
created_by: "auto-detect",
|
|
117
|
+
});
|
|
118
|
+
edgesWritten++;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return edgesWritten;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
// Session compaction
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Compact session content when it exceeds the working memory token budget.
|
|
131
|
+
* Creates a summary entity tagged with 'session-compaction'.
|
|
132
|
+
*/
|
|
133
|
+
export async function compactSession(
|
|
134
|
+
db: SiaDb,
|
|
135
|
+
sessionContent: string,
|
|
136
|
+
config: SiaConfig,
|
|
137
|
+
): Promise<void> {
|
|
138
|
+
// Rough token estimate: 1 token ~ 4 chars
|
|
139
|
+
const estimatedTokens = Math.ceil(sessionContent.length / 4);
|
|
140
|
+
if (estimatedTokens <= config.workingMemoryTokenBudget) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const summary = sessionContent.slice(0, 200);
|
|
145
|
+
await insertEntity(db, {
|
|
146
|
+
type: "Concept",
|
|
147
|
+
name: summary.slice(0, 50),
|
|
148
|
+
content: summary,
|
|
149
|
+
summary: summary.slice(0, 80),
|
|
150
|
+
tags: JSON.stringify(["session-compaction"]),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
// Pipeline timeout helper
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
|
|
158
|
+
const PIPELINE_TIMEOUT_MS = 8_000;
|
|
159
|
+
|
|
160
|
+
function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
|
|
161
|
+
return Promise.race([
|
|
162
|
+
promise,
|
|
163
|
+
new Promise<never>((_resolve, reject) => {
|
|
164
|
+
setTimeout(() => reject(new Error("Pipeline timeout")), ms);
|
|
165
|
+
}),
|
|
166
|
+
]);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
// Sharing rules enforcement (Task 11.6)
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* After consolidation, check sharing_rules in meta.db and override entity
|
|
175
|
+
* visibility for entities matching a rule's workspace + type criteria.
|
|
176
|
+
* Logs auto-promotion to audit_log.
|
|
177
|
+
*/
|
|
178
|
+
async function applySharingRules(
|
|
179
|
+
graphDb: SiaDb,
|
|
180
|
+
metaDb: SiaDb,
|
|
181
|
+
repoHash: string,
|
|
182
|
+
entityIds: string[],
|
|
183
|
+
): Promise<void> {
|
|
184
|
+
if (entityIds.length === 0) return;
|
|
185
|
+
|
|
186
|
+
// Find which workspace this repo belongs to
|
|
187
|
+
const { rows: wsRows } = await metaDb.execute(
|
|
188
|
+
"SELECT workspace_id FROM workspace_repos WHERE repo_id = ?",
|
|
189
|
+
[repoHash],
|
|
190
|
+
);
|
|
191
|
+
if (wsRows.length === 0) return;
|
|
192
|
+
|
|
193
|
+
const workspaceId = wsRows[0].workspace_id as string;
|
|
194
|
+
|
|
195
|
+
// Query sharing rules for this workspace (or global rules where workspace_id IS NULL)
|
|
196
|
+
const { rows: rules } = await metaDb.execute(
|
|
197
|
+
`SELECT entity_type, default_visibility FROM sharing_rules
|
|
198
|
+
WHERE (workspace_id = ? OR workspace_id IS NULL)
|
|
199
|
+
ORDER BY workspace_id DESC`,
|
|
200
|
+
[workspaceId],
|
|
201
|
+
);
|
|
202
|
+
if (rules.length === 0) return;
|
|
203
|
+
|
|
204
|
+
// Build a type→visibility lookup (workspace-specific rules take precedence)
|
|
205
|
+
const ruleMap = new Map<string | null, string>();
|
|
206
|
+
for (const rule of rules) {
|
|
207
|
+
const type = (rule.entity_type as string | null) ?? null;
|
|
208
|
+
if (!ruleMap.has(type)) {
|
|
209
|
+
ruleMap.set(type, rule.default_visibility as string);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Apply rules to newly created entities
|
|
214
|
+
for (const entityId of entityIds) {
|
|
215
|
+
const { rows } = await graphDb.execute(
|
|
216
|
+
"SELECT type, visibility FROM graph_nodes WHERE id = ?",
|
|
217
|
+
[entityId],
|
|
218
|
+
);
|
|
219
|
+
if (rows.length === 0) continue;
|
|
220
|
+
|
|
221
|
+
const entityType = rows[0].type as string;
|
|
222
|
+
const currentVisibility = rows[0].visibility as string;
|
|
223
|
+
|
|
224
|
+
// Check type-specific rule first, then wildcard (null type)
|
|
225
|
+
const newVisibility = ruleMap.get(entityType) ?? ruleMap.get(null);
|
|
226
|
+
if (newVisibility && newVisibility !== currentVisibility) {
|
|
227
|
+
await updateEntity(graphDb, entityId, { visibility: newVisibility });
|
|
228
|
+
await writeAuditEntry(graphDb, "UPDATE", { entity_id: entityId });
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// ---------------------------------------------------------------------------
|
|
234
|
+
// Main pipeline
|
|
235
|
+
// ---------------------------------------------------------------------------
|
|
236
|
+
|
|
237
|
+
export async function runPipeline(
|
|
238
|
+
payload: HookPayload,
|
|
239
|
+
opts?: PipelineOpts,
|
|
240
|
+
): Promise<PipelineResult> {
|
|
241
|
+
const start = Date.now();
|
|
242
|
+
const siaHome = opts?.siaHome;
|
|
243
|
+
const config = opts?.config ?? getConfig(siaHome);
|
|
244
|
+
const repoHash = resolveRepoHash(payload.cwd);
|
|
245
|
+
|
|
246
|
+
const graphDb = openGraphDb(repoHash, siaHome);
|
|
247
|
+
const episodicDb = openEpisodicDb(repoHash, siaHome);
|
|
248
|
+
|
|
249
|
+
// Partial result used on timeout or failure
|
|
250
|
+
const partialResult = (): PipelineResult => ({
|
|
251
|
+
candidates: 0,
|
|
252
|
+
consolidation: { added: 0, updated: 0, invalidated: 0, noops: 0 },
|
|
253
|
+
edgesCreated: 0,
|
|
254
|
+
flagsProcessed: 0,
|
|
255
|
+
durationMs: Date.now() - start,
|
|
256
|
+
circuitBreakerActive: isCircuitBreakerActive(),
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
async function run(): Promise<PipelineResult> {
|
|
260
|
+
try {
|
|
261
|
+
// Step 4-5: Write episode to episodic.db FIRST
|
|
262
|
+
const episodeId = randomUUID();
|
|
263
|
+
const episodeType = payload.toolName ? "tool_use" : "conversation";
|
|
264
|
+
const role = payload.type === "Stop" ? "assistant" : "tool";
|
|
265
|
+
|
|
266
|
+
await episodicDb.execute(
|
|
267
|
+
`INSERT INTO episodes (id, session_id, ts, type, role, content, tool_name, file_path, trust_tier)
|
|
268
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
269
|
+
[
|
|
270
|
+
episodeId,
|
|
271
|
+
payload.sessionId,
|
|
272
|
+
Date.now(),
|
|
273
|
+
episodeType,
|
|
274
|
+
role,
|
|
275
|
+
payload.content,
|
|
276
|
+
payload.toolName ?? null,
|
|
277
|
+
payload.filePath ?? null,
|
|
278
|
+
payload.type === "Stop" ? 1 : 3,
|
|
279
|
+
],
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
// Step 6: Run chunker
|
|
283
|
+
const chunkerCandidates = await chunkPayload(payload, config, graphDb);
|
|
284
|
+
|
|
285
|
+
// Step 7: Run Track A + Track B in parallel
|
|
286
|
+
const [trackAResult, trackBResult] = await Promise.allSettled([
|
|
287
|
+
Promise.resolve(extractTrackA(payload.content, payload.filePath)),
|
|
288
|
+
extractTrackB(payload.content, {
|
|
289
|
+
captureModel: config.captureModel,
|
|
290
|
+
minExtractConfidence: config.minExtractConfidence,
|
|
291
|
+
airGapped: config.airGapped,
|
|
292
|
+
}),
|
|
293
|
+
]);
|
|
294
|
+
|
|
295
|
+
// Step 8: Merge all candidates
|
|
296
|
+
const allCandidates: CandidateFact[] = [...chunkerCandidates];
|
|
297
|
+
if (trackAResult.status === "fulfilled") {
|
|
298
|
+
allCandidates.push(...trackAResult.value);
|
|
299
|
+
}
|
|
300
|
+
if (trackBResult.status === "fulfilled") {
|
|
301
|
+
allCandidates.push(...trackBResult.value);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Step 9: Consolidation (or direct-write if circuit breaker active)
|
|
305
|
+
let consolidation: ConsolidationResult = { added: 0, updated: 0, invalidated: 0, noops: 0 };
|
|
306
|
+
const newEntityIds: string[] = [];
|
|
307
|
+
|
|
308
|
+
if (isCircuitBreakerActive()) {
|
|
309
|
+
// Direct-write: insert all as ADD
|
|
310
|
+
for (const candidate of allCandidates) {
|
|
311
|
+
const entity = await insertEntity(graphDb, {
|
|
312
|
+
type: candidate.type,
|
|
313
|
+
name: candidate.name,
|
|
314
|
+
content: candidate.content,
|
|
315
|
+
summary: candidate.summary,
|
|
316
|
+
tags: JSON.stringify(candidate.tags),
|
|
317
|
+
file_paths: JSON.stringify(candidate.file_paths),
|
|
318
|
+
trust_tier: candidate.trust_tier,
|
|
319
|
+
confidence: candidate.confidence,
|
|
320
|
+
extraction_method: candidate.extraction_method ?? null,
|
|
321
|
+
t_valid_from: candidate.t_valid_from ?? null,
|
|
322
|
+
});
|
|
323
|
+
newEntityIds.push(entity.id);
|
|
324
|
+
consolidation.added++;
|
|
325
|
+
}
|
|
326
|
+
} else {
|
|
327
|
+
try {
|
|
328
|
+
// Route Tier 4 candidates to staging instead of consolidation
|
|
329
|
+
const tier4Candidates = allCandidates.filter((c) => c.trust_tier === 4);
|
|
330
|
+
const nonTier4Candidates = allCandidates.filter((c) => c.trust_tier !== 4);
|
|
331
|
+
|
|
332
|
+
for (const candidate of tier4Candidates) {
|
|
333
|
+
await insertStagedFact(graphDb, {
|
|
334
|
+
source_episode: payload.sessionId,
|
|
335
|
+
proposed_type: candidate.type,
|
|
336
|
+
proposed_name: candidate.name,
|
|
337
|
+
proposed_content: candidate.content,
|
|
338
|
+
proposed_tags: JSON.stringify(candidate.tags ?? []),
|
|
339
|
+
proposed_file_paths: JSON.stringify(candidate.file_paths ?? []),
|
|
340
|
+
trust_tier: candidate.trust_tier,
|
|
341
|
+
raw_confidence: candidate.confidence,
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Only consolidate non-Tier-4 candidates
|
|
346
|
+
consolidation = await consolidate(graphDb, nonTier4Candidates);
|
|
347
|
+
|
|
348
|
+
// Gather IDs of newly added entities for edge inference
|
|
349
|
+
for (const candidate of nonTier4Candidates) {
|
|
350
|
+
const result = await graphDb.execute(
|
|
351
|
+
"SELECT id FROM graph_nodes WHERE name = ? AND type = ? AND t_valid_until IS NULL AND archived_at IS NULL ORDER BY t_created DESC LIMIT 1",
|
|
352
|
+
[candidate.name, candidate.type],
|
|
353
|
+
);
|
|
354
|
+
const row = result.rows[0] as { id: string } | undefined;
|
|
355
|
+
if (row) {
|
|
356
|
+
newEntityIds.push(row.id);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Reset failure count on success
|
|
361
|
+
failureCount = 0;
|
|
362
|
+
} catch {
|
|
363
|
+
failureCount++;
|
|
364
|
+
if (failureCount >= 3) {
|
|
365
|
+
breakerActiveUntil = Date.now() + 5 * 60 * 1000;
|
|
366
|
+
}
|
|
367
|
+
// Fall through — consolidation failed but pipeline continues
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Step 10: Edge inference
|
|
372
|
+
const edgesCreated = newEntityIds.length > 0 ? await inferEdges(graphDb, newEntityIds) : 0;
|
|
373
|
+
|
|
374
|
+
// Step 10.6: Cross-repo edge detection — writes depends_on edges to bridge.db
|
|
375
|
+
if (opts?.metaDb && allCandidates.length > 0) {
|
|
376
|
+
try {
|
|
377
|
+
const bridgeDb = openBridgeDb(siaHome);
|
|
378
|
+
try {
|
|
379
|
+
await detectCrossRepoEdges(graphDb, bridgeDb, allCandidates, repoHash, opts.metaDb);
|
|
380
|
+
} finally {
|
|
381
|
+
await bridgeDb.close();
|
|
382
|
+
}
|
|
383
|
+
} catch {
|
|
384
|
+
// Best effort — bridge edge detection failure should not break pipeline
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Step 10.5: Sharing rules enforcement (Task 11.6)
|
|
389
|
+
if (opts?.metaDb && newEntityIds.length > 0) {
|
|
390
|
+
try {
|
|
391
|
+
await applySharingRules(graphDb, opts.metaDb, repoHash, newEntityIds);
|
|
392
|
+
} catch {
|
|
393
|
+
// Best effort — sharing rules failure should not break pipeline
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Step 11: Flag processor
|
|
398
|
+
const flagsProcessed = await processFlags(graphDb, payload.sessionId, config);
|
|
399
|
+
|
|
400
|
+
// Step 12: Write sessions_processed entry
|
|
401
|
+
await episodicDb.execute(
|
|
402
|
+
`INSERT OR REPLACE INTO sessions_processed (session_id, processing_status, processed_at, entity_count, pipeline_version)
|
|
403
|
+
VALUES (?, ?, ?, ?, ?)`,
|
|
404
|
+
[payload.sessionId, "complete", Date.now(), consolidation.added, config.captureModel],
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
return {
|
|
408
|
+
candidates: allCandidates.length,
|
|
409
|
+
consolidation,
|
|
410
|
+
edgesCreated,
|
|
411
|
+
flagsProcessed,
|
|
412
|
+
durationMs: Date.now() - start,
|
|
413
|
+
circuitBreakerActive: isCircuitBreakerActive(),
|
|
414
|
+
};
|
|
415
|
+
} catch (err) {
|
|
416
|
+
// Write failed status
|
|
417
|
+
try {
|
|
418
|
+
await episodicDb.execute(
|
|
419
|
+
`INSERT OR REPLACE INTO sessions_processed (session_id, processing_status, processed_at, entity_count, pipeline_version)
|
|
420
|
+
VALUES (?, ?, ?, ?, ?)`,
|
|
421
|
+
[payload.sessionId, "failed", Date.now(), 0, config.captureModel],
|
|
422
|
+
);
|
|
423
|
+
} catch {
|
|
424
|
+
// Best effort
|
|
425
|
+
}
|
|
426
|
+
throw err;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
try {
|
|
431
|
+
const result = await withTimeout(run(), PIPELINE_TIMEOUT_MS);
|
|
432
|
+
return result;
|
|
433
|
+
} catch (_err) {
|
|
434
|
+
// On timeout or unhandled error: write failed status, return partial
|
|
435
|
+
try {
|
|
436
|
+
await episodicDb.execute(
|
|
437
|
+
`INSERT OR REPLACE INTO sessions_processed (session_id, processing_status, processed_at, entity_count, pipeline_version)
|
|
438
|
+
VALUES (?, ?, ?, ?, ?)`,
|
|
439
|
+
[payload.sessionId, "failed", Date.now(), 0, config.captureModel],
|
|
440
|
+
);
|
|
441
|
+
} catch {
|
|
442
|
+
// Best effort
|
|
443
|
+
}
|
|
444
|
+
return partialResult();
|
|
445
|
+
} finally {
|
|
446
|
+
// Step 13: Close databases
|
|
447
|
+
await graphDb.close();
|
|
448
|
+
await episodicDb.close();
|
|
449
|
+
}
|
|
450
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// src/capture/prompts/consolidate.ts — Two-phase consolidation prompt template
|
|
2
|
+
|
|
3
|
+
export function consolidatePrompt(
|
|
4
|
+
candidate: { kind: string; name: string; content: string; summary: string },
|
|
5
|
+
existingEntities: Array<{
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
content: string;
|
|
9
|
+
summary: string;
|
|
10
|
+
type: string;
|
|
11
|
+
}>,
|
|
12
|
+
): { system: string; user: string } {
|
|
13
|
+
const system = `You are a knowledge graph consolidation engine. A new candidate fact has been extracted. Compare it against the existing entities and choose exactly one operation:
|
|
14
|
+
|
|
15
|
+
- NOOP: candidate duplicates an existing entity (>80% content overlap)
|
|
16
|
+
- UPDATE: candidate adds new information to an existing entity (20–80% overlap). Specify which entity ID.
|
|
17
|
+
- INVALIDATE: candidate supersedes or contradicts an existing entity. Specify which entity ID.
|
|
18
|
+
- ADD: candidate is genuinely new knowledge (no significant overlap with any existing entity)
|
|
19
|
+
|
|
20
|
+
Return JSON: { "decision": "ADD"|"UPDATE"|"INVALIDATE"|"NOOP", "target_id": "<entity_id or null>", "reasoning": "<brief explanation>" }
|
|
21
|
+
target_id is required for UPDATE and INVALIDATE, null for ADD and NOOP.`;
|
|
22
|
+
|
|
23
|
+
const user = `Candidate:\n${JSON.stringify(candidate, null, 2)}\n\nExisting entities:\n${JSON.stringify(existingEntities, null, 2)}`;
|
|
24
|
+
return { system, user };
|
|
25
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// src/capture/prompts/edge-infer.ts — Edge inference prompt template
|
|
2
|
+
|
|
3
|
+
export function edgeInferPrompt(
|
|
4
|
+
source: { id: string; kind: string; name: string; content: string },
|
|
5
|
+
candidates: Array<{ id: string; kind: string; name: string; summary: string }>,
|
|
6
|
+
): { system: string; user: string } {
|
|
7
|
+
const system = `You are a relationship inference engine for a code knowledge graph. Given a newly created entity and candidate related entities, propose edges (relationships) between them.
|
|
8
|
+
|
|
9
|
+
Valid edge types by source→target kind:
|
|
10
|
+
- Decision/Convention/Concept → CodeEntity/FileNode: pertains_to
|
|
11
|
+
- Bug → CodeEntity/FileNode: caused_by
|
|
12
|
+
- Solution → Bug: solves
|
|
13
|
+
- Solution → CodeEntity/FileNode: pertains_to
|
|
14
|
+
- Concept → Decision: elaborates
|
|
15
|
+
- Same kind → same kind: supersedes (if new replaces old)
|
|
16
|
+
- Same kind → same kind: contradicts (if they conflict)
|
|
17
|
+
- Any → Any: relates_to (general relationship)
|
|
18
|
+
|
|
19
|
+
Return JSON: { "edges": [{ "target_id": "<id>", "type": "<edge_type>", "weight": 0.0-1.0, "confidence": 0.0-1.0 }] }
|
|
20
|
+
|
|
21
|
+
Rules:
|
|
22
|
+
- Max 5 edges per entity
|
|
23
|
+
- Discard edges with weight < 0.3
|
|
24
|
+
- Only propose edges with valid source→target kind combinations
|
|
25
|
+
- Return { "edges": [] } if no meaningful relationships found`;
|
|
26
|
+
|
|
27
|
+
const user = `New entity:\n${JSON.stringify(source, null, 2)}\n\nCandidate targets:\n${JSON.stringify(candidates, null, 2)}`;
|
|
28
|
+
return { system, user };
|
|
29
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// src/capture/prompts/extract-flagged.ts — Augmented extraction for developer-flagged content
|
|
2
|
+
import { sanitizeFlagReason, sanitizePromptInput } from "@/security/sanitize";
|
|
3
|
+
|
|
4
|
+
export function extractFlaggedPrompt(
|
|
5
|
+
flag: { reason: string; session_id: string },
|
|
6
|
+
transcriptChunk: string,
|
|
7
|
+
): { system: string; user: string } {
|
|
8
|
+
const system = `You are a knowledge extraction engine for a code knowledge graph.
|
|
9
|
+
The developer has explicitly flagged the following content as significant.
|
|
10
|
+
Apply a lower confidence threshold (0.4) and pay special attention to the flagged reason.
|
|
11
|
+
|
|
12
|
+
Extract structured facts with confidence >= 0.4 (lower than the normal 0.6 threshold).
|
|
13
|
+
Return a JSON object with a "facts" array. Each fact must have:
|
|
14
|
+
- type: one of "Decision", "Convention", "Bug", "Solution", "Concept"
|
|
15
|
+
- name: concise name (3–200 characters)
|
|
16
|
+
- content: full description (10–2000 characters)
|
|
17
|
+
- summary: one sentence (max 20 words)
|
|
18
|
+
- tags: up to 5 relevant string tags
|
|
19
|
+
- file_paths: related file paths mentioned in context
|
|
20
|
+
- confidence: number 0.0–1.0
|
|
21
|
+
- proposed_relationships: optional array of { target_name, type, weight }
|
|
22
|
+
|
|
23
|
+
Return { "facts": [] } if nothing worth extracting.`;
|
|
24
|
+
|
|
25
|
+
const sanitizedReason = sanitizeFlagReason(flag.reason);
|
|
26
|
+
const sanitizedContent = sanitizePromptInput(transcriptChunk);
|
|
27
|
+
|
|
28
|
+
const user = `*** DEVELOPER FLAG ***
|
|
29
|
+
Reason: ${sanitizedReason}
|
|
30
|
+
*** END FLAG ***
|
|
31
|
+
|
|
32
|
+
Content to analyze:
|
|
33
|
+
${sanitizedContent}`;
|
|
34
|
+
|
|
35
|
+
return { system, user };
|
|
36
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// src/capture/prompts/extract.ts — Track B LLM extraction prompt template
|
|
2
|
+
import { sanitizePromptInput } from "@/security/sanitize";
|
|
3
|
+
|
|
4
|
+
export interface EntityContext {
|
|
5
|
+
name: string;
|
|
6
|
+
type: string;
|
|
7
|
+
summary: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function extractPrompt(
|
|
11
|
+
content: string,
|
|
12
|
+
context?: EntityContext[],
|
|
13
|
+
): { system: string; user: string } {
|
|
14
|
+
let contextBlock = "";
|
|
15
|
+
if (context && context.length > 0) {
|
|
16
|
+
const entries = context.map((e) => `- ${e.name} (${e.type}): ${e.summary}`).join("\n");
|
|
17
|
+
contextBlock = `\nThe graph already contains these entities — avoid duplicates:\n${entries}\n`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const system = `You are a knowledge extraction engine for a code knowledge graph.
|
|
21
|
+
Extract structured facts from the content provided by the user.
|
|
22
|
+
${contextBlock}
|
|
23
|
+
Return a JSON object with a "facts" array. Each fact must have:
|
|
24
|
+
- type: one of "Decision", "Convention", "Bug", "Solution", "Concept"
|
|
25
|
+
- name: concise name (3–200 characters)
|
|
26
|
+
- content: full description (10–2000 characters)
|
|
27
|
+
- summary: one sentence (max 20 words)
|
|
28
|
+
- tags: up to 5 relevant string tags
|
|
29
|
+
- file_paths: related file paths mentioned in context
|
|
30
|
+
- confidence: number 0.0–1.0 (how certain this fact is)
|
|
31
|
+
- proposed_relationships: optional array of { target_name: string, type: string, weight: number }
|
|
32
|
+
|
|
33
|
+
Rules:
|
|
34
|
+
- Only extract facts with confidence >= 0.6
|
|
35
|
+
- Do not extract raw code snippets as facts
|
|
36
|
+
- Decisions must include rationale
|
|
37
|
+
- Bugs must include symptoms or root cause
|
|
38
|
+
- Return { "facts": [] } if nothing worth extracting`;
|
|
39
|
+
|
|
40
|
+
const user = `Content to analyze:\n\n${sanitizePromptInput(content)}`;
|
|
41
|
+
return { system, user };
|
|
42
|
+
}
|