@dinoxx/dinox-cli 2.14.0 → 2.16.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/README.md +2 -0
- package/dist/ai/ragxClient.d.ts +15 -0
- package/dist/ai/ragxClient.js +71 -0
- package/dist/cli.js +27 -3
- package/dist/commands/batch.d.ts +35 -0
- package/dist/commands/batch.js +202 -0
- package/dist/commands/boxes/index.js +21 -21
- package/dist/commands/mcp.d.ts +6 -0
- package/dist/commands/mcp.js +47 -0
- package/dist/commands/notes/actions.js +18 -2
- package/dist/commands/notes/descriptors.js +111 -5
- package/dist/commands/notes/detailContent.d.ts +19 -0
- package/dist/commands/notes/detailContent.js +62 -0
- package/dist/commands/notes/export.js +4 -0
- package/dist/commands/notes/repo/search.d.ts +2 -1
- package/dist/commands/notes/repo/search.js +1 -1
- package/dist/commands/notes/repo/semantic.d.ts +14 -0
- package/dist/commands/notes/repo/semantic.js +31 -0
- package/dist/commands/notes/searchResponse.d.ts +3 -0
- package/dist/commands/notes/searchResponse.js +1 -0
- package/dist/commands/notes/semantic.d.ts +116 -0
- package/dist/commands/notes/semantic.js +332 -0
- package/dist/commands/prompt/index.js +7 -5
- package/dist/commands/savedViews/index.js +12 -3
- package/dist/commands/schema/globalOptions.d.ts +6 -0
- package/dist/commands/schema/globalOptions.js +6 -0
- package/dist/commands/schema/renderSkills.js +5 -2
- package/dist/commands/schema/spec.js +18 -7
- package/dist/commands/storage/index.js +7 -5
- package/dist/commands/sync.js +3 -3
- package/dist/commands/tags/index.js +21 -21
- package/dist/commands/todo/index.js +22 -2
- package/dist/commands/todo/repo.d.ts +5 -0
- package/dist/commands/todo/repo.js +7 -2
- package/dist/commands/writeReceipt.d.ts +13 -0
- package/dist/commands/writeReceipt.js +12 -0
- package/dist/config/serviceEndpoints.d.ts +2 -0
- package/dist/config/serviceEndpoints.js +2 -0
- package/dist/daemon/client.d.ts +2 -0
- package/dist/daemon/client.js +22 -2
- package/dist/daemon/forward.d.ts +4 -1
- package/dist/daemon/forward.js +13 -4
- package/dist/daemon/server.d.ts +1 -1
- package/dist/daemon/server.js +17 -1
- package/dist/daemon/types.d.ts +6 -0
- package/dist/dinox.js +12 -10
- package/dist/gateway/adapters/acp.d.ts +5 -1
- package/dist/gateway/adapters/acp.js +21 -9
- package/dist/gateway/adapters/echo.js +7 -4
- package/dist/gateway/adapters/index.d.ts +1 -0
- package/dist/gateway/adapters/index.js +5 -3
- package/dist/gateway/deviceHost.d.ts +3 -1
- package/dist/gateway/deviceHost.js +75 -5
- package/dist/gateway/mcpCommandTools.d.ts +15 -5
- package/dist/gateway/mcpCommandTools.js +30 -19
- package/dist/gateway/mcpEnv.d.ts +4 -0
- package/dist/gateway/mcpEnv.js +4 -0
- package/dist/gateway/mcpGroups.d.ts +3 -0
- package/dist/gateway/mcpGroups.js +4 -0
- package/dist/gateway/mcpServer.d.ts +10 -1
- package/dist/gateway/mcpServer.js +26 -5
- package/dist/gateway/protocol.d.ts +31 -2
- package/dist/gateway/protocol.js +15 -3
- package/dist/gateway/runExecutor.js +23 -12
- package/dist/gateway/service.d.ts +2 -0
- package/dist/gateway/service.js +29 -4
- package/dist/gateway/threadStore.d.ts +2 -0
- package/dist/gateway/threadStore.js +13 -0
- package/dist/gateway/types.d.ts +5 -4
- package/dist/gateway/workspace.d.ts +5 -0
- package/dist/gateway/workspace.js +30 -0
- package/dist/gateway/workspaceFolders.d.ts +5 -3
- package/dist/gateway/workspaceFolders.js +20 -7
- package/dist/gateway/workspaceListing.d.ts +5 -0
- package/dist/gateway/workspaceListing.js +78 -0
- package/dist/powersync/syncPass.js +13 -1
- package/dist/powersync/tokenIndex.d.ts +2 -0
- package/dist/powersync/tokenIndex.js +1 -0
- package/dist/requests/execute.d.ts +11 -0
- package/dist/requests/execute.js +26 -0
- package/dist/skills/commandRefs.js +2 -10
- package/dist/utils/cursor.d.ts +9 -0
- package/dist/utils/cursor.js +61 -0
- package/dist/utils/defaultFormat.d.ts +8 -0
- package/dist/utils/defaultFormat.js +38 -0
- package/dist/utils/errorCodes.d.ts +4 -0
- package/dist/utils/errorCodes.js +1 -0
- package/dist/utils/output.d.ts +2 -0
- package/dist/utils/output.js +41 -3
- package/dist/utils/progress.d.ts +25 -0
- package/dist/utils/progress.js +59 -0
- package/dist/utils/requestContext.d.ts +8 -0
- package/dist/utils/select.d.ts +20 -0
- package/dist/utils/select.js +92 -0
- package/dist/utils/usageError.d.ts +37 -0
- package/dist/utils/usageError.js +127 -0
- package/package.json +1 -1
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { WRITE_DURABILITY_OPTION } from '../writeDurability.js';
|
|
2
|
+
import { completeWrite, WRITE_RECEIPT_FIELDS } from '../writeReceipt.js';
|
|
1
3
|
import { resolveAuthIdentity } from '../../auth/userInfo.js';
|
|
2
4
|
import { registerCommandGroup } from '../descriptor/register.js';
|
|
3
5
|
import { FORMAT_OPTIONS, OFFLINE_OPTIONS, REQUIRE_SYNC_OPTIONS, SYNC_TIMEOUT_OPTIONS } from '../schema/globalOptions.js';
|
|
@@ -5,7 +7,7 @@ import { buildTagAddDryRunPreview, buildTagMutationDryRunPreview } from '../writ
|
|
|
5
7
|
import { printDryRunPreview } from '../../utils/dryRun.js';
|
|
6
8
|
import { DinoxError } from '../../utils/errors.js';
|
|
7
9
|
import { getRequestedStructuredOutputFormat, printHumanReadableLine, printSuccess, } from '../../utils/output.js';
|
|
8
|
-
import { commandStale, printStaleCacheWarning, syncBeforeCommand,
|
|
10
|
+
import { commandStale, printStaleCacheWarning, syncBeforeCommand, resolveWriteDurabilityForRuntime, withCommandRuntime, } from '../runtime.js';
|
|
9
11
|
import { assertWriteConfirmationProvided, parseExpectedCount } from '../writeConfirmation.js';
|
|
10
12
|
import { addTag, inspectAddTag, listTags } from './repo.js';
|
|
11
13
|
import { getTagStats, getTagTree, inspectTagCleanup, mergeTag, moveTag, renameTag, suggestTagMerges, } from './operations.js';
|
|
@@ -56,6 +58,7 @@ async function runTagAdd(context) {
|
|
|
56
58
|
}
|
|
57
59
|
const structuredOutput = getRequestedStructuredOutputFormat() !== null;
|
|
58
60
|
await withCommandRuntime(context, async (runtime) => {
|
|
61
|
+
const durability = resolveWriteDurabilityForRuntime(runtime, context.options.durability);
|
|
59
62
|
const identity = await resolveAuthIdentity(runtime.config);
|
|
60
63
|
await syncBeforeCommand(runtime, { syncTokenIndex: true });
|
|
61
64
|
const emoji = typeof context.options.emoji === 'string' ? context.options.emoji : undefined;
|
|
@@ -76,8 +79,7 @@ async function runTagAdd(context) {
|
|
|
76
79
|
userId: identity.userId,
|
|
77
80
|
emoji,
|
|
78
81
|
});
|
|
79
|
-
await
|
|
80
|
-
const payload = { ok: true, stale: commandStale(runtime), ...result };
|
|
82
|
+
const payload = { ok: true, ...(await completeWrite(runtime, durability)), ...result };
|
|
81
83
|
if (structuredOutput) {
|
|
82
84
|
printSuccess(payload);
|
|
83
85
|
return;
|
|
@@ -88,9 +90,10 @@ async function runTagAdd(context) {
|
|
|
88
90
|
}
|
|
89
91
|
async function withTagWriteRuntime(context, run) {
|
|
90
92
|
return withCommandRuntime(context, async (runtime) => {
|
|
93
|
+
const durability = resolveWriteDurabilityForRuntime(runtime, context.options.durability);
|
|
91
94
|
const identity = await resolveAuthIdentity(runtime.config);
|
|
92
95
|
await syncBeforeCommand(runtime, { syncTokenIndex: true });
|
|
93
|
-
return run({ runtime, userId: identity.userId });
|
|
96
|
+
return run({ runtime, userId: identity.userId, durability });
|
|
94
97
|
});
|
|
95
98
|
}
|
|
96
99
|
function requireArg(value, message) {
|
|
@@ -103,7 +106,7 @@ function requireArg(value, message) {
|
|
|
103
106
|
async function runTagRename(context) {
|
|
104
107
|
const path = requireArg(context.args.path, 'Tag path is required');
|
|
105
108
|
const newName = requireArg(context.args.newName, 'New tag name is required');
|
|
106
|
-
await withTagWriteRuntime(context, async ({ runtime, userId }) => {
|
|
109
|
+
await withTagWriteRuntime(context, async ({ runtime, userId, durability }) => {
|
|
107
110
|
const result = await renameTag(runtime.db, { path, newName, userId }, { dryRun: Boolean(context.options.dryRun) });
|
|
108
111
|
if (Boolean(context.options.dryRun)) {
|
|
109
112
|
printDryRunPreview(buildTagMutationDryRunPreview({
|
|
@@ -118,8 +121,7 @@ async function runTagRename(context) {
|
|
|
118
121
|
}), runtime);
|
|
119
122
|
return;
|
|
120
123
|
}
|
|
121
|
-
await
|
|
122
|
-
printSuccess({ ok: true, stale: commandStale(runtime), ...result });
|
|
124
|
+
printSuccess({ ok: true, ...(await completeWrite(runtime, durability)), ...result });
|
|
123
125
|
});
|
|
124
126
|
}
|
|
125
127
|
async function runTagMove(context) {
|
|
@@ -128,7 +130,7 @@ async function runTagMove(context) {
|
|
|
128
130
|
if (!to) {
|
|
129
131
|
throw new DinoxError('--to is required');
|
|
130
132
|
}
|
|
131
|
-
await withTagWriteRuntime(context, async ({ runtime, userId }) => {
|
|
133
|
+
await withTagWriteRuntime(context, async ({ runtime, userId, durability }) => {
|
|
132
134
|
const result = await moveTag(runtime.db, { path, to, userId }, { dryRun: Boolean(context.options.dryRun) });
|
|
133
135
|
if (Boolean(context.options.dryRun)) {
|
|
134
136
|
printDryRunPreview(buildTagMutationDryRunPreview({
|
|
@@ -143,8 +145,7 @@ async function runTagMove(context) {
|
|
|
143
145
|
}), runtime);
|
|
144
146
|
return;
|
|
145
147
|
}
|
|
146
|
-
await
|
|
147
|
-
printSuccess({ ok: true, stale: commandStale(runtime), ...result });
|
|
148
|
+
printSuccess({ ok: true, ...(await completeWrite(runtime, durability)), ...result });
|
|
148
149
|
});
|
|
149
150
|
}
|
|
150
151
|
async function runTagMerge(context) {
|
|
@@ -158,7 +159,7 @@ async function runTagMerge(context) {
|
|
|
158
159
|
expectedCount,
|
|
159
160
|
};
|
|
160
161
|
assertWriteConfirmationProvided('Tag merge', writeOptions);
|
|
161
|
-
await withTagWriteRuntime(context, async ({ runtime, userId }) => {
|
|
162
|
+
await withTagWriteRuntime(context, async ({ runtime, userId, durability }) => {
|
|
162
163
|
const result = await mergeTag(runtime.db, { from, to, userId }, writeOptions);
|
|
163
164
|
if (dryRun) {
|
|
164
165
|
printDryRunPreview(buildTagMutationDryRunPreview({
|
|
@@ -179,8 +180,7 @@ async function runTagMerge(context) {
|
|
|
179
180
|
}), runtime);
|
|
180
181
|
return;
|
|
181
182
|
}
|
|
182
|
-
await
|
|
183
|
-
printSuccess({ ok: true, stale: commandStale(runtime), ...result });
|
|
183
|
+
printSuccess({ ok: true, ...(await completeWrite(runtime, durability)), ...result });
|
|
184
184
|
});
|
|
185
185
|
}
|
|
186
186
|
async function runTagSuggest(context) {
|
|
@@ -273,7 +273,7 @@ export const tagCommandGroup = {
|
|
|
273
273
|
options: [
|
|
274
274
|
{ flags: '--name <string>', description: 'Tag name/path (alternative to positional name)' },
|
|
275
275
|
{ flags: '--emoji <string>', description: 'Tag emoji' },
|
|
276
|
-
{ flags: '--dry-run', description: 'Preview the write without executing it' },
|
|
276
|
+
WRITE_DURABILITY_OPTION, { flags: '--dry-run', description: 'Preview the write without executing it' },
|
|
277
277
|
],
|
|
278
278
|
schema: {
|
|
279
279
|
path: 'tag.add',
|
|
@@ -283,7 +283,7 @@ export const tagCommandGroup = {
|
|
|
283
283
|
output: {
|
|
284
284
|
type: 'structured',
|
|
285
285
|
summary: 'Tag creation acknowledgement',
|
|
286
|
-
fields: ['id', 'tag', 'createdNodes', 'restoredNodes',
|
|
286
|
+
fields: ['id', 'tag', 'createdNodes', 'restoredNodes', ...WRITE_RECEIPT_FIELDS],
|
|
287
287
|
},
|
|
288
288
|
examples: ['dino tag add "work/projects" --format json --dry-run', 'dino tag add "work/projects" --emoji "🏷️" --format json'],
|
|
289
289
|
},
|
|
@@ -296,7 +296,7 @@ export const tagCommandGroup = {
|
|
|
296
296
|
{ syntax: '<path>', description: 'Existing tag path' },
|
|
297
297
|
{ syntax: '<new-name>', description: 'New leaf name' },
|
|
298
298
|
],
|
|
299
|
-
options: [{ flags: '--dry-run', description: 'Preview the write without executing it' }],
|
|
299
|
+
options: [WRITE_DURABILITY_OPTION, { flags: '--dry-run', description: 'Preview the write without executing it' }],
|
|
300
300
|
schema: {
|
|
301
301
|
path: 'tag.rename',
|
|
302
302
|
risk: 'write',
|
|
@@ -305,7 +305,7 @@ export const tagCommandGroup = {
|
|
|
305
305
|
output: {
|
|
306
306
|
type: 'structured',
|
|
307
307
|
summary: 'Tag rename result',
|
|
308
|
-
fields: ['id', 'fromPath', 'toPath', 'updatedTags', 'updatedNotes',
|
|
308
|
+
fields: ['id', 'fromPath', 'toPath', 'updatedTags', 'updatedNotes', ...WRITE_RECEIPT_FIELDS],
|
|
309
309
|
},
|
|
310
310
|
examples: ['dino tag rename "AI/old" "new" --format json --dry-run'],
|
|
311
311
|
},
|
|
@@ -317,7 +317,7 @@ export const tagCommandGroup = {
|
|
|
317
317
|
arguments: [{ syntax: '<path>', description: 'Existing tag path' }],
|
|
318
318
|
options: [
|
|
319
319
|
{ flags: '--to <parent-path>', description: 'Target parent tag path', required: true, type: 'string' },
|
|
320
|
-
{ flags: '--dry-run', description: 'Preview the write without executing it' },
|
|
320
|
+
WRITE_DURABILITY_OPTION, { flags: '--dry-run', description: 'Preview the write without executing it' },
|
|
321
321
|
],
|
|
322
322
|
schema: {
|
|
323
323
|
path: 'tag.move',
|
|
@@ -327,7 +327,7 @@ export const tagCommandGroup = {
|
|
|
327
327
|
output: {
|
|
328
328
|
type: 'structured',
|
|
329
329
|
summary: 'Tag move result',
|
|
330
|
-
fields: ['id', 'fromPath', 'toPath', 'updatedTags', 'updatedNotes',
|
|
330
|
+
fields: ['id', 'fromPath', 'toPath', 'updatedTags', 'updatedNotes', ...WRITE_RECEIPT_FIELDS],
|
|
331
331
|
},
|
|
332
332
|
examples: ['dino tag move "AI" --to "Technology" --format json --dry-run'],
|
|
333
333
|
},
|
|
@@ -343,7 +343,7 @@ export const tagCommandGroup = {
|
|
|
343
343
|
options: [
|
|
344
344
|
{ flags: '--expected-count <n>', description: 'Required for real writes; must equal source tags plus notes affected', type: 'number' },
|
|
345
345
|
{ flags: '--confirm', description: 'Required for real writes after reviewing a dry run', type: 'boolean' },
|
|
346
|
-
{ flags: '--dry-run', description: 'Preview the write without executing it', type: 'boolean' },
|
|
346
|
+
WRITE_DURABILITY_OPTION, { flags: '--dry-run', description: 'Preview the write without executing it', type: 'boolean' },
|
|
347
347
|
],
|
|
348
348
|
schema: {
|
|
349
349
|
path: 'tag.merge',
|
|
@@ -353,7 +353,7 @@ export const tagCommandGroup = {
|
|
|
353
353
|
output: {
|
|
354
354
|
type: 'structured',
|
|
355
355
|
summary: 'Tag merge result',
|
|
356
|
-
fields: ['fromId', 'toId', 'fromPath', 'toPath', 'softDeletedTagIds', 'updatedNotes', 'affectedCount',
|
|
356
|
+
fields: ['fromId', 'toId', 'fromPath', 'toPath', 'softDeletedTagIds', 'updatedNotes', 'affectedCount', ...WRITE_RECEIPT_FIELDS],
|
|
357
357
|
},
|
|
358
358
|
examples: [
|
|
359
359
|
'dino tag merge "ai" "AI" --format json --dry-run',
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolveAuthIdentity } from '../../auth/userInfo.js';
|
|
2
|
+
import { nextCursor, resolveCursorOffset } from '../../utils/cursor.js';
|
|
2
3
|
import { registerCommandGroup } from '../descriptor/register.js';
|
|
3
4
|
import { FORMAT_OPTIONS, OFFLINE_OPTIONS, REQUIRE_SYNC_OPTIONS, SYNC_TIMEOUT_OPTIONS } from '../schema/globalOptions.js';
|
|
4
5
|
import { WRITE_DURABILITY_OPTION } from '../writeDurability.js';
|
|
@@ -147,12 +148,25 @@ async function runTodoSearch({ args, globals, options }) {
|
|
|
147
148
|
});
|
|
148
149
|
const limit = parsePositiveIntegerOption(searchOptions.limit, '--limit', DEFAULT_TASK_LIMIT, MAX_TASK_LIMIT);
|
|
149
150
|
const scanLimit = parsePositiveIntegerOption(searchOptions.scanLimit, '--scan-limit', DEFAULT_NOTE_SCAN_LIMIT, MAX_NOTE_SCAN_LIMIT);
|
|
151
|
+
// Raw option values, not the resolved range: `--days` must not change the hash between pages.
|
|
152
|
+
const cursorQuery = {
|
|
153
|
+
keyword,
|
|
154
|
+
includeDeleted: Boolean(searchOptions.includeDeleted),
|
|
155
|
+
taskStatus,
|
|
156
|
+
taskTagFilter,
|
|
157
|
+
from: searchOptions.from,
|
|
158
|
+
to: searchOptions.to,
|
|
159
|
+
days: searchOptions.days,
|
|
160
|
+
scanLimit,
|
|
161
|
+
};
|
|
162
|
+
const offset = resolveCursorOffset(searchOptions.cursor, 0, 'todo.search', cursorQuery);
|
|
150
163
|
const wire = toTodoSearchWire(keyword, {
|
|
151
164
|
includeDeleted: Boolean(searchOptions.includeDeleted),
|
|
152
165
|
taskStatus,
|
|
153
166
|
taskTagFilter,
|
|
154
167
|
taskDateRange,
|
|
155
168
|
limit,
|
|
169
|
+
offset,
|
|
156
170
|
scanLimit,
|
|
157
171
|
});
|
|
158
172
|
const result = await routeRead(globals, 'todo.search', wire, () => withTodoDatabase(globals, async (runtime) => {
|
|
@@ -161,7 +175,12 @@ async function runTodoSearch({ args, globals, options }) {
|
|
|
161
175
|
return { ...local, stale: commandStale(runtime) };
|
|
162
176
|
}));
|
|
163
177
|
const { stale, ...response } = result;
|
|
164
|
-
|
|
178
|
+
const nextOffset = response.meta.offset + response.meta.returned_count;
|
|
179
|
+
printSuccess({
|
|
180
|
+
stale: stale ?? false,
|
|
181
|
+
...response,
|
|
182
|
+
meta: { ...response.meta, next_cursor: nextCursor('todo.search', cursorQuery, nextOffset, response.meta.has_more) },
|
|
183
|
+
});
|
|
165
184
|
}
|
|
166
185
|
async function runTodoAppend({ args, globals, options }) {
|
|
167
186
|
const appendOptions = options;
|
|
@@ -290,6 +309,7 @@ const todoSearchCommand = {
|
|
|
290
309
|
{ flags: '--days <n>', description: 'Recent N days; mutually exclusive with --from/--to' },
|
|
291
310
|
{ flags: '--limit <n>', description: 'Maximum returned tasks' },
|
|
292
311
|
{ flags: '--scan-limit <n>', description: 'Maximum scanned note rows' },
|
|
312
|
+
{ flags: '--cursor <token>', description: 'Continue from meta.next_cursor of the previous page (same query)' },
|
|
293
313
|
{ flags: '--include-deleted', description: 'Include soft-deleted notes' },
|
|
294
314
|
],
|
|
295
315
|
schema: {
|
|
@@ -301,7 +321,7 @@ const todoSearchCommand = {
|
|
|
301
321
|
type: 'structured',
|
|
302
322
|
summary: 'Todo search payload with metadata and task list',
|
|
303
323
|
fields: ['tasks.task_id', 'tasks.task_key', 'tasks.note_id', 'tasks.note_title', 'tasks.status', 'tasks.depth', 'tasks.parent_id', 'tasks.tags'],
|
|
304
|
-
metaFields: ['stale', 'meta.query', 'meta.returned_count', 'meta.total_count', 'meta.total_count_is_lower_bound', 'meta.matched_note_count', 'meta.limit', 'meta.scan_limit', 'meta.scanned_note_count', 'meta.scan_truncated', 'meta.truncated', 'meta.applied_filters.status', 'meta.applied_filters.tags', 'meta.applied_filters.include_deleted', 'meta.applied_filters.date_range'],
|
|
324
|
+
metaFields: ['stale', 'meta.query', 'meta.returned_count', 'meta.total_count', 'meta.total_count_is_lower_bound', 'meta.matched_note_count', 'meta.limit', 'meta.offset', 'meta.has_more', 'meta.next_cursor', 'meta.scan_limit', 'meta.scanned_note_count', 'meta.scan_truncated', 'meta.truncated', 'meta.applied_filters.status', 'meta.applied_filters.tags', 'meta.applied_filters.include_deleted', 'meta.applied_filters.date_range'],
|
|
305
325
|
},
|
|
306
326
|
examples: ['dino todo search "报销" --status uncompleted --format json', 'dino todo search --days 7 --format json'],
|
|
307
327
|
},
|
|
@@ -7,6 +7,7 @@ export type SearchTodoOptions = {
|
|
|
7
7
|
taskTagFilter: string[];
|
|
8
8
|
taskDateRange?: TaskDateRangeFilter;
|
|
9
9
|
limit: number;
|
|
10
|
+
offset?: number;
|
|
10
11
|
scanLimit: number;
|
|
11
12
|
};
|
|
12
13
|
export type AppendTodoTasksOptions = {
|
|
@@ -65,6 +66,8 @@ export type SearchedTodoResponse = {
|
|
|
65
66
|
total_count: number;
|
|
66
67
|
matched_note_count: number;
|
|
67
68
|
limit: number;
|
|
69
|
+
offset: number;
|
|
70
|
+
has_more: boolean;
|
|
68
71
|
scan_limit: number;
|
|
69
72
|
scanned_note_count: number;
|
|
70
73
|
scan_truncated: boolean;
|
|
@@ -109,6 +112,8 @@ export type TodoSearchWire = {
|
|
|
109
112
|
taskStatus: TaskStatusFilter;
|
|
110
113
|
taskTagFilter: string[];
|
|
111
114
|
limit: number;
|
|
115
|
+
/** Index of the first returned task among the matches (from `--cursor`). */
|
|
116
|
+
offset?: number;
|
|
112
117
|
scanLimit: number;
|
|
113
118
|
startDate?: string;
|
|
114
119
|
endDate?: string;
|
|
@@ -40,6 +40,7 @@ export function toTodoSearchWire(query, options) {
|
|
|
40
40
|
taskStatus: options.taskStatus,
|
|
41
41
|
taskTagFilter: options.taskTagFilter,
|
|
42
42
|
limit: options.limit,
|
|
43
|
+
...(options.offset ? { offset: options.offset } : {}),
|
|
43
44
|
scanLimit: options.scanLimit,
|
|
44
45
|
startDate: options.taskDateRange?.startDate?.toISOString(),
|
|
45
46
|
endDate: options.taskDateRange?.endDate?.toISOString(),
|
|
@@ -62,6 +63,7 @@ export async function executeTodoSearch(db, wire) {
|
|
|
62
63
|
taskTagFilter: wire.taskTagFilter,
|
|
63
64
|
taskDateRange,
|
|
64
65
|
limit: wire.limit,
|
|
66
|
+
offset: wire.offset,
|
|
65
67
|
scanLimit: wire.scanLimit,
|
|
66
68
|
});
|
|
67
69
|
}
|
|
@@ -71,7 +73,8 @@ export async function searchTodoTasks(db, query, options) {
|
|
|
71
73
|
const noteRows = scannedRows.slice(0, options.scanLimit);
|
|
72
74
|
const allTasks = extractFlattenedTasks(noteRows);
|
|
73
75
|
const filteredTasks = filterTasksForTodoList(allTasks, query, options.taskStatus, options.taskTagFilter, options.taskDateRange);
|
|
74
|
-
const
|
|
76
|
+
const offset = options.offset ?? 0;
|
|
77
|
+
const visibleTasks = filteredTasks.slice(offset, offset + options.limit);
|
|
75
78
|
const tasks = visibleTasks.map((task) => ({
|
|
76
79
|
task_key: buildTaskKey(task.noteId, task.taskId),
|
|
77
80
|
note_id: task.noteId,
|
|
@@ -96,11 +99,13 @@ export async function searchTodoTasks(db, query, options) {
|
|
|
96
99
|
total_count: filteredTasks.length,
|
|
97
100
|
matched_note_count: new Set(filteredTasks.map((task) => task.noteId)).size,
|
|
98
101
|
limit: options.limit,
|
|
102
|
+
offset,
|
|
103
|
+
has_more: filteredTasks.length > offset + tasks.length,
|
|
99
104
|
scan_limit: options.scanLimit,
|
|
100
105
|
scanned_note_count: noteRows.length,
|
|
101
106
|
scan_truncated: scanTruncated,
|
|
102
107
|
total_count_is_lower_bound: scanTruncated,
|
|
103
|
-
truncated: scanTruncated || filteredTasks.length > tasks.length,
|
|
108
|
+
truncated: scanTruncated || filteredTasks.length > offset + tasks.length,
|
|
104
109
|
applied_filters: {
|
|
105
110
|
status: options.taskStatus,
|
|
106
111
|
tags: [...options.taskTagFilter],
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { WriteDurability } from './writeDurability.js';
|
|
2
|
+
import { type CommandRuntime, type MutationUploadReceipt } from './runtime.js';
|
|
3
|
+
/** Output fields every local-database write reports, as note and todo writes do. */
|
|
4
|
+
export declare const WRITE_RECEIPT_FIELDS: readonly ["durability", "upload_queue_remaining", "stale"];
|
|
5
|
+
export type WriteReceipt = MutationUploadReceipt & {
|
|
6
|
+
stale: boolean;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Waits for the upload `--durability` asks for and describes where the write
|
|
10
|
+
* stands: `durability` local or uploaded, the remaining upload queue, any
|
|
11
|
+
* upload error, and whether the pre-write sync was stale.
|
|
12
|
+
*/
|
|
13
|
+
export declare function completeWrite(runtime: CommandRuntime, durability: WriteDurability): Promise<WriteReceipt>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { commandStale, waitForMutationUpload } from './runtime.js';
|
|
2
|
+
/** Output fields every local-database write reports, as note and todo writes do. */
|
|
3
|
+
export const WRITE_RECEIPT_FIELDS = ['durability', 'upload_queue_remaining', 'stale'];
|
|
4
|
+
/**
|
|
5
|
+
* Waits for the upload `--durability` asks for and describes where the write
|
|
6
|
+
* stands: `durability` local or uploaded, the remaining upload queue, any
|
|
7
|
+
* upload error, and whether the pre-write sync was stale.
|
|
8
|
+
*/
|
|
9
|
+
export async function completeWrite(runtime, durability) {
|
|
10
|
+
const upload = await waitForMutationUpload(runtime, { durability });
|
|
11
|
+
return { ...upload, stale: commandStale(runtime) };
|
|
12
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export declare const POWERSYNC_DEFAULT_ENDPOINT = "https://powersync.dinoai.fun";
|
|
2
2
|
export declare const POWERSYNC_DEFAULT_TOKEN_ENDPOINT = "https://dinoai.chatgo.pro/auth/v2/token";
|
|
3
3
|
export declare const POWERSYNC_DEFAULT_UPLOAD_BASE_URL = "https://dinoai.chatgo.pro";
|
|
4
|
+
/** dinox-tool business API (semantic search, gateway credentials). */
|
|
5
|
+
export declare const AI_SERVICE_URL = "https://aisdk.chatgo.pro";
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export const POWERSYNC_DEFAULT_ENDPOINT = 'https://powersync.dinoai.fun';
|
|
2
2
|
export const POWERSYNC_DEFAULT_TOKEN_ENDPOINT = 'https://dinoai.chatgo.pro/auth/v2/token';
|
|
3
3
|
export const POWERSYNC_DEFAULT_UPLOAD_BASE_URL = 'https://dinoai.chatgo.pro';
|
|
4
|
+
/** dinox-tool business API (semantic search, gateway credentials). */
|
|
5
|
+
export const AI_SERVICE_URL = 'https://aisdk.chatgo.pro';
|
package/dist/daemon/client.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { DaemonPingResult, DaemonShutdownResult } from './types.js';
|
|
2
2
|
export declare function sendDaemonRequest(method: string, params?: unknown, requestOptions?: {
|
|
3
3
|
timeoutMs?: number;
|
|
4
|
+
/** Streamed responses: called with each NDJSON frame ahead of the final response line. */
|
|
5
|
+
onFrame?: (frame: unknown) => void;
|
|
4
6
|
}): Promise<unknown>;
|
|
5
7
|
export declare function isDaemonRunning(timeoutMs?: number): Promise<boolean>;
|
|
6
8
|
/**
|
package/dist/daemon/client.js
CHANGED
|
@@ -66,8 +66,9 @@ export async function sendDaemonRequest(method, params, requestOptions = {}) {
|
|
|
66
66
|
};
|
|
67
67
|
const req = httpRequest(options, (res) => {
|
|
68
68
|
const statusCode = res.statusCode ?? 0;
|
|
69
|
-
|
|
69
|
+
let chunks = [];
|
|
70
70
|
let totalBytes = 0;
|
|
71
|
+
const { onFrame } = requestOptions;
|
|
71
72
|
res.on('data', (chunk) => {
|
|
72
73
|
totalBytes += chunk.length;
|
|
73
74
|
if (method !== 'command.execute' && totalBytes > MAX_DAEMON_RESPONSE_BYTES) {
|
|
@@ -75,6 +76,21 @@ export async function sendDaemonRequest(method, params, requestOptions = {}) {
|
|
|
75
76
|
return;
|
|
76
77
|
}
|
|
77
78
|
chunks.push(chunk);
|
|
79
|
+
if (!onFrame || !chunk.includes(0x0a))
|
|
80
|
+
return;
|
|
81
|
+
// Every complete line is a frame; the response itself is the unterminated last line.
|
|
82
|
+
let pending = Buffer.concat(chunks);
|
|
83
|
+
for (let newline = pending.indexOf(0x0a); newline !== -1; newline = pending.indexOf(0x0a)) {
|
|
84
|
+
const line = pending.subarray(0, newline).toString('utf-8');
|
|
85
|
+
pending = pending.subarray(newline + 1);
|
|
86
|
+
try {
|
|
87
|
+
onFrame(JSON.parse(line));
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// A malformed frame only loses that progress line.
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
chunks = [pending];
|
|
78
94
|
});
|
|
79
95
|
res.on('end', () => {
|
|
80
96
|
try {
|
|
@@ -97,8 +113,12 @@ export async function sendDaemonRequest(method, params, requestOptions = {}) {
|
|
|
97
113
|
});
|
|
98
114
|
});
|
|
99
115
|
req.on('socket', socket => {
|
|
100
|
-
|
|
116
|
+
// A reused keep-alive socket is already connected and never emits
|
|
117
|
+
// 'connect' again; listening anyway leaks one listener per request.
|
|
118
|
+
if (!socket.connecting) {
|
|
101
119
|
connected = true;
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
102
122
|
socket.once('connect', () => { connected = true; });
|
|
103
123
|
});
|
|
104
124
|
req.on('timeout', () => {
|
package/dist/daemon/forward.d.ts
CHANGED
|
@@ -30,5 +30,8 @@ export type ForwardDependencies = typeof forwardDependencies;
|
|
|
30
30
|
* the daemon could have received the request. A failure after that point
|
|
31
31
|
* throws DAEMON_UNAVAILABLE, never falls back, so a write is not applied twice.
|
|
32
32
|
*/
|
|
33
|
-
export declare function tryForwardToDaemon(argv: string[], overrides?: Partial<ForwardDependencies>
|
|
33
|
+
export declare function tryForwardToDaemon(argv: string[], overrides?: Partial<ForwardDependencies> & {
|
|
34
|
+
/** Receives `--progress` events live while the daemon runs the command. */
|
|
35
|
+
onProgress?: (text: string) => void;
|
|
36
|
+
}): Promise<CommandExecuteResult | null>;
|
|
34
37
|
export {};
|
package/dist/daemon/forward.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { loadConfig } from '../config/store.js';
|
|
3
3
|
import { resolveConfig } from '../config/resolve.js';
|
|
4
|
+
import { GLOBAL_VALUE_OPTIONS } from '../commands/schema/globalOptions.js';
|
|
4
5
|
import { DinoxError } from '../utils/errors.js';
|
|
5
6
|
import { printHumanReadableWarning } from '../utils/output.js';
|
|
6
7
|
import { parseSyncTimeoutMs } from '../utils/syncTimeout.js';
|
|
@@ -29,7 +30,7 @@ export function commandExecutionTarget(input) {
|
|
|
29
30
|
words.push(...argv.slice(i + 1));
|
|
30
31
|
break;
|
|
31
32
|
}
|
|
32
|
-
if (arg
|
|
33
|
+
if (GLOBAL_VALUE_OPTIONS.includes(arg)) {
|
|
33
34
|
i++;
|
|
34
35
|
continue;
|
|
35
36
|
}
|
|
@@ -66,7 +67,8 @@ const forwardDependencies = {
|
|
|
66
67
|
* throws DAEMON_UNAVAILABLE, never falls back, so a write is not applied twice.
|
|
67
68
|
*/
|
|
68
69
|
export async function tryForwardToDaemon(argv, overrides = {}) {
|
|
69
|
-
const
|
|
70
|
+
const { onProgress, ...dependencyOverrides } = overrides;
|
|
71
|
+
const deps = { ...forwardDependencies, ...dependencyOverrides };
|
|
70
72
|
if (commandExecutionTarget(argv) !== 'daemon' || /^(0|false|off|no)$/i.test(deps.env.DINOX_DAEMON ?? ''))
|
|
71
73
|
return null;
|
|
72
74
|
const fallback = (error) => {
|
|
@@ -106,8 +108,15 @@ export async function tryForwardToDaemon(argv, overrides = {}) {
|
|
|
106
108
|
}
|
|
107
109
|
const execute = async () => {
|
|
108
110
|
const result = await deps.sendDaemonRequest('command.execute', {
|
|
109
|
-
argv, cwd: deps.cwd(), clientVersion: deps.version(), requestId,
|
|
110
|
-
}, {
|
|
111
|
+
argv, cwd: deps.cwd(), clientVersion: deps.version(), requestId, ...(onProgress ? { stream: true } : {}),
|
|
112
|
+
}, {
|
|
113
|
+
timeoutMs,
|
|
114
|
+
...(onProgress ? { onFrame: (frame) => {
|
|
115
|
+
const text = frame?.progress;
|
|
116
|
+
if (typeof text === 'string')
|
|
117
|
+
onProgress(text);
|
|
118
|
+
} } : {}),
|
|
119
|
+
});
|
|
111
120
|
if (!result || typeof result.stdout !== 'string' || typeof result.stderr !== 'string' || !Number.isInteger(result.exitCode)) {
|
|
112
121
|
throw new Error('Invalid command.execute response');
|
|
113
122
|
}
|
package/dist/daemon/server.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export declare class DaemonServer {
|
|
|
37
37
|
onStopRequested?: (reason: string, details?: Record<string, unknown>) => void | Promise<void>;
|
|
38
38
|
});
|
|
39
39
|
initialize(): Promise<void>;
|
|
40
|
-
handleRequest(req: DaemonRequest): Promise<DaemonResponse>;
|
|
40
|
+
handleRequest(req: DaemonRequest, onProgress?: (text: string) => void): Promise<DaemonResponse>;
|
|
41
41
|
private isCacheStale;
|
|
42
42
|
start(port: number): Promise<void>;
|
|
43
43
|
stop(): Promise<void>;
|
package/dist/daemon/server.js
CHANGED
|
@@ -74,6 +74,9 @@ function validateLocalRequest(req) {
|
|
|
74
74
|
}
|
|
75
75
|
return { ok: true };
|
|
76
76
|
}
|
|
77
|
+
function isStreamedCommand(request) {
|
|
78
|
+
return request?.method === 'command.execute' && request.params?.stream === true;
|
|
79
|
+
}
|
|
77
80
|
export class DaemonServer {
|
|
78
81
|
options;
|
|
79
82
|
config = null;
|
|
@@ -144,7 +147,7 @@ export class DaemonServer {
|
|
|
144
147
|
// PowerSync keeps the local cache in sync continuously while connected,
|
|
145
148
|
// so no background polling loop is needed here.
|
|
146
149
|
}
|
|
147
|
-
async handleRequest(req) {
|
|
150
|
+
async handleRequest(req, onProgress) {
|
|
148
151
|
try {
|
|
149
152
|
if (!this.db) {
|
|
150
153
|
throw new Error('Database not initialized');
|
|
@@ -171,6 +174,7 @@ export class DaemonServer {
|
|
|
171
174
|
format: null,
|
|
172
175
|
noticeProvider: null,
|
|
173
176
|
cwd: input.cwd,
|
|
177
|
+
...(onProgress ? { onProgress } : {}),
|
|
174
178
|
daemon: {
|
|
175
179
|
db: this.db,
|
|
176
180
|
config: this.config,
|
|
@@ -316,12 +320,24 @@ export class DaemonServer {
|
|
|
316
320
|
}
|
|
317
321
|
try {
|
|
318
322
|
const daemonReq = await readJsonBody(req);
|
|
323
|
+
if (isStreamedCommand(daemonReq)) {
|
|
324
|
+
res.writeHead(200, { 'Content-Type': 'application/x-ndjson' });
|
|
325
|
+
const daemonRes = await this.handleRequest(daemonReq, (progress) => {
|
|
326
|
+
res.write(`${JSON.stringify({ progress })}\n`);
|
|
327
|
+
});
|
|
328
|
+
res.end(JSON.stringify(daemonRes));
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
319
331
|
const daemonRes = await this.handleRequest(daemonReq);
|
|
320
332
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
321
333
|
res.end(JSON.stringify(daemonRes));
|
|
322
334
|
}
|
|
323
335
|
catch (error) {
|
|
324
336
|
const message = error instanceof Error ? error.message : String(error);
|
|
337
|
+
if (res.headersSent) {
|
|
338
|
+
res.end(JSON.stringify({ ok: false, error: message }));
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
325
341
|
const statusCode = message.includes('too large') ? 413 : 400;
|
|
326
342
|
res.writeHead(statusCode, { 'Content-Type': 'application/json' });
|
|
327
343
|
res.end(JSON.stringify({ ok: false, error: message }));
|
package/dist/daemon/types.d.ts
CHANGED
|
@@ -57,6 +57,12 @@ export type CommandExecuteParams = {
|
|
|
57
57
|
cwd: string;
|
|
58
58
|
clientVersion: string;
|
|
59
59
|
requestId?: string;
|
|
60
|
+
/** Answer as NDJSON: `{"progress": text}` frames while the command runs, then the response. */
|
|
61
|
+
stream?: boolean;
|
|
62
|
+
};
|
|
63
|
+
/** A frame the daemon streams ahead of a `stream: true` response. */
|
|
64
|
+
export type CommandExecuteFrame = {
|
|
65
|
+
progress: string;
|
|
60
66
|
};
|
|
61
67
|
export type CommandExecuteResult = {
|
|
62
68
|
stdout: string;
|
package/dist/dinox.js
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { commandExecutionTarget, tryForwardToDaemon } from './daemon/forward.js';
|
|
3
|
+
import { applyDefaultFormat } from './utils/defaultFormat.js';
|
|
3
4
|
import { getPackageVersion } from './utils/version.js';
|
|
4
5
|
import { requestIdFromArgv, runWithRequestId } from './requests/store.js';
|
|
5
6
|
import { isDinoxError } from './utils/errors.js';
|
|
6
7
|
import { exitProcessAfterFlushing } from './utils/processExit.js';
|
|
7
|
-
import { localCommandExecution
|
|
8
|
-
|
|
8
|
+
import { localCommandExecution } from './utils/requestContext.js';
|
|
9
|
+
/** `--progress` before `--`: the daemon streams events back while it runs the command. */
|
|
10
|
+
function wantsProgress(args) {
|
|
11
|
+
const end = args.indexOf('--');
|
|
12
|
+
return (end === -1 ? args : args.slice(0, end)).includes('--progress');
|
|
13
|
+
}
|
|
14
|
+
let argv = process.argv.slice(2);
|
|
9
15
|
let fatalError;
|
|
10
16
|
try {
|
|
17
|
+
argv = applyDefaultFormat(argv);
|
|
11
18
|
const versionOnly = argv.length === 1 && ['--version', '-V'].includes(argv[0]);
|
|
12
19
|
const forwarded = versionOnly
|
|
13
20
|
? { stdout: `${getPackageVersion()}\n`, stderr: '', exitCode: 0 }
|
|
14
|
-
: await tryForwardToDaemon(argv);
|
|
21
|
+
: await tryForwardToDaemon(argv, wantsProgress(argv) ? { onProgress: (text) => process.stderr.write(text) } : {});
|
|
15
22
|
if (forwarded) {
|
|
16
23
|
process.stdout.write(forwarded.stdout);
|
|
17
24
|
process.stderr.write(forwarded.stderr);
|
|
@@ -21,13 +28,8 @@ try {
|
|
|
21
28
|
const { runCli } = await import('./runCli.js');
|
|
22
29
|
const key = requestIdFromArgv(argv);
|
|
23
30
|
if (key && commandExecutionTarget(argv) === 'daemon') {
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
stdout: [], stderr: [], format: null, noticeProvider: null, cwd: process.cwd(),
|
|
27
|
-
};
|
|
28
|
-
const exitCode = await requestContext.run(context, () => localCommandExecution.run(true, () => runCli(argv, error => { fatalError = error; })));
|
|
29
|
-
return { stdout: context.stdout.join(''), stderr: context.stderr.join(''), exitCode };
|
|
30
|
-
});
|
|
31
|
+
const { runCapturedInProcess } = await import('./requests/execute.js');
|
|
32
|
+
const result = await runWithRequestId(key, argv, () => runCapturedInProcess(argv, error => { fatalError = error; }));
|
|
31
33
|
process.stdout.write(result.stdout);
|
|
32
34
|
process.stderr.write(result.stderr);
|
|
33
35
|
process.exitCode = result.exitCode;
|
|
@@ -37,11 +37,15 @@ export declare class AcpGatewayAdapter implements GatewayAdapter {
|
|
|
37
37
|
* MCP servers offered to sessions as they are created or loaded, e.g. the
|
|
38
38
|
* Dinox tools; `sessionToken` lets their `send_file` reach this session.
|
|
39
39
|
*/
|
|
40
|
-
mcpServers?: (sessionToken: string) => McpServer[]);
|
|
40
|
+
mcpServers?: (sessionToken: string, cwd: string) => McpServer[]);
|
|
41
41
|
info(): GatewayAdapterInfo;
|
|
42
42
|
runTurn(input: GatewayTurnInput): Promise<GatewayTurnResult>;
|
|
43
43
|
sendFile(token: string, file: GatewayFileSource): Promise<GatewaySentFile> | null;
|
|
44
|
+
private catalogExpiresAt;
|
|
45
|
+
private catalogRevision;
|
|
46
|
+
private probing;
|
|
44
47
|
describeConfig(): Promise<GatewayConfigOption[]>;
|
|
48
|
+
private probeConfig;
|
|
45
49
|
dispose(): Promise<void>;
|
|
46
50
|
/** Codex leaves generated images on disk; send the ones this turn made when it sent nothing itself. */
|
|
47
51
|
private sendGeneratedImages;
|