@swarmvaultai/engine 1.2.0 → 1.4.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/README.md CHANGED
@@ -206,7 +206,7 @@ This matters because many "OpenAI-compatible" backends only implement part of th
206
206
  ### Compile + Query
207
207
 
208
208
  - `compileVault(rootDir, { approve })` writes wiki pages, graph data, and search state using the vault schema as guidance, or stages a review bundle
209
- - compile also writes graph orientation pages such as `wiki/graph/report.md`, `wiki/graph/share-card.md`, `wiki/graph/report.json`, and `wiki/graph/communities/<community>.md`
209
+ - compile also writes graph orientation artifacts such as `wiki/graph/report.md`, `wiki/graph/share-card.md`, `wiki/graph/share-card.svg`, `wiki/graph/share-kit/`, `wiki/graph/report.json`, and `wiki/graph/communities/<community>.md`
210
210
  - compile propagates semantic tags onto page frontmatter and source-backed graph nodes, and records deterministic `contradicts` edges plus a Contradictions section in the graph report when conflicting claims are found
211
211
  - `benchmarkVault(rootDir, { questions })` writes `state/benchmark.json` and folds the latest benchmark summary into `wiki/graph/report.md` and `wiki/graph/report.json`
212
212
  - semantic graph query and embedding-backed similarity enrichment cache vectors under `state/embeddings.json` so graph-semantic refresh stays incremental
@@ -218,7 +218,7 @@ This matters because many "OpenAI-compatible" backends only implement part of th
218
218
  - `explainGraphVault(rootDir, target)` returns node, community, neighbor, provenance, and group-pattern details
219
219
  - `listGraphHyperedges(rootDir, target?, limit?)` returns graph hyperedges globally or for a specific node/page target
220
220
  - `listGodNodes(rootDir, limit)` returns the most connected bridge-heavy graph nodes
221
- - `buildGraphShareArtifact(...)` and `renderGraphShareMarkdown(...)` produce the post-ready graph summary used by `wiki/graph/share-card.md` and the CLI `graph share` command
221
+ - `buildGraphShareArtifact(...)`, `renderGraphShareMarkdown(...)`, `renderGraphShareSvg(...)`, `renderGraphSharePreviewHtml(...)`, and `renderGraphShareBundleFiles(...)` produce the post-ready text, 1200x630 visual card, self-contained HTML preview, and portable share kit used by `wiki/graph/share-card.md`, `wiki/graph/share-card.svg`, `wiki/graph/share-kit/`, and the CLI `graph share` command
222
222
  - project-aware compile also builds `wiki/projects/index.md` plus `wiki/projects/<project>/index.md` rollups without duplicating page trees
223
223
  - human-authored insight pages in `wiki/insights/` are indexed into search and available to query without being rewritten by compile
224
224
  - `chart` and `image` formats save wrapper markdown pages plus local output assets under `wiki/outputs/assets/<slug>/`
@@ -263,7 +263,7 @@ Running the engine produces a local workspace with these main areas:
263
263
  - `raw/sources/`: immutable source copies
264
264
  - `raw/assets/`: copied attachments referenced by ingested markdown bundles and remote URL ingests
265
265
  - `wiki/`: generated markdown pages, the append-only `log.md` activity trail, staged candidates, saved query outputs, exploration hub pages, and a human-only `insights/` area
266
- - `wiki/graph/`: generated graph report pages, the share card, and per-community summaries derived from `state/graph.json`
266
+ - `wiki/graph/`: generated graph report pages, markdown/SVG share cards, the portable `share-kit/`, and per-community summaries derived from `state/graph.json`
267
267
  - `wiki/graph/report.json`: machine-readable graph report data used by the viewer and export surfaces
268
268
  - `wiki/outputs/assets/`: local chart/image artifacts and JSON manifests for saved visual outputs
269
269
  - `wiki/code/`: generated module pages for ingested code sources
package/dist/index.d.ts CHANGED
@@ -1662,6 +1662,10 @@ interface GraphShareArtifact {
1662
1662
  relatedPageIds: string[];
1663
1663
  relatedSourceIds: string[];
1664
1664
  }
1665
+ interface GraphShareBundleFile {
1666
+ relativePath: string;
1667
+ content: string;
1668
+ }
1665
1669
  interface ScheduledCompileTask {
1666
1670
  type: "compile";
1667
1671
  approve?: boolean;
@@ -2009,6 +2013,9 @@ declare function buildGraphShareArtifact(input: {
2009
2013
  vaultName?: string;
2010
2014
  }): GraphShareArtifact;
2011
2015
  declare function renderGraphShareMarkdown(artifact: GraphShareArtifact): string;
2016
+ declare function renderGraphShareSvg(artifact: GraphShareArtifact): string;
2017
+ declare function renderGraphSharePreviewHtml(artifact: GraphShareArtifact): string;
2018
+ declare function renderGraphShareBundleFiles(artifact: GraphShareArtifact): GraphShareBundleFile[];
2012
2019
 
2013
2020
  declare function graphDiff(oldGraph: GraphArtifact, newGraph: GraphArtifact): GraphDiffResult;
2014
2021
  /**
@@ -2613,4 +2620,4 @@ declare function createWebSearchAdapter(id: string, config: WebSearchProviderCon
2613
2620
  type WebSearchTaskId = "deepLintProvider" | "queryProvider" | "exploreProvider";
2614
2621
  declare function getWebSearchAdapterForTask(rootDir: string, task: WebSearchTaskId): Promise<WebSearchAdapter>;
2615
2622
 
2616
- export { ALL_MIGRATIONS, type AddOptions, type AddResult, type AgentType, type AnalyzedTerm, type ApprovalBundleType, type ApprovalChangeType, type ApprovalDetail, type ApprovalDiffHunk, type ApprovalDiffLine, type ApprovalEntry, type ApprovalEntryDetail, type ApprovalEntryLabel, type ApprovalEntryStatus, type ApprovalFrontmatterChange, type ApprovalManifest, type ApprovalStructuredDiff, type ApprovalSummary, type AudioTranscriptionRequest, type AudioTranscriptionResponse, type BenchmarkArtifact, type BenchmarkByClassEntry, type BenchmarkOptions, type BenchmarkQuestionResult, type BenchmarkSummary, type BlastRadiusResult, type CandidatePromotionConfig, type CandidateRecord, type ChartDatum, type ChartSpec, type ClaimStatus, type CodeAnalysis, type CodeDiagnostic, type CodeImport, type CodeIndexArtifact, type CodeIndexEntry, type CodeLanguage, type CodeSymbol, type CodeSymbolKind, type CommandRoleExecutorConfig, type CompileOptions, type CompileResult, type CompileState, type ConsolidationConfig, type ConsolidationPromotion, type ConsolidationResult, DEFAULT_CONSOLIDATION_CONFIG, DEFAULT_HALF_LIFE_DAYS, DEFAULT_HALF_LIFE_DAYS_BY_SOURCE_CLASS, DEFAULT_PROMOTION_CONFIG, DEFAULT_REDACTION_PATTERNS, DEFAULT_STALE_THRESHOLD, type DegradationOutcome, type DirectoryIngestFailure, type DirectoryIngestResult, type DirectoryIngestSkip, type EmbeddingCacheArtifact, type EmbeddingCacheEntry, type EvidenceClass, type ExploreOptions, type ExploreResult, type ExploreStepResult, type ExtractionClaim, type ExtractionKind, type ExtractionTerm, type Freshness, type FreshnessConfig, type GenerationAttachment, type GenerationRequest, type GenerationResponse, type GitHookStatus, type GraphArtifact, type GraphDiffResult, type GraphEdge, type GraphExplainNeighbor, type GraphExplainResult, type GraphExportFormat, type GraphExportResult, type GraphHyperedge, type GraphNode, type GraphPage, type GraphPathResult, type GraphPushCounts, type GraphPushNeo4jOptions, type GraphPushResult, type GraphQueryMatch, type GraphQueryResult, type GraphReportArtifact, type GraphShareArtifact, type GuidedSessionMode, type GuidedSourceSessionAnswers, type GuidedSourceSessionQuestion, type GuidedSourceSessionRecord, type GuidedSourceSessionStatus, type ImageGenerationRequest, type ImageGenerationResponse, type ImageVisionExtraction, type InboxImportResult, type InboxImportSkip, type IngestOptions, type InitOptions, type InputIngestResult, type InstallAgentOptions, type InstallAgentResult, LARGE_REPO_NODE_THRESHOLD, LOCAL_WHISPER_MODEL_SIZES, type LintFinding, type LintOptions, type LocalWhisperAdapterOptions, type LocalWhisperBinaryDiscovery, LocalWhisperProviderAdapter, type LocalWhisperSetupStatus, type ManagedSourceAddOptions, type ManagedSourceAddResult, type ManagedSourceDeleteResult, type ManagedSourceKind, type ManagedSourceRecord, type ManagedSourceReloadOptions, type ManagedSourceReloadResult, type ManagedSourceStatus, type ManagedSourceSyncCounts, type ManagedSourcesArtifact, type MemoryTier, type MigrationPlan, type MigrationResult, type MigrationStep, type Neo4jGraphSinkConfig, OPENAI_COMPATIBLE_CAPABILITY_MATRIX, type OpenAiCompatiblePresetId, type OrchestrationConfig, type OrchestrationFinding, type OrchestrationProposal, type OrchestrationRole, type OrchestrationRoleConfig, type OrchestrationRoleResult, type OutputAsset, type OutputAssetRole, type OutputFormat, type OutputOrigin, type PageKind, type PageManager, type PageStatus, type PendingSemanticRefreshEntry, type Polarity, type PromotionDecision, type PromotionGateKind, type PromotionGateResult, type PromotionSession, type ProviderAdapter, type ProviderCapability, type ProviderConfig, type ProviderPresetCapability, type ProviderRegistrationOptions, type ProviderRegistrationResult, type ProviderRoleExecutorConfig, type ProviderType, type QueryOptions, type QueryResult, type RedactionMatchSummary, type RedactionPatternConfig, type RedactionSettings, type RedactionSummary, type RepoSyncResult, type ResolvedLargeRepoDefaults, type ResolvedPaths, type ReviewActionResult, type RoleExecutorConfig, type SceneElement, type SceneSpec, type ScheduleController, type ScheduleJobConfig, type ScheduleStateRecord, type ScheduleTriggerConfig, type ScheduledCompileTask, type ScheduledConsolidateTask, type ScheduledExploreTask, type ScheduledLintTask, type ScheduledQueryTask, type ScheduledRunResult, type ScheduledTaskConfig, type SearchResult, type SourceAnalysis, type SourceAttachment, type SourceCaptureType, type SourceClaim, type SourceClass, type SourceExtractionArtifact, type SourceGuideResult, type SourceKind, type SourceManifest, type SourceRationale, type SourceReviewResult, type SynthesizedHubEdge, type SynthesizedHubNode, type SynthesizedHyperedgeHubs, type VaultConfig, type VaultDashboardPack, type VaultProfileConfig, type VaultProfilePreset, type VaultVersionRecord, type WatchConfig, type WatchController, type WatchOptions, type WatchRepoSyncResult, type WatchRunRecord, type WatchStatusResult, type WebSearchAdapter, type WebSearchProviderConfig, type WebSearchProviderType, type WebSearchResult, type WhisperRunResult, type WhisperRunner, acceptApproval, addInput, addManagedSource, addWatchedRoot, agentTypeSchema, applyDecayToPages, archiveCandidate, assertProviderCapability, autoCommitWikiChanges, benchmarkVault, blastRadius, blastRadiusVault, bootstrapDemo, buildConfiguredRedactor, buildGraphShareArtifact, buildRedactor, compileVault, computeDecayScore, consolidateVault, createMcpServer, createProvider, createSupersessionEdge, createWebSearchAdapter, defaultVaultConfig, defaultVaultSchema, deleteManagedSource, detectVaultVersion, discoverLocalWhisperBinary, downloadWhisperModel, estimatePageTokens, estimateTokens, evaluateCandidateForPromotion, expectedModelPath, explainGraphVault, exploreVault, exportGraphFormat, exportGraphHtml, exportGraphReportHtml, exportObsidianCanvas, exportObsidianVault, getGitHookStatus, getProviderForTask, getWatchStatus, getWebSearchAdapterForTask, getWorkspaceInfo, graphDiff, guideManagedSource, guideSourceScope, importInbox, ingestDirectory, ingestInput, ingestInputDetailed, initVault, initWorkspace, installAgent, installConfiguredAgents, installGitHooks, lintVault, listApprovals, listCandidates, listGodNodes, listGraphHyperedges, listManagedSourceRecords, listManifests, listPages, listSchedules, listTrackedRepoRoots, listWatchedRoots, loadVaultConfig, loadVaultSchema, loadVaultSchemas, lookupPresetCapabilities, markSuperseded, modelDownloadUrl, pathGraphVault, persistDecayFrontmatter, planMigration, previewCandidatePromotions, promoteCandidate, providerCapabilitySchema, providerTypeSchema, pushGraphNeo4j, queryGraphVault, queryVault, readApproval, readExtractedText, readGraphReport, readPage, registerLocalWhisperProvider, rejectApproval, reloadManagedSources, removeWatchedRoot, renderGraphShareMarkdown, resetDecay, resolveConsolidationConfig, resolveDecayConfig, resolveLargeRepoDefaults, resolvePaths, resolveRedactionPatterns, resolveWatchedRepoRoots, resumeSourceSession, reviewManagedSource, reviewSourceScope, runAutoPromotion, runConsolidation, runDecayPass, runMigration, runSchedule, runWatchCycle, searchVault, serveSchedules, stageGeneratedOutputPages, startGraphServer, startMcpServer, summarizeLocalWhisperSetup, syncTrackedRepos, syncTrackedReposForWatch, synthesizeHyperedgeHubs, trimToTokenBudget, uninstallGitHooks, watchVault, webSearchProviderTypeSchema, withCapabilityFallback };
2623
+ export { ALL_MIGRATIONS, type AddOptions, type AddResult, type AgentType, type AnalyzedTerm, type ApprovalBundleType, type ApprovalChangeType, type ApprovalDetail, type ApprovalDiffHunk, type ApprovalDiffLine, type ApprovalEntry, type ApprovalEntryDetail, type ApprovalEntryLabel, type ApprovalEntryStatus, type ApprovalFrontmatterChange, type ApprovalManifest, type ApprovalStructuredDiff, type ApprovalSummary, type AudioTranscriptionRequest, type AudioTranscriptionResponse, type BenchmarkArtifact, type BenchmarkByClassEntry, type BenchmarkOptions, type BenchmarkQuestionResult, type BenchmarkSummary, type BlastRadiusResult, type CandidatePromotionConfig, type CandidateRecord, type ChartDatum, type ChartSpec, type ClaimStatus, type CodeAnalysis, type CodeDiagnostic, type CodeImport, type CodeIndexArtifact, type CodeIndexEntry, type CodeLanguage, type CodeSymbol, type CodeSymbolKind, type CommandRoleExecutorConfig, type CompileOptions, type CompileResult, type CompileState, type ConsolidationConfig, type ConsolidationPromotion, type ConsolidationResult, DEFAULT_CONSOLIDATION_CONFIG, DEFAULT_HALF_LIFE_DAYS, DEFAULT_HALF_LIFE_DAYS_BY_SOURCE_CLASS, DEFAULT_PROMOTION_CONFIG, DEFAULT_REDACTION_PATTERNS, DEFAULT_STALE_THRESHOLD, type DegradationOutcome, type DirectoryIngestFailure, type DirectoryIngestResult, type DirectoryIngestSkip, type EmbeddingCacheArtifact, type EmbeddingCacheEntry, type EvidenceClass, type ExploreOptions, type ExploreResult, type ExploreStepResult, type ExtractionClaim, type ExtractionKind, type ExtractionTerm, type Freshness, type FreshnessConfig, type GenerationAttachment, type GenerationRequest, type GenerationResponse, type GitHookStatus, type GraphArtifact, type GraphDiffResult, type GraphEdge, type GraphExplainNeighbor, type GraphExplainResult, type GraphExportFormat, type GraphExportResult, type GraphHyperedge, type GraphNode, type GraphPage, type GraphPathResult, type GraphPushCounts, type GraphPushNeo4jOptions, type GraphPushResult, type GraphQueryMatch, type GraphQueryResult, type GraphReportArtifact, type GraphShareArtifact, type GraphShareBundleFile, type GuidedSessionMode, type GuidedSourceSessionAnswers, type GuidedSourceSessionQuestion, type GuidedSourceSessionRecord, type GuidedSourceSessionStatus, type ImageGenerationRequest, type ImageGenerationResponse, type ImageVisionExtraction, type InboxImportResult, type InboxImportSkip, type IngestOptions, type InitOptions, type InputIngestResult, type InstallAgentOptions, type InstallAgentResult, LARGE_REPO_NODE_THRESHOLD, LOCAL_WHISPER_MODEL_SIZES, type LintFinding, type LintOptions, type LocalWhisperAdapterOptions, type LocalWhisperBinaryDiscovery, LocalWhisperProviderAdapter, type LocalWhisperSetupStatus, type ManagedSourceAddOptions, type ManagedSourceAddResult, type ManagedSourceDeleteResult, type ManagedSourceKind, type ManagedSourceRecord, type ManagedSourceReloadOptions, type ManagedSourceReloadResult, type ManagedSourceStatus, type ManagedSourceSyncCounts, type ManagedSourcesArtifact, type MemoryTier, type MigrationPlan, type MigrationResult, type MigrationStep, type Neo4jGraphSinkConfig, OPENAI_COMPATIBLE_CAPABILITY_MATRIX, type OpenAiCompatiblePresetId, type OrchestrationConfig, type OrchestrationFinding, type OrchestrationProposal, type OrchestrationRole, type OrchestrationRoleConfig, type OrchestrationRoleResult, type OutputAsset, type OutputAssetRole, type OutputFormat, type OutputOrigin, type PageKind, type PageManager, type PageStatus, type PendingSemanticRefreshEntry, type Polarity, type PromotionDecision, type PromotionGateKind, type PromotionGateResult, type PromotionSession, type ProviderAdapter, type ProviderCapability, type ProviderConfig, type ProviderPresetCapability, type ProviderRegistrationOptions, type ProviderRegistrationResult, type ProviderRoleExecutorConfig, type ProviderType, type QueryOptions, type QueryResult, type RedactionMatchSummary, type RedactionPatternConfig, type RedactionSettings, type RedactionSummary, type RepoSyncResult, type ResolvedLargeRepoDefaults, type ResolvedPaths, type ReviewActionResult, type RoleExecutorConfig, type SceneElement, type SceneSpec, type ScheduleController, type ScheduleJobConfig, type ScheduleStateRecord, type ScheduleTriggerConfig, type ScheduledCompileTask, type ScheduledConsolidateTask, type ScheduledExploreTask, type ScheduledLintTask, type ScheduledQueryTask, type ScheduledRunResult, type ScheduledTaskConfig, type SearchResult, type SourceAnalysis, type SourceAttachment, type SourceCaptureType, type SourceClaim, type SourceClass, type SourceExtractionArtifact, type SourceGuideResult, type SourceKind, type SourceManifest, type SourceRationale, type SourceReviewResult, type SynthesizedHubEdge, type SynthesizedHubNode, type SynthesizedHyperedgeHubs, type VaultConfig, type VaultDashboardPack, type VaultProfileConfig, type VaultProfilePreset, type VaultVersionRecord, type WatchConfig, type WatchController, type WatchOptions, type WatchRepoSyncResult, type WatchRunRecord, type WatchStatusResult, type WebSearchAdapter, type WebSearchProviderConfig, type WebSearchProviderType, type WebSearchResult, type WhisperRunResult, type WhisperRunner, acceptApproval, addInput, addManagedSource, addWatchedRoot, agentTypeSchema, applyDecayToPages, archiveCandidate, assertProviderCapability, autoCommitWikiChanges, benchmarkVault, blastRadius, blastRadiusVault, bootstrapDemo, buildConfiguredRedactor, buildGraphShareArtifact, buildRedactor, compileVault, computeDecayScore, consolidateVault, createMcpServer, createProvider, createSupersessionEdge, createWebSearchAdapter, defaultVaultConfig, defaultVaultSchema, deleteManagedSource, detectVaultVersion, discoverLocalWhisperBinary, downloadWhisperModel, estimatePageTokens, estimateTokens, evaluateCandidateForPromotion, expectedModelPath, explainGraphVault, exploreVault, exportGraphFormat, exportGraphHtml, exportGraphReportHtml, exportObsidianCanvas, exportObsidianVault, getGitHookStatus, getProviderForTask, getWatchStatus, getWebSearchAdapterForTask, getWorkspaceInfo, graphDiff, guideManagedSource, guideSourceScope, importInbox, ingestDirectory, ingestInput, ingestInputDetailed, initVault, initWorkspace, installAgent, installConfiguredAgents, installGitHooks, lintVault, listApprovals, listCandidates, listGodNodes, listGraphHyperedges, listManagedSourceRecords, listManifests, listPages, listSchedules, listTrackedRepoRoots, listWatchedRoots, loadVaultConfig, loadVaultSchema, loadVaultSchemas, lookupPresetCapabilities, markSuperseded, modelDownloadUrl, pathGraphVault, persistDecayFrontmatter, planMigration, previewCandidatePromotions, promoteCandidate, providerCapabilitySchema, providerTypeSchema, pushGraphNeo4j, queryGraphVault, queryVault, readApproval, readExtractedText, readGraphReport, readPage, registerLocalWhisperProvider, rejectApproval, reloadManagedSources, removeWatchedRoot, renderGraphShareBundleFiles, renderGraphShareMarkdown, renderGraphSharePreviewHtml, renderGraphShareSvg, resetDecay, resolveConsolidationConfig, resolveDecayConfig, resolveLargeRepoDefaults, resolvePaths, resolveRedactionPatterns, resolveWatchedRepoRoots, resumeSourceSession, reviewManagedSource, reviewSourceScope, runAutoPromotion, runConsolidation, runDecayPass, runMigration, runSchedule, runWatchCycle, searchVault, serveSchedules, stageGeneratedOutputPages, startGraphServer, startMcpServer, summarizeLocalWhisperSetup, syncTrackedRepos, syncTrackedReposForWatch, synthesizeHyperedgeHubs, trimToTokenBudget, uninstallGitHooks, watchVault, webSearchProviderTypeSchema, withCapabilityFallback };
package/dist/index.js CHANGED
@@ -7113,6 +7113,45 @@ function buildShortPost(input) {
7113
7113
  "Everything stays local. Try: npm install -g @swarmvaultai/cli && swarmvault scan ./your-repo"
7114
7114
  ].join("\n");
7115
7115
  }
7116
+ function escapeXml(value) {
7117
+ return String(value ?? "").replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
7118
+ }
7119
+ function clipText(value, maxLength) {
7120
+ const normalized = value.replaceAll("\n", " ").replaceAll("\r", " ").trim();
7121
+ if (normalized.length <= maxLength) {
7122
+ return normalized;
7123
+ }
7124
+ return `${normalized.slice(0, Math.max(0, maxLength - 3)).trimEnd()}...`;
7125
+ }
7126
+ function svgText(input) {
7127
+ const attrs = [
7128
+ `x="${input.x}"`,
7129
+ `y="${input.y}"`,
7130
+ `font-size="${input.size}"`,
7131
+ `fill="${input.fill ?? "#f8fafc"}"`,
7132
+ `font-weight="${input.weight ?? 500}"`,
7133
+ `text-anchor="${input.anchor ?? "start"}"`,
7134
+ input.opacity === void 0 ? "" : `opacity="${input.opacity}"`
7135
+ ].filter(Boolean);
7136
+ return ` <text ${attrs.join(" ")}>${escapeXml(input.text)}</text>`;
7137
+ }
7138
+ function svgStatCard(input) {
7139
+ return [
7140
+ ` <rect x="${input.x}" y="${input.y}" width="168" height="92" rx="14" fill="#111827" stroke="#334155" />`,
7141
+ svgText({ x: input.x + 20, y: input.y + 36, text: String(input.value), size: 30, fill: "#ecfeff", weight: 800 }),
7142
+ svgText({ x: input.x + 20, y: input.y + 66, text: input.label, size: 16, fill: "#94a3b8", weight: 600 })
7143
+ ];
7144
+ }
7145
+ function svgListLines(input) {
7146
+ const items = input.items.length ? input.items.slice(0, input.maxItems) : [input.empty];
7147
+ const lines = [svgText({ x: input.x, y: input.y, text: input.title, size: 19, fill: "#a7f3d0", weight: 800 })];
7148
+ for (const [index, item] of items.entries()) {
7149
+ lines.push(
7150
+ svgText({ x: input.x, y: input.y + 38 + index * 30, text: `- ${clipText(item, 58)}`, size: 19, fill: "#e2e8f0", weight: 600 })
7151
+ );
7152
+ }
7153
+ return lines;
7154
+ }
7116
7155
  function buildGraphShareArtifact(input) {
7117
7156
  const { graph, report } = input;
7118
7157
  const vaultName = displayVaultName(input.vaultName);
@@ -7268,6 +7307,175 @@ function renderGraphShareMarkdown(artifact) {
7268
7307
  }
7269
7308
  return `${lines.join("\n")}`;
7270
7309
  }
7310
+ function renderGraphShareSvg(artifact) {
7311
+ const topHubs = artifact.highlights.topHubs.map((node) => node.degree ? `${node.label} (${node.degree})` : node.label);
7312
+ const bridges = artifact.highlights.bridgeNodes.map((node) => node.label);
7313
+ const surprise = artifact.highlights.surprisingConnections[0];
7314
+ const surpriseLine = surprise ? `${surprise.sourceLabel} ${surprise.relation} ${surprise.targetLabel}` : "Add more sources to reveal the first surprising link";
7315
+ const generated = new Date(artifact.generatedAt);
7316
+ const generatedLabel = Number.isNaN(generated.getTime()) ? artifact.generatedAt : generated.toISOString().slice(0, 10);
7317
+ const lines = [
7318
+ '<?xml version="1.0" encoding="UTF-8"?>',
7319
+ `<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="630" viewBox="0 0 1200 630" role="img" aria-labelledby="title desc">`,
7320
+ ` <title>SwarmVault share card for ${escapeXml(artifact.vaultName)}</title>`,
7321
+ ` <desc>${escapeXml(artifact.tagline)}</desc>`,
7322
+ " <defs>",
7323
+ ' <linearGradient id="background" x1="0" y1="0" x2="1" y2="1">',
7324
+ ' <stop offset="0%" stop-color="#020617" />',
7325
+ ' <stop offset="58%" stop-color="#0f172a" />',
7326
+ ' <stop offset="100%" stop-color="#063f37" />',
7327
+ " </linearGradient>",
7328
+ ' <linearGradient id="accent" x1="0" y1="0" x2="1" y2="0">',
7329
+ ' <stop offset="0%" stop-color="#22c55e" />',
7330
+ ' <stop offset="100%" stop-color="#06b6d4" />',
7331
+ " </linearGradient>",
7332
+ " </defs>",
7333
+ ' <rect width="1200" height="630" fill="url(#background)" />',
7334
+ ' <rect x="34" y="34" width="1132" height="562" rx="28" fill="#020617" opacity="0.72" stroke="#1f2937" />',
7335
+ ' <path d="M92 512 C214 386 314 456 438 326 C540 218 648 284 746 194 C860 88 1004 152 1110 84" fill="none" stroke="#22c55e" stroke-width="4" opacity="0.35" />',
7336
+ ' <circle cx="92" cy="512" r="9" fill="#22c55e" />',
7337
+ ' <circle cx="438" cy="326" r="10" fill="#06b6d4" />',
7338
+ ' <circle cx="746" cy="194" r="10" fill="#a7f3d0" />',
7339
+ ' <circle cx="1110" cy="84" r="9" fill="#22c55e" />',
7340
+ svgText({ x: 78, y: 96, text: "SwarmVault", size: 28, fill: "#86efac", weight: 900 }),
7341
+ svgText({ x: 78, y: 152, text: clipText(artifact.vaultName, 42), size: 54, fill: "#f8fafc", weight: 900 }),
7342
+ svgText({ x: 78, y: 196, text: clipText(artifact.tagline, 86), size: 22, fill: "#cbd5e1", weight: 600 }),
7343
+ ...svgStatCard({ x: 78, y: 242, label: "Sources", value: artifact.overview.sources }),
7344
+ ...svgStatCard({ x: 270, y: 242, label: "Wiki pages", value: artifact.overview.pages }),
7345
+ ...svgStatCard({ x: 462, y: 242, label: "Graph nodes", value: artifact.overview.nodes }),
7346
+ ...svgStatCard({ x: 654, y: 242, label: "Edges", value: artifact.overview.edges }),
7347
+ ` <rect x="870" y="240" width="246" height="94" rx="18" fill="url(#accent)" opacity="0.95" />`,
7348
+ svgText({ x: 993, y: 278, text: "Local-first", size: 22, fill: "#052e16", weight: 900, anchor: "middle" }),
7349
+ svgText({ x: 993, y: 307, text: "no API keys required", size: 18, fill: "#064e3b", weight: 800, anchor: "middle" }),
7350
+ ...svgListLines({
7351
+ x: 82,
7352
+ y: 398,
7353
+ title: "Top hubs",
7354
+ items: topHubs,
7355
+ empty: "Still emerging",
7356
+ maxItems: 3
7357
+ }),
7358
+ ...svgListLines({
7359
+ x: 470,
7360
+ y: 398,
7361
+ title: "Bridge nodes",
7362
+ items: bridges,
7363
+ empty: "Still emerging",
7364
+ maxItems: 3
7365
+ }),
7366
+ svgText({ x: 820, y: 398, text: "Surprising link", size: 19, fill: "#a7f3d0", weight: 800 }),
7367
+ svgText({ x: 820, y: 436, text: clipText(surpriseLine, 40), size: 21, fill: "#e2e8f0", weight: 800 }),
7368
+ svgText({
7369
+ x: 820,
7370
+ y: 470,
7371
+ text: clipText(surprise?.why ?? "Run compile again after adding more sources.", 44),
7372
+ size: 17,
7373
+ fill: "#94a3b8",
7374
+ weight: 600
7375
+ }),
7376
+ ` <rect x="78" y="536" width="744" height="42" rx="12" fill="#0f172a" stroke="#1e293b" />`,
7377
+ svgText({
7378
+ x: 100,
7379
+ y: 564,
7380
+ text: "npm install -g @swarmvaultai/cli && swarmvault scan ./your-repo",
7381
+ size: 18,
7382
+ fill: "#d1fae5",
7383
+ weight: 800
7384
+ }),
7385
+ svgText({ x: 1116, y: 564, text: `Generated ${generatedLabel}`, size: 16, fill: "#94a3b8", weight: 600, anchor: "end" }),
7386
+ "</svg>",
7387
+ ""
7388
+ ];
7389
+ return lines.join("\n");
7390
+ }
7391
+ function renderGraphSharePreviewHtml(artifact) {
7392
+ const rawSvg = renderGraphShareSvg(artifact);
7393
+ const xmlDeclaration = '<?xml version="1.0" encoding="UTF-8"?>\n';
7394
+ const svg = rawSvg.startsWith(xmlDeclaration) ? rawSvg.slice(xmlDeclaration.length) : rawSvg;
7395
+ const topHubs = artifact.highlights.topHubs.slice(0, 5).map((node) => `<li>${escapeXml(node.degree ? `${node.label} (${node.degree})` : node.label)}</li>`).join("\n");
7396
+ const questions = artifact.highlights.suggestedQuestions.slice(0, 3).map((question) => `<li>${escapeXml(question)}</li>`).join("\n");
7397
+ const title = `SwarmVault Share Kit - ${artifact.vaultName}`;
7398
+ return [
7399
+ "<!doctype html>",
7400
+ '<html lang="en">',
7401
+ "<head>",
7402
+ ' <meta charset="utf-8">',
7403
+ ' <meta name="viewport" content="width=device-width, initial-scale=1">',
7404
+ ` <title>${escapeXml(title)}</title>`,
7405
+ ` <meta name="description" content="${escapeXml(artifact.tagline)}">`,
7406
+ " <style>",
7407
+ " :root { color-scheme: dark; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #020617; color: #e2e8f0; }",
7408
+ " body { margin: 0; min-height: 100vh; background: #020617; }",
7409
+ " main { width: min(1120px, calc(100% - 32px)); margin: 0 auto; padding: 32px 0 48px; }",
7410
+ " header { margin-bottom: 24px; }",
7411
+ " h1 { margin: 0 0 8px; font-size: 34px; line-height: 1.15; letter-spacing: 0; color: #f8fafc; }",
7412
+ " p { margin: 0; color: #94a3b8; line-height: 1.6; }",
7413
+ " .preview { display: block; width: 100%; max-width: 960px; margin: 0 auto 28px; border: 1px solid #1e293b; background: #020617; }",
7414
+ " .preview svg { display: block; width: 100%; height: auto; }",
7415
+ " .grid { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(280px, 0.8fr); gap: 18px; }",
7416
+ " section { border: 1px solid #1e293b; background: #0f172a; padding: 18px; }",
7417
+ " h2 { margin: 0 0 12px; font-size: 16px; color: #86efac; letter-spacing: 0; }",
7418
+ " pre { white-space: pre-wrap; overflow-wrap: anywhere; margin: 0; color: #d1fae5; font-size: 14px; line-height: 1.55; }",
7419
+ " ul { margin: 0; padding-left: 20px; color: #cbd5e1; line-height: 1.6; }",
7420
+ " code { color: #d1fae5; }",
7421
+ " .cta { margin-top: 14px; padding: 12px 14px; background: #020617; border: 1px solid #334155; color: #d1fae5; font-weight: 700; overflow-wrap: anywhere; }",
7422
+ " @media (max-width: 760px) { main { width: min(100% - 24px, 1120px); padding-top: 20px; } .grid { grid-template-columns: 1fr; } h1 { font-size: 26px; } section { padding: 14px; } }",
7423
+ " </style>",
7424
+ "</head>",
7425
+ "<body>",
7426
+ ' <main aria-labelledby="share-title">',
7427
+ " <header>",
7428
+ ` <h1 id="share-title">${escapeXml(artifact.vaultName)}</h1>`,
7429
+ ` <p>${escapeXml(artifact.tagline)}</p>`,
7430
+ " </header>",
7431
+ ' <section class="preview" aria-label="Visual share card">',
7432
+ svg.split("\n").map((line) => ` ${line}`).join("\n"),
7433
+ " </section>",
7434
+ ' <div class="grid">',
7435
+ ' <section aria-labelledby="share-post-title">',
7436
+ ' <h2 id="share-post-title">Share Post</h2>',
7437
+ ` <pre>${escapeXml(artifact.shortPost)}</pre>`,
7438
+ " </section>",
7439
+ ' <section aria-labelledby="share-details-title">',
7440
+ ' <h2 id="share-details-title">Highlights</h2>',
7441
+ ` <ul>${topHubs || "<li>Top hubs are still emerging.</li>"}</ul>`,
7442
+ ' <h2 style="margin-top:18px">Ask Next</h2>',
7443
+ ` <ul>${questions || "<li>Add more sources, run compile, then ask what changed.</li>"}</ul>`,
7444
+ ' <div class="cta">npm install -g @swarmvaultai/cli && swarmvault scan ./your-repo</div>',
7445
+ " </section>",
7446
+ " </div>",
7447
+ " </main>",
7448
+ "</body>",
7449
+ "</html>",
7450
+ ""
7451
+ ].join("\n");
7452
+ }
7453
+ function renderGraphShareBundleFiles(artifact) {
7454
+ return [
7455
+ {
7456
+ relativePath: "share-card.md",
7457
+ content: renderGraphShareMarkdown(artifact)
7458
+ },
7459
+ {
7460
+ relativePath: "share-post.txt",
7461
+ content: `${artifact.shortPost}
7462
+ `
7463
+ },
7464
+ {
7465
+ relativePath: "share-card.svg",
7466
+ content: renderGraphShareSvg(artifact)
7467
+ },
7468
+ {
7469
+ relativePath: "share-preview.html",
7470
+ content: renderGraphSharePreviewHtml(artifact)
7471
+ },
7472
+ {
7473
+ relativePath: "share-artifact.json",
7474
+ content: `${JSON.stringify(artifact, null, 2)}
7475
+ `
7476
+ }
7477
+ ];
7478
+ }
7271
7479
 
7272
7480
  // src/graph-query-core.ts
7273
7481
  var NODE_TYPE_PRIORITY = {
@@ -9106,7 +9314,7 @@ function buildGraphReportPage(input) {
9106
9314
  function buildGraphSharePage(input) {
9107
9315
  const pageId = "graph:share-card";
9108
9316
  const pathValue = "graph/share-card.md";
9109
- const artifact = buildGraphShareArtifact({
9317
+ const artifact = input.artifact ?? buildGraphShareArtifact({
9110
9318
  graph: input.graph,
9111
9319
  report: input.report,
9112
9320
  vaultName: input.vaultName
@@ -20354,7 +20562,7 @@ async function runDeepLint(rootDir, structuralFindings, options = {}) {
20354
20562
 
20355
20563
  // src/output-artifacts.ts
20356
20564
  import { z as z6 } from "zod";
20357
- function escapeXml(value) {
20565
+ function escapeXml2(value) {
20358
20566
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
20359
20567
  }
20360
20568
  function clampNumber(value, min, max) {
@@ -20425,7 +20633,7 @@ function renderChartSvg(spec) {
20425
20633
  const y = projectY(value);
20426
20634
  return [
20427
20635
  `<line x1="${margin.left}" y1="${y}" x2="${width - margin.right}" y2="${y}" stroke="#dbe4ec" stroke-width="1" />`,
20428
- `<text x="${margin.left - 16}" y="${y + 4}" text-anchor="end" font-size="14" fill="#475569">${escapeXml(value.toFixed(0))}</text>`
20636
+ `<text x="${margin.left - 16}" y="${y + 4}" text-anchor="end" font-size="14" fill="#475569">${escapeXml2(value.toFixed(0))}</text>`
20429
20637
  ].join("");
20430
20638
  }).join("");
20431
20639
  const bars = spec.kind === "bar" ? points.map((point) => {
@@ -20433,7 +20641,7 @@ function renderChartSvg(spec) {
20433
20641
  const barHeight = Math.max(8, Math.abs(zeroY - point.y));
20434
20642
  return [
20435
20643
  `<rect x="${point.centerX - barWidth / 2}" y="${top}" width="${barWidth}" height="${barHeight}" rx="12" fill="#0ea5e9" opacity="0.92" />`,
20436
- `<text x="${point.centerX}" y="${top - 10}" text-anchor="middle" font-size="13" fill="#0f172a">${escapeXml(
20644
+ `<text x="${point.centerX}" y="${top - 10}" text-anchor="middle" font-size="13" fill="#0f172a">${escapeXml2(
20437
20645
  point.value.toFixed(0)
20438
20646
  )}</text>`
20439
20647
  ].join("");
@@ -20443,33 +20651,33 @@ function renderChartSvg(spec) {
20443
20651
  `<path d="${linePath}" fill="none" stroke="#0ea5e9" stroke-width="5" stroke-linecap="round" stroke-linejoin="round" />`,
20444
20652
  ...points.map(
20445
20653
  (point) => `<circle cx="${point.centerX}" cy="${point.y}" r="8" fill="#f8fafc" stroke="#0ea5e9" stroke-width="4" />
20446
- <text x="${point.centerX}" y="${point.y - 18}" text-anchor="middle" font-size="13" fill="#0f172a">${escapeXml(
20654
+ <text x="${point.centerX}" y="${point.y - 18}" text-anchor="middle" font-size="13" fill="#0f172a">${escapeXml2(
20447
20655
  point.value.toFixed(0)
20448
20656
  )}</text>`
20449
20657
  )
20450
20658
  ].join("") : "";
20451
20659
  const labels = points.map(
20452
- (point) => `<text x="${point.centerX}" y="${height - margin.bottom + 28}" text-anchor="middle" font-size="14" fill="#334155">${escapeXml(
20660
+ (point) => `<text x="${point.centerX}" y="${height - margin.bottom + 28}" text-anchor="middle" font-size="14" fill="#334155">${escapeXml2(
20453
20661
  point.label
20454
20662
  )}</text>`
20455
20663
  ).join("");
20456
20664
  const notes = (spec.notes ?? []).map(
20457
- (note, index) => `<text x="${margin.left}" y="${height - 26 - index * 18}" font-size="13" fill="#475569">${escapeXml(note)}</text>`
20665
+ (note, index) => `<text x="${margin.left}" y="${height - 26 - index * 18}" font-size="13" fill="#475569">${escapeXml2(note)}</text>`
20458
20666
  ).join("");
20459
20667
  const svg = [
20460
- `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" role="img" aria-label="${escapeXml(spec.title)}">`,
20668
+ `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" role="img" aria-label="${escapeXml2(spec.title)}">`,
20461
20669
  '<rect width="100%" height="100%" fill="#f8fafc" />',
20462
- `<text x="${margin.left}" y="56" font-size="34" font-weight="700" fill="#0f172a">${escapeXml(spec.title)}</text>`,
20463
- spec.subtitle ? `<text x="${margin.left}" y="86" font-size="18" fill="#475569">${escapeXml(spec.subtitle)}</text>` : "",
20670
+ `<text x="${margin.left}" y="56" font-size="34" font-weight="700" fill="#0f172a">${escapeXml2(spec.title)}</text>`,
20671
+ spec.subtitle ? `<text x="${margin.left}" y="86" font-size="18" fill="#475569">${escapeXml2(spec.subtitle)}</text>` : "",
20464
20672
  gridLines,
20465
20673
  `<line x1="${margin.left}" y1="${zeroY}" x2="${width - margin.right}" y2="${zeroY}" stroke="#0f172a" stroke-width="2" />`,
20466
20674
  `<line x1="${margin.left}" y1="${margin.top}" x2="${margin.left}" y2="${height - margin.bottom}" stroke="#0f172a" stroke-width="2" />`,
20467
20675
  bars,
20468
20676
  lineMarks,
20469
20677
  labels,
20470
- spec.xLabel ? `<text x="${margin.left + chartWidth / 2}" y="${height - 46}" text-anchor="middle" font-size="15" fill="#475569">${escapeXml(spec.xLabel)}</text>` : "",
20471
- spec.yLabel ? `<text x="34" y="${margin.top + chartHeight / 2}" text-anchor="middle" font-size="15" fill="#475569" transform="rotate(-90 34 ${margin.top + chartHeight / 2})">${escapeXml(spec.yLabel)}</text>` : "",
20472
- spec.seriesLabel ? `<text x="${width - margin.right}" y="56" text-anchor="end" font-size="15" fill="#475569">${escapeXml(spec.seriesLabel)}</text>` : "",
20678
+ spec.xLabel ? `<text x="${margin.left + chartWidth / 2}" y="${height - 46}" text-anchor="middle" font-size="15" fill="#475569">${escapeXml2(spec.xLabel)}</text>` : "",
20679
+ spec.yLabel ? `<text x="34" y="${margin.top + chartHeight / 2}" text-anchor="middle" font-size="15" fill="#475569" transform="rotate(-90 34 ${margin.top + chartHeight / 2})">${escapeXml2(spec.yLabel)}</text>` : "",
20680
+ spec.seriesLabel ? `<text x="${width - margin.right}" y="56" text-anchor="end" font-size="15" fill="#475569">${escapeXml2(spec.seriesLabel)}</text>` : "",
20473
20681
  notes,
20474
20682
  "</svg>"
20475
20683
  ].filter(Boolean).join("");
@@ -20481,33 +20689,33 @@ function renderSceneSvg(spec) {
20481
20689
  const elements = spec.elements.map((element) => {
20482
20690
  const opacity = element.opacity === void 0 ? 1 : clampNumber(element.opacity, 0, 1);
20483
20691
  if (element.kind === "label") {
20484
- return `<text x="${element.x}" y="${element.y}" font-size="${clampNumber(element.fontSize ?? 28, 10, 72)}" fill="${escapeXml(
20692
+ return `<text x="${element.x}" y="${element.y}" font-size="${clampNumber(element.fontSize ?? 28, 10, 72)}" fill="${escapeXml2(
20485
20693
  element.fill ?? "#0f172a"
20486
- )}" opacity="${opacity}" font-family="'Avenir Next', 'Segoe UI', sans-serif">${escapeXml(element.text ?? "")}</text>`;
20694
+ )}" opacity="${opacity}" font-family="'Avenir Next', 'Segoe UI', sans-serif">${escapeXml2(element.text ?? "")}</text>`;
20487
20695
  }
20488
20696
  switch (element.shape) {
20489
20697
  case "circle":
20490
- return `<circle cx="${element.x}" cy="${element.y}" r="${Math.max(6, element.radius ?? 40)}" fill="${escapeXml(
20698
+ return `<circle cx="${element.x}" cy="${element.y}" r="${Math.max(6, element.radius ?? 40)}" fill="${escapeXml2(
20491
20699
  element.fill ?? "#dbeafe"
20492
- )}" stroke="${escapeXml(element.stroke ?? "#0ea5e9")}" stroke-width="${Math.max(1, element.strokeWidth ?? 2)}" opacity="${opacity}" />`;
20700
+ )}" stroke="${escapeXml2(element.stroke ?? "#0ea5e9")}" stroke-width="${Math.max(1, element.strokeWidth ?? 2)}" opacity="${opacity}" />`;
20493
20701
  case "line":
20494
- return `<line x1="${element.x}" y1="${element.y}" x2="${element.x + (element.width ?? 120)}" y2="${element.y + (element.height ?? 0)}" stroke="${escapeXml(element.stroke ?? "#475569")}" stroke-width="${Math.max(1, element.strokeWidth ?? 3)}" opacity="${opacity}" />`;
20702
+ return `<line x1="${element.x}" y1="${element.y}" x2="${element.x + (element.width ?? 120)}" y2="${element.y + (element.height ?? 0)}" stroke="${escapeXml2(element.stroke ?? "#475569")}" stroke-width="${Math.max(1, element.strokeWidth ?? 3)}" opacity="${opacity}" />`;
20495
20703
  default:
20496
20704
  return `<rect x="${element.x}" y="${element.y}" width="${Math.max(8, element.width ?? 160)}" height="${Math.max(
20497
20705
  8,
20498
20706
  element.height ?? 120
20499
- )}" rx="22" fill="${escapeXml(element.fill ?? "#e2e8f0")}" stroke="${escapeXml(element.stroke ?? "#94a3b8")}" stroke-width="${Math.max(
20707
+ )}" rx="22" fill="${escapeXml2(element.fill ?? "#e2e8f0")}" stroke="${escapeXml2(element.stroke ?? "#94a3b8")}" stroke-width="${Math.max(
20500
20708
  1,
20501
20709
  element.strokeWidth ?? 2
20502
20710
  )}" opacity="${opacity}" />`;
20503
20711
  }
20504
20712
  }).join("");
20505
20713
  const svg = [
20506
- `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" role="img" aria-label="${escapeXml(
20714
+ `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" role="img" aria-label="${escapeXml2(
20507
20715
  spec.alt
20508
20716
  )}">`,
20509
- `<rect width="100%" height="100%" fill="${escapeXml(spec.background ?? "#f8fafc")}" />`,
20510
- `<text x="48" y="64" font-size="34" font-weight="700" fill="#0f172a">${escapeXml(spec.title)}</text>`,
20717
+ `<rect width="100%" height="100%" fill="${escapeXml2(spec.background ?? "#f8fafc")}" />`,
20718
+ `<text x="48" y="64" font-size="34" font-weight="700" fill="#0f172a">${escapeXml2(spec.title)}</text>`,
20511
20719
  elements,
20512
20720
  `</svg>`
20513
20721
  ].join("");
@@ -20518,12 +20726,12 @@ function renderRasterPosterSvg(input) {
20518
20726
  const height = clampNumber(input.height ?? 720, 320, 1200);
20519
20727
  const inset = 42;
20520
20728
  const svg = [
20521
- `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" role="img" aria-label="${escapeXml(
20729
+ `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" role="img" aria-label="${escapeXml2(
20522
20730
  input.alt
20523
20731
  )}">`,
20524
20732
  '<rect width="100%" height="100%" fill="#f8fafc" />',
20525
- `<text x="${inset}" y="56" font-size="34" font-weight="700" fill="#0f172a">${escapeXml(input.title)}</text>`,
20526
- `<image href="${escapeXml(input.rasterFileName)}" x="${inset}" y="92" width="${width - inset * 2}" height="${height - 148}" preserveAspectRatio="xMidYMid meet" />`,
20733
+ `<text x="${inset}" y="56" font-size="34" font-weight="700" fill="#0f172a">${escapeXml2(input.title)}</text>`,
20734
+ `<image href="${escapeXml2(input.rasterFileName)}" x="${inset}" y="92" width="${width - inset * 2}" height="${height - 148}" preserveAspectRatio="xMidYMid meet" />`,
20527
20735
  `</svg>`
20528
20736
  ].join("");
20529
20737
  return { svg, width, height };
@@ -22896,6 +23104,11 @@ async function buildGraphOrientationPages(graph, paths, schemaHash, previousComp
22896
23104
  report
22897
23105
  })
22898
23106
  );
23107
+ const shareArtifact = buildGraphShareArtifact({
23108
+ graph,
23109
+ report,
23110
+ vaultName: path26.basename(paths.rootDir)
23111
+ });
22899
23112
  const shareRecord = await buildManagedGraphPage(
22900
23113
  path26.join(paths.wikiDir, "graph", "share-card.md"),
22901
23114
  {
@@ -22907,13 +23120,16 @@ async function buildGraphOrientationPages(graph, paths, schemaHash, previousComp
22907
23120
  graph,
22908
23121
  schemaHash,
22909
23122
  metadata,
23123
+ artifact: shareArtifact,
22910
23124
  report,
22911
23125
  vaultName: path26.basename(paths.rootDir)
22912
23126
  })
22913
23127
  );
22914
23128
  return {
22915
23129
  records: [reportRecord, shareRecord, ...communityRecords],
22916
- report
23130
+ report,
23131
+ shareSvg: renderGraphShareSvg(shareArtifact),
23132
+ shareBundleFiles: renderGraphShareBundleFiles(shareArtifact)
22917
23133
  };
22918
23134
  }
22919
23135
  async function writePage(wikiDir, relativePath, content, changedPages) {
@@ -22923,6 +23139,11 @@ async function writePage(wikiDir, relativePath, content, changedPages) {
22923
23139
  changedPages.push(relativePath);
22924
23140
  }
22925
23141
  }
23142
+ async function writeGraphShareBundle(wikiDir, files) {
23143
+ for (const file of files) {
23144
+ await writeFileIfChanged(path26.join(wikiDir, "graph", "share-kit", file.relativePath), file.content);
23145
+ }
23146
+ }
22926
23147
  function aggregateItems(analyses, kind) {
22927
23148
  const grouped = /* @__PURE__ */ new Map();
22928
23149
  for (const analysis of analyses) {
@@ -23534,6 +23755,8 @@ async function syncVaultArtifacts(rootDir, input) {
23534
23755
  }
23535
23756
  await writeJsonFile(paths.graphPath, graph);
23536
23757
  await writeJsonFile(path26.join(paths.wikiDir, "graph", "report.json"), graphOrientation.report);
23758
+ await writeFileIfChanged(path26.join(paths.wikiDir, "graph", "share-card.svg"), graphOrientation.shareSvg);
23759
+ await writeGraphShareBundle(paths.wikiDir, graphOrientation.shareBundleFiles);
23537
23760
  await writeJsonFile(paths.codeIndexPath, input.codeIndex);
23538
23761
  await writeJsonFile(paths.compileStatePath, {
23539
23762
  generatedAt: graph.generatedAt,
@@ -23592,7 +23815,7 @@ async function refreshIndexesAndSearch(rootDir, pages) {
23592
23815
  compileState?.generatedAt,
23593
23816
  [],
23594
23817
  config
23595
- ) : { records: [], report: null };
23818
+ ) : { records: [], report: null, shareSvg: "", shareBundleFiles: [] };
23596
23819
  const dashboardRecords = currentGraph ? await buildDashboardRecords(
23597
23820
  config,
23598
23821
  paths,
@@ -23728,6 +23951,8 @@ async function refreshIndexesAndSearch(rootDir, pages) {
23728
23951
  }
23729
23952
  if (graphOrientation.report) {
23730
23953
  await writeJsonFile(path26.join(paths.wikiDir, "graph", "report.json"), graphOrientation.report);
23954
+ await writeFileIfChanged(path26.join(paths.wikiDir, "graph", "share-card.svg"), graphOrientation.shareSvg);
23955
+ await writeGraphShareBundle(paths.wikiDir, graphOrientation.shareBundleFiles);
23731
23956
  }
23732
23957
  const existingProjectIndexPaths = (await listFilesRecursive(paths.projectsDir)).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(path26.relative(paths.wikiDir, absolutePath)));
23733
23958
  const allowedProjectIndexPaths = /* @__PURE__ */ new Set([
@@ -23738,7 +23963,11 @@ async function refreshIndexesAndSearch(rootDir, pages) {
23738
23963
  existingProjectIndexPaths.filter((relativePath) => !allowedProjectIndexPaths.has(relativePath)).map((relativePath) => fs22.rm(path26.join(paths.wikiDir, relativePath), { force: true }))
23739
23964
  );
23740
23965
  const existingGraphPages = (await listFilesRecursive(path26.join(paths.wikiDir, "graph").replace(/\/$/, "")).catch(() => [])).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(path26.relative(paths.wikiDir, absolutePath)));
23741
- const allowedGraphPages = /* @__PURE__ */ new Set(["graph/index.md", ...graphOrientation.records.map((record) => record.page.path)]);
23966
+ const allowedGraphPages = /* @__PURE__ */ new Set([
23967
+ "graph/index.md",
23968
+ "graph/share-kit/share-card.md",
23969
+ ...graphOrientation.records.map((record) => record.page.path)
23970
+ ]);
23742
23971
  await Promise.all(
23743
23972
  existingGraphPages.filter((relativePath) => !allowedGraphPages.has(relativePath)).map((relativePath) => fs22.rm(path26.join(paths.wikiDir, relativePath), { force: true }))
23744
23973
  );
@@ -26885,7 +27114,7 @@ async function getWatchStatus(rootDir) {
26885
27114
  }
26886
27115
 
26887
27116
  // src/mcp.ts
26888
- var SERVER_VERSION = "1.2.0";
27117
+ var SERVER_VERSION = "1.4.0";
26889
27118
  async function createMcpServer(rootDir) {
26890
27119
  const server = new McpServer({
26891
27120
  name: "swarmvault",
@@ -30418,7 +30647,10 @@ export {
30418
30647
  rejectApproval,
30419
30648
  reloadManagedSources,
30420
30649
  removeWatchedRoot,
30650
+ renderGraphShareBundleFiles,
30421
30651
  renderGraphShareMarkdown,
30652
+ renderGraphSharePreviewHtml,
30653
+ renderGraphShareSvg,
30422
30654
  resetDecay,
30423
30655
  resolveConsolidationConfig,
30424
30656
  resolveDecayConfig,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swarmvaultai/engine",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Core engine for SwarmVault: ingest, compile, query, lint, and provider abstractions.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",