agent-remnote 0.0.1 → 0.1.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/cli.js +2 -0
- package/dist/apps/cli/src/adapters/mcp.js +1 -0
- package/dist/apps/cli/src/commands/_enqueue.js +138 -0
- package/dist/apps/cli/src/commands/_shared.js +57 -0
- package/dist/apps/cli/src/commands/_tool.js +28 -0
- package/dist/apps/cli/src/commands/apply.js +81 -0
- package/dist/apps/cli/src/commands/config/index.js +3 -0
- package/dist/apps/cli/src/commands/config/print.js +28 -0
- package/dist/apps/cli/src/commands/daily/index.js +4 -0
- package/dist/apps/cli/src/commands/daily/summary.js +25 -0
- package/dist/apps/cli/src/commands/daily/write.js +145 -0
- package/dist/apps/cli/src/commands/db/backups.js +23 -0
- package/dist/apps/cli/src/commands/db/index.js +4 -0
- package/dist/apps/cli/src/commands/db/recent.js +178 -0
- package/dist/apps/cli/src/commands/doctor.js +124 -0
- package/dist/apps/cli/src/commands/index.js +73 -0
- package/dist/apps/cli/src/commands/ops/index.js +4 -0
- package/dist/apps/cli/src/commands/ops/list.js +12 -0
- package/dist/apps/cli/src/commands/ops/schema.js +77 -0
- package/dist/apps/cli/src/commands/queue/enqueue.js +73 -0
- package/dist/apps/cli/src/commands/queue/index.js +5 -0
- package/dist/apps/cli/src/commands/queue/inspect.js +26 -0
- package/dist/apps/cli/src/commands/queue/stats.js +14 -0
- package/dist/apps/cli/src/commands/read/by-reference.js +35 -0
- package/dist/apps/cli/src/commands/read/connections.js +15 -0
- package/dist/apps/cli/src/commands/read/index.js +21 -0
- package/dist/apps/cli/src/commands/read/inspect.js +34 -0
- package/dist/apps/cli/src/commands/read/outline.js +59 -0
- package/dist/apps/cli/src/commands/read/query.js +95 -0
- package/dist/apps/cli/src/commands/read/references.js +41 -0
- package/dist/apps/cli/src/commands/read/resolve-ref.js +32 -0
- package/dist/apps/cli/src/commands/read/search.js +40 -0
- package/dist/apps/cli/src/commands/read/table.js +32 -0
- package/dist/apps/cli/src/commands/todos/index.js +3 -0
- package/dist/apps/cli/src/commands/todos/list.js +33 -0
- package/dist/apps/cli/src/commands/topic/index.js +3 -0
- package/dist/apps/cli/src/commands/topic/summary.js +44 -0
- package/dist/apps/cli/src/commands/wechat/index.js +3 -0
- package/dist/apps/cli/src/commands/wechat/outline.js +430 -0
- package/dist/apps/cli/src/commands/write/bullet.js +76 -0
- package/dist/apps/cli/src/commands/write/index.js +4 -0
- package/dist/apps/cli/src/commands/write/md.js +91 -0
- package/dist/apps/cli/src/commands/ws/_shared.js +129 -0
- package/dist/apps/cli/src/commands/ws/ensure.js +22 -0
- package/dist/apps/cli/src/commands/ws/health.js +15 -0
- package/dist/apps/cli/src/commands/ws/index.js +21 -0
- package/dist/apps/cli/src/commands/ws/logs.js +95 -0
- package/dist/apps/cli/src/commands/ws/restart.js +73 -0
- package/dist/apps/cli/src/commands/ws/serve.js +52 -0
- package/dist/apps/cli/src/commands/ws/start.js +70 -0
- package/dist/apps/cli/src/commands/ws/status.js +60 -0
- package/dist/apps/cli/src/commands/ws/stop.js +59 -0
- package/dist/apps/cli/src/commands/ws/trigger.js +20 -0
- package/dist/apps/cli/src/main.js +79 -0
- package/dist/apps/cli/src/services/AppConfig.js +3 -0
- package/dist/apps/cli/src/services/Config.js +91 -0
- package/dist/apps/cli/src/services/DaemonFiles.js +91 -0
- package/dist/apps/cli/src/services/Errors.js +49 -0
- package/dist/apps/cli/src/services/Output.js +16 -0
- package/dist/apps/cli/src/services/Payload.js +90 -0
- package/dist/apps/cli/src/services/Process.js +94 -0
- package/dist/apps/cli/src/services/Queue.js +120 -0
- package/dist/apps/cli/src/services/RefResolver.js +111 -0
- package/dist/apps/cli/src/services/RemDb.js +35 -0
- package/dist/apps/cli/src/services/WsClient.js +170 -0
- package/dist/apps/cli/tests/apply.contract.test.js +31 -0
- package/dist/apps/cli/tests/db-recent.contract.test.js +22 -0
- package/dist/apps/cli/tests/help.contract.test.js +30 -0
- package/dist/apps/cli/tests/helpers/runCli.js +45 -0
- package/dist/apps/cli/tests/ids-output.contract.test.js +30 -0
- package/dist/apps/cli/tests/payload-stdin.contract.test.js +15 -0
- package/dist/apps/cli/tests/read-search.contract.test.js +22 -0
- package/dist/apps/cli/tests/ws-health.contract.test.js +36 -0
- package/dist/apps/cli/vitest.config.js +7 -0
- package/dist/main.js +101037 -0
- package/dist/packages/mcp/src/public.js +18 -0
- package/dist/packages/mcp/src/queue/dao.js +165 -0
- package/dist/packages/mcp/src/queue/db.js +26 -0
- package/dist/packages/mcp/src/tools/executeSearchQuery.js +914 -0
- package/dist/packages/mcp/src/tools/findRemsByReference.js +447 -0
- package/dist/packages/mcp/src/tools/getRemConnections.js +566 -0
- package/dist/packages/mcp/src/tools/inspectRemDoc.js +60 -0
- package/dist/packages/mcp/src/tools/listRemBackups.js +35 -0
- package/dist/packages/mcp/src/tools/listRemReferences.js +421 -0
- package/dist/packages/mcp/src/tools/listSupportedOps.js +41 -0
- package/dist/packages/mcp/src/tools/listTodos.js +815 -0
- package/dist/packages/mcp/src/tools/outlineRemSubtree.js +203 -0
- package/dist/packages/mcp/src/tools/readRemTable.js +252 -0
- package/dist/packages/mcp/src/tools/resolveRemReference.js +174 -0
- package/dist/packages/mcp/src/tools/searchQueryTypes.js +127 -0
- package/dist/packages/mcp/src/tools/searchRemOverview.js +422 -0
- package/dist/packages/mcp/src/tools/searchUtils.js +32 -0
- package/dist/packages/mcp/src/tools/shared.js +393 -0
- package/dist/packages/mcp/src/tools/summarizeDailyNotes.js +221 -0
- package/dist/packages/mcp/src/tools/summarizeTopicActivity.js +605 -0
- package/dist/packages/mcp/src/tools/timeFilters.js +130 -0
- package/dist/packages/mcp/src/ws/bridge.js +377 -0
- package/package.json +40 -8
- package/README.md +0 -3
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -5
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Command } from '@effect/cli';
|
|
2
|
+
import { readByReferenceCommand } from './by-reference.js';
|
|
3
|
+
import { readConnectionsCommand } from './connections.js';
|
|
4
|
+
import { readInspectCommand } from './inspect.js';
|
|
5
|
+
import { readOutlineCommand } from './outline.js';
|
|
6
|
+
import { readQueryCommand } from './query.js';
|
|
7
|
+
import { readReferencesCommand } from './references.js';
|
|
8
|
+
import { readResolveRefCommand } from './resolve-ref.js';
|
|
9
|
+
import { readSearchCommand } from './search.js';
|
|
10
|
+
import { readTableCommand } from './table.js';
|
|
11
|
+
export const readCommand = Command.make('read', {}).pipe(Command.withSubcommands([
|
|
12
|
+
readSearchCommand,
|
|
13
|
+
readQueryCommand,
|
|
14
|
+
readOutlineCommand,
|
|
15
|
+
readInspectCommand,
|
|
16
|
+
readResolveRefCommand,
|
|
17
|
+
readConnectionsCommand,
|
|
18
|
+
readReferencesCommand,
|
|
19
|
+
readByReferenceCommand,
|
|
20
|
+
readTableCommand,
|
|
21
|
+
]));
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Command } from '@effect/cli';
|
|
2
|
+
import * as Options from '@effect/cli/Options';
|
|
3
|
+
import * as Effect from 'effect/Effect';
|
|
4
|
+
import * as Option from 'effect/Option';
|
|
5
|
+
import { executeInspectRemDoc } from '../../adapters/mcp.js';
|
|
6
|
+
import { AppConfig } from '../../services/AppConfig.js';
|
|
7
|
+
import { writeFailure, writeSuccess } from '../_shared.js';
|
|
8
|
+
import { cliErrorFromUnknown } from '../_tool.js';
|
|
9
|
+
function optionToUndefined(opt) {
|
|
10
|
+
return Option.isSome(opt) ? opt.value : undefined;
|
|
11
|
+
}
|
|
12
|
+
const maxReferenceDepth = Options.integer('max-reference-depth').pipe(Options.optional, Options.map(optionToUndefined));
|
|
13
|
+
export const readInspectCommand = Command.make('inspect', {
|
|
14
|
+
id: Options.text('id'),
|
|
15
|
+
expandReferences: Options.boolean('expand-references'),
|
|
16
|
+
maxReferenceDepth,
|
|
17
|
+
}, ({ id, expandReferences, maxReferenceDepth }) => Effect.gen(function* () {
|
|
18
|
+
const cfg = yield* AppConfig;
|
|
19
|
+
const result = yield* Effect.tryPromise({
|
|
20
|
+
try: async () => await executeInspectRemDoc({
|
|
21
|
+
id,
|
|
22
|
+
dbPath: cfg.remnoteDb,
|
|
23
|
+
expandReferences,
|
|
24
|
+
maxReferenceDepth: maxReferenceDepth,
|
|
25
|
+
}),
|
|
26
|
+
catch: (e) => cliErrorFromUnknown(e, { code: 'DB_UNAVAILABLE' }),
|
|
27
|
+
});
|
|
28
|
+
const summaryText = result?.summary?.text ? String(result.summary.text) : '';
|
|
29
|
+
const refs = Array.isArray(result?.summary?.references) ? result.summary.references.length : 0;
|
|
30
|
+
const md = [`- id: ${String(result.id ?? id)}`, summaryText ? `- text: ${summaryText}` : '', `- references: ${refs}`]
|
|
31
|
+
.filter(Boolean)
|
|
32
|
+
.join('\n');
|
|
33
|
+
yield* writeSuccess({ data: result, md });
|
|
34
|
+
}).pipe(Effect.catchAll(writeFailure)));
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Command } from '@effect/cli';
|
|
2
|
+
import * as Options from '@effect/cli/Options';
|
|
3
|
+
import * as Effect from 'effect/Effect';
|
|
4
|
+
import * as Option from 'effect/Option';
|
|
5
|
+
import { executeOutlineRemSubtree } from '../../adapters/mcp.js';
|
|
6
|
+
import { AppConfig } from '../../services/AppConfig.js';
|
|
7
|
+
import { RefResolver } from '../../services/RefResolver.js';
|
|
8
|
+
import { CliError } from '../../services/Errors.js';
|
|
9
|
+
import { writeFailure, writeSuccess } from '../_shared.js';
|
|
10
|
+
import { cliErrorFromUnknown } from '../_tool.js';
|
|
11
|
+
function optionToUndefined(opt) {
|
|
12
|
+
return Option.isSome(opt) ? opt.value : undefined;
|
|
13
|
+
}
|
|
14
|
+
const depth = Options.integer('depth').pipe(Options.optional, Options.map(optionToUndefined));
|
|
15
|
+
const offset = Options.integer('offset').pipe(Options.optional, Options.map(optionToUndefined));
|
|
16
|
+
const nodes = Options.integer('nodes').pipe(Options.optional, Options.map(optionToUndefined));
|
|
17
|
+
const format = Options.choice('format', ['md', 'json']).pipe(Options.optional, Options.map(optionToUndefined));
|
|
18
|
+
const id = Options.text('id').pipe(Options.optional, Options.map(optionToUndefined));
|
|
19
|
+
const ref = Options.text('ref').pipe(Options.optional, Options.map(optionToUndefined));
|
|
20
|
+
export const readOutlineCommand = Command.make('outline', {
|
|
21
|
+
id,
|
|
22
|
+
ref,
|
|
23
|
+
depth,
|
|
24
|
+
offset,
|
|
25
|
+
nodes,
|
|
26
|
+
format,
|
|
27
|
+
excludeProperties: Options.boolean('exclude-properties'),
|
|
28
|
+
includeEmpty: Options.boolean('include-empty'),
|
|
29
|
+
expandReferences: Options.boolean('expand-references'),
|
|
30
|
+
maxReferenceDepth: Options.integer('max-reference-depth').pipe(Options.optional, Options.map(optionToUndefined)),
|
|
31
|
+
detail: Options.boolean('detail'),
|
|
32
|
+
}, ({ id, ref, depth, offset, nodes, format, excludeProperties, includeEmpty, expandReferences, maxReferenceDepth, detail }) => Effect.gen(function* () {
|
|
33
|
+
const cfg = yield* AppConfig;
|
|
34
|
+
const refs = yield* RefResolver;
|
|
35
|
+
if (id && ref) {
|
|
36
|
+
return yield* Effect.fail(new CliError({ code: 'INVALID_ARGS', message: '--id 与 --ref 只能二选一', exitCode: 2 }));
|
|
37
|
+
}
|
|
38
|
+
const resolvedId = ref ? yield* refs.resolve(ref) : id;
|
|
39
|
+
if (!resolvedId) {
|
|
40
|
+
return yield* Effect.fail(new CliError({ code: 'INVALID_ARGS', message: '必须提供 --id 或 --ref', exitCode: 2 }));
|
|
41
|
+
}
|
|
42
|
+
const result = yield* Effect.tryPromise({
|
|
43
|
+
try: async () => await executeOutlineRemSubtree({
|
|
44
|
+
id: resolvedId,
|
|
45
|
+
dbPath: cfg.remnoteDb,
|
|
46
|
+
maxDepth: depth,
|
|
47
|
+
startOffset: offset,
|
|
48
|
+
maxNodes: nodes,
|
|
49
|
+
format: format === 'json' ? 'json' : 'markdown',
|
|
50
|
+
excludeProperties,
|
|
51
|
+
includeEmpty,
|
|
52
|
+
expandReferences: expandReferences === false ? false : undefined,
|
|
53
|
+
maxReferenceDepth: maxReferenceDepth,
|
|
54
|
+
detail,
|
|
55
|
+
}),
|
|
56
|
+
catch: (e) => cliErrorFromUnknown(e, { code: 'DB_UNAVAILABLE' }),
|
|
57
|
+
});
|
|
58
|
+
yield* writeSuccess({ data: result, md: result.markdown ?? '' });
|
|
59
|
+
}).pipe(Effect.catchAll(writeFailure)));
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Command } from '@effect/cli';
|
|
2
|
+
import * as Options from '@effect/cli/Options';
|
|
3
|
+
import * as Effect from 'effect/Effect';
|
|
4
|
+
import * as Option from 'effect/Option';
|
|
5
|
+
import { executeSearchQuery } from '../../adapters/mcp.js';
|
|
6
|
+
import { AppConfig } from '../../services/AppConfig.js';
|
|
7
|
+
import { CliError } from '../../services/Errors.js';
|
|
8
|
+
import { Payload } from '../../services/Payload.js';
|
|
9
|
+
import { writeFailure, writeSuccess } from '../_shared.js';
|
|
10
|
+
import { cliErrorFromUnknown } from '../_tool.js';
|
|
11
|
+
function optionToUndefined(opt) {
|
|
12
|
+
return Option.isSome(opt) ? opt.value : undefined;
|
|
13
|
+
}
|
|
14
|
+
function buildMarkdown(items, total) {
|
|
15
|
+
const lines = [`# Query 结果(${items.length}/${total})`];
|
|
16
|
+
for (const item of items) {
|
|
17
|
+
const title = (item?.title && String(item.title).trim()) || '';
|
|
18
|
+
const head = title ? `${title} (${item.id})` : String(item.id);
|
|
19
|
+
lines.push(`- ${head}`);
|
|
20
|
+
if (item?.snippet)
|
|
21
|
+
lines.push(` - ${String(item.snippet)}`);
|
|
22
|
+
}
|
|
23
|
+
return lines.join('\n');
|
|
24
|
+
}
|
|
25
|
+
const payload = Options.text('payload').pipe(Options.optional, Options.map(optionToUndefined));
|
|
26
|
+
const text = Options.text('text').pipe(Options.optional, Options.map(optionToUndefined));
|
|
27
|
+
const tag = Options.text('tag').pipe(Options.repeated);
|
|
28
|
+
const limit = Options.integer('limit').pipe(Options.optional, Options.map(optionToUndefined));
|
|
29
|
+
const offset = Options.integer('offset').pipe(Options.optional, Options.map(optionToUndefined));
|
|
30
|
+
const snippetLength = Options.integer('snippet-length').pipe(Options.optional, Options.map(optionToUndefined));
|
|
31
|
+
const sort = Options.choice('sort', ['rank', 'updatedAt', 'createdAt']).pipe(Options.optional, Options.map(optionToUndefined));
|
|
32
|
+
const sortDirection = Options.choice('sort-direction', ['asc', 'desc']).pipe(Options.optional, Options.map(optionToUndefined));
|
|
33
|
+
export const readQueryCommand = Command.make('query', { payload, text, tag, limit, offset, snippetLength, sort, sortDirection }, ({ payload, text, tag, limit, offset, snippetLength, sort, sortDirection }) => Effect.gen(function* () {
|
|
34
|
+
const cfg = yield* AppConfig;
|
|
35
|
+
const payloadSvc = yield* Payload;
|
|
36
|
+
const queryObj = {};
|
|
37
|
+
if (payload) {
|
|
38
|
+
const raw = yield* payloadSvc.readJson(payload);
|
|
39
|
+
if (raw && typeof raw === 'object' && raw.query && raw.query.root) {
|
|
40
|
+
Object.assign(queryObj, raw);
|
|
41
|
+
}
|
|
42
|
+
else if (raw && typeof raw === 'object' && raw.root) {
|
|
43
|
+
Object.assign(queryObj, { query: raw });
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
return yield* Effect.fail(new CliError({
|
|
47
|
+
code: 'INVALID_PAYLOAD',
|
|
48
|
+
message: 'payload 形状不合法:需要 { query: { root: ... } } 或 { root: ... }',
|
|
49
|
+
exitCode: 2,
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const nodes = [];
|
|
55
|
+
if (text && text.trim()) {
|
|
56
|
+
nodes.push({ type: 'text', value: text.trim(), mode: 'contains' });
|
|
57
|
+
}
|
|
58
|
+
for (const t of tag ?? []) {
|
|
59
|
+
const v = t.trim();
|
|
60
|
+
if (v)
|
|
61
|
+
nodes.push({ type: 'tag', id: v });
|
|
62
|
+
}
|
|
63
|
+
if (nodes.length === 0) {
|
|
64
|
+
return yield* Effect.fail(new CliError({
|
|
65
|
+
code: 'INVALID_ARGS',
|
|
66
|
+
message: '请提供 --payload 或至少一个筛选条件(例如 --text / --tag)',
|
|
67
|
+
exitCode: 2,
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
queryObj.query = {
|
|
71
|
+
root: nodes.length === 1 ? nodes[0] : { type: 'and', nodes },
|
|
72
|
+
sort: sort === 'rank'
|
|
73
|
+
? { mode: 'rank' }
|
|
74
|
+
: sort === 'updatedAt'
|
|
75
|
+
? { mode: 'updatedAt', direction: sortDirection ?? 'desc' }
|
|
76
|
+
: sort === 'createdAt'
|
|
77
|
+
? { mode: 'createdAt', direction: sortDirection ?? 'desc' }
|
|
78
|
+
: undefined,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const { payload: result } = yield* Effect.tryPromise({
|
|
82
|
+
try: async () => await executeSearchQuery({
|
|
83
|
+
...queryObj,
|
|
84
|
+
dbPath: cfg.remnoteDb,
|
|
85
|
+
limit: limit,
|
|
86
|
+
offset: offset,
|
|
87
|
+
snippetLength: snippetLength,
|
|
88
|
+
}),
|
|
89
|
+
catch: (e) => cliErrorFromUnknown(e, { code: 'DB_UNAVAILABLE' }),
|
|
90
|
+
});
|
|
91
|
+
yield* writeSuccess({
|
|
92
|
+
data: result,
|
|
93
|
+
md: buildMarkdown(result.items ?? [], Number(result.totalMatched ?? 0)),
|
|
94
|
+
});
|
|
95
|
+
}).pipe(Effect.catchAll(writeFailure)));
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Command } from '@effect/cli';
|
|
2
|
+
import * as Options from '@effect/cli/Options';
|
|
3
|
+
import * as Effect from 'effect/Effect';
|
|
4
|
+
import * as Option from 'effect/Option';
|
|
5
|
+
import { executeListRemReferences } from '../../adapters/mcp.js';
|
|
6
|
+
import { AppConfig } from '../../services/AppConfig.js';
|
|
7
|
+
import { writeFailure, writeSuccess } from '../_shared.js';
|
|
8
|
+
import { cliErrorFromUnknown } from '../_tool.js';
|
|
9
|
+
function optionToUndefined(opt) {
|
|
10
|
+
return Option.isSome(opt) ? opt.value : undefined;
|
|
11
|
+
}
|
|
12
|
+
const maxDepth = Options.integer('max-depth').pipe(Options.optional, Options.map(optionToUndefined));
|
|
13
|
+
const inboundMaxDepth = Options.integer('inbound-max-depth').pipe(Options.optional, Options.map(optionToUndefined));
|
|
14
|
+
export const readReferencesCommand = Command.make('references', {
|
|
15
|
+
id: Options.text('id'),
|
|
16
|
+
includeDescendants: Options.boolean('include-descendants'),
|
|
17
|
+
maxDepth,
|
|
18
|
+
includeOccurrences: Options.boolean('include-occurrences'),
|
|
19
|
+
resolveText: Options.boolean('resolve-text'),
|
|
20
|
+
includeInbound: Options.boolean('include-inbound'),
|
|
21
|
+
inboundMaxDepth,
|
|
22
|
+
}, ({ id, includeDescendants, maxDepth, includeOccurrences, resolveText, includeInbound, inboundMaxDepth }) => Effect.gen(function* () {
|
|
23
|
+
const cfg = yield* AppConfig;
|
|
24
|
+
const payload = yield* Effect.tryPromise({
|
|
25
|
+
try: async () => {
|
|
26
|
+
const { payload } = await executeListRemReferences({
|
|
27
|
+
id,
|
|
28
|
+
dbPath: cfg.remnoteDb,
|
|
29
|
+
includeDescendants,
|
|
30
|
+
maxDepth: maxDepth,
|
|
31
|
+
includeOccurrences,
|
|
32
|
+
resolveText: resolveText === false ? false : undefined,
|
|
33
|
+
includeInbound,
|
|
34
|
+
inboundMaxDepth: inboundMaxDepth,
|
|
35
|
+
});
|
|
36
|
+
return payload;
|
|
37
|
+
},
|
|
38
|
+
catch: (e) => cliErrorFromUnknown(e, { code: 'DB_UNAVAILABLE' }),
|
|
39
|
+
});
|
|
40
|
+
yield* writeSuccess({ data: payload, md: payload.markdown ?? '' });
|
|
41
|
+
}).pipe(Effect.catchAll(writeFailure)));
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Command } from '@effect/cli';
|
|
2
|
+
import * as Options from '@effect/cli/Options';
|
|
3
|
+
import * as Effect from 'effect/Effect';
|
|
4
|
+
import * as Option from 'effect/Option';
|
|
5
|
+
import { executeResolveRemReference } from '../../adapters/mcp.js';
|
|
6
|
+
import { AppConfig } from '../../services/AppConfig.js';
|
|
7
|
+
import { writeFailure, writeSuccess } from '../_shared.js';
|
|
8
|
+
import { cliErrorFromUnknown } from '../_tool.js';
|
|
9
|
+
const ids = Options.text('ids').pipe(Options.repeated);
|
|
10
|
+
function optionToUndefined(opt) {
|
|
11
|
+
return Option.isSome(opt) ? opt.value : undefined;
|
|
12
|
+
}
|
|
13
|
+
const maxReferenceDepth = Options.integer('max-reference-depth').pipe(Options.optional, Options.map(optionToUndefined));
|
|
14
|
+
export const readResolveRefCommand = Command.make('resolve-ref', {
|
|
15
|
+
ids,
|
|
16
|
+
expandReferences: Options.boolean('expand-references'),
|
|
17
|
+
maxReferenceDepth,
|
|
18
|
+
detail: Options.boolean('detail'),
|
|
19
|
+
}, ({ ids, expandReferences, maxReferenceDepth, detail }) => Effect.gen(function* () {
|
|
20
|
+
const cfg = yield* AppConfig;
|
|
21
|
+
const result = yield* Effect.tryPromise({
|
|
22
|
+
try: async () => await executeResolveRemReference({
|
|
23
|
+
ids,
|
|
24
|
+
dbPath: cfg.remnoteDb,
|
|
25
|
+
expandReferences: expandReferences === false ? false : undefined,
|
|
26
|
+
maxReferenceDepth: maxReferenceDepth,
|
|
27
|
+
detail,
|
|
28
|
+
}),
|
|
29
|
+
catch: (e) => cliErrorFromUnknown(e, { code: 'DB_UNAVAILABLE' }),
|
|
30
|
+
});
|
|
31
|
+
yield* writeSuccess({ data: result, md: result.markdown ?? '' });
|
|
32
|
+
}).pipe(Effect.catchAll(writeFailure)));
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Command } from '@effect/cli';
|
|
2
|
+
import * as Options from '@effect/cli/Options';
|
|
3
|
+
import * as Effect from 'effect/Effect';
|
|
4
|
+
import * as Option from 'effect/Option';
|
|
5
|
+
import { executeSearchRemOverview } from '../../adapters/mcp.js';
|
|
6
|
+
import { AppConfig } from '../../services/AppConfig.js';
|
|
7
|
+
import { writeFailure, writeSuccess } from '../_shared.js';
|
|
8
|
+
import { cliErrorFromUnknown } from '../_tool.js';
|
|
9
|
+
function optionToUndefined(opt) {
|
|
10
|
+
return Option.isSome(opt) ? opt.value : undefined;
|
|
11
|
+
}
|
|
12
|
+
const timeRange = Options.text('time').pipe(Options.optional, Options.map(optionToUndefined));
|
|
13
|
+
const parentId = Options.text('parent').pipe(Options.optional, Options.map(optionToUndefined));
|
|
14
|
+
const limit = Options.integer('limit').pipe(Options.optional, Options.map(optionToUndefined));
|
|
15
|
+
const offset = Options.integer('offset').pipe(Options.optional, Options.map(optionToUndefined));
|
|
16
|
+
export const readSearchCommand = Command.make('search', {
|
|
17
|
+
query: Options.text('query'),
|
|
18
|
+
timeRange,
|
|
19
|
+
parentId,
|
|
20
|
+
pagesOnly: Options.boolean('pages-only'),
|
|
21
|
+
excludePages: Options.boolean('exclude-pages'),
|
|
22
|
+
limit,
|
|
23
|
+
offset,
|
|
24
|
+
}, ({ query, timeRange, parentId, pagesOnly, excludePages, limit, offset }) => Effect.gen(function* () {
|
|
25
|
+
const cfg = yield* AppConfig;
|
|
26
|
+
const result = yield* Effect.tryPromise({
|
|
27
|
+
try: async () => await executeSearchRemOverview({
|
|
28
|
+
query,
|
|
29
|
+
dbPath: cfg.remnoteDb,
|
|
30
|
+
timeRange: timeRange,
|
|
31
|
+
parentId,
|
|
32
|
+
pagesOnly,
|
|
33
|
+
excludePages,
|
|
34
|
+
limit: limit,
|
|
35
|
+
offset: offset,
|
|
36
|
+
}),
|
|
37
|
+
catch: (e) => cliErrorFromUnknown(e, { code: 'DB_UNAVAILABLE' }),
|
|
38
|
+
});
|
|
39
|
+
yield* writeSuccess({ data: result, md: result.markdown ?? '' });
|
|
40
|
+
}).pipe(Effect.catchAll(writeFailure)));
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Command } from '@effect/cli';
|
|
2
|
+
import * as Options from '@effect/cli/Options';
|
|
3
|
+
import * as Effect from 'effect/Effect';
|
|
4
|
+
import * as Option from 'effect/Option';
|
|
5
|
+
import { executeReadRemTable } from '../../adapters/mcp.js';
|
|
6
|
+
import { AppConfig } from '../../services/AppConfig.js';
|
|
7
|
+
import { writeFailure, writeSuccess } from '../_shared.js';
|
|
8
|
+
import { cliErrorFromUnknown, unwrapStructuredContent } from '../_tool.js';
|
|
9
|
+
function optionToUndefined(opt) {
|
|
10
|
+
return Option.isSome(opt) ? opt.value : undefined;
|
|
11
|
+
}
|
|
12
|
+
const limit = Options.integer('limit').pipe(Options.optional, Options.map(optionToUndefined));
|
|
13
|
+
const offset = Options.integer('offset').pipe(Options.optional, Options.map(optionToUndefined));
|
|
14
|
+
export const readTableCommand = Command.make('table', {
|
|
15
|
+
id: Options.text('id'),
|
|
16
|
+
includeOptions: Options.boolean('include-options'),
|
|
17
|
+
limit,
|
|
18
|
+
offset,
|
|
19
|
+
}, ({ id, includeOptions, limit, offset }) => Effect.gen(function* () {
|
|
20
|
+
const cfg = yield* AppConfig;
|
|
21
|
+
const payload = yield* Effect.tryPromise({
|
|
22
|
+
try: async () => unwrapStructuredContent(await executeReadRemTable({
|
|
23
|
+
tagId: id,
|
|
24
|
+
dbPath: cfg.remnoteDb,
|
|
25
|
+
includeOptions,
|
|
26
|
+
limit: limit,
|
|
27
|
+
offset: offset,
|
|
28
|
+
})),
|
|
29
|
+
catch: (e) => cliErrorFromUnknown(e, { code: 'DB_UNAVAILABLE' }),
|
|
30
|
+
});
|
|
31
|
+
yield* writeSuccess({ data: payload, md: payload.markdown ?? '' });
|
|
32
|
+
}).pipe(Effect.catchAll(writeFailure)));
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Command } from '@effect/cli';
|
|
2
|
+
import * as Options from '@effect/cli/Options';
|
|
3
|
+
import * as Effect from 'effect/Effect';
|
|
4
|
+
import * as Option from 'effect/Option';
|
|
5
|
+
import { executeListTodos } from '../../adapters/mcp.js';
|
|
6
|
+
import { AppConfig } from '../../services/AppConfig.js';
|
|
7
|
+
import { writeFailure, writeSuccess } from '../_shared.js';
|
|
8
|
+
import { cliErrorFromUnknown, unwrapStructuredContent } from '../_tool.js';
|
|
9
|
+
function optionToUndefined(opt) {
|
|
10
|
+
return Option.isSome(opt) ? opt.value : undefined;
|
|
11
|
+
}
|
|
12
|
+
const status = Options.choice('status', ['unfinished', 'finished', 'all']).pipe(Options.optional, Options.map(optionToUndefined));
|
|
13
|
+
const ancestor = Options.text('ancestor').pipe(Options.optional, Options.map(optionToUndefined));
|
|
14
|
+
const dueBefore = Options.text('due-before').pipe(Options.optional, Options.map(optionToUndefined));
|
|
15
|
+
const dueAfter = Options.text('due-after').pipe(Options.optional, Options.map(optionToUndefined));
|
|
16
|
+
const limit = Options.integer('limit').pipe(Options.optional, Options.map(optionToUndefined));
|
|
17
|
+
const offset = Options.integer('offset').pipe(Options.optional, Options.map(optionToUndefined));
|
|
18
|
+
export const todosListCommand = Command.make('list', { status, ancestor, dueBefore, dueAfter, limit, offset }, ({ status, ancestor, dueBefore, dueAfter, limit, offset }) => Effect.gen(function* () {
|
|
19
|
+
const cfg = yield* AppConfig;
|
|
20
|
+
const payload = yield* Effect.tryPromise({
|
|
21
|
+
try: async () => unwrapStructuredContent(await executeListTodos({
|
|
22
|
+
dbPath: cfg.remnoteDb,
|
|
23
|
+
status: status,
|
|
24
|
+
ancestorId: ancestor,
|
|
25
|
+
dueBefore: dueBefore,
|
|
26
|
+
dueAfter: dueAfter,
|
|
27
|
+
limit: limit,
|
|
28
|
+
offset: offset,
|
|
29
|
+
})),
|
|
30
|
+
catch: (e) => cliErrorFromUnknown(e, { code: 'DB_UNAVAILABLE' }),
|
|
31
|
+
});
|
|
32
|
+
yield* writeSuccess({ data: payload, md: payload.markdown ?? '' });
|
|
33
|
+
}).pipe(Effect.catchAll(writeFailure)));
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Command } from '@effect/cli';
|
|
2
|
+
import * as Options from '@effect/cli/Options';
|
|
3
|
+
import * as Effect from 'effect/Effect';
|
|
4
|
+
import * as Option from 'effect/Option';
|
|
5
|
+
import { executeSummarizeTopicActivity } from '../../adapters/mcp.js';
|
|
6
|
+
import { AppConfig } from '../../services/AppConfig.js';
|
|
7
|
+
import { CliError } from '../../services/Errors.js';
|
|
8
|
+
import { writeFailure, writeSuccess } from '../_shared.js';
|
|
9
|
+
import { cliErrorFromUnknown } from '../_tool.js';
|
|
10
|
+
function optionToUndefined(opt) {
|
|
11
|
+
return Option.isSome(opt) ? opt.value : undefined;
|
|
12
|
+
}
|
|
13
|
+
const keywords = Options.text('keywords').pipe(Options.optional, Options.map(optionToUndefined));
|
|
14
|
+
const query = Options.text('query').pipe(Options.optional, Options.map(optionToUndefined));
|
|
15
|
+
const timeRange = Options.text('time').pipe(Options.optional, Options.map(optionToUndefined));
|
|
16
|
+
const maxResults = Options.integer('max-results').pipe(Options.optional, Options.map(optionToUndefined));
|
|
17
|
+
const maxNodesPerResult = Options.integer('max-nodes').pipe(Options.optional, Options.map(optionToUndefined));
|
|
18
|
+
const groupBy = Options.choice('group-by', ['none', 'parent', 'date']).pipe(Options.optional, Options.map(optionToUndefined));
|
|
19
|
+
export const topicSummaryCommand = Command.make('summary', { keywords, query, timeRange, maxResults, maxNodesPerResult, groupBy }, ({ keywords, query, timeRange, maxResults, maxNodesPerResult, groupBy }) => Effect.gen(function* () {
|
|
20
|
+
const cfg = yield* AppConfig;
|
|
21
|
+
const keywordList = keywords
|
|
22
|
+
? keywords
|
|
23
|
+
.split(',')
|
|
24
|
+
.map((s) => s.trim())
|
|
25
|
+
.filter(Boolean)
|
|
26
|
+
: undefined;
|
|
27
|
+
const queryText = query?.trim() || undefined;
|
|
28
|
+
if ((!keywordList || keywordList.length === 0) && !queryText) {
|
|
29
|
+
return yield* Effect.fail(new CliError({ code: 'INVALID_ARGS', message: '请提供 --keywords 或 --query', exitCode: 2 }));
|
|
30
|
+
}
|
|
31
|
+
const result = yield* Effect.tryPromise({
|
|
32
|
+
try: async () => await executeSummarizeTopicActivity({
|
|
33
|
+
keywords: keywordList,
|
|
34
|
+
query: queryText,
|
|
35
|
+
timeRange: timeRange,
|
|
36
|
+
maxResults: maxResults,
|
|
37
|
+
maxNodesPerResult: maxNodesPerResult,
|
|
38
|
+
groupBy: groupBy,
|
|
39
|
+
dbPath: cfg.remnoteDb,
|
|
40
|
+
}),
|
|
41
|
+
catch: (e) => cliErrorFromUnknown(e, { code: 'DB_UNAVAILABLE' }),
|
|
42
|
+
});
|
|
43
|
+
yield* writeSuccess({ data: result, md: result.markdown ?? '' });
|
|
44
|
+
}).pipe(Effect.catchAll(writeFailure)));
|