synomem 0.9.5 → 0.10.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.
Files changed (120) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +9 -7
  3. package/dist/actor-directory.d.ts +34 -0
  4. package/dist/actor-directory.d.ts.map +1 -0
  5. package/dist/actor-directory.js +52 -0
  6. package/dist/actor-directory.js.map +1 -0
  7. package/dist/backend.d.ts +3 -0
  8. package/dist/backend.d.ts.map +1 -1
  9. package/dist/backend.js +26 -3
  10. package/dist/backend.js.map +1 -1
  11. package/dist/bookmarks.d.ts +30 -0
  12. package/dist/bookmarks.d.ts.map +1 -0
  13. package/dist/bookmarks.js +87 -0
  14. package/dist/bookmarks.js.map +1 -0
  15. package/dist/cli.d.ts.map +1 -1
  16. package/dist/cli.js +291 -61
  17. package/dist/cli.js.map +1 -1
  18. package/dist/client.d.ts +115 -4
  19. package/dist/client.d.ts.map +1 -1
  20. package/dist/client.js +854 -138
  21. package/dist/client.js.map +1 -1
  22. package/dist/cursors.d.ts +30 -0
  23. package/dist/cursors.d.ts.map +1 -0
  24. package/dist/cursors.js +101 -0
  25. package/dist/cursors.js.map +1 -0
  26. package/dist/errors.d.ts +1 -1
  27. package/dist/errors.d.ts.map +1 -1
  28. package/dist/errors.js +2 -0
  29. package/dist/errors.js.map +1 -1
  30. package/dist/import.d.ts +605 -39
  31. package/dist/import.d.ts.map +1 -1
  32. package/dist/index.d.ts +19 -1
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +11 -1
  35. package/dist/index.js.map +1 -1
  36. package/dist/mcp/index.d.ts +1 -1
  37. package/dist/mcp/index.d.ts.map +1 -1
  38. package/dist/mcp/index.js +337 -30
  39. package/dist/mcp/index.js.map +1 -1
  40. package/dist/mutation-receipts.d.ts +8 -0
  41. package/dist/mutation-receipts.d.ts.map +1 -0
  42. package/dist/mutation-receipts.js +2 -0
  43. package/dist/mutation-receipts.js.map +1 -0
  44. package/dist/notifications.d.ts +73 -0
  45. package/dist/notifications.d.ts.map +1 -0
  46. package/dist/notifications.js +309 -0
  47. package/dist/notifications.js.map +1 -0
  48. package/dist/participation-repository.d.ts +46 -0
  49. package/dist/participation-repository.d.ts.map +1 -0
  50. package/dist/participation-repository.js +296 -0
  51. package/dist/participation-repository.js.map +1 -0
  52. package/dist/participation.d.ts +97 -0
  53. package/dist/participation.d.ts.map +1 -0
  54. package/dist/participation.js +10 -0
  55. package/dist/participation.js.map +1 -0
  56. package/dist/policy.d.ts +31 -0
  57. package/dist/policy.d.ts.map +1 -0
  58. package/dist/policy.js +71 -0
  59. package/dist/policy.js.map +1 -0
  60. package/dist/ports/repository.d.ts +23 -0
  61. package/dist/ports/repository.d.ts.map +1 -1
  62. package/dist/profiles.d.ts +12 -0
  63. package/dist/profiles.d.ts.map +1 -1
  64. package/dist/profiles.js +2 -1
  65. package/dist/profiles.js.map +1 -1
  66. package/dist/projections.d.ts.map +1 -1
  67. package/dist/projections.js +29 -11
  68. package/dist/projections.js.map +1 -1
  69. package/dist/remote.d.ts +79 -0
  70. package/dist/remote.d.ts.map +1 -1
  71. package/dist/remote.js +65 -6
  72. package/dist/remote.js.map +1 -1
  73. package/dist/schemas.d.ts +746 -58
  74. package/dist/schemas.d.ts.map +1 -1
  75. package/dist/schemas.js +114 -16
  76. package/dist/schemas.js.map +1 -1
  77. package/dist/search.d.ts +25 -0
  78. package/dist/search.d.ts.map +1 -0
  79. package/dist/search.js +2 -0
  80. package/dist/search.js.map +1 -0
  81. package/dist/service.d.ts +89 -0
  82. package/dist/service.d.ts.map +1 -1
  83. package/dist/storage.d.ts +38 -3
  84. package/dist/storage.d.ts.map +1 -1
  85. package/dist/storage.js +494 -367
  86. package/dist/storage.js.map +1 -1
  87. package/dist/types.d.ts +65 -34
  88. package/dist/types.d.ts.map +1 -1
  89. package/docs/cli.md +6 -0
  90. package/docs/human-participation.md +20 -0
  91. package/docs/mcp.md +3 -1
  92. package/docs/storage-format.md +4 -15
  93. package/openapi/synomem-v1.yaml +187 -10
  94. package/package.json +2 -1
  95. package/skills/synomem/SKILL.md +13 -13
  96. package/skills/synomem/agents/openai.yaml +1 -1
  97. package/skills/synomem/references/examples.md +2 -3
  98. package/src/actor-directory.ts +87 -0
  99. package/src/backend.ts +29 -3
  100. package/src/bookmarks.ts +127 -0
  101. package/src/cli.ts +941 -546
  102. package/src/client.ts +1143 -279
  103. package/src/cursors.ts +132 -0
  104. package/src/errors.ts +2 -0
  105. package/src/index.ts +50 -0
  106. package/src/mcp/index.ts +420 -104
  107. package/src/mutation-receipts.ts +7 -0
  108. package/src/notifications.ts +483 -0
  109. package/src/participation-repository.ts +406 -0
  110. package/src/participation.ts +103 -0
  111. package/src/policy.ts +109 -0
  112. package/src/ports/repository.ts +33 -0
  113. package/src/profiles.ts +2 -1
  114. package/src/projections.ts +49 -48
  115. package/src/remote.ts +227 -37
  116. package/src/schemas.ts +116 -16
  117. package/src/search.ts +24 -0
  118. package/src/service.ts +122 -8
  119. package/src/storage.ts +1039 -699
  120. package/src/types.ts +67 -32
package/CHANGELOG.md CHANGED
@@ -3,6 +3,22 @@
3
3
  All notable changes will be documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and releases follow Semantic Versioning.
5
5
 
6
+ ## [0.10.0] - 2026-09-29
7
+
8
+ - Human and agent references use explicit `{kind,id}` identities. Humans receive no administrative rights merely for being human; local stores bootstrap an owner and can register additional humans. Hosted access follows live organization/workspace membership and operator grants.
9
+ - Fresh local stores use SQLite schema 9 and version-2 canonical events. Populated older stores are export-only; there is no automatic conversion or legacy reply adapter. Take a raw export before creating a new store.
10
+ - Add branching replies, canonical typed mentions, follow/mute/read state, per-actor notifications, desired-state reactions, useful recognition, bookmarks, visibility-aware actor profiles and hosted search. Notes and todos stay private to their owners and authorized human overseers. Posts have workspace audience. Notification read state never performs memo, kudos or task actions.
11
+ - Version-check lifecycle and text changes independently, normalize mutation receipts for retry, and sign actor-bound cursors. Hosted reply/reaction budgets are durable and configurable by the API operator.
12
+ - Extend remote, CLI and stdio MCP operations for participation. Hosted clients require version-2 participation capability; local search is explicitly unsupported. Deleted reply bodies are hidden in normal reads; raw administrator recovery exports retain canonical history.
13
+ - On-behalf-of attribution is deferred. Interventions retain original authorship and append the intervening human's identity and reason.
14
+
15
+ ## 0.9.6
16
+
17
+ - Local stores: a human now sees agents' todos, as the hosted API already lets workspace owners and
18
+ admins. Todos and notes are hidden from other agents, not from the humans responsible for them.
19
+ - Skill, MCP and docs wording: notes and todos are "not visible to other agents" instead of
20
+ "private", and the dashboard caveat is gone.
21
+
6
22
  ## 0.9.5
7
23
 
8
24
  - MCP: tag fields no longer advertise the `\p{L}\p{N}` Unicode pattern in tool JSON Schemas.
package/README.md CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  # Synomem
4
4
 
5
- ### Shared Memory for Agents
5
+ #Human participation in 0.10.0 adds typed human/agent recipients, branching discussion, reactions, personal notifications, saved records and visibility-aware actor profiles. Local schema-9 stores are greenfield; populated older stores remain export-only. Hosted search and push are server/portal capabilities and do not add network listeners or credentials to the local package. See the [participation contract](docs/human-participation.md) and [storage upgrade boundary](docs/storage-format.md).
6
+
7
+ ## Shared Memory for Agents
6
8
 
7
9
  **Local-first · Multi-agent · Auditable · No account required**
8
10
 
@@ -31,7 +33,7 @@ Synomem gives humans and AI agents durable ways to coordinate beyond a disappear
31
33
  - **Notes** retain agent-owned, revisable knowledge.
32
34
  - **Posts** announce something to everyone in the workspace, and record who has acknowledged it.
33
35
  - **Tasks** delegate work to another agent, with their consent.
34
- - **Todos** track an agent's own actions, private to them, with optional date-only or
36
+ - **Todos** track an agent's own actions, not visible to other agents, with optional date-only or
35
37
  timezone-aware deadlines.
36
38
 
37
39
  ## Core philosophy
@@ -92,7 +94,7 @@ synomem task create codex --title "Review the migration" --due-date 2026-09-15
92
94
  synomem --profile codex inbox
93
95
  synomem --profile codex task accept <task-id> --response "Starting after the tests."
94
96
 
95
- # A todo is private to the agent that wrote it; nobody else can assign one.
97
+ # A todo is the agent's own reminder; other agents cannot see it or assign one.
96
98
  synomem --profile codex todo create --title "Re-read the migration notes"
97
99
 
98
100
  # A post is readable by everyone in the workspace, and tracks acknowledgement.
@@ -143,7 +145,7 @@ const client = new SynomemClient({
143
145
  await client.init();
144
146
 
145
147
  await client.memos.send({
146
- recipientAgentId: 'codex',
148
+ recipient: { kind: 'agent', id: 'codex' },
147
149
  subject: 'Review follow-up',
148
150
  body: 'Please recheck the migration after the tests pass.',
149
151
  idempotencyKey: 'gracie-codex-migration-follow-up',
@@ -162,12 +164,12 @@ await client.notes.revise({
162
164
 
163
165
  // A task is assigned to someone else and needs their consent.
164
166
  await client.tasks.create({
165
- assigneeAgentId: 'codex',
167
+ assignee: { kind: 'agent', id: 'codex' },
166
168
  title: 'Review the migration',
167
169
  due: { kind: 'date', date: '2026-09-15' },
168
170
  });
169
171
 
170
- // A todo is the agent's own reminder, visible to no one else.
172
+ // A todo is the agent's own reminder, not visible to other agents.
171
173
  await client.todos.create({
172
174
  title: 'Re-read the migration notes',
173
175
  due: { kind: 'date', date: '2026-09-14' },
@@ -254,7 +256,7 @@ regenerating it somewhere new and leaving your notes behind.
254
256
  SQLite events are canonical and append-only. Markdown and current-state tables are rebuildable
255
257
  projections — run `synomem rebuild` to regenerate them, and `synomem projection status` to see
256
258
  whether they currently match the events. Posts and todos project no files: a post belongs to the
257
- whole workspace rather than to one agent's directory, and a todo is private to its owner.
259
+ whole workspace rather than to one agent's directory, and a todo is not visible to other agents.
258
260
 
259
261
  `NOTES.md` is human-owned and is never overwritten; canonical agent notes project to `MEMORY.md`.
260
262
  Each projection can be turned off individually, in which case its file is not written at all.
@@ -0,0 +1,34 @@
1
+ import type { CursorBinding } from './cursors.js';
2
+ import type { AddressableActor, ActorRef } from './policy.js';
3
+ import type { ActorIdentity, ItemSummary, Page } from './types.js';
4
+ export interface ActorProfileInput {
5
+ target: ActorRef;
6
+ after?: string;
7
+ limit?: number;
8
+ }
9
+ export interface ActorProfile {
10
+ actor: AddressableActor;
11
+ counts: {
12
+ kudosReceived: number;
13
+ usefulReceived: number;
14
+ };
15
+ authored: Page<ItemSummary>;
16
+ }
17
+ export interface ActorDirectoryInput {
18
+ query?: string;
19
+ kind?: 'human' | 'agent';
20
+ cursor?: string;
21
+ limit?: number;
22
+ }
23
+ export interface ActorDirectoryPage {
24
+ items: AddressableActor[];
25
+ hasMore: boolean;
26
+ nextCursor?: string;
27
+ total: number;
28
+ limit: number;
29
+ }
30
+ export declare function actorDirectoryBinding(workspaceId: string, viewer: ActorIdentity, input: ActorDirectoryInput): CursorBinding;
31
+ export declare function actorDirectoryKey(actor: Pick<AddressableActor, 'kind' | 'handle' | 'id'>): string;
32
+ export declare function parseActorDirectoryKey(key: string): [string, string, string];
33
+ export declare function actorDirectoryInput(input?: ActorDirectoryInput): Required<Pick<ActorDirectoryInput, 'query' | 'limit'>> & Pick<ActorDirectoryInput, 'kind' | 'cursor'>;
34
+ //# sourceMappingURL=actor-directory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actor-directory.d.ts","sourceRoot":"","sources":["../src/actor-directory.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACnE,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AACD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,gBAAgB,CAAC;IACxB,MAAM,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1D,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;CAC7B;AACD,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AACD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AACD,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,mBAAmB,GACzB,aAAa,CAOf;AACD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,gBAAgB,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,MAAM,CAEjG;AACD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAiB5E;AACD,wBAAgB,mBAAmB,CACjC,KAAK,GAAE,mBAAwB,GAC9B,QAAQ,CAAC,IAAI,CAAC,mBAAmB,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,GACvD,IAAI,CAAC,mBAAmB,EAAE,MAAM,GAAG,QAAQ,CAAC,CAsB7C"}
@@ -0,0 +1,52 @@
1
+ import { SynomemError } from './errors.js';
2
+ import { cursorFilter } from './cursors.js';
3
+ export function actorDirectoryBinding(workspaceId, viewer, input) {
4
+ return {
5
+ purpose: 'actor-directory',
6
+ workspaceId,
7
+ actor: { kind: viewer.kind, id: viewer.id },
8
+ filter: cursorFilter({ query: (input.query ?? '').toLowerCase(), kind: input.kind ?? null }),
9
+ };
10
+ }
11
+ export function actorDirectoryKey(actor) {
12
+ return JSON.stringify([actor.kind, actor.handle, actor.id]);
13
+ }
14
+ export function parseActorDirectoryKey(key) {
15
+ try {
16
+ const parts = JSON.parse(key);
17
+ if (Array.isArray(parts) &&
18
+ parts.length === 3 &&
19
+ (parts[0] === 'human' || parts[0] === 'agent') &&
20
+ typeof parts[1] === 'string' &&
21
+ typeof parts[2] === 'string' &&
22
+ parts[1].length <= 100 &&
23
+ parts[2].length <= 200)
24
+ return parts;
25
+ }
26
+ catch {
27
+ // A signed cursor can still be stale or malformed after a codec change.
28
+ }
29
+ throw new SynomemError('INVALID_INPUT', 'Invalid actor directory cursor.');
30
+ }
31
+ export function actorDirectoryInput(input = {}) {
32
+ if (Object.keys(input).some((key) => !['query', 'kind', 'cursor', 'limit'].includes(key)) ||
33
+ (input.query !== undefined && typeof input.query !== 'string') ||
34
+ (input.kind !== undefined && !['human', 'agent'].includes(input.kind)) ||
35
+ (input.cursor !== undefined &&
36
+ (typeof input.cursor !== 'string' ||
37
+ input.cursor.length < 1 ||
38
+ input.cursor.length > 4096)) ||
39
+ (input.limit !== undefined &&
40
+ (!Number.isSafeInteger(input.limit) || input.limit < 1 || input.limit > 50)))
41
+ throw new SynomemError('INVALID_INPUT', 'Invalid actor directory query.');
42
+ const query = (input.query ?? '').trim();
43
+ if (query.length > 100)
44
+ throw new SynomemError('INVALID_INPUT', 'Actor query is limited to 100 characters.');
45
+ return {
46
+ query,
47
+ limit: input.limit ?? 20,
48
+ ...(input.kind ? { kind: input.kind } : {}),
49
+ ...(input.cursor ? { cursor: input.cursor } : {}),
50
+ };
51
+ }
52
+ //# sourceMappingURL=actor-directory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actor-directory.js","sourceRoot":"","sources":["../src/actor-directory.ts"],"names":[],"mappings":"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"}
package/dist/backend.d.ts CHANGED
@@ -18,4 +18,7 @@ export declare function ensureLocalStore(explicitHome?: string): SynomemConfig;
18
18
  export declare function localStoreWorkspaceId(explicitHome?: string): string;
19
19
  /** Opens (and initializes) a local store as one actor. The caller closes it. */
20
20
  export declare function openLocalService(home: string | undefined, actor: ActorIdentity): Promise<SynomemClient>;
21
+ export declare function openLocalOwnerService(home?: string): Promise<SynomemClient>;
22
+ /** Filesystem-owner recovery path: no migration, normalization or writes. */
23
+ export declare function exportRawLocalEvents(home?: string, format?: 'json' | 'jsonl'): string;
21
24
  //# sourceMappingURL=backend.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAS5C,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE/D;;;;GAIG;AACH,eAAO,MAAM,cAAc,EAAE,aAI5B,CAAC;AAOF,qEAAqE;AACrE,wBAAgB,iBAAiB,CAC/B,YAAY,CAAC,EAAE,MAAM,EACrB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,aAAa,GAAG,SAAS,CAe3B;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,aAAa,CAiBrE;AAED,+EAA+E;AAC/E,wBAAgB,qBAAqB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,gFAAgF;AAChF,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,KAAK,EAAE,aAAa,GACnB,OAAO,CAAC,aAAa,CAAC,CAKxB"}
1
+ {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAgBA,OAAO,EAA0B,aAAa,EAAE,MAAM,aAAa,CAAC;AASpE,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE/D;;;;GAIG;AACH,eAAO,MAAM,cAAc,EAAE,aAI5B,CAAC;AAOF,qEAAqE;AACrE,wBAAgB,iBAAiB,CAC/B,YAAY,CAAC,EAAE,MAAM,EACrB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,aAAa,GAAG,SAAS,CAe3B;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,aAAa,CAiBrE;AAED,+EAA+E;AAC/E,wBAAgB,qBAAqB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,gFAAgF;AAChF,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,KAAK,EAAE,aAAa,GACnB,OAAO,CAAC,aAAa,CAAC,CAKxB;AAED,wBAAsB,qBAAqB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAKjF;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,GAAG,OAAiB,GAAG,MAAM,CAe9F"}
package/dist/backend.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { DatabaseSync } from 'node:sqlite';
1
2
  /**
2
3
  * Local store helpers.
3
4
  *
@@ -13,7 +14,7 @@
13
14
  import { chmodSync, existsSync, lstatSync, mkdirSync } from 'node:fs';
14
15
  import { join } from 'node:path';
15
16
  import { ulid } from 'ulid';
16
- import { SynomemClient } from './client.js';
17
+ import { createLocalOwnerClient, SynomemClient } from './client.js';
17
18
  import { defaultConfig, mergeConfig, resolveHome } from './config.js';
18
19
  import { SynomemError } from './errors.js';
19
20
  import { assertNoSymlinkEscape, atomicWriteFile, ensureDirectory, readJsonFile, } from './fs-utils.js';
@@ -58,11 +59,11 @@ export function ensureLocalStore(explicitHome) {
58
59
  if (lstatSync(home).isSymbolicLink()) {
59
60
  throw new SynomemError('UNSAFE_PATH', 'The configured Synomem home cannot be a symbolic link.');
60
61
  }
61
- ensureDirectory(home);
62
- chmodSync(home, 0o700);
63
62
  const existing = readSynomemConfig(explicitHome, {});
64
63
  if (existing)
65
64
  return existing;
65
+ ensureDirectory(home);
66
+ chmodSync(home, 0o700);
66
67
  const config = mergeConfig({ ...defaultConfig, backend: { kind: 'local' }, workspaceId: ulid() }, undefined, {});
67
68
  atomicWriteFile(configPath, `${JSON.stringify(config, null, 2)}\n`);
68
69
  return config;
@@ -78,4 +79,26 @@ export async function openLocalService(home, actor) {
78
79
  await client.init();
79
80
  return client;
80
81
  }
82
+ export async function openLocalOwnerService(home) {
83
+ ensureLocalStore(home);
84
+ const client = createLocalOwnerClient({ ...(home ? { home } : {}), actor: LOCAL_OPERATOR });
85
+ await client.init();
86
+ return client;
87
+ }
88
+ /** Filesystem-owner recovery path: no migration, normalization or writes. */
89
+ export function exportRawLocalEvents(home, format = 'jsonl') {
90
+ const root = resolveHome(home);
91
+ const databasePath = join(root, 'synomem.sqlite3');
92
+ assertNoSymlinkEscape(root, databasePath);
93
+ const database = new DatabaseSync(databasePath, { readOnly: true });
94
+ try {
95
+ const rows = database.prepare('SELECT payload FROM events ORDER BY rowid').all();
96
+ return format === 'jsonl'
97
+ ? rows.map((row) => row.payload).join('\n') + (rows.length ? '\n' : '')
98
+ : `[${rows.map((row) => row.payload).join(',\n')}]\n`;
99
+ }
100
+ finally {
101
+ database.close();
102
+ }
103
+ }
81
104
  //# sourceMappingURL=backend.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"backend.js","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"backend.js","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { ActorIdentity, ItemSummary } from './types.js';
2
+ import type { ActorRef } from './policy.js';
3
+ import type { NotificationSql } from './notifications.js';
4
+ export interface BookmarkInput {
5
+ after?: string;
6
+ limit?: number;
7
+ }
8
+ export interface BookmarkPage {
9
+ items: Array<{
10
+ root: Pick<ItemSummary, 'id' | 'kind' | 'title'>;
11
+ savedAt: string;
12
+ }>;
13
+ hasMore: boolean;
14
+ nextCursor?: string;
15
+ watermark: string;
16
+ }
17
+ export interface BookmarkRepository {
18
+ set(rootId: string, actor: ActorRef, present: boolean): Promise<void>;
19
+ has(rootId: string, actor: ActorRef): Promise<boolean>;
20
+ list(input: BookmarkInput, actor: ActorIdentity): Promise<BookmarkPage>;
21
+ }
22
+ export declare const bookmarkTables = "\nCREATE TABLE bookmark_sequences(workspace_id TEXT PRIMARY KEY,last_sequence BIGINT NOT NULL);\nCREATE TABLE bookmarks(workspace_id TEXT NOT NULL,actor_kind TEXT NOT NULL,actor_id TEXT NOT NULL,root_id TEXT NOT NULL,saved_at TEXT NOT NULL,saved_sequence BIGINT NOT NULL,PRIMARY KEY(workspace_id,actor_kind,actor_id,root_id));\nCREATE INDEX bookmarks_actor_sequence ON bookmarks(workspace_id,actor_kind,actor_id,saved_sequence);\n";
23
+ export declare class SqlBookmarkRepository implements BookmarkRepository {
24
+ private readonly sql;
25
+ constructor(sql: NotificationSql);
26
+ has(rootId: string, actor: ActorRef): Promise<boolean>;
27
+ set(rootId: string, actor: ActorRef, present: boolean): Promise<void>;
28
+ list(input: BookmarkInput, actor: ActorIdentity): Promise<BookmarkPage>;
29
+ }
30
+ //# sourceMappingURL=bookmarks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bookmarks.d.ts","sourceRoot":"","sources":["../src/bookmarks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AACD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpF,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AACD,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CACzE;AACD,eAAO,MAAM,cAAc,mbAI1B,CAAC;AACF,qBAAa,qBAAsB,YAAW,kBAAkB;IAClD,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,EAAE,eAAe;IAC3C,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAUtD,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BrE,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;CA+D9E"}
@@ -0,0 +1,87 @@
1
+ import { cursorFilter } from './cursors.js';
2
+ export const bookmarkTables = `
3
+ CREATE TABLE bookmark_sequences(workspace_id TEXT PRIMARY KEY,last_sequence BIGINT NOT NULL);
4
+ CREATE TABLE bookmarks(workspace_id TEXT NOT NULL,actor_kind TEXT NOT NULL,actor_id TEXT NOT NULL,root_id TEXT NOT NULL,saved_at TEXT NOT NULL,saved_sequence BIGINT NOT NULL,PRIMARY KEY(workspace_id,actor_kind,actor_id,root_id));
5
+ CREATE INDEX bookmarks_actor_sequence ON bookmarks(workspace_id,actor_kind,actor_id,saved_sequence);
6
+ `;
7
+ export class SqlBookmarkRepository {
8
+ sql;
9
+ constructor(sql) {
10
+ this.sql = sql;
11
+ }
12
+ async has(rootId, actor) {
13
+ return ((await this.sql.query('SELECT 1 FROM bookmarks WHERE workspace_id=? AND actor_kind=? AND actor_id=? AND root_id=?', [this.sql.workspaceId, actor.kind, actor.id, rootId])).length > 0);
14
+ }
15
+ async set(rootId, actor, present) {
16
+ if (!present) {
17
+ await this.sql.execute('DELETE FROM bookmarks WHERE workspace_id=? AND actor_kind=? AND actor_id=? AND root_id=?', [this.sql.workspaceId, actor.kind, actor.id, rootId]);
18
+ return;
19
+ }
20
+ if (await this.has(rootId, actor))
21
+ return;
22
+ const counter = (await this.sql.query('INSERT INTO bookmark_sequences(workspace_id,last_sequence) VALUES(?,1) ON CONFLICT(workspace_id) DO UPDATE SET last_sequence=bookmark_sequences.last_sequence+1 RETURNING last_sequence', [this.sql.workspaceId]))[0];
23
+ await this.sql.execute('INSERT INTO bookmarks(workspace_id,actor_kind,actor_id,root_id,saved_at,saved_sequence) VALUES(?,?,?,?,?,?) ON CONFLICT(workspace_id,actor_kind,actor_id,root_id) DO NOTHING', [
24
+ this.sql.workspaceId,
25
+ actor.kind,
26
+ actor.id,
27
+ rootId,
28
+ new Date().toISOString(),
29
+ String(counter.last_sequence),
30
+ ]);
31
+ }
32
+ async list(input, actor) {
33
+ const maximum = String((await this.sql.query('SELECT COALESCE((SELECT last_sequence FROM bookmark_sequences WHERE workspace_id=?),0) AS max', [this.sql.workspaceId]))[0].max);
34
+ const binding = {
35
+ purpose: 'bookmarks',
36
+ workspaceId: this.sql.workspaceId,
37
+ actor,
38
+ filter: cursorFilter({}),
39
+ };
40
+ const codec = this.sql.codec();
41
+ const position = input.after ? codec.decode(input.after, binding, maximum) : undefined;
42
+ const high = position?.watermark ?? maximum;
43
+ const policy = this.sql.visibility(actor);
44
+ const limit = input.limit ?? 20;
45
+ const rows = await this.sql.query(`SELECT b.saved_sequence,b.saved_at,i.item_id,i.kind,i.title FROM bookmarks b JOIN items_current i ON i.workspace_id=b.workspace_id AND i.item_id=b.root_id WHERE b.workspace_id=? AND b.actor_kind=? AND b.actor_id=? AND b.saved_sequence>? AND b.saved_sequence<=? AND (${policy.sql}) ORDER BY b.saved_sequence LIMIT ?`, [
46
+ this.sql.workspaceId,
47
+ actor.kind,
48
+ actor.id,
49
+ position?.sequence ?? '0',
50
+ high,
51
+ ...policy.values,
52
+ limit + 1,
53
+ ]);
54
+ const items = [];
55
+ let bytes = 2048;
56
+ for (const row of rows.slice(0, limit)) {
57
+ const entry = {
58
+ root: {
59
+ id: String(row.item_id),
60
+ kind: String(row.kind),
61
+ title: String(row.title),
62
+ },
63
+ savedAt: String(row.saved_at),
64
+ };
65
+ const size = Buffer.byteLength(JSON.stringify(entry));
66
+ if (items.length && bytes + size > 24576)
67
+ break;
68
+ items.push(entry);
69
+ bytes += size;
70
+ }
71
+ const hasMore = rows.length > items.length;
72
+ return {
73
+ items,
74
+ hasMore,
75
+ ...(hasMore
76
+ ? {
77
+ nextCursor: codec.encode(binding, {
78
+ sequence: String(rows[items.length - 1].saved_sequence),
79
+ watermark: high,
80
+ }),
81
+ }
82
+ : {}),
83
+ watermark: codec.encode(binding, { sequence: high, watermark: high }),
84
+ };
85
+ }
86
+ }
87
+ //# sourceMappingURL=bookmarks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bookmarks.js","sourceRoot":"","sources":["../src/bookmarks.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAKA,OAAO,EAAE,OAAO,EAA0B,MAAM,WAAW,CAAC;AAU5D,OAAO,EAGL,KAAK,gBAAgB,EAErB,KAAK,qBAAqB,EAC3B,MAAM,kBAAkB,CAAC;AAI1B,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AAErB,OAAO,EAA6B,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,EASL,YAAY,EAQb,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAgC,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AA0BhF,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,eAAe;IAC9B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,gBAAgB,CAAC;IACtD,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,YAAY,CAAC;IAC9C,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC5E,oBAAoB,CAAC,EAAE,OAAO,oBAAoB,CAAC;IACnD,mBAAmB,CAAC,EAAE,OAAO,mBAAmB,CAAC;IACjD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,QAAQ,EAAE,eAAe,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAC7D,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE;QACvB,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,YAAY,CAAC;QACrB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,KAAK,OAAO,CAAC,aAAa,GAAG,YAAY,CAAC,CAAC;CAC7C;AAkOD,wBAAgB,SAAS,CAAC,EAAE,GAAE,KAAiB,EAAE,YAAY,GAAE,eAAoB,GAAG,OAAO,CAyxF5F;AA0BD,wBAAsB,MAAM,CAC1B,IAAI,WAAe,EACnB,EAAE,GAAE,KAAiB,EACrB,YAAY,GAAE,eAAoB,GACjC,OAAO,CAAC,MAAM,CAAC,CAgCjB"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAUA,OAAO,EAAE,OAAO,EAA0B,MAAM,WAAW,CAAC;AAU5D,OAAO,EAGL,KAAK,gBAAgB,EAErB,KAAK,qBAAqB,EAC3B,MAAM,kBAAkB,CAAC;AAI1B,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AAErB,OAAO,EAA6B,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,EASL,YAAY,EAQb,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAgC,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAyBhF,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AACD,MAAM,WAAW,eAAe;IAC9B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,gBAAgB,CAAC;IACtD,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,YAAY,CAAC;IAC9C,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC5E,oBAAoB,CAAC,EAAE,OAAO,oBAAoB,CAAC;IACnD,mBAAmB,CAAC,EAAE,OAAO,mBAAmB,CAAC;IACjD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,QAAQ,EAAE,eAAe,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAC7D,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE;QACvB,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,YAAY,CAAC;QACrB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,KAAK,OAAO,CAAC,aAAa,GAAG,YAAY,CAAC,CAAC;CAC7C;AAuND,wBAAgB,SAAS,CAAC,EAAE,GAAE,KAAiB,EAAE,YAAY,GAAE,eAAoB,GAAG,OAAO,CA+qG5F;AAwBD,wBAAsB,MAAM,CAC1B,IAAI,WAAe,EACnB,EAAE,GAAE,KAAiB,EACrB,YAAY,GAAE,eAAoB,GACjC,OAAO,CAAC,MAAM,CAAC,CAgCjB"}