memorio 5.0.0 → 5.1.1

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.
Files changed (60) hide show
  1. package/README.md +98 -435
  2. package/SECURITY.md +152 -42
  3. package/SUMMARY.md +1 -1
  4. package/adr/001-state-proxy-model.md +95 -96
  5. package/adr/002-observer-semantics.md +179 -180
  6. package/adr/003-deep-mutation-semantics.md +7 -8
  7. package/adr/004-array-mutation-semantics.md +127 -128
  8. package/adr/005-scheduler-contract.md +148 -149
  9. package/adr/006-context-isolation.md +91 -92
  10. package/adr/007-mutation-records.md +5 -6
  11. package/adr/008-transactions.md +6 -7
  12. package/adr/009-history-model.md +6 -7
  13. package/adr/README.md +46 -46
  14. package/adr/template.md +48 -49
  15. package/bin/cli.js +68 -0
  16. package/global.cjs +1462 -323
  17. package/global.js +1459 -324
  18. package/index.cjs +1462 -323
  19. package/index.d.ts +1 -0
  20. package/index.js +1459 -324
  21. package/llms.txt +42 -5
  22. package/markdown/AUDIT-REPORT.md +7 -8
  23. package/markdown/CACHE.md +190 -99
  24. package/markdown/DEVTOOLS.md +0 -1
  25. package/markdown/DISPATCH.md +0 -1
  26. package/markdown/HISTORY.md +0 -1
  27. package/markdown/IDB.md +0 -1
  28. package/markdown/IMPORT.md +0 -1
  29. package/markdown/INSPECT.md +0 -1
  30. package/markdown/LOGGER.md +0 -1
  31. package/markdown/MEMORY-ATTACHMENT.md +0 -1
  32. package/markdown/MEMORY.md +0 -1
  33. package/markdown/OBSERVER.md +0 -1
  34. package/markdown/PLATFORM.md +277 -271
  35. package/markdown/REDUX.md +54 -0
  36. package/markdown/SCHEMA.md +0 -1
  37. package/markdown/SESSION.md +0 -1
  38. package/markdown/SQLITE.md +0 -1
  39. package/markdown/STATE.md +0 -1
  40. package/markdown/STORE.md +0 -1
  41. package/markdown/SYNC.md +0 -1
  42. package/markdown/TYPED.md +0 -1
  43. package/markdown/USEOBSERVER.md +0 -1
  44. package/modules/redux.cjs +381 -10
  45. package/modules/redux.cjs.map +1 -1
  46. package/modules/redux.js +381 -10
  47. package/modules/redux.js.map +1 -1
  48. package/package.json +14 -2
  49. package/types/broadcast.d.ts +61 -0
  50. package/types/computed.d.ts +96 -0
  51. package/types/encryption.d.ts +129 -0
  52. package/types/exports.d.ts +9 -0
  53. package/types/memorio.d.ts +19 -12
  54. package/types/security.d.ts +67 -0
  55. package/types/session.d.ts +23 -5
  56. package/types/store.d.ts +19 -3
  57. package/vsix/memorio.vsix +0 -0
  58. package/markdown/CHANGELOG.md +0 -243
  59. package/markdown/PROJECT.md +0 -311
  60. package/markdown/SECURITY.md +0 -330
@@ -1,92 +1,91 @@
1
- # ADR-006: Context Isolation Model
2
-
3
- > **Status:** Accepted
4
- > **Date:** 2026-09-12
5
- > **Deciders:** Memorio 5.x Core Team
6
-
7
- ## Context
8
-
9
- Memorio must support multiple isolated state trees within a single
10
- process — for tests, micro-frontends, SSR, workers, and multi-tenant
11
- environments. The 4.7.3 baseline uses `createContext` /
12
- `memorio.isolate(name)` to create context-prefixed state, but the
13
- mechanics and guarantees are undocumented.
14
-
15
- This ADR defines how context isolation works, what the isolation
16
- boundary is, and how it interacts with the Mutation Engine (ADR-007).
17
-
18
- ## Assumptions
19
-
20
- - The core `state`, `store`, `session`, `cache` singletons live on
21
- `globalThis` and are shared across all import paths (ESM, CJS,
22
- absolute-path imports).
23
- - A "context" is a string ID that prefixes internal store keys.
24
- - `memorio.setContext(id)` sets the active context ID at runtime.
25
- - Server-side code must create per-request contexts from trusted
26
- server-side data (never client-controlled input).
27
-
28
- ## Decision
29
-
30
- ### Global singleton vs. isolated context
31
-
32
- - The global `state` / `store` / `session` / `cache` are **singletons**
33
- on `globalThis`. Importing `memorio` in any module returns the same
34
- instances. This is the default and is intended for single-instance
35
- applications (e.g. one browser tab, one Next.js server instance).
36
- - `memorio.isolate(name)` creates a new context and returns
37
- context-scoped proxies. These proxies share the same underlying
38
- engine but read/write to context-prefixed keys in `store`.
39
-
40
- ### Context ID
41
-
42
- - Context IDs are strings. They must be unique within a process.
43
- - Context IDs are **organizational**, not a security boundary. They
44
- do not prevent unauthorized access to another context's data within
45
- the same process. Server-side authorization must be enforced at the
46
- application layer.
47
- - `internal.currentContext` is a module-level string on the singleton
48
- `internal` object. Mutations record the active context ID.
49
-
50
- ### Context-scoped state
51
-
52
- When `internal.currentContext` is set to `ctxId`:
53
-
54
- 1. `state.set(key, value)` writes to `state` but records
55
- `context: ctxId` in the MutationRecord.
56
- 2. `store.set(key, value)` writes to storage with key
57
- `ctxId:key` (key-prefix isolation).
58
- 3. `session.set(key, value)` writes to storage with key
59
- `ctxId:key`.
60
- 4. Reads from `store.get(key)` and `session.get(key)` read from
61
- `ctxId:key`.
62
-
63
- ### Default context
64
-
65
- When `internal.currentContext` is `null` (the default), all state and
66
- store operations use the un-prefixed keys. This is the "default" or
67
- "global" context.
68
-
69
- ### Multi-tenant caveat
70
-
71
- `state` (the Proxy) is always global — it is a single reactive tree.
72
- Context isolation applies to **persistence** (`store`, `session`) and
73
- **mutation records** (`context` field). To achieve true state-tree
74
- isolation, consumers should use `memorio.isolate(name)` which creates
75
- a new context, or instantiate isolated Memorio instances.
76
-
77
- ## Consequences
78
-
79
- - **Positive:** Single global singleton simplifies the common case
80
- (one app, one state tree).
81
- - **Positive:** Context-prefixed persistence enables multi-tenant
82
- server-side usage without separate state trees.
83
- - **Positive:** Mutation records carry context, enabling causal-graph
84
- partitioning (Phase 4).
85
- - **Negative:** `state` itself is not multi-tenant — consumers needing
86
- isolated state trees must use `isolate()` or separate processes.
87
- - **Negative:** Context isolation is organizational, not a security
88
- boundary — documented clearly in AGENTS.md.
89
-
90
- ## Compliance tests
91
-
92
- - `tests/vitest/tests/contracts/adr-006-context.test.ts`
1
+ # ADR-006: Context Isolation Model
2
+
3
+ > **Status:** Accepted
4
+ > **Date:** 2026-09-12
5
+
6
+ ## Context
7
+
8
+ Memorio must support multiple isolated state trees within a single
9
+ process - for tests, micro-frontends, SSR, workers, and multi-tenant
10
+ environments. The 4.7.3 baseline uses `createContext` /
11
+ `memorio.isolate(name)` to create context-prefixed state, but the
12
+ mechanics and guarantees are undocumented.
13
+
14
+ This ADR defines how context isolation works, what the isolation
15
+ boundary is, and how it interacts with the Mutation Engine (ADR-007).
16
+
17
+ ## Assumptions
18
+
19
+ - The core `state`, `store`, `session`, `cache` singletons live on
20
+ `globalThis` and are shared across all import paths (ESM, CJS,
21
+ absolute-path imports).
22
+ - A "context" is a string ID that prefixes internal store keys.
23
+ - `memorio.setContext(id)` sets the active context ID at runtime.
24
+ - Server-side code must create per-request contexts from trusted
25
+ server-side data (never client-controlled input).
26
+
27
+ ## Decision
28
+
29
+ ### Global singleton vs. isolated context
30
+
31
+ - The global `state` / `store` / `session` / `cache` are **singletons**
32
+ on `globalThis`. Importing `memorio` in any module returns the same
33
+ instances. This is the default and is intended for single-instance
34
+ applications (e.g. one browser tab, one Next.js server instance).
35
+ - `memorio.isolate(name)` creates a new context and returns
36
+ context-scoped proxies. These proxies share the same underlying
37
+ engine but read/write to context-prefixed keys in `store`.
38
+
39
+ ### Context ID
40
+
41
+ - Context IDs are strings. They must be unique within a process.
42
+ - Context IDs are **organizational**, not a security boundary. They
43
+ do not prevent unauthorized access to another context's data within
44
+ the same process. Server-side authorization must be enforced at the
45
+ application layer.
46
+ - `internal.currentContext` is a module-level string on the singleton
47
+ `internal` object. Mutations record the active context ID.
48
+
49
+ ### Context-scoped state
50
+
51
+ When `internal.currentContext` is set to `ctxId`:
52
+
53
+ 1. `state.set(key, value)` writes to `state` but records
54
+ `context: ctxId` in the MutationRecord.
55
+ 2. `store.set(key, value)` writes to storage with key
56
+ `ctxId:key` (key-prefix isolation).
57
+ 3. `session.set(key, value)` writes to storage with key
58
+ `ctxId:key`.
59
+ 4. Reads from `store.get(key)` and `session.get(key)` read from
60
+ `ctxId:key`.
61
+
62
+ ### Default context
63
+
64
+ When `internal.currentContext` is `null` (the default), all state and
65
+ store operations use the un-prefixed keys. This is the "default" or
66
+ "global" context.
67
+
68
+ ### Multi-tenant caveat
69
+
70
+ `state` (the Proxy) is always global - it is a single reactive tree.
71
+ Context isolation applies to **persistence** (`store`, `session`) and
72
+ **mutation records** (`context` field). To achieve true state-tree
73
+ isolation, consumers should use `memorio.isolate(name)` which creates
74
+ a new context, or instantiate isolated Memorio instances.
75
+
76
+ ## Consequences
77
+
78
+ - **Positive:** Single global singleton simplifies the common case
79
+ (one app, one state tree).
80
+ - **Positive:** Context-prefixed persistence enables multi-tenant
81
+ server-side usage without separate state trees.
82
+ - **Positive:** Mutation records carry context, enabling causal-graph
83
+ partitioning (Phase 4).
84
+ - **Negative:** `state` itself is not multi-tenant - consumers needing
85
+ isolated state trees must use `isolate()` or separate processes.
86
+ - **Negative:** Context isolation is organizational, not a security
87
+ boundary - documented clearly in AGENTS.md.
88
+
89
+ ## Compliance tests
90
+
91
+ - `tests/vitest/tests/contracts/adr-006-context.test.ts`
@@ -2,7 +2,6 @@
2
2
 
3
3
  > **Status:** Accepted
4
4
  > **Date:** 2026-09-12
5
- > **Deciders:** Memorio 5.x Core Team
6
5
 
7
6
  ## Context
8
7
 
@@ -59,12 +58,12 @@ interface MutationRecord {
59
58
  ### Guarantees
60
59
 
61
60
  1. **Every mutation gets a unique ID.** The ID is generated via
62
- `generateMutationId()` which calls `hlc.tick()` — guaranteeing
61
+ `generateMutationId()` which calls `hlc.tick()` - guaranteeing
63
62
  causal ordering within a single node. The node suffix ensures
64
63
  uniqueness across devices.
65
64
 
66
65
  2. **Before/after are deepRaw'd.** Proxy wrappers are never stored in
67
- the record — only plain values. This ensures serializable,
66
+ the record - only plain values. This ensures serializable,
68
67
  comparison-safe records.
69
68
 
70
69
  3. **Single write point.** `internal.recordMutation()` is the only
@@ -73,7 +72,7 @@ interface MutationRecord {
73
72
 
74
73
  4. **Redo stack clears on new mutation.** Any mutation (including
75
74
  undo/redo inverse writes, since those temporarily disable history)
76
- must NOT clear the redo stack — undo/redo use
75
+ must NOT clear the redo stack - undo/redo use
77
76
  `internal.historyEnabled = false` to bypass `recordMutation`.
78
77
 
79
78
  5. **Max history depth.** Both stacks are trimmed to
@@ -107,8 +106,8 @@ transaction's mutation list.
107
106
  - **Positive:** Legacy fields maintain full backward compatibility
108
107
  with 4.x consumers.
109
108
  - **Negative:** Storing both legacy and canonical fields doubles the
110
- record size — acceptable for the opt-in history feature.
111
- - **Negative:** No-op mutations are stored — a future optimization
109
+ record size - acceptable for the opt-in history feature.
110
+ - **Negative:** No-op mutations are stored - a future optimization
112
111
  could skip them in the set trap, but the Mutation Engine must remain
113
112
  the source of truth.
114
113
 
@@ -2,7 +2,6 @@
2
2
 
3
3
  > **Status:** Accepted
4
4
  > **Date:** 2026-09-12
5
- > **Deciders:** Memorio 5.x Core Team
6
5
 
7
6
  ## Context
8
7
 
@@ -53,7 +52,7 @@ abortTransaction()
53
52
 
54
53
  `beginTransaction` called while a transaction is already active
55
54
  creates a **new** transaction context (with a new ID). The previous
56
- transaction remains active in the registry — it is **not** suspended
55
+ transaction remains active in the registry - it is **not** suspended
57
56
  or paused. `commitTransaction()` only commits the **most recently
58
57
  started** active transaction.
59
58
 
@@ -84,20 +83,20 @@ Once committed or aborted, a transaction's `mutations` list is frozen
84
83
  1. Calls `createMutation(...)` which auto-tags with the active
85
84
  transaction ID via `tagForTransaction()`.
86
85
  2. Writes to state with `_recording = false` (no double recording).
87
- 3. Calls `recordMutation(mutation)` — the mutation is recorded in the
86
+ 3. Calls `recordMutation(mutation)` - the mutation is recorded in the
88
87
  trace log AND tagged in the transaction.
89
88
 
90
89
  ## Consequences
91
90
 
92
91
  - **Positive:** Mutations are grouped and attributable to a logical
93
- operation — essential for explain() and impact() in Phase 4.
94
- - **Positive:** `abortTransaction` provides atomic rollback — all
92
+ operation - essential for explain() and impact() in Phase 4.
93
+ - **Positive:** `abortTransaction` provides atomic rollback - all
95
94
  mutations are undone.
96
95
  - **Positive:** Registry on `globalThis` survives module duplication.
97
- - **Negative:** Nested transactions are flat (not hierarchical) —
96
+ - **Negative:** Nested transactions are flat (not hierarchical) -
98
97
  the outer transaction is not aborted if the inner is aborted.
99
98
  - **Negative:** Rollback via inverse application requires all
100
- `before` values to be present in the MutationRecord — for
99
+ `before` values to be present in the MutationRecord - for
101
100
  very large objects this is memory-intensive.
102
101
 
103
102
  ## Compliance tests
@@ -2,7 +2,6 @@
2
2
 
3
3
  > **Status:** Proposed
4
4
  > **Date:** 2026-09-12
5
- > **Deciders:** Memorio 5.x Core Team
6
5
 
7
6
  ## Context
8
7
 
@@ -31,7 +30,7 @@ the full Commit → Snapshot → Delta model.
31
30
  - `redo()` pops from `redoStack`, pushes to `undoStack`, re-applies.
32
31
  - `trace()` returns the full `mutations` log (trimmed to
33
32
  `maxHistory`).
34
- - No commit concept exists — every mutation is an individual entry.
33
+ - No commit concept exists - every mutation is an individual entry.
35
34
 
36
35
  ### Target state (Memorio 5.0)
37
36
 
@@ -48,7 +47,7 @@ Commit (immutable, append-only)
48
47
  - **Snapshots** are deep clones of state, materialized every
49
48
  `snapshotInterval` commits (default: 100) to bound replay cost.
50
49
  - **Deltas** are the `Patch[]` that transform a snapshot to the next
51
- state. Only patches are stored between snapshots — never full
50
+ state. Only patches are stored between snapshots - never full
52
51
  state copies.
53
52
  - **Undo/Redo** operate at the commit level, not the individual
54
53
  mutation level. Undoing a commit applies the inverse of every patch
@@ -88,16 +87,16 @@ Commit (immutable, append-only)
88
87
 
89
88
  ## Consequences
90
89
 
91
- - **Positive:** Commits group mutations logically — essential for
90
+ - **Positive:** Commits group mutations logically - essential for
92
91
  explain(), business history, and audit trails.
93
92
  - **Positive:** Snapshot/delta model bounds memory and replay cost.
94
- - **Positive:** Undo and Revert are distinct operations — no
93
+ - **Positive:** Undo and Revert are distinct operations - no
95
94
  conflation.
96
95
  - **Negative:** The current flat stack must be replaced in Phase 3,
97
96
  which is a breaking change to `undo()`/`redo()` semantics
98
97
  (per-mutation → per-commit).
99
98
  - **Negative:** Snapshot materialization at intervals is a trade-off
100
- between memory and CPU — defaults must be benchmark-driven.
99
+ between memory and CPU - defaults must be benchmark-driven.
101
100
 
102
101
  ## Compliance tests
103
102
 
@@ -106,5 +105,5 @@ Commit (immutable, append-only)
106
105
 
107
106
  ## Benchmarks
108
107
 
109
- - `experimental/benchmarks/replay.bench.ts` — measures replay cost
108
+ - `experimental/benchmarks/replay.bench.ts` - measures replay cost
110
109
  with and without interval snapshots.
package/adr/README.md CHANGED
@@ -1,46 +1,46 @@
1
- # Architecture Decision Records (ADRs)
2
-
3
- This directory contains Architecture Decision Records (ADRs) for the
4
- **Memorio 5.x** "Application State Intelligence Runtime" initiative.
5
-
6
- ## Format
7
-
8
- ADRs follow the [MADR](https://adr.github.io/) (Markdown Architectural
9
- Decision Records) format. Each decision record answers four questions:
10
-
11
- 1. **Context** — What is the issue that we were dealing with when we
12
- started thinking about it?
13
- 2. **Decision** — What is the change that we will make (that resolves
14
- the issue)?
15
- 3. **Consequences** — What becomes easier or more difficult to do
16
- because of this change?
17
-
18
- ## Numbering
19
-
20
- | ADR | Title | Status |
21
- |-----|-------|--------|
22
- | [001](001-state-proxy-model.md) | State Proxy Model | Accepted |
23
- | [002](002-observer-semantics.md) | Observer Semantics | Proposed |
24
- | [003](003-deep-mutation-semantics.md) | Deep Mutation Semantics | Proposed |
25
- | [004](004-array-mutation-semantics.md) | Array Mutation Semantics | Proposed |
26
- | [005](005-scheduler-contract.md) | Scheduler Contract | Proposed |
27
- | [006](006-context-isolation.md) | Context Isolation Model | Accepted |
28
- | [007](007-mutation-records.md) | Mutation Records | Accepted |
29
- | [008](008-transactions.md) | Transactions | Accepted |
30
- | [009](009-history-model.md) | History Model (Snapshot/Delta) | Proposed |
31
-
32
- ## Lifecycle
33
-
34
- New ADRs start as **Proposed**, move to **Accepted** when the decision
35
- is implemented and tests pass, and become **Superseded** when a later
36
- ADR supersedes them. A **Deprecated** status marks decisions that are no
37
- longer relevant but kept for historical context.
38
-
39
- ## Compliance
40
-
41
- Every ADR that defines a behavioral contract must have a corresponding
42
- compliance test suite under `tests/vitest/tests/contracts/`. The test
43
- file name mirrors the ADR number (e.g. `adr-004-arrays.test.ts`).
44
-
45
- A release must not be published if any **Accepted** ADR has failing
46
- compliance tests.
1
+ # Architecture Decision Records (ADRs)
2
+
3
+ This directory contains Architecture Decision Records (ADRs) for the
4
+ **Memorio 5.x** "Application State Intelligence Runtime" initiative.
5
+
6
+ ## Format
7
+
8
+ ADRs follow the [MADR](https://adr.github.io/) (Markdown Architectural
9
+ Decision Records) format. Each decision record answers four questions:
10
+
11
+ 1. **Context** - What is the issue that we were dealing with when we
12
+ started thinking about it?
13
+ 2. **Decision** - What is the change that we will make (that resolves
14
+ the issue)?
15
+ 3. **Consequences** - What becomes easier or more difficult to do
16
+ because of this change?
17
+
18
+ ## Numbering
19
+
20
+ | ADR | Title | Status |
21
+ |-----|-------|--------|
22
+ | [001](001-state-proxy-model.md) | State Proxy Model | Accepted |
23
+ | [002](002-observer-semantics.md) | Observer Semantics | Proposed |
24
+ | [003](003-deep-mutation-semantics.md) | Deep Mutation Semantics | Proposed |
25
+ | [004](004-array-mutation-semantics.md) | Array Mutation Semantics | Proposed |
26
+ | [005](005-scheduler-contract.md) | Scheduler Contract | Proposed |
27
+ | [006](006-context-isolation.md) | Context Isolation Model | Accepted |
28
+ | [007](007-mutation-records.md) | Mutation Records | Accepted |
29
+ | [008](008-transactions.md) | Transactions | Accepted |
30
+ | [009](009-history-model.md) | History Model (Snapshot/Delta) | Proposed |
31
+
32
+ ## Lifecycle
33
+
34
+ New ADRs start as **Proposed**, move to **Accepted** when the decision
35
+ is implemented and tests pass, and become **Superseded** when a later
36
+ ADR supersedes them. A **Deprecated** status marks decisions that are no
37
+ longer relevant but kept for historical context.
38
+
39
+ ## Compliance
40
+
41
+ Every ADR that defines a behavioral contract must have a corresponding
42
+ compliance test suite under `tests/vitest/tests/contracts/`. The test
43
+ file name mirrors the ADR number (e.g. `adr-004-arrays.test.ts`).
44
+
45
+ A release must not be published if any **Accepted** ADR has failing
46
+ compliance tests.
package/adr/template.md CHANGED
@@ -1,49 +1,48 @@
1
- # ADR Template — MADR format
2
-
3
- > **Status:** `{Proposed | Accepted | Superseded by [ADR-XXX](adr-XXX.md) | Deprecated}`
4
- > **Date:** YYYY-MM-DD
5
- > **Deciders:** Memorio 5.x Core Team
6
-
7
- ## Context
8
-
9
- > What is the issue that we were dealing with when we started thinking
10
- > about it? What are the forces at play? Consider the unique constraints
11
- > of this project — the need for deterministic, explainable state that
12
- > remembers, understands, replays, and simulates application state.
13
-
14
- ## Assumptions
15
-
16
- > List any assumptions the decision relies on (e.g. “state mutations are
17
- > synchronous,” “the Proxy target is always a plain object or array”).
18
-
19
- ## Decision
20
-
21
- > What is the change that we will make? Describe the chosen approach in
22
- > detail. This section must be precise enough to serve as an implementation
23
- > contract. Include:
24
- >
25
- > - The precise semantics (what happens, what does not happen)
26
- > - Edge cases and error behavior
27
- > - Performance characteristics
28
- > - Backward-compatibility implications
29
-
30
- ## Consequences
31
-
32
- > What becomes easier or more difficult to do because of this change?
33
- > Consider:
34
- >
35
- > - **Positive** — benefits gained (e.g. improved developer experience,
36
- > better performance, deterministic behavior)
37
- > - **Negative** — trade-offs and drawbacks (e.g. loss of flexibility,
38
- > migration complexity, runtime overhead)
39
- > - **Testability** — how this decision is covered by compliance tests
40
-
41
- ## Compliance tests
42
-
43
- > Reference the test file(s) that verify this contract. Every Accepted
44
- > ADR must list at least one compliance test file path relative to the
45
- > repository root.
46
-
47
- ```
48
-
49
- File: _ADR_TITLE_PLACEHOLDER.md
1
+ # ADR Template - MADR format
2
+
3
+ > **Status:** `{Proposed | Accepted | Superseded by [ADR-XXX](adr-XXX.md) | Deprecated}`
4
+ > **Date:** YYYY-MM-DD
5
+
6
+ ## Context
7
+
8
+ > What is the issue that we were dealing with when we started thinking
9
+ > about it? What are the forces at play? Consider the unique constraints
10
+ > of this project - the need for deterministic, explainable state that
11
+ > remembers, understands, replays, and simulates application state.
12
+
13
+ ## Assumptions
14
+
15
+ > List any assumptions the decision relies on (e.g. "state mutations are
16
+ > synchronous," "the Proxy target is always a plain object or array").
17
+
18
+ ## Decision
19
+
20
+ > What is the change that we will make? Describe the chosen approach in
21
+ > detail. This section must be precise enough to serve as an implementation
22
+ > contract. Include:
23
+ >
24
+ > - The precise semantics (what happens, what does not happen)
25
+ > - Edge cases and error behavior
26
+ > - Performance characteristics
27
+ > - Backward-compatibility implications
28
+
29
+ ## Consequences
30
+
31
+ > What becomes easier or more difficult to do because of this change?
32
+ > Consider:
33
+ >
34
+ > - **Positive** - benefits gained (e.g. improved developer experience,
35
+ > better performance, deterministic behavior)
36
+ > - **Negative** - trade-offs and drawbacks (e.g. loss of flexibility,
37
+ > migration complexity, runtime overhead)
38
+ > - **Testability** - how this decision is covered by compliance tests
39
+
40
+ ## Compliance tests
41
+
42
+ > Reference the test file(s) that verify this contract. Every Accepted
43
+ > ADR must list at least one compliance test file path relative to the
44
+ > repository root.
45
+
46
+ ```
47
+
48
+ File: _ADR_TITLE_PLACEHOLDER.md
package/bin/cli.js ADDED
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+ import { spawnSync } from 'node:child_process';
3
+ import path from 'node:path';
4
+ import fs from 'node:fs';
5
+ import os from 'node:os';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+
10
+ const args = process.argv.slice(2);
11
+ const command = args[0];
12
+
13
+ if (command === 'install-extension') {
14
+ installExtension();
15
+ } else {
16
+ console.log('Usage: npx memorio install-extension');
17
+ process.exit(command ? 1 : 0);
18
+ }
19
+
20
+ function installExtension() {
21
+ const vsixPath = path.join(__dirname, '..', 'vsix', 'memorio.vsix');
22
+
23
+ if (!fs.existsSync(vsixPath)) {
24
+ console.error(`VSIX file not found at ${vsixPath}.`);
25
+ console.error('The npm package may be corrupted, or the build did not copy the .vsix into vsix/.');
26
+ process.exit(1);
27
+ }
28
+
29
+ const candidates = candidateBinaries();
30
+ const found = candidates.find((bin) => isAvailable(bin));
31
+
32
+ if (!found) {
33
+ console.error('No compatible editor found in PATH (tried: ' + candidates.join(', ') + ').');
34
+ console.error('Manual installation:');
35
+ console.error(' 1. Open your editor (VSCodium/VSCode)');
36
+ console.error(' 2. Command Palette -> "Extensions: Install from VSIX..."');
37
+ console.error(` 3. Select: ${vsixPath}`);
38
+ process.exit(1);
39
+ }
40
+
41
+ console.log(`Editor detected: ${found}. Installing memorio extension...`);
42
+ const result = spawnSync(found, ['--install-extension', vsixPath], {
43
+ stdio: 'inherit',
44
+ shell: os.platform() === 'win32',
45
+ });
46
+
47
+ if (result.status !== 0) {
48
+ console.error('Installation failed. Try manually:');
49
+ console.error(` ${found} --install-extension "${vsixPath}"`);
50
+ process.exit(result.status || 1);
51
+ }
52
+
53
+ console.log('Memorio extension installed successfully.');
54
+ }
55
+
56
+ function candidateBinaries() {
57
+ const names = ['codium', 'vscodium', 'code', 'code-insiders'];
58
+ if (os.platform() === 'win32') {
59
+ return names.map((n) => `${n}.cmd`);
60
+ }
61
+ return names;
62
+ }
63
+
64
+ function isAvailable(bin) {
65
+ const checkCmd = os.platform() === 'win32' ? 'where' : 'which';
66
+ const result = spawnSync(checkCmd, [bin], { stdio: 'ignore', shell: true });
67
+ return result.status === 0;
68
+ }