@remnic/core 9.3.751 → 9.3.753
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/dist/access-admin-ops-surface.d.ts +194 -0
- package/dist/access-admin-ops-surface.js +128 -0
- package/dist/access-boundary.d.ts +5 -5
- package/dist/access-boundary.js +30 -30
- package/dist/access-cli.js +92 -92
- package/dist/access-http.d.ts +5 -5
- package/dist/access-http.js +38 -38
- package/dist/access-mcp.d.ts +5 -5
- package/dist/access-mcp.js +35 -35
- package/dist/access-operations-batch.js +32 -32
- package/dist/access-operations.d.ts +11 -11
- package/dist/access-operations.js +34 -34
- package/dist/access-recall-surface.d.ts +363 -0
- package/dist/access-recall-surface.js +128 -0
- package/dist/access-schema.d.ts +116 -116
- package/dist/access-schema.js +8 -8
- package/dist/{access-service-DmAEOJdJ.d.ts → access-service-MitduesD.d.ts} +75 -118
- package/dist/access-service.d.ts +5 -5
- package/dist/access-service.js +33 -29
- package/dist/access-surface-catalog.d.ts +5 -5
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +6 -6
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +4 -4
- package/dist/briefing.d.ts +3 -3
- package/dist/briefing.js +10 -10
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +3 -3
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-CZJSLEFG.js} +3 -3
- package/dist/capsule-crypto-CZJSLEFG.js.map +1 -0
- package/dist/{catalog-BpOcwHdE.d.ts → catalog-BEmNVRN0.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +15 -15
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-6SXNQFHB.js → chunk-243P7YYV.js} +7 -7
- package/dist/{chunk-2NLLXCJG.js → chunk-2BFLDH5F.js} +2 -2
- package/dist/{chunk-ZBVQ4ZM4.js → chunk-34THARMH.js} +17 -17
- package/dist/{chunk-SNEXVX3U.js → chunk-3HGZX26P.js} +21 -21
- package/dist/{chunk-5PZCDUJ6.js → chunk-3ZIKDH6C.js} +4 -4
- package/dist/{chunk-X7Y7WX73.js → chunk-437S3G37.js} +2 -2
- package/dist/{chunk-RS25QOKZ.js → chunk-64SE4X5G.js} +2 -2
- package/dist/{chunk-JBPKEARU.js → chunk-AU7Q3LSC.js} +4 -4
- package/dist/{chunk-6FNZ3NMS.js → chunk-AXBRVBT6.js} +2 -2
- package/dist/{chunk-W3BFT5OJ.js → chunk-BWOEYBRB.js} +2 -2
- package/dist/{chunk-UU32EAIY.js → chunk-C3IHRWIC.js} +7 -7
- package/dist/{chunk-DBRVU5PR.js → chunk-DKIZ4BUQ.js} +14 -14
- package/dist/{chunk-EEKDRAWX.js → chunk-DS4QM6I7.js} +4 -4
- package/dist/{chunk-WOX2UW4K.js → chunk-E3MRYDUQ.js} +2 -2
- package/dist/{chunk-K2R3DEEH.js → chunk-E6LENGYV.js} +2 -2
- package/dist/{chunk-CGZWGVQF.js → chunk-EEO4YWQ7.js} +9 -9
- package/dist/{chunk-ORAK3LNZ.js → chunk-ER3CCWK2.js} +2 -2
- package/dist/{chunk-TPLE6SNY.js → chunk-GWGWBK5Y.js} +7 -7
- package/dist/{chunk-BJMBJZ2Y.js → chunk-GWTFLF2P.js} +59 -59
- package/dist/chunk-GWTFLF2P.js.map +1 -0
- package/dist/{chunk-IKHKHADN.js → chunk-ITLJATQI.js} +5 -5
- package/dist/{chunk-E4PFDD3N.js → chunk-JES2O5Q6.js} +4 -4
- package/dist/{chunk-QOGXUNWL.js → chunk-JGPURIEH.js} +7 -7
- package/dist/{chunk-YGGXUNS4.js → chunk-KY4WOZ3P.js} +55 -55
- package/dist/{chunk-WA7FECSG.js → chunk-KYHGLDFU.js} +7 -7
- package/dist/{chunk-V5RVMULT.js → chunk-LZ73Y56P.js} +10 -10
- package/dist/{chunk-ARV3AUOM.js → chunk-M5QKGHCR.js} +2 -2
- package/dist/{chunk-SD34EK4Z.js → chunk-N3VE7OCY.js} +4 -4
- package/dist/{chunk-KQAFEZQX.js → chunk-OUXPVWTZ.js} +6 -6
- package/dist/{chunk-NNL4LJAD.js → chunk-OZMBT7N3.js} +5 -5
- package/dist/{chunk-RWZB6MAY.js → chunk-PN5AMCK2.js} +1065 -1176
- package/dist/chunk-PN5AMCK2.js.map +1 -0
- package/dist/{chunk-WWSXVOGY.js → chunk-QIRZI3C3.js} +2 -2
- package/dist/{chunk-B35L45HZ.js → chunk-TVISHYL5.js} +2 -2
- package/dist/{chunk-SQNED75R.js → chunk-V5UV7BOA.js} +1 -1
- package/dist/{chunk-7TWA7DKP.js → chunk-VVSV2QVY.js} +2 -2
- package/dist/{chunk-4NWIGAIC.js → chunk-XOPLMSVV.js} +2 -2
- package/dist/{chunk-K2JM4DZZ.js → chunk-YNBEHUZH.js} +2 -2
- package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
- package/dist/{chunk-UETBEHBA.js → chunk-ZECLLIMX.js} +3442 -3085
- package/dist/chunk-ZECLLIMX.js.map +1 -0
- package/dist/{chunk-QRRBXD24.js → chunk-ZIFPFKB2.js} +7 -7
- package/dist/{chunk-HYI2GP3F.js → chunk-ZMHDSIEX.js} +7 -7
- package/dist/{cli-lmf5RGyQ.d.ts → cli-DqonYBZ0.d.ts} +3 -3
- package/dist/cli.d.ts +6 -6
- package/dist/cli.js +64 -64
- package/dist/compounding/engine.d.ts +3 -3
- package/dist/compounding/engine.js +11 -11
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +3 -3
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +11 -11
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +12 -12
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/contradiction/index.d.ts +1 -1
- package/dist/contradiction/index.js +2 -2
- package/dist/{contradiction-scan-3FJYWS3G.js → contradiction-scan-2SODRNUF.js} +3 -3
- package/dist/contradiction-scan-2SODRNUF.js.map +1 -0
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/dashboard-runtime.js +2 -2
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +1 -1
- package/dist/entity-retrieval.js +11 -11
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +6 -6
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction.d.ts +1 -1
- package/dist/extraction.js +3 -3
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{first-start-migration-4I3VDSYS.js → first-start-migration-DY6YCRC2.js} +2 -2
- package/dist/{forget-WYLR4ZFV.js → forget-OEE5OELK.js} +2 -2
- package/dist/graph-dashboard-diff.d.ts +1 -1
- package/dist/graph-dashboard-key.d.ts +1 -1
- package/dist/graph-dashboard-parser.d.ts +1 -1
- package/dist/graph-edge-reinforcement.d.ts +1 -1
- package/dist/graph-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +1284 -1284
- package/dist/index.js +148 -148
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/engine.js +4 -4
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +8 -8
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -1
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +10 -10
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -10
- package/dist/maintenance/rebuild-memory-projection.js +11 -11
- package/dist/mcp-memory-inspector-app.d.ts +5 -5
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +1 -1
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +2 -2
- package/dist/namespaces/migrate.js +13 -13
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +1 -1
- package/dist/namespaces/storage.d.ts +2 -2
- package/dist/namespaces/storage.js +12 -12
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +19 -19
- package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
- package/dist/orchestration/maintenance.d.ts +2 -2
- package/dist/orchestration/maintenance.js +15 -15
- package/dist/{orchestrator-D7bb8ZGp.d.ts → orchestrator-D7ZGOQLX.d.ts} +101 -180
- package/dist/orchestrator.d.ts +4 -4
- package/dist/orchestrator.js +92 -92
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +1 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +3 -3
- package/dist/retrieval-agents.d.ts +1 -1
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/schemas.d.ts +100 -100
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +1 -1
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +1 -1
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/secure-store/index.js +2 -2
- package/dist/{semantic-consolidation-CTfbVwCA.d.ts → semantic-consolidation-7Sndms2M.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +13 -13
- package/dist/semantic-rule-promotion.js +10 -10
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +10 -10
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +9 -9
- package/dist/signal.d.ts +1 -1
- package/dist/storage.d.ts +1 -1
- package/dist/storage.js +9 -9
- package/dist/summarizer.d.ts +1 -1
- package/dist/summarizer.js +2 -2
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +1 -1
- package/dist/tier-routing.d.ts +1 -1
- package/dist/{tier-stats-5XF4UBRQ.js → tier-stats-TG6GUZ6N.js} +4 -4
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/autodetect.js +1 -1
- package/dist/transfer/backup.js +3 -3
- package/dist/transfer/capsule-export.js +4 -4
- package/dist/transfer/capsule-import.js +3 -3
- package/dist/transfer/types.d.ts +110 -110
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-D4NYDtXI.d.ts → types-DTEFxFuL.d.ts} +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +10 -10
- package/package.json +2 -2
- package/src/access-admin-ops-surface.ts +828 -0
- package/src/access-recall-surface.ts +1552 -0
- package/src/access-service.ts +70 -1917
- package/src/orchestration/recall-entry.ts +290 -0
- package/src/orchestration/session-context.ts +407 -0
- package/src/orchestrator.ts +125 -462
- package/dist/chunk-BJMBJZ2Y.js.map +0 -1
- package/dist/chunk-RWZB6MAY.js.map +0 -1
- package/dist/chunk-UETBEHBA.js.map +0 -1
- /package/dist/{capsule-crypto-7FJQINUR.js.map → access-admin-ops-surface.js.map} +0 -0
- /package/dist/{contradiction-scan-3FJYWS3G.js.map → access-recall-surface.js.map} +0 -0
- /package/dist/{chunk-6SXNQFHB.js.map → chunk-243P7YYV.js.map} +0 -0
- /package/dist/{chunk-2NLLXCJG.js.map → chunk-2BFLDH5F.js.map} +0 -0
- /package/dist/{chunk-ZBVQ4ZM4.js.map → chunk-34THARMH.js.map} +0 -0
- /package/dist/{chunk-SNEXVX3U.js.map → chunk-3HGZX26P.js.map} +0 -0
- /package/dist/{chunk-5PZCDUJ6.js.map → chunk-3ZIKDH6C.js.map} +0 -0
- /package/dist/{chunk-X7Y7WX73.js.map → chunk-437S3G37.js.map} +0 -0
- /package/dist/{chunk-RS25QOKZ.js.map → chunk-64SE4X5G.js.map} +0 -0
- /package/dist/{chunk-JBPKEARU.js.map → chunk-AU7Q3LSC.js.map} +0 -0
- /package/dist/{chunk-6FNZ3NMS.js.map → chunk-AXBRVBT6.js.map} +0 -0
- /package/dist/{chunk-W3BFT5OJ.js.map → chunk-BWOEYBRB.js.map} +0 -0
- /package/dist/{chunk-UU32EAIY.js.map → chunk-C3IHRWIC.js.map} +0 -0
- /package/dist/{chunk-DBRVU5PR.js.map → chunk-DKIZ4BUQ.js.map} +0 -0
- /package/dist/{chunk-EEKDRAWX.js.map → chunk-DS4QM6I7.js.map} +0 -0
- /package/dist/{chunk-WOX2UW4K.js.map → chunk-E3MRYDUQ.js.map} +0 -0
- /package/dist/{chunk-K2R3DEEH.js.map → chunk-E6LENGYV.js.map} +0 -0
- /package/dist/{chunk-CGZWGVQF.js.map → chunk-EEO4YWQ7.js.map} +0 -0
- /package/dist/{chunk-ORAK3LNZ.js.map → chunk-ER3CCWK2.js.map} +0 -0
- /package/dist/{chunk-TPLE6SNY.js.map → chunk-GWGWBK5Y.js.map} +0 -0
- /package/dist/{chunk-IKHKHADN.js.map → chunk-ITLJATQI.js.map} +0 -0
- /package/dist/{chunk-E4PFDD3N.js.map → chunk-JES2O5Q6.js.map} +0 -0
- /package/dist/{chunk-QOGXUNWL.js.map → chunk-JGPURIEH.js.map} +0 -0
- /package/dist/{chunk-YGGXUNS4.js.map → chunk-KY4WOZ3P.js.map} +0 -0
- /package/dist/{chunk-WA7FECSG.js.map → chunk-KYHGLDFU.js.map} +0 -0
- /package/dist/{chunk-V5RVMULT.js.map → chunk-LZ73Y56P.js.map} +0 -0
- /package/dist/{chunk-ARV3AUOM.js.map → chunk-M5QKGHCR.js.map} +0 -0
- /package/dist/{chunk-SD34EK4Z.js.map → chunk-N3VE7OCY.js.map} +0 -0
- /package/dist/{chunk-KQAFEZQX.js.map → chunk-OUXPVWTZ.js.map} +0 -0
- /package/dist/{chunk-NNL4LJAD.js.map → chunk-OZMBT7N3.js.map} +0 -0
- /package/dist/{chunk-WWSXVOGY.js.map → chunk-QIRZI3C3.js.map} +0 -0
- /package/dist/{chunk-B35L45HZ.js.map → chunk-TVISHYL5.js.map} +0 -0
- /package/dist/{chunk-SQNED75R.js.map → chunk-V5UV7BOA.js.map} +0 -0
- /package/dist/{chunk-7TWA7DKP.js.map → chunk-VVSV2QVY.js.map} +0 -0
- /package/dist/{chunk-4NWIGAIC.js.map → chunk-XOPLMSVV.js.map} +0 -0
- /package/dist/{chunk-K2JM4DZZ.js.map → chunk-YNBEHUZH.js.map} +0 -0
- /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
- /package/dist/{chunk-QRRBXD24.js.map → chunk-ZIFPFKB2.js.map} +0 -0
- /package/dist/{chunk-HYI2GP3F.js.map → chunk-ZMHDSIEX.js.map} +0 -0
- /package/dist/{first-start-migration-4I3VDSYS.js.map → first-start-migration-DY6YCRC2.js.map} +0 -0
- /package/dist/{forget-WYLR4ZFV.js.map → forget-OEE5OELK.js.map} +0 -0
- /package/dist/{tier-stats-5XF4UBRQ.js.map → tier-stats-TG6GUZ6N.js.map} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { PluginEntryResolverOptions, resolvePluginEntry } from './plugin-entry-resolver.js';
|
|
2
2
|
export { isOpenaiApiKeyDisabled, parseConfig, resolveEnvVars } from './config.js';
|
|
3
3
|
export { MigrationOptions, MigrationResult, RollbackResult, migrateFromEngram, rollbackFromEngramMigration } from './migrate/from-engram.js';
|
|
4
|
-
import { b as SpeakerRegistry, W as WearablesService } from './orchestrator-
|
|
5
|
-
export { D as DEFAULT_SELF_NAME, O as Orchestrator, c as ResolvedSpeaker, d as SpeakerOverride, e as WEARABLE_SOURCE_PREFIX, f as WearableDayTranscriptView, g as WearableMemoryGenDeps, h as WearableMemoryGenResult, i as WearableMemorySearchResult, j as WearableMemoryWriter, k as WearableSearchBackend, l as WearableStorageIo, m as WearableSyncDeps, n as WearableSyncOptions, o as WearableTranscriptSearchResult, p as WearablesServiceDeps, q as buildExtractionTurns, r as dateInTimezone, s as defaultTimezone, t as defaultWorkspaceDir, u as distinctSpeakerLabels, v as emptySpeakerRegistry, w as generateWearableMemories, x as importNativeMemories, y as loadSpeakerRegistry, z as locateTranscriptPath, A as memoryStatusForMode, B as resolveSpeaker, C as resolveSyncDates, E as sanitizeSessionKeyForFilename, F as saveSpeakerRegistry, H as speakerRegistryKey, J as speakersFilePath, K as syncWearableSource, L as wearableDayTag, M as wearableSourceLabel, N as writeDailyDigestMemory } from './orchestrator-
|
|
4
|
+
import { b as SpeakerRegistry, W as WearablesService } from './orchestrator-D7ZGOQLX.js';
|
|
5
|
+
export { D as DEFAULT_SELF_NAME, O as Orchestrator, c as ResolvedSpeaker, d as SpeakerOverride, e as WEARABLE_SOURCE_PREFIX, f as WearableDayTranscriptView, g as WearableMemoryGenDeps, h as WearableMemoryGenResult, i as WearableMemorySearchResult, j as WearableMemoryWriter, k as WearableSearchBackend, l as WearableStorageIo, m as WearableSyncDeps, n as WearableSyncOptions, o as WearableTranscriptSearchResult, p as WearablesServiceDeps, q as buildExtractionTurns, r as dateInTimezone, s as defaultTimezone, t as defaultWorkspaceDir, u as distinctSpeakerLabels, v as emptySpeakerRegistry, w as generateWearableMemories, x as importNativeMemories, y as loadSpeakerRegistry, z as locateTranscriptPath, A as memoryStatusForMode, B as resolveSpeaker, C as resolveSyncDates, E as sanitizeSessionKeyForFilename, F as saveSpeakerRegistry, H as speakerRegistryKey, J as speakersFilePath, K as syncWearableSource, L as wearableDayTag, M as wearableSourceLabel, N as writeDailyDigestMemory } from './orchestrator-D7ZGOQLX.js';
|
|
6
6
|
export { normalizeProjectionPreview, normalizeProjectionTags } from './memory-projection-format.js';
|
|
7
7
|
export { ModelCapabilities, ModelRegistry } from './model-registry.js';
|
|
8
8
|
export { ACTIVE_STATUSES, ContradictionFilter, ContradictionJudgeBatchResult, ContradictionJudgeInput, ContradictionJudgeResult, ContradictionListResult, ContradictionVerdict, ResolutionResult, ResolutionVerb, ScanDependencies, ScanResult, computePairId, executeResolution, isCoolingDown, isValidResolutionVerb, judgeContradictionPairs, listPairs, readPair, resolvePair, runContradictionScan, writePair, writePairs } from './contradiction/index.js';
|
|
@@ -20,11 +20,11 @@ export { CodexCliFallbackConfig, CodexCliFallbackMessage, CodexCliFallbackOption
|
|
|
20
20
|
export { BufferSurpriseProbe, SmartBuffer, TriggerDecision } from './buffer.js';
|
|
21
21
|
export { ComputeSurpriseOptions, DEFAULT_SURPRISE_K, RecentMemoryLike, computeSurprise } from './buffer-surprise.js';
|
|
22
22
|
export { BufferSurpriseDistribution, BufferSurpriseReader, BufferSurpriseReportOptions, reportBufferSurpriseDistribution } from './buffer-surprise-report.js';
|
|
23
|
-
import {
|
|
24
|
-
export {
|
|
23
|
+
import { az as CodingContext, aS as CodingModeConfig, P as PluginConfig, aT as CodingKnowledgeConfig, h as MemoryCategory, aU as WearableCleanupSettings, aF as WearableSourceSettings, aJ as WearablesConfig, aI as WearableSourceConnector, aE as WearableConversation, aN as WearableCorrectionRule, aV as WearableDayTranscriptMeta, aM as WearableDayTranscript } from './types-DTEFxFuL.js';
|
|
24
|
+
export { Z as AgentAccessAuthToken, m as BriefingActiveThread, aW as BriefingConfig, k as BriefingFocus, j as BriefingFollowup, aX as BriefingOpenCommitment, o as BriefingRecentEntity, n as BriefingResult, i as BriefingSections, aY as BriefingWindow, X as BufferSurpriseEvent, l as CalendarEvent, C as CalendarSource, aZ as CodexCompatConfig, aR as ConsolidationObservation, ab as ContinuityImprovementLoop, a_ as DEFAULT_RECALL_DISCLOSURE, E as EntityFile, a7 as EntityStructuredSection, a$ as ExtractedFact, G as GatewayConfig, ah as MemoryActionEligibilityContext, b0 as MemoryActionEligibilitySource, a1 as MemoryActionType, M as MemoryFile, q as MemoryFrontmatter, b1 as MemoryObservation, b2 as MemoryScope, b3 as RECALL_DISCLOSURE_LEVELS, R as RecallDisclosure, Y as SecretRef, b4 as WearableAuthCheck, b5 as WearableFetchOptions, b6 as WearableFetchPage, aH as WearableMemoryMode, aG as WearableNativeMemory, b7 as WearableNativeMemoryPage, aL as WearableSourceStatus, aK as WearableSyncSummary, b8 as WearableTranscriptSegment, b9 as isRecallDisclosure } from './types-DTEFxFuL.js';
|
|
25
25
|
export { JudgeBatchResult, JudgeCandidate, JudgeVerdict, JudgeVerdictKind, clearVerdictCache, createVerdictCache, getVerdictKind, isDurableVerdict, isValidCachedVerdict, judgeFactDurability, normalizeCachedVerdict, verdictCacheSize } from './extraction-judge.js';
|
|
26
26
|
export { hasBroadGraphIntent, inferIntentFromText, intentCompatibilityScore, isTaskInitiationIntent, planRecallMode } from './intent.js';
|
|
27
|
-
export {
|
|
27
|
+
export { q as EngramAccessInputError, p as EngramAccessService, P as ProcedureStatsConfigSnapshot, r as ProcedureStatsRecent, s as ProcedureStatsReport, t as ProcedureStatusCounts, u as computeProcedureStats, v as formatProcedureStatsText } from './access-service-MitduesD.js';
|
|
28
28
|
export { FILTER_LABELS as DIRECT_ANSWER_FILTER_LABELS, DirectAnswerCandidate, DirectAnswerConfig, DirectAnswerInput, DirectAnswerReason, DirectAnswerResult, isDirectAnswerEligible } from './direct-answer.js';
|
|
29
29
|
export { MemoryTier, TierRoutingPolicy, TierTransitionDecision, computeTierValueScore, decideTierTransition } from './tier-routing.js';
|
|
30
30
|
export { ApplyReasoningTraceBoostOptions, BoostableResult, DEFAULT_REASONING_TRACE_BOOST, applyReasoningTraceBoost, isReasoningTracePath, looksLikeProblemSolvingQuery } from './reasoning-trace-recall.js';
|
|
@@ -38,7 +38,7 @@ export { OramaBackend } from './search/orama-backend.js';
|
|
|
38
38
|
export { MeilisearchBackend } from './search/meilisearch-backend.js';
|
|
39
39
|
export { buildEntityRecallSection } from './entity-retrieval.js';
|
|
40
40
|
export { resolvePrincipal } from './namespaces/principal.js';
|
|
41
|
-
export { N as NamespaceCatalog, c as NamespaceCatalogFilter, d as NamespaceCatalogRebuildResult, e as NamespaceCatalogSkippedRoot, f as NamespaceDiscoverySource, b as NamespaceKind, a as NamespaceRecord, g as NamespaceTouchMetadata } from './catalog-
|
|
41
|
+
export { N as NamespaceCatalog, c as NamespaceCatalogFilter, d as NamespaceCatalogRebuildResult, e as NamespaceCatalogSkippedRoot, f as NamespaceDiscoverySource, b as NamespaceKind, a as NamespaceRecord, g as NamespaceTouchMetadata } from './catalog-BEmNVRN0.js';
|
|
42
42
|
export { SESSION_CHANNEL_TYPE, SessionIdentity, SessionStoragePaths, legacyParserReadbackDir, parseSessionIdentity, sessionStoragePaths } from './session-identity.js';
|
|
43
43
|
export { storagePathHash } from './storage-paths.js';
|
|
44
44
|
export { TrustZoneName, TrustZoneRecord, TrustZoneRecordKind, TrustZoneSourceClass, isTrustZoneName } from './trust-zones.js';
|
|
@@ -62,8 +62,8 @@ export { CitationBlock, CitationEntry, CitationMetadata, buildCitationGuidance,
|
|
|
62
62
|
export { initLogger, log } from './logger.js';
|
|
63
63
|
export { b as SemanticDedupDecision, a as SemanticDedupHit, S as SemanticDedupLookup, c as SemanticDedupOptions, d as decideSemanticDedup } from './semantic-DJR8_DMQ.js';
|
|
64
64
|
export { OFFLINE_SYNC_APPLY_MAX_BODY_BYTES, OFFLINE_SYNC_CHANGESET_FORMAT, OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES, OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES, OFFLINE_SYNC_SNAPSHOT_BASE_MAX_BODY_BYTES, OFFLINE_SYNC_SNAPSHOT_FORMAT, OFFLINE_SYNC_STATE_VERSION, OfflineSyncApplyChangesetResult, OfflineSyncApplyFileContentChunkResult, OfflineSyncApplySnapshotResult, OfflineSyncChange, OfflineSyncChangeset, OfflineSyncConflict, OfflineSyncFileContentChunk, OfflineSyncFileDigest, OfflineSyncFileRecord, OfflineSyncFileState, OfflineSyncFileTarget, OfflineSyncFileWriteTarget, OfflineSyncSnapshot, OfflineSyncState, applyOfflineSyncChangeset, applyOfflineSyncFileContentChunk, applyOfflineSyncSnapshot, buildOfflineSyncChangeset, buildOfflineSyncChangesetFromSnapshot, buildOfflineSyncSnapshot, buildOfflineSyncSnapshotForPaths, buildOfflineSyncSnapshotFromBase, compileOfflineSyncExcludeGlobs, defaultOfflineSyncStatePath, fileStatesFromSnapshot, globToRegExp, iterateOfflineSyncSnapshotFileRecords, normalizeOfflineSyncChangeset, normalizeOfflineSyncSnapshot, offlineSyncStateFromSnapshot, readOfflineSyncFileContentChunk, readOfflineSyncState, shouldPreferIncomingOfflineRuntimeFile, summarizeOfflineSyncChangeset, summarizeOfflineSyncPendingChanges, summarizeOfflineSyncPendingFiles, writeOfflineSyncState } from './offline-sync.js';
|
|
65
|
-
import { D as DiscoveredExtension } from './semantic-consolidation-
|
|
66
|
-
export { E as ExtensionSchema, R as REMNIC_EXTENSIONS_TOTAL_TOKEN_LIMIT, b as buildExtensionsBlockForConsolidation, d as discoverMemoryExtensions, r as resolveExtensionsRoot } from './semantic-consolidation-
|
|
65
|
+
import { D as DiscoveredExtension } from './semantic-consolidation-7Sndms2M.js';
|
|
66
|
+
export { E as ExtensionSchema, R as REMNIC_EXTENSIONS_TOTAL_TOKEN_LIMIT, b as buildExtensionsBlockForConsolidation, d as discoverMemoryExtensions, r as resolveExtensionsRoot } from './semantic-consolidation-7Sndms2M.js';
|
|
67
67
|
export { ConnectorCapability, ConnectorInstance, ConnectorManifest, ConnectorRegistry, DoctorCheck, DoctorResult, InstallOptions, InstallResult, MARKETPLACE_MANIFEST_FILENAME, MARKETPLACE_SCHEMA_VERSION, MarketplaceConfig, MarketplaceEntry, MarketplaceInstallResult, MarketplaceInstallType, MarketplaceLogger, MarketplaceManifest, MarketplaceValidation, RemoveResult, checkMarketplaceManifest, coerceInstallExtension, doctorConnector, generateMarketplaceManifest, getConnectorToken, installConnector, installFromMarketplace, listConnectors, loadRegistry, removeConnector, saveRegistry, validateMarketplaceManifest, writeMarketplaceManifest } from './connectors/index.js';
|
|
68
68
|
import { L as LiveConnector, S as SyncIncrementalResult } from './framework-CNDn2164.js';
|
|
69
69
|
export { c as CONNECTOR_ID_PATTERN, C as ConnectorConfig, b as ConnectorCursor, a as ConnectorDocument, d as ConnectorDocumentSource, e as SyncIncrementalArgs, i as isValidConnectorId, p as persistableConnectorConfig, r as redactConnectorConfigSecrets } from './framework-CNDn2164.js';
|
|
@@ -79,7 +79,7 @@ export { EnrichmentAuditEntry, EnrichmentCandidate, EnrichmentCostTier, Enrichme
|
|
|
79
79
|
export { d as BulkImportError, B as BulkImportOptions, b as BulkImportResult, a as BulkImportSource, e as BulkImportSourceAdapter, f as ImportSourceRole, I as ImportTurn, g as ImportTurnValidationIssue, i as isImportRole, p as parseIsoTimestamp, v as validateImportTurn } from './types-gb_SNtjR.js';
|
|
80
80
|
export { clearBulkImportSources, getBulkImportSource, listBulkImportSources, registerBulkImportSource } from './bulk-import/index.js';
|
|
81
81
|
export { a as ProcessBatchContext, P as ProcessBatchFn, b as ProcessBatchResult, f as formatBatchTranscript, r as resolveBulkImportContext, c as runBulkImportPipeline, v as validateBatchSize } from './pipeline-DmqtvION.js';
|
|
82
|
-
export { B as BulkImportCliCommandOptions, p as parseStrictCliDate, r as runBulkImportCliCommand } from './cli-
|
|
82
|
+
export { B as BulkImportCliCommandOptions, p as parseStrictCliDate, r as runBulkImportCliCommand } from './cli-DqonYBZ0.js';
|
|
83
83
|
export { DEFAULT_IMPORT_BATCH_SIZE, ImportProgress, ImportedMemory, ImporterAdapter, ImporterParseOptions, ImporterTransformOptions, ImporterWriteResult, ImporterWriteTarget, RunImportOptions, RunImporterResult, defaultWriteMemoriesToOrchestrator, importedMemoryToTurn, runImporter, validateImportBatchSize, validateImportRateLimit } from './importers/index.js';
|
|
84
84
|
export { FallbackLlmClient, FallbackLlmOptions, FallbackLlmResponse, FallbackLlmRuntimeContext } from './fallback-llm.js';
|
|
85
85
|
export { ComputeMemoryWorthInput, MemoryWorthResult, computeMemoryWorth } from './memory-worth.js';
|
|
@@ -342,1473 +342,1473 @@ declare function buildProcedureMarkdownBody(steps: ProcedureStep[]): string;
|
|
|
342
342
|
*/
|
|
343
343
|
declare function parseProcedureStepsFromBody(content: string): ProcedureStep[] | null;
|
|
344
344
|
|
|
345
|
-
|
|
345
|
+
/**
|
|
346
|
+
* @remnic/core — Live Connectors Registry (issue #683 PR 1/N)
|
|
347
|
+
*
|
|
348
|
+
* Pure in-memory registry. No I/O. Concrete connectors register themselves at
|
|
349
|
+
* orchestrator boot (later PRs); the maintenance scheduler asks the registry
|
|
350
|
+
* for the active set when running due syncs.
|
|
351
|
+
*/
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Thrown when registering a duplicate id or an id that fails validation.
|
|
355
|
+
*
|
|
356
|
+
* Distinct error class so callers can distinguish framework-level mistakes
|
|
357
|
+
* (which are programmer errors) from connector-runtime failures.
|
|
358
|
+
*/
|
|
359
|
+
declare class LiveConnectorRegistryError extends Error {
|
|
360
|
+
constructor(message: string);
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* In-memory registry of live connectors. One instance per orchestrator. Not
|
|
364
|
+
* safe for cross-process sharing — wire each process to its own registry.
|
|
365
|
+
*/
|
|
366
|
+
declare class LiveConnectorRegistry {
|
|
367
|
+
private readonly connectors;
|
|
346
368
|
/**
|
|
347
|
-
*
|
|
348
|
-
*
|
|
369
|
+
* Register a connector. Throws `LiveConnectorRegistryError` if the id is
|
|
370
|
+
* malformed or already registered.
|
|
349
371
|
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
372
|
+
* Re-registration is rejected (rather than silently overwriting) because
|
|
373
|
+
* silent overwrites mask plugin loading bugs in development and could let
|
|
374
|
+
* a malicious extension shadow a built-in connector.
|
|
352
375
|
*/
|
|
353
|
-
|
|
376
|
+
register(connector: LiveConnector): void;
|
|
354
377
|
/**
|
|
355
|
-
*
|
|
356
|
-
* state (e.g. rebase in progress). Callers should treat `null` as "no
|
|
357
|
-
* branch-scope overlay applies" without erroring.
|
|
378
|
+
* Look up a connector by id. Returns `undefined` if not registered.
|
|
358
379
|
*/
|
|
359
|
-
|
|
380
|
+
get(id: string): LiveConnector | undefined;
|
|
360
381
|
/**
|
|
361
|
-
*
|
|
362
|
-
* Tilde-expanded per CLAUDE.md #17.
|
|
382
|
+
* Return all registered connectors, sorted by id for stable enumeration.
|
|
363
383
|
*/
|
|
364
|
-
|
|
384
|
+
list(): LiveConnector[];
|
|
365
385
|
/**
|
|
366
|
-
*
|
|
367
|
-
*
|
|
368
|
-
*
|
|
386
|
+
* Remove a connector. Returns `true` if a connector was removed, `false`
|
|
387
|
+
* otherwise. The cursor / state file on disk is **not** touched — callers
|
|
388
|
+
* who want to fully decommission a connector must also delete its state
|
|
389
|
+
* file via the `state-store` module.
|
|
369
390
|
*/
|
|
370
|
-
|
|
371
|
-
}
|
|
372
|
-
/**
|
|
373
|
-
* Injectable git-invocation surface. Only the commands `resolveGitContext`
|
|
374
|
-
* actually needs are exposed. Tests inject a mock implementation to avoid
|
|
375
|
-
* spawning a real git process.
|
|
376
|
-
*/
|
|
377
|
-
interface GitInvoker {
|
|
391
|
+
unregister(id: string): boolean;
|
|
378
392
|
/**
|
|
379
|
-
*
|
|
380
|
-
* `{ stdout, exitCode }` with `stdout` trimmed by the caller as needed.
|
|
381
|
-
* Implementations should NOT throw for non-zero exit codes — they should
|
|
382
|
-
* return the exit code so the resolver can decide how to recover.
|
|
393
|
+
* Number of registered connectors. Cheap; safe to call frequently.
|
|
383
394
|
*/
|
|
384
|
-
(
|
|
385
|
-
stdout: string;
|
|
386
|
-
exitCode: number;
|
|
387
|
-
};
|
|
395
|
+
size(): number;
|
|
388
396
|
}
|
|
397
|
+
|
|
389
398
|
/**
|
|
390
|
-
*
|
|
391
|
-
* `projectId` from either the origin URL or the root path. The hash does not
|
|
392
|
-
* need to be collision-resistant against adversarial input — it is purely a
|
|
393
|
-
* namespace discriminator.
|
|
399
|
+
* @remnic/core — Google Drive live connector (issue #683 PR 2/N)
|
|
394
400
|
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* Normalize a git remote URL so that equivalent SSH / HTTPS forms of the
|
|
401
|
-
* same repo produce the same `projectId`. Handles:
|
|
402
|
-
* - `git@github.com:foo/bar.git` → `github.com/foo/bar`
|
|
403
|
-
* - `https://github.com/foo/bar` → `github.com/foo/bar`
|
|
404
|
-
* - `https://github.com/foo/bar.git` → `github.com/foo/bar`
|
|
405
|
-
* - `ssh://git@github.com/foo/bar` → `github.com/foo/bar`
|
|
406
|
-
* - `ssh://git@github.com:2222/foo/bar` → `github.com/foo/bar` (port stripped)
|
|
401
|
+
* Concrete `LiveConnector` implementation that incrementally imports text
|
|
402
|
+
* content from a user's Google Drive into Remnic. Built on top of the
|
|
403
|
+
* framework shipped in PR 1/N (`framework.ts` / `registry.ts` /
|
|
404
|
+
* `state-store.ts`).
|
|
407
405
|
*
|
|
408
|
-
*
|
|
409
|
-
* case-insensitive in practice).
|
|
410
|
-
*/
|
|
411
|
-
declare function normalizeOriginUrl(rawUrl: string): string;
|
|
412
|
-
interface ResolveGitContextOptions {
|
|
413
|
-
/** Inject a git invoker (tests). Defaults to spawning real `git`. */
|
|
414
|
-
invoker?: GitInvoker;
|
|
415
|
-
}
|
|
416
|
-
/**
|
|
417
|
-
* Detect the git project + branch for `cwd`.
|
|
406
|
+
* Design notes:
|
|
418
407
|
*
|
|
419
|
-
*
|
|
420
|
-
*
|
|
421
|
-
*
|
|
422
|
-
*
|
|
408
|
+
* - **Cursor semantics.** We page Drive with the official `changes` API
|
|
409
|
+
* when a `startPageToken` is available. The cursor is opaque from the
|
|
410
|
+
* framework's POV (`{kind: "drivePageToken", value: ...}`), and on the
|
|
411
|
+
* very first sync (cursor=null) we call `changes.getStartPageToken()`
|
|
412
|
+
* to seed it without importing anything. This matches the documented
|
|
413
|
+
* Drive incremental-sync recipe and means re-runs never re-ingest the
|
|
414
|
+
* same file as long as the cursor file survives.
|
|
423
415
|
*
|
|
424
|
-
*
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
*
|
|
416
|
+
* - **Folder scope.** When `folderIds` is non-empty, files are filtered
|
|
417
|
+
* to those whose `parents` intersect the configured folder set. Drive
|
|
418
|
+
* does not currently support server-side parent filtering on the
|
|
419
|
+
* `changes.list` endpoint, so we pull the change record's `file` payload
|
|
420
|
+
* and apply the filter on our side. Folder ids are validated up front so
|
|
421
|
+
* a typo in config doesn't silently cause a broad import.
|
|
430
422
|
*
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
435
|
-
*
|
|
436
|
-
*
|
|
423
|
+
* - **Content extraction.** Google-native MIME types
|
|
424
|
+
* (`application/vnd.google-apps.{document,spreadsheet,presentation}`)
|
|
425
|
+
* are exported via `files.export` to plaintext. Plain-text MIME types
|
|
426
|
+
* are pulled with `files.get?alt=media`. Everything else is skipped —
|
|
427
|
+
* bytes from binary formats (images, PDFs, archives) belong in the
|
|
428
|
+
* binary-lifecycle pipeline, not in the textual ingestion path.
|
|
437
429
|
*
|
|
438
|
-
*
|
|
439
|
-
* `
|
|
430
|
+
* - **Idempotency.** Each emitted `ConnectorDocument.source` carries
|
|
431
|
+
* `externalId = file.id` plus `externalRevision = file.modifiedTime`,
|
|
432
|
+
* so downstream dedup (CLAUDE.md gotcha #44 — never index content that
|
|
433
|
+
* failed to persist) can recognise repeat fetches even if the cursor is
|
|
434
|
+
* manually rewound.
|
|
440
435
|
*
|
|
441
|
-
* -
|
|
442
|
-
*
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
*
|
|
446
|
-
*
|
|
447
|
-
*
|
|
448
|
-
* - `"native"` — the in-family @remnic/coding-graph engine, adapted to
|
|
449
|
-
* this port by a future PR (#1551/#1554). Only the enum
|
|
450
|
-
* value and this doc note land in this PR — no engine
|
|
451
|
-
* code. codebase-memory-mcp remains a supported
|
|
452
|
-
* subprocess provider through this same port regardless.
|
|
436
|
+
* - **Privacy.** No document content is ever logged. Folder ids and
|
|
437
|
+
* counts may be logged. OAuth credentials (`clientId`,
|
|
438
|
+
* `clientSecret`, `refreshToken`) are accepted via config but the
|
|
439
|
+
* intent is for callers to populate them from a secret store; we never
|
|
440
|
+
* persist credentials through the connector state-store. Per CLAUDE.md
|
|
441
|
+
* repository-privacy rules, no real credentials may appear in tests,
|
|
442
|
+
* fixtures, or comments.
|
|
453
443
|
*
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
* "
|
|
457
|
-
*
|
|
458
|
-
*
|
|
444
|
+
* - **À-la-carte packaging (CLAUDE.md gotcha #57).** `googleapis` is NOT
|
|
445
|
+
* listed as a hard dependency of `@remnic/core`. It is loaded via a
|
|
446
|
+
* computed-specifier dynamic import (`await import("google" + "apis")`)
|
|
447
|
+
* so bundlers cannot statically resolve it, and it is declared as an
|
|
448
|
+
* optional peer dependency. Operators who never enable the connector
|
|
449
|
+
* pay nothing for it.
|
|
459
450
|
*
|
|
460
|
-
*
|
|
461
|
-
*
|
|
462
|
-
* `globalThis`, mirroring `host-embedding-provider.ts`.
|
|
451
|
+
* - **Read-only.** This connector only reads. It never marks files as
|
|
452
|
+
* read, edits metadata, or modifies sharing settings.
|
|
463
453
|
*/
|
|
464
454
|
|
|
465
455
|
/**
|
|
466
|
-
*
|
|
467
|
-
* load-bearing: callers (review-context, `remnic doctor`, xray) switch on
|
|
468
|
-
* `code` to distinguish "binary not installed" from "timed out" from
|
|
469
|
-
* "protocol violation" so a silent provider failure can never look like an
|
|
470
|
-
* empty-but-healthy result.
|
|
456
|
+
* Stable connector id. Lives in the registry under this exact string.
|
|
471
457
|
*/
|
|
472
|
-
|
|
473
|
-
/** Probe failed: binary missing / not executable, or native package absent. */
|
|
474
|
-
"provider_unavailable"
|
|
475
|
-
/** The provider exceeded its deadline. */
|
|
476
|
-
| "provider_timeout"
|
|
477
|
-
/** Output was present but not a valid JSON object/array (rule 18). */
|
|
478
|
-
| "provider_malformed"
|
|
479
|
-
/** Provider ran but returned an explicit error or threw. */
|
|
480
|
-
| "provider_error";
|
|
458
|
+
declare const GOOGLE_DRIVE_CONNECTOR_ID = "google-drive";
|
|
481
459
|
/**
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
* are informational and surface in xray when present.
|
|
460
|
+
* Cursor `kind` we emit. Treated as opaque by the framework; documented
|
|
461
|
+
* here so tests can assert on it.
|
|
485
462
|
*/
|
|
486
|
-
|
|
487
|
-
/** Qualified or bare symbol name, e.g. `"AuthService.login"` or `"login"`. */
|
|
488
|
-
readonly symbol: string;
|
|
489
|
-
/** Source file the symbol lives in (forward-slashed, repo-relative when possible). */
|
|
490
|
-
readonly path?: string;
|
|
491
|
-
/** Coarse kind if the provider knows it (`function`/`method`/`class`/...). */
|
|
492
|
-
readonly kind?: string;
|
|
493
|
-
}
|
|
494
|
-
interface SymbolsForDiffOk {
|
|
495
|
-
readonly ok: true;
|
|
496
|
-
readonly symbols: StructuralSymbol[];
|
|
497
|
-
/** Provider-reported latency in ms, when available. */
|
|
498
|
-
readonly latencyMs?: number;
|
|
499
|
-
}
|
|
500
|
-
interface SymbolsForDiffErr {
|
|
501
|
-
readonly ok: false;
|
|
502
|
-
readonly code: StructuralContextErrorCode;
|
|
503
|
-
readonly detail?: string;
|
|
504
|
-
}
|
|
505
|
-
type SymbolsForDiffResult = SymbolsForDiffOk | SymbolsForDiffErr;
|
|
506
|
-
interface ArchitectureHintsOk {
|
|
507
|
-
readonly ok: true;
|
|
508
|
-
readonly hints: string[];
|
|
509
|
-
}
|
|
510
|
-
interface ArchitectureHintsErr {
|
|
511
|
-
readonly ok: false;
|
|
512
|
-
readonly code: StructuralContextErrorCode;
|
|
513
|
-
readonly detail?: string;
|
|
514
|
-
}
|
|
515
|
-
type ArchitectureHintsResult = ArchitectureHintsOk | ArchitectureHintsErr;
|
|
463
|
+
declare const GOOGLE_DRIVE_CURSOR_KIND = "drivePageToken";
|
|
516
464
|
/**
|
|
517
|
-
*
|
|
518
|
-
*
|
|
519
|
-
*
|
|
520
|
-
*
|
|
465
|
+
* Default poll interval (5 minutes). Surfaced in `openclaw.plugin.json`
|
|
466
|
+
* defaults and in the documented config schema. Drive's `changes.list`
|
|
467
|
+
* endpoint is cheap, but polling sub-minute is wasteful for a personal
|
|
468
|
+
* memory layer.
|
|
521
469
|
*/
|
|
522
|
-
|
|
523
|
-
/** Stable identifier for registry logging / `remnic doctor`. */
|
|
524
|
-
readonly id: string;
|
|
525
|
-
/**
|
|
526
|
-
* Probe availability. Resolves to a tagged result so a missing binary
|
|
527
|
-
* (subprocess) or absent package (native) is surfaced, never thrown
|
|
528
|
-
* (rule 34). Implementations SHOULD cache the outcome per instance
|
|
529
|
-
* (rule 11).
|
|
530
|
-
*/
|
|
531
|
-
probe(): Promise<{
|
|
532
|
-
available: boolean;
|
|
533
|
-
detail?: string;
|
|
534
|
-
}>;
|
|
535
|
-
/**
|
|
536
|
-
* Expand a unified diff to the symbols it touches. NEVER throws — every
|
|
537
|
-
* failure path returns a tagged `{ ok: false, code }`. The optional
|
|
538
|
-
* `signal` lets the caller cancel an in-flight subprocess (rule 40).
|
|
539
|
-
*/
|
|
540
|
-
symbolsForDiff(diff: string, options?: {
|
|
541
|
-
signal?: AbortSignal;
|
|
542
|
-
}): Promise<SymbolsForDiffResult>;
|
|
543
|
-
/**
|
|
544
|
-
* Optional architecture hints for a repo root. Used by the architecture
|
|
545
|
-
* card composition (#1548 Track A PR 3 + #1554). Implementations MAY omit
|
|
546
|
-
* this; callers MUST handle its absence.
|
|
547
|
-
*/
|
|
548
|
-
architectureHints?(root: string, options?: {
|
|
549
|
-
signal?: AbortSignal;
|
|
550
|
-
}): Promise<ArchitectureHintsResult>;
|
|
551
|
-
/** Release any resources the provider holds (subprocess handles, etc.). */
|
|
552
|
-
close?(): Promise<void> | void;
|
|
553
|
-
}
|
|
470
|
+
declare const DEFAULT_POLL_INTERVAL_MS: number;
|
|
554
471
|
/**
|
|
555
|
-
*
|
|
556
|
-
* alongside `SearchDegradation` (`backend: "qmd"`). `detail` is optional
|
|
557
|
-
* and never load-bearing — `code` is the signal.
|
|
472
|
+
* Validated, frozen view of `connectors.googleDrive.*`.
|
|
558
473
|
*/
|
|
559
|
-
interface
|
|
560
|
-
readonly
|
|
561
|
-
readonly
|
|
562
|
-
readonly
|
|
474
|
+
interface GoogleDriveConnectorConfig {
|
|
475
|
+
readonly clientId: string;
|
|
476
|
+
readonly clientSecret: string;
|
|
477
|
+
readonly refreshToken: string;
|
|
478
|
+
/** Poll interval surfaced to the scheduler. */
|
|
479
|
+
readonly pollIntervalMs: number;
|
|
480
|
+
/** Folder ids to scope import to. Empty = "all accessible". */
|
|
481
|
+
readonly folderIds: readonly string[];
|
|
563
482
|
}
|
|
564
483
|
/**
|
|
565
|
-
*
|
|
566
|
-
*
|
|
567
|
-
*
|
|
484
|
+
* Optional injection point for tests. The real connector dynamically imports
|
|
485
|
+
* `googleapis`; tests pass a stub here to avoid the optional-peer-dep
|
|
486
|
+
* machinery and to keep the test suite hermetic.
|
|
487
|
+
*
|
|
488
|
+
* The shape only covers the tiny slice of the SDK we actually use.
|
|
568
489
|
*/
|
|
569
|
-
|
|
490
|
+
interface GoogleDriveClientFactory {
|
|
491
|
+
(config: GoogleDriveConnectorConfig): Promise<GoogleDriveClient>;
|
|
492
|
+
}
|
|
570
493
|
/**
|
|
571
|
-
*
|
|
572
|
-
*
|
|
573
|
-
*
|
|
574
|
-
*
|
|
494
|
+
* Minimal Drive client surface. Tests provide a fake; production wraps
|
|
495
|
+
* `googleapis` to fit. Method shapes mirror the upstream API where it
|
|
496
|
+
* matters (`startPageToken` / `nextPageToken` / `newStartPageToken`,
|
|
497
|
+
* `files.modifiedTime` ISO 8601 strings).
|
|
575
498
|
*/
|
|
576
|
-
|
|
577
|
-
/**
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
499
|
+
interface GoogleDriveClient {
|
|
500
|
+
/** Mirrors `drive.changes.getStartPageToken()`. */
|
|
501
|
+
getStartPageToken(): Promise<{
|
|
502
|
+
startPageToken: string;
|
|
503
|
+
}>;
|
|
504
|
+
/**
|
|
505
|
+
* Mirrors `drive.changes.list(...)`. We page until the response yields a
|
|
506
|
+
* `newStartPageToken` (i.e., no more pages). Each `change.file`, when
|
|
507
|
+
* present, includes the metadata we need to decide whether to ingest.
|
|
508
|
+
*/
|
|
509
|
+
listChanges(args: {
|
|
510
|
+
pageToken: string;
|
|
511
|
+
pageSize: number;
|
|
512
|
+
}): Promise<DriveChangesPage>;
|
|
513
|
+
/**
|
|
514
|
+
* Export a Google-native doc to plaintext. Returns the body as a string.
|
|
515
|
+
*/
|
|
516
|
+
exportFile(args: {
|
|
517
|
+
fileId: string;
|
|
518
|
+
mimeType: string;
|
|
519
|
+
}): Promise<string>;
|
|
520
|
+
/**
|
|
521
|
+
* Download a non-Google-native file as a string. Used for `text/*` MIME
|
|
522
|
+
* types; binary formats are filtered out before we get here.
|
|
523
|
+
*/
|
|
524
|
+
getFileMedia(args: {
|
|
525
|
+
fileId: string;
|
|
526
|
+
}): Promise<string>;
|
|
527
|
+
}
|
|
528
|
+
interface DriveChangesPage {
|
|
529
|
+
readonly changes: readonly DriveChange[];
|
|
530
|
+
readonly newStartPageToken?: string;
|
|
531
|
+
readonly nextPageToken?: string;
|
|
532
|
+
}
|
|
533
|
+
interface DriveChange {
|
|
534
|
+
readonly removed?: boolean;
|
|
535
|
+
readonly fileId?: string;
|
|
536
|
+
readonly file?: DriveFileMetadata;
|
|
537
|
+
}
|
|
538
|
+
interface DriveFileMetadata {
|
|
539
|
+
readonly id: string;
|
|
540
|
+
readonly name?: string;
|
|
541
|
+
readonly mimeType?: string;
|
|
542
|
+
readonly modifiedTime?: string;
|
|
543
|
+
readonly trashed?: boolean;
|
|
544
|
+
readonly parents?: readonly string[];
|
|
545
|
+
readonly webViewLink?: string;
|
|
546
|
+
readonly size?: string | number;
|
|
547
|
+
}
|
|
581
548
|
/**
|
|
582
|
-
*
|
|
583
|
-
*
|
|
584
|
-
* on AND `structuralProvider` is not `"none"`. When this returns `false`,
|
|
585
|
-
* review-context runs its pure file-path-only ranker — byte-identical to
|
|
586
|
-
* pre-feature behaviour on every path.
|
|
549
|
+
* Result of a single sync pass — exposed for richer test assertions.
|
|
550
|
+
* Strict superset of `SyncIncrementalResult`.
|
|
587
551
|
*/
|
|
588
|
-
|
|
552
|
+
interface GoogleDriveSyncResult extends SyncIncrementalResult {
|
|
553
|
+
readonly skippedBinary: number;
|
|
554
|
+
readonly skippedFolderScope: number;
|
|
555
|
+
readonly skippedTooLarge: number;
|
|
556
|
+
}
|
|
589
557
|
/**
|
|
590
|
-
*
|
|
591
|
-
*
|
|
592
|
-
* with a live `probed` field.
|
|
558
|
+
* Validate and normalise raw config. Throws with a concrete message on any
|
|
559
|
+
* malformed input — never silently defaults (CLAUDE.md gotcha #51).
|
|
593
560
|
*/
|
|
594
|
-
|
|
595
|
-
readonly active: boolean;
|
|
596
|
-
readonly mode: CodingKnowledgeConfig["structuralProvider"];
|
|
597
|
-
/** Command path when mode is `"subprocess"` and a command is configured. */
|
|
598
|
-
readonly command?: string;
|
|
599
|
-
/** Provider id when one is registered for the scope. */
|
|
600
|
-
readonly providerId?: string;
|
|
601
|
-
/** Live probe outcome — set only by the async doctor probe. */
|
|
602
|
-
probed?: {
|
|
603
|
-
available: boolean;
|
|
604
|
-
detail?: string;
|
|
605
|
-
};
|
|
606
|
-
}
|
|
561
|
+
declare function validateGoogleDriveConfig(raw: unknown): GoogleDriveConnectorConfig;
|
|
607
562
|
/**
|
|
608
|
-
*
|
|
609
|
-
*
|
|
610
|
-
* for xray labels.
|
|
563
|
+
* Construct the connector. The `clientFactory` argument is the test hook —
|
|
564
|
+
* production callers omit it and the connector lazy-loads `googleapis`.
|
|
611
565
|
*/
|
|
612
|
-
declare function
|
|
566
|
+
declare function createGoogleDriveConnector(options?: {
|
|
567
|
+
clientFactory?: GoogleDriveClientFactory;
|
|
568
|
+
}): LiveConnector;
|
|
613
569
|
/**
|
|
614
|
-
*
|
|
570
|
+
* Production client factory. Lazy-loads `googleapis` via a computed-specifier
|
|
571
|
+
* dynamic import so bundlers never statically resolve it (CLAUDE.md gotcha
|
|
572
|
+
* #57). Surfaces a precise install hint on miss.
|
|
615
573
|
*
|
|
616
|
-
*
|
|
617
|
-
*
|
|
618
|
-
* `structural-context provider: subprocess, command=/usr/local/bin/cbm, probed=unavailable (binary not found)`
|
|
574
|
+
* Exported only for the `index.ts` barrel; consumers that already inject a
|
|
575
|
+
* test factory don't need to touch this.
|
|
619
576
|
*/
|
|
620
|
-
declare
|
|
577
|
+
declare const defaultGoogleDriveClientFactory: GoogleDriveClientFactory;
|
|
621
578
|
|
|
622
579
|
/**
|
|
623
|
-
*
|
|
580
|
+
* @remnic/core — Notion live connector (issue #683 PR 3/N)
|
|
624
581
|
*
|
|
625
|
-
*
|
|
626
|
-
*
|
|
627
|
-
*
|
|
582
|
+
* Concrete `LiveConnector` implementation that incrementally imports text
|
|
583
|
+
* content from Notion database pages into Remnic. Built on top of the
|
|
584
|
+
* framework shipped in PR 1/N (`framework.ts` / `registry.ts` /
|
|
585
|
+
* `state-store.ts`) and mirrors the structure of the Google Drive connector
|
|
586
|
+
* (PR 2/N).
|
|
628
587
|
*
|
|
629
|
-
*
|
|
630
|
-
* 2. Extracts the touched file list from a unified diff via
|
|
631
|
-
* `parseTouchedFiles`.
|
|
632
|
-
* 3. Re-ranks a set of candidate memories so that memories whose
|
|
633
|
-
* `entityRefs` mention a touched path float to the top. The boost is
|
|
634
|
-
* additive and bounded so it doesn't obliterate the original ranking —
|
|
635
|
-
* it's a bias, not a filter.
|
|
588
|
+
* Design notes:
|
|
636
589
|
*
|
|
637
|
-
*
|
|
638
|
-
*
|
|
639
|
-
*
|
|
640
|
-
*
|
|
641
|
-
*
|
|
590
|
+
* - **Auth.** Integration token from config (`connectors.notion.token`).
|
|
591
|
+
* The token is accepted at config-parse time but never logged. Operators
|
|
592
|
+
* must populate it from a secret store; per the repo-wide privacy policy
|
|
593
|
+
* no real value may appear in tests or comments.
|
|
594
|
+
*
|
|
595
|
+
* - **Scope.** `databaseIds` in config limits the import to the listed
|
|
596
|
+
* Notion databases. The connector queries each database for pages whose
|
|
597
|
+
* `last_edited_time` is after a per-page high-water mark stored in the
|
|
598
|
+
* cursor. When `databaseIds` is empty the connector does nothing (safe
|
|
599
|
+
* default — no credentials → no import).
|
|
600
|
+
*
|
|
601
|
+
* - **Cursor semantics.** The cursor is a JSON string encoding a
|
|
602
|
+
* `NotionCursorPayload`: a map from page-id to last-seen
|
|
603
|
+
* `last_edited_time` ISO string. On the first sync (cursor=null) we
|
|
604
|
+
* seed the payload from the current state of each database WITHOUT
|
|
605
|
+
* importing any content, so "first install" doesn't re-ingest history.
|
|
606
|
+
* Each subsequent pass only imports pages edited after the stored
|
|
607
|
+
* watermark.
|
|
608
|
+
*
|
|
609
|
+
* - **Block extraction.** Page content is fetched via
|
|
610
|
+
* `blocks.children.list` recursively up to `MAX_BLOCK_DEPTH` levels.
|
|
611
|
+
* Block text is extracted to Markdown-ish plain text (no raw JSON blobs).
|
|
612
|
+
* Only text-bearing block types are included; unsupported types are
|
|
613
|
+
* silently skipped.
|
|
614
|
+
*
|
|
615
|
+
* - **Raw `fetch`.** We call the Notion REST API directly rather than using
|
|
616
|
+
* `@notionhq/client` — there is no optional-peer-dep machinery needed and
|
|
617
|
+
* the API surface we consume is tiny. The `fetchFn` argument is the test
|
|
618
|
+
* hook allowing stubbing without network access.
|
|
619
|
+
*
|
|
620
|
+
* - **Idempotency.** `ConnectorDocument.source.externalId` is the page id
|
|
621
|
+
* and `externalRevision` is `last_edited_time`, so downstream dedup can
|
|
622
|
+
* recognise repeat fetches if the cursor is rewound.
|
|
623
|
+
*
|
|
624
|
+
* - **Privacy.** No page content is ever logged. Database ids and counts
|
|
625
|
+
* may be logged. The integration token is never exposed in logs, state,
|
|
626
|
+
* or error messages.
|
|
627
|
+
*
|
|
628
|
+
* - **Read-only.** This connector only reads. It never modifies pages,
|
|
629
|
+
* databases, or any other Notion resource.
|
|
642
630
|
*/
|
|
643
631
|
|
|
632
|
+
/** Stable connector id. Lives in the registry under this exact string. */
|
|
633
|
+
declare const NOTION_CONNECTOR_ID = "notion";
|
|
644
634
|
/**
|
|
645
|
-
*
|
|
646
|
-
*
|
|
647
|
-
* fields we actually need — so this module stays decoupled from the rest of
|
|
648
|
-
* the codebase and can be reused by CLI tools, bench fixtures, etc.
|
|
635
|
+
* Cursor `kind` we emit. Opaque to the framework; documented here so
|
|
636
|
+
* tests can assert on it.
|
|
649
637
|
*/
|
|
650
|
-
|
|
651
|
-
/** Opaque identifier. Echoed unchanged in the output. */
|
|
652
|
-
id: string;
|
|
653
|
-
/**
|
|
654
|
-
* Pre-review relevance score from the upstream recall pipeline. Higher is
|
|
655
|
-
* better. `0` is treated as "no prior signal" and gets the full review
|
|
656
|
-
* boost when a path match is found.
|
|
657
|
-
*/
|
|
658
|
-
score: number;
|
|
659
|
-
/**
|
|
660
|
-
* References the memory mentions (file paths, entity names, etc.). Used
|
|
661
|
-
* to decide whether any touched file appears in the memory's scope.
|
|
662
|
-
*
|
|
663
|
-
* Accepts `undefined`/missing so callers can pass sparse records from
|
|
664
|
-
* legacy storage without pre-filling.
|
|
665
|
-
*/
|
|
666
|
-
entityRefs?: string[];
|
|
667
|
-
}
|
|
668
|
-
interface ReviewContext {
|
|
669
|
-
/**
|
|
670
|
-
* Normalized file paths touched by the diff. Each entry is forward-slashed
|
|
671
|
-
* and relative to the repo root when possible.
|
|
672
|
-
*/
|
|
673
|
-
touchedFiles: string[];
|
|
674
|
-
/**
|
|
675
|
-
* Candidates re-sorted so memories whose `entityRefs` mention a touched
|
|
676
|
-
* path are boosted. Shape matches the input `ReviewCandidate[]` — the
|
|
677
|
-
* boost is recorded on each entry as `boost` for observability.
|
|
678
|
-
*/
|
|
679
|
-
rankedRecall: Array<ReviewCandidate & {
|
|
680
|
-
boost: number;
|
|
681
|
-
}>;
|
|
682
|
-
/**
|
|
683
|
-
* Structural-context provider degradation observed while expanding the
|
|
684
|
-
* diff to touched symbols (issue #1548 Track A PR 5, #1536 pattern).
|
|
685
|
-
* Present only when a provider was consulted AND it failed — a silent
|
|
686
|
-
* provider failure must never look like "no structural matches"
|
|
687
|
-
* (CLAUDE.md rule 34). Undefined when no provider was consulted (the
|
|
688
|
-
* pure {@link packReviewContext} path) or when the provider succeeded.
|
|
689
|
-
*/
|
|
690
|
-
structuralDegradation?: StructuralContextDegradation;
|
|
691
|
-
}
|
|
692
|
-
/**
|
|
693
|
-
* `true` when the prompt looks like a review / diff-explanation request.
|
|
694
|
-
*
|
|
695
|
-
* Empty / non-string input → `false` (the caller shouldn't branch on an
|
|
696
|
-
* invalid prompt).
|
|
697
|
-
*/
|
|
698
|
-
declare function isReviewPrompt(prompt: string | null | undefined): boolean;
|
|
638
|
+
declare const NOTION_CURSOR_KIND = "notionWatermark";
|
|
699
639
|
/**
|
|
700
|
-
*
|
|
701
|
-
*
|
|
702
|
-
* (`--- a/foo\n+++ b/bar`). Returns deduplicated, repo-root-relative paths
|
|
703
|
-
* (with the conventional `a/` / `b/` prefixes stripped).
|
|
704
|
-
*
|
|
705
|
-
* Path entries of `/dev/null` (used in adds/deletes) are excluded.
|
|
640
|
+
* Default poll interval (5 minutes). Notion's API has no push capability;
|
|
641
|
+
* polling sub-minute wastes quota for a personal memory layer.
|
|
706
642
|
*/
|
|
707
|
-
declare
|
|
643
|
+
declare const NOTION_DEFAULT_POLL_INTERVAL_MS: number;
|
|
708
644
|
/**
|
|
709
|
-
*
|
|
710
|
-
*
|
|
711
|
-
* Contract:
|
|
712
|
-
* - `touchedFiles` is the parsed diff file list.
|
|
713
|
-
* - `candidates` is passed through unchanged when no boost applies.
|
|
714
|
-
* - When a boost applies, the result is sorted by `(score + boost)` desc,
|
|
715
|
-
* with a stable secondary sort on the original `id` for determinism
|
|
716
|
-
* (CLAUDE.md #19 — comparators must return 0 for equal items).
|
|
645
|
+
* Validated, frozen view of `connectors.notion.*`.
|
|
717
646
|
*/
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
candidates: ReviewCandidate[];
|
|
647
|
+
interface NotionConnectorConfig {
|
|
648
|
+
/** Notion integration token. Starts with `secret_`. */
|
|
649
|
+
readonly token: string;
|
|
650
|
+
/** Database ids to import pages from. Empty = connector is a no-op. */
|
|
651
|
+
readonly databaseIds: readonly string[];
|
|
652
|
+
/** Poll interval surfaced to the scheduler (ms). */
|
|
653
|
+
readonly pollIntervalMs: number;
|
|
726
654
|
}
|
|
727
655
|
/**
|
|
728
|
-
*
|
|
729
|
-
*
|
|
730
|
-
*
|
|
731
|
-
* Parses the diff, re-ranks the candidates, and returns both artefacts so
|
|
732
|
-
* the caller can surface `touchedFiles` as context and `rankedRecall` as
|
|
733
|
-
* the recall result.
|
|
656
|
+
* Minimal fetch-compatible surface we use. The real connector delegates to
|
|
657
|
+
* the global `fetch`; tests inject a stub factory.
|
|
734
658
|
*/
|
|
735
|
-
|
|
659
|
+
type NotionFetchFn = (url: string, init: {
|
|
660
|
+
method: string;
|
|
661
|
+
headers: Record<string, string>;
|
|
662
|
+
body?: string;
|
|
663
|
+
signal?: AbortSignal;
|
|
664
|
+
}) => Promise<{
|
|
665
|
+
ok: boolean;
|
|
666
|
+
status: number;
|
|
667
|
+
json(): Promise<unknown>;
|
|
668
|
+
}>;
|
|
736
669
|
/**
|
|
737
|
-
*
|
|
738
|
-
*
|
|
739
|
-
* variant consults a {@link StructuralContextProvider} to expand the diff's
|
|
740
|
-
* touched FILE paths into touched SYMBOL names, widening the match set so
|
|
741
|
-
* memories that mention a changed symbol — not just the file path — float
|
|
742
|
-
* up. The gate (`structuralProvider !== "none"`) is checked ONCE by the
|
|
743
|
-
* caller, never inside this function (rule 39).
|
|
670
|
+
* Validate and normalise raw config. Throws with a concrete message on any
|
|
671
|
+
* malformed input — never silently defaults (CLAUDE.md gotcha #51).
|
|
744
672
|
*/
|
|
745
|
-
|
|
746
|
-
/** A probed structural-context provider. Never undefined here. */
|
|
747
|
-
provider: StructuralContextProvider;
|
|
748
|
-
/** Cancellation forwarded to the provider subprocess (rule 40). */
|
|
749
|
-
signal?: AbortSignal;
|
|
750
|
-
}
|
|
673
|
+
declare function validateNotionConfig(raw: unknown): NotionConnectorConfig;
|
|
751
674
|
/**
|
|
752
|
-
*
|
|
753
|
-
*
|
|
754
|
-
* Contract (issue #1548 Track A PR 5, prove-fail-before characterization):
|
|
755
|
-
* - Provider returns symbols (`ok: true`) → symbol names are ADDED to the
|
|
756
|
-
* match set alongside touched files; memories mentioning a symbol get the
|
|
757
|
-
* same bounded additive boost as a file-path match.
|
|
758
|
-
* - Provider fails (`ok: false`, any code) → ranking falls back to
|
|
759
|
-
* FILE-PATH-ONLY boosting, BYTE-IDENTICAL to {@link packReviewContext}
|
|
760
|
-
* (the match set is exactly the touched files), AND `structuralDegradation`
|
|
761
|
-
* is populated so xray/doctor can surface the failure (rule 34).
|
|
762
|
-
*
|
|
763
|
-
* The underlying ranker ({@link rankReviewCandidates}) is reused unchanged,
|
|
764
|
-
* so the deterministic ordering, boost cap, and tie-break are identical to
|
|
765
|
-
* the pure path.
|
|
675
|
+
* Construct the connector. The `fetchFn` argument is the test hook —
|
|
676
|
+
* production callers omit it and the connector uses the global `fetch`.
|
|
766
677
|
*/
|
|
767
|
-
declare function
|
|
678
|
+
declare function createNotionConnector(options?: {
|
|
679
|
+
fetchFn?: NotionFetchFn;
|
|
680
|
+
}): LiveConnector;
|
|
768
681
|
|
|
769
|
-
|
|
770
|
-
type StructuralSpawnFn = (command: string, argv: readonly string[], options: {
|
|
771
|
-
timeout: number;
|
|
772
|
-
signal?: AbortSignal;
|
|
773
|
-
}) => Promise<{
|
|
774
|
-
stdout: string;
|
|
775
|
-
stderr: string;
|
|
776
|
-
}>;
|
|
777
|
-
interface SubprocessProviderOptions {
|
|
778
|
-
/** Absolute path to the binary (rule 24 — statSync at probe time). */
|
|
779
|
-
readonly command: string;
|
|
682
|
+
interface GitContext {
|
|
780
683
|
/**
|
|
781
|
-
*
|
|
782
|
-
*
|
|
684
|
+
* Stable identifier for the project. Derived from `git remote get-url origin`
|
|
685
|
+
* when an origin remote is configured, otherwise from the repo root path.
|
|
686
|
+
*
|
|
687
|
+
* Formatted as `origin:<hex>` or `root:<hex>` so that the source is visible
|
|
688
|
+
* to operators (see `remnic doctor`, issue #569 acceptance criteria).
|
|
783
689
|
*/
|
|
784
|
-
|
|
785
|
-
/** Per-call deadline in ms. Default 5000. */
|
|
786
|
-
readonly timeoutMs?: number;
|
|
690
|
+
projectId: string;
|
|
787
691
|
/**
|
|
788
|
-
*
|
|
789
|
-
*
|
|
692
|
+
* Current branch, e.g. `main`, `feat/foo`. `null` only in detached-HEAD
|
|
693
|
+
* state (e.g. rebase in progress). Callers should treat `null` as "no
|
|
694
|
+
* branch-scope overlay applies" without erroring.
|
|
790
695
|
*/
|
|
791
|
-
|
|
792
|
-
/**
|
|
793
|
-
|
|
696
|
+
branch: string | null;
|
|
697
|
+
/**
|
|
698
|
+
* Absolute path to the repository root (the directory containing `.git`).
|
|
699
|
+
* Tilde-expanded per CLAUDE.md #17.
|
|
700
|
+
*/
|
|
701
|
+
rootPath: string;
|
|
702
|
+
/**
|
|
703
|
+
* Best-effort default branch (usually `main` or `master`). Derived from the
|
|
704
|
+
* `refs/remotes/origin/HEAD` symbolic ref. `null` when not available (e.g.
|
|
705
|
+
* fresh clone without a default branch symref, or no origin remote).
|
|
706
|
+
*/
|
|
707
|
+
defaultBranch: string | null;
|
|
794
708
|
}
|
|
795
709
|
/**
|
|
796
|
-
*
|
|
797
|
-
*
|
|
798
|
-
*
|
|
799
|
-
* returned unregister handle.
|
|
710
|
+
* Injectable git-invocation surface. Only the commands `resolveGitContext`
|
|
711
|
+
* actually needs are exposed. Tests inject a mock implementation to avoid
|
|
712
|
+
* spawning a real git process.
|
|
800
713
|
*/
|
|
801
|
-
|
|
714
|
+
interface GitInvoker {
|
|
715
|
+
/**
|
|
716
|
+
* Run `git <args>` with `cwd` as the working directory. Must return
|
|
717
|
+
* `{ stdout, exitCode }` with `stdout` trimmed by the caller as needed.
|
|
718
|
+
* Implementations should NOT throw for non-zero exit codes — they should
|
|
719
|
+
* return the exit code so the resolver can decide how to recover.
|
|
720
|
+
*/
|
|
721
|
+
(cwd: string, args: string[]): {
|
|
722
|
+
stdout: string;
|
|
723
|
+
exitCode: number;
|
|
724
|
+
};
|
|
725
|
+
}
|
|
802
726
|
/**
|
|
803
|
-
*
|
|
804
|
-
*
|
|
805
|
-
*
|
|
806
|
-
*
|
|
807
|
-
* - `"subprocess"` → builds a throwaway provider from
|
|
808
|
-
* `structuralProviderCommand`, probes it, disposes it.
|
|
809
|
-
* - `"native"` → asks `isCodingGraphInstalled()` whether the optional
|
|
810
|
-
* @remnic/coding-graph peer is present (the adapter that
|
|
811
|
-
* turns the engine into a provider lands in #1551).
|
|
727
|
+
* Non-cryptographic stable hash. Used only to derive a deterministic
|
|
728
|
+
* `projectId` from either the origin URL or the root path. The hash does not
|
|
729
|
+
* need to be collision-resistant against adversarial input — it is purely a
|
|
730
|
+
* namespace discriminator.
|
|
812
731
|
*
|
|
813
|
-
*
|
|
732
|
+
* Uses FNV-1a 32-bit so we don't pull in `node:crypto` for a simple bucket
|
|
733
|
+
* key. Output is lowercase hex, zero-padded to 8 characters.
|
|
814
734
|
*/
|
|
815
|
-
declare function
|
|
816
|
-
|
|
735
|
+
declare function stableHash(input: string): string;
|
|
817
736
|
/**
|
|
818
|
-
*
|
|
737
|
+
* Normalize a git remote URL so that equivalent SSH / HTTPS forms of the
|
|
738
|
+
* same repo produce the same `projectId`. Handles:
|
|
739
|
+
* - `git@github.com:foo/bar.git` → `github.com/foo/bar`
|
|
740
|
+
* - `https://github.com/foo/bar` → `github.com/foo/bar`
|
|
741
|
+
* - `https://github.com/foo/bar.git` → `github.com/foo/bar`
|
|
742
|
+
* - `ssh://git@github.com/foo/bar` → `github.com/foo/bar`
|
|
743
|
+
* - `ssh://git@github.com:2222/foo/bar` → `github.com/foo/bar` (port stripped)
|
|
819
744
|
*
|
|
820
|
-
*
|
|
821
|
-
*
|
|
745
|
+
* Case-insensitive (remote hostnames and most repo paths on major forges are
|
|
746
|
+
* case-insensitive in practice).
|
|
822
747
|
*/
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
gracePeriodDays: number;
|
|
828
|
-
/** Files larger than this are skipped during scan. Default: 50 MB. */
|
|
829
|
-
maxBinarySizeBytes: number;
|
|
830
|
-
/** Glob patterns for binary file types to manage. */
|
|
831
|
-
scanPatterns: string[];
|
|
832
|
-
/** Backend configuration for binary storage. */
|
|
833
|
-
backend: BinaryStorageBackendConfig;
|
|
834
|
-
}
|
|
835
|
-
interface BinaryStorageBackendConfig {
|
|
836
|
-
/** Backend type. "filesystem" copies to a local directory. "none" is a no-op (dry-run/testing). */
|
|
837
|
-
type: "filesystem" | "s3" | "none";
|
|
838
|
-
/** Destination directory for the filesystem backend. */
|
|
839
|
-
basePath?: string;
|
|
840
|
-
/** S3 bucket name (future). */
|
|
841
|
-
s3Bucket?: string;
|
|
842
|
-
/** S3 region (future). */
|
|
843
|
-
s3Region?: string;
|
|
844
|
-
/** S3 key prefix (future). */
|
|
845
|
-
s3Prefix?: string;
|
|
748
|
+
declare function normalizeOriginUrl(rawUrl: string): string;
|
|
749
|
+
interface ResolveGitContextOptions {
|
|
750
|
+
/** Inject a git invoker (tests). Defaults to spawning real `git`. */
|
|
751
|
+
invoker?: GitInvoker;
|
|
846
752
|
}
|
|
847
|
-
type BinaryAssetStatus = "pending" | "mirrored" | "redirected" | "cleaned" | "error";
|
|
848
|
-
interface BinaryAssetRecord {
|
|
849
|
-
/** Relative path from memoryDir to the original file. */
|
|
850
|
-
originalPath: string;
|
|
851
|
-
/** Path (or URL) in the backend storage. */
|
|
852
|
-
mirroredPath: string;
|
|
853
|
-
/** Optional user-resolvable target to write into markdown links. */
|
|
854
|
-
redirectPath?: string;
|
|
855
|
-
/** SHA-256 hex digest of file content. */
|
|
856
|
-
contentHash: string;
|
|
857
|
-
/** File size in bytes. */
|
|
858
|
-
sizeBytes: number;
|
|
859
|
-
/** MIME type (e.g. "image/png"). */
|
|
860
|
-
mimeType: string;
|
|
861
|
-
/** ISO 8601 timestamp when the file was mirrored. */
|
|
862
|
-
mirroredAt: string;
|
|
863
|
-
/** ISO 8601 timestamp when markdown references were rewritten. */
|
|
864
|
-
redirectedAt?: string;
|
|
865
|
-
/** ISO 8601 timestamp when the local copy was deleted. */
|
|
866
|
-
cleanedAt?: string;
|
|
867
|
-
/** Current lifecycle status. */
|
|
868
|
-
status: BinaryAssetStatus;
|
|
869
|
-
}
|
|
870
|
-
interface BinaryLifecycleManifest {
|
|
871
|
-
version: 1;
|
|
872
|
-
assets: BinaryAssetRecord[];
|
|
873
|
-
lastScanAt?: string;
|
|
874
|
-
}
|
|
875
|
-
interface PipelineResult {
|
|
876
|
-
scanned: number;
|
|
877
|
-
mirrored: number;
|
|
878
|
-
redirected: number;
|
|
879
|
-
cleaned: number;
|
|
880
|
-
errors: string[];
|
|
881
|
-
dryRun: boolean;
|
|
882
|
-
}
|
|
883
|
-
declare const DEFAULT_SCAN_PATTERNS: string[];
|
|
884
|
-
declare const DEFAULT_MAX_BINARY_SIZE_BYTES: number;
|
|
885
|
-
declare const DEFAULT_GRACE_PERIOD_DAYS = 7;
|
|
886
|
-
|
|
887
753
|
/**
|
|
888
|
-
*
|
|
754
|
+
* Detect the git project + branch for `cwd`.
|
|
889
755
|
*
|
|
890
|
-
*
|
|
891
|
-
*
|
|
892
|
-
*
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
interface BinaryStorageBackend {
|
|
896
|
-
/** Discriminator for the backend type. */
|
|
897
|
-
readonly type: string;
|
|
898
|
-
/**
|
|
899
|
-
* Upload a local file to the backend.
|
|
900
|
-
* @returns The backend path or URL where the file was stored.
|
|
901
|
-
*/
|
|
902
|
-
upload(localPath: string, remotePath: string): Promise<string>;
|
|
903
|
-
/** Check whether a remote path already exists in the backend. */
|
|
904
|
-
exists(remotePath: string): Promise<boolean>;
|
|
905
|
-
/** Delete a file from the backend. */
|
|
906
|
-
delete(remotePath: string): Promise<void>;
|
|
907
|
-
/** Return the user-resolvable markdown target for a stored backend path. */
|
|
908
|
-
getRedirectTarget?(remotePath: string): string;
|
|
909
|
-
}
|
|
910
|
-
declare class FilesystemBackend implements BinaryStorageBackend {
|
|
911
|
-
readonly type = "filesystem";
|
|
912
|
-
private readonly basePath;
|
|
913
|
-
constructor(basePath: string);
|
|
914
|
-
private resolveRemotePath;
|
|
915
|
-
private isInsideBase;
|
|
916
|
-
private realBasePathIfExists;
|
|
917
|
-
private ensureBaseDirectory;
|
|
918
|
-
private ensureSafeParentDirectory;
|
|
919
|
-
private resolveExistingRemotePath;
|
|
920
|
-
upload(localPath: string, remotePath: string): Promise<string>;
|
|
921
|
-
exists(remotePath: string): Promise<boolean>;
|
|
922
|
-
delete(remotePath: string): Promise<void>;
|
|
923
|
-
getRedirectTarget(remotePath: string): string;
|
|
924
|
-
}
|
|
925
|
-
declare class NoneBackend implements BinaryStorageBackend {
|
|
926
|
-
readonly type = "none";
|
|
927
|
-
upload(_localPath: string, remotePath: string): Promise<string>;
|
|
928
|
-
exists(_remotePath: string): Promise<boolean>;
|
|
929
|
-
delete(_remotePath: string): Promise<void>;
|
|
930
|
-
}
|
|
931
|
-
declare function createBackend(cfg: BinaryStorageBackendConfig): BinaryStorageBackend;
|
|
932
|
-
|
|
933
|
-
/**
|
|
934
|
-
* Binary file scanner.
|
|
756
|
+
* Returns `null` when:
|
|
757
|
+
* - `cwd` is not an absolute path (invalid input, CLAUDE.md #51)
|
|
758
|
+
* - `cwd` is not inside a git worktree
|
|
759
|
+
* - `git` is not available on PATH
|
|
935
760
|
*
|
|
936
|
-
*
|
|
937
|
-
* glob patterns, skips files already tracked in the manifest, and respects
|
|
938
|
-
* the max-size limit.
|
|
939
|
-
*/
|
|
940
|
-
|
|
941
|
-
/**
|
|
942
|
-
* Test whether a filename matches any of the provided glob patterns.
|
|
943
|
-
* Supports simple `*.ext` patterns (the default scan patterns).
|
|
944
|
-
* For more complex globs a proper library should be used; this covers
|
|
945
|
-
* the 95% case without adding a dependency.
|
|
946
|
-
*/
|
|
947
|
-
declare function matchesPatterns(filename: string, patterns: string[]): boolean;
|
|
948
|
-
/**
|
|
949
|
-
* Scan memoryDir recursively for binary files matching the configured patterns.
|
|
950
|
-
* Returns relative paths (relative to memoryDir) for files not yet tracked.
|
|
761
|
+
* Never throws.
|
|
951
762
|
*/
|
|
952
|
-
declare function
|
|
763
|
+
declare function resolveGitContext(cwd: string, options?: ResolveGitContextOptions): Promise<GitContext | null>;
|
|
953
764
|
|
|
954
765
|
/**
|
|
955
|
-
*
|
|
766
|
+
* Structural-context provider port (issue #1548 Track A PR 5).
|
|
956
767
|
*
|
|
957
|
-
* The
|
|
958
|
-
*
|
|
768
|
+
* The architectural boundary between Track A (durable coding-memory
|
|
769
|
+
* features) and Track B (the native @remnic/coding-graph engine). A
|
|
770
|
+
* structural-context provider expands a unified diff into the SYMBOLS it
|
|
771
|
+
* touches (and optionally yields architecture hints), so review-intent
|
|
772
|
+
* recall can boost memories that mention those symbols — not just the
|
|
773
|
+
* bare file paths that `review-context.ts` already boosts on.
|
|
774
|
+
*
|
|
775
|
+
* Three providers satisfy this port, selected by
|
|
776
|
+
* `codingKnowledge.structuralProvider`:
|
|
777
|
+
*
|
|
778
|
+
* - `"none"` — no provider consulted (default; review-context stays
|
|
779
|
+
* file-path-only, byte-identical to pre-feature — rule 39).
|
|
780
|
+
* - `"subprocess"` — an external binary shelled out via `execFile` with an
|
|
781
|
+
* argv ARRAY (never a shell string — rule 10). The
|
|
782
|
+
* built-in adapter lives in `structural-subprocess-provider.ts`;
|
|
783
|
+
* codebase-memory-mcp's CLI mode is the canonical target,
|
|
784
|
+
* but the provider is command-agnostic.
|
|
785
|
+
* - `"native"` — the in-family @remnic/coding-graph engine, adapted to
|
|
786
|
+
* this port by a future PR (#1551/#1554). Only the enum
|
|
787
|
+
* value and this doc note land in this PR — no engine
|
|
788
|
+
* code. codebase-memory-mcp remains a supported
|
|
789
|
+
* subprocess provider through this same port regardless.
|
|
790
|
+
*
|
|
791
|
+
* Every result is a tagged outcome shaped like #1536's `SearchDegradation`
|
|
792
|
+
* (CLAUDE.md rule 34 — a degraded/absent provider must NEVER masquerade as
|
|
793
|
+
* "no structural matches"):
|
|
794
|
+
* - `{ ok: true, symbols }` on success
|
|
795
|
+
* - `{ ok: false, code }` on every failure (distinct codes per mode)
|
|
796
|
+
*
|
|
797
|
+
* No module-level mutable state (rule 11): the registry is keyed per
|
|
798
|
+
* orchestrator/service instance via a `Symbol.for(...)` slot on
|
|
799
|
+
* `globalThis`, mirroring `host-embedding-provider.ts`.
|
|
959
800
|
*/
|
|
960
801
|
|
|
961
|
-
declare function manifestDir(memoryDir: string): string;
|
|
962
|
-
declare function manifestPath(memoryDir: string): string;
|
|
963
802
|
/**
|
|
964
|
-
*
|
|
965
|
-
*
|
|
966
|
-
* not
|
|
803
|
+
* Distinct failure codes for the structural-context port. Every code is
|
|
804
|
+
* load-bearing: callers (review-context, `remnic doctor`, xray) switch on
|
|
805
|
+
* `code` to distinguish "binary not installed" from "timed out" from
|
|
806
|
+
* "protocol violation" so a silent provider failure can never look like an
|
|
807
|
+
* empty-but-healthy result.
|
|
967
808
|
*/
|
|
968
|
-
|
|
809
|
+
type StructuralContextErrorCode =
|
|
810
|
+
/** Probe failed: binary missing / not executable, or native package absent. */
|
|
811
|
+
"provider_unavailable"
|
|
812
|
+
/** The provider exceeded its deadline. */
|
|
813
|
+
| "provider_timeout"
|
|
814
|
+
/** Output was present but not a valid JSON object/array (rule 18). */
|
|
815
|
+
| "provider_malformed"
|
|
816
|
+
/** Provider ran but returned an explicit error or threw. */
|
|
817
|
+
| "provider_error";
|
|
969
818
|
/**
|
|
970
|
-
*
|
|
971
|
-
*
|
|
819
|
+
* A single symbol touched by a diff. The `symbol` name is the load-bearing
|
|
820
|
+
* field — it is what review-context adds to its match set. `path`/`kind`
|
|
821
|
+
* are informational and surface in xray when present.
|
|
972
822
|
*/
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
823
|
+
interface StructuralSymbol {
|
|
824
|
+
/** Qualified or bare symbol name, e.g. `"AuthService.login"` or `"login"`. */
|
|
825
|
+
readonly symbol: string;
|
|
826
|
+
/** Source file the symbol lives in (forward-slashed, repo-relative when possible). */
|
|
827
|
+
readonly path?: string;
|
|
828
|
+
/** Coarse kind if the provider knows it (`function`/`method`/`class`/...). */
|
|
829
|
+
readonly kind?: string;
|
|
830
|
+
}
|
|
831
|
+
interface SymbolsForDiffOk {
|
|
832
|
+
readonly ok: true;
|
|
833
|
+
readonly symbols: StructuralSymbol[];
|
|
834
|
+
/** Provider-reported latency in ms, when available. */
|
|
835
|
+
readonly latencyMs?: number;
|
|
836
|
+
}
|
|
837
|
+
interface SymbolsForDiffErr {
|
|
838
|
+
readonly ok: false;
|
|
839
|
+
readonly code: StructuralContextErrorCode;
|
|
840
|
+
readonly detail?: string;
|
|
841
|
+
}
|
|
842
|
+
type SymbolsForDiffResult = SymbolsForDiffOk | SymbolsForDiffErr;
|
|
843
|
+
interface ArchitectureHintsOk {
|
|
844
|
+
readonly ok: true;
|
|
845
|
+
readonly hints: string[];
|
|
846
|
+
}
|
|
847
|
+
interface ArchitectureHintsErr {
|
|
848
|
+
readonly ok: false;
|
|
849
|
+
readonly code: StructuralContextErrorCode;
|
|
850
|
+
readonly detail?: string;
|
|
851
|
+
}
|
|
852
|
+
type ArchitectureHintsResult = ArchitectureHintsOk | ArchitectureHintsErr;
|
|
976
853
|
/**
|
|
977
|
-
*
|
|
978
|
-
*
|
|
979
|
-
*
|
|
980
|
-
*
|
|
981
|
-
* 2. Redirect: scan markdown for inline refs, replace with redirect path
|
|
982
|
-
* 3. Clean: after grace period, delete local copy
|
|
854
|
+
* The port contract. Both the built-in subprocess adapter
|
|
855
|
+
* (`structural-subprocess-provider.ts`) and the future native engine
|
|
856
|
+
* adapter (#1551) implement this. Registry callers retrieve an instance by
|
|
857
|
+
* scope; never construct one inline at a call site.
|
|
983
858
|
*/
|
|
984
|
-
|
|
985
|
-
/**
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
859
|
+
interface StructuralContextProvider {
|
|
860
|
+
/** Stable identifier for registry logging / `remnic doctor`. */
|
|
861
|
+
readonly id: string;
|
|
862
|
+
/**
|
|
863
|
+
* Probe availability. Resolves to a tagged result so a missing binary
|
|
864
|
+
* (subprocess) or absent package (native) is surfaced, never thrown
|
|
865
|
+
* (rule 34). Implementations SHOULD cache the outcome per instance
|
|
866
|
+
* (rule 11).
|
|
867
|
+
*/
|
|
868
|
+
probe(): Promise<{
|
|
869
|
+
available: boolean;
|
|
870
|
+
detail?: string;
|
|
871
|
+
}>;
|
|
872
|
+
/**
|
|
873
|
+
* Expand a unified diff to the symbols it touches. NEVER throws — every
|
|
874
|
+
* failure path returns a tagged `{ ok: false, code }`. The optional
|
|
875
|
+
* `signal` lets the caller cancel an in-flight subprocess (rule 40).
|
|
876
|
+
*/
|
|
877
|
+
symbolsForDiff(diff: string, options?: {
|
|
878
|
+
signal?: AbortSignal;
|
|
879
|
+
}): Promise<SymbolsForDiffResult>;
|
|
880
|
+
/**
|
|
881
|
+
* Optional architecture hints for a repo root. Used by the architecture
|
|
882
|
+
* card composition (#1548 Track A PR 3 + #1554). Implementations MAY omit
|
|
883
|
+
* this; callers MUST handle its absence.
|
|
884
|
+
*/
|
|
885
|
+
architectureHints?(root: string, options?: {
|
|
886
|
+
signal?: AbortSignal;
|
|
887
|
+
}): Promise<ArchitectureHintsResult>;
|
|
888
|
+
/** Release any resources the provider holds (subprocess handles, etc.). */
|
|
889
|
+
close?(): Promise<void> | void;
|
|
990
890
|
}
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
writeMarkdownFile?: WriteMarkdownFile;
|
|
891
|
+
/**
|
|
892
|
+
* Backend tag is a literal so consumers can switch on it programmatically
|
|
893
|
+
* alongside `SearchDegradation` (`backend: "qmd"`). `detail` is optional
|
|
894
|
+
* and never load-bearing — `code` is the signal.
|
|
895
|
+
*/
|
|
896
|
+
interface StructuralContextDegradation {
|
|
897
|
+
readonly backend: "structural-context";
|
|
898
|
+
readonly code: StructuralContextErrorCode;
|
|
899
|
+
readonly detail?: string;
|
|
1001
900
|
}
|
|
1002
901
|
/**
|
|
1003
|
-
*
|
|
902
|
+
* Coerce a {@link SymbolsForDiffErr} into the degradation record consumers
|
|
903
|
+
* attach to recall snapshots / xray. Centralised so the `{ backend: ... }`
|
|
904
|
+
* tag is set in one place (rule 22 spirit).
|
|
1004
905
|
*/
|
|
1005
|
-
declare function
|
|
1006
|
-
|
|
906
|
+
declare function toStructuralContextDegradation(err: SymbolsForDiffErr): StructuralContextDegradation;
|
|
1007
907
|
/**
|
|
1008
|
-
*
|
|
1009
|
-
*
|
|
1010
|
-
*
|
|
1011
|
-
*
|
|
1012
|
-
* Manual edits are preserved in fenced blocks.
|
|
908
|
+
* Register a provider for a scope (typically an orchestrator `serviceId`).
|
|
909
|
+
* Overwriting a previous registration closes the old provider. Returns an
|
|
910
|
+
* unregister function — callers SHOULD invoke it on service teardown so a
|
|
911
|
+
* hot-reloaded host does not leak subprocess handles.
|
|
1013
912
|
*/
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
/** Categories to include (default: all) */
|
|
1045
|
-
categories?: string[];
|
|
1046
|
-
/** Whether to include entity graph */
|
|
1047
|
-
includeEntities?: boolean;
|
|
1048
|
-
/** Whether to include orphaned questions */
|
|
1049
|
-
includeQuestions?: boolean;
|
|
1050
|
-
/** Max nodes per category (default: unlimited) */
|
|
1051
|
-
maxPerCategory?: number;
|
|
1052
|
-
/** Whether to watch for changes and regenerate incrementally */
|
|
1053
|
-
watch?: boolean;
|
|
1054
|
-
}
|
|
1055
|
-
interface GenerateResult {
|
|
1056
|
-
nodesGenerated: number;
|
|
1057
|
-
nodesSkipped: number;
|
|
1058
|
-
categories: Record<string, number>;
|
|
1059
|
-
durationMs: number;
|
|
1060
|
-
outputDir: string;
|
|
913
|
+
declare function registerStructuralContextProvider(scope: string, provider: StructuralContextProvider): () => void;
|
|
914
|
+
/** Look up the provider registered for a scope, if any. */
|
|
915
|
+
declare function getStructuralContextProvider(scope: string): StructuralContextProvider | undefined;
|
|
916
|
+
/** Test-only: clear every registered provider. */
|
|
917
|
+
declare function clearStructuralContextProvidersForTest(): void;
|
|
918
|
+
/**
|
|
919
|
+
* The single gate every review-context consumer consults before consulting a
|
|
920
|
+
* provider. Returns `true` iff the master `codingKnowledge.enabled` switch is
|
|
921
|
+
* on AND `structuralProvider` is not `"none"`. When this returns `false`,
|
|
922
|
+
* review-context runs its pure file-path-only ranker — byte-identical to
|
|
923
|
+
* pre-feature behaviour on every path.
|
|
924
|
+
*/
|
|
925
|
+
declare function structuralProviderActive(config: PluginConfig): boolean;
|
|
926
|
+
/**
|
|
927
|
+
* Config-only structural provider status. `remnic doctor` and xray render
|
|
928
|
+
* this; an async sibling in `structural-subprocess-provider.ts` augments it
|
|
929
|
+
* with a live `probed` field.
|
|
930
|
+
*/
|
|
931
|
+
interface StructuralProviderStatus {
|
|
932
|
+
readonly active: boolean;
|
|
933
|
+
readonly mode: CodingKnowledgeConfig["structuralProvider"];
|
|
934
|
+
/** Command path when mode is `"subprocess"` and a command is configured. */
|
|
935
|
+
readonly command?: string;
|
|
936
|
+
/** Provider id when one is registered for the scope. */
|
|
937
|
+
readonly providerId?: string;
|
|
938
|
+
/** Live probe outcome — set only by the async doctor probe. */
|
|
939
|
+
probed?: {
|
|
940
|
+
available: boolean;
|
|
941
|
+
detail?: string;
|
|
942
|
+
};
|
|
1061
943
|
}
|
|
1062
944
|
/**
|
|
1063
|
-
*
|
|
945
|
+
* Summarise the structural provider status from config ALONE (no probe, no
|
|
946
|
+
* I/O). Pure — safe to call from any context, including the recall hot path
|
|
947
|
+
* for xray labels.
|
|
948
|
+
*/
|
|
949
|
+
declare function describeStructuralProviderStatus(config: PluginConfig, scope?: string): StructuralProviderStatus;
|
|
950
|
+
/**
|
|
951
|
+
* Render a single human-readable line for `remnic doctor`. Pure.
|
|
1064
952
|
*
|
|
1065
|
-
*
|
|
953
|
+
* `structural-context provider: none (inactive — review-context stays file-path-only)`
|
|
954
|
+
* `structural-context provider: subprocess, command=/usr/local/bin/cbm, probed=available`
|
|
955
|
+
* `structural-context provider: subprocess, command=/usr/local/bin/cbm, probed=unavailable (binary not found)`
|
|
1066
956
|
*/
|
|
1067
|
-
declare function
|
|
957
|
+
declare function renderStructuralProviderStatusLine(status: StructuralProviderStatus): string;
|
|
1068
958
|
|
|
1069
959
|
/**
|
|
1070
|
-
*
|
|
960
|
+
* Diff-aware review-context packer (issue #569 PR 4).
|
|
1071
961
|
*
|
|
1072
|
-
*
|
|
1073
|
-
*
|
|
962
|
+
* When an agent is asked "review this PR" / "what changed in this diff" /
|
|
963
|
+
* "look at this diff", the prompt that reaches recall is short and generic
|
|
964
|
+
* — the real signal is the diff itself. This module:
|
|
965
|
+
*
|
|
966
|
+
* 1. Detects review-intent prompts via `isReviewPrompt`.
|
|
967
|
+
* 2. Extracts the touched file list from a unified diff via
|
|
968
|
+
* `parseTouchedFiles`.
|
|
969
|
+
* 3. Re-ranks a set of candidate memories so that memories whose
|
|
970
|
+
* `entityRefs` mention a touched path float to the top. The boost is
|
|
971
|
+
* additive and bounded so it doesn't obliterate the original ranking —
|
|
972
|
+
* it's a bias, not a filter.
|
|
973
|
+
*
|
|
974
|
+
* Pure — no orchestrator, no storage. Callers inject the candidate memories
|
|
975
|
+
* they already have from their normal recall pipeline. This keeps the
|
|
976
|
+
* module easy to test and integrates cleanly with the existing tiered-recall
|
|
977
|
+
* code in `orchestrator.ts` (the tier itself can be wired later; the pure
|
|
978
|
+
* surface is what PRs 5/6/7 will call).
|
|
1074
979
|
*/
|
|
1075
|
-
interface OnboardOptions {
|
|
1076
|
-
/** Directory to scan (defaults to cwd) */
|
|
1077
|
-
directory?: string;
|
|
1078
|
-
/** Max depth to walk (default: 6) */
|
|
1079
|
-
maxDepth?: number;
|
|
1080
|
-
/** Directories to skip */
|
|
1081
|
-
excludeDirs?: string[];
|
|
1082
|
-
}
|
|
1083
|
-
interface LanguageInfo {
|
|
1084
|
-
/** Language name (e.g. "TypeScript", "Python") */
|
|
1085
|
-
language: string;
|
|
1086
|
-
/** Confidence in detection (0-1) */
|
|
1087
|
-
confidence: number;
|
|
1088
|
-
/** Evidence (e.g. ["package.json", "tsconfig.json", "*.ts files"]) */
|
|
1089
|
-
evidence: string[];
|
|
1090
|
-
}
|
|
1091
|
-
interface DocFile {
|
|
1092
|
-
/** Absolute path */
|
|
1093
|
-
path: string;
|
|
1094
|
-
/** Relative path from project root */
|
|
1095
|
-
relativePath: string;
|
|
1096
|
-
/** Estimated type */
|
|
1097
|
-
kind: "readme" | "changelog" | "contributing" | "license" | "config" | "docs" | "other";
|
|
1098
|
-
/** File size in bytes */
|
|
1099
|
-
size: number;
|
|
1100
|
-
}
|
|
1101
|
-
type ProjectShape = "app" | "library" | "monorepo" | "workspace" | "script" | "unknown";
|
|
1102
|
-
interface OnboardResult {
|
|
1103
|
-
/** Project root */
|
|
1104
|
-
directory: string;
|
|
1105
|
-
/** Detected languages (sorted by confidence) */
|
|
1106
|
-
languages: LanguageInfo[];
|
|
1107
|
-
/** Detected project shape */
|
|
1108
|
-
shape: ProjectShape;
|
|
1109
|
-
/** Shape evidence */
|
|
1110
|
-
shapeEvidence: string[];
|
|
1111
|
-
/** Discovered documentation files */
|
|
1112
|
-
docs: DocFile[];
|
|
1113
|
-
/** Total files scanned */
|
|
1114
|
-
totalFiles: number;
|
|
1115
|
-
/** Duration in ms */
|
|
1116
|
-
durationMs: number;
|
|
1117
|
-
/** Suggested ingestion plan */
|
|
1118
|
-
plan: IngestionPlan;
|
|
1119
|
-
}
|
|
1120
|
-
interface IngestionPlan {
|
|
1121
|
-
/** Priority files to ingest first */
|
|
1122
|
-
priorityFiles: DocFile[];
|
|
1123
|
-
/** Estimated total files to ingest */
|
|
1124
|
-
estimatedFiles: number;
|
|
1125
|
-
/** Recommended categories */
|
|
1126
|
-
categories: string[];
|
|
1127
|
-
/** Suggested memory namespace */
|
|
1128
|
-
suggestedNamespace: string;
|
|
1129
|
-
}
|
|
1130
|
-
declare function onboard(options: OnboardOptions): OnboardResult;
|
|
1131
980
|
|
|
1132
981
|
/**
|
|
1133
|
-
*
|
|
1134
|
-
*
|
|
1135
|
-
*
|
|
1136
|
-
*
|
|
982
|
+
* A memory candidate as fed into review-context ranking. The shape is a
|
|
983
|
+
* deliberate subset of the core `MemorySummary` / recall result — only the
|
|
984
|
+
* fields we actually need — so this module stays decoupled from the rest of
|
|
985
|
+
* the codebase and can be reused by CLI tools, bench fixtures, etc.
|
|
1137
986
|
*/
|
|
1138
|
-
interface
|
|
1139
|
-
/**
|
|
1140
|
-
targetPath: string;
|
|
1141
|
-
/** Memory root directory for writing */
|
|
1142
|
-
memoryDir: string;
|
|
1143
|
-
/** Source label (e.g. "manual", "docs", "onboarding") */
|
|
1144
|
-
source?: string;
|
|
1145
|
-
/** Category override (default: auto-detect) */
|
|
1146
|
-
category?: string;
|
|
1147
|
-
/** Confidence to assign (default: 0.9 for curated items) */
|
|
1148
|
-
confidence?: number;
|
|
1149
|
-
/** Entity reference to attach */
|
|
1150
|
-
entityRef?: string;
|
|
1151
|
-
/** Tags to add */
|
|
1152
|
-
tags?: string[];
|
|
1153
|
-
/** Whether to perform dedup check against existing memories */
|
|
1154
|
-
checkDuplicates?: boolean;
|
|
1155
|
-
/** Whether to detect contradictions */
|
|
1156
|
-
checkContradictions?: boolean;
|
|
1157
|
-
/** Whether to write files (default: true). False = dry run */
|
|
1158
|
-
write?: boolean;
|
|
1159
|
-
}
|
|
1160
|
-
interface CuratedStatement {
|
|
1161
|
-
/** Unique ID for this statement */
|
|
987
|
+
interface ReviewCandidate {
|
|
988
|
+
/** Opaque identifier. Echoed unchanged in the output. */
|
|
1162
989
|
id: string;
|
|
1163
|
-
/**
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
/**
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
}
|
|
1178
|
-
interface StatementProvenance {
|
|
1179
|
-
/** Source file path */
|
|
1180
|
-
sourcePath: string;
|
|
1181
|
-
/** Relative path from project root */
|
|
1182
|
-
relativePath: string;
|
|
1183
|
-
/** Source label */
|
|
1184
|
-
source: string;
|
|
1185
|
-
/** Line number if extractable (0 = unknown) */
|
|
1186
|
-
lineNumber: number;
|
|
1187
|
-
/** Timestamp of ingestion */
|
|
1188
|
-
ingestedAt: string;
|
|
1189
|
-
/** Hash of the source file for diff tracking */
|
|
1190
|
-
sourceFileHash: string;
|
|
990
|
+
/**
|
|
991
|
+
* Pre-review relevance score from the upstream recall pipeline. Higher is
|
|
992
|
+
* better. `0` is treated as "no prior signal" and gets the full review
|
|
993
|
+
* boost when a path match is found.
|
|
994
|
+
*/
|
|
995
|
+
score: number;
|
|
996
|
+
/**
|
|
997
|
+
* References the memory mentions (file paths, entity names, etc.). Used
|
|
998
|
+
* to decide whether any touched file appears in the memory's scope.
|
|
999
|
+
*
|
|
1000
|
+
* Accepts `undefined`/missing so callers can pass sparse records from
|
|
1001
|
+
* legacy storage without pre-filling.
|
|
1002
|
+
*/
|
|
1003
|
+
entityRefs?: string[];
|
|
1191
1004
|
}
|
|
1192
|
-
interface
|
|
1193
|
-
/**
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
/** Recommended action */
|
|
1216
|
-
action: "skip" | "merge" | "keep";
|
|
1217
|
-
}
|
|
1218
|
-
interface ContradictionResult$1 {
|
|
1219
|
-
/** New statement */
|
|
1220
|
-
newStatement: CuratedStatement;
|
|
1221
|
-
/** Conflicting memory ID */
|
|
1222
|
-
conflictingId: string;
|
|
1223
|
-
/** The conflicting content */
|
|
1224
|
-
conflictingContent: string;
|
|
1225
|
-
/** Severity */
|
|
1226
|
-
severity: "high" | "medium" | "low";
|
|
1005
|
+
interface ReviewContext {
|
|
1006
|
+
/**
|
|
1007
|
+
* Normalized file paths touched by the diff. Each entry is forward-slashed
|
|
1008
|
+
* and relative to the repo root when possible.
|
|
1009
|
+
*/
|
|
1010
|
+
touchedFiles: string[];
|
|
1011
|
+
/**
|
|
1012
|
+
* Candidates re-sorted so memories whose `entityRefs` mention a touched
|
|
1013
|
+
* path are boosted. Shape matches the input `ReviewCandidate[]` — the
|
|
1014
|
+
* boost is recorded on each entry as `boost` for observability.
|
|
1015
|
+
*/
|
|
1016
|
+
rankedRecall: Array<ReviewCandidate & {
|
|
1017
|
+
boost: number;
|
|
1018
|
+
}>;
|
|
1019
|
+
/**
|
|
1020
|
+
* Structural-context provider degradation observed while expanding the
|
|
1021
|
+
* diff to touched symbols (issue #1548 Track A PR 5, #1536 pattern).
|
|
1022
|
+
* Present only when a provider was consulted AND it failed — a silent
|
|
1023
|
+
* provider failure must never look like "no structural matches"
|
|
1024
|
+
* (CLAUDE.md rule 34). Undefined when no provider was consulted (the
|
|
1025
|
+
* pure {@link packReviewContext} path) or when the provider succeeded.
|
|
1026
|
+
*/
|
|
1027
|
+
structuralDegradation?: StructuralContextDegradation;
|
|
1227
1028
|
}
|
|
1228
|
-
declare function curate(options: CurateOptions): Promise<CurateResult>;
|
|
1229
|
-
|
|
1230
1029
|
/**
|
|
1231
|
-
*
|
|
1030
|
+
* `true` when the prompt looks like a review / diff-explanation request.
|
|
1232
1031
|
*
|
|
1233
|
-
*
|
|
1234
|
-
*
|
|
1032
|
+
* Empty / non-string input → `false` (the caller shouldn't branch on an
|
|
1033
|
+
* invalid prompt).
|
|
1235
1034
|
*/
|
|
1236
|
-
|
|
1237
|
-
/** Memory ID */
|
|
1238
|
-
id: string;
|
|
1239
|
-
/** Content text */
|
|
1240
|
-
content: string;
|
|
1241
|
-
/** Category */
|
|
1242
|
-
category: string;
|
|
1243
|
-
/** File path (if known) */
|
|
1244
|
-
filePath?: string;
|
|
1245
|
-
}
|
|
1246
|
-
interface DedupOptions {
|
|
1247
|
-
/** Memory root directory */
|
|
1248
|
-
memoryDir: string;
|
|
1249
|
-
/** Categories to scan (default: all) */
|
|
1250
|
-
categories?: string[];
|
|
1251
|
-
/** Similarity threshold for fuzzy matching (0-1, default: 0.85) */
|
|
1252
|
-
threshold?: number;
|
|
1253
|
-
/** Max memories to load (default: 10000) */
|
|
1254
|
-
maxLoad?: number;
|
|
1255
|
-
}
|
|
1256
|
-
interface DedupResult {
|
|
1257
|
-
/** Total memories scanned */
|
|
1258
|
-
scanned: number;
|
|
1259
|
-
/** Duplicate pairs found */
|
|
1260
|
-
duplicates: DuplicatePair[];
|
|
1261
|
-
/** Duration in ms */
|
|
1262
|
-
durationMs: number;
|
|
1263
|
-
}
|
|
1264
|
-
interface DuplicatePair {
|
|
1265
|
-
/** First memory */
|
|
1266
|
-
left: MemoryEntry;
|
|
1267
|
-
/** Second memory */
|
|
1268
|
-
right: MemoryEntry;
|
|
1269
|
-
/** Similarity score */
|
|
1270
|
-
similarity: number;
|
|
1271
|
-
/** Recommended action */
|
|
1272
|
-
action: "merge" | "keep_left" | "keep_right";
|
|
1273
|
-
}
|
|
1274
|
-
interface ContradictionOptions {
|
|
1275
|
-
/** Memory root directory */
|
|
1276
|
-
memoryDir: string;
|
|
1277
|
-
/** Categories to scan (default: all) */
|
|
1278
|
-
categories?: string[];
|
|
1279
|
-
/** Max memories to load (default: 10000) */
|
|
1280
|
-
maxLoad?: number;
|
|
1281
|
-
}
|
|
1282
|
-
interface ContradictionResult {
|
|
1283
|
-
/** Total memories scanned */
|
|
1284
|
-
scanned: number;
|
|
1285
|
-
/** Contradictions found */
|
|
1286
|
-
contradictions: ContradictionPair[];
|
|
1287
|
-
/** Duration in ms */
|
|
1288
|
-
durationMs: number;
|
|
1289
|
-
}
|
|
1290
|
-
interface ContradictionPair {
|
|
1291
|
-
/** First statement */
|
|
1292
|
-
left: MemoryEntry;
|
|
1293
|
-
/** Contradicting statement */
|
|
1294
|
-
right: MemoryEntry;
|
|
1295
|
-
/** Severity */
|
|
1296
|
-
severity: "high" | "medium" | "low";
|
|
1297
|
-
/** Reason */
|
|
1298
|
-
reason: string;
|
|
1299
|
-
}
|
|
1300
|
-
declare function findDuplicates(options: DedupOptions): DedupResult;
|
|
1301
|
-
declare function findContradictions(options: ContradictionOptions): ContradictionResult;
|
|
1302
|
-
|
|
1035
|
+
declare function isReviewPrompt(prompt: string | null | undefined): boolean;
|
|
1303
1036
|
/**
|
|
1304
|
-
*
|
|
1037
|
+
* Parse a unified diff and return the set of files touched. Accepts both the
|
|
1038
|
+
* `diff --git` form (`diff --git a/foo b/bar`) and the `--- / +++` form
|
|
1039
|
+
* (`--- a/foo\n+++ b/bar`). Returns deduplicated, repo-root-relative paths
|
|
1040
|
+
* (with the conventional `a/` / `b/` prefixes stripped).
|
|
1305
1041
|
*
|
|
1306
|
-
*
|
|
1307
|
-
* Integrates with the existing review-queue system.
|
|
1042
|
+
* Path entries of `/dev/null` (used in adds/deletes) are excluded.
|
|
1308
1043
|
*/
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
/**
|
|
1325
|
-
|
|
1326
|
-
/**
|
|
1327
|
-
|
|
1328
|
-
/** Additional context */
|
|
1329
|
-
context?: string;
|
|
1330
|
-
}
|
|
1331
|
-
type ReviewAction = "approve" | "dismiss" | "flag";
|
|
1332
|
-
interface ReviewResult {
|
|
1333
|
-
/** Item acted upon */
|
|
1334
|
-
itemId: string;
|
|
1335
|
-
/** Action taken */
|
|
1336
|
-
action: ReviewAction;
|
|
1337
|
-
/** Updated file path (if modified) */
|
|
1338
|
-
updatedPath?: string;
|
|
1339
|
-
/** Status message */
|
|
1340
|
-
message: string;
|
|
1341
|
-
/** Tombstone id cleared by an approve action (for the caller to revoke). */
|
|
1342
|
-
clearedTombstoneId?: string;
|
|
1343
|
-
}
|
|
1344
|
-
interface ReviewListResult {
|
|
1345
|
-
/** Items pending review */
|
|
1346
|
-
items: ReviewItem[];
|
|
1347
|
-
/** Total count */
|
|
1348
|
-
total: number;
|
|
1349
|
-
/** Duration in ms */
|
|
1350
|
-
durationMs: number;
|
|
1351
|
-
}
|
|
1352
|
-
interface ReviewOptions {
|
|
1353
|
-
/** Memory root directory */
|
|
1354
|
-
memoryDir: string;
|
|
1355
|
-
/** Filter by reason */
|
|
1356
|
-
reason?: ReviewItem["reviewReason"];
|
|
1357
|
-
/** Max items to return (default: 50) */
|
|
1358
|
-
limit?: number;
|
|
1359
|
-
/** Include items with confidence below this threshold (default: 0.7) */
|
|
1360
|
-
confidenceThreshold?: number;
|
|
1361
|
-
}
|
|
1362
|
-
interface ReviewActionOptions {
|
|
1363
|
-
/** Match the threshold used when listing review items (default: 0.7) */
|
|
1364
|
-
confidenceThreshold?: number;
|
|
1365
|
-
/**
|
|
1366
|
-
* Revocation hook (issue #1579). When approving a memory whose frontmatter
|
|
1367
|
-
* carries `blockedBy: <tombstoneId>`, the hook fires so the caller (CLI /
|
|
1368
|
-
* orchestrator) can append a `kind: "revocation"` tombstone entry —
|
|
1369
|
-
* re-allowing the content. Fire-and-forget: a revocation failure MUST NOT
|
|
1370
|
-
* fail the approval (gotcha #13). The hook receives the tombstone id and
|
|
1371
|
-
* the memory id.
|
|
1372
|
-
*/
|
|
1373
|
-
onApproveBlockedMemory?: (tombstoneId: string, memoryId: string) => void | Promise<void>;
|
|
1044
|
+
declare function parseTouchedFiles(diff: string | null | undefined): string[];
|
|
1045
|
+
/**
|
|
1046
|
+
* Build a review-context ranking for a set of candidate memories.
|
|
1047
|
+
*
|
|
1048
|
+
* Contract:
|
|
1049
|
+
* - `touchedFiles` is the parsed diff file list.
|
|
1050
|
+
* - `candidates` is passed through unchanged when no boost applies.
|
|
1051
|
+
* - When a boost applies, the result is sorted by `(score + boost)` desc,
|
|
1052
|
+
* with a stable secondary sort on the original `id` for determinism
|
|
1053
|
+
* (CLAUDE.md #19 — comparators must return 0 for equal items).
|
|
1054
|
+
*/
|
|
1055
|
+
declare function rankReviewCandidates(candidates: ReviewCandidate[], touchedFiles: string[]): Array<ReviewCandidate & {
|
|
1056
|
+
boost: number;
|
|
1057
|
+
}>;
|
|
1058
|
+
interface PackReviewContextInput {
|
|
1059
|
+
/** Unified diff, as produced by `git diff`. */
|
|
1060
|
+
diff: string | null | undefined;
|
|
1061
|
+
/** Candidate memories from the upstream recall pipeline. */
|
|
1062
|
+
candidates: ReviewCandidate[];
|
|
1374
1063
|
}
|
|
1375
1064
|
/**
|
|
1376
|
-
*
|
|
1065
|
+
* Top-level entry point used by the orchestrator (and CLI / bench) when a
|
|
1066
|
+
* review-intent prompt is detected.
|
|
1067
|
+
*
|
|
1068
|
+
* Parses the diff, re-ranks the candidates, and returns both artefacts so
|
|
1069
|
+
* the caller can surface `touchedFiles` as context and `rankedRecall` as
|
|
1070
|
+
* the recall result.
|
|
1377
1071
|
*/
|
|
1378
|
-
declare function
|
|
1072
|
+
declare function packReviewContext(input: PackReviewContextInput): ReviewContext;
|
|
1379
1073
|
/**
|
|
1380
|
-
*
|
|
1074
|
+
* Input for the structural-context-aware review-context packer. The pure
|
|
1075
|
+
* {@link packReviewContext} stays unchanged (gate-off parity); this async
|
|
1076
|
+
* variant consults a {@link StructuralContextProvider} to expand the diff's
|
|
1077
|
+
* touched FILE paths into touched SYMBOL names, widening the match set so
|
|
1078
|
+
* memories that mention a changed symbol — not just the file path — float
|
|
1079
|
+
* up. The gate (`structuralProvider !== "none"`) is checked ONCE by the
|
|
1080
|
+
* caller, never inside this function (rule 39).
|
|
1381
1081
|
*/
|
|
1382
|
-
|
|
1383
|
-
|
|
1082
|
+
interface PackReviewContextStructuralInput extends PackReviewContextInput {
|
|
1083
|
+
/** A probed structural-context provider. Never undefined here. */
|
|
1084
|
+
provider: StructuralContextProvider;
|
|
1085
|
+
/** Cancellation forwarded to the provider subprocess (rule 40). */
|
|
1086
|
+
signal?: AbortSignal;
|
|
1087
|
+
}
|
|
1384
1088
|
/**
|
|
1385
|
-
*
|
|
1089
|
+
* Structural-context-aware packer.
|
|
1386
1090
|
*
|
|
1387
|
-
*
|
|
1388
|
-
*
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
/**
|
|
1412
|
-
|
|
1413
|
-
/**
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
/**
|
|
1426
|
-
|
|
1427
|
-
/** Change type */
|
|
1428
|
-
type: "added" | "modified" | "deleted";
|
|
1429
|
-
/** Current content hash */
|
|
1430
|
-
currentHash: string;
|
|
1431
|
-
/** Previous content hash (if modified) */
|
|
1432
|
-
previousHash?: string;
|
|
1433
|
-
/** File size in bytes */
|
|
1434
|
-
size: number;
|
|
1435
|
-
}
|
|
1436
|
-
interface SyncState {
|
|
1437
|
-
/** Map of relative path → content hash */
|
|
1438
|
-
fileHashes: Record<string, string>;
|
|
1439
|
-
/** Last sync timestamp */
|
|
1440
|
-
lastSyncAt: string;
|
|
1441
|
-
/** Version of state format */
|
|
1442
|
-
version: number;
|
|
1091
|
+
* Contract (issue #1548 Track A PR 5, prove-fail-before characterization):
|
|
1092
|
+
* - Provider returns symbols (`ok: true`) → symbol names are ADDED to the
|
|
1093
|
+
* match set alongside touched files; memories mentioning a symbol get the
|
|
1094
|
+
* same bounded additive boost as a file-path match.
|
|
1095
|
+
* - Provider fails (`ok: false`, any code) → ranking falls back to
|
|
1096
|
+
* FILE-PATH-ONLY boosting, BYTE-IDENTICAL to {@link packReviewContext}
|
|
1097
|
+
* (the match set is exactly the touched files), AND `structuralDegradation`
|
|
1098
|
+
* is populated so xray/doctor can surface the failure (rule 34).
|
|
1099
|
+
*
|
|
1100
|
+
* The underlying ranker ({@link rankReviewCandidates}) is reused unchanged,
|
|
1101
|
+
* so the deterministic ordering, boost cap, and tie-break are identical to
|
|
1102
|
+
* the pure path.
|
|
1103
|
+
*/
|
|
1104
|
+
declare function packReviewContextStructural(input: PackReviewContextStructuralInput): Promise<ReviewContext>;
|
|
1105
|
+
|
|
1106
|
+
/** Injectable spawn shape so tests substitute a stub (rule 33). */
|
|
1107
|
+
type StructuralSpawnFn = (command: string, argv: readonly string[], options: {
|
|
1108
|
+
timeout: number;
|
|
1109
|
+
signal?: AbortSignal;
|
|
1110
|
+
}) => Promise<{
|
|
1111
|
+
stdout: string;
|
|
1112
|
+
stderr: string;
|
|
1113
|
+
}>;
|
|
1114
|
+
interface SubprocessProviderOptions {
|
|
1115
|
+
/** Absolute path to the binary (rule 24 — statSync at probe time). */
|
|
1116
|
+
readonly command: string;
|
|
1117
|
+
/**
|
|
1118
|
+
* Extra argv appended after the symbols-for-diff subcommand
|
|
1119
|
+
* (rule 10 — array, never a shell string).
|
|
1120
|
+
*/
|
|
1121
|
+
readonly args?: readonly string[];
|
|
1122
|
+
/** Per-call deadline in ms. Default 5000. */
|
|
1123
|
+
readonly timeoutMs?: number;
|
|
1124
|
+
/**
|
|
1125
|
+
* Subcommand the provider invokes for symbol expansion.
|
|
1126
|
+
* Default `"symbols-for-diff"`.
|
|
1127
|
+
*/
|
|
1128
|
+
readonly symbolsSubcommand?: string;
|
|
1129
|
+
/** Test seam — defaults to promisified `execFile`. */
|
|
1130
|
+
readonly spawn?: StructuralSpawnFn;
|
|
1443
1131
|
}
|
|
1444
|
-
declare function syncChanges(options: SyncOptions): SyncResult;
|
|
1445
1132
|
/**
|
|
1446
|
-
*
|
|
1447
|
-
*
|
|
1133
|
+
* Construct a structural-context provider backed by an external subprocess.
|
|
1134
|
+
* The instance is self-contained: callers register it via
|
|
1135
|
+
* `registerStructuralContextProvider(scope, provider)` and dispose via the
|
|
1136
|
+
* returned unregister handle.
|
|
1448
1137
|
*/
|
|
1449
|
-
declare function
|
|
1450
|
-
stop: () => void;
|
|
1451
|
-
};
|
|
1452
|
-
|
|
1138
|
+
declare function createSubprocessStructuralProvider(options: SubprocessProviderOptions): StructuralContextProvider;
|
|
1453
1139
|
/**
|
|
1454
|
-
*
|
|
1455
|
-
*
|
|
1140
|
+
* Augment the pure {@link describeStructuralProviderStatus} with a LIVE probe
|
|
1141
|
+
* so `remnic doctor` can render "configured / probed / last error code".
|
|
1456
1142
|
*
|
|
1457
|
-
*
|
|
1458
|
-
*
|
|
1143
|
+
* - `"none"` → inactive (no probe).
|
|
1144
|
+
* - `"subprocess"` → builds a throwaway provider from
|
|
1145
|
+
* `structuralProviderCommand`, probes it, disposes it.
|
|
1146
|
+
* - `"native"` → asks `isCodingGraphInstalled()` whether the optional
|
|
1147
|
+
* @remnic/coding-graph peer is present (the adapter that
|
|
1148
|
+
* turns the engine into a provider lands in #1551).
|
|
1149
|
+
*
|
|
1150
|
+
* Never throws — a probe failure populates `probed.available = false`.
|
|
1459
1151
|
*/
|
|
1152
|
+
declare function probeStructuralProviderForDoctor(config: PluginConfig): Promise<StructuralProviderStatus>;
|
|
1460
1153
|
|
|
1461
1154
|
/**
|
|
1462
|
-
*
|
|
1463
|
-
* into consolidation prompts.
|
|
1155
|
+
* Binary file lifecycle management types.
|
|
1464
1156
|
*
|
|
1465
|
-
*
|
|
1466
|
-
*
|
|
1467
|
-
* If the budget is exceeded, appends a truncation footer listing omitted extensions.
|
|
1157
|
+
* Defines the configuration, manifest, and record structures for the
|
|
1158
|
+
* three-stage binary lifecycle pipeline: mirror, redirect, clean.
|
|
1468
1159
|
*/
|
|
1469
|
-
|
|
1160
|
+
interface BinaryLifecycleConfig {
|
|
1161
|
+
/** Master toggle. Default: false. */
|
|
1162
|
+
enabled: boolean;
|
|
1163
|
+
/** Days after mirror before local copy is eligible for cleanup. Default: 7. */
|
|
1164
|
+
gracePeriodDays: number;
|
|
1165
|
+
/** Files larger than this are skipped during scan. Default: 50 MB. */
|
|
1166
|
+
maxBinarySizeBytes: number;
|
|
1167
|
+
/** Glob patterns for binary file types to manage. */
|
|
1168
|
+
scanPatterns: string[];
|
|
1169
|
+
/** Backend configuration for binary storage. */
|
|
1170
|
+
backend: BinaryStorageBackendConfig;
|
|
1171
|
+
}
|
|
1172
|
+
interface BinaryStorageBackendConfig {
|
|
1173
|
+
/** Backend type. "filesystem" copies to a local directory. "none" is a no-op (dry-run/testing). */
|
|
1174
|
+
type: "filesystem" | "s3" | "none";
|
|
1175
|
+
/** Destination directory for the filesystem backend. */
|
|
1176
|
+
basePath?: string;
|
|
1177
|
+
/** S3 bucket name (future). */
|
|
1178
|
+
s3Bucket?: string;
|
|
1179
|
+
/** S3 region (future). */
|
|
1180
|
+
s3Region?: string;
|
|
1181
|
+
/** S3 key prefix (future). */
|
|
1182
|
+
s3Prefix?: string;
|
|
1183
|
+
}
|
|
1184
|
+
type BinaryAssetStatus = "pending" | "mirrored" | "redirected" | "cleaned" | "error";
|
|
1185
|
+
interface BinaryAssetRecord {
|
|
1186
|
+
/** Relative path from memoryDir to the original file. */
|
|
1187
|
+
originalPath: string;
|
|
1188
|
+
/** Path (or URL) in the backend storage. */
|
|
1189
|
+
mirroredPath: string;
|
|
1190
|
+
/** Optional user-resolvable target to write into markdown links. */
|
|
1191
|
+
redirectPath?: string;
|
|
1192
|
+
/** SHA-256 hex digest of file content. */
|
|
1193
|
+
contentHash: string;
|
|
1194
|
+
/** File size in bytes. */
|
|
1195
|
+
sizeBytes: number;
|
|
1196
|
+
/** MIME type (e.g. "image/png"). */
|
|
1197
|
+
mimeType: string;
|
|
1198
|
+
/** ISO 8601 timestamp when the file was mirrored. */
|
|
1199
|
+
mirroredAt: string;
|
|
1200
|
+
/** ISO 8601 timestamp when markdown references were rewritten. */
|
|
1201
|
+
redirectedAt?: string;
|
|
1202
|
+
/** ISO 8601 timestamp when the local copy was deleted. */
|
|
1203
|
+
cleanedAt?: string;
|
|
1204
|
+
/** Current lifecycle status. */
|
|
1205
|
+
status: BinaryAssetStatus;
|
|
1206
|
+
}
|
|
1207
|
+
interface BinaryLifecycleManifest {
|
|
1208
|
+
version: 1;
|
|
1209
|
+
assets: BinaryAssetRecord[];
|
|
1210
|
+
lastScanAt?: string;
|
|
1211
|
+
}
|
|
1212
|
+
interface PipelineResult {
|
|
1213
|
+
scanned: number;
|
|
1214
|
+
mirrored: number;
|
|
1215
|
+
redirected: number;
|
|
1216
|
+
cleaned: number;
|
|
1217
|
+
errors: string[];
|
|
1218
|
+
dryRun: boolean;
|
|
1219
|
+
}
|
|
1220
|
+
declare const DEFAULT_SCAN_PATTERNS: string[];
|
|
1221
|
+
declare const DEFAULT_MAX_BINARY_SIZE_BYTES: number;
|
|
1222
|
+
declare const DEFAULT_GRACE_PERIOD_DAYS = 7;
|
|
1223
|
+
|
|
1470
1224
|
/**
|
|
1471
|
-
*
|
|
1472
|
-
*
|
|
1225
|
+
* Binary storage backend interface and implementations.
|
|
1226
|
+
*
|
|
1227
|
+
* Backends handle the actual persistence of binary files to an external
|
|
1228
|
+
* location. The pipeline calls upload/exists/delete through this interface
|
|
1229
|
+
* so swapping storage providers requires no pipeline changes.
|
|
1473
1230
|
*/
|
|
1474
|
-
|
|
1231
|
+
|
|
1232
|
+
interface BinaryStorageBackend {
|
|
1233
|
+
/** Discriminator for the backend type. */
|
|
1234
|
+
readonly type: string;
|
|
1235
|
+
/**
|
|
1236
|
+
* Upload a local file to the backend.
|
|
1237
|
+
* @returns The backend path or URL where the file was stored.
|
|
1238
|
+
*/
|
|
1239
|
+
upload(localPath: string, remotePath: string): Promise<string>;
|
|
1240
|
+
/** Check whether a remote path already exists in the backend. */
|
|
1241
|
+
exists(remotePath: string): Promise<boolean>;
|
|
1242
|
+
/** Delete a file from the backend. */
|
|
1243
|
+
delete(remotePath: string): Promise<void>;
|
|
1244
|
+
/** Return the user-resolvable markdown target for a stored backend path. */
|
|
1245
|
+
getRedirectTarget?(remotePath: string): string;
|
|
1246
|
+
}
|
|
1247
|
+
declare class FilesystemBackend implements BinaryStorageBackend {
|
|
1248
|
+
readonly type = "filesystem";
|
|
1249
|
+
private readonly basePath;
|
|
1250
|
+
constructor(basePath: string);
|
|
1251
|
+
private resolveRemotePath;
|
|
1252
|
+
private isInsideBase;
|
|
1253
|
+
private realBasePathIfExists;
|
|
1254
|
+
private ensureBaseDirectory;
|
|
1255
|
+
private ensureSafeParentDirectory;
|
|
1256
|
+
private resolveExistingRemotePath;
|
|
1257
|
+
upload(localPath: string, remotePath: string): Promise<string>;
|
|
1258
|
+
exists(remotePath: string): Promise<boolean>;
|
|
1259
|
+
delete(remotePath: string): Promise<void>;
|
|
1260
|
+
getRedirectTarget(remotePath: string): string;
|
|
1261
|
+
}
|
|
1262
|
+
declare class NoneBackend implements BinaryStorageBackend {
|
|
1263
|
+
readonly type = "none";
|
|
1264
|
+
upload(_localPath: string, remotePath: string): Promise<string>;
|
|
1265
|
+
exists(_remotePath: string): Promise<boolean>;
|
|
1266
|
+
delete(_remotePath: string): Promise<void>;
|
|
1267
|
+
}
|
|
1268
|
+
declare function createBackend(cfg: BinaryStorageBackendConfig): BinaryStorageBackend;
|
|
1475
1269
|
|
|
1476
1270
|
/**
|
|
1477
|
-
*
|
|
1271
|
+
* Binary file scanner.
|
|
1478
1272
|
*
|
|
1479
|
-
*
|
|
1480
|
-
*
|
|
1481
|
-
*
|
|
1273
|
+
* Recursively walks the memory directory, matches files against configured
|
|
1274
|
+
* glob patterns, skips files already tracked in the manifest, and respects
|
|
1275
|
+
* the max-size limit.
|
|
1482
1276
|
*/
|
|
1483
1277
|
|
|
1484
1278
|
/**
|
|
1485
|
-
*
|
|
1486
|
-
*
|
|
1487
|
-
*
|
|
1488
|
-
*
|
|
1279
|
+
* Test whether a filename matches any of the provided glob patterns.
|
|
1280
|
+
* Supports simple `*.ext` patterns (the default scan patterns).
|
|
1281
|
+
* For more complex globs a proper library should be used; this covers
|
|
1282
|
+
* the 95% case without adding a dependency.
|
|
1489
1283
|
*/
|
|
1490
|
-
declare
|
|
1491
|
-
constructor(message: string);
|
|
1492
|
-
}
|
|
1284
|
+
declare function matchesPatterns(filename: string, patterns: string[]): boolean;
|
|
1493
1285
|
/**
|
|
1494
|
-
*
|
|
1495
|
-
*
|
|
1286
|
+
* Scan memoryDir recursively for binary files matching the configured patterns.
|
|
1287
|
+
* Returns relative paths (relative to memoryDir) for files not yet tracked.
|
|
1496
1288
|
*/
|
|
1497
|
-
declare
|
|
1498
|
-
private readonly connectors;
|
|
1499
|
-
/**
|
|
1500
|
-
* Register a connector. Throws `LiveConnectorRegistryError` if the id is
|
|
1501
|
-
* malformed or already registered.
|
|
1502
|
-
*
|
|
1503
|
-
* Re-registration is rejected (rather than silently overwriting) because
|
|
1504
|
-
* silent overwrites mask plugin loading bugs in development and could let
|
|
1505
|
-
* a malicious extension shadow a built-in connector.
|
|
1506
|
-
*/
|
|
1507
|
-
register(connector: LiveConnector): void;
|
|
1508
|
-
/**
|
|
1509
|
-
* Look up a connector by id. Returns `undefined` if not registered.
|
|
1510
|
-
*/
|
|
1511
|
-
get(id: string): LiveConnector | undefined;
|
|
1512
|
-
/**
|
|
1513
|
-
* Return all registered connectors, sorted by id for stable enumeration.
|
|
1514
|
-
*/
|
|
1515
|
-
list(): LiveConnector[];
|
|
1516
|
-
/**
|
|
1517
|
-
* Remove a connector. Returns `true` if a connector was removed, `false`
|
|
1518
|
-
* otherwise. The cursor / state file on disk is **not** touched — callers
|
|
1519
|
-
* who want to fully decommission a connector must also delete its state
|
|
1520
|
-
* file via the `state-store` module.
|
|
1521
|
-
*/
|
|
1522
|
-
unregister(id: string): boolean;
|
|
1523
|
-
/**
|
|
1524
|
-
* Number of registered connectors. Cheap; safe to call frequently.
|
|
1525
|
-
*/
|
|
1526
|
-
size(): number;
|
|
1527
|
-
}
|
|
1289
|
+
declare function scanForBinaries(memoryDir: string, config: BinaryLifecycleConfig, manifest: BinaryLifecycleManifest): Promise<string[]>;
|
|
1528
1290
|
|
|
1529
1291
|
/**
|
|
1530
|
-
*
|
|
1531
|
-
*
|
|
1532
|
-
* Concrete `LiveConnector` implementation that incrementally imports text
|
|
1533
|
-
* content from a user's Google Drive into Remnic. Built on top of the
|
|
1534
|
-
* framework shipped in PR 1/N (`framework.ts` / `registry.ts` /
|
|
1535
|
-
* `state-store.ts`).
|
|
1536
|
-
*
|
|
1537
|
-
* Design notes:
|
|
1538
|
-
*
|
|
1539
|
-
* - **Cursor semantics.** We page Drive with the official `changes` API
|
|
1540
|
-
* when a `startPageToken` is available. The cursor is opaque from the
|
|
1541
|
-
* framework's POV (`{kind: "drivePageToken", value: ...}`), and on the
|
|
1542
|
-
* very first sync (cursor=null) we call `changes.getStartPageToken()`
|
|
1543
|
-
* to seed it without importing anything. This matches the documented
|
|
1544
|
-
* Drive incremental-sync recipe and means re-runs never re-ingest the
|
|
1545
|
-
* same file as long as the cursor file survives.
|
|
1546
|
-
*
|
|
1547
|
-
* - **Folder scope.** When `folderIds` is non-empty, files are filtered
|
|
1548
|
-
* to those whose `parents` intersect the configured folder set. Drive
|
|
1549
|
-
* does not currently support server-side parent filtering on the
|
|
1550
|
-
* `changes.list` endpoint, so we pull the change record's `file` payload
|
|
1551
|
-
* and apply the filter on our side. Folder ids are validated up front so
|
|
1552
|
-
* a typo in config doesn't silently cause a broad import.
|
|
1553
|
-
*
|
|
1554
|
-
* - **Content extraction.** Google-native MIME types
|
|
1555
|
-
* (`application/vnd.google-apps.{document,spreadsheet,presentation}`)
|
|
1556
|
-
* are exported via `files.export` to plaintext. Plain-text MIME types
|
|
1557
|
-
* are pulled with `files.get?alt=media`. Everything else is skipped —
|
|
1558
|
-
* bytes from binary formats (images, PDFs, archives) belong in the
|
|
1559
|
-
* binary-lifecycle pipeline, not in the textual ingestion path.
|
|
1560
|
-
*
|
|
1561
|
-
* - **Idempotency.** Each emitted `ConnectorDocument.source` carries
|
|
1562
|
-
* `externalId = file.id` plus `externalRevision = file.modifiedTime`,
|
|
1563
|
-
* so downstream dedup (CLAUDE.md gotcha #44 — never index content that
|
|
1564
|
-
* failed to persist) can recognise repeat fetches even if the cursor is
|
|
1565
|
-
* manually rewound.
|
|
1566
|
-
*
|
|
1567
|
-
* - **Privacy.** No document content is ever logged. Folder ids and
|
|
1568
|
-
* counts may be logged. OAuth credentials (`clientId`,
|
|
1569
|
-
* `clientSecret`, `refreshToken`) are accepted via config but the
|
|
1570
|
-
* intent is for callers to populate them from a secret store; we never
|
|
1571
|
-
* persist credentials through the connector state-store. Per CLAUDE.md
|
|
1572
|
-
* repository-privacy rules, no real credentials may appear in tests,
|
|
1573
|
-
* fixtures, or comments.
|
|
1292
|
+
* Binary lifecycle manifest — read/write operations.
|
|
1574
1293
|
*
|
|
1575
|
-
*
|
|
1576
|
-
*
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1294
|
+
* The manifest lives at `${memoryDir}/.binary-lifecycle/manifest.json`.
|
|
1295
|
+
* Writes use the atomic temp-then-rename pattern (CLAUDE.md #54).
|
|
1296
|
+
*/
|
|
1297
|
+
|
|
1298
|
+
declare function manifestDir(memoryDir: string): string;
|
|
1299
|
+
declare function manifestPath(memoryDir: string): string;
|
|
1300
|
+
/**
|
|
1301
|
+
* Read the manifest from disk. Returns a fresh empty manifest if the file
|
|
1302
|
+
* does not exist. Existing invalid manifests fail closed so the pipeline does
|
|
1303
|
+
* not overwrite state needed for safe cleanup.
|
|
1304
|
+
*/
|
|
1305
|
+
declare function readManifest(memoryDir: string): Promise<BinaryLifecycleManifest>;
|
|
1306
|
+
/**
|
|
1307
|
+
* Write the manifest atomically: write to a temp file, then rename.
|
|
1308
|
+
* CLAUDE.md #54: never delete before write. Write temp first, rename atomically.
|
|
1309
|
+
*/
|
|
1310
|
+
declare function writeManifest(memoryDir: string, manifest: BinaryLifecycleManifest): Promise<void>;
|
|
1311
|
+
declare function emptyManifest(): BinaryLifecycleManifest;
|
|
1312
|
+
|
|
1313
|
+
/**
|
|
1314
|
+
* Binary lifecycle pipeline — mirror, redirect, clean.
|
|
1581
1315
|
*
|
|
1582
|
-
*
|
|
1583
|
-
*
|
|
1316
|
+
* Three-stage pipeline:
|
|
1317
|
+
* 1. Mirror: upload binary to backend, record in manifest
|
|
1318
|
+
* 2. Redirect: scan markdown for inline refs, replace with redirect path
|
|
1319
|
+
* 3. Clean: after grace period, delete local copy
|
|
1584
1320
|
*/
|
|
1585
1321
|
|
|
1322
|
+
/** Minimal logger interface so we don't depend on the full logger module. */
|
|
1323
|
+
interface PipelineLogger {
|
|
1324
|
+
info(msg: string): void;
|
|
1325
|
+
warn(msg: string): void;
|
|
1326
|
+
error(msg: string): void;
|
|
1327
|
+
}
|
|
1328
|
+
type ReadMarkdownFile = (filePath: string) => Promise<string>;
|
|
1329
|
+
type WriteMarkdownFile = (filePath: string, content: string) => Promise<void>;
|
|
1330
|
+
interface PipelineOptions {
|
|
1331
|
+
dryRun?: boolean;
|
|
1332
|
+
/** Force-clean all files past grace period, ignoring redirect status. */
|
|
1333
|
+
forceClean?: boolean;
|
|
1334
|
+
/** Test hook for deterministic markdown read failures. */
|
|
1335
|
+
readMarkdownFile?: ReadMarkdownFile;
|
|
1336
|
+
/** Test hook for deterministic markdown write failures. */
|
|
1337
|
+
writeMarkdownFile?: WriteMarkdownFile;
|
|
1338
|
+
}
|
|
1586
1339
|
/**
|
|
1587
|
-
*
|
|
1340
|
+
* Run the binary lifecycle pipeline: scan, mirror, redirect, clean.
|
|
1588
1341
|
*/
|
|
1589
|
-
declare
|
|
1342
|
+
declare function runBinaryLifecyclePipeline(memoryDir: string, config: BinaryLifecycleConfig, backend: BinaryStorageBackend, log: PipelineLogger, opts?: PipelineOptions): Promise<PipelineResult>;
|
|
1343
|
+
|
|
1590
1344
|
/**
|
|
1591
|
-
*
|
|
1592
|
-
*
|
|
1345
|
+
* @remnic/core — Workspace Tree Projection
|
|
1346
|
+
*
|
|
1347
|
+
* Generates a human-readable `.engram/context-tree/` from canonical memory.
|
|
1348
|
+
* Each node is a `.md` file with rich metadata, * (provenance, trust, confidence, source anchors).
|
|
1349
|
+
* Manual edits are preserved in fenced blocks.
|
|
1593
1350
|
*/
|
|
1594
|
-
|
|
1351
|
+
interface TreeNode {
|
|
1352
|
+
/** Relative path from context-tree root, e.g. "entities/claude.md" */
|
|
1353
|
+
path: string;
|
|
1354
|
+
/** Category from canonical memory */
|
|
1355
|
+
category: string;
|
|
1356
|
+
/** Human-readable title */
|
|
1357
|
+
title: string;
|
|
1358
|
+
/** File content (rendered markdown) */
|
|
1359
|
+
content: string;
|
|
1360
|
+
/** Source memory IDs that contributed to this node */
|
|
1361
|
+
sourceAnchors: string[];
|
|
1362
|
+
/** Confidence (0-1) */
|
|
1363
|
+
confidence: number;
|
|
1364
|
+
/** Trust zone classification */
|
|
1365
|
+
confidenceTier: string;
|
|
1366
|
+
/** When this node was generated */
|
|
1367
|
+
generatedAt: string;
|
|
1368
|
+
/** Provenance chain */
|
|
1369
|
+
provenance: ProvenanceEntry[];
|
|
1370
|
+
}
|
|
1371
|
+
interface ProvenanceEntry {
|
|
1372
|
+
memoryId: string;
|
|
1373
|
+
source: string;
|
|
1374
|
+
extracted: string;
|
|
1375
|
+
}
|
|
1376
|
+
interface GenerateOptions {
|
|
1377
|
+
/** Memory root directory (e.g. ~/.openclaw/workspace/memory/local) */
|
|
1378
|
+
memoryDir: string;
|
|
1379
|
+
/** Output directory (e.g. .engram/context-tree) */
|
|
1380
|
+
outputDir: string;
|
|
1381
|
+
/** Categories to include (default: all) */
|
|
1382
|
+
categories?: string[];
|
|
1383
|
+
/** Whether to include entity graph */
|
|
1384
|
+
includeEntities?: boolean;
|
|
1385
|
+
/** Whether to include orphaned questions */
|
|
1386
|
+
includeQuestions?: boolean;
|
|
1387
|
+
/** Max nodes per category (default: unlimited) */
|
|
1388
|
+
maxPerCategory?: number;
|
|
1389
|
+
/** Whether to watch for changes and regenerate incrementally */
|
|
1390
|
+
watch?: boolean;
|
|
1391
|
+
}
|
|
1392
|
+
interface GenerateResult {
|
|
1393
|
+
nodesGenerated: number;
|
|
1394
|
+
nodesSkipped: number;
|
|
1395
|
+
categories: Record<string, number>;
|
|
1396
|
+
durationMs: number;
|
|
1397
|
+
outputDir: string;
|
|
1398
|
+
}
|
|
1595
1399
|
/**
|
|
1596
|
-
*
|
|
1597
|
-
*
|
|
1598
|
-
*
|
|
1599
|
-
* memory layer.
|
|
1400
|
+
* Generate a context tree from canonical memory.
|
|
1401
|
+
*
|
|
1402
|
+
* Reads memory `.md` files from the source directory, * and projects them into a clean, * human-readable tree structure at `outputDir`.
|
|
1600
1403
|
*/
|
|
1601
|
-
declare
|
|
1404
|
+
declare function generateContextTree(options: GenerateOptions): Promise<GenerateResult>;
|
|
1405
|
+
|
|
1602
1406
|
/**
|
|
1603
|
-
*
|
|
1407
|
+
* @remnic/core — Onboarding
|
|
1408
|
+
*
|
|
1409
|
+
* Detects project language, shape, and documentation to produce
|
|
1410
|
+
* an onboarding plan for memory ingestion.
|
|
1604
1411
|
*/
|
|
1605
|
-
interface
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1412
|
+
interface OnboardOptions {
|
|
1413
|
+
/** Directory to scan (defaults to cwd) */
|
|
1414
|
+
directory?: string;
|
|
1415
|
+
/** Max depth to walk (default: 6) */
|
|
1416
|
+
maxDepth?: number;
|
|
1417
|
+
/** Directories to skip */
|
|
1418
|
+
excludeDirs?: string[];
|
|
1419
|
+
}
|
|
1420
|
+
interface LanguageInfo {
|
|
1421
|
+
/** Language name (e.g. "TypeScript", "Python") */
|
|
1422
|
+
language: string;
|
|
1423
|
+
/** Confidence in detection (0-1) */
|
|
1424
|
+
confidence: number;
|
|
1425
|
+
/** Evidence (e.g. ["package.json", "tsconfig.json", "*.ts files"]) */
|
|
1426
|
+
evidence: string[];
|
|
1427
|
+
}
|
|
1428
|
+
interface DocFile {
|
|
1429
|
+
/** Absolute path */
|
|
1430
|
+
path: string;
|
|
1431
|
+
/** Relative path from project root */
|
|
1432
|
+
relativePath: string;
|
|
1433
|
+
/** Estimated type */
|
|
1434
|
+
kind: "readme" | "changelog" | "contributing" | "license" | "config" | "docs" | "other";
|
|
1435
|
+
/** File size in bytes */
|
|
1436
|
+
size: number;
|
|
1437
|
+
}
|
|
1438
|
+
type ProjectShape = "app" | "library" | "monorepo" | "workspace" | "script" | "unknown";
|
|
1439
|
+
interface OnboardResult {
|
|
1440
|
+
/** Project root */
|
|
1441
|
+
directory: string;
|
|
1442
|
+
/** Detected languages (sorted by confidence) */
|
|
1443
|
+
languages: LanguageInfo[];
|
|
1444
|
+
/** Detected project shape */
|
|
1445
|
+
shape: ProjectShape;
|
|
1446
|
+
/** Shape evidence */
|
|
1447
|
+
shapeEvidence: string[];
|
|
1448
|
+
/** Discovered documentation files */
|
|
1449
|
+
docs: DocFile[];
|
|
1450
|
+
/** Total files scanned */
|
|
1451
|
+
totalFiles: number;
|
|
1452
|
+
/** Duration in ms */
|
|
1453
|
+
durationMs: number;
|
|
1454
|
+
/** Suggested ingestion plan */
|
|
1455
|
+
plan: IngestionPlan;
|
|
1456
|
+
}
|
|
1457
|
+
interface IngestionPlan {
|
|
1458
|
+
/** Priority files to ingest first */
|
|
1459
|
+
priorityFiles: DocFile[];
|
|
1460
|
+
/** Estimated total files to ingest */
|
|
1461
|
+
estimatedFiles: number;
|
|
1462
|
+
/** Recommended categories */
|
|
1463
|
+
categories: string[];
|
|
1464
|
+
/** Suggested memory namespace */
|
|
1465
|
+
suggestedNamespace: string;
|
|
1613
1466
|
}
|
|
1467
|
+
declare function onboard(options: OnboardOptions): OnboardResult;
|
|
1468
|
+
|
|
1614
1469
|
/**
|
|
1615
|
-
*
|
|
1616
|
-
* `googleapis`; tests pass a stub here to avoid the optional-peer-dep
|
|
1617
|
-
* machinery and to keep the test suite hermetic.
|
|
1470
|
+
* @remnic/core — Curation
|
|
1618
1471
|
*
|
|
1619
|
-
*
|
|
1472
|
+
* Deliberate ingestion of files into memory with provenance tracking.
|
|
1473
|
+
* Supports statement-level extraction, dedup, and contradiction checks.
|
|
1620
1474
|
*/
|
|
1621
|
-
interface
|
|
1622
|
-
|
|
1475
|
+
interface CurateOptions {
|
|
1476
|
+
/** File or directory path to curate */
|
|
1477
|
+
targetPath: string;
|
|
1478
|
+
/** Memory root directory for writing */
|
|
1479
|
+
memoryDir: string;
|
|
1480
|
+
/** Source label (e.g. "manual", "docs", "onboarding") */
|
|
1481
|
+
source?: string;
|
|
1482
|
+
/** Category override (default: auto-detect) */
|
|
1483
|
+
category?: string;
|
|
1484
|
+
/** Confidence to assign (default: 0.9 for curated items) */
|
|
1485
|
+
confidence?: number;
|
|
1486
|
+
/** Entity reference to attach */
|
|
1487
|
+
entityRef?: string;
|
|
1488
|
+
/** Tags to add */
|
|
1489
|
+
tags?: string[];
|
|
1490
|
+
/** Whether to perform dedup check against existing memories */
|
|
1491
|
+
checkDuplicates?: boolean;
|
|
1492
|
+
/** Whether to detect contradictions */
|
|
1493
|
+
checkContradictions?: boolean;
|
|
1494
|
+
/** Whether to write files (default: true). False = dry run */
|
|
1495
|
+
write?: boolean;
|
|
1496
|
+
}
|
|
1497
|
+
interface CuratedStatement {
|
|
1498
|
+
/** Unique ID for this statement */
|
|
1499
|
+
id: string;
|
|
1500
|
+
/** The extracted statement text */
|
|
1501
|
+
content: string;
|
|
1502
|
+
/** Category */
|
|
1503
|
+
category: string;
|
|
1504
|
+
/** Confidence */
|
|
1505
|
+
confidence: number;
|
|
1506
|
+
/** Provenance info */
|
|
1507
|
+
provenance: StatementProvenance;
|
|
1508
|
+
/** Hash of content for dedup */
|
|
1509
|
+
contentHash: string;
|
|
1510
|
+
/** Tags */
|
|
1511
|
+
tags: string[];
|
|
1512
|
+
/** Entity reference */
|
|
1513
|
+
entityRef?: string;
|
|
1514
|
+
}
|
|
1515
|
+
interface StatementProvenance {
|
|
1516
|
+
/** Source file path */
|
|
1517
|
+
sourcePath: string;
|
|
1518
|
+
/** Relative path from project root */
|
|
1519
|
+
relativePath: string;
|
|
1520
|
+
/** Source label */
|
|
1521
|
+
source: string;
|
|
1522
|
+
/** Line number if extractable (0 = unknown) */
|
|
1523
|
+
lineNumber: number;
|
|
1524
|
+
/** Timestamp of ingestion */
|
|
1525
|
+
ingestedAt: string;
|
|
1526
|
+
/** Hash of the source file for diff tracking */
|
|
1527
|
+
sourceFileHash: string;
|
|
1623
1528
|
}
|
|
1529
|
+
interface CurateResult {
|
|
1530
|
+
/** Statements extracted */
|
|
1531
|
+
statements: CuratedStatement[];
|
|
1532
|
+
/** Files processed */
|
|
1533
|
+
filesProcessed: number;
|
|
1534
|
+
/** Files skipped (empty, binary, etc.) */
|
|
1535
|
+
filesSkipped: number;
|
|
1536
|
+
/** Duplicate statements found (if checkDuplicates) */
|
|
1537
|
+
duplicates: DuplicateResult[];
|
|
1538
|
+
/** Contradictions found (if checkContradictions) */
|
|
1539
|
+
contradictions: ContradictionResult$1[];
|
|
1540
|
+
/** Memory files written */
|
|
1541
|
+
written: string[];
|
|
1542
|
+
/** Duration in ms */
|
|
1543
|
+
durationMs: number;
|
|
1544
|
+
}
|
|
1545
|
+
interface DuplicateResult {
|
|
1546
|
+
/** New statement */
|
|
1547
|
+
newStatement: CuratedStatement;
|
|
1548
|
+
/** Existing memory ID that matches */
|
|
1549
|
+
existingId: string;
|
|
1550
|
+
/** Similarity score (0-1) */
|
|
1551
|
+
similarity: number;
|
|
1552
|
+
/** Recommended action */
|
|
1553
|
+
action: "skip" | "merge" | "keep";
|
|
1554
|
+
}
|
|
1555
|
+
interface ContradictionResult$1 {
|
|
1556
|
+
/** New statement */
|
|
1557
|
+
newStatement: CuratedStatement;
|
|
1558
|
+
/** Conflicting memory ID */
|
|
1559
|
+
conflictingId: string;
|
|
1560
|
+
/** The conflicting content */
|
|
1561
|
+
conflictingContent: string;
|
|
1562
|
+
/** Severity */
|
|
1563
|
+
severity: "high" | "medium" | "low";
|
|
1564
|
+
}
|
|
1565
|
+
declare function curate(options: CurateOptions): Promise<CurateResult>;
|
|
1566
|
+
|
|
1624
1567
|
/**
|
|
1625
|
-
*
|
|
1626
|
-
*
|
|
1627
|
-
*
|
|
1628
|
-
*
|
|
1568
|
+
* @remnic/core — Dedup & Contradiction Detection
|
|
1569
|
+
*
|
|
1570
|
+
* Statement-level deduplication and contradiction detection
|
|
1571
|
+
* against existing memories. Can be used standalone or via curation.
|
|
1629
1572
|
*/
|
|
1630
|
-
interface
|
|
1631
|
-
/**
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
/**
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
/**
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1573
|
+
interface MemoryEntry {
|
|
1574
|
+
/** Memory ID */
|
|
1575
|
+
id: string;
|
|
1576
|
+
/** Content text */
|
|
1577
|
+
content: string;
|
|
1578
|
+
/** Category */
|
|
1579
|
+
category: string;
|
|
1580
|
+
/** File path (if known) */
|
|
1581
|
+
filePath?: string;
|
|
1582
|
+
}
|
|
1583
|
+
interface DedupOptions {
|
|
1584
|
+
/** Memory root directory */
|
|
1585
|
+
memoryDir: string;
|
|
1586
|
+
/** Categories to scan (default: all) */
|
|
1587
|
+
categories?: string[];
|
|
1588
|
+
/** Similarity threshold for fuzzy matching (0-1, default: 0.85) */
|
|
1589
|
+
threshold?: number;
|
|
1590
|
+
/** Max memories to load (default: 10000) */
|
|
1591
|
+
maxLoad?: number;
|
|
1592
|
+
}
|
|
1593
|
+
interface DedupResult {
|
|
1594
|
+
/** Total memories scanned */
|
|
1595
|
+
scanned: number;
|
|
1596
|
+
/** Duplicate pairs found */
|
|
1597
|
+
duplicates: DuplicatePair[];
|
|
1598
|
+
/** Duration in ms */
|
|
1599
|
+
durationMs: number;
|
|
1600
|
+
}
|
|
1601
|
+
interface DuplicatePair {
|
|
1602
|
+
/** First memory */
|
|
1603
|
+
left: MemoryEntry;
|
|
1604
|
+
/** Second memory */
|
|
1605
|
+
right: MemoryEntry;
|
|
1606
|
+
/** Similarity score */
|
|
1607
|
+
similarity: number;
|
|
1608
|
+
/** Recommended action */
|
|
1609
|
+
action: "merge" | "keep_left" | "keep_right";
|
|
1610
|
+
}
|
|
1611
|
+
interface ContradictionOptions {
|
|
1612
|
+
/** Memory root directory */
|
|
1613
|
+
memoryDir: string;
|
|
1614
|
+
/** Categories to scan (default: all) */
|
|
1615
|
+
categories?: string[];
|
|
1616
|
+
/** Max memories to load (default: 10000) */
|
|
1617
|
+
maxLoad?: number;
|
|
1618
|
+
}
|
|
1619
|
+
interface ContradictionResult {
|
|
1620
|
+
/** Total memories scanned */
|
|
1621
|
+
scanned: number;
|
|
1622
|
+
/** Contradictions found */
|
|
1623
|
+
contradictions: ContradictionPair[];
|
|
1624
|
+
/** Duration in ms */
|
|
1625
|
+
durationMs: number;
|
|
1626
|
+
}
|
|
1627
|
+
interface ContradictionPair {
|
|
1628
|
+
/** First statement */
|
|
1629
|
+
left: MemoryEntry;
|
|
1630
|
+
/** Contradicting statement */
|
|
1631
|
+
right: MemoryEntry;
|
|
1632
|
+
/** Severity */
|
|
1633
|
+
severity: "high" | "medium" | "low";
|
|
1634
|
+
/** Reason */
|
|
1635
|
+
reason: string;
|
|
1636
|
+
}
|
|
1637
|
+
declare function findDuplicates(options: DedupOptions): DedupResult;
|
|
1638
|
+
declare function findContradictions(options: ContradictionOptions): ContradictionResult;
|
|
1639
|
+
|
|
1640
|
+
/**
|
|
1641
|
+
* @remnic/core — Review Inbox
|
|
1642
|
+
*
|
|
1643
|
+
* Manages low-confidence memories and suggestions pending review.
|
|
1644
|
+
* Integrates with the existing review-queue system.
|
|
1645
|
+
*/
|
|
1646
|
+
interface ReviewItem {
|
|
1647
|
+
/** Memory ID */
|
|
1648
|
+
id: string;
|
|
1649
|
+
/** Content text */
|
|
1650
|
+
content: string;
|
|
1651
|
+
/** Category */
|
|
1652
|
+
category: string;
|
|
1653
|
+
/** Confidence score (0-1) */
|
|
1654
|
+
confidence: number;
|
|
1655
|
+
/** Confidence tier */
|
|
1656
|
+
confidenceTier: string;
|
|
1657
|
+
/** Source */
|
|
1658
|
+
source: string;
|
|
1659
|
+
/** File path if available */
|
|
1660
|
+
filePath?: string;
|
|
1661
|
+
/** Created date */
|
|
1662
|
+
created: string;
|
|
1663
|
+
/** Reason it's in review */
|
|
1664
|
+
reviewReason: "low_confidence" | "suggestion" | "contradiction" | "duplicate" | "tombstone_blocked";
|
|
1665
|
+
/** Additional context */
|
|
1666
|
+
context?: string;
|
|
1667
|
+
}
|
|
1668
|
+
type ReviewAction = "approve" | "dismiss" | "flag";
|
|
1669
|
+
interface ReviewResult {
|
|
1670
|
+
/** Item acted upon */
|
|
1671
|
+
itemId: string;
|
|
1672
|
+
/** Action taken */
|
|
1673
|
+
action: ReviewAction;
|
|
1674
|
+
/** Updated file path (if modified) */
|
|
1675
|
+
updatedPath?: string;
|
|
1676
|
+
/** Status message */
|
|
1677
|
+
message: string;
|
|
1678
|
+
/** Tombstone id cleared by an approve action (for the caller to revoke). */
|
|
1679
|
+
clearedTombstoneId?: string;
|
|
1658
1680
|
}
|
|
1659
|
-
interface
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1681
|
+
interface ReviewListResult {
|
|
1682
|
+
/** Items pending review */
|
|
1683
|
+
items: ReviewItem[];
|
|
1684
|
+
/** Total count */
|
|
1685
|
+
total: number;
|
|
1686
|
+
/** Duration in ms */
|
|
1687
|
+
durationMs: number;
|
|
1663
1688
|
}
|
|
1664
|
-
interface
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1689
|
+
interface ReviewOptions {
|
|
1690
|
+
/** Memory root directory */
|
|
1691
|
+
memoryDir: string;
|
|
1692
|
+
/** Filter by reason */
|
|
1693
|
+
reason?: ReviewItem["reviewReason"];
|
|
1694
|
+
/** Max items to return (default: 50) */
|
|
1695
|
+
limit?: number;
|
|
1696
|
+
/** Include items with confidence below this threshold (default: 0.7) */
|
|
1697
|
+
confidenceThreshold?: number;
|
|
1668
1698
|
}
|
|
1669
|
-
interface
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1699
|
+
interface ReviewActionOptions {
|
|
1700
|
+
/** Match the threshold used when listing review items (default: 0.7) */
|
|
1701
|
+
confidenceThreshold?: number;
|
|
1702
|
+
/**
|
|
1703
|
+
* Revocation hook (issue #1579). When approving a memory whose frontmatter
|
|
1704
|
+
* carries `blockedBy: <tombstoneId>`, the hook fires so the caller (CLI /
|
|
1705
|
+
* orchestrator) can append a `kind: "revocation"` tombstone entry —
|
|
1706
|
+
* re-allowing the content. Fire-and-forget: a revocation failure MUST NOT
|
|
1707
|
+
* fail the approval (gotcha #13). The hook receives the tombstone id and
|
|
1708
|
+
* the memory id.
|
|
1709
|
+
*/
|
|
1710
|
+
onApproveBlockedMemory?: (tombstoneId: string, memoryId: string) => void | Promise<void>;
|
|
1678
1711
|
}
|
|
1679
1712
|
/**
|
|
1680
|
-
*
|
|
1681
|
-
* Strict superset of `SyncIncrementalResult`.
|
|
1713
|
+
* List items pending review.
|
|
1682
1714
|
*/
|
|
1683
|
-
|
|
1684
|
-
readonly skippedBinary: number;
|
|
1685
|
-
readonly skippedFolderScope: number;
|
|
1686
|
-
readonly skippedTooLarge: number;
|
|
1687
|
-
}
|
|
1715
|
+
declare function listReviewItems(options: ReviewOptions): ReviewListResult;
|
|
1688
1716
|
/**
|
|
1689
|
-
*
|
|
1690
|
-
* malformed input — never silently defaults (CLAUDE.md gotcha #51).
|
|
1717
|
+
* Perform a review action on an item.
|
|
1691
1718
|
*/
|
|
1692
|
-
declare function
|
|
1719
|
+
declare function performReview(memoryDir: string, itemId: string, action: ReviewAction, options?: ReviewActionOptions): ReviewResult;
|
|
1720
|
+
|
|
1693
1721
|
/**
|
|
1694
|
-
*
|
|
1695
|
-
*
|
|
1722
|
+
* @remnic/core — Diff-Aware Sync
|
|
1723
|
+
*
|
|
1724
|
+
* Watches source files for changes and triggers re-ingestion
|
|
1725
|
+
* only for changed content. Uses file hashing to detect changes.
|
|
1696
1726
|
*/
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1727
|
+
interface SyncOptions {
|
|
1728
|
+
/** Source directory to watch */
|
|
1729
|
+
sourceDir: string;
|
|
1730
|
+
/** Memory root directory */
|
|
1731
|
+
memoryDir: string;
|
|
1732
|
+
/** State file path (stores hashes). Default: memoryDir/.sync-state.json */
|
|
1733
|
+
stateFile?: string;
|
|
1734
|
+
/** File extensions to watch (default: .md, .txt, .mdx) */
|
|
1735
|
+
extensions?: string[];
|
|
1736
|
+
/** Directories to exclude */
|
|
1737
|
+
excludeDirs?: string[];
|
|
1738
|
+
/** Poll interval for watchForChanges. Default: 5000ms */
|
|
1739
|
+
pollIntervalMs?: number;
|
|
1740
|
+
/** Whether to actually write changes (default: true) */
|
|
1741
|
+
dryRun?: boolean;
|
|
1742
|
+
}
|
|
1743
|
+
interface SyncResult {
|
|
1744
|
+
/** Files scanned */
|
|
1745
|
+
scanned: number;
|
|
1746
|
+
/** Files changed since last sync */
|
|
1747
|
+
changed: FileChange[];
|
|
1748
|
+
/** Files unchanged */
|
|
1749
|
+
unchanged: number;
|
|
1750
|
+
/** Files deleted since last sync */
|
|
1751
|
+
deleted: string[];
|
|
1752
|
+
/** Files newly added */
|
|
1753
|
+
added: string[];
|
|
1754
|
+
/** Duration in ms */
|
|
1755
|
+
durationMs: number;
|
|
1756
|
+
/** State file path */
|
|
1757
|
+
stateFile: string;
|
|
1758
|
+
}
|
|
1759
|
+
interface FileChange {
|
|
1760
|
+
/** Absolute file path */
|
|
1761
|
+
filePath: string;
|
|
1762
|
+
/** Relative path from source root */
|
|
1763
|
+
relativePath: string;
|
|
1764
|
+
/** Change type */
|
|
1765
|
+
type: "added" | "modified" | "deleted";
|
|
1766
|
+
/** Current content hash */
|
|
1767
|
+
currentHash: string;
|
|
1768
|
+
/** Previous content hash (if modified) */
|
|
1769
|
+
previousHash?: string;
|
|
1770
|
+
/** File size in bytes */
|
|
1771
|
+
size: number;
|
|
1772
|
+
}
|
|
1773
|
+
interface SyncState {
|
|
1774
|
+
/** Map of relative path → content hash */
|
|
1775
|
+
fileHashes: Record<string, string>;
|
|
1776
|
+
/** Last sync timestamp */
|
|
1777
|
+
lastSyncAt: string;
|
|
1778
|
+
/** Version of state format */
|
|
1779
|
+
version: number;
|
|
1780
|
+
}
|
|
1781
|
+
declare function syncChanges(options: SyncOptions): SyncResult;
|
|
1700
1782
|
/**
|
|
1701
|
-
*
|
|
1702
|
-
*
|
|
1703
|
-
* #57). Surfaces a precise install hint on miss.
|
|
1704
|
-
*
|
|
1705
|
-
* Exported only for the `index.ts` barrel; consumers that already inject a
|
|
1706
|
-
* test factory don't need to touch this.
|
|
1783
|
+
* Watch for changes and call callback on file changes.
|
|
1784
|
+
* Returns a stop function.
|
|
1707
1785
|
*/
|
|
1708
|
-
declare
|
|
1786
|
+
declare function watchForChanges(options: SyncOptions, onChange: (changes: FileChange[]) => void | Promise<void>): {
|
|
1787
|
+
stop: () => void;
|
|
1788
|
+
};
|
|
1709
1789
|
|
|
1710
1790
|
/**
|
|
1711
|
-
*
|
|
1712
|
-
*
|
|
1713
|
-
* Concrete `LiveConnector` implementation that incrementally imports text
|
|
1714
|
-
* content from Notion database pages into Remnic. Built on top of the
|
|
1715
|
-
* framework shipped in PR 1/N (`framework.ts` / `registry.ts` /
|
|
1716
|
-
* `state-store.ts`) and mirrors the structure of the Google Drive connector
|
|
1717
|
-
* (PR 2/N).
|
|
1718
|
-
*
|
|
1719
|
-
* Design notes:
|
|
1720
|
-
*
|
|
1721
|
-
* - **Auth.** Integration token from config (`connectors.notion.token`).
|
|
1722
|
-
* The token is accepted at config-parse time but never logged. Operators
|
|
1723
|
-
* must populate it from a secret store; per the repo-wide privacy policy
|
|
1724
|
-
* no real value may appear in tests or comments.
|
|
1725
|
-
*
|
|
1726
|
-
* - **Scope.** `databaseIds` in config limits the import to the listed
|
|
1727
|
-
* Notion databases. The connector queries each database for pages whose
|
|
1728
|
-
* `last_edited_time` is after a per-page high-water mark stored in the
|
|
1729
|
-
* cursor. When `databaseIds` is empty the connector does nothing (safe
|
|
1730
|
-
* default — no credentials → no import).
|
|
1731
|
-
*
|
|
1732
|
-
* - **Cursor semantics.** The cursor is a JSON string encoding a
|
|
1733
|
-
* `NotionCursorPayload`: a map from page-id to last-seen
|
|
1734
|
-
* `last_edited_time` ISO string. On the first sync (cursor=null) we
|
|
1735
|
-
* seed the payload from the current state of each database WITHOUT
|
|
1736
|
-
* importing any content, so "first install" doesn't re-ingest history.
|
|
1737
|
-
* Each subsequent pass only imports pages edited after the stored
|
|
1738
|
-
* watermark.
|
|
1739
|
-
*
|
|
1740
|
-
* - **Block extraction.** Page content is fetched via
|
|
1741
|
-
* `blocks.children.list` recursively up to `MAX_BLOCK_DEPTH` levels.
|
|
1742
|
-
* Block text is extracted to Markdown-ish plain text (no raw JSON blobs).
|
|
1743
|
-
* Only text-bearing block types are included; unsupported types are
|
|
1744
|
-
* silently skipped.
|
|
1745
|
-
*
|
|
1746
|
-
* - **Raw `fetch`.** We call the Notion REST API directly rather than using
|
|
1747
|
-
* `@notionhq/client` — there is no optional-peer-dep machinery needed and
|
|
1748
|
-
* the API surface we consume is tiny. The `fetchFn` argument is the test
|
|
1749
|
-
* hook allowing stubbing without network access.
|
|
1750
|
-
*
|
|
1751
|
-
* - **Idempotency.** `ConnectorDocument.source.externalId` is the page id
|
|
1752
|
-
* and `externalRevision` is `last_edited_time`, so downstream dedup can
|
|
1753
|
-
* recognise repeat fetches if the cursor is rewound.
|
|
1754
|
-
*
|
|
1755
|
-
* - **Privacy.** No page content is ever logged. Database ids and counts
|
|
1756
|
-
* may be logged. The integration token is never exposed in logs, state,
|
|
1757
|
-
* or error messages.
|
|
1791
|
+
* memory-extension-host/render-extensions-block.ts — Render discovered extensions
|
|
1792
|
+
* into a markdown block for injection into consolidation prompts.
|
|
1758
1793
|
*
|
|
1759
|
-
*
|
|
1760
|
-
*
|
|
1794
|
+
* Respects the global token budget (REMNIC_EXTENSIONS_TOTAL_TOKEN_LIMIT) and
|
|
1795
|
+
* truncates with a footer listing omitted extensions when over budget.
|
|
1761
1796
|
*/
|
|
1762
1797
|
|
|
1763
|
-
/** Stable connector id. Lives in the registry under this exact string. */
|
|
1764
|
-
declare const NOTION_CONNECTOR_ID = "notion";
|
|
1765
|
-
/**
|
|
1766
|
-
* Cursor `kind` we emit. Opaque to the framework; documented here so
|
|
1767
|
-
* tests can assert on it.
|
|
1768
|
-
*/
|
|
1769
|
-
declare const NOTION_CURSOR_KIND = "notionWatermark";
|
|
1770
|
-
/**
|
|
1771
|
-
* Default poll interval (5 minutes). Notion's API has no push capability;
|
|
1772
|
-
* polling sub-minute wastes quota for a personal memory layer.
|
|
1773
|
-
*/
|
|
1774
|
-
declare const NOTION_DEFAULT_POLL_INTERVAL_MS: number;
|
|
1775
|
-
/**
|
|
1776
|
-
* Validated, frozen view of `connectors.notion.*`.
|
|
1777
|
-
*/
|
|
1778
|
-
interface NotionConnectorConfig {
|
|
1779
|
-
/** Notion integration token. Starts with `secret_`. */
|
|
1780
|
-
readonly token: string;
|
|
1781
|
-
/** Database ids to import pages from. Empty = connector is a no-op. */
|
|
1782
|
-
readonly databaseIds: readonly string[];
|
|
1783
|
-
/** Poll interval surfaced to the scheduler (ms). */
|
|
1784
|
-
readonly pollIntervalMs: number;
|
|
1785
|
-
}
|
|
1786
1798
|
/**
|
|
1787
|
-
*
|
|
1788
|
-
*
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
body?: string;
|
|
1794
|
-
signal?: AbortSignal;
|
|
1795
|
-
}) => Promise<{
|
|
1796
|
-
ok: boolean;
|
|
1797
|
-
status: number;
|
|
1798
|
-
json(): Promise<unknown>;
|
|
1799
|
-
}>;
|
|
1800
|
-
/**
|
|
1801
|
-
* Validate and normalise raw config. Throws with a concrete message on any
|
|
1802
|
-
* malformed input — never silently defaults (CLAUDE.md gotcha #51).
|
|
1799
|
+
* Render a markdown block containing extension instructions for injection
|
|
1800
|
+
* into consolidation prompts.
|
|
1801
|
+
*
|
|
1802
|
+
* If the list is empty, returns "".
|
|
1803
|
+
* Inlines extensions in name order until the token budget is exhausted.
|
|
1804
|
+
* If the budget is exceeded, appends a truncation footer listing omitted extensions.
|
|
1803
1805
|
*/
|
|
1804
|
-
declare function
|
|
1806
|
+
declare function renderExtensionsBlock(extensions: DiscoveredExtension[]): string;
|
|
1805
1807
|
/**
|
|
1806
|
-
*
|
|
1807
|
-
*
|
|
1808
|
+
* Render a compact one-line footer listing active extension names.
|
|
1809
|
+
* Used by day-summary and summary-snapshot where full instructions are not needed.
|
|
1808
1810
|
*/
|
|
1809
|
-
declare function
|
|
1810
|
-
fetchFn?: NotionFetchFn;
|
|
1811
|
-
}): LiveConnector;
|
|
1811
|
+
declare function renderExtensionsFooter(extensions: DiscoveredExtension[]): string;
|
|
1812
1812
|
|
|
1813
1813
|
/**
|
|
1814
1814
|
* @remnic/core — Spaces + Collaboration
|