@dinoxx/dinox-cli 1.1.1 → 2.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.
Files changed (141) hide show
  1. package/README.md +44 -3
  2. package/dist/cli.js +4 -0
  3. package/dist/commands/auth/index.js +1 -2
  4. package/dist/commands/boxes/index.js +37 -13
  5. package/dist/commands/boxes/operations.d.ts +3 -3
  6. package/dist/commands/boxes/operations.js +51 -28
  7. package/dist/commands/info/index.js +30 -5
  8. package/dist/commands/meta/repo.js +2 -1
  9. package/dist/commands/notes/actions.js +20 -37
  10. package/dist/commands/notes/bulk.d.ts +2 -2
  11. package/dist/commands/notes/bulk.js +3 -18
  12. package/dist/commands/notes/contentPatch.d.ts +5 -1
  13. package/dist/commands/notes/contentPatch.js +12 -1
  14. package/dist/commands/notes/contentPatchCommand.d.ts +3 -0
  15. package/dist/commands/notes/contentPatchCommand.js +29 -8
  16. package/dist/commands/notes/descriptors.js +19 -16
  17. package/dist/commands/notes/export.js +3 -0
  18. package/dist/commands/notes/repo/read.d.ts +8 -0
  19. package/dist/commands/notes/repo/read.js +321 -0
  20. package/dist/commands/notes/repo/resolve.d.ts +8 -0
  21. package/dist/commands/notes/repo/resolve.js +187 -0
  22. package/dist/commands/notes/repo/search.d.ts +42 -0
  23. package/dist/commands/notes/repo/search.js +513 -0
  24. package/dist/commands/notes/repo/shared.d.ts +190 -0
  25. package/dist/commands/notes/repo/shared.js +102 -0
  26. package/dist/commands/notes/repo/write.d.ts +24 -0
  27. package/dist/commands/notes/repo/write.js +251 -0
  28. package/dist/commands/notes/repo.d.ts +7 -177
  29. package/dist/commands/notes/repo.js +7 -1310
  30. package/dist/commands/notes/searchOutput.d.ts +2 -1
  31. package/dist/commands/notes/searchOutput.js +2 -1
  32. package/dist/commands/notes/searchSql.js +9 -3
  33. package/dist/commands/prompt/index.d.ts +1 -0
  34. package/dist/commands/prompt/index.js +26 -11
  35. package/dist/commands/savedViews/index.d.ts +7 -0
  36. package/dist/commands/savedViews/index.js +458 -0
  37. package/dist/commands/savedViews/model.d.ts +87 -0
  38. package/dist/commands/savedViews/model.js +306 -0
  39. package/dist/commands/savedViews/repo.d.ts +123 -0
  40. package/dist/commands/savedViews/repo.js +512 -0
  41. package/dist/commands/savedViews/semantics.d.ts +46 -0
  42. package/dist/commands/savedViews/semantics.js +738 -0
  43. package/dist/commands/schema/commandMetadata.js +4 -4
  44. package/dist/commands/schema/index.d.ts +1 -0
  45. package/dist/commands/schema/index.js +23 -2
  46. package/dist/commands/schema/renderSkills.d.ts +6 -0
  47. package/dist/commands/schema/renderSkills.js +109 -11
  48. package/dist/commands/schema/spec.js +4 -0
  49. package/dist/commands/skills/index.d.ts +80 -0
  50. package/dist/commands/skills/index.js +572 -0
  51. package/dist/commands/storage/index.js +2 -2
  52. package/dist/commands/storage/repo/configs.d.ts +30 -0
  53. package/dist/commands/storage/repo/configs.js +259 -0
  54. package/dist/commands/storage/repo/operations.d.ts +25 -0
  55. package/dist/commands/storage/repo/operations.js +337 -0
  56. package/dist/commands/storage/repo/remote.d.ts +32 -0
  57. package/dist/commands/storage/repo/remote.js +132 -0
  58. package/dist/commands/storage/repo/resources.d.ts +12 -0
  59. package/dist/commands/storage/repo/resources.js +134 -0
  60. package/dist/commands/storage/repo/shared.d.ts +181 -0
  61. package/dist/commands/storage/repo/shared.js +36 -0
  62. package/dist/commands/storage/repo/targets.d.ts +12 -0
  63. package/dist/commands/storage/repo/targets.js +178 -0
  64. package/dist/commands/storage/repo.d.ts +3 -166
  65. package/dist/commands/storage/repo.js +4 -1034
  66. package/dist/commands/sync.js +2 -1
  67. package/dist/commands/tags/index.js +30 -11
  68. package/dist/commands/tags/operations.d.ts +3 -3
  69. package/dist/commands/tags/operations.js +45 -20
  70. package/dist/commands/templates/model.d.ts +50 -0
  71. package/dist/commands/templates/model.js +239 -0
  72. package/dist/commands/todo/index.js +3 -3
  73. package/dist/commands/update.d.ts +1 -0
  74. package/dist/commands/update.js +46 -9
  75. package/dist/commands/writeConfirmation.d.ts +13 -0
  76. package/dist/commands/writeConfirmation.js +54 -0
  77. package/dist/config/resolve.js +5 -10
  78. package/dist/config/types.d.ts +3 -6
  79. package/dist/constants/links.d.ts +18 -1
  80. package/dist/constants/links.js +26 -1
  81. package/dist/contract/snapshot.d.ts +30 -0
  82. package/dist/contract/snapshot.js +114 -0
  83. package/dist/daemon/client.d.ts +2 -2
  84. package/dist/daemon/client.js +108 -54
  85. package/dist/daemon/index.d.ts +5 -3
  86. package/dist/daemon/index.js +28 -5
  87. package/dist/daemon/lifecycle.d.ts +7 -2
  88. package/dist/daemon/lifecycle.js +53 -13
  89. package/dist/daemon/pid.d.ts +1 -1
  90. package/dist/daemon/pid.js +6 -3
  91. package/dist/dinox.js +9 -1
  92. package/dist/powersync/exclusiveRuntime.d.ts +1 -0
  93. package/dist/powersync/exclusiveRuntime.js +26 -8
  94. package/dist/powersync/runtime.d.ts +3 -2
  95. package/dist/powersync/runtime.js +19 -3
  96. package/dist/powersync/schema/content.d.ts +1 -78
  97. package/dist/powersync/schema/content.js +1 -78
  98. package/dist/powersync/schema/electronCanonical.d.ts +1561 -0
  99. package/dist/powersync/schema/electronCanonical.js +1154 -0
  100. package/dist/powersync/schema/index.d.ts +573 -129
  101. package/dist/powersync/schema/index.js +3 -32
  102. package/dist/powersync/schema/local.d.ts +1 -56
  103. package/dist/powersync/schema/local.js +1 -60
  104. package/dist/powersync/schema/note.d.ts +1 -35
  105. package/dist/powersync/schema/note.js +1 -35
  106. package/dist/powersync/schema/notesExtras.d.ts +1 -62
  107. package/dist/powersync/schema/notesExtras.js +1 -71
  108. package/dist/powersync/schema/projects.d.ts +1 -104
  109. package/dist/powersync/schema/projects.js +1 -104
  110. package/dist/powersync/schema/savedViews.d.ts +1 -0
  111. package/dist/powersync/schema/savedViews.js +1 -0
  112. package/dist/powersync/schema/storage.d.ts +1 -24
  113. package/dist/powersync/schema/storage.js +1 -24
  114. package/dist/powersync/schema/tags.d.ts +1 -37
  115. package/dist/powersync/schema/tags.js +1 -37
  116. package/dist/powersync/syncGate.d.ts +20 -2
  117. package/dist/powersync/uploader.d.ts +16 -2
  118. package/dist/powersync/uploader.js +152 -158
  119. package/dist/skills/check.d.ts +1 -0
  120. package/dist/skills/check.js +538 -70
  121. package/dist/skills/commandRefs.d.ts +21 -0
  122. package/dist/skills/commandRefs.js +132 -0
  123. package/dist/skills/generate.d.ts +13 -0
  124. package/dist/skills/generate.js +80 -0
  125. package/dist/skills/registry.d.ts +13 -0
  126. package/dist/skills/registry.js +58 -0
  127. package/dist/skills/retired.d.ts +60 -0
  128. package/dist/skills/retired.js +58 -0
  129. package/dist/utils/deadline.d.ts +8 -0
  130. package/dist/utils/deadline.js +31 -0
  131. package/dist/utils/dryRun.d.ts +20 -1
  132. package/dist/utils/dryRun.js +22 -3
  133. package/dist/utils/errorCodes.d.ts +311 -0
  134. package/dist/utils/errorCodes.js +92 -0
  135. package/dist/utils/errors.d.ts +15 -2
  136. package/dist/utils/errors.js +13 -0
  137. package/dist/utils/processExit.d.ts +1 -0
  138. package/dist/utils/processExit.js +33 -0
  139. package/dist/utils/updateNotice.d.ts +1 -0
  140. package/dist/utils/updateNotice.js +1 -1
  141. package/package.json +18 -8
@@ -0,0 +1,311 @@
1
+ export type ErrorCodeDefinition = Readonly<{
2
+ exitCode: 1 | 2 | 3 | 4 | 5;
3
+ description: string;
4
+ }>;
5
+ export declare const ERROR_CODES: {
6
+ readonly ALREADY_EXISTS: {
7
+ readonly exitCode: 5;
8
+ readonly description: "The target resource already exists.";
9
+ };
10
+ readonly AUTH_INVALID: {
11
+ readonly exitCode: 3;
12
+ readonly description: "The configured credentials were rejected.";
13
+ };
14
+ readonly AUTH_REQUIRED: {
15
+ readonly exitCode: 3;
16
+ readonly description: "The command needs an authenticated Dinox account.";
17
+ };
18
+ readonly AUTH_STATE_CHANGED: {
19
+ readonly exitCode: 3;
20
+ readonly description: "Authentication changed while the command was running.";
21
+ };
22
+ readonly CACHE_CLEANUP_FAILED: {
23
+ readonly exitCode: 1;
24
+ readonly description: "Local cache cleanup after logout did not complete.";
25
+ };
26
+ readonly COMMAND_FAILED: {
27
+ readonly exitCode: 1;
28
+ readonly description: "Generic command failure without a more specific code.";
29
+ };
30
+ readonly CONFIG_INVALID_JSON: {
31
+ readonly exitCode: 1;
32
+ readonly description: "The CLI config file is not valid JSON.";
33
+ };
34
+ readonly CONFIG_WRITE_BUSY: {
35
+ readonly exitCode: 1;
36
+ readonly description: "Another process is writing the CLI config.";
37
+ };
38
+ readonly DAEMON_ERROR: {
39
+ readonly exitCode: 5;
40
+ readonly description: "The background daemon reported an error.";
41
+ };
42
+ readonly DAEMON_INSTANCE_CHANGED: {
43
+ readonly exitCode: 1;
44
+ readonly description: "The daemon instance changed between requests.";
45
+ };
46
+ readonly DAEMON_INSTANCE_MISMATCH: {
47
+ readonly exitCode: 1;
48
+ readonly description: "The running daemon belongs to a different CLI version or account.";
49
+ };
50
+ readonly DAEMON_INSTANCE_UNKNOWN: {
51
+ readonly exitCode: 1;
52
+ readonly description: "The daemon identity could not be verified.";
53
+ };
54
+ readonly DAEMON_LEGACY_UNVERIFIED: {
55
+ readonly exitCode: 1;
56
+ readonly description: "A daemon from an older CLI could not be verified safely.";
57
+ };
58
+ readonly DAEMON_RELEASE_FAILED: {
59
+ readonly exitCode: 1;
60
+ readonly description: "The daemon could not release database ownership.";
61
+ };
62
+ readonly DAEMON_RELEASE_TIMEOUT: {
63
+ readonly exitCode: 1;
64
+ readonly description: "The daemon did not release database ownership in time.";
65
+ };
66
+ readonly DAEMON_STALE: {
67
+ readonly exitCode: 5;
68
+ readonly description: "The daemon state is stale and needs a restart.";
69
+ };
70
+ readonly DAEMON_START_FAILED: {
71
+ readonly exitCode: 5;
72
+ readonly description: "The daemon process failed to start.";
73
+ };
74
+ readonly DAEMON_START_TIMEOUT: {
75
+ readonly exitCode: 1;
76
+ readonly description: "The daemon did not become ready in time.";
77
+ };
78
+ readonly DAEMON_STOP_FAILED: {
79
+ readonly exitCode: 1;
80
+ readonly description: "The daemon could not be stopped.";
81
+ };
82
+ readonly DAEMON_UNAVAILABLE: {
83
+ readonly exitCode: 1;
84
+ readonly description: "The daemon is not available for this request.";
85
+ };
86
+ readonly DAEMON_UNREACHABLE: {
87
+ readonly exitCode: 1;
88
+ readonly description: "The daemon socket could not be reached.";
89
+ };
90
+ readonly INTERNAL_ERROR: {
91
+ readonly exitCode: 1;
92
+ readonly description: "Unexpected internal error; not a DinoxError.";
93
+ };
94
+ readonly INVALID_ARGUMENT: {
95
+ readonly exitCode: 2;
96
+ readonly description: "An argument or option value is invalid.";
97
+ };
98
+ readonly INVALID_STORAGE_KEY: {
99
+ readonly exitCode: 2;
100
+ readonly description: "The storage object key is invalid.";
101
+ };
102
+ readonly NOTE_INVALID_PROPERTIES: {
103
+ readonly exitCode: 1;
104
+ readonly description: "Note properties are invalid.";
105
+ };
106
+ readonly NOTE_NOT_FOUND: {
107
+ readonly exitCode: 5;
108
+ readonly description: "The note does not exist or is deleted.";
109
+ };
110
+ readonly NOTE_TEMPLATE_INVALID_CONTENT: {
111
+ readonly exitCode: 1;
112
+ readonly description: "The note template content is invalid.";
113
+ };
114
+ readonly NOTE_TEMPLATE_INVALID_PROPERTY_DEF: {
115
+ readonly exitCode: 1;
116
+ readonly description: "A note template property definition is invalid.";
117
+ };
118
+ readonly NOTE_TEMPLATE_INVALID_TOKEN_CONTEXT: {
119
+ readonly exitCode: 1;
120
+ readonly description: "A note template token is used in an invalid context.";
121
+ };
122
+ readonly NOTE_TEMPLATE_UNSUPPORTED_PROPERTY_DEF_VERSION: {
123
+ readonly exitCode: 1;
124
+ readonly description: "The note template property definition version is unsupported.";
125
+ };
126
+ readonly NOT_FOUND: {
127
+ readonly exitCode: 5;
128
+ readonly description: "The requested resource was not found.";
129
+ };
130
+ readonly POWERSYNC_OWNER_BUSY: {
131
+ readonly exitCode: 1;
132
+ readonly description: "Another process owns the local PowerSync database.";
133
+ };
134
+ readonly PRECONDITION_FAILED: {
135
+ readonly exitCode: 5;
136
+ readonly description: "A safety precondition for the operation did not hold.";
137
+ };
138
+ readonly SAVED_VIEW_FILTER_TOO_COMPLEX: {
139
+ readonly exitCode: 1;
140
+ readonly description: "The saved view filter exceeds supported complexity.";
141
+ };
142
+ readonly SAVED_VIEW_FILTER_VALUE_REQUIRED: {
143
+ readonly exitCode: 5;
144
+ readonly description: "A saved view filter condition is missing its value.";
145
+ };
146
+ readonly SAVED_VIEW_INVALID_CONFIG: {
147
+ readonly exitCode: 1;
148
+ readonly description: "The saved view config is invalid.";
149
+ };
150
+ readonly SAVED_VIEW_INVALID_DATE_VALUE: {
151
+ readonly exitCode: 1;
152
+ readonly description: "A saved view date value is not a real calendar date.";
153
+ };
154
+ readonly SAVED_VIEW_INVALID_FIELD: {
155
+ readonly exitCode: 1;
156
+ readonly description: "A saved view references an invalid field.";
157
+ };
158
+ readonly SAVED_VIEW_INVALID_FILTER: {
159
+ readonly exitCode: 1;
160
+ readonly description: "The saved view filter is invalid.";
161
+ };
162
+ readonly SAVED_VIEW_INVALID_ROW: {
163
+ readonly exitCode: 1;
164
+ readonly description: "A stored saved view row is invalid.";
165
+ };
166
+ readonly SAVED_VIEW_NOT_FOUND: {
167
+ readonly exitCode: 5;
168
+ readonly description: "The saved view does not exist.";
169
+ };
170
+ readonly SAVED_VIEW_OPERATOR_TYPE_MISMATCH: {
171
+ readonly exitCode: 1;
172
+ readonly description: "A filter operator is not valid for the field type.";
173
+ };
174
+ readonly SAVED_VIEW_OPTION_NOT_FOUND: {
175
+ readonly exitCode: 5;
176
+ readonly description: "A select option id referenced by the view does not exist.";
177
+ };
178
+ readonly SAVED_VIEW_PROPERTY_CONFIG_INVALID: {
179
+ readonly exitCode: 1;
180
+ readonly description: "A property configuration used by the view is invalid.";
181
+ };
182
+ readonly SAVED_VIEW_PROPERTY_INVALID: {
183
+ readonly exitCode: 1;
184
+ readonly description: "A property used by the view is invalid.";
185
+ };
186
+ readonly SAVED_VIEW_PROPERTY_NOT_FOUND: {
187
+ readonly exitCode: 5;
188
+ readonly description: "A property referenced by the view does not exist.";
189
+ };
190
+ readonly SAVED_VIEW_PROPERTY_OPTIONS_INVALID: {
191
+ readonly exitCode: 1;
192
+ readonly description: "Property options used by the view are invalid.";
193
+ };
194
+ readonly SAVED_VIEW_PROPERTY_OPTIONS_MIGRATION_REQUIRED: {
195
+ readonly exitCode: 5;
196
+ readonly description: "Property options need migration before use.";
197
+ };
198
+ readonly SAVED_VIEW_SORT_TYPE_UNSUPPORTED: {
199
+ readonly exitCode: 1;
200
+ readonly description: "The field type cannot be sorted.";
201
+ };
202
+ readonly SAVED_VIEW_UNSUPPORTED_CONFIG_VERSION: {
203
+ readonly exitCode: 1;
204
+ readonly description: "The saved view config version is unsupported.";
205
+ };
206
+ readonly SAVED_VIEW_UNSUPPORTED_FILTER_VERSION: {
207
+ readonly exitCode: 1;
208
+ readonly description: "The saved view filter version is unsupported.";
209
+ };
210
+ readonly SAVED_VIEW_UNSUPPORTED_LAYOUT: {
211
+ readonly exitCode: 1;
212
+ readonly description: "The saved view layout is unsupported.";
213
+ };
214
+ readonly SAVED_VIEW_VALUE_TYPE_MISMATCH: {
215
+ readonly exitCode: 1;
216
+ readonly description: "A filter value does not match the field type.";
217
+ };
218
+ readonly SCHEMA_PATH_NOT_FOUND: {
219
+ readonly exitCode: 5;
220
+ readonly description: "No command schema exists for the requested path.";
221
+ };
222
+ readonly SKILLS_LOCK_INVALID: {
223
+ readonly exitCode: 1;
224
+ readonly description: "The skills installer lock file is malformed.";
225
+ };
226
+ readonly SKILLS_LOCK_READ_FAILED: {
227
+ readonly exitCode: 1;
228
+ readonly description: "The skills installer lock file could not be read.";
229
+ };
230
+ readonly SKILLS_MIGRATION_FAILED: {
231
+ readonly exitCode: 1;
232
+ readonly description: "The skills installer failed during migration.";
233
+ };
234
+ readonly SKILLS_MIGRATION_PRECONDITION_FAILED: {
235
+ readonly exitCode: 1;
236
+ readonly description: "The skills lock changed before migration ran.";
237
+ };
238
+ readonly SKILLS_MIGRATION_VERIFICATION_FAILED: {
239
+ readonly exitCode: 1;
240
+ readonly description: "Post-migration verification did not match the plan.";
241
+ };
242
+ readonly STORAGE_IMAGE_PROCESSING_UNAVAILABLE: {
243
+ readonly exitCode: 1;
244
+ readonly description: "The optional sharp image library is unavailable, so image uploads are refused.";
245
+ };
246
+ readonly STORAGE_OBJECT_ALREADY_EXISTS: {
247
+ readonly exitCode: 5;
248
+ readonly description: "The storage object already exists; overwrite was not confirmed.";
249
+ };
250
+ readonly STORAGE_RESOURCE_INSERT_FAILED: {
251
+ readonly exitCode: 1;
252
+ readonly description: "The uploaded object could not be recorded as a resource.";
253
+ };
254
+ readonly STORAGE_TEST_CLEANUP_FAILED: {
255
+ readonly exitCode: 1;
256
+ readonly description: "The storage connectivity test object could not be removed.";
257
+ };
258
+ readonly STORAGE_THUMBNAIL_UPLOAD_FAILED: {
259
+ readonly exitCode: 1;
260
+ readonly description: "The thumbnail upload failed.";
261
+ };
262
+ readonly STORAGE_UPLOAD_OUTCOME_UNKNOWN: {
263
+ readonly exitCode: 1;
264
+ readonly description: "The upload outcome is unknown; verify before retrying.";
265
+ };
266
+ readonly SYNC_REQUIRED: {
267
+ readonly exitCode: 4;
268
+ readonly description: "Fresh sync was required (--require-sync) but not confirmed.";
269
+ };
270
+ readonly SYNC_STALE: {
271
+ readonly exitCode: 4;
272
+ readonly description: "The local cache is stale.";
273
+ };
274
+ readonly SYNC_TIMEOUT: {
275
+ readonly exitCode: 4;
276
+ readonly description: "Sync did not complete within the timeout.";
277
+ };
278
+ readonly TODO_TASK_LOOKUP_TRUNCATED: {
279
+ readonly exitCode: 1;
280
+ readonly description: "Task lookup hit its scan limit; pass --note-id.";
281
+ };
282
+ readonly TODO_TASK_NOT_FOUND: {
283
+ readonly exitCode: 5;
284
+ readonly description: "The todo task does not exist.";
285
+ };
286
+ readonly UNAUTHENTICATED: {
287
+ readonly exitCode: 3;
288
+ readonly description: "The backend rejected the request as unauthenticated.";
289
+ };
290
+ readonly UNSUPPORTED_CRUD_OPERATION: {
291
+ readonly exitCode: 1;
292
+ readonly description: "A queued upload contains an unsupported operation.";
293
+ };
294
+ readonly UPDATE_FAILED: {
295
+ readonly exitCode: 1;
296
+ readonly description: "The CLI self-update failed.";
297
+ };
298
+ readonly UPLOAD_PENDING: {
299
+ readonly exitCode: 4;
300
+ readonly description: "Local writes are still waiting to upload.";
301
+ };
302
+ readonly USAGE_ERROR: {
303
+ readonly exitCode: 2;
304
+ readonly description: "Invalid command usage, arguments, or flags.";
305
+ };
306
+ };
307
+ export type DinoxErrorCode = keyof typeof ERROR_CODES;
308
+ export declare function isRegisteredErrorCode(code: string): code is DinoxErrorCode;
309
+ export declare function listErrorCodes(): Array<{
310
+ code: DinoxErrorCode;
311
+ } & ErrorCodeDefinition>;
@@ -0,0 +1,92 @@
1
+ // Registry of every structured error `code` the CLI can emit. Agents branch on
2
+ // these codes, so they are part of the public contract: add new codes here,
3
+ // never rename or re-number an existing one without a major version.
4
+ //
5
+ // Exit codes: 1 failure, 2 usage, 3 auth, 4 sync freshness, 5 precondition / not found.
6
+ // They are pinned per code (not derived from the name) so that renaming or
7
+ // adding a code cannot silently change an exit status.
8
+ export const ERROR_CODES = {
9
+ ALREADY_EXISTS: { exitCode: 5, description: 'The target resource already exists.' },
10
+ AUTH_INVALID: { exitCode: 3, description: 'The configured credentials were rejected.' },
11
+ AUTH_REQUIRED: { exitCode: 3, description: 'The command needs an authenticated Dinox account.' },
12
+ AUTH_STATE_CHANGED: { exitCode: 3, description: 'Authentication changed while the command was running.' },
13
+ CACHE_CLEANUP_FAILED: { exitCode: 1, description: 'Local cache cleanup after logout did not complete.' },
14
+ COMMAND_FAILED: { exitCode: 1, description: 'Generic command failure without a more specific code.' },
15
+ CONFIG_INVALID_JSON: { exitCode: 1, description: 'The CLI config file is not valid JSON.' },
16
+ CONFIG_WRITE_BUSY: { exitCode: 1, description: 'Another process is writing the CLI config.' },
17
+ DAEMON_ERROR: { exitCode: 5, description: 'The background daemon reported an error.' },
18
+ DAEMON_INSTANCE_CHANGED: { exitCode: 1, description: 'The daemon instance changed between requests.' },
19
+ DAEMON_INSTANCE_MISMATCH: { exitCode: 1, description: 'The running daemon belongs to a different CLI version or account.' },
20
+ DAEMON_INSTANCE_UNKNOWN: { exitCode: 1, description: 'The daemon identity could not be verified.' },
21
+ DAEMON_LEGACY_UNVERIFIED: { exitCode: 1, description: 'A daemon from an older CLI could not be verified safely.' },
22
+ DAEMON_RELEASE_FAILED: { exitCode: 1, description: 'The daemon could not release database ownership.' },
23
+ DAEMON_RELEASE_TIMEOUT: { exitCode: 1, description: 'The daemon did not release database ownership in time.' },
24
+ DAEMON_STALE: { exitCode: 5, description: 'The daemon state is stale and needs a restart.' },
25
+ DAEMON_START_FAILED: { exitCode: 5, description: 'The daemon process failed to start.' },
26
+ DAEMON_START_TIMEOUT: { exitCode: 1, description: 'The daemon did not become ready in time.' },
27
+ DAEMON_STOP_FAILED: { exitCode: 1, description: 'The daemon could not be stopped.' },
28
+ DAEMON_UNAVAILABLE: { exitCode: 1, description: 'The daemon is not available for this request.' },
29
+ DAEMON_UNREACHABLE: { exitCode: 1, description: 'The daemon socket could not be reached.' },
30
+ INTERNAL_ERROR: { exitCode: 1, description: 'Unexpected internal error; not a DinoxError.' },
31
+ INVALID_ARGUMENT: { exitCode: 2, description: 'An argument or option value is invalid.' },
32
+ INVALID_STORAGE_KEY: { exitCode: 2, description: 'The storage object key is invalid.' },
33
+ NOTE_INVALID_PROPERTIES: { exitCode: 1, description: 'Note properties are invalid.' },
34
+ NOTE_NOT_FOUND: { exitCode: 5, description: 'The note does not exist or is deleted.' },
35
+ NOTE_TEMPLATE_INVALID_CONTENT: { exitCode: 1, description: 'The note template content is invalid.' },
36
+ NOTE_TEMPLATE_INVALID_PROPERTY_DEF: { exitCode: 1, description: 'A note template property definition is invalid.' },
37
+ NOTE_TEMPLATE_INVALID_TOKEN_CONTEXT: { exitCode: 1, description: 'A note template token is used in an invalid context.' },
38
+ NOTE_TEMPLATE_UNSUPPORTED_PROPERTY_DEF_VERSION: { exitCode: 1, description: 'The note template property definition version is unsupported.' },
39
+ NOT_FOUND: { exitCode: 5, description: 'The requested resource was not found.' },
40
+ POWERSYNC_OWNER_BUSY: { exitCode: 1, description: 'Another process owns the local PowerSync database.' },
41
+ PRECONDITION_FAILED: { exitCode: 5, description: 'A safety precondition for the operation did not hold.' },
42
+ SAVED_VIEW_FILTER_TOO_COMPLEX: { exitCode: 1, description: 'The saved view filter exceeds supported complexity.' },
43
+ SAVED_VIEW_FILTER_VALUE_REQUIRED: { exitCode: 5, description: 'A saved view filter condition is missing its value.' },
44
+ SAVED_VIEW_INVALID_CONFIG: { exitCode: 1, description: 'The saved view config is invalid.' },
45
+ SAVED_VIEW_INVALID_DATE_VALUE: { exitCode: 1, description: 'A saved view date value is not a real calendar date.' },
46
+ SAVED_VIEW_INVALID_FIELD: { exitCode: 1, description: 'A saved view references an invalid field.' },
47
+ SAVED_VIEW_INVALID_FILTER: { exitCode: 1, description: 'The saved view filter is invalid.' },
48
+ SAVED_VIEW_INVALID_ROW: { exitCode: 1, description: 'A stored saved view row is invalid.' },
49
+ SAVED_VIEW_NOT_FOUND: { exitCode: 5, description: 'The saved view does not exist.' },
50
+ SAVED_VIEW_OPERATOR_TYPE_MISMATCH: { exitCode: 1, description: 'A filter operator is not valid for the field type.' },
51
+ SAVED_VIEW_OPTION_NOT_FOUND: { exitCode: 5, description: 'A select option id referenced by the view does not exist.' },
52
+ SAVED_VIEW_PROPERTY_CONFIG_INVALID: { exitCode: 1, description: 'A property configuration used by the view is invalid.' },
53
+ SAVED_VIEW_PROPERTY_INVALID: { exitCode: 1, description: 'A property used by the view is invalid.' },
54
+ SAVED_VIEW_PROPERTY_NOT_FOUND: { exitCode: 5, description: 'A property referenced by the view does not exist.' },
55
+ SAVED_VIEW_PROPERTY_OPTIONS_INVALID: { exitCode: 1, description: 'Property options used by the view are invalid.' },
56
+ SAVED_VIEW_PROPERTY_OPTIONS_MIGRATION_REQUIRED: { exitCode: 5, description: 'Property options need migration before use.' },
57
+ SAVED_VIEW_SORT_TYPE_UNSUPPORTED: { exitCode: 1, description: 'The field type cannot be sorted.' },
58
+ SAVED_VIEW_UNSUPPORTED_CONFIG_VERSION: { exitCode: 1, description: 'The saved view config version is unsupported.' },
59
+ SAVED_VIEW_UNSUPPORTED_FILTER_VERSION: { exitCode: 1, description: 'The saved view filter version is unsupported.' },
60
+ SAVED_VIEW_UNSUPPORTED_LAYOUT: { exitCode: 1, description: 'The saved view layout is unsupported.' },
61
+ SAVED_VIEW_VALUE_TYPE_MISMATCH: { exitCode: 1, description: 'A filter value does not match the field type.' },
62
+ SCHEMA_PATH_NOT_FOUND: { exitCode: 5, description: 'No command schema exists for the requested path.' },
63
+ SKILLS_LOCK_INVALID: { exitCode: 1, description: 'The skills installer lock file is malformed.' },
64
+ SKILLS_LOCK_READ_FAILED: { exitCode: 1, description: 'The skills installer lock file could not be read.' },
65
+ SKILLS_MIGRATION_FAILED: { exitCode: 1, description: 'The skills installer failed during migration.' },
66
+ SKILLS_MIGRATION_PRECONDITION_FAILED: { exitCode: 1, description: 'The skills lock changed before migration ran.' },
67
+ SKILLS_MIGRATION_VERIFICATION_FAILED: { exitCode: 1, description: 'Post-migration verification did not match the plan.' },
68
+ STORAGE_IMAGE_PROCESSING_UNAVAILABLE: { exitCode: 1, description: 'The optional sharp image library is unavailable, so image uploads are refused.' },
69
+ STORAGE_OBJECT_ALREADY_EXISTS: { exitCode: 5, description: 'The storage object already exists; overwrite was not confirmed.' },
70
+ STORAGE_RESOURCE_INSERT_FAILED: { exitCode: 1, description: 'The uploaded object could not be recorded as a resource.' },
71
+ STORAGE_TEST_CLEANUP_FAILED: { exitCode: 1, description: 'The storage connectivity test object could not be removed.' },
72
+ STORAGE_THUMBNAIL_UPLOAD_FAILED: { exitCode: 1, description: 'The thumbnail upload failed.' },
73
+ STORAGE_UPLOAD_OUTCOME_UNKNOWN: { exitCode: 1, description: 'The upload outcome is unknown; verify before retrying.' },
74
+ SYNC_REQUIRED: { exitCode: 4, description: 'Fresh sync was required (--require-sync) but not confirmed.' },
75
+ SYNC_STALE: { exitCode: 4, description: 'The local cache is stale.' },
76
+ SYNC_TIMEOUT: { exitCode: 4, description: 'Sync did not complete within the timeout.' },
77
+ TODO_TASK_LOOKUP_TRUNCATED: { exitCode: 1, description: 'Task lookup hit its scan limit; pass --note-id.' },
78
+ TODO_TASK_NOT_FOUND: { exitCode: 5, description: 'The todo task does not exist.' },
79
+ UNAUTHENTICATED: { exitCode: 3, description: 'The backend rejected the request as unauthenticated.' },
80
+ UNSUPPORTED_CRUD_OPERATION: { exitCode: 1, description: 'A queued upload contains an unsupported operation.' },
81
+ UPDATE_FAILED: { exitCode: 1, description: 'The CLI self-update failed.' },
82
+ UPLOAD_PENDING: { exitCode: 4, description: 'Local writes are still waiting to upload.' },
83
+ USAGE_ERROR: { exitCode: 2, description: 'Invalid command usage, arguments, or flags.' },
84
+ };
85
+ export function isRegisteredErrorCode(code) {
86
+ return Object.prototype.hasOwnProperty.call(ERROR_CODES, code);
87
+ }
88
+ export function listErrorCodes() {
89
+ return Object.keys(ERROR_CODES)
90
+ .sort()
91
+ .map((code) => ({ code, ...ERROR_CODES[code] }));
92
+ }
@@ -1,11 +1,23 @@
1
+ import { type DinoxErrorCode } from './errorCodes.js';
2
+ export type { DinoxErrorCode } from './errorCodes.js';
3
+ declare const wireErrorCodeBrand: unique symbol;
4
+ /**
5
+ * A code received from another process (e.g. the daemon) that may not be registered in this
6
+ * CLI build. Only `wireErrorCode()` produces one; local code must use a registered code.
7
+ */
8
+ export type WireErrorCode = string & {
9
+ readonly [wireErrorCodeBrand]: true;
10
+ };
11
+ export declare function wireErrorCode(code: string): WireErrorCode;
1
12
  export type DinoxErrorOptions = {
2
13
  exitCode?: number;
3
14
  cause?: unknown;
4
15
  details?: unknown;
5
- code?: string;
16
+ code?: DinoxErrorCode | WireErrorCode;
6
17
  suggestion?: string;
7
18
  suggestedAction?: SuggestedAction;
8
19
  recoverable?: boolean;
20
+ requiresProcessExit?: boolean;
9
21
  };
10
22
  export type SuggestedAction = {
11
23
  command: string;
@@ -30,10 +42,11 @@ export type StructuredErrorPayload = {
30
42
  export declare class DinoxError extends Error {
31
43
  readonly exitCode: number;
32
44
  readonly details?: unknown;
33
- readonly code: string;
45
+ readonly code: DinoxErrorCode | WireErrorCode;
34
46
  readonly suggestion?: string;
35
47
  readonly suggestedAction?: SuggestedAction;
36
48
  readonly recoverable: boolean;
49
+ readonly requiresProcessExit: boolean;
37
50
  constructor(message: string, options?: DinoxErrorOptions);
38
51
  }
39
52
  export declare function isDinoxError(error: unknown): error is DinoxError;
@@ -1,3 +1,7 @@
1
+ import { ERROR_CODES, isRegisteredErrorCode } from './errorCodes.js';
2
+ export function wireErrorCode(code) {
3
+ return code;
4
+ }
1
5
  export class DinoxError extends Error {
2
6
  exitCode;
3
7
  details;
@@ -5,6 +9,7 @@ export class DinoxError extends Error {
5
9
  suggestion;
6
10
  suggestedAction;
7
11
  recoverable;
12
+ requiresProcessExit;
8
13
  constructor(message, options) {
9
14
  super(message);
10
15
  const code = normalizeErrorCode(options?.code ?? inferDinoxErrorCode(message));
@@ -18,6 +23,7 @@ export class DinoxError extends Error {
18
23
  ?? suggestedActionFromSuggestion(suggestion)
19
24
  ?? defaultSuggestedActionForCode(code, message);
20
25
  this.recoverable = options?.recoverable ?? true;
26
+ this.requiresProcessExit = options?.requiresProcessExit ?? false;
21
27
  if (options?.cause !== undefined) {
22
28
  // Node 16+ supports Error.cause.
23
29
  this.cause = options.cause;
@@ -117,6 +123,13 @@ function inferDinoxErrorCode(message) {
117
123
  }
118
124
  export function exitCodeForErrorCode(code) {
119
125
  const normalized = normalizeErrorCode(code);
126
+ if (isRegisteredErrorCode(normalized)) {
127
+ return ERROR_CODES[normalized].exitCode;
128
+ }
129
+ return legacyExitCodeForUnregisteredCode(normalized);
130
+ }
131
+ // Fallback for codes outside the registry (for example a daemon from another CLI build).
132
+ function legacyExitCodeForUnregisteredCode(normalized) {
120
133
  if (normalized === 'USAGE_ERROR' || normalized === 'INVALID_ARGUMENT' || normalized.startsWith('INVALID_')) {
121
134
  return 2;
122
135
  }
@@ -0,0 +1 @@
1
+ export declare function exitProcessAfterFlushing(exitCode: number, flushTimeoutMs?: number): Promise<never>;
@@ -0,0 +1,33 @@
1
+ const DEFAULT_FLUSH_TIMEOUT_MS = 100;
2
+ async function flushWritable(stream, timeoutMs) {
3
+ if (stream.destroyed || stream.writableEnded || !stream.writable) {
4
+ return;
5
+ }
6
+ await new Promise((resolve) => {
7
+ let settled = false;
8
+ const finish = () => {
9
+ if (settled)
10
+ return;
11
+ settled = true;
12
+ clearTimeout(timer);
13
+ resolve();
14
+ };
15
+ const timer = setTimeout(finish, timeoutMs);
16
+ try {
17
+ stream.write('', finish);
18
+ }
19
+ catch {
20
+ finish();
21
+ }
22
+ });
23
+ }
24
+ export async function exitProcessAfterFlushing(exitCode, flushTimeoutMs = DEFAULT_FLUSH_TIMEOUT_MS) {
25
+ const timeoutMs = Number.isFinite(flushTimeoutMs)
26
+ ? Math.max(1, Math.floor(flushTimeoutMs))
27
+ : DEFAULT_FLUSH_TIMEOUT_MS;
28
+ await Promise.all([
29
+ flushWritable(process.stdout, timeoutMs),
30
+ flushWritable(process.stderr, timeoutMs),
31
+ ]);
32
+ process.exit(exitCode);
33
+ }
@@ -4,4 +4,5 @@ export type UpdateNotice = {
4
4
  message: string;
5
5
  };
6
6
  export declare function isVersionNewer(candidate: string, current: string): boolean;
7
+ export declare function fetchLatestPublishedVersion(fetchImpl?: typeof fetch): Promise<string | null>;
7
8
  export declare function getUpdateNotice(currentVersion: string, fetchImpl?: typeof fetch): Promise<UpdateNotice | null>;
@@ -26,7 +26,7 @@ export function isVersionNewer(candidate, current) {
26
26
  }
27
27
  return false;
28
28
  }
29
- async function fetchLatestPublishedVersion(fetchImpl = fetch) {
29
+ export async function fetchLatestPublishedVersion(fetchImpl = fetch) {
30
30
  const controller = new AbortController();
31
31
  const timeout = setTimeout(() => controller.abort(), 1500);
32
32
  try {
package/package.json CHANGED
@@ -1,22 +1,28 @@
1
1
  {
2
2
  "name": "@dinoxx/dinox-cli",
3
- "version": "1.1.1",
3
+ "version": "2.1.0",
4
4
  "description": "Dinox CLI",
5
5
  "main": "dist/dinox.js",
6
6
  "scripts": {
7
7
  "build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.json && node scripts/add-shebang.mjs",
8
8
  "dev": "tsx src/dinox.ts",
9
- "prepublishOnly": "pnpm run build",
9
+ "prepublishOnly": "pnpm run skills:check && pnpm run build",
10
10
  "publish:npm": "sh ./publish-npm.sh --no-bump",
11
- "publish:npm:dry-run": "sh ./publish-npm.sh --dry-run",
11
+ "publish:npm:dry-run": "sh ./publish-npm.sh --dry-run --no-bump",
12
12
  "skills:check": "tsx scripts/check-skills.ts",
13
+ "skills:eval:triggers": "tsx scripts/evaluate-skill-triggers.ts",
13
14
  "skills:sync:standalone": "tsx scripts/sync-standalone-skills-repo.ts",
14
15
  "skills:sync:standalone:check": "tsx scripts/sync-standalone-skills-repo.ts --check",
15
16
  "skills:sync:standalone:dry-run": "tsx scripts/sync-standalone-skills-repo.ts --dry-run",
16
17
  "skills:sync": "tsx scripts/sync-skills-reference.ts",
18
+ "schema:sync:electron": "tsx scripts/sync-electron-powersync-schema.ts",
19
+ "schema:sync:electron:check": "tsx scripts/sync-electron-powersync-schema.ts --check",
17
20
  "start": "node dist/dinox.js",
18
21
  "test": "node scripts/run-tests.mjs",
19
- "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json"
22
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json",
23
+ "lint": "eslint .",
24
+ "contract:sync": "tsx scripts/sync-contract.ts",
25
+ "contract:check": "tsx scripts/sync-contract.ts --check"
20
26
  },
21
27
  "keywords": [],
22
28
  "author": "",
@@ -38,8 +44,8 @@
38
44
  "dependencies": {
39
45
  "@aws-sdk/client-s3": "^3.1021.0",
40
46
  "@node-rs/jieba": "^2.0.1",
41
- "@powersync/common": "^1.57.0",
42
- "@powersync/node": "^0.19.2",
47
+ "@powersync/common": "^2.3.1",
48
+ "@powersync/node": "^1.1.1",
43
49
  "@tiptap/core": "^3.20.0",
44
50
  "@tiptap/extension-blockquote": "^3.20.0",
45
51
  "@tiptap/extension-bold": "^3.20.0",
@@ -70,17 +76,21 @@
70
76
  "remark-gfm": "^4.0.1",
71
77
  "remark-parse": "^11.0.0",
72
78
  "remark-stringify": "^11.0.0",
73
- "sharp": "^0.34.5",
74
79
  "strip-markdown": "^6.0.0",
75
80
  "unified": "^11.0.5",
76
81
  "uuidv7": "^1.0.2",
77
82
  "yaml": "^2.9.0"
78
83
  },
84
+ "optionalDependencies": {
85
+ "sharp": "^0.34.5"
86
+ },
79
87
  "devDependencies": {
80
88
  "@types/better-sqlite3": "^7.6.13",
81
89
  "@types/node": "^20.19.0",
90
+ "eslint": "^10.12.0",
82
91
  "tsx": "^4.20.3",
83
- "typescript": "^5.9.3"
92
+ "typescript": "^5.9.3",
93
+ "typescript-eslint": "^8.71.1"
84
94
  },
85
95
  "packageManager": "pnpm@10.34.5"
86
96
  }