agent-remnote 0.1.0 → 0.3.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 (99) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +47 -0
  3. package/dist/main.js +7969 -4691
  4. package/package.json +19 -4
  5. package/dist/apps/cli/src/adapters/mcp.js +0 -1
  6. package/dist/apps/cli/src/commands/_enqueue.js +0 -138
  7. package/dist/apps/cli/src/commands/_shared.js +0 -57
  8. package/dist/apps/cli/src/commands/_tool.js +0 -28
  9. package/dist/apps/cli/src/commands/apply.js +0 -81
  10. package/dist/apps/cli/src/commands/config/index.js +0 -3
  11. package/dist/apps/cli/src/commands/config/print.js +0 -28
  12. package/dist/apps/cli/src/commands/daily/index.js +0 -4
  13. package/dist/apps/cli/src/commands/daily/summary.js +0 -25
  14. package/dist/apps/cli/src/commands/daily/write.js +0 -145
  15. package/dist/apps/cli/src/commands/db/backups.js +0 -23
  16. package/dist/apps/cli/src/commands/db/index.js +0 -4
  17. package/dist/apps/cli/src/commands/db/recent.js +0 -178
  18. package/dist/apps/cli/src/commands/doctor.js +0 -124
  19. package/dist/apps/cli/src/commands/index.js +0 -73
  20. package/dist/apps/cli/src/commands/ops/index.js +0 -4
  21. package/dist/apps/cli/src/commands/ops/list.js +0 -12
  22. package/dist/apps/cli/src/commands/ops/schema.js +0 -77
  23. package/dist/apps/cli/src/commands/queue/enqueue.js +0 -73
  24. package/dist/apps/cli/src/commands/queue/index.js +0 -5
  25. package/dist/apps/cli/src/commands/queue/inspect.js +0 -26
  26. package/dist/apps/cli/src/commands/queue/stats.js +0 -14
  27. package/dist/apps/cli/src/commands/read/by-reference.js +0 -35
  28. package/dist/apps/cli/src/commands/read/connections.js +0 -15
  29. package/dist/apps/cli/src/commands/read/index.js +0 -21
  30. package/dist/apps/cli/src/commands/read/inspect.js +0 -34
  31. package/dist/apps/cli/src/commands/read/outline.js +0 -59
  32. package/dist/apps/cli/src/commands/read/query.js +0 -95
  33. package/dist/apps/cli/src/commands/read/references.js +0 -41
  34. package/dist/apps/cli/src/commands/read/resolve-ref.js +0 -32
  35. package/dist/apps/cli/src/commands/read/search.js +0 -40
  36. package/dist/apps/cli/src/commands/read/table.js +0 -32
  37. package/dist/apps/cli/src/commands/todos/index.js +0 -3
  38. package/dist/apps/cli/src/commands/todos/list.js +0 -33
  39. package/dist/apps/cli/src/commands/topic/index.js +0 -3
  40. package/dist/apps/cli/src/commands/topic/summary.js +0 -44
  41. package/dist/apps/cli/src/commands/wechat/index.js +0 -3
  42. package/dist/apps/cli/src/commands/wechat/outline.js +0 -430
  43. package/dist/apps/cli/src/commands/write/bullet.js +0 -76
  44. package/dist/apps/cli/src/commands/write/index.js +0 -4
  45. package/dist/apps/cli/src/commands/write/md.js +0 -91
  46. package/dist/apps/cli/src/commands/ws/_shared.js +0 -129
  47. package/dist/apps/cli/src/commands/ws/ensure.js +0 -22
  48. package/dist/apps/cli/src/commands/ws/health.js +0 -15
  49. package/dist/apps/cli/src/commands/ws/index.js +0 -21
  50. package/dist/apps/cli/src/commands/ws/logs.js +0 -95
  51. package/dist/apps/cli/src/commands/ws/restart.js +0 -73
  52. package/dist/apps/cli/src/commands/ws/serve.js +0 -52
  53. package/dist/apps/cli/src/commands/ws/start.js +0 -70
  54. package/dist/apps/cli/src/commands/ws/status.js +0 -60
  55. package/dist/apps/cli/src/commands/ws/stop.js +0 -59
  56. package/dist/apps/cli/src/commands/ws/trigger.js +0 -20
  57. package/dist/apps/cli/src/main.js +0 -79
  58. package/dist/apps/cli/src/services/AppConfig.js +0 -3
  59. package/dist/apps/cli/src/services/Config.js +0 -91
  60. package/dist/apps/cli/src/services/DaemonFiles.js +0 -91
  61. package/dist/apps/cli/src/services/Errors.js +0 -49
  62. package/dist/apps/cli/src/services/Output.js +0 -16
  63. package/dist/apps/cli/src/services/Payload.js +0 -90
  64. package/dist/apps/cli/src/services/Process.js +0 -94
  65. package/dist/apps/cli/src/services/Queue.js +0 -120
  66. package/dist/apps/cli/src/services/RefResolver.js +0 -111
  67. package/dist/apps/cli/src/services/RemDb.js +0 -35
  68. package/dist/apps/cli/src/services/WsClient.js +0 -170
  69. package/dist/apps/cli/tests/apply.contract.test.js +0 -31
  70. package/dist/apps/cli/tests/db-recent.contract.test.js +0 -22
  71. package/dist/apps/cli/tests/help.contract.test.js +0 -30
  72. package/dist/apps/cli/tests/helpers/runCli.js +0 -45
  73. package/dist/apps/cli/tests/ids-output.contract.test.js +0 -30
  74. package/dist/apps/cli/tests/payload-stdin.contract.test.js +0 -15
  75. package/dist/apps/cli/tests/read-search.contract.test.js +0 -22
  76. package/dist/apps/cli/tests/ws-health.contract.test.js +0 -36
  77. package/dist/apps/cli/vitest.config.js +0 -7
  78. package/dist/packages/mcp/src/public.js +0 -18
  79. package/dist/packages/mcp/src/queue/dao.js +0 -165
  80. package/dist/packages/mcp/src/queue/db.js +0 -26
  81. package/dist/packages/mcp/src/tools/executeSearchQuery.js +0 -914
  82. package/dist/packages/mcp/src/tools/findRemsByReference.js +0 -447
  83. package/dist/packages/mcp/src/tools/getRemConnections.js +0 -566
  84. package/dist/packages/mcp/src/tools/inspectRemDoc.js +0 -60
  85. package/dist/packages/mcp/src/tools/listRemBackups.js +0 -35
  86. package/dist/packages/mcp/src/tools/listRemReferences.js +0 -421
  87. package/dist/packages/mcp/src/tools/listSupportedOps.js +0 -41
  88. package/dist/packages/mcp/src/tools/listTodos.js +0 -815
  89. package/dist/packages/mcp/src/tools/outlineRemSubtree.js +0 -203
  90. package/dist/packages/mcp/src/tools/readRemTable.js +0 -252
  91. package/dist/packages/mcp/src/tools/resolveRemReference.js +0 -174
  92. package/dist/packages/mcp/src/tools/searchQueryTypes.js +0 -127
  93. package/dist/packages/mcp/src/tools/searchRemOverview.js +0 -422
  94. package/dist/packages/mcp/src/tools/searchUtils.js +0 -32
  95. package/dist/packages/mcp/src/tools/shared.js +0 -393
  96. package/dist/packages/mcp/src/tools/summarizeDailyNotes.js +0 -221
  97. package/dist/packages/mcp/src/tools/summarizeTopicActivity.js +0 -605
  98. package/dist/packages/mcp/src/tools/timeFilters.js +0 -130
  99. package/dist/packages/mcp/src/ws/bridge.js +0 -377
@@ -1,111 +0,0 @@
1
- import * as Context from 'effect/Context';
2
- import * as Effect from 'effect/Effect';
3
- import * as Layer from 'effect/Layer';
4
- import { executeSearchRemOverview } from '../adapters/mcp.js';
5
- import { AppConfig } from './AppConfig.js';
6
- import { CliError } from './Errors.js';
7
- export class RefResolver extends Context.Tag('RefResolver')() {
8
- }
9
- function stripQuotes(s) {
10
- const t = s.trim();
11
- if ((t.startsWith('"') && t.endsWith('"')) || (t.startsWith("'") && t.endsWith("'"))) {
12
- return t.slice(1, -1);
13
- }
14
- return t;
15
- }
16
- function parseRef(input) {
17
- const raw = input.trim();
18
- const idx = raw.indexOf(':');
19
- if (idx <= 0) {
20
- throw new CliError({
21
- code: 'INVALID_ARGS',
22
- message: `ref 不合法:${input}`,
23
- exitCode: 2,
24
- hint: ['示例:--ref id:xxx', '示例:--ref title:Demo', '示例:--ref daily:today', '示例:--ref daily:-1'],
25
- });
26
- }
27
- const kind = raw.slice(0, idx).trim();
28
- const value = stripQuotes(raw.slice(idx + 1));
29
- if (!value) {
30
- throw new CliError({
31
- code: 'INVALID_ARGS',
32
- message: `ref 不合法(缺少值):${input}`,
33
- exitCode: 2,
34
- });
35
- }
36
- if (kind === 'id' || kind === 'title' || kind === 'daily') {
37
- return { kind, value };
38
- }
39
- throw new CliError({
40
- code: 'INVALID_ARGS',
41
- message: `ref 不支持:${input}`,
42
- exitCode: 2,
43
- hint: ['支持:id:/title:/daily:'],
44
- });
45
- }
46
- function parseDailyOffset(value) {
47
- const v = value.trim().toLowerCase();
48
- if (v === 'today' || v === 'now' || v === '0')
49
- return 0;
50
- if (v === 'yesterday')
51
- return -1;
52
- if (v === 'tomorrow')
53
- return 1;
54
- const n = Number.parseInt(v, 10);
55
- if (!Number.isFinite(n)) {
56
- throw new CliError({
57
- code: 'INVALID_ARGS',
58
- message: `daily ref 不合法:${value}(需要 today/yesterday/tomorrow 或整数偏移)`,
59
- exitCode: 2,
60
- });
61
- }
62
- return n;
63
- }
64
- export const RefResolverLive = Layer.succeed(RefResolver, {
65
- resolve: (ref) => Effect.gen(function* () {
66
- const cfg = yield* AppConfig;
67
- const parsed = yield* Effect.try({
68
- try: () => parseRef(ref),
69
- catch: (e) => e && typeof e === 'object' && e._tag === 'CliError'
70
- ? e
71
- : new CliError({ code: 'INVALID_ARGS', message: `ref 不合法:${ref}`, exitCode: 2 }),
72
- });
73
- if (parsed.kind === 'id')
74
- return parsed.value;
75
- const dailyOffset = parsed.kind === 'daily'
76
- ? yield* Effect.try({
77
- try: () => parseDailyOffset(parsed.value),
78
- catch: (e) => e && typeof e === 'object' && e._tag === 'CliError'
79
- ? e
80
- : new CliError({ code: 'INVALID_ARGS', message: `daily ref 不合法:${parsed.value}`, exitCode: 2 }),
81
- })
82
- : undefined;
83
- const queryInput = parsed.kind === 'title'
84
- ? { query: parsed.value }
85
- : { query: 'date', useCurrentDate: true, dateOffsetDays: dailyOffset };
86
- const result = yield* Effect.tryPromise({
87
- try: async () => await executeSearchRemOverview({
88
- ...queryInput,
89
- dbPath: cfg.remnoteDb,
90
- limit: 1,
91
- preferExact: true,
92
- exactFirstSingle: true,
93
- }),
94
- catch: (e) => new CliError({
95
- code: 'DB_UNAVAILABLE',
96
- message: String(e?.message || e || 'RemNote DB 不可用'),
97
- exitCode: 1,
98
- }),
99
- });
100
- const first = Array.isArray(result.matches) ? result.matches[0] : undefined;
101
- const id = first?.id ? String(first.id) : '';
102
- if (!id) {
103
- return yield* Effect.fail(new CliError({
104
- code: 'INVALID_ARGS',
105
- message: `未找到 ref 对应的 Rem:${ref}`,
106
- exitCode: 2,
107
- }));
108
- }
109
- return id;
110
- }),
111
- });
@@ -1,35 +0,0 @@
1
- import * as Context from 'effect/Context';
2
- import * as Effect from 'effect/Effect';
3
- import * as Layer from 'effect/Layer';
4
- import { CliError, isCliError } from './Errors.js';
5
- import { discoverBackups, withResolvedDatabase } from '../adapters/mcp.js';
6
- export class RemDb extends Context.Tag('RemDb')() {
7
- }
8
- export const RemDbLive = Layer.succeed(RemDb, {
9
- withDb: (dbPath, fn) => Effect.tryPromise({
10
- try: async () => await withResolvedDatabase(dbPath, fn),
11
- catch: (error) => {
12
- if (isCliError(error))
13
- return error;
14
- return new CliError({
15
- code: 'DB_UNAVAILABLE',
16
- message: String(error?.message || error || 'RemNote DB 不可用'),
17
- exitCode: 1,
18
- details: { db_path: dbPath },
19
- });
20
- },
21
- }),
22
- backups: (basePath) => Effect.tryPromise({
23
- try: async () => await discoverBackups(basePath),
24
- catch: (error) => {
25
- if (isCliError(error))
26
- return error;
27
- return new CliError({
28
- code: 'DB_UNAVAILABLE',
29
- message: String(error?.message || error || '无法读取 RemNote 备份目录'),
30
- exitCode: 1,
31
- details: { base_path: basePath },
32
- });
33
- },
34
- }),
35
- });
@@ -1,170 +0,0 @@
1
- import * as Context from 'effect/Context';
2
- import * as Effect from 'effect/Effect';
3
- import * as Layer from 'effect/Layer';
4
- import WebSocket from 'ws';
5
- import { CliError } from './Errors.js';
6
- export class WsClient extends Context.Tag('WsClient')() {
7
- }
8
- function formatError(e) {
9
- if (!e)
10
- return 'unknown error';
11
- if (typeof e === 'string')
12
- return e;
13
- const anyErr = e;
14
- if (anyErr?.errors && Array.isArray(anyErr.errors)) {
15
- const parts = anyErr.errors
16
- .map((inner) => {
17
- const code = inner?.code ? String(inner.code) : '';
18
- const msg = inner?.message ? String(inner.message) : String(inner);
19
- return code ? `${code}: ${msg}` : msg;
20
- })
21
- .filter(Boolean);
22
- if (parts.length > 0)
23
- return `AggregateError(${parts.join('; ')})`;
24
- }
25
- if (typeof anyErr?.message === 'string')
26
- return anyErr.message;
27
- return String(e);
28
- }
29
- function connectOnce(params) {
30
- return new Promise((resolve, reject) => {
31
- const ws = new WebSocket(params.url);
32
- let done = false;
33
- const finishOk = () => {
34
- if (done)
35
- return;
36
- done = true;
37
- clearTimeout(timer);
38
- try {
39
- ws.terminate();
40
- }
41
- catch (_) { }
42
- resolve();
43
- };
44
- const finishErr = (error) => {
45
- if (done)
46
- return;
47
- done = true;
48
- clearTimeout(timer);
49
- try {
50
- ws.terminate();
51
- }
52
- catch (_) { }
53
- reject(error);
54
- };
55
- const timer = setTimeout(() => {
56
- finishErr(new Error(`timeout after ${params.timeoutMs}ms`));
57
- }, params.timeoutMs);
58
- ws.on('open', () => {
59
- try {
60
- params.onOpen(ws);
61
- }
62
- catch (e) {
63
- finishErr(e);
64
- }
65
- });
66
- ws.on('message', (data) => {
67
- try {
68
- const txt = String(data);
69
- const msg = JSON.parse(txt);
70
- params.onMessage(ws, msg);
71
- }
72
- catch (_) {
73
- // ignore non-json
74
- }
75
- });
76
- ws.on('error', (e) => {
77
- finishErr(e);
78
- });
79
- ws.on('close', () => {
80
- finishErr(new Error('connection closed'));
81
- });
82
- ws.__finishOk = finishOk;
83
- });
84
- }
85
- export const WsClientLive = Layer.succeed(WsClient, {
86
- health: ({ url, timeoutMs }) => Effect.tryPromise({
87
- try: async () => {
88
- const startedAt = Date.now();
89
- await connectOnce({
90
- url,
91
- timeoutMs,
92
- onOpen: (ws) => {
93
- ws.send(JSON.stringify({ type: 'Hello' }));
94
- },
95
- onMessage: (ws, msg) => {
96
- if (msg?.type === 'HelloAck' && msg?.ok === true) {
97
- ;
98
- ws.__finishOk?.();
99
- }
100
- },
101
- });
102
- return { url, rtt_ms: Date.now() - startedAt };
103
- },
104
- catch: (error) => {
105
- const message = formatError(error);
106
- return new CliError({
107
- code: message.includes('timeout after') ? 'WS_TIMEOUT' : 'WS_UNAVAILABLE',
108
- message,
109
- exitCode: 1,
110
- details: { url, timeout_ms: timeoutMs },
111
- });
112
- },
113
- }),
114
- triggerStartSync: ({ url, timeoutMs, consumerId }) => Effect.tryPromise({
115
- try: async () => {
116
- let result;
117
- await connectOnce({
118
- url,
119
- timeoutMs,
120
- onOpen: (ws) => {
121
- ws.send(JSON.stringify({ type: 'TriggerStartSync', consumerId }));
122
- },
123
- onMessage: (ws, msg) => {
124
- if (msg?.type === 'StartSyncTriggered') {
125
- result = { sent: typeof msg?.sent === 'number' ? msg.sent : 0 };
126
- ws.__finishOk?.();
127
- }
128
- },
129
- });
130
- return result ?? { sent: 0 };
131
- },
132
- catch: (error) => {
133
- const message = formatError(error);
134
- return new CliError({
135
- code: message.includes('timeout after') ? 'WS_TIMEOUT' : 'WS_UNAVAILABLE',
136
- message,
137
- exitCode: 1,
138
- details: { url, timeout_ms: timeoutMs, consumer_id: consumerId },
139
- });
140
- },
141
- }),
142
- queryClients: ({ url, timeoutMs }) => Effect.tryPromise({
143
- try: async () => {
144
- let result;
145
- await connectOnce({
146
- url,
147
- timeoutMs,
148
- onOpen: (ws) => {
149
- ws.send(JSON.stringify({ type: 'QueryClients' }));
150
- },
151
- onMessage: (ws, msg) => {
152
- if (msg?.type === 'Clients' && Array.isArray(msg?.clients)) {
153
- result = { clients: msg.clients };
154
- ws.__finishOk?.();
155
- }
156
- },
157
- });
158
- return result ?? { clients: [] };
159
- },
160
- catch: (error) => {
161
- const message = formatError(error);
162
- return new CliError({
163
- code: message.includes('timeout after') ? 'WS_TIMEOUT' : 'WS_UNAVAILABLE',
164
- message,
165
- exitCode: 1,
166
- details: { url, timeout_ms: timeoutMs },
167
- });
168
- },
169
- }),
170
- });
@@ -1,31 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { runCli } from './helpers/runCli.js';
3
- describe('cli contract: apply --dry-run --json', () => {
4
- it('prints ok envelope and does not require queue db', async () => {
5
- const payload = '[{"type":"create_rem","payload":{"fooBar":1}}]';
6
- const res = await runCli(['--json', 'apply', '--dry-run', '--payload', payload]);
7
- expect(res.exitCode).toBe(0);
8
- expect(res.stderr).toBe('');
9
- const parsed = JSON.parse(res.stdout.trim());
10
- expect(parsed.ok).toBe(true);
11
- expect(parsed.data.dry_run).toBe(true);
12
- expect(Array.isArray(parsed.data.ops)).toBe(true);
13
- expect(parsed.data.ops[0].type).toBe('create_rem');
14
- expect(parsed.data.ops[0].payload.foo_bar).toBe(1);
15
- });
16
- it('accepts object payload with meta (and normalizes keys)', async () => {
17
- const payload = JSON.stringify({
18
- ops: [{ type: 'create_rem', payload: { fooBar: 1 } }],
19
- meta: { traceId: 't1', fooBar: 2 },
20
- clientId: 'test-client',
21
- });
22
- const res = await runCli(['--json', 'apply', '--dry-run', '--payload', payload]);
23
- expect(res.exitCode).toBe(0);
24
- expect(res.stderr).toBe('');
25
- const parsed = JSON.parse(res.stdout.trim());
26
- expect(parsed.ok).toBe(true);
27
- expect(parsed.data.dry_run).toBe(true);
28
- expect(parsed.data.meta.trace_id).toBe('t1');
29
- expect(parsed.data.meta.foo_bar).toBe(2);
30
- });
31
- });
@@ -1,22 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import os from 'node:os';
3
- import path from 'node:path';
4
- import { promises as fs } from 'node:fs';
5
- import { runCli } from './helpers/runCli.js';
6
- describe('cli contract: db recent --json', () => {
7
- it('prints a single json envelope and keeps stderr empty on db error', async () => {
8
- const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'remnote-cli-test-'));
9
- const missingDb = path.join(tmpDir, 'missing-remnote.db');
10
- try {
11
- const res = await runCli(['--json', '--remnote-db', missingDb, 'db', 'recent']);
12
- expect(res.exitCode).toBe(1);
13
- expect(res.stderr).toBe('');
14
- const parsed = JSON.parse(res.stdout.trim());
15
- expect(parsed.ok).toBe(false);
16
- expect(parsed.error.code).toBe('DB_UNAVAILABLE');
17
- }
18
- finally {
19
- await fs.rm(tmpDir, { recursive: true, force: true });
20
- }
21
- });
22
- });
@@ -1,30 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { runCli } from './helpers/runCli.js';
3
- function stripAnsi(input) {
4
- return input.replace(/\u001b\[[0-9;]*m/g, '');
5
- }
6
- describe('cli contract: --help', () => {
7
- it('prints root help with subcommands', async () => {
8
- const res = await runCli(['--help']);
9
- expect(res.exitCode).toBe(0);
10
- expect(res.stderr).toBe('');
11
- const out = stripAnsi(res.stdout);
12
- expect(out).toContain('remnote');
13
- expect(out).toContain('ws');
14
- expect(out).toContain('queue');
15
- expect(out).toContain('apply');
16
- expect(out).toContain('read');
17
- expect(out).toContain('write');
18
- expect(out).toContain('wechat');
19
- });
20
- it('prints ws help with subcommands', async () => {
21
- const res = await runCli(['ws', '--help']);
22
- expect(res.exitCode).toBe(0);
23
- expect(res.stderr).toBe('');
24
- const out = stripAnsi(res.stdout);
25
- expect(out).toContain('health');
26
- expect(out).toContain('start');
27
- expect(out).toContain('stop');
28
- expect(out).toContain('status');
29
- });
30
- });
@@ -1,45 +0,0 @@
1
- import { spawn } from 'node:child_process';
2
- import path from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
- export async function runCli(args, options) {
5
- const __filename = fileURLToPath(import.meta.url);
6
- const __dirname = path.dirname(__filename);
7
- const repoRoot = path.resolve(__dirname, '../../../../');
8
- const entry = path.join(repoRoot, 'apps/cli/src/main.ts');
9
- const timeoutMs = options?.timeoutMs ?? 30_000;
10
- return await new Promise((resolve) => {
11
- const child = spawn('bun', ['x', 'tsx', entry, ...args], {
12
- cwd: repoRoot,
13
- env: { ...process.env, ...(options?.env ?? {}) },
14
- stdio: 'pipe',
15
- });
16
- let stdout = '';
17
- let stderr = '';
18
- child.stdout.setEncoding('utf8');
19
- child.stderr.setEncoding('utf8');
20
- child.stdout.on('data', (d) => {
21
- stdout += d;
22
- });
23
- child.stderr.on('data', (d) => {
24
- stderr += d;
25
- });
26
- if (options?.stdin !== undefined) {
27
- child.stdin.setDefaultEncoding('utf8');
28
- child.stdin.write(options.stdin);
29
- child.stdin.end();
30
- }
31
- else {
32
- child.stdin.end();
33
- }
34
- const timer = setTimeout(() => {
35
- try {
36
- child.kill('SIGKILL');
37
- }
38
- catch (_) { }
39
- }, timeoutMs);
40
- child.on('close', (code) => {
41
- clearTimeout(timer);
42
- resolve({ exitCode: typeof code === 'number' ? code : 1, stdout, stderr });
43
- });
44
- });
45
- }
@@ -1,30 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import os from 'node:os';
3
- import path from 'node:path';
4
- import { promises as fs } from 'node:fs';
5
- import { runCli } from './helpers/runCli.js';
6
- describe('cli contract: --ids output', () => {
7
- it('prints ids one per line', async () => {
8
- const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'remnote-cli-test-'));
9
- const tmpHome = path.join(tmpDir, 'home');
10
- const queueDb = path.join(tmpDir, 'queue.sqlite');
11
- try {
12
- const payload = '[{"type":"create_rem","payload":{"text":"hello"}}]';
13
- const res = await runCli(['--ids', 'apply', '--payload', payload], {
14
- env: { HOME: tmpHome, REMNOTE_QUEUE_DB: queueDb },
15
- });
16
- expect(res.exitCode).toBe(0);
17
- expect(res.stderr).toBe('');
18
- const lines = res.stdout
19
- .split(/\r?\n/)
20
- .map((l) => l.trim())
21
- .filter(Boolean);
22
- expect(lines.length).toBe(2);
23
- expect(lines[0].length).toBeGreaterThan(10);
24
- expect(lines[1].length).toBeGreaterThan(10);
25
- }
26
- finally {
27
- await fs.rm(tmpDir, { recursive: true, force: true });
28
- }
29
- });
30
- });
@@ -1,15 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { runCli } from './helpers/runCli.js';
3
- describe('cli contract: --payload - stdin', () => {
4
- it('reads payload from stdin in dry-run mode', async () => {
5
- const stdin = '[{"type":"create_rem","payload":{"fooBar":1}}]';
6
- const res = await runCli(['--json', 'apply', '--dry-run', '--payload', '-'], { stdin });
7
- expect(res.exitCode).toBe(0);
8
- expect(res.stderr).toBe('');
9
- const parsed = JSON.parse(res.stdout.trim());
10
- expect(parsed.ok).toBe(true);
11
- expect(parsed.data.dry_run).toBe(true);
12
- expect(parsed.data.ops[0].type).toBe('create_rem');
13
- expect(parsed.data.ops[0].payload.foo_bar).toBe(1);
14
- });
15
- });
@@ -1,22 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import os from 'node:os';
3
- import path from 'node:path';
4
- import { promises as fs } from 'node:fs';
5
- import { runCli } from './helpers/runCli.js';
6
- describe('cli contract: read search --json', () => {
7
- it('prints a single json envelope and keeps stderr empty on db error', async () => {
8
- const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'remnote-cli-test-'));
9
- const missingDb = path.join(tmpDir, 'missing-remnote.db');
10
- try {
11
- const res = await runCli(['--json', '--remnote-db', missingDb, 'read', 'search', '--query', 'hello']);
12
- expect(res.exitCode).toBe(1);
13
- expect(res.stderr).toBe('');
14
- const parsed = JSON.parse(res.stdout.trim());
15
- expect(parsed.ok).toBe(false);
16
- expect(parsed.error.code).toBe('DB_UNAVAILABLE');
17
- }
18
- finally {
19
- await fs.rm(tmpDir, { recursive: true, force: true });
20
- }
21
- });
22
- });
@@ -1,36 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import os from 'node:os';
3
- import path from 'node:path';
4
- import { promises as fs } from 'node:fs';
5
- import { startWebSocketBridge } from '../../../packages/mcp/src/ws/bridge.js';
6
- import { runCli } from './helpers/runCli.js';
7
- describe('cli contract: ws health --json', () => {
8
- it('prints ok envelope and health data', async () => {
9
- const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'remnote-cli-test-'));
10
- const queueDb = path.join(tmpDir, 'queue.sqlite');
11
- const prevQueueDb = process.env.REMNOTE_QUEUE_DB;
12
- process.env.REMNOTE_QUEUE_DB = queueDb;
13
- const started = startWebSocketBridge({ enable: true, port: 0, path: '/ws' });
14
- expect(started).toBeTruthy();
15
- try {
16
- const addr = started.wss.address();
17
- const port = typeof addr === 'string' ? Number(addr) : addr.port;
18
- const wsUrl = `ws://localhost:${port}/ws`;
19
- const res = await runCli(['--json', '--ws-url', wsUrl, 'ws', 'health']);
20
- expect(res.exitCode).toBe(0);
21
- expect(res.stderr).toBe('');
22
- const parsed = JSON.parse(res.stdout.trim());
23
- expect(parsed.ok).toBe(true);
24
- expect(parsed.data.url).toBe(wsUrl);
25
- expect(typeof parsed.data.rtt_ms).toBe('number');
26
- }
27
- finally {
28
- await started.close();
29
- if (prevQueueDb === undefined)
30
- delete process.env.REMNOTE_QUEUE_DB;
31
- else
32
- process.env.REMNOTE_QUEUE_DB = prevQueueDb;
33
- await fs.rm(tmpDir, { recursive: true, force: true });
34
- }
35
- });
36
- });
@@ -1,7 +0,0 @@
1
- import { defineConfig } from 'vitest/config';
2
- export default defineConfig({
3
- test: {
4
- environment: 'node',
5
- include: ['tests/**/*.test.ts'],
6
- },
7
- });
@@ -1,18 +0,0 @@
1
- export { startWebSocketBridge } from './ws/bridge.js';
2
- export { openQueueDb } from './queue/db.js';
3
- export { enqueueTxn, getTxnIdByOpId, queueStats } from './queue/dao.js';
4
- export { discoverBackups, formatDateWithPattern, getDateFormatting, withResolvedDatabase } from './tools/shared.js';
5
- export { TYPES } from './tools/listSupportedOps.js';
6
- export { executeListRemBackups } from './tools/listRemBackups.js';
7
- export { executeSummarizeTopicActivity } from './tools/summarizeTopicActivity.js';
8
- export { executeListRemReferences } from './tools/listRemReferences.js';
9
- export { executeSummarizeDailyNotes } from './tools/summarizeDailyNotes.js';
10
- export { executeSearchRemOverview } from './tools/searchRemOverview.js';
11
- export { executeInspectRemDoc } from './tools/inspectRemDoc.js';
12
- export { executeOutlineRemSubtree } from './tools/outlineRemSubtree.js';
13
- export { executeReadRemTable } from './tools/readRemTable.js';
14
- export { executeFindRemsByReference } from './tools/findRemsByReference.js';
15
- export { executeGetRemConnections } from './tools/getRemConnections.js';
16
- export { executeListTodos } from './tools/listTodos.js';
17
- export { executeResolveRemReference } from './tools/resolveRemReference.js';
18
- export { executeSearchQuery } from './tools/executeSearchQuery.js';