@happyvertical/smrt-dev-mcp 0.60.8 → 0.60.10
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/AGENTS.md +27 -1
- package/README.md +17 -1
- package/agents/intent-duplicates.md +26 -0
- package/dist/dev-plane.js +2 -2
- package/dist/{http-CCiO7qQW.js → http-BqKiyqgN.js} +2 -2
- package/dist/{http-CCiO7qQW.js.map → http-BqKiyqgN.js.map} +1 -1
- package/dist/index.js +12 -409
- package/dist/index.js.map +1 -1
- package/dist/knowledge/index.d.ts +1 -1
- package/dist/knowledge/index.d.ts.map +1 -1
- package/dist/knowledge/intents/audit-trail.md +63 -0
- package/dist/knowledge/intents/auth-and-users.md +67 -0
- package/dist/knowledge/intents/background-work.md +72 -0
- package/dist/knowledge/intents/feature-flags-and-entitlements.md +60 -0
- package/dist/knowledge/intents/file-and-asset-storage.md +71 -0
- package/dist/knowledge/intents/human-approvals.md +56 -0
- package/dist/knowledge/intents/index.md +41 -0
- package/dist/knowledge/intents/money-and-rates.md +65 -0
- package/dist/knowledge/intents/outbound-messages.md +67 -0
- package/dist/knowledge/intents/prompts-and-ai-operations.md +72 -0
- package/dist/knowledge/intents/relationships-and-trees.md +56 -0
- package/dist/knowledge/intents/scheduled-runs.md +61 -0
- package/dist/knowledge/intents/search-facts-knowledge.md +68 -0
- package/dist/knowledge/intents/secrets-and-config.md +66 -0
- package/dist/knowledge/intents/tenant-scoping.md +63 -0
- package/dist/knowledge/intents/webhooks-and-events.md +71 -0
- package/dist/knowledge/okf-bundle.d.ts +61 -0
- package/dist/knowledge/okf-bundle.d.ts.map +1 -0
- package/dist/{knowledge-DqoDX-lZ.js → knowledge-DUiMUjEg.js} +218 -3
- package/dist/knowledge-DUiMUjEg.js.map +1 -0
- package/dist/knowledge.js +2 -2
- package/dist/review-cli-DJIWUlFp.js +75 -0
- package/dist/review-cli-DJIWUlFp.js.map +1 -0
- package/dist/review-smrt-project-ByEwPcor.js +774 -0
- package/dist/review-smrt-project-ByEwPcor.js.map +1 -0
- package/dist/smrt-knowledge.okf.md +60 -0
- package/dist/{tool-catalog-RHq7nyCm.js → tool-catalog-BhnSCF8g.js} +11 -2
- package/dist/tool-catalog-BhnSCF8g.js.map +1 -0
- package/dist/tool-catalog.d.ts.map +1 -1
- package/dist/tools/intent-detector.d.ts +57 -0
- package/dist/tools/intent-detector.d.ts.map +1 -0
- package/dist/tools/intent-index.d.ts +40 -0
- package/dist/tools/intent-index.d.ts.map +1 -0
- package/dist/tools/review-cli.d.ts +40 -0
- package/dist/tools/review-cli.d.ts.map +1 -0
- package/dist/tools/review-smrt-project.d.ts +25 -0
- package/dist/tools/review-smrt-project.d.ts.map +1 -1
- package/package.json +6 -6
- package/dist/knowledge-DqoDX-lZ.js.map +0 -1
- package/dist/tool-catalog-RHq7nyCm.js.map +0 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Capability
|
|
3
|
+
title: "Search, facts and extracted knowledge"
|
|
4
|
+
description: "Reach for core semanticSearch, smrt-facts reconciliation and smrt-ingestion before writing embedding search or a facts table."
|
|
5
|
+
tags:
|
|
6
|
+
- smrt
|
|
7
|
+
- intent
|
|
8
|
+
status: draft
|
|
9
|
+
generated:
|
|
10
|
+
by: claude/smrt-4687
|
|
11
|
+
at: 2026-11-05T00:00:00Z
|
|
12
|
+
stale_after: 2027-02-03T00:00:00Z
|
|
13
|
+
audience: internal
|
|
14
|
+
evidence_level: source-inspected
|
|
15
|
+
package_version: 0.60.8
|
|
16
|
+
sources:
|
|
17
|
+
- id: s1
|
|
18
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/facts/src/facts.ts
|
|
19
|
+
path: packages/facts/src/facts.ts
|
|
20
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
21
|
+
title: "packages/facts/src/facts.ts (FactCollection.reconcile)"
|
|
22
|
+
- id: s2
|
|
23
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/core/src/collection.ts
|
|
24
|
+
path: packages/core/src/collection.ts
|
|
25
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
26
|
+
title: "packages/core/src/collection.ts (SmrtCollection.findSimilarToEmbedding, semanticSearch)"
|
|
27
|
+
- id: s3
|
|
28
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/core/src/embeddings/storage.ts
|
|
29
|
+
path: packages/core/src/embeddings/storage.ts
|
|
30
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
31
|
+
title: "packages/core/src/embeddings/storage.ts (EmbeddingStorage.searchSimilar)"
|
|
32
|
+
- id: s4
|
|
33
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/ingestion/AGENTS.md
|
|
34
|
+
path: packages/ingestion/AGENTS.md
|
|
35
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
36
|
+
title: "packages/ingestion/AGENTS.md (ingestion invariants)"
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
# Search, facts and extracted knowledge
|
|
40
|
+
|
|
41
|
+
# Entry point
|
|
42
|
+
|
|
43
|
+
Search: any SmrtCollection with embeddings configured exposes `semanticSearch(query, options)` (core). Knowledge: `FactCollection.reconcile(options)` from `@happyvertical/smrt-facts` decides whether new text creates, merges into or branches an existing `Fact`, with provenance in `FactSource`, entity links in `FactSubject` and document links in `FactContent` (to smrt-content `Content`). Extraction pipelines: smrt-ingestion owns sources, extraction attempts, proposals, review and execution; server-only services are under its `/server` subpath and generated mutation routes are disabled.
|
|
44
|
+
|
|
45
|
+
# Why not hand-roll it
|
|
46
|
+
|
|
47
|
+
`FactCollection.reconcile()` in `facts.ts` serializes under a PostgreSQL advisory lock keyed on the reconciliation identity and applies three zones over embedding similarity: at or above 0.85 merge (add a source, bump `sourceCount`), between 0.60 and 0.85 a typed decision or AI disambiguation, below 0.60 create.[^s1] In core, `findSimilarToEmbedding()` runs the tenant interceptor's list prefilter and ranks only that tenant's ids through `EmbeddingStorage.searchSimilar(..., { objectIds })`, where an empty id set returns no results rather than falling through to an unrestricted search, because `_smrt_embeddings` has no tenant column.[^s2][^s3] The ingestion package requires a tenant and confidentiality scope on every record and keeps analysis input, attempts, proposals and decisions append-only.[^s4] A hand-rolled vector search ranks across tenants first and filters afterwards, which both leaks and truncates.
|
|
48
|
+
|
|
49
|
+
# Component pages
|
|
50
|
+
|
|
51
|
+
- [smrt-facts](/components/smrt-facts.md)
|
|
52
|
+
- [smrt-content](/components/smrt-content.md)
|
|
53
|
+
- [smrt-ingestion](/components/smrt-ingestion.md)
|
|
54
|
+
- [smrt-core](/components/smrt-core.md)
|
|
55
|
+
|
|
56
|
+
# Detection signals
|
|
57
|
+
|
|
58
|
+
- `import:@pinecone-database/pinecone`
|
|
59
|
+
- `import:pgvector`
|
|
60
|
+
- `import:minisearch`
|
|
61
|
+
- `import:flexsearch`
|
|
62
|
+
- `import:lunr`
|
|
63
|
+
- `regex:cosine_?[sS]imilarity`
|
|
64
|
+
|
|
65
|
+
[^s1]: `packages/facts/src/facts.ts` at `478ae36900`: FactCollection.reconcile.
|
|
66
|
+
[^s2]: `packages/core/src/collection.ts` at `478ae36900`: SmrtCollection.findSimilarToEmbedding, semanticSearch.
|
|
67
|
+
[^s3]: `packages/core/src/embeddings/storage.ts` at `478ae36900`: EmbeddingStorage.searchSimilar.
|
|
68
|
+
[^s4]: `packages/ingestion/AGENTS.md` at `478ae36900`: ingestion invariants.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Capability
|
|
3
|
+
title: "Secrets and configuration"
|
|
4
|
+
description: "Reach for smrt-secrets for per-tenant encrypted secrets and smrt-config for application configuration instead of raw env reads and ad-hoc encryption."
|
|
5
|
+
tags:
|
|
6
|
+
- smrt
|
|
7
|
+
- intent
|
|
8
|
+
status: draft
|
|
9
|
+
generated:
|
|
10
|
+
by: claude/smrt-4687
|
|
11
|
+
at: 2026-11-05T00:00:00Z
|
|
12
|
+
stale_after: 2027-02-03T00:00:00Z
|
|
13
|
+
audience: internal
|
|
14
|
+
evidence_level: source-inspected
|
|
15
|
+
package_version: 0.60.8
|
|
16
|
+
sources:
|
|
17
|
+
- id: s1
|
|
18
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/secrets/src/services/SecretService.ts
|
|
19
|
+
path: packages/secrets/src/services/SecretService.ts
|
|
20
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
21
|
+
title: "packages/secrets/src/services/SecretService.ts (SecretService.store)"
|
|
22
|
+
- id: s2
|
|
23
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/secrets/src/index.ts
|
|
24
|
+
path: packages/secrets/src/index.ts
|
|
25
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
26
|
+
title: "packages/secrets/src/index.ts (public exports)"
|
|
27
|
+
- id: s3
|
|
28
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/config/src/loaded-config.ts
|
|
29
|
+
path: packages/config/src/loaded-config.ts
|
|
30
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
31
|
+
title: "packages/config/src/loaded-config.ts (globalThis.__smrtConfigCache)"
|
|
32
|
+
- id: s4
|
|
33
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/config/src/index.ts
|
|
34
|
+
path: packages/config/src/index.ts
|
|
35
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
36
|
+
title: "packages/config/src/index.ts (loadConfig)"
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
# Secrets and configuration
|
|
40
|
+
|
|
41
|
+
# Entry point
|
|
42
|
+
|
|
43
|
+
Secrets: `SecretService.create({ db, ... })` from `@happyvertical/smrt-secrets`, then `store(name, value, { description, category, expiresAt })` inside a tenant context (`storeForTenant()` outside one). Values are envelope-encrypted by the @happyvertical/secrets store under a per-tenant data key, and key drift is diagnosed with `diagnoseTenantSecretKeyDrift()`. Config: `await loadConfig()` once at startup (finds `smrt.config.*`), then `getConfig()`, `getModuleConfig()` or `getPackageConfig()` from `@happyvertical/smrt-config`; `defineConfig()` types the file.[^s2][^s4]
|
|
44
|
+
|
|
45
|
+
# Why not hand-roll it
|
|
46
|
+
|
|
47
|
+
`SecretService.store()` in `SecretService.ts` looks the secret up for the current tenant only (an unscoped lookup once found another tenant's same-named row and overwrote it with an envelope encrypted under the wrong key, #1501), refuses to save over a foreign row even if a lookup regresses, keys the upsert on slug plus `context = tenantId` so tenants can reuse names, and writes a `SecretAuditLog` row for create, update and failure alike, classifying tenant-key failures.[^s1] For config, `loaded-config.ts` keeps the parsed config on `globalThis.__smrtConfigCache` so every module instance, including pnpm workspace packages loaded from different paths, sees the same object.[^s3] Raw `process.env` reads and home-made AES have no tenant boundary, rotation or audit trail.
|
|
48
|
+
|
|
49
|
+
# Component pages
|
|
50
|
+
|
|
51
|
+
- [smrt-secrets](/components/smrt-secrets.md)
|
|
52
|
+
- [smrt-config](/components/smrt-config.md)
|
|
53
|
+
|
|
54
|
+
# Detection signals
|
|
55
|
+
|
|
56
|
+
- `import:dotenv`
|
|
57
|
+
- `import:node-vault`
|
|
58
|
+
- `import:cosmiconfig`
|
|
59
|
+
- `import:convict`
|
|
60
|
+
- `regex:process\.env\.\w*SECRET`
|
|
61
|
+
- `regex:createCipheriv\(`
|
|
62
|
+
|
|
63
|
+
[^s1]: `packages/secrets/src/services/SecretService.ts` at `478ae36900`: SecretService.store.
|
|
64
|
+
[^s2]: `packages/secrets/src/index.ts` at `478ae36900`: public exports.
|
|
65
|
+
[^s3]: `packages/config/src/loaded-config.ts` at `478ae36900`: globalThis.__smrtConfigCache.
|
|
66
|
+
[^s4]: `packages/config/src/index.ts` at `478ae36900`: loadConfig.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Capability
|
|
3
|
+
title: "Tenant scoping and cross-tenant reads"
|
|
4
|
+
description: "Reach for smrt-tenancy and the core allowCrossTenant opt-in instead of filtering by tenant_id by hand."
|
|
5
|
+
tags:
|
|
6
|
+
- smrt
|
|
7
|
+
- intent
|
|
8
|
+
status: draft
|
|
9
|
+
generated:
|
|
10
|
+
by: claude/smrt-4687
|
|
11
|
+
at: 2026-11-05T00:00:00Z
|
|
12
|
+
stale_after: 2027-02-03T00:00:00Z
|
|
13
|
+
audience: internal
|
|
14
|
+
evidence_level: source-inspected
|
|
15
|
+
package_version: 0.60.8
|
|
16
|
+
sources:
|
|
17
|
+
- id: s1
|
|
18
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/tenancy/src/interceptor.ts
|
|
19
|
+
path: packages/tenancy/src/interceptor.ts
|
|
20
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
21
|
+
title: "packages/tenancy/src/interceptor.ts (createTenantInterceptor, rawQueryPolicy)"
|
|
22
|
+
- id: s2
|
|
23
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/tenancy/src/index.ts
|
|
24
|
+
path: packages/tenancy/src/index.ts
|
|
25
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
26
|
+
title: "packages/tenancy/src/index.ts (withTenant, withSystemContext, queryGlobal, queryWithGlobals)"
|
|
27
|
+
- id: s3
|
|
28
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/core/src/object.ts
|
|
29
|
+
path: packages/core/src/object.ts
|
|
30
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
31
|
+
title: "packages/core/src/object.ts (SmrtObject.assertRelatedTenant, allowCrossTenant)"
|
|
32
|
+
- id: s4
|
|
33
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/core/src/collection.ts
|
|
34
|
+
path: packages/core/src/collection.ts
|
|
35
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
36
|
+
title: "packages/core/src/collection.ts (SmrtCollection.findSimilarToEmbedding tenant prefilter)"
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
# Tenant scoping and cross-tenant reads
|
|
40
|
+
|
|
41
|
+
# Entry point
|
|
42
|
+
|
|
43
|
+
Import from `@happyvertical/smrt-tenancy`. Declare a model with `@TenantScoped({ mode })` and a `@tenantId()` field, call `enableTenancy()` once at startup, and run request work inside `withTenant({ tenantId }, fn)` (adapters: `createSvelteKitHandle`, `createExpressMiddleware`, `createCliContext`). Collections then filter by tenant automatically. Read shared rows with `queryWithGlobals()`/`queryGlobal()`, use `withSystemContext()` only for reviewed system work, and opt into a cross-tenant relationship load with `{ allowCrossTenant: true }` on `loadRelated`/`getRelated` (core).[^s2]
|
|
44
|
+
|
|
45
|
+
# Why not hand-roll it
|
|
46
|
+
|
|
47
|
+
A hand-written `WHERE tenant_id = ?` covers only the query you wrote. The interceptor in `interceptor.ts` throws `TenantIsolationError` for any raw SQL against a tenant-scoped class unless the call passes `allowRawOnTenantScoped` (default `rawQueryPolicy: 'throw'`).[^s1] In core, `SmrtObject.assertRelatedTenant()` makes relationship loads, including cache hits from an earlier eager load, throw on a cross-tenant reference, and only the exact value `allowCrossTenant === true` bypasses it, not a truthy value from untyped callers (#1321).[^s3] Semantic search runs the tenant interceptor's list prefilter first and ranks only that tenant's ids, because the embeddings table has no tenant column.[^s4]
|
|
48
|
+
|
|
49
|
+
# Component pages
|
|
50
|
+
|
|
51
|
+
- [smrt-tenancy](/components/smrt-tenancy.md)
|
|
52
|
+
- [smrt-core](/components/smrt-core.md)
|
|
53
|
+
|
|
54
|
+
# Detection signals
|
|
55
|
+
|
|
56
|
+
- `regex:WHERE\s+tenant_id`
|
|
57
|
+
- `regex:tenant_?[iI]d\s*=\s*\?`
|
|
58
|
+
- `regex:tenantId\s*[!=]==`
|
|
59
|
+
|
|
60
|
+
[^s1]: `packages/tenancy/src/interceptor.ts` at `478ae36900`: createTenantInterceptor, rawQueryPolicy.
|
|
61
|
+
[^s2]: `packages/tenancy/src/index.ts` at `478ae36900`: withTenant, withSystemContext, queryGlobal, queryWithGlobals.
|
|
62
|
+
[^s3]: `packages/core/src/object.ts` at `478ae36900`: SmrtObject.assertRelatedTenant, allowCrossTenant.
|
|
63
|
+
[^s4]: `packages/core/src/collection.ts` at `478ae36900`: SmrtCollection.findSimilarToEmbedding tenant prefilter.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Capability
|
|
3
|
+
title: "Webhooks and events"
|
|
4
|
+
description: "Reach for smrt-webhooks for outbound signed delivery and the core DispatchBus for in-process events; there is no generic inbound webhook receiver at this revision."
|
|
5
|
+
tags:
|
|
6
|
+
- smrt
|
|
7
|
+
- intent
|
|
8
|
+
status: draft
|
|
9
|
+
generated:
|
|
10
|
+
by: claude/smrt-4687
|
|
11
|
+
at: 2026-11-05T00:00:00Z
|
|
12
|
+
stale_after: 2027-02-03T00:00:00Z
|
|
13
|
+
audience: internal
|
|
14
|
+
evidence_level: source-inspected
|
|
15
|
+
package_version: 0.60.8
|
|
16
|
+
sources:
|
|
17
|
+
- id: s1
|
|
18
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/webhooks/src/security.ts
|
|
19
|
+
path: packages/webhooks/src/security.ts
|
|
20
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
21
|
+
title: "packages/webhooks/src/security.ts (assertWebhookUrl, assertHmacSecret, sendPublicWebhook)"
|
|
22
|
+
- id: s2
|
|
23
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/webhooks/src/dispatcher.ts
|
|
24
|
+
path: packages/webhooks/src/dispatcher.ts
|
|
25
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
26
|
+
title: "packages/webhooks/src/dispatcher.ts (WebhookDispatcher.deliver)"
|
|
27
|
+
- id: s3
|
|
28
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/core/src/dispatch/bus.ts
|
|
29
|
+
path: packages/core/src/dispatch/bus.ts
|
|
30
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
31
|
+
title: "packages/core/src/dispatch/bus.ts (DispatchBus.emit, process)"
|
|
32
|
+
- id: s4
|
|
33
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/jobs/src/forge-projection.ts
|
|
34
|
+
path: packages/jobs/src/forge-projection.ts
|
|
35
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
36
|
+
title: "packages/jobs/src/forge-projection.ts (ForgeDelivery inbox)"
|
|
37
|
+
- id: s5
|
|
38
|
+
resource: https://github.com/happyvertical/smrt/blob/478ae3690052b825b79b28235369ee7a5f6d2f20/packages/events/package.json
|
|
39
|
+
path: packages/events/package.json
|
|
40
|
+
source_revision: 478ae3690052b825b79b28235369ee7a5f6d2f20
|
|
41
|
+
title: "packages/events/package.json (description)"
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
# Webhooks and events
|
|
45
|
+
|
|
46
|
+
# Entry point
|
|
47
|
+
|
|
48
|
+
Outbound: `@happyvertical/smrt-webhooks` is server-only. Subscribers are `WebhookSubscription` rows managed through `WebhookAdminService`; publish from the change feed with `WebhookChangeFeed` (preferred) or `registerWebhookModelEvents()` (never both for one model), and run deliveries with `runWebhookDeliveryJob` on the smrt-jobs queue. In-process events: `createDispatchBus()` / `DispatchBus` (`emit()`, `on()`, `subscribe()`, `process()`) in `@happyvertical/smrt-core`. Corrections to the expected home: [smrt-events](/components/smrt-events.md) is the calendar and event-hierarchy model, not an event bus; and no package provides a generic inbound webhook receiver at this revision. The closest inbound pattern is the provider-neutral forge delivery inbox in smrt-jobs (`ForgeDelivery`, `ForgeProjectionRuntime`).[^s4][^s5]
|
|
49
|
+
|
|
50
|
+
# Why not hand-roll it
|
|
51
|
+
|
|
52
|
+
`sendPublicWebhook()` in `security.ts` validates every DNS answer as a public address, pins the socket lookup to the validated answer so a second resolution cannot rebind, follows no redirects, uses no proxy or pooled sockets, and bounds DNS (5 s) and request (10 s) time; `assertWebhookUrl()` rejects non-HTTPS, ports other than 443, embedded credentials and localhost, and `assertHmacSecret()` requires a 32 to 4096 byte secret.[^s1] `WebhookDispatcher.deliver()` signs `timestamp.payload` with HMAC-SHA256 over the exact stored bytes and sends a stable `x-smrt-delivery` id because HTTP delivery is at-least-once and receivers must deduplicate.[^s2] `DispatchBus` derives the tenant server-side from the active context and claims a dispatch with a conditional UPDATE on `status = 'pending'`, so a subscriber in one tenant cannot see another tenant's dispatches.[^s3]
|
|
53
|
+
|
|
54
|
+
# Component pages
|
|
55
|
+
|
|
56
|
+
- [smrt-webhooks](/components/smrt-webhooks.md)
|
|
57
|
+
- [smrt-core](/components/smrt-core.md)
|
|
58
|
+
- [smrt-jobs](/components/smrt-jobs.md)
|
|
59
|
+
- [smrt-events](/components/smrt-events.md)
|
|
60
|
+
|
|
61
|
+
# Detection signals
|
|
62
|
+
|
|
63
|
+
- `import:svix`
|
|
64
|
+
- `regex:createHmac\(`
|
|
65
|
+
- `regex:x-[a-z-]*signature`
|
|
66
|
+
|
|
67
|
+
[^s1]: `packages/webhooks/src/security.ts` at `478ae36900`: assertWebhookUrl, assertHmacSecret, sendPublicWebhook.
|
|
68
|
+
[^s2]: `packages/webhooks/src/dispatcher.ts` at `478ae36900`: WebhookDispatcher.deliver.
|
|
69
|
+
[^s3]: `packages/core/src/dispatch/bus.ts` at `478ae36900`: DispatchBus.emit, process.
|
|
70
|
+
[^s4]: `packages/jobs/src/forge-projection.ts` at `478ae36900`: ForgeDelivery inbox.
|
|
71
|
+
[^s5]: `packages/events/package.json` at `478ae36900`: description.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { KnowledgeIssue } from './index.js';
|
|
2
|
+
export declare const OKF_BUNDLE_FORMAT = "smrt-okf-bundle/1";
|
|
3
|
+
export declare const OKF_BUNDLE_DIR_NAME = "smrt-knowledge";
|
|
4
|
+
export declare const OKF_BUNDLE_MANIFEST = "bundle.json";
|
|
5
|
+
/** Project-relative directories a bundle may live under (`docs:agents`, `docs:claude`). */
|
|
6
|
+
export declare const OKF_BUNDLE_PARENT_DIRS: readonly [".agents", ".claude"];
|
|
7
|
+
/** File a published package ships its component page as, next to `smrt-knowledge.json`. */
|
|
8
|
+
export declare const OKF_SHIPPED_COMPONENT_PAGE = "smrt-knowledge.okf.md";
|
|
9
|
+
/** Directory under a home package's `dist/` that ships the full intent pages. */
|
|
10
|
+
export declare const OKF_SHIPPED_INTENTS_DIR = "knowledge/intents";
|
|
11
|
+
/**
|
|
12
|
+
* Packages that ship the full intent set: `smrt-cli` (the `docs:agents` export
|
|
13
|
+
* source) and this package (the trusted duplicate-detection index, #4690).
|
|
14
|
+
* Mirrored by `INTENT_HOME_PACKAGES` in `scripts/ship-knowledge-pages.mjs`.
|
|
15
|
+
*/
|
|
16
|
+
export declare const OKF_INTENT_HOME_PACKAGES: readonly ["@happyvertical/smrt-cli", "@happyvertical/smrt-dev-mcp"];
|
|
17
|
+
/** Bundles older than this draw a warning even when every version matches. */
|
|
18
|
+
export declare const OKF_BUNDLE_MAX_AGE_DAYS = 90;
|
|
19
|
+
export interface OkfBundlePackage {
|
|
20
|
+
/** Full package name, e.g. `@happyvertical/smrt-jobs`. */
|
|
21
|
+
name: string;
|
|
22
|
+
/** Installed version at export time; equals the page's `package_version`. */
|
|
23
|
+
version: string;
|
|
24
|
+
/** Concept ID of the exported page, e.g. `/components/smrt-jobs.md`. */
|
|
25
|
+
concept: string;
|
|
26
|
+
}
|
|
27
|
+
export interface OkfBundleManifest {
|
|
28
|
+
format: typeof OKF_BUNDLE_FORMAT;
|
|
29
|
+
exportedBy: string;
|
|
30
|
+
/**
|
|
31
|
+
* First export of this exact content. Re-running `docs:agents` with nothing
|
|
32
|
+
* changed keeps it, so the committed bundle does not churn.
|
|
33
|
+
*/
|
|
34
|
+
exportedAt: string;
|
|
35
|
+
/** `sha256:` over the exported pages and package versions. */
|
|
36
|
+
contentHash: string;
|
|
37
|
+
packages: OkfBundlePackage[];
|
|
38
|
+
/** Exported intent slugs. */
|
|
39
|
+
intents: string[];
|
|
40
|
+
}
|
|
41
|
+
/** Reads a top-level scalar from a page's YAML frontmatter, unquoted. */
|
|
42
|
+
export declare function readFrontmatterScalar(page: string, key: string): string | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Sets `package_version` in a page's frontmatter, leaving every other field
|
|
45
|
+
* byte-identical. The value is quoted when the page quotes its scalars.
|
|
46
|
+
*/
|
|
47
|
+
export declare function stampPackageVersion(page: string, version: string): string;
|
|
48
|
+
export declare function readOkfBundleManifest(bundleDir: string): OkfBundleManifest | null;
|
|
49
|
+
export interface OkfBundleFreshnessOptions {
|
|
50
|
+
now?: Date;
|
|
51
|
+
maxAgeDays?: number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Reports each exported bundle's age and whether it still matches
|
|
55
|
+
* `node_modules`. Drift is `stale-okf-bundle`, which the caller downgrades to a
|
|
56
|
+
* warning outside strict mode like every other `stale-*` finding; the age is an
|
|
57
|
+
* `info` line, escalating to `okf-bundle-aged` past the age limit. Projects
|
|
58
|
+
* without an exported bundle yield nothing.
|
|
59
|
+
*/
|
|
60
|
+
export declare function checkOkfBundleFreshness(rootDir: string, options?: OkfBundleFreshnessOptions): KnowledgeIssue[];
|
|
61
|
+
//# sourceMappingURL=okf-bundle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"okf-bundle.d.ts","sourceRoot":"","sources":["../../src/knowledge/okf-bundle.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,eAAO,MAAM,iBAAiB,sBAAsB,CAAC;AACrD,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AACpD,eAAO,MAAM,mBAAmB,gBAAgB,CAAC;AACjD,2FAA2F;AAC3F,eAAO,MAAM,sBAAsB,iCAAkC,CAAC;AACtE,2FAA2F;AAC3F,eAAO,MAAM,0BAA0B,0BAA0B,CAAC;AAClE,iFAAiF;AACjF,eAAO,MAAM,uBAAuB,sBAAsB,CAAC;AAC3D;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,qEAG3B,CAAC;AACX,8EAA8E;AAC9E,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAE1C,MAAM,WAAW,gBAAgB;IAC/B,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,OAAO,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,OAAO,iBAAiB,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,6BAA6B;IAC7B,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAID,yEAAyE;AACzE,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GACV,MAAM,GAAG,SAAS,CAOpB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAWzE;AAED,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,GAChB,iBAAiB,GAAG,IAAI,CAY1B;AAwBD,MAAM,WAAW,yBAAyB;IACxC,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,yBAA8B,GACtC,cAAc,EAAE,CAwGlB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as TOOLS } from "./tool-catalog-
|
|
1
|
+
import { n as TOOLS } from "./tool-catalog-BhnSCF8g.js";
|
|
2
2
|
import { existsSync, lstatSync, opendirSync, readFileSync, readdirSync, realpathSync } from "node:fs";
|
|
3
3
|
import { basename, dirname, isAbsolute, join, matchesGlob, relative, resolve, sep } from "node:path";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
@@ -178,6 +178,186 @@ function compareNames(left, right) {
|
|
|
178
178
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
179
179
|
}
|
|
180
180
|
//#endregion
|
|
181
|
+
//#region src/knowledge/okf-bundle.ts
|
|
182
|
+
/**
|
|
183
|
+
* Consumer-facing contract for the exported OKF knowledge bundle (#4689).
|
|
184
|
+
*
|
|
185
|
+
* `smrt docs:agents` writes `<dir of the output file>/smrt-knowledge/` (by
|
|
186
|
+
* default `.agents/smrt-knowledge/`) into a consumer project:
|
|
187
|
+
*
|
|
188
|
+
* bundle.json manifest (below)
|
|
189
|
+
* components/<unscoped>.md one OKF component page per installed package
|
|
190
|
+
* that ships one, `package_version` re-stamped
|
|
191
|
+
* from the installed `package.json`
|
|
192
|
+
* intents/index.md the intent index, rows limited to intents with
|
|
193
|
+
* an installed home package
|
|
194
|
+
* intents/<slug>.md those intents' pages
|
|
195
|
+
*
|
|
196
|
+
* Concept IDs keep the monorepo form (`/components/smrt-jobs.md`), resolved
|
|
197
|
+
* against the bundle directory. A link to the page of an uninstalled package
|
|
198
|
+
* dangles by design.
|
|
199
|
+
*
|
|
200
|
+
* This module owns the shape shared by the writer (`smrt-cli`) and the
|
|
201
|
+
* freshness gate (`check-knowledge-freshness` / `dev:knowledge-check`), so the
|
|
202
|
+
* two cannot drift. It has no side effects beyond reading the filesystem.
|
|
203
|
+
*/
|
|
204
|
+
var OKF_BUNDLE_FORMAT = "smrt-okf-bundle/1";
|
|
205
|
+
var OKF_BUNDLE_DIR_NAME = "smrt-knowledge";
|
|
206
|
+
var OKF_BUNDLE_MANIFEST = "bundle.json";
|
|
207
|
+
/** Project-relative directories a bundle may live under (`docs:agents`, `docs:claude`). */
|
|
208
|
+
var OKF_BUNDLE_PARENT_DIRS = [".agents", ".claude"];
|
|
209
|
+
/** File a published package ships its component page as, next to `smrt-knowledge.json`. */
|
|
210
|
+
var OKF_SHIPPED_COMPONENT_PAGE = "smrt-knowledge.okf.md";
|
|
211
|
+
/** Directory under a home package's `dist/` that ships the full intent pages. */
|
|
212
|
+
var OKF_SHIPPED_INTENTS_DIR = "knowledge/intents";
|
|
213
|
+
/**
|
|
214
|
+
* Packages that ship the full intent set: `smrt-cli` (the `docs:agents` export
|
|
215
|
+
* source) and this package (the trusted duplicate-detection index, #4690).
|
|
216
|
+
* Mirrored by `INTENT_HOME_PACKAGES` in `scripts/ship-knowledge-pages.mjs`.
|
|
217
|
+
*/
|
|
218
|
+
var OKF_INTENT_HOME_PACKAGES = ["@happyvertical/smrt-cli", "@happyvertical/smrt-dev-mcp"];
|
|
219
|
+
/** Bundles older than this draw a warning even when every version matches. */
|
|
220
|
+
var OKF_BUNDLE_MAX_AGE_DAYS = 90;
|
|
221
|
+
var FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/;
|
|
222
|
+
/** Reads a top-level scalar from a page's YAML frontmatter, unquoted. */
|
|
223
|
+
function readFrontmatterScalar(page, key) {
|
|
224
|
+
const match = FRONTMATTER.exec(page);
|
|
225
|
+
if (!match) return void 0;
|
|
226
|
+
const line = new RegExp(`^${key}:[ \\t]*(.*)$`, "m").exec(match[1]);
|
|
227
|
+
if (!line) return void 0;
|
|
228
|
+
return line[1].trim().replace(/^(["'])(.*)\1$/, "$2");
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Sets `package_version` in a page's frontmatter, leaving every other field
|
|
232
|
+
* byte-identical. The value is quoted when the page quotes its scalars.
|
|
233
|
+
*/
|
|
234
|
+
function stampPackageVersion(page, version) {
|
|
235
|
+
const match = FRONTMATTER.exec(page);
|
|
236
|
+
if (!match) return page;
|
|
237
|
+
const front = match[1];
|
|
238
|
+
const existing = /^package_version:[ \t]*(["']?).*$/m.exec(front);
|
|
239
|
+
const quote = existing?.[1] ?? "\"";
|
|
240
|
+
const line = `package_version: ${quote}${version}${quote}`;
|
|
241
|
+
const nextFront = existing ? front.replace(/^package_version:.*$/m, line) : `${front}\n${line}`;
|
|
242
|
+
return page.replace(front, nextFront);
|
|
243
|
+
}
|
|
244
|
+
function readOkfBundleManifest(bundleDir) {
|
|
245
|
+
const path = join(bundleDir, OKF_BUNDLE_MANIFEST);
|
|
246
|
+
if (!existsSync(path)) return null;
|
|
247
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
248
|
+
if (parsed?.format !== "smrt-okf-bundle/1" || !Array.isArray(parsed.packages) || typeof parsed.exportedAt !== "string") throw new Error(`unrecognised bundle manifest format in ${path}`);
|
|
249
|
+
return parsed;
|
|
250
|
+
}
|
|
251
|
+
function installedVersion(rootDir, name) {
|
|
252
|
+
const path = join(rootDir, "node_modules", name, "package.json");
|
|
253
|
+
if (!existsSync(path)) return void 0;
|
|
254
|
+
try {
|
|
255
|
+
const version = JSON.parse(readFileSync(path, "utf8")).version;
|
|
256
|
+
return typeof version === "string" ? version : void 0;
|
|
257
|
+
} catch {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/** Installed `@happyvertical/*` packages whose published artifact ships a page. */
|
|
262
|
+
function installedPackagesShippingPages(rootDir) {
|
|
263
|
+
const scopeDir = join(rootDir, "node_modules", "@happyvertical");
|
|
264
|
+
if (!existsSync(scopeDir)) return [];
|
|
265
|
+
return readdirSync(scopeDir).filter((entry) => existsSync(join(scopeDir, entry, "dist", OKF_SHIPPED_COMPONENT_PAGE))).map((entry) => `@happyvertical/${entry}`);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Reports each exported bundle's age and whether it still matches
|
|
269
|
+
* `node_modules`. Drift is `stale-okf-bundle`, which the caller downgrades to a
|
|
270
|
+
* warning outside strict mode like every other `stale-*` finding; the age is an
|
|
271
|
+
* `info` line, escalating to `okf-bundle-aged` past the age limit. Projects
|
|
272
|
+
* without an exported bundle yield nothing.
|
|
273
|
+
*/
|
|
274
|
+
function checkOkfBundleFreshness(rootDir, options = {}) {
|
|
275
|
+
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
276
|
+
const maxAgeDays = options.maxAgeDays ?? 90;
|
|
277
|
+
const issues = [];
|
|
278
|
+
for (const parent of OKF_BUNDLE_PARENT_DIRS) {
|
|
279
|
+
const bundleDir = join(rootDir, parent, OKF_BUNDLE_DIR_NAME);
|
|
280
|
+
const where = relative(rootDir, bundleDir);
|
|
281
|
+
let manifest;
|
|
282
|
+
try {
|
|
283
|
+
manifest = readOkfBundleManifest(bundleDir);
|
|
284
|
+
} catch (error) {
|
|
285
|
+
issues.push({
|
|
286
|
+
severity: "warning",
|
|
287
|
+
code: "okf-bundle-invalid",
|
|
288
|
+
message: `Exported OKF bundle manifest is unreadable (${error instanceof Error ? error.message : String(error)}). Rerun \`smrt docs:agents\`.`,
|
|
289
|
+
file: join(where, OKF_BUNDLE_MANIFEST)
|
|
290
|
+
});
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (!manifest) continue;
|
|
294
|
+
const exportedMs = Date.parse(manifest.exportedAt);
|
|
295
|
+
const ageDays = Number.isNaN(exportedMs) ? void 0 : Math.max(0, Math.floor((now.getTime() - exportedMs) / 864e5));
|
|
296
|
+
const summary = `${manifest.packages.length} package page(s), ${manifest.intents.length} intent page(s), exported ${manifest.exportedAt}`;
|
|
297
|
+
if (ageDays === void 0) issues.push({
|
|
298
|
+
severity: "warning",
|
|
299
|
+
code: "okf-bundle-invalid",
|
|
300
|
+
message: `Exported OKF bundle has an invalid exportedAt (${manifest.exportedAt}). Rerun \`smrt docs:agents\`.`,
|
|
301
|
+
file: join(where, OKF_BUNDLE_MANIFEST)
|
|
302
|
+
});
|
|
303
|
+
else if (ageDays > maxAgeDays) issues.push({
|
|
304
|
+
severity: "warning",
|
|
305
|
+
code: "okf-bundle-aged",
|
|
306
|
+
message: `Exported OKF bundle is ${ageDays} days old (limit ${maxAgeDays}; ${summary}). Rerun \`smrt docs:agents\`.`,
|
|
307
|
+
file: join(where, OKF_BUNDLE_MANIFEST)
|
|
308
|
+
});
|
|
309
|
+
else issues.push({
|
|
310
|
+
severity: "info",
|
|
311
|
+
code: "okf-bundle-age",
|
|
312
|
+
message: `Exported OKF bundle is ${ageDays} day(s) old (${summary}).`,
|
|
313
|
+
file: join(where, OKF_BUNDLE_MANIFEST)
|
|
314
|
+
});
|
|
315
|
+
const exported = /* @__PURE__ */ new Set();
|
|
316
|
+
for (const entry of manifest.packages) {
|
|
317
|
+
exported.add(entry.name);
|
|
318
|
+
const pagePath = join(bundleDir, entry.concept.replace(/^\/+/, ""));
|
|
319
|
+
const pageFile = join(where, entry.concept.replace(/^\/+/, ""));
|
|
320
|
+
const stamped = existsSync(pagePath) ? readFrontmatterScalar(readFileSync(pagePath, "utf8"), "package_version") : void 0;
|
|
321
|
+
if (stamped === void 0) {
|
|
322
|
+
issues.push({
|
|
323
|
+
severity: "error",
|
|
324
|
+
code: "stale-okf-bundle",
|
|
325
|
+
message: `Exported OKF page for ${entry.name} is missing or has no package_version. Rerun \`smrt docs:agents\`.`,
|
|
326
|
+
file: pageFile,
|
|
327
|
+
packageName: entry.name
|
|
328
|
+
});
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
const installed = installedVersion(rootDir, entry.name);
|
|
332
|
+
if (installed === void 0) issues.push({
|
|
333
|
+
severity: "error",
|
|
334
|
+
code: "stale-okf-bundle",
|
|
335
|
+
message: `Exported OKF page for ${entry.name} (${stamped}) but the package is no longer installed. Rerun \`smrt docs:agents\`.`,
|
|
336
|
+
file: pageFile,
|
|
337
|
+
packageName: entry.name
|
|
338
|
+
});
|
|
339
|
+
else if (installed !== stamped) issues.push({
|
|
340
|
+
severity: "error",
|
|
341
|
+
code: "stale-okf-bundle",
|
|
342
|
+
message: `Exported OKF page for ${entry.name} is stamped ${stamped} but ${installed} is installed. Rerun \`smrt docs:agents\`.`,
|
|
343
|
+
file: pageFile,
|
|
344
|
+
packageName: entry.name
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
for (const name of installedPackagesShippingPages(rootDir)) {
|
|
348
|
+
if (exported.has(name)) continue;
|
|
349
|
+
issues.push({
|
|
350
|
+
severity: "error",
|
|
351
|
+
code: "stale-okf-bundle",
|
|
352
|
+
message: `${name} is installed and ships a knowledge page the exported OKF bundle does not include. Rerun \`smrt docs:agents\`.`,
|
|
353
|
+
file: join(where, OKF_BUNDLE_MANIFEST),
|
|
354
|
+
packageName: name
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return issues;
|
|
359
|
+
}
|
|
360
|
+
//#endregion
|
|
181
361
|
//#region src/knowledge/index.ts
|
|
182
362
|
var SDK_PACKAGE_NAMES = /* @__PURE__ */ new Set([
|
|
183
363
|
"@happyvertical/ai",
|
|
@@ -514,6 +694,7 @@ async function checkKnowledgeFreshnessFromIndex(index, options = {}) {
|
|
|
514
694
|
if (devMcpPackage) issues.push(...checkMcpToolDocumentation(index.rootDir, devMcpPackage.directory, TOOLS));
|
|
515
695
|
issues.push(...findAgentSurfaceDriftIssues(authoredPackages));
|
|
516
696
|
issues.push(...findKnowledgeGraphIssues(index.rootDir));
|
|
697
|
+
issues.push(...checkOkfBundleFreshness(index.rootDir));
|
|
517
698
|
issues.push(...findStalePatternIssues(index.rootDir, changedFiles));
|
|
518
699
|
issues.push(...findNumericPrecisionIssues(index, authoredPackages, changedFiles));
|
|
519
700
|
const effectiveIssues = issues.map((issue) => issue.code.startsWith("stale-") ? {
|
|
@@ -1416,14 +1597,46 @@ function readKnowledgePackage(rootDir, directory, includeDocs, options = {}) {
|
|
|
1416
1597
|
checkedObjectPaths: resolvedObjects.checkedPaths
|
|
1417
1598
|
};
|
|
1418
1599
|
}
|
|
1600
|
+
/**
|
|
1601
|
+
* Artifact locations a package declares through its own export map: a direct
|
|
1602
|
+
* `./smrt-knowledge.json` target, and the directory of its `./manifest.json`
|
|
1603
|
+
* target (the Vite plugin writes both artifacts beside each other in the
|
|
1604
|
+
* library `outDir`). A package that builds its library into `dist/lib` and
|
|
1605
|
+
* maps `"./manifest.json": "./dist/lib/manifest.json"` (#2923) is otherwise
|
|
1606
|
+
* invisible to the conventional probes below, and the index silently falls
|
|
1607
|
+
* back to the scanner view — which a turbo cache replay (`dist/**` restored,
|
|
1608
|
+
* `.smrt/` not) turns into a gate that depends on cache state.
|
|
1609
|
+
*/
|
|
1610
|
+
function exportedArtifactCandidates(directory) {
|
|
1611
|
+
const exportsMap = objectRecord(objectRecord(readJson(join(directory, "package.json"))).exports);
|
|
1612
|
+
const target = (subpath) => {
|
|
1613
|
+
const entry = exportsMap[subpath];
|
|
1614
|
+
const value = typeof entry === "string" ? entry : [
|
|
1615
|
+
"smrt",
|
|
1616
|
+
"node",
|
|
1617
|
+
"import",
|
|
1618
|
+
"default"
|
|
1619
|
+
].map((condition) => objectRecord(entry)[condition]).find((candidate) => typeof candidate === "string");
|
|
1620
|
+
return typeof value === "string" && value.startsWith("./") ? join(directory, value) : void 0;
|
|
1621
|
+
};
|
|
1622
|
+
const knowledge = target("./smrt-knowledge.json");
|
|
1623
|
+
const manifest = target("./manifest.json") ?? target("./manifest");
|
|
1624
|
+
return {
|
|
1625
|
+
knowledge: [...knowledge ? [knowledge] : [], ...manifest ? [join(dirname(manifest), "smrt-knowledge.json")] : []],
|
|
1626
|
+
manifest: manifest ? [manifest] : []
|
|
1627
|
+
};
|
|
1628
|
+
}
|
|
1419
1629
|
/** Artifact paths consulted for a package's objects, in precedence order. */
|
|
1420
1630
|
function objectArtifactCandidates(directory) {
|
|
1631
|
+
const exported = exportedArtifactCandidates(directory);
|
|
1421
1632
|
return [
|
|
1422
1633
|
join(directory, ".smrt", "smrt-knowledge.json"),
|
|
1634
|
+
...exported.knowledge,
|
|
1423
1635
|
join(directory, "dist", "smrt-knowledge.json"),
|
|
1424
1636
|
join(directory, "src", "manifest", "smrt-knowledge.json"),
|
|
1425
1637
|
join(directory, "src", "manifest", "manifest.json"),
|
|
1426
1638
|
join(directory, ".smrt", "manifest.json"),
|
|
1639
|
+
...exported.manifest,
|
|
1427
1640
|
join(directory, "dist", "manifest.json")
|
|
1428
1641
|
];
|
|
1429
1642
|
}
|
|
@@ -1537,6 +1750,7 @@ function messageFromError(error) {
|
|
|
1537
1750
|
function readDomainKnowledge(directory) {
|
|
1538
1751
|
for (const path of [
|
|
1539
1752
|
join(directory, ".smrt", "smrt-knowledge.json"),
|
|
1753
|
+
...exportedArtifactCandidates(directory).knowledge,
|
|
1540
1754
|
join(directory, "dist", "smrt-knowledge.json"),
|
|
1541
1755
|
join(directory, "src", "manifest", "smrt-knowledge.json")
|
|
1542
1756
|
]) {
|
|
@@ -1557,6 +1771,7 @@ function readManifest(directory) {
|
|
|
1557
1771
|
for (const path of [
|
|
1558
1772
|
join(directory, "src", "manifest", "manifest.json"),
|
|
1559
1773
|
join(directory, ".smrt", "manifest.json"),
|
|
1774
|
+
...exportedArtifactCandidates(directory).manifest,
|
|
1560
1775
|
join(directory, "dist", "manifest.json")
|
|
1561
1776
|
]) {
|
|
1562
1777
|
const content = readJson(path);
|
|
@@ -2725,6 +2940,6 @@ function gitignoredTopLevelEntries(directory) {
|
|
|
2725
2940
|
return ignored;
|
|
2726
2941
|
}
|
|
2727
2942
|
//#endregion
|
|
2728
|
-
export { buildReviewContext as a, compactContextResult as c, packageDocPaths as d, renderFreshnessResult as f, smrtReview as h, buildPackageSpecialistContext as i, coreCompatibleToSnakeCase as l, smrtArchitecture as m, buildContext as n, checkKnowledgeFreshness as o, renderKnowledgeIndexMarkdown as p, buildKnowledgeIndex as r, checkKnowledgeFreshnessFromIndex as s, buildArchitectureContext as t, diffKnowledgeIndex as u };
|
|
2943
|
+
export { OKF_SHIPPED_INTENTS_DIR as C, stampPackageVersion as D, readOkfBundleManifest as E, OKF_SHIPPED_COMPONENT_PAGE as S, readFrontmatterScalar as T, OKF_BUNDLE_FORMAT as _, buildReviewContext as a, OKF_BUNDLE_PARENT_DIRS as b, compactContextResult as c, packageDocPaths as d, renderFreshnessResult as f, OKF_BUNDLE_DIR_NAME as g, smrtReview as h, buildPackageSpecialistContext as i, coreCompatibleToSnakeCase as l, smrtArchitecture as m, buildContext as n, checkKnowledgeFreshness as o, renderKnowledgeIndexMarkdown as p, buildKnowledgeIndex as r, checkKnowledgeFreshnessFromIndex as s, buildArchitectureContext as t, diffKnowledgeIndex as u, OKF_BUNDLE_MANIFEST as v, checkOkfBundleFreshness as w, OKF_INTENT_HOME_PACKAGES as x, OKF_BUNDLE_MAX_AGE_DAYS as y };
|
|
2729
2944
|
|
|
2730
|
-
//# sourceMappingURL=knowledge-
|
|
2945
|
+
//# sourceMappingURL=knowledge-DUiMUjEg.js.map
|