@remnic/core 9.10.0 → 9.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access-cli.js +1 -1
- package/dist/{chunk-7PY55HMI.js → chunk-3VBXP5HS.js} +626 -38
- package/dist/chunk-3VBXP5HS.js.map +1 -0
- package/dist/index.d.ts +154 -2
- package/dist/index.js +31 -1
- package/dist/orchestrator.js +1 -1
- package/package.json +2 -2
- package/src/activity/digest.test.ts +180 -0
- package/src/activity/digest.ts +429 -0
- package/src/activity/index.ts +9 -0
- package/src/activity/store.test.ts +226 -0
- package/src/activity/store.ts +352 -0
- package/src/activity/types.ts +86 -0
- package/src/admin/admin-surfaces.test.ts +4 -5
- package/src/chat/chat-cli.test.ts +4 -7
- package/src/chat/chat-engine.test.ts +4 -8
- package/src/chat/chat-http.test.ts +4 -7
- package/src/chat/chat-security.test.ts +4 -6
- package/src/console/trace.test.ts +4 -9
- package/src/contradiction/contradiction.test.ts +4 -3
- package/src/correction/correction-executor.test.ts +4 -10
- package/src/correction/correction-planner.test.ts +5 -10
- package/src/extraction-redaction-rules.test.ts +5 -10
- package/src/index.ts +1 -1
- package/src/maintenance/graph-edge-decay.test.ts +5 -10
- package/src/peers/migrate-from-identity-anchor.test.ts +3 -4
- package/src/peers/peers.test.ts +3 -4
- package/src/session-summaries/session-summaries.test.ts +4 -8
- package/src/testing/tmp-dir.ts +68 -0
- package/src/transfer/capsule-encrypt.test.ts +4 -5
- package/src/write-quarantine.test.ts +4 -8
- package/dist/chunk-7PY55HMI.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -87,6 +87,7 @@ export { EnrichmentAuditEntry, EnrichmentCandidate, EnrichmentCostTier, Enrichme
|
|
|
87
87
|
export { clearBulkImportSources, getBulkImportSource, listBulkImportSources, registerBulkImportSource } from './bulk-import/index.js';
|
|
88
88
|
export { a as ProcessBatchContext, P as ProcessBatchFn, b as ProcessBatchResult, f as formatBatchTranscript, r as resolveBulkImportContext, c as runBulkImportPipeline, v as validateBatchSize } from './pipeline-Cn-kvYeV.js';
|
|
89
89
|
export { B as BulkImportCliCommandOptions, p as parseStrictCliDate, r as runBulkImportCliCommand } from './cli-5tNLVTvJ.js';
|
|
90
|
+
import { BetterSqlite3Database } from './runtime/better-sqlite.js';
|
|
90
91
|
export { DEFAULT_IMPORT_BATCH_SIZE, ImportProgress, ImportedMemory, ImporterAdapter, ImporterParseOptions, ImporterTransformOptions, ImporterWriteResult, ImporterWriteTarget, RunImportOptions, RunImporterResult, defaultWriteMemoriesToOrchestrator, importedMemoryToTurn, runImporter, validateImportBatchSize, validateImportRateLimit } from './importers/index.js';
|
|
91
92
|
export { FallbackLlmClient, FallbackLlmOptions, FallbackLlmResponse, FallbackLlmRuntimeContext } from './fallback-llm.js';
|
|
92
93
|
export { ComputeMemoryWorthInput, MemoryWorthResult, computeMemoryWorth } from './memory-worth.js';
|
|
@@ -121,7 +122,6 @@ import './namespaces/search.js';
|
|
|
121
122
|
import './consolidation-operator.js';
|
|
122
123
|
import './memory-projection-store.js';
|
|
123
124
|
import './maintenance/memory-governance.js';
|
|
124
|
-
import './runtime/better-sqlite.js';
|
|
125
125
|
import 'better-sqlite3';
|
|
126
126
|
import './compounding/engine.js';
|
|
127
127
|
import './shared-context/manager.js';
|
|
@@ -6818,6 +6818,158 @@ interface WearablesCliIo {
|
|
|
6818
6818
|
*/
|
|
6819
6819
|
declare function runWearablesCliCommand(service: WearablesService, args: string[], io: WearablesCliIo): Promise<number>;
|
|
6820
6820
|
|
|
6821
|
+
/**
|
|
6822
|
+
* Screen-activity subsystem — shared types (issue #1899).
|
|
6823
|
+
*
|
|
6824
|
+
* A third ingestion modality alongside wearables (conversations) and live
|
|
6825
|
+
* connectors (documents). Screen text has no speakers and is high-volume, so it
|
|
6826
|
+
* gets its own store and day-digest rather than being forced into the wearable
|
|
6827
|
+
* conversation shape. Capture daemons live in the à-la-carte `@remnic/capture-screen`
|
|
6828
|
+
* package; this core subsystem is host-agnostic and consumes snapshots over a
|
|
6829
|
+
* loopback HTTP client.
|
|
6830
|
+
*
|
|
6831
|
+
* All timestamps are UTC ISO-8601; day bucketing is half-open [start, end).
|
|
6832
|
+
*/
|
|
6833
|
+
/** One captured on-screen text snapshot (a single window at a single instant). */
|
|
6834
|
+
interface ActivitySnapshot {
|
|
6835
|
+
/** Store row id (assigned on insert; absent before persistence). */
|
|
6836
|
+
id?: number;
|
|
6837
|
+
/** Capture-machine label (disambiguates multi-machine stores). */
|
|
6838
|
+
machine: string;
|
|
6839
|
+
/** UTC ISO-8601 capture instant. */
|
|
6840
|
+
capturedAtUtc: string;
|
|
6841
|
+
/** Frontmost application name. */
|
|
6842
|
+
app: string;
|
|
6843
|
+
/** Frontmost window title. */
|
|
6844
|
+
windowTitle: string;
|
|
6845
|
+
/** Browser tab URL, when the frontmost window is a known browser. */
|
|
6846
|
+
browserUrl?: string;
|
|
6847
|
+
/** Extracted visible text (accessibility tree or OCR). */
|
|
6848
|
+
text: string;
|
|
6849
|
+
/** Where the text came from. */
|
|
6850
|
+
textSource: "ax" | "ocr";
|
|
6851
|
+
/** SHA-256 of the normalized snapshot content (idempotency key). */
|
|
6852
|
+
contentHash: string;
|
|
6853
|
+
/** 64-bit SimHash (hex) for near-duplicate detection, when computed. */
|
|
6854
|
+
simhash?: string;
|
|
6855
|
+
}
|
|
6856
|
+
/** Frontmatter persisted on a rendered day digest. */
|
|
6857
|
+
interface ActivityDayMeta {
|
|
6858
|
+
kind: "activity-digest";
|
|
6859
|
+
/** Local day, YYYY-MM-DD. */
|
|
6860
|
+
date: string;
|
|
6861
|
+
/** Machines that contributed snapshots, sorted. */
|
|
6862
|
+
machines: string[];
|
|
6863
|
+
snapshotCount: number;
|
|
6864
|
+
/** SHA-256 of the rendered body (rebuild-idempotency). */
|
|
6865
|
+
contentHash: string;
|
|
6866
|
+
formatVersion: number;
|
|
6867
|
+
}
|
|
6868
|
+
/** A parsed day digest (frontmatter + rendered body). */
|
|
6869
|
+
interface ActivityDayDigest {
|
|
6870
|
+
meta: ActivityDayMeta;
|
|
6871
|
+
body: string;
|
|
6872
|
+
}
|
|
6873
|
+
/** Result of a capture-daemon auth/health probe. */
|
|
6874
|
+
interface ActivitySourceCheck {
|
|
6875
|
+
ok: boolean;
|
|
6876
|
+
detail?: string;
|
|
6877
|
+
}
|
|
6878
|
+
/** One page of snapshots pulled from a capture daemon. */
|
|
6879
|
+
interface ActivitySnapshotPage {
|
|
6880
|
+
snapshots: ActivitySnapshot[];
|
|
6881
|
+
nextCursor: string | null;
|
|
6882
|
+
}
|
|
6883
|
+
/**
|
|
6884
|
+
* Client contract for a screen-capture daemon (one per capture machine).
|
|
6885
|
+
* Implemented by a later slice (the HTTP source client); defined here so the
|
|
6886
|
+
* store and pipeline can be built and tested against a fixture double first.
|
|
6887
|
+
*/
|
|
6888
|
+
interface ActivitySourceClient {
|
|
6889
|
+
/** Stable capture-machine label. */
|
|
6890
|
+
machineLabel: string;
|
|
6891
|
+
/** Probe connectivity/auth without mutating anything. */
|
|
6892
|
+
verify(signal?: AbortSignal): Promise<ActivitySourceCheck>;
|
|
6893
|
+
/** Fetch one page of snapshots for a single local day. */
|
|
6894
|
+
fetchSnapshots(opts: {
|
|
6895
|
+
date: string;
|
|
6896
|
+
timezone: string;
|
|
6897
|
+
cursor?: string | null;
|
|
6898
|
+
signal?: AbortSignal;
|
|
6899
|
+
}): Promise<ActivitySnapshotPage>;
|
|
6900
|
+
}
|
|
6901
|
+
|
|
6902
|
+
/**
|
|
6903
|
+
* Screen-activity SQLite store (issue #1899).
|
|
6904
|
+
*
|
|
6905
|
+
* Durable, capture-machine-agnostic store for on-screen text snapshots plus a
|
|
6906
|
+
* per-machine sync cursor. Mirrors the LCM store conventions
|
|
6907
|
+
* (packages/remnic-core/src/lcm/schema.ts): WAL, a `<name>_meta` schema-version
|
|
6908
|
+
* row, `CREATE TABLE IF NOT EXISTS`, and an FTS5 virtual table created
|
|
6909
|
+
* separately. better-sqlite3 is synchronous.
|
|
6910
|
+
*
|
|
6911
|
+
* Snapshots dedup on `(machine, content_hash)` so a re-sync is idempotent, and
|
|
6912
|
+
* day queries use half-open [start, end) UTC bounds (AGENTS.md §23).
|
|
6913
|
+
*/
|
|
6914
|
+
|
|
6915
|
+
declare function activityDatabasePath(memoryDir: string): string;
|
|
6916
|
+
declare function ensureActivityStateDir(memoryDir: string): Promise<void>;
|
|
6917
|
+
declare function openActivityDatabase(memoryDir: string): BetterSqlite3Database;
|
|
6918
|
+
/** Apply the activity schema on an already-open handle (test/in-memory use). */
|
|
6919
|
+
declare function applyActivitySchema(db: BetterSqlite3Database): void;
|
|
6920
|
+
declare class ActivityStore {
|
|
6921
|
+
private readonly db;
|
|
6922
|
+
constructor(db: BetterSqlite3Database);
|
|
6923
|
+
static open(memoryDir: string): ActivityStore;
|
|
6924
|
+
/**
|
|
6925
|
+
* Insert a snapshot, idempotent on (machine, captured_at_utc, content_hash):
|
|
6926
|
+
* the same screen content recurring at a *different* time is kept; only an
|
|
6927
|
+
* exact re-ingestion of the same capture dedups. Returns `inserted: false`
|
|
6928
|
+
* for a duplicate. The FTS row is written only on a real insert (atomically),
|
|
6929
|
+
* so it never drifts from the base table.
|
|
6930
|
+
*/
|
|
6931
|
+
insertSnapshot(snapshot: ActivitySnapshot): {
|
|
6932
|
+
inserted: boolean;
|
|
6933
|
+
id: number;
|
|
6934
|
+
};
|
|
6935
|
+
/** Snapshots whose capture instant is in the half-open [start, end) window. */
|
|
6936
|
+
listSnapshotsForDay(machine: string | null, startUtcInclusive: string, endUtcExclusive: string): ActivitySnapshot[];
|
|
6937
|
+
getCursor(machine: string): string | null;
|
|
6938
|
+
setCursor(machine: string, cursor: string | null, updatedAtUtc?: string): void;
|
|
6939
|
+
/** Full-text search over snapshot text/app/window/url; newest first. */
|
|
6940
|
+
searchSnapshots(query: string, limit: number): ActivitySnapshot[];
|
|
6941
|
+
/** Retention: drop snapshots captured strictly before `cutoffUtc`. */
|
|
6942
|
+
pruneOlderThan(cutoffUtc: string): number;
|
|
6943
|
+
close(): void;
|
|
6944
|
+
}
|
|
6945
|
+
|
|
6946
|
+
/**
|
|
6947
|
+
* Deterministic screen-activity day-digest renderer (issue #1899).
|
|
6948
|
+
*
|
|
6949
|
+
* Renders a day's snapshots into markdown with YAML frontmatter, placed at
|
|
6950
|
+
* `<memoryDir>/activity/<date>.md` — outside the memory scan roots but inside
|
|
6951
|
+
* the QMD collection root (searchable, never auto-recalled). No LLM: the body
|
|
6952
|
+
* is a pure, byte-identical function of its inputs so an unchanged day skips
|
|
6953
|
+
* rewrite by contentHash. Day bucketing is DST-aware and half-open
|
|
6954
|
+
* [start, end) (AGENTS.md §23); sort keys are total with stable tiebreakers
|
|
6955
|
+
* (§12).
|
|
6956
|
+
*/
|
|
6957
|
+
|
|
6958
|
+
declare const ACTIVITY_DIGEST_FORMAT_VERSION = 1;
|
|
6959
|
+
declare const ACTIVITY_DIR_NAME = "activity";
|
|
6960
|
+
declare function isValidActivityDate(date: string): boolean;
|
|
6961
|
+
declare function activityDigestPath(memoryDir: string, date: string): string;
|
|
6962
|
+
/** Half-open [start, end) UTC ISO bounds of a local day. */
|
|
6963
|
+
declare function activityDayWindow(date: string, timezone: string): {
|
|
6964
|
+
startUtc: string;
|
|
6965
|
+
endUtc: string;
|
|
6966
|
+
};
|
|
6967
|
+
declare function composeActivityDigestBody(date: string, timezone: string, snapshots: ActivitySnapshot[]): string;
|
|
6968
|
+
declare function hashActivityBody(body: string): string;
|
|
6969
|
+
declare function composeActivityDigestMeta(date: string, machines: string[], snapshots: ActivitySnapshot[], body: string): ActivityDayMeta;
|
|
6970
|
+
declare function serializeActivityDigest(meta: ActivityDayMeta, body: string): string;
|
|
6971
|
+
declare function parseActivityDigest(raw: string): ActivityDayDigest | null;
|
|
6972
|
+
|
|
6821
6973
|
type LocalSessionRole = "user" | "assistant" | "tool" | "system" | "other";
|
|
6822
6974
|
interface LocalSessionTurn {
|
|
6823
6975
|
role: LocalSessionRole;
|
|
@@ -7134,4 +7286,4 @@ declare function forkCapsule(opts: ForkCapsuleOptions): Promise<ForkCapsuleResul
|
|
|
7134
7286
|
*/
|
|
7135
7287
|
declare function readForkLineage(targetRoot: string, forkId: string): Promise<ForkLineage | null>;
|
|
7136
7288
|
|
|
7137
|
-
export { type ArchitectureHintsResult, type AuditEntry, type BinaryAssetRecord, type BinaryAssetStatus, type BinaryLifecycleConfig, type BinaryLifecycleManifest, type BinaryStorageBackend, type BinaryStorageBackendConfig, ClaudeCodeMemoryExtensionPublisher, type CleanupResult, CodexMemoryExtensionPublisher, type CodingNamespaceOverlay, type CodingScopeDescription, type CollectLocalSessionSummariesOptions, type CompiledCorrectionRule, type CompiledRedactionRule, type ConflictEntry, type ContradictionOptions, type ContradictionPair, type ContradictionResult$1 as CurateContradictionResult, type DuplicateResult as CurateDuplicateResult, type CurateOptions, type CurateResult, type CuratedStatement, DEFAULT_GRACE_PERIOD_DAYS, DEFAULT_MAX_BINARY_SIZE_BYTES, DEFAULT_PROXIMITY_GAP_MS, DEFAULT_REDACTION_RULES, DEFAULT_SCAN_PATTERNS, DEFAULT_SOURCE_TRUST, DEFAULT_TAXONOMY, DEFAULT_WINDOW_TOLERANCE_MS, type DedupOptions, type DedupResult, DiscoveredExtension, type DocFile, type DriveChange, type DriveChangesPage, type DriveFileMetadata, type DuplicatePair, EngramAccessService, type FileChange, FilesystemBackend, type ForkCapsuleOptions, type ForkCapsuleResult, type ForkLineage, type FuseClusterResult, FusedDisagreement, FusedSegment, FusedSpeaker, FusionConversationInput, FusionDayResult, FusionOptions, GOOGLE_DRIVE_CONNECTOR_ID, GOOGLE_DRIVE_CURSOR_KIND, DEFAULT_POLL_INTERVAL_MS as GOOGLE_DRIVE_DEFAULT_POLL_INTERVAL_MS, type GenerateOptions, type GenerateResult, type GitContext, type GitInvoker, type GoogleDriveClient, type GoogleDriveClientFactory, type GoogleDriveConnectorConfig, type GoogleDriveSyncResult, HermesMemoryExtensionPublisher, type IngestionPlan, KNOWN_WEARABLE_SOURCE_IDS, type LanguageInfo, LiveConnector, LiveConnectorRegistry, LiveConnectorRegistryError, type LocalSessionAdapterInput, type LocalSessionAdapterOptions, type LocalSessionParseWarning, type LocalSessionParsedFile, type LocalSessionRole, type LocalSessionSourceAdapter, type LocalSessionSummaryCliOptions, type LocalSessionSummaryReport, type LocalSessionTurn, MemoryCategory, type MemoryEntry, type MemoryExtensionPublisher, type MergeResult, NOTION_CONNECTOR_ID, NOTION_CURSOR_KIND, NOTION_DEFAULT_POLL_INTERVAL_MS, NoneBackend, type NotionConnectorConfig, type OnboardOptions, type OnboardResult, PUBLISHERS, type PackReviewContextStructuralInput, type PipelineResult, PluginConfig, type ProjectShape, type ProvenanceEntry, type PublishContext, type PublishResult, type PublisherCapabilities, REDACTION_PLACEHOLDER, RELAY_DEMO_MISSION_ID, RELAY_DEMO_NAMESPACE, RELAY_MISSION_DEFAULT_EVENT_LIMIT, RELAY_MISSION_MAX_EVENTS, RELAY_MISSION_MAX_EVENT_LIMIT, RELAY_MISSION_MAX_FILE_BYTES, RELAY_MISSION_MAX_LINE_BYTES, RELAY_MISSION_SCHEMA_VERSION, REMNIC_CITATION_FORMAT, REMNIC_MCP_TOOL_INVENTORY, REMNIC_RECALL_DECISION_RULES, REMNIC_SEMANTIC_OVERVIEW, type RedactionConfig, type RedactionReport, type RedactionRuleConfig, type RelayAgentOutputSnapshot, type RelayAgentSnapshot, type RelayConflictSnapshot, type RelayCorrectionSnapshot, type RelayDecisionSnapshot, type RelayEvidenceRef, RelayEvidenceRefSchema, type RelayMissionAppendAccessInput, type RelayMissionAppendAccessOutput, type RelayMissionAppendResult, type RelayMissionEvent, type RelayMissionEventInput, RelayMissionEventInputSchema, RelayMissionEventSchema, type RelayMissionPayload, RelayMissionPayloadSchema, type RelayMissionReadAccessInput, type RelayMissionReadAccessOutput, type RelayMissionReadOptions, RelayMissionReadOptionsSchema, type RelayMissionSnapshot, type RelayMissionStatus, RelayMissionStore, RelayMissionStoreError, type RelayMissionStoreErrorCode, type RelayMissionStoreOptions, type RelayPropagationSnapshot, type RelayRecallSnapshot, type RelayTestSnapshot, ResolverDecision, type ReviewAction, type ReviewCandidate, type ReviewContext, type ReviewItem, type ReviewListResult, type ReviewOptions, type ReviewResult, type SessionSummaryDraft, type SessionSummaryExcerpt, type Space, type SpaceKind, type SpaceManifest, type SpacePromoteResult, type SpacePullResult, type SpacePushResult, type SpaceShareResult, type SpaceSwitchResult, SpeakerRegistry, type StatementProvenance, StorageManager, type StructuralContextDegradation, type StructuralContextErrorCode, type StructuralContextProvider, type StructuralProviderStatus, type StructuralSpawnFn, type StructuralSymbol, type SubprocessProviderOptions, type SymbolsForDiffErr, type SymbolsForDiffOk, type SymbolsForDiffResult, SyncIncrementalResult, type SyncOptions, type SyncResult, type SyncState, TRANSCRIPT_FORMAT_VERSION, Taxonomy, TokenEntry, type TrainingExportAdapter, type TrainingExportOptions, type TrainingExportRecord, type TranscriptSegmentMatch, type TreeNode, WEARABLES_DIR_NAME, WearableCleanupSettings, type WearableConnectorFactory, type WearableConnectorFactoryOptions, type WearableConnectorRegistration, WearableConversation, WearableCorrectionRule, WearableDayTranscript, WearableDayTranscriptMeta, WearableFusionConfig, WearableSourceConnector, WearableSourceSettings, type WearableSourceSyncState, type WearableSyncStateFile, type WearablesCliIo, WearablesConfig, WearablesInputError, WearablesService, appendRelayMissionEvent, applyCorrections, applyOffTheRecord, bodyIsEscaped, branchNamespaceName, buildProcedureMarkdownBody, buildProcedureRecallSection, cleanConversation, clearStructuralContextProvidersForTest, clearTrainingExportAdapters, clearWearableConnectors, clusterConversations, collapseImmediateRepeats, collectLocalSessionSummaries, compareRelayEvents, compileCorrectionRule, compileCorrectionRules, compileRedactionPatterns, compileRedactionRules, composeDayTranscriptBody, composeDayTranscriptMeta, convertMemoriesToRecords, correctionsFilePath, createBackend, createGoogleDriveConnector, createNotionConnector, createRelayMissionFixture, createSpace, createSubprocessStructuralProvider, curate, decodeTranscriptBody, defaultGoogleDriveClientFactory, defaultWearableCleanupSettings, defaultWearableFusionConfig, defaultWearableSourceSettings, defaultWearablesConfig, deleteSpace, describeCodingScope, describeErrorForOperator, describeStructuralProviderStatus, emptyManifest, emptySyncState, ensureBuiltInWearableConnectors, escapeSegmentText, findContradictions, findDuplicates, forkCapsule, fuseCluster, fuseDay, fusionInputsFromConversations, generateContextTree, generateResolverDocument, getActiveSpace, getAuditLog, getLocalSessionSourceAdapter, getManifestPath, getSpacesDir, getStructuralContextProvider, getTaxonomyDir, getTaxonomyFilePath, getTrainingExportAdapter, getWearableConnector, hashTranscriptBody, hostIdForConnector, isLowQualitySegment, isReviewPrompt, isValidTranscriptDate, listLocalSessionSourceAdapters, listReviewItems, listSpaces, listTrainingExportAdapters, listWearableConnectors, loadCorrectionsFile, loadManifest, loadSyncState, loadTaxonomy, manifestDir, manifestPath, matchesPatterns, mergeSpaces, normalizeOriginUrl, onboard, packReviewContext, packReviewContextStructural, parseDayTranscript, parseFlexibleIsoTimestamp, parseIsoOffsetTimestamp, parseIsoUtcTimestamp, parseProcedureStepsFromBody, parseTouchedFiles, parseTranscriptSegmentLine, parseWearablesConfig, performReview, probeStructuralProviderForDoctor, projectNamespaceName, promoteSpace, publisherFor, publisherForConnector, pullFromSpace, pushToSpace, rankReviewCandidates, readForkLineage, readManifest, readRelayMission, reconstructFusionInputs, redactSessionSummaryText, redactText, reduceRelayMission, registerLocalSessionSourceAdapter, registerPublisher, registerStructuralContextProvider, registerTrainingExportAdapter, registerWearableConnector, relayMissionAppendOperation, relayMissionReadOperation, relayMissionReceiptDigest, renderExtensionsBlock, renderExtensionsFooter, renderStructuralProviderStatusLine, resolveCategory, resolveCodingNamespaceOverlay, resolveGitContext, runBinaryLifecyclePipeline, runLocalSessionSummaryCliCommand, runWearablesCliCommand, saveCorrectionsFile, saveManifest, saveSyncState, saveTaxonomy, scanForBinaries, serializeDayTranscript, shareSpace, stableHash, stripFillerTokens, structuralProviderActive, switchSpace, syncChanges, syncStateFilePath, toStructuralContextDegradation, unescapeSegmentText, unescapeSpeakerLabel, updateSourceSyncState, validateGoogleDriveConfig, validateNotionConfig, validateSlug, validateTaxonomy, watchForChanges, writeManifest };
|
|
7289
|
+
export { ACTIVITY_DIGEST_FORMAT_VERSION, ACTIVITY_DIR_NAME, type ActivityDayDigest, type ActivityDayMeta, type ActivitySnapshot, type ActivitySnapshotPage, type ActivitySourceCheck, type ActivitySourceClient, ActivityStore, type ArchitectureHintsResult, type AuditEntry, type BinaryAssetRecord, type BinaryAssetStatus, type BinaryLifecycleConfig, type BinaryLifecycleManifest, type BinaryStorageBackend, type BinaryStorageBackendConfig, ClaudeCodeMemoryExtensionPublisher, type CleanupResult, CodexMemoryExtensionPublisher, type CodingNamespaceOverlay, type CodingScopeDescription, type CollectLocalSessionSummariesOptions, type CompiledCorrectionRule, type CompiledRedactionRule, type ConflictEntry, type ContradictionOptions, type ContradictionPair, type ContradictionResult$1 as CurateContradictionResult, type DuplicateResult as CurateDuplicateResult, type CurateOptions, type CurateResult, type CuratedStatement, DEFAULT_GRACE_PERIOD_DAYS, DEFAULT_MAX_BINARY_SIZE_BYTES, DEFAULT_PROXIMITY_GAP_MS, DEFAULT_REDACTION_RULES, DEFAULT_SCAN_PATTERNS, DEFAULT_SOURCE_TRUST, DEFAULT_TAXONOMY, DEFAULT_WINDOW_TOLERANCE_MS, type DedupOptions, type DedupResult, DiscoveredExtension, type DocFile, type DriveChange, type DriveChangesPage, type DriveFileMetadata, type DuplicatePair, EngramAccessService, type FileChange, FilesystemBackend, type ForkCapsuleOptions, type ForkCapsuleResult, type ForkLineage, type FuseClusterResult, FusedDisagreement, FusedSegment, FusedSpeaker, FusionConversationInput, FusionDayResult, FusionOptions, GOOGLE_DRIVE_CONNECTOR_ID, GOOGLE_DRIVE_CURSOR_KIND, DEFAULT_POLL_INTERVAL_MS as GOOGLE_DRIVE_DEFAULT_POLL_INTERVAL_MS, type GenerateOptions, type GenerateResult, type GitContext, type GitInvoker, type GoogleDriveClient, type GoogleDriveClientFactory, type GoogleDriveConnectorConfig, type GoogleDriveSyncResult, HermesMemoryExtensionPublisher, type IngestionPlan, KNOWN_WEARABLE_SOURCE_IDS, type LanguageInfo, LiveConnector, LiveConnectorRegistry, LiveConnectorRegistryError, type LocalSessionAdapterInput, type LocalSessionAdapterOptions, type LocalSessionParseWarning, type LocalSessionParsedFile, type LocalSessionRole, type LocalSessionSourceAdapter, type LocalSessionSummaryCliOptions, type LocalSessionSummaryReport, type LocalSessionTurn, MemoryCategory, type MemoryEntry, type MemoryExtensionPublisher, type MergeResult, NOTION_CONNECTOR_ID, NOTION_CURSOR_KIND, NOTION_DEFAULT_POLL_INTERVAL_MS, NoneBackend, type NotionConnectorConfig, type OnboardOptions, type OnboardResult, PUBLISHERS, type PackReviewContextStructuralInput, type PipelineResult, PluginConfig, type ProjectShape, type ProvenanceEntry, type PublishContext, type PublishResult, type PublisherCapabilities, REDACTION_PLACEHOLDER, RELAY_DEMO_MISSION_ID, RELAY_DEMO_NAMESPACE, RELAY_MISSION_DEFAULT_EVENT_LIMIT, RELAY_MISSION_MAX_EVENTS, RELAY_MISSION_MAX_EVENT_LIMIT, RELAY_MISSION_MAX_FILE_BYTES, RELAY_MISSION_MAX_LINE_BYTES, RELAY_MISSION_SCHEMA_VERSION, REMNIC_CITATION_FORMAT, REMNIC_MCP_TOOL_INVENTORY, REMNIC_RECALL_DECISION_RULES, REMNIC_SEMANTIC_OVERVIEW, type RedactionConfig, type RedactionReport, type RedactionRuleConfig, type RelayAgentOutputSnapshot, type RelayAgentSnapshot, type RelayConflictSnapshot, type RelayCorrectionSnapshot, type RelayDecisionSnapshot, type RelayEvidenceRef, RelayEvidenceRefSchema, type RelayMissionAppendAccessInput, type RelayMissionAppendAccessOutput, type RelayMissionAppendResult, type RelayMissionEvent, type RelayMissionEventInput, RelayMissionEventInputSchema, RelayMissionEventSchema, type RelayMissionPayload, RelayMissionPayloadSchema, type RelayMissionReadAccessInput, type RelayMissionReadAccessOutput, type RelayMissionReadOptions, RelayMissionReadOptionsSchema, type RelayMissionSnapshot, type RelayMissionStatus, RelayMissionStore, RelayMissionStoreError, type RelayMissionStoreErrorCode, type RelayMissionStoreOptions, type RelayPropagationSnapshot, type RelayRecallSnapshot, type RelayTestSnapshot, ResolverDecision, type ReviewAction, type ReviewCandidate, type ReviewContext, type ReviewItem, type ReviewListResult, type ReviewOptions, type ReviewResult, type SessionSummaryDraft, type SessionSummaryExcerpt, type Space, type SpaceKind, type SpaceManifest, type SpacePromoteResult, type SpacePullResult, type SpacePushResult, type SpaceShareResult, type SpaceSwitchResult, SpeakerRegistry, type StatementProvenance, StorageManager, type StructuralContextDegradation, type StructuralContextErrorCode, type StructuralContextProvider, type StructuralProviderStatus, type StructuralSpawnFn, type StructuralSymbol, type SubprocessProviderOptions, type SymbolsForDiffErr, type SymbolsForDiffOk, type SymbolsForDiffResult, SyncIncrementalResult, type SyncOptions, type SyncResult, type SyncState, TRANSCRIPT_FORMAT_VERSION, Taxonomy, TokenEntry, type TrainingExportAdapter, type TrainingExportOptions, type TrainingExportRecord, type TranscriptSegmentMatch, type TreeNode, WEARABLES_DIR_NAME, WearableCleanupSettings, type WearableConnectorFactory, type WearableConnectorFactoryOptions, type WearableConnectorRegistration, WearableConversation, WearableCorrectionRule, WearableDayTranscript, WearableDayTranscriptMeta, WearableFusionConfig, WearableSourceConnector, WearableSourceSettings, type WearableSourceSyncState, type WearableSyncStateFile, type WearablesCliIo, WearablesConfig, WearablesInputError, WearablesService, activityDatabasePath, activityDayWindow, activityDigestPath, appendRelayMissionEvent, applyActivitySchema, applyCorrections, applyOffTheRecord, bodyIsEscaped, branchNamespaceName, buildProcedureMarkdownBody, buildProcedureRecallSection, cleanConversation, clearStructuralContextProvidersForTest, clearTrainingExportAdapters, clearWearableConnectors, clusterConversations, collapseImmediateRepeats, collectLocalSessionSummaries, compareRelayEvents, compileCorrectionRule, compileCorrectionRules, compileRedactionPatterns, compileRedactionRules, composeActivityDigestBody, composeActivityDigestMeta, composeDayTranscriptBody, composeDayTranscriptMeta, convertMemoriesToRecords, correctionsFilePath, createBackend, createGoogleDriveConnector, createNotionConnector, createRelayMissionFixture, createSpace, createSubprocessStructuralProvider, curate, decodeTranscriptBody, defaultGoogleDriveClientFactory, defaultWearableCleanupSettings, defaultWearableFusionConfig, defaultWearableSourceSettings, defaultWearablesConfig, deleteSpace, describeCodingScope, describeErrorForOperator, describeStructuralProviderStatus, emptyManifest, emptySyncState, ensureActivityStateDir, ensureBuiltInWearableConnectors, escapeSegmentText, findContradictions, findDuplicates, forkCapsule, fuseCluster, fuseDay, fusionInputsFromConversations, generateContextTree, generateResolverDocument, getActiveSpace, getAuditLog, getLocalSessionSourceAdapter, getManifestPath, getSpacesDir, getStructuralContextProvider, getTaxonomyDir, getTaxonomyFilePath, getTrainingExportAdapter, getWearableConnector, hashActivityBody, hashTranscriptBody, hostIdForConnector, isLowQualitySegment, isReviewPrompt, isValidActivityDate, isValidTranscriptDate, listLocalSessionSourceAdapters, listReviewItems, listSpaces, listTrainingExportAdapters, listWearableConnectors, loadCorrectionsFile, loadManifest, loadSyncState, loadTaxonomy, manifestDir, manifestPath, matchesPatterns, mergeSpaces, normalizeOriginUrl, onboard, openActivityDatabase, packReviewContext, packReviewContextStructural, parseActivityDigest, parseDayTranscript, parseFlexibleIsoTimestamp, parseIsoOffsetTimestamp, parseIsoUtcTimestamp, parseProcedureStepsFromBody, parseTouchedFiles, parseTranscriptSegmentLine, parseWearablesConfig, performReview, probeStructuralProviderForDoctor, projectNamespaceName, promoteSpace, publisherFor, publisherForConnector, pullFromSpace, pushToSpace, rankReviewCandidates, readForkLineage, readManifest, readRelayMission, reconstructFusionInputs, redactSessionSummaryText, redactText, reduceRelayMission, registerLocalSessionSourceAdapter, registerPublisher, registerStructuralContextProvider, registerTrainingExportAdapter, registerWearableConnector, relayMissionAppendOperation, relayMissionReadOperation, relayMissionReceiptDigest, renderExtensionsBlock, renderExtensionsFooter, renderStructuralProviderStatusLine, resolveCategory, resolveCodingNamespaceOverlay, resolveGitContext, runBinaryLifecyclePipeline, runLocalSessionSummaryCliCommand, runWearablesCliCommand, saveCorrectionsFile, saveManifest, saveSyncState, saveTaxonomy, scanForBinaries, serializeActivityDigest, serializeDayTranscript, shareSpace, stableHash, stripFillerTokens, structuralProviderActive, switchSpace, syncChanges, syncStateFilePath, toStructuralContextDegradation, unescapeSegmentText, unescapeSpeakerLabel, updateSourceSyncState, validateGoogleDriveConfig, validateNotionConfig, validateSlug, validateTaxonomy, watchForChanges, writeManifest };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ACTIVITY_DIGEST_FORMAT_VERSION,
|
|
3
|
+
ACTIVITY_DIR_NAME,
|
|
4
|
+
ActivityStore,
|
|
2
5
|
ClaudeCodeMemoryExtensionPublisher,
|
|
3
6
|
CodexMemoryExtensionPublisher,
|
|
4
7
|
DEFAULT_GRACE_PERIOD_DAYS,
|
|
@@ -18,11 +21,17 @@ import {
|
|
|
18
21
|
REMNIC_RECALL_DECISION_RULES,
|
|
19
22
|
REMNIC_SEMANTIC_OVERVIEW,
|
|
20
23
|
WearablesService,
|
|
24
|
+
activityDatabasePath,
|
|
25
|
+
activityDayWindow,
|
|
26
|
+
activityDigestPath,
|
|
27
|
+
applyActivitySchema,
|
|
21
28
|
buildProcedureRecallSection,
|
|
22
29
|
clearStructuralContextProvidersForTest,
|
|
23
30
|
clearWearableConnectors,
|
|
24
31
|
collectLocalSessionSummaries,
|
|
25
32
|
compileRedactionRules,
|
|
33
|
+
composeActivityDigestBody,
|
|
34
|
+
composeActivityDigestMeta,
|
|
26
35
|
createBackend,
|
|
27
36
|
createRelayMissionFixture,
|
|
28
37
|
createSpace,
|
|
@@ -33,6 +42,7 @@ import {
|
|
|
33
42
|
deleteSpace,
|
|
34
43
|
describeStructuralProviderStatus,
|
|
35
44
|
emptyManifest,
|
|
45
|
+
ensureActivityStateDir,
|
|
36
46
|
ensureBuiltInWearableConnectors,
|
|
37
47
|
findContradictions,
|
|
38
48
|
findDuplicates,
|
|
@@ -48,8 +58,10 @@ import {
|
|
|
48
58
|
getTaxonomyDir,
|
|
49
59
|
getTaxonomyFilePath,
|
|
50
60
|
getWearableConnector,
|
|
61
|
+
hashActivityBody,
|
|
51
62
|
hostIdForConnector,
|
|
52
63
|
isReviewPrompt,
|
|
64
|
+
isValidActivityDate,
|
|
53
65
|
listLocalSessionSourceAdapters,
|
|
54
66
|
listReviewItems,
|
|
55
67
|
listSpaces,
|
|
@@ -62,8 +74,10 @@ import {
|
|
|
62
74
|
matchesPatterns,
|
|
63
75
|
mergeSpaces,
|
|
64
76
|
onboard,
|
|
77
|
+
openActivityDatabase,
|
|
65
78
|
packReviewContext,
|
|
66
79
|
packReviewContextStructural,
|
|
80
|
+
parseActivityDigest,
|
|
67
81
|
parseTouchedFiles,
|
|
68
82
|
performReview,
|
|
69
83
|
probeStructuralProviderForDoctor,
|
|
@@ -87,6 +101,7 @@ import {
|
|
|
87
101
|
saveManifest,
|
|
88
102
|
saveTaxonomy,
|
|
89
103
|
scanForBinaries,
|
|
104
|
+
serializeActivityDigest,
|
|
90
105
|
shareSpace,
|
|
91
106
|
structuralProviderActive,
|
|
92
107
|
switchSpace,
|
|
@@ -96,7 +111,7 @@ import {
|
|
|
96
111
|
validateTaxonomy,
|
|
97
112
|
watchForChanges,
|
|
98
113
|
writeManifest
|
|
99
|
-
} from "./chunk-
|
|
114
|
+
} from "./chunk-3VBXP5HS.js";
|
|
100
115
|
import {
|
|
101
116
|
WEARABLE_SOURCE_PREFIX,
|
|
102
117
|
buildExtractionTurns,
|
|
@@ -1038,7 +1053,10 @@ export {
|
|
|
1038
1053
|
ACTION_CONFIDENCE_RISK_CATEGORIES,
|
|
1039
1054
|
ACTION_CONFIDENCE_RULE_KINDS,
|
|
1040
1055
|
ACTIVE_STATUSES,
|
|
1056
|
+
ACTIVITY_DIGEST_FORMAT_VERSION,
|
|
1057
|
+
ACTIVITY_DIR_NAME,
|
|
1041
1058
|
AccessAuditAdapter,
|
|
1059
|
+
ActivityStore,
|
|
1042
1060
|
BRIEFING_FORMAT_ALLOWED,
|
|
1043
1061
|
BootstrapEngine,
|
|
1044
1062
|
CITATION_UNKNOWN,
|
|
@@ -1162,9 +1180,13 @@ export {
|
|
|
1162
1180
|
WearablesInputError,
|
|
1163
1181
|
WearablesService,
|
|
1164
1182
|
WebSearchProvider,
|
|
1183
|
+
activityDatabasePath,
|
|
1184
|
+
activityDayWindow,
|
|
1185
|
+
activityDigestPath,
|
|
1165
1186
|
appendAuditEntry,
|
|
1166
1187
|
appendInteractionLog,
|
|
1167
1188
|
appendRelayMissionEvent,
|
|
1189
|
+
applyActivitySchema,
|
|
1168
1190
|
applyCorrections,
|
|
1169
1191
|
applyLcmSchema,
|
|
1170
1192
|
applyMemoryWorthFilter,
|
|
@@ -1238,6 +1260,8 @@ export {
|
|
|
1238
1260
|
compileOfflineSyncExcludeGlobs,
|
|
1239
1261
|
compileRedactionPatterns,
|
|
1240
1262
|
compileRedactionRules,
|
|
1263
|
+
composeActivityDigestBody,
|
|
1264
|
+
composeActivityDigestMeta,
|
|
1241
1265
|
composeDayTranscriptBody,
|
|
1242
1266
|
composeDayTranscriptMeta,
|
|
1243
1267
|
composeFusionDayMeta,
|
|
@@ -1288,6 +1312,7 @@ export {
|
|
|
1288
1312
|
emptyManifest,
|
|
1289
1313
|
emptySpeakerRegistry,
|
|
1290
1314
|
emptySyncState,
|
|
1315
|
+
ensureActivityStateDir,
|
|
1291
1316
|
ensureBuiltInWearableConnectors,
|
|
1292
1317
|
ensureLcmStateDir,
|
|
1293
1318
|
ensureSentinel,
|
|
@@ -1339,6 +1364,7 @@ export {
|
|
|
1339
1364
|
hasBroadGraphIntent,
|
|
1340
1365
|
hasCitation,
|
|
1341
1366
|
hasEnabledLiveConnector,
|
|
1367
|
+
hashActivityBody,
|
|
1342
1368
|
hashFusionBody,
|
|
1343
1369
|
hashTranscriptBody,
|
|
1344
1370
|
hostIdForConnector,
|
|
@@ -1370,6 +1396,7 @@ export {
|
|
|
1370
1396
|
isUserBoundaryScope,
|
|
1371
1397
|
isUserContextScope,
|
|
1372
1398
|
isUserModelDimension,
|
|
1399
|
+
isValidActivityDate,
|
|
1373
1400
|
isValidCachedVerdict,
|
|
1374
1401
|
isValidConnectorId,
|
|
1375
1402
|
isValidNamespaceValue,
|
|
@@ -1429,9 +1456,11 @@ export {
|
|
|
1429
1456
|
observeRequestSchema,
|
|
1430
1457
|
offlineSyncStateFromSnapshot,
|
|
1431
1458
|
onboard,
|
|
1459
|
+
openActivityDatabase,
|
|
1432
1460
|
openLcmDatabase,
|
|
1433
1461
|
packReviewContext,
|
|
1434
1462
|
packReviewContextStructural,
|
|
1463
|
+
parseActivityDigest,
|
|
1435
1464
|
parseAllCitations,
|
|
1436
1465
|
parseAnthropicMessageParts,
|
|
1437
1466
|
parseBriefingFocus,
|
|
@@ -1560,6 +1589,7 @@ export {
|
|
|
1560
1589
|
saveTokenStore,
|
|
1561
1590
|
scanForBinaries,
|
|
1562
1591
|
sealedWriteToLegacyArgs,
|
|
1592
|
+
serializeActivityDigest,
|
|
1563
1593
|
serializeDayTranscript,
|
|
1564
1594
|
serializeEntityFile,
|
|
1565
1595
|
serializeFusionDay,
|
package/dist/orchestrator.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remnic/core",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.12.0",
|
|
4
4
|
"description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -3045,7 +3045,7 @@
|
|
|
3045
3045
|
"core"
|
|
3046
3046
|
],
|
|
3047
3047
|
"peerDependencies": {
|
|
3048
|
-
"@remnic/coding-graph": "^9.
|
|
3048
|
+
"@remnic/coding-graph": "^9.12.0"
|
|
3049
3049
|
},
|
|
3050
3050
|
"peerDependenciesMeta": {
|
|
3051
3051
|
"@remnic/coding-graph": {
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { test } from "node:test";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
activityDayWindow,
|
|
6
|
+
activityDigestPath,
|
|
7
|
+
composeActivityDigestBody,
|
|
8
|
+
composeActivityDigestMeta,
|
|
9
|
+
isValidActivityDate,
|
|
10
|
+
parseActivityDigest,
|
|
11
|
+
serializeActivityDigest,
|
|
12
|
+
} from "./digest.js";
|
|
13
|
+
import type { ActivitySnapshot } from "./types.js";
|
|
14
|
+
|
|
15
|
+
function snap(overrides: Partial<ActivitySnapshot> = {}): ActivitySnapshot {
|
|
16
|
+
return {
|
|
17
|
+
machine: "macstudio",
|
|
18
|
+
capturedAtUtc: "2026-03-10T14:00:00.000Z",
|
|
19
|
+
app: "Chrome",
|
|
20
|
+
windowTitle: "Roadmap",
|
|
21
|
+
text: "quarterly roadmap review notes",
|
|
22
|
+
textSource: "ax",
|
|
23
|
+
contentHash: "h",
|
|
24
|
+
...overrides,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const DAY = [
|
|
29
|
+
snap({ id: 1, contentHash: "a", capturedAtUtc: "2026-03-10T14:00:00.000Z", app: "Chrome", windowTitle: "Roadmap", text: "roadmap planning" }),
|
|
30
|
+
snap({ id: 2, contentHash: "b", capturedAtUtc: "2026-03-10T14:10:00.000Z", app: "Slack", windowTitle: "#eng", text: "deploy staging soon" }),
|
|
31
|
+
snap({ id: 3, contentHash: "c", capturedAtUtc: "2026-03-10T14:12:00.000Z", app: "Chrome", windowTitle: "PR 412", browserUrl: "https://github.com/x/pull/412", text: "review pull request" }),
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
test("composeActivityDigestBody is byte-identical across two renders (deterministic)", () => {
|
|
35
|
+
const a = composeActivityDigestBody("2026-03-10", "America/Chicago", DAY);
|
|
36
|
+
const b = composeActivityDigestBody("2026-03-10", "America/Chicago", [...DAY].reverse());
|
|
37
|
+
assert.equal(a, b);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("per-app time section is sorted with a stable tiebreaker on equal dwell", () => {
|
|
41
|
+
// Two apps with identical (zero) dwell — last snapshots — must order by name.
|
|
42
|
+
const snaps = [
|
|
43
|
+
snap({ id: 1, contentHash: "a", capturedAtUtc: "2026-03-10T14:00:00.000Z", app: "Zed" }),
|
|
44
|
+
snap({ id: 2, contentHash: "b", capturedAtUtc: "2026-03-10T14:00:00.000Z", app: "Arc" }),
|
|
45
|
+
];
|
|
46
|
+
const body1 = composeActivityDigestBody("2026-03-10", "UTC", snaps);
|
|
47
|
+
const body2 = composeActivityDigestBody("2026-03-10", "UTC", [...snaps].reverse());
|
|
48
|
+
assert.equal(body1, body2);
|
|
49
|
+
// Arc sorts before Zed at equal dwell.
|
|
50
|
+
assert.ok(body1.indexOf("- Arc:") < body1.indexOf("- Zed:"));
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("contentHash is stable across renders and meta reflects inputs", () => {
|
|
54
|
+
const body = composeActivityDigestBody("2026-03-10", "UTC", DAY);
|
|
55
|
+
const meta = composeActivityDigestMeta("2026-03-10", ["laptop", "macstudio", "laptop"], DAY, body);
|
|
56
|
+
assert.equal(meta.kind, "activity-digest");
|
|
57
|
+
assert.equal(meta.snapshotCount, 3);
|
|
58
|
+
assert.deepEqual(meta.machines, ["laptop", "macstudio"]); // deduped + sorted
|
|
59
|
+
assert.equal(meta.contentHash, composeActivityDigestMeta("2026-03-10", ["macstudio"], DAY, body).contentHash);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("serialize → parse round-trips meta and body", () => {
|
|
63
|
+
const body = composeActivityDigestBody("2026-03-10", "UTC", DAY);
|
|
64
|
+
const meta = composeActivityDigestMeta("2026-03-10", ["macstudio"], DAY, body);
|
|
65
|
+
const parsed = parseActivityDigest(serializeActivityDigest(meta, body));
|
|
66
|
+
assert.ok(parsed);
|
|
67
|
+
assert.deepEqual(parsed?.meta, meta);
|
|
68
|
+
assert.equal(parsed?.body, body);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("parseActivityDigest returns null on malformed input", () => {
|
|
72
|
+
assert.equal(parseActivityDigest("no frontmatter here"), null);
|
|
73
|
+
assert.equal(parseActivityDigest("---\nkind: activity-digest\n(no closing fence)"), null);
|
|
74
|
+
assert.equal(parseActivityDigest("---\nkind: other\ndate: 2026-03-10\ncontentHash: x\n---\nbody"), null);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("activityDayWindow yields half-open DST-aware bounds", () => {
|
|
78
|
+
const w = activityDayWindow("2026-03-10", "America/Chicago");
|
|
79
|
+
assert.equal(w.startUtc, "2026-03-10T05:00:00.000Z");
|
|
80
|
+
assert.equal(w.endUtc, "2026-03-11T05:00:00.000Z");
|
|
81
|
+
// Spring-forward day: CST→CDT shift reflected.
|
|
82
|
+
const dst = activityDayWindow("2026-03-08", "America/Chicago");
|
|
83
|
+
assert.equal(dst.startUtc, "2026-03-08T06:00:00.000Z");
|
|
84
|
+
assert.equal(dst.endUtc, "2026-03-09T05:00:00.000Z");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("a snapshot at exactly local midnight lands in exactly one day", () => {
|
|
88
|
+
// Local midnight 2026-03-10 in America/Chicago (CST) == 06:00Z.
|
|
89
|
+
const midnightUtc = "2026-03-10T06:00:00.000Z";
|
|
90
|
+
const day10 = activityDayWindow("2026-03-10", "America/Chicago");
|
|
91
|
+
const day09 = activityDayWindow("2026-03-09", "America/Chicago");
|
|
92
|
+
// Included in the 10th (start-inclusive), excluded from the 9th (end-exclusive).
|
|
93
|
+
assert.ok(midnightUtc >= day10.startUtc && midnightUtc < day10.endUtc);
|
|
94
|
+
assert.ok(!(midnightUtc >= day09.startUtc && midnightUtc < day09.endUtc));
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("activityDigestPath places the file under <memoryDir>/activity/", () => {
|
|
98
|
+
assert.equal(activityDigestPath("/mem", "2026-03-10"), "/mem/activity/2026-03-10.md");
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("isValidActivityDate rejects impossible and malformed calendar days", () => {
|
|
102
|
+
assert.equal(isValidActivityDate("2026-03-10"), true);
|
|
103
|
+
assert.equal(isValidActivityDate("2026-02-30"), false); // Feb has no 30th
|
|
104
|
+
assert.equal(isValidActivityDate("2026-13-01"), false); // no month 13
|
|
105
|
+
assert.equal(isValidActivityDate("2026-00-10"), false);
|
|
106
|
+
assert.equal(isValidActivityDate("not-a-date"), false);
|
|
107
|
+
assert.equal(isValidActivityDate("2026-3-10"), false); // wrong shape
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("activityDigestPath rejects path-traversal / invalid dates", () => {
|
|
111
|
+
assert.equal(activityDigestPath("/mem", "2026-03-10"), "/mem/activity/2026-03-10.md");
|
|
112
|
+
assert.throws(() => activityDigestPath("/mem", "../../etc/passwd"), RangeError);
|
|
113
|
+
assert.throws(() => activityDigestPath("/mem", "2026-02-30"), RangeError);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test("activityDayWindow rejects an impossible date", () => {
|
|
117
|
+
assert.throws(() => activityDayWindow("2026-02-30", "UTC"), RangeError);
|
|
118
|
+
assert.throws(() => activityDayWindow("../evil", "UTC"), RangeError);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("parseActivityDigest rejects a non-numeric snapshotCount/formatVersion", () => {
|
|
122
|
+
const body = composeActivityDigestBody("2026-03-10", "UTC", DAY);
|
|
123
|
+
const meta = composeActivityDigestMeta("2026-03-10", ["macstudio"], DAY, body);
|
|
124
|
+
const good = serializeActivityDigest(meta, body);
|
|
125
|
+
const broken = good.replace(/snapshotCount: \d+/, "snapshotCount: lots");
|
|
126
|
+
assert.equal(parseActivityDigest(broken), null);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test("dwell is scoped per capture machine — an interleaved machine can't steal it", () => {
|
|
130
|
+
const snaps = [
|
|
131
|
+
snap({ machine: "A", app: "A-app", capturedAtUtc: "2026-03-10T14:00:00.000Z", contentHash: "a1" }),
|
|
132
|
+
snap({ machine: "B", app: "B-app", capturedAtUtc: "2026-03-10T14:01:00.000Z", contentHash: "b1" }),
|
|
133
|
+
snap({ machine: "A", app: "A-app", capturedAtUtc: "2026-03-10T14:10:00.000Z", contentHash: "a2" }),
|
|
134
|
+
];
|
|
135
|
+
const body = composeActivityDigestBody("2026-03-10", "UTC", snaps);
|
|
136
|
+
// A-app dwell = A@14:00 → A@14:10 = 10m (per-machine), not 1m (global next = B@14:01).
|
|
137
|
+
assert.ok(body.includes("- A-app: 10m"), body);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("digest ordering is deterministic for same-time unsaved snapshots", () => {
|
|
141
|
+
const a = snap({ capturedAtUtc: "2026-03-10T14:00:00.000Z", contentHash: "h-a", app: "Alpha", text: "alpha window" });
|
|
142
|
+
const b = snap({ capturedAtUtc: "2026-03-10T14:00:00.000Z", contentHash: "h-b", app: "Beta", text: "beta window" });
|
|
143
|
+
const one = composeActivityDigestBody("2026-03-10", "UTC", [a, b]);
|
|
144
|
+
const two = composeActivityDigestBody("2026-03-10", "UTC", [b, a]);
|
|
145
|
+
assert.equal(one, two);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("activityDayWindow does not backdate a skipped local midnight", () => {
|
|
149
|
+
// Egypt restarts DST on the last Friday of April at 00:00 (00:00 → 01:00),
|
|
150
|
+
// so local midnight is skipped. The day-start must land on the correct local
|
|
151
|
+
// day (the first existing local time), never backdated into the prior day.
|
|
152
|
+
const w = activityDayWindow("2026-04-24", "Africa/Cairo");
|
|
153
|
+
const local = new Intl.DateTimeFormat("en-CA", {
|
|
154
|
+
timeZone: "Africa/Cairo",
|
|
155
|
+
year: "numeric",
|
|
156
|
+
month: "2-digit",
|
|
157
|
+
day: "2-digit",
|
|
158
|
+
hour: "2-digit",
|
|
159
|
+
minute: "2-digit",
|
|
160
|
+
hour12: false,
|
|
161
|
+
}).format(new Date(w.startUtc));
|
|
162
|
+
assert.ok(local.startsWith("2026-04-24"), local);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test("timeline keeps a second machine's span even with the same app/window", () => {
|
|
166
|
+
const a = snap({ machine: "A", capturedAtUtc: "2026-03-10T14:00:00.000Z", app: "Chrome", windowTitle: "Doc", contentHash: "a1", text: "" });
|
|
167
|
+
const b = snap({ machine: "B", capturedAtUtc: "2026-03-10T14:00:30.000Z", app: "Chrome", windowTitle: "Doc", contentHash: "b1", text: "" });
|
|
168
|
+
const body = composeActivityDigestBody("2026-03-10", "UTC", [a, b]);
|
|
169
|
+
// machine is part of the timeline-span key, so the same app/window on a
|
|
170
|
+
// different machine is not coalesced away.
|
|
171
|
+
const timelineLines = body.split("\n").filter((line) => line.startsWith("- ["));
|
|
172
|
+
assert.equal(timelineLines.length, 2);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("machine labels with YAML-special chars round-trip through the digest", () => {
|
|
176
|
+
const body = composeActivityDigestBody("2026-03-10", "UTC", DAY);
|
|
177
|
+
const meta = composeActivityDigestMeta("2026-03-10", ["alpha, beta", "macstudio"], DAY, body);
|
|
178
|
+
const parsed = parseActivityDigest(serializeActivityDigest(meta, body));
|
|
179
|
+
assert.deepEqual(parsed?.meta.machines, ["alpha, beta", "macstudio"]);
|
|
180
|
+
});
|