@dinoxx/dinox-cli 1.0.22 → 1.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/README.md +29 -9
- package/dist/auth/userInfo.d.ts +2 -0
- package/dist/auth/userInfo.js +55 -14
- package/dist/cli.js +36 -2
- package/dist/commands/auth/index.d.ts +35 -0
- package/dist/commands/auth/index.js +382 -83
- package/dist/commands/boxes/index.js +2 -6
- package/dist/commands/boxes/model.d.ts +3 -0
- package/dist/commands/boxes/model.js +16 -1
- package/dist/commands/boxes/operations.js +18 -8
- package/dist/commands/boxes/repo.js +13 -11
- package/dist/commands/boxes/store.js +1 -1
- package/dist/commands/config/index.js +7 -5
- package/dist/commands/descriptor/register.js +9 -0
- package/dist/commands/doctor.d.ts +123 -0
- package/dist/commands/doctor.js +539 -0
- package/dist/commands/graph/index.d.ts +1 -1
- package/dist/commands/graph/index.js +35 -21
- package/dist/commands/graph/repo.js +92 -17
- package/dist/commands/meta/index.js +4 -4
- package/dist/commands/meta/repo.js +4 -3
- package/dist/commands/notes/actions.d.ts +1 -1
- package/dist/commands/notes/actions.js +121 -78
- package/dist/commands/notes/bulk.d.ts +1 -0
- package/dist/commands/notes/bulk.js +23 -17
- package/dist/commands/notes/contentEngine.js +69 -11
- package/dist/commands/notes/contentPatch.d.ts +4 -1
- package/dist/commands/notes/contentPatch.js +105 -41
- package/dist/commands/notes/contentPatchCommand.js +28 -11
- package/dist/commands/notes/descriptors.js +50 -20
- package/dist/commands/notes/dryRun.d.ts +1 -0
- package/dist/commands/notes/dryRun.js +4 -7
- package/dist/commands/notes/export.d.ts +6 -0
- package/dist/commands/notes/export.js +26 -6
- package/dist/commands/notes/metadataMutation.d.ts +1 -0
- package/dist/commands/notes/metadataMutation.js +14 -3
- package/dist/commands/notes/repo.d.ts +46 -4
- package/dist/commands/notes/repo.js +113 -28
- package/dist/commands/notes/runtime.d.ts +2 -1
- package/dist/commands/notes/runtime.js +17 -1
- package/dist/commands/notes/searchSql.js +13 -6
- package/dist/commands/notes/writeReceipt.d.ts +20 -0
- package/dist/commands/notes/writeReceipt.js +82 -0
- package/dist/commands/prompt/index.js +3 -3
- package/dist/commands/prompt/repo.d.ts +4 -1
- package/dist/commands/prompt/repo.js +17 -7
- package/dist/commands/runtime.d.ts +14 -2
- package/dist/commands/runtime.js +74 -15
- package/dist/commands/schema/renderSkills.js +5 -2
- package/dist/commands/schema/spec.js +4 -0
- package/dist/commands/storage/index.js +8 -2
- package/dist/commands/storage/repo.d.ts +4 -0
- package/dist/commands/storage/repo.js +356 -92
- package/dist/commands/sync.js +16 -12
- package/dist/commands/tags/content.js +9 -0
- package/dist/commands/tags/index.js +2 -6
- package/dist/commands/tags/operations.js +15 -10
- package/dist/commands/tags/repo.d.ts +2 -0
- package/dist/commands/tags/repo.js +18 -5
- package/dist/commands/tags/store.js +1 -1
- package/dist/commands/todo/contentModel.d.ts +4 -3
- package/dist/commands/todo/contentModel.js +78 -28
- package/dist/commands/todo/dryRun.d.ts +1 -0
- package/dist/commands/todo/dryRun.js +17 -13
- package/dist/commands/todo/index.d.ts +6 -0
- package/dist/commands/todo/index.js +89 -123
- package/dist/commands/todo/repo.d.ts +36 -1
- package/dist/commands/todo/repo.js +146 -37
- package/dist/commands/todo/taskIdentity.d.ts +2 -0
- package/dist/commands/todo/taskIdentity.js +64 -0
- package/dist/commands/todo/taskModel.js +27 -17
- package/dist/commands/update.d.ts +13 -1
- package/dist/commands/update.js +135 -23
- package/dist/commands/writeDryRun.d.ts +3 -2
- package/dist/commands/writeDryRun.js +4 -3
- package/dist/commands/writeDurability.d.ts +5 -0
- package/dist/commands/writeDurability.js +22 -0
- package/dist/config/paths.js +6 -1
- package/dist/config/resolve.d.ts +2 -0
- package/dist/config/resolve.js +23 -9
- package/dist/config/store.d.ts +3 -0
- package/dist/config/store.js +61 -14
- package/dist/config/types.d.ts +4 -0
- package/dist/daemon/client.d.ts +26 -1
- package/dist/daemon/client.js +236 -12
- package/dist/daemon/ensure.js +74 -12
- package/dist/daemon/index.d.ts +42 -0
- package/dist/daemon/index.js +202 -52
- package/dist/daemon/lifecycle.d.ts +42 -0
- package/dist/daemon/lifecycle.js +115 -0
- package/dist/daemon/pid.d.ts +19 -6
- package/dist/daemon/pid.js +147 -13
- package/dist/daemon/route.d.ts +14 -0
- package/dist/daemon/route.js +40 -0
- package/dist/daemon/server.d.ts +11 -0
- package/dist/daemon/server.js +201 -50
- package/dist/daemon/types.d.ts +29 -1
- package/dist/daemon/types.js +1 -0
- package/dist/dinox.js +25 -1
- package/dist/powersync/connector.js +31 -16
- package/dist/powersync/exclusiveRuntime.d.ts +19 -0
- package/dist/powersync/exclusiveRuntime.js +42 -0
- package/dist/powersync/runtime.d.ts +24 -4
- package/dist/powersync/runtime.js +234 -36
- package/dist/powersync/syncGate.d.ts +3 -1
- package/dist/powersync/syncGate.js +7 -1
- package/dist/powersync/tokenIndex.d.ts +11 -0
- package/dist/powersync/tokenIndex.js +159 -22
- package/dist/powersync/uploader.js +107 -52
- package/dist/utils/abort.js +0 -4
- package/dist/utils/asyncRelease.d.ts +2 -0
- package/dist/utils/asyncRelease.js +25 -0
- package/dist/utils/bidlinkCanonicalization.js +3 -0
- package/dist/utils/dryRun.d.ts +1 -1
- package/dist/utils/errors.d.ts +15 -1
- package/dist/utils/errors.js +223 -5
- package/dist/utils/output.d.ts +1 -0
- package/dist/utils/output.js +51 -15
- package/dist/utils/redact.js +1 -1
- package/dist/utils/sqliteLease.d.ts +8 -0
- package/dist/utils/sqliteLease.js +59 -0
- package/dist/utils/syncTimeout.d.ts +7 -1
- package/dist/utils/syncTimeout.js +8 -7
- package/dist/utils/terminalSanitization.js +6 -2
- package/dist/utils/tiptapMarkdown.js +49 -3
- package/dist/utils/tiptapMarkdownSyntax.d.ts +9 -0
- package/dist/utils/tiptapMarkdownSyntax.js +249 -0
- package/dist/utils/tokenize.js +24 -2
- package/dist/utils/updateNotice.js +60 -12
- package/package.json +12 -10
- package/dist/commands/mcp/auth.d.ts +0 -4
- package/dist/commands/mcp/auth.js +0 -75
- package/dist/commands/mcp/index.d.ts +0 -2
- package/dist/commands/mcp/index.js +0 -86
- package/dist/commands/mcp/noteContentTools.d.ts +0 -222
- package/dist/commands/mcp/noteContentTools.js +0 -390
- package/dist/commands/mcp/server.d.ts +0 -34
- package/dist/commands/mcp/server.js +0 -424
- package/dist/commands/mcp/tools.d.ts +0 -2
- package/dist/commands/mcp/tools.js +0 -32
- package/dist/commands/mcp/types.d.ts +0 -39
- package/dist/commands/mcp/types.js +0 -1
- package/dist/utils/noteContentEngine.d.ts +0 -333
- package/dist/utils/noteContentEngine.js +0 -740
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { withPowerSyncWriteTransaction } from '../../powersync/runtime.js';
|
|
2
2
|
import { DinoxError } from '../../utils/errors.js';
|
|
3
3
|
import { nowIsoUtc } from '../../utils/time.js';
|
|
4
|
-
import { MAX_BOX_NAME_LENGTH,
|
|
4
|
+
import { MAX_BOX_NAME_LENGTH, REQUIRED_NOTE_BOX_COLUMNS, assertBoxPathLimits, assertTextLimits, canonicalizeBoxPath, getLeafName, normalizeBoxLookupKey, parseStoredBoxIds, trimString, } from './model.js';
|
|
5
5
|
import { activeBoxNodes, activeNodeByPath, assertCanWriteBox, assertRequiredColumns, assertWritableBoxNodes, descendantsOf, ensureNoPathConflict, getTableColumns, isActiveBoxNode, isDescendantBoxPath, loadAllBoxNodes, requireActivePath, toBoxListItem, } from './store.js';
|
|
6
6
|
function buildSubtreeChanges(args) {
|
|
7
7
|
const newRootPath = canonicalizeBoxPath(args.newRootPath);
|
|
8
8
|
if (!newRootPath) {
|
|
9
9
|
throw new DinoxError('Target box path is required');
|
|
10
10
|
}
|
|
11
|
-
assertMaxLength('Box path', newRootPath, MAX_BOX_PATH_LENGTH);
|
|
12
11
|
const rootPrefix = `${args.root.path}/`;
|
|
13
12
|
return descendantsOf(args.nodes, args.root).map((node) => {
|
|
14
13
|
const suffix = node.id === args.root.id ? '' : node.path.slice(rootPrefix.length);
|
|
15
14
|
const toPath = suffix ? `${newRootPath}/${suffix}` : newRootPath;
|
|
15
|
+
assertBoxPathLimits(toPath, 'Target box path');
|
|
16
16
|
return {
|
|
17
17
|
id: node.id,
|
|
18
18
|
fromPath: node.path,
|
|
@@ -53,7 +53,8 @@ async function applySubtreePathChanges(args) {
|
|
|
53
53
|
UPDATE c_zettel_box
|
|
54
54
|
SET name = ?, path = ?, parent_id = ?, updated_at = ?
|
|
55
55
|
WHERE id = ?
|
|
56
|
-
|
|
56
|
+
AND TRIM(COALESCE(user_no, '')) = ?
|
|
57
|
+
`, [getLeafName(change.toPath), change.toPath, parentId, args.timestamp, change.id, args.userId]);
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
function parseRenameInput(input) {
|
|
@@ -66,7 +67,8 @@ function parseRenameInput(input) {
|
|
|
66
67
|
if (!newName || newName.includes('/')) {
|
|
67
68
|
throw new DinoxError('New box name must be a single path segment');
|
|
68
69
|
}
|
|
69
|
-
|
|
70
|
+
assertBoxPathLimits(path);
|
|
71
|
+
assertTextLimits('Box name', newName, MAX_BOX_NAME_LENGTH);
|
|
70
72
|
return { path, newName, userId };
|
|
71
73
|
}
|
|
72
74
|
function parseMoveInput(input) {
|
|
@@ -79,6 +81,8 @@ function parseMoveInput(input) {
|
|
|
79
81
|
if (!to) {
|
|
80
82
|
throw new DinoxError('Target parent path is required');
|
|
81
83
|
}
|
|
84
|
+
assertBoxPathLimits(path);
|
|
85
|
+
assertBoxPathLimits(to, 'Target parent path');
|
|
82
86
|
return { path, to, userId };
|
|
83
87
|
}
|
|
84
88
|
function parseMergeInput(input) {
|
|
@@ -91,6 +95,8 @@ function parseMergeInput(input) {
|
|
|
91
95
|
if (!to) {
|
|
92
96
|
throw new DinoxError('Target box path is required');
|
|
93
97
|
}
|
|
98
|
+
assertBoxPathLimits(from, 'Source box path');
|
|
99
|
+
assertBoxPathLimits(to, 'Target box path');
|
|
94
100
|
return { from, to, userId };
|
|
95
101
|
}
|
|
96
102
|
export async function getBoxTree(db, input = {}) {
|
|
@@ -127,13 +133,13 @@ async function loadNoteBoxRows(db, userId) {
|
|
|
127
133
|
FROM c_note
|
|
128
134
|
WHERE TRIM(COALESCE(id, '')) <> ''
|
|
129
135
|
AND (is_del IS NULL OR is_del = 0)
|
|
130
|
-
AND
|
|
136
|
+
AND TRIM(COALESCE(user_no, '')) = ?
|
|
131
137
|
`, [userId]);
|
|
132
138
|
}
|
|
133
139
|
async function loadNoteBoxStats(db, userId) {
|
|
134
140
|
const normalizedUserId = trimString(userId);
|
|
135
141
|
const userFilter = normalizedUserId
|
|
136
|
-
? `AND
|
|
142
|
+
? `AND TRIM(COALESCE(n.user_no, '')) = ?`
|
|
137
143
|
: '';
|
|
138
144
|
const rows = await db.getAll(`
|
|
139
145
|
SELECT
|
|
@@ -299,6 +305,7 @@ export async function renameBox(db, input, options = {}) {
|
|
|
299
305
|
nodes,
|
|
300
306
|
changes,
|
|
301
307
|
newRootParentId: root.parentId,
|
|
308
|
+
userId: parsed.userId,
|
|
302
309
|
timestamp: nowIsoUtc(),
|
|
303
310
|
});
|
|
304
311
|
});
|
|
@@ -331,6 +338,7 @@ export async function moveBox(db, input, options = {}) {
|
|
|
331
338
|
nodes,
|
|
332
339
|
changes,
|
|
333
340
|
newRootParentId: targetParent.id,
|
|
341
|
+
userId: parsed.userId,
|
|
334
342
|
timestamp: nowIsoUtc(),
|
|
335
343
|
});
|
|
336
344
|
});
|
|
@@ -393,14 +401,16 @@ export async function mergeBox(db, input, options = {}) {
|
|
|
393
401
|
UPDATE c_note
|
|
394
402
|
SET zettel_boxes = ?, updated_at = ?, version = COALESCE(version, 0) + 1
|
|
395
403
|
WHERE id = ?
|
|
396
|
-
|
|
404
|
+
AND TRIM(COALESCE(user_no, '')) = ?
|
|
405
|
+
`, [JSON.stringify(note.after), timestamp, note.id, parsed.userId]);
|
|
397
406
|
}
|
|
398
407
|
for (const boxId of softDeletedBoxIds) {
|
|
399
408
|
await tx.execute(`
|
|
400
409
|
UPDATE c_zettel_box
|
|
401
410
|
SET is_del = 1, updated_at = ?
|
|
402
411
|
WHERE id = ?
|
|
403
|
-
|
|
412
|
+
AND TRIM(COALESCE(user_no, '')) = ?
|
|
413
|
+
`, [timestamp, boxId, parsed.userId]);
|
|
404
414
|
}
|
|
405
415
|
});
|
|
406
416
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { generateId } from '../../utils/id.js';
|
|
2
2
|
import { DinoxError } from '../../utils/errors.js';
|
|
3
3
|
import { withPowerSyncWriteTransaction } from '../../powersync/runtime.js';
|
|
4
|
-
import { MAX_BOX_COLOR_LENGTH, MAX_BOX_DESCRIPTION_LENGTH, MAX_BOX_NAME_LENGTH,
|
|
4
|
+
import { MAX_BOX_COLOR_LENGTH, MAX_BOX_DESCRIPTION_LENGTH, MAX_BOX_NAME_LENGTH, assertBoxPathLimits, assertTextLimits, canonicalizeBoxPath, getLeafName, normalizeBoxLookupKey, toNullableId, trimString, } from './model.js';
|
|
5
5
|
import { assertCanWriteBox, getTableColumns } from './store.js';
|
|
6
6
|
export { canonicalizeBoxPath } from './model.js';
|
|
7
7
|
function normalizeLookupKey(value) {
|
|
@@ -16,10 +16,10 @@ function parseAddBoxInput(input) {
|
|
|
16
16
|
const name = getLeafName(path);
|
|
17
17
|
const description = trimString(input.description);
|
|
18
18
|
const color = trimString(input.color);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
assertBoxPathLimits(path);
|
|
20
|
+
assertTextLimits('Box name', name, MAX_BOX_NAME_LENGTH);
|
|
21
|
+
assertTextLimits('Box description', description, MAX_BOX_DESCRIPTION_LENGTH);
|
|
22
|
+
assertTextLimits('Box color', color, MAX_BOX_COLOR_LENGTH);
|
|
23
23
|
return {
|
|
24
24
|
userId,
|
|
25
25
|
path,
|
|
@@ -28,7 +28,7 @@ function parseAddBoxInput(input) {
|
|
|
28
28
|
color,
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
-
async function loadBoxNodesByPath(db) {
|
|
31
|
+
async function loadBoxNodesByPath(db, userId) {
|
|
32
32
|
const rows = await db.getAll(`
|
|
33
33
|
SELECT
|
|
34
34
|
TRIM(COALESCE(id, '')) AS id,
|
|
@@ -41,12 +41,13 @@ async function loadBoxNodesByPath(db) {
|
|
|
41
41
|
TRIM(COALESCE(user_no, '')) AS user_no
|
|
42
42
|
FROM c_zettel_box
|
|
43
43
|
WHERE TRIM(COALESCE(id, '')) <> ''
|
|
44
|
+
AND TRIM(COALESCE(user_no, '')) = ?
|
|
44
45
|
ORDER BY
|
|
45
46
|
CASE WHEN is_del IS NULL OR is_del = 0 THEN 0 ELSE 1 END ASC,
|
|
46
47
|
updated_at DESC,
|
|
47
48
|
created_at DESC,
|
|
48
49
|
id DESC
|
|
49
|
-
`, []);
|
|
50
|
+
`, [userId]);
|
|
50
51
|
const nodesByPath = new Map();
|
|
51
52
|
for (const row of rows) {
|
|
52
53
|
const id = trimString(row.id);
|
|
@@ -77,7 +78,7 @@ async function loadBoxNodesByPath(db) {
|
|
|
77
78
|
export async function listBoxes(db, input = {}) {
|
|
78
79
|
const userId = trimString(input.userId);
|
|
79
80
|
const userFilter = userId
|
|
80
|
-
? `AND
|
|
81
|
+
? `AND TRIM(COALESCE(user_no, '')) = ?`
|
|
81
82
|
: '';
|
|
82
83
|
const rows = await db.getAll(`
|
|
83
84
|
SELECT DISTINCT
|
|
@@ -158,7 +159,8 @@ async function restoreOrUpdateExistingBox(args) {
|
|
|
158
159
|
UPDATE c_zettel_box
|
|
159
160
|
SET ${assignments.join(', ')}
|
|
160
161
|
WHERE id = ?
|
|
161
|
-
|
|
162
|
+
AND TRIM(COALESCE(user_no, '')) = ?
|
|
163
|
+
`, [...params, userId]);
|
|
162
164
|
return wasDeleted;
|
|
163
165
|
}
|
|
164
166
|
async function insertBoxNode(args) {
|
|
@@ -186,7 +188,7 @@ export async function addBox(db, input) {
|
|
|
186
188
|
const parsed = parseAddBoxInput(input);
|
|
187
189
|
const columnNames = await getTableColumns(db, 'c_zettel_box');
|
|
188
190
|
assertCanWriteBox(columnNames, parsed.userId, 'insert');
|
|
189
|
-
const nodesByPath = await loadBoxNodesByPath(db);
|
|
191
|
+
const nodesByPath = await loadBoxNodesByPath(db, parsed.userId);
|
|
190
192
|
const existingLeaf = nodesByPath.get(normalizeLookupKey(parsed.path));
|
|
191
193
|
if (existingLeaf && existingLeaf.isDel !== 1) {
|
|
192
194
|
throw buildBoxExistsError(parsed.path, [existingLeaf.id]);
|
|
@@ -286,7 +288,7 @@ export async function inspectAddBox(db, input) {
|
|
|
286
288
|
const parsed = parseAddBoxInput(input);
|
|
287
289
|
const columnNames = await getTableColumns(db, 'c_zettel_box');
|
|
288
290
|
assertCanWriteBox(columnNames, parsed.userId, 'insert');
|
|
289
|
-
const nodesByPath = await loadBoxNodesByPath(db);
|
|
291
|
+
const nodesByPath = await loadBoxNodesByPath(db, parsed.userId);
|
|
290
292
|
const existingLeaf = nodesByPath.get(normalizeLookupKey(parsed.path));
|
|
291
293
|
if (existingLeaf && existingLeaf.isDel !== 1) {
|
|
292
294
|
throw buildBoxExistsError(parsed.path, [existingLeaf.id]);
|
|
@@ -20,7 +20,7 @@ export function assertCanWriteBox(columnNames, userId, action) {
|
|
|
20
20
|
export async function loadAllBoxNodes(db, options = {}) {
|
|
21
21
|
const userId = trimString(options.userId);
|
|
22
22
|
const userFilter = userId
|
|
23
|
-
? `AND
|
|
23
|
+
? `AND TRIM(COALESCE(user_no, '')) = ?`
|
|
24
24
|
: '';
|
|
25
25
|
const rows = await db.getAll(`
|
|
26
26
|
SELECT
|
|
@@ -5,6 +5,7 @@ import { FORMAT_OPTIONS } from '../schema/globalOptions.js';
|
|
|
5
5
|
import { DinoxError } from '../../utils/errors.js';
|
|
6
6
|
import { getRequestedStructuredOutputFormat, printSuccess } from '../../utils/output.js';
|
|
7
7
|
import { redactAuthorization } from '../../utils/redact.js';
|
|
8
|
+
import { MAX_SYNC_TIMEOUT_MS, parseSyncTimeoutMs } from '../../utils/syncTimeout.js';
|
|
8
9
|
export function sanitizeConfigForDisplay(config) {
|
|
9
10
|
if (!config || typeof config !== 'object' || Array.isArray(config)) {
|
|
10
11
|
return config;
|
|
@@ -13,6 +14,7 @@ export function sanitizeConfigForDisplay(config) {
|
|
|
13
14
|
const auth = clone?.auth;
|
|
14
15
|
if (auth && typeof auth === 'object') {
|
|
15
16
|
auth.authorization = redactAuthorization(auth.authorization);
|
|
17
|
+
delete auth.stateRevision;
|
|
16
18
|
}
|
|
17
19
|
delete clone.powersync;
|
|
18
20
|
return clone;
|
|
@@ -38,13 +40,13 @@ async function runConfigSet(context) {
|
|
|
38
40
|
throw new DinoxError(`Unknown config key: ${key}`);
|
|
39
41
|
}
|
|
40
42
|
if (key === 'sync.timeoutMs') {
|
|
41
|
-
const parsed =
|
|
42
|
-
if (
|
|
43
|
-
throw new DinoxError(
|
|
43
|
+
const parsed = parseSyncTimeoutMs(value, { label: 'sync.timeoutMs' });
|
|
44
|
+
if (parsed === undefined) {
|
|
45
|
+
throw new DinoxError(`sync.timeoutMs must be a positive integer no greater than ${MAX_SYNC_TIMEOUT_MS}`);
|
|
44
46
|
}
|
|
45
|
-
await setConfigValue(key,
|
|
47
|
+
await setConfigValue(key, parsed);
|
|
46
48
|
if (getRequestedStructuredOutputFormat()) {
|
|
47
|
-
printSuccess({ ok: true, key, value:
|
|
49
|
+
printSuccess({ ok: true, key, value: parsed });
|
|
48
50
|
}
|
|
49
51
|
return;
|
|
50
52
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { DinoxError } from '../../utils/errors.js';
|
|
2
|
+
import { getRequestedStructuredOutputFormat } from '../../utils/output.js';
|
|
1
3
|
import { toSchemaArgument, toSchemaOption } from './types.js';
|
|
2
4
|
function deriveArgumentKey(syntax) {
|
|
3
5
|
const normalized = syntax.trim().replace(/^[<[.]+|[>\].]+$/g, '');
|
|
@@ -64,6 +66,13 @@ export function registerCommandGroup(program, group) {
|
|
|
64
66
|
});
|
|
65
67
|
}
|
|
66
68
|
parent.action((_options, command) => {
|
|
69
|
+
if (getRequestedStructuredOutputFormat()) {
|
|
70
|
+
throw new DinoxError(`Missing subcommand for \`dino ${group.name}\``, {
|
|
71
|
+
code: 'USAGE_ERROR',
|
|
72
|
+
suggestion: `Run \`dino ${group.name} --help\` to list available subcommands.`,
|
|
73
|
+
recoverable: true,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
67
76
|
command.outputHelp();
|
|
68
77
|
});
|
|
69
78
|
return parent;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { hydrateResolvedAuthIdentity } from '../auth/userInfo.js';
|
|
3
|
+
import { loadConfig } from '../config/store.js';
|
|
4
|
+
import { resolveConfig } from '../config/resolve.js';
|
|
5
|
+
import type { ResolvedDinoxConfig } from '../config/types.js';
|
|
6
|
+
import { shutdownDaemonForExclusiveAccess } from '../daemon/client.js';
|
|
7
|
+
import { restartDaemonLocked } from '../daemon/index.js';
|
|
8
|
+
import { acquireDaemonStartLock } from '../daemon/pid.js';
|
|
9
|
+
import type { DaemonPidInfo } from '../daemon/pid.js';
|
|
10
|
+
import { type DaemonPingResult } from '../daemon/types.js';
|
|
11
|
+
import { connectPowerSync } from '../powersync/runtime.js';
|
|
12
|
+
import { type NoteTokenIndexInspection } from '../powersync/tokenIndex.js';
|
|
13
|
+
import type { CommandDescriptor, CommandExecutionContext } from './descriptor/types.js';
|
|
14
|
+
type HealthStatus = 'ok' | 'warn' | 'error' | 'skipped';
|
|
15
|
+
type DoctorFix = {
|
|
16
|
+
target: 'index' | 'upload_queue' | 'daemon';
|
|
17
|
+
status: HealthStatus;
|
|
18
|
+
message: string;
|
|
19
|
+
};
|
|
20
|
+
type DoctorPayload = {
|
|
21
|
+
ok: true;
|
|
22
|
+
healthy: boolean;
|
|
23
|
+
fixed: boolean;
|
|
24
|
+
auth: {
|
|
25
|
+
status: HealthStatus;
|
|
26
|
+
logged_in: boolean;
|
|
27
|
+
verified: boolean;
|
|
28
|
+
user_id: string | null;
|
|
29
|
+
username: string | null;
|
|
30
|
+
email: string | null;
|
|
31
|
+
error?: string;
|
|
32
|
+
};
|
|
33
|
+
sync: {
|
|
34
|
+
status: HealthStatus;
|
|
35
|
+
connected: boolean;
|
|
36
|
+
connecting: boolean;
|
|
37
|
+
has_synced: boolean;
|
|
38
|
+
last_synced_at: string | null;
|
|
39
|
+
upload_queue: number | null;
|
|
40
|
+
downloading: boolean;
|
|
41
|
+
uploading: boolean;
|
|
42
|
+
download_error?: {
|
|
43
|
+
name: string;
|
|
44
|
+
message: string;
|
|
45
|
+
};
|
|
46
|
+
upload_error?: {
|
|
47
|
+
name: string;
|
|
48
|
+
message: string;
|
|
49
|
+
};
|
|
50
|
+
error?: string;
|
|
51
|
+
};
|
|
52
|
+
index: NoteTokenIndexInspection & {
|
|
53
|
+
status: HealthStatus;
|
|
54
|
+
};
|
|
55
|
+
daemon: {
|
|
56
|
+
status: HealthStatus;
|
|
57
|
+
running: boolean;
|
|
58
|
+
pid: number | null;
|
|
59
|
+
port: number | null;
|
|
60
|
+
transport: 'socket';
|
|
61
|
+
socket_path: string | null;
|
|
62
|
+
version: string | null;
|
|
63
|
+
user_id: string | null;
|
|
64
|
+
authenticated: boolean | null;
|
|
65
|
+
version_match: boolean | null;
|
|
66
|
+
account_match: boolean | null;
|
|
67
|
+
token_match: boolean | null;
|
|
68
|
+
runtime_config_match: boolean | null;
|
|
69
|
+
error?: string;
|
|
70
|
+
};
|
|
71
|
+
db: {
|
|
72
|
+
status: HealthStatus;
|
|
73
|
+
path: string;
|
|
74
|
+
integrity: 'ok' | 'error' | 'unknown';
|
|
75
|
+
message?: string;
|
|
76
|
+
};
|
|
77
|
+
fixes: DoctorFix[];
|
|
78
|
+
issues: string[];
|
|
79
|
+
};
|
|
80
|
+
type DoctorRuntime = {
|
|
81
|
+
db: Awaited<ReturnType<typeof connectPowerSync>>['db'];
|
|
82
|
+
dbPath: string;
|
|
83
|
+
config: ResolvedDinoxConfig;
|
|
84
|
+
authError: string | null;
|
|
85
|
+
syncError: string | null;
|
|
86
|
+
offline: boolean;
|
|
87
|
+
timeoutMs: number;
|
|
88
|
+
releaseOwner: () => Promise<void>;
|
|
89
|
+
daemonBefore: DoctorDaemonSnapshot;
|
|
90
|
+
daemonWasStopped: boolean;
|
|
91
|
+
releaseDaemonStartLock: () => Promise<void>;
|
|
92
|
+
daemonStartLockReleased: boolean;
|
|
93
|
+
released: boolean;
|
|
94
|
+
};
|
|
95
|
+
type DoctorDaemonSnapshot = {
|
|
96
|
+
info: DaemonPingResult | null;
|
|
97
|
+
pidInfo: DaemonPidInfo | null;
|
|
98
|
+
socketExists: boolean;
|
|
99
|
+
};
|
|
100
|
+
type DoctorPreparationDependencies = {
|
|
101
|
+
loadConfig: typeof loadConfig;
|
|
102
|
+
resolveConfig: typeof resolveConfig;
|
|
103
|
+
hydrateAuthIdentity: typeof hydrateResolvedAuthIdentity;
|
|
104
|
+
acquireDaemonStartLock: typeof acquireDaemonStartLock;
|
|
105
|
+
captureDaemonSnapshot: typeof captureDaemonSnapshot;
|
|
106
|
+
shutdownDaemon: typeof shutdownDaemonForExclusiveAccess;
|
|
107
|
+
connectPowerSync: typeof connectPowerSync;
|
|
108
|
+
restartDaemon: typeof restartDaemonLocked;
|
|
109
|
+
};
|
|
110
|
+
export declare function prepareDoctorRuntime(context: CommandExecutionContext, overrides?: Partial<DoctorPreparationDependencies>): Promise<DoctorRuntime>;
|
|
111
|
+
declare function captureDaemonSnapshot(): Promise<DoctorDaemonSnapshot>;
|
|
112
|
+
export declare function applyDatabaseFixes(runtime: DoctorRuntime, payload: DoctorPayload): Promise<void>;
|
|
113
|
+
export declare function releaseDoctorRuntime(runtime: DoctorRuntime): Promise<void>;
|
|
114
|
+
export declare function releaseDoctorDaemonStartLock(runtime: DoctorRuntime): Promise<void>;
|
|
115
|
+
type DoctorDaemonDependencies = {
|
|
116
|
+
restart: typeof restartDaemonLocked;
|
|
117
|
+
capture: typeof captureDaemonSnapshot;
|
|
118
|
+
};
|
|
119
|
+
export declare function applyDoctorDaemonLifecycle(runtime: DoctorRuntime, payload: DoctorPayload, fixRequested: boolean, dependencies?: DoctorDaemonDependencies): Promise<void>;
|
|
120
|
+
export declare function finalizeDoctorPayload(payload: DoctorPayload): DoctorPayload;
|
|
121
|
+
export declare const doctorCommandDescriptor: CommandDescriptor;
|
|
122
|
+
export declare function registerDoctorCommand(program: Command): void;
|
|
123
|
+
export {};
|