@dinoxx/dinox-cli 1.0.17 → 1.0.19

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 (111) hide show
  1. package/README.md +72 -34
  2. package/dist/cli.js +15 -1
  3. package/dist/commands/auth/index.d.ts +2 -0
  4. package/dist/commands/auth/index.js +209 -163
  5. package/dist/commands/boxes/index.d.ts +2 -0
  6. package/dist/commands/boxes/index.js +119 -75
  7. package/dist/commands/boxes/repo.d.ts +8 -0
  8. package/dist/commands/boxes/repo.js +41 -0
  9. package/dist/commands/config/index.d.ts +2 -0
  10. package/dist/commands/config/index.js +85 -36
  11. package/dist/commands/descriptor/register.d.ts +8 -0
  12. package/dist/commands/descriptor/register.js +113 -0
  13. package/dist/commands/descriptor/types.d.ts +37 -0
  14. package/dist/commands/descriptor/types.js +17 -0
  15. package/dist/commands/graph/index.d.ts +2 -0
  16. package/dist/commands/graph/index.js +143 -73
  17. package/dist/commands/info/index.d.ts +2 -0
  18. package/dist/commands/info/index.js +41 -14
  19. package/dist/commands/mcp/index.js +11 -10
  20. package/dist/commands/mcp/server.js +6 -3
  21. package/dist/commands/mcp/tools.js +30 -104
  22. package/dist/commands/mcp/types.d.ts +8 -1
  23. package/dist/commands/meta/index.d.ts +2 -0
  24. package/dist/commands/meta/index.js +64 -33
  25. package/dist/commands/meta/repo.d.ts +6 -0
  26. package/dist/commands/meta/repo.js +6 -0
  27. package/dist/commands/notes/actions.d.ts +10 -0
  28. package/dist/commands/notes/actions.js +403 -0
  29. package/dist/commands/notes/descriptors.d.ts +4 -0
  30. package/dist/commands/notes/descriptors.js +250 -0
  31. package/dist/commands/notes/dryRun.d.ts +31 -0
  32. package/dist/commands/notes/dryRun.js +130 -0
  33. package/dist/commands/notes/index.d.ts +2 -51
  34. package/dist/commands/notes/index.js +2 -581
  35. package/dist/commands/notes/repo.d.ts +9 -0
  36. package/dist/commands/notes/repo.js +56 -10
  37. package/dist/commands/notes/runtime.d.ts +28 -0
  38. package/dist/commands/notes/runtime.js +185 -0
  39. package/dist/commands/notes/searchOutput.d.ts +10 -2
  40. package/dist/commands/notes/searchOutput.js +14 -2
  41. package/dist/commands/notes/searchResponse.d.ts +51 -0
  42. package/dist/commands/notes/searchResponse.js +56 -0
  43. package/dist/commands/notes/searchSql.js +2 -0
  44. package/dist/commands/prompt/index.d.ts +2 -0
  45. package/dist/commands/prompt/index.js +122 -72
  46. package/dist/commands/prompt/repo.d.ts +7 -0
  47. package/dist/commands/prompt/repo.js +46 -0
  48. package/dist/commands/schema/commandMetadata.d.ts +2 -0
  49. package/dist/commands/schema/commandMetadata.js +18 -0
  50. package/dist/commands/schema/globalOptions.d.ts +3 -0
  51. package/dist/commands/schema/globalOptions.js +3 -0
  52. package/dist/commands/schema/index.d.ts +4 -0
  53. package/dist/commands/schema/index.js +109 -0
  54. package/dist/commands/schema/renderSkills.d.ts +6 -0
  55. package/dist/commands/schema/renderSkills.js +216 -0
  56. package/dist/commands/schema/spec.d.ts +6 -0
  57. package/dist/commands/schema/spec.js +40 -0
  58. package/dist/commands/schema/types.d.ts +47 -0
  59. package/dist/commands/schema/types.js +1 -0
  60. package/dist/commands/storage/index.d.ts +4 -0
  61. package/dist/commands/storage/index.js +292 -0
  62. package/dist/commands/storage/repo.d.ts +162 -0
  63. package/dist/commands/storage/repo.js +751 -0
  64. package/dist/commands/sync.d.ts +2 -0
  65. package/dist/commands/sync.js +41 -27
  66. package/dist/commands/tags/index.d.ts +2 -0
  67. package/dist/commands/tags/index.js +121 -79
  68. package/dist/commands/tags/repo.d.ts +7 -0
  69. package/dist/commands/tags/repo.js +52 -0
  70. package/dist/commands/todo/dryRun.d.ts +23 -0
  71. package/dist/commands/todo/dryRun.js +133 -0
  72. package/dist/commands/todo/index.d.ts +2 -0
  73. package/dist/commands/todo/index.js +285 -135
  74. package/dist/commands/todo/repo.d.ts +11 -0
  75. package/dist/commands/todo/repo.js +37 -9
  76. package/dist/commands/update.d.ts +3 -0
  77. package/dist/commands/update.js +35 -13
  78. package/dist/commands/writeDryRun.d.ts +62 -0
  79. package/dist/commands/writeDryRun.js +131 -0
  80. package/dist/constants/links.d.ts +1 -1
  81. package/dist/constants/links.js +1 -1
  82. package/dist/daemon/ensure.js +3 -2
  83. package/dist/daemon/index.js +17 -15
  84. package/dist/dinox.js +9 -13
  85. package/dist/powersync/schema/index.d.ts +27 -0
  86. package/dist/powersync/schema/index.js +2 -0
  87. package/dist/powersync/schema/note.d.ts +1 -0
  88. package/dist/powersync/schema/note.js +1 -0
  89. package/dist/powersync/schema/projects.d.ts +3 -0
  90. package/dist/powersync/schema/projects.js +3 -0
  91. package/dist/powersync/schema/storage.d.ts +24 -0
  92. package/dist/powersync/schema/storage.js +24 -0
  93. package/dist/skills/check.d.ts +6 -0
  94. package/dist/skills/check.js +254 -0
  95. package/dist/utils/bidlinkCanonicalization.d.ts +2 -0
  96. package/dist/utils/bidlinkCanonicalization.js +161 -0
  97. package/dist/utils/dryRun.d.ts +13 -0
  98. package/dist/utils/dryRun.js +69 -0
  99. package/dist/utils/output.d.ts +19 -0
  100. package/dist/utils/output.js +155 -1
  101. package/dist/utils/terminalSanitization.d.ts +2 -0
  102. package/dist/utils/terminalSanitization.js +33 -0
  103. package/dist/utils/tiptapMarkdown.d.ts +4 -1
  104. package/dist/utils/tiptapMarkdown.js +285 -113
  105. package/dist/utils/tiptapMarkdownSchema.d.ts +37 -0
  106. package/dist/utils/tiptapMarkdownSchema.js +577 -0
  107. package/dist/utils/tiptapMarkdownSchemaUtils.d.ts +74 -0
  108. package/dist/utils/tiptapMarkdownSchemaUtils.js +394 -0
  109. package/dist/utils/updateNotice.d.ts +7 -0
  110. package/dist/utils/updateNotice.js +64 -0
  111. package/package.json +25 -3
@@ -0,0 +1,394 @@
1
+ const DINOX_COMMENT_REGEX = /^<!--\s*({[\s\S]*})\s*-->$/;
2
+ const FRONTMATTER_BLOCK_RE = /^(?:\uFEFF)?---[ \t]*\n([\s\S]*?)\n---[ \t]*(?:\n|$)/;
3
+ const EXACT_FRONTMATTER_BLOCK_RE = /^(?:\uFEFF)?---[ \t]*\n([\s\S]*?)\n---[ \t]*$/;
4
+ const DEFAULT_FILE_TYPE = 'application/octet-stream';
5
+ const IMAGE_WIDTH_PERCENT_ATTR = 'data-dinox-width-percent';
6
+ const MEDIA_RESOURCE_ID_ATTR = 'data-resource-id';
7
+ const MEDIA_STORAGE_KEY_ATTR = 'data-storage-key';
8
+ const MIN_IMAGE_WIDTH_PERCENT = 40;
9
+ const MAX_IMAGE_WIDTH_PERCENT = 100;
10
+ const MIME_BY_EXTENSION = {
11
+ csv: 'text/csv',
12
+ gif: 'image/gif',
13
+ heic: 'image/heic',
14
+ html: 'text/html',
15
+ jpeg: 'image/jpeg',
16
+ jpg: 'image/jpeg',
17
+ js: 'text/javascript',
18
+ json: 'application/json',
19
+ m4a: 'audio/mp4',
20
+ md: 'text/markdown',
21
+ markdown: 'text/markdown',
22
+ mov: 'video/quicktime',
23
+ mp3: 'audio/mpeg',
24
+ mp4: 'video/mp4',
25
+ pdf: 'application/pdf',
26
+ png: 'image/png',
27
+ svg: 'image/svg+xml',
28
+ tar: 'application/x-tar',
29
+ ts: 'text/typescript',
30
+ tsx: 'text/tsx',
31
+ txt: 'text/plain',
32
+ wav: 'audio/wav',
33
+ webp: 'image/webp',
34
+ xml: 'application/xml',
35
+ yaml: 'application/yaml',
36
+ yml: 'application/yaml',
37
+ zip: 'application/zip',
38
+ };
39
+ function normalizeNonEmptyString(value) {
40
+ return typeof value === 'string' && value.trim() ? value.trim() : '';
41
+ }
42
+ function normalizeOptionalString(value) {
43
+ const normalized = normalizeNonEmptyString(value);
44
+ return normalized || undefined;
45
+ }
46
+ function normalizeDimension(value) {
47
+ if (typeof value === 'number' && Number.isFinite(value) && value > 0) {
48
+ return value;
49
+ }
50
+ const parsed = Number(value);
51
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
52
+ }
53
+ function normalizeBoolean(value) {
54
+ if (value === true) {
55
+ return true;
56
+ }
57
+ if (value === false || value == null) {
58
+ return undefined;
59
+ }
60
+ const normalized = String(value).trim().toLowerCase();
61
+ if (!normalized || normalized === 'false' || normalized === '0' || normalized === 'no') {
62
+ return undefined;
63
+ }
64
+ return true;
65
+ }
66
+ function parseHtmlAttributes(attrString) {
67
+ const attributes = {};
68
+ const regex = /([^\s=/>]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
69
+ let match = regex.exec(attrString);
70
+ while (match !== null) {
71
+ const [, rawKey, doubleQuoted, singleQuoted, bareValue] = match;
72
+ attributes[rawKey] = doubleQuoted ?? singleQuoted ?? bareValue ?? true;
73
+ match = regex.exec(attrString);
74
+ }
75
+ return attributes;
76
+ }
77
+ function getFileExtension(value) {
78
+ const sanitized = value.split(/[?#]/, 1)[0] ?? '';
79
+ const filename = sanitized.split('/').pop() ?? '';
80
+ const lastDotIndex = filename.lastIndexOf('.');
81
+ if (lastDotIndex < 0 || lastDotIndex === filename.length - 1) {
82
+ return '';
83
+ }
84
+ return filename.slice(lastDotIndex + 1).toLowerCase();
85
+ }
86
+ function parseSize(value) {
87
+ const numeric = typeof value === 'number' ? value : Number(value);
88
+ return Number.isFinite(numeric) && numeric > 0 ? Math.round(numeric) : 0;
89
+ }
90
+ export function parseMarkdownAttributes(attrString) {
91
+ if (!attrString.trim()) {
92
+ return {};
93
+ }
94
+ const attributes = {};
95
+ const regex = /(\w+)=(?:"([^"]*)"|'([^']*)')/g;
96
+ let match = regex.exec(attrString);
97
+ while (match !== null) {
98
+ const [, key, doubleQuoted, singleQuoted] = match;
99
+ attributes[key] = (doubleQuoted || singleQuoted || '').replace(/\\"/g, '"');
100
+ match = regex.exec(attrString);
101
+ }
102
+ return attributes;
103
+ }
104
+ export function serializeMarkdownAttributes(attrs, allowedKeys) {
105
+ const keys = allowedKeys ?? Object.keys(attrs);
106
+ return keys
107
+ .filter((key) => attrs[key] !== undefined && attrs[key] !== null && attrs[key] !== '')
108
+ .map((key) => `${key}="${String(attrs[key]).replace(/"/g, '\\"')}"`)
109
+ .join(' ');
110
+ }
111
+ export function normalizeMarkdownLineEndings(value) {
112
+ return value.replace(/\r\n?/g, '\n').replace(/^\uFEFF/, '');
113
+ }
114
+ export function normalizeFrontmatterRaw(raw) {
115
+ let value = typeof raw === 'string' ? raw : raw == null ? '' : String(raw);
116
+ value = normalizeMarkdownLineEndings(value);
117
+ const exactBlockMatch = value.match(EXACT_FRONTMATTER_BLOCK_RE);
118
+ if (exactBlockMatch) {
119
+ value = exactBlockMatch[1] ?? '';
120
+ }
121
+ return value.replace(/^\n+/, '').replace(/\n+$/, '');
122
+ }
123
+ export function buildFrontmatterMarkdownBlock(raw) {
124
+ const normalized = normalizeFrontmatterRaw(raw);
125
+ if (!normalized) {
126
+ return '';
127
+ }
128
+ return `---\n${normalized}\n---`;
129
+ }
130
+ export function extractMarkdownFrontmatter(markdown) {
131
+ const normalized = normalizeMarkdownLineEndings(markdown || '');
132
+ const match = normalized.match(FRONTMATTER_BLOCK_RE);
133
+ if (!match) {
134
+ return {
135
+ body: normalized,
136
+ frontmatter: null,
137
+ };
138
+ }
139
+ return {
140
+ body: normalized.slice(match[0].length).replace(/^\n+/, ''),
141
+ frontmatter: normalizeFrontmatterRaw(match[1] ?? ''),
142
+ };
143
+ }
144
+ export function normalizeStoredImageWidthPercent(value) {
145
+ if (value == null || value === '') {
146
+ return null;
147
+ }
148
+ const parsed = Number(value);
149
+ if (!Number.isFinite(parsed)) {
150
+ return null;
151
+ }
152
+ const rounded = Math.round(parsed);
153
+ const clamped = Math.min(MAX_IMAGE_WIDTH_PERCENT, Math.max(MIN_IMAGE_WIDTH_PERCENT, rounded));
154
+ return clamped >= MAX_IMAGE_WIDTH_PERCENT ? null : clamped;
155
+ }
156
+ export function parseImageWidthPercentFromStyle(styleValue) {
157
+ if (typeof styleValue !== 'string' || !styleValue.trim()) {
158
+ return null;
159
+ }
160
+ const match = styleValue.match(/(?:^|;)\s*width\s*:\s*([0-9]+(?:\.[0-9]+)?)\s*%/i);
161
+ if (!match) {
162
+ return null;
163
+ }
164
+ return normalizeStoredImageWidthPercent(match[1]);
165
+ }
166
+ export function buildImageWidthPercentStyle(widthPercent) {
167
+ const normalized = normalizeStoredImageWidthPercent(widthPercent);
168
+ return normalized == null ? null : `width: ${normalized}%;`;
169
+ }
170
+ export function normalizeDinoxImageAttrs(input) {
171
+ return {
172
+ alt: normalizeOptionalString(input.alt) ?? null,
173
+ height: normalizeDimension(input.height),
174
+ resourceId: normalizeOptionalString(input.resourceId) ?? null,
175
+ src: normalizeOptionalString(input.src) ?? null,
176
+ storageKey: normalizeOptionalString(input.storageKey) ?? null,
177
+ title: normalizeOptionalString(input.title) ?? null,
178
+ width: normalizeDimension(input.width),
179
+ widthPercent: normalizeStoredImageWidthPercent(input.widthPercent),
180
+ };
181
+ }
182
+ export function normalizeAudioMarkdownAttrs(input) {
183
+ const normalized = {};
184
+ const src = normalizeNonEmptyString(input.src);
185
+ if (src) {
186
+ normalized.src = src;
187
+ }
188
+ const title = normalizeNonEmptyString(input.title);
189
+ if (title) {
190
+ normalized.title = title;
191
+ }
192
+ const preload = normalizeNonEmptyString(input.preload);
193
+ if (preload) {
194
+ normalized.preload = preload;
195
+ }
196
+ const resourceId = normalizeNonEmptyString(input.resourceId ?? input[MEDIA_RESOURCE_ID_ATTR]);
197
+ if (resourceId) {
198
+ normalized.resourceId = resourceId;
199
+ }
200
+ const storageKey = normalizeNonEmptyString(input.storageKey ?? input[MEDIA_STORAGE_KEY_ATTR]);
201
+ if (storageKey) {
202
+ normalized.storageKey = storageKey;
203
+ }
204
+ return normalized;
205
+ }
206
+ export function normalizeVideoMarkdownAttrs(input) {
207
+ const normalized = {};
208
+ const src = normalizeNonEmptyString(input.src);
209
+ if (src) {
210
+ normalized.src = src;
211
+ }
212
+ const poster = normalizeNonEmptyString(input.poster);
213
+ if (poster) {
214
+ normalized.poster = poster;
215
+ }
216
+ const title = normalizeNonEmptyString(input.title);
217
+ if (title) {
218
+ normalized.title = title;
219
+ }
220
+ const resourceId = normalizeNonEmptyString(input.resourceId ?? input[MEDIA_RESOURCE_ID_ATTR]);
221
+ if (resourceId) {
222
+ normalized.resourceId = resourceId;
223
+ }
224
+ const storageKey = normalizeNonEmptyString(input.storageKey ?? input[MEDIA_STORAGE_KEY_ATTR]);
225
+ if (storageKey) {
226
+ normalized.storageKey = storageKey;
227
+ }
228
+ if (normalizeBoolean(input.autoplay)) {
229
+ normalized.autoplay = true;
230
+ }
231
+ if (normalizeBoolean(input.loop)) {
232
+ normalized.loop = true;
233
+ }
234
+ if (normalizeBoolean(input.muted)) {
235
+ normalized.muted = true;
236
+ }
237
+ if (normalizeBoolean(input.playsInline ?? input.playsinline ?? input['plays-inline'])) {
238
+ normalized.playsInline = true;
239
+ }
240
+ return normalized;
241
+ }
242
+ export function normalizeFileBlockAttrs(input) {
243
+ const name = normalizeNonEmptyString(input.name) || '未命名文件';
244
+ const type = normalizeNonEmptyString(input.type) || DEFAULT_FILE_TYPE;
245
+ return {
246
+ id: normalizeNonEmptyString(input.id) || generateId(),
247
+ name,
248
+ resourceId: normalizeOptionalString(input.resourceId),
249
+ size: parseSize(input.size),
250
+ src: normalizeNonEmptyString(input.src),
251
+ type,
252
+ };
253
+ }
254
+ export function inferMimeTypeFromHref(href) {
255
+ const extension = getFileExtension(href);
256
+ return extension ? MIME_BY_EXTENSION[extension] : undefined;
257
+ }
258
+ export function parseDinoxMarkdownComment(rawComment) {
259
+ if (typeof rawComment !== 'string') {
260
+ return null;
261
+ }
262
+ const normalized = rawComment.trim();
263
+ if (!normalized) {
264
+ return null;
265
+ }
266
+ const match = normalized.match(DINOX_COMMENT_REGEX);
267
+ if (!match) {
268
+ return null;
269
+ }
270
+ try {
271
+ const parsed = JSON.parse(match[1]);
272
+ const kindValue = typeof parsed.kind === 'string' ? parsed.kind.trim().toLowerCase() : '';
273
+ const kind = kindValue === 'image' || kindValue === 'video' || kindValue === 'audio' || kindValue === 'file'
274
+ ? kindValue
275
+ : null;
276
+ const resourceId = typeof parsed.resourceId === 'string' && parsed.resourceId.trim()
277
+ ? parsed.resourceId.trim()
278
+ : null;
279
+ const widthPercent = normalizeStoredImageWidthPercent(parsed.widthPercent);
280
+ if (!kind && !resourceId && widthPercent == null) {
281
+ return null;
282
+ }
283
+ return {
284
+ kind,
285
+ resourceId,
286
+ widthPercent,
287
+ };
288
+ }
289
+ catch {
290
+ return null;
291
+ }
292
+ }
293
+ export function extractAudioAttrsFromHtml(html) {
294
+ const rootMatch = html.match(/^<audio\b([^>]*)>/i);
295
+ if (!rootMatch) {
296
+ return null;
297
+ }
298
+ const rootAttrs = parseHtmlAttributes(rootMatch[1] || '');
299
+ const sourceMatch = html.match(/<source\b([^>]*)>/i);
300
+ const sourceAttrs = sourceMatch ? parseHtmlAttributes(sourceMatch[1] || '') : {};
301
+ const combined = {
302
+ ...rootAttrs,
303
+ src: rootAttrs.src ?? sourceAttrs.src,
304
+ resourceId: rootAttrs[MEDIA_RESOURCE_ID_ATTR],
305
+ storageKey: rootAttrs[MEDIA_STORAGE_KEY_ATTR],
306
+ };
307
+ const normalized = normalizeAudioMarkdownAttrs(combined);
308
+ return normalized.src ? normalized : null;
309
+ }
310
+ export function extractVideoAttrsFromHtml(html) {
311
+ const rootMatch = html.match(/^<video\b([^>]*)>/i);
312
+ if (!rootMatch) {
313
+ return null;
314
+ }
315
+ const rootAttrs = parseHtmlAttributes(rootMatch[1] || '');
316
+ const sourceMatch = html.match(/<source\b([^>]*)>/i);
317
+ const sourceAttrs = sourceMatch ? parseHtmlAttributes(sourceMatch[1] || '') : {};
318
+ const combined = {
319
+ ...rootAttrs,
320
+ src: rootAttrs.src ?? sourceAttrs.src,
321
+ resourceId: rootAttrs[MEDIA_RESOURCE_ID_ATTR],
322
+ storageKey: rootAttrs[MEDIA_STORAGE_KEY_ATTR],
323
+ };
324
+ const normalized = normalizeVideoMarkdownAttrs(combined);
325
+ return normalized.src ? normalized : null;
326
+ }
327
+ function isAsciiLetterOrDigit(charCode) {
328
+ return ((charCode >= 0x30 && charCode <= 0x39) ||
329
+ (charCode >= 0x41 && charCode <= 0x5a) ||
330
+ (charCode >= 0x61 && charCode <= 0x7a));
331
+ }
332
+ function isCjkChar(charCode) {
333
+ return charCode >= 0x4e00 && charCode <= 0x9fff;
334
+ }
335
+ function isHashtagPathSegmentChar(charCode) {
336
+ return isAsciiLetterOrDigit(charCode) || charCode === 0x5f || charCode === 0x2d || isCjkChar(charCode);
337
+ }
338
+ function isHashtagBoundaryBlockingChar(charCode) {
339
+ return isAsciiLetterOrDigit(charCode) || charCode === 0x5f || isCjkChar(charCode);
340
+ }
341
+ export function parseHashtagPath(source, hashIndex) {
342
+ if (hashIndex < 0 || hashIndex >= source.length || source.charCodeAt(hashIndex) !== 0x23) {
343
+ return null;
344
+ }
345
+ if (hashIndex > 0 && isHashtagBoundaryBlockingChar(source.charCodeAt(hashIndex - 1))) {
346
+ return null;
347
+ }
348
+ let index = hashIndex + 1;
349
+ let hasSegmentChar = false;
350
+ while (index < source.length) {
351
+ const charCode = source.charCodeAt(index);
352
+ if (isHashtagPathSegmentChar(charCode)) {
353
+ hasSegmentChar = true;
354
+ index += 1;
355
+ continue;
356
+ }
357
+ if (charCode === 0x2f) {
358
+ const nextIndex = index + 1;
359
+ if (!hasSegmentChar || nextIndex >= source.length) {
360
+ return null;
361
+ }
362
+ const nextCharCode = source.charCodeAt(nextIndex);
363
+ if (!isHashtagPathSegmentChar(nextCharCode)) {
364
+ return null;
365
+ }
366
+ hasSegmentChar = false;
367
+ index += 1;
368
+ continue;
369
+ }
370
+ break;
371
+ }
372
+ if (!hasSegmentChar || index <= hashIndex + 1) {
373
+ return null;
374
+ }
375
+ const raw = source.slice(hashIndex, index);
376
+ return {
377
+ end: index,
378
+ label: raw.slice(1),
379
+ raw,
380
+ };
381
+ }
382
+ export function findHashtagPathStart(source) {
383
+ for (let index = 0; index < source.length; index += 1) {
384
+ if (source.charCodeAt(index) !== 0x23) {
385
+ continue;
386
+ }
387
+ if (parseHashtagPath(source, index)) {
388
+ return index;
389
+ }
390
+ }
391
+ return -1;
392
+ }
393
+ export { DEFAULT_FILE_TYPE, IMAGE_WIDTH_PERCENT_ATTR, MEDIA_RESOURCE_ID_ATTR, MEDIA_STORAGE_KEY_ATTR, };
394
+ import { generateId } from './id.js';
@@ -0,0 +1,7 @@
1
+ export type UpdateNotice = {
2
+ current: string;
3
+ latest: string;
4
+ message: string;
5
+ };
6
+ export declare function isVersionNewer(candidate: string, current: string): boolean;
7
+ export declare function getUpdateNotice(currentVersion: string, fetchImpl?: typeof fetch): Promise<UpdateNotice | null>;
@@ -0,0 +1,64 @@
1
+ const PACKAGE_NAME = '@dinoxx/dinox-cli';
2
+ const LATEST_VERSION_URL = 'https://registry.npmjs.org/@dinoxx%2Fdinox-cli/latest';
3
+ let cachedUpdateNotice = null;
4
+ let lastCheckedAt = 0;
5
+ const UPDATE_CACHE_TTL_MS = 5 * 60 * 1000;
6
+ function parseSemverParts(version) {
7
+ const base = version.trim().split('-', 1)[0] ?? '';
8
+ return base.split('.').map((part) => Number.parseInt(part, 10) || 0);
9
+ }
10
+ export function isVersionNewer(candidate, current) {
11
+ const left = parseSemverParts(candidate);
12
+ const right = parseSemverParts(current);
13
+ const maxLength = Math.max(left.length, right.length);
14
+ for (let index = 0; index < maxLength; index += 1) {
15
+ const lhs = left[index] ?? 0;
16
+ const rhs = right[index] ?? 0;
17
+ if (lhs > rhs) {
18
+ return true;
19
+ }
20
+ if (lhs < rhs) {
21
+ return false;
22
+ }
23
+ }
24
+ return false;
25
+ }
26
+ async function fetchLatestPublishedVersion(fetchImpl = fetch) {
27
+ const controller = new AbortController();
28
+ const timeout = setTimeout(() => controller.abort(), 1500);
29
+ try {
30
+ const response = await fetchImpl(LATEST_VERSION_URL, {
31
+ headers: { Accept: 'application/json' },
32
+ signal: controller.signal,
33
+ });
34
+ if (!response.ok) {
35
+ return null;
36
+ }
37
+ const payload = await response.json();
38
+ return typeof payload.version === 'string' ? payload.version.trim() : null;
39
+ }
40
+ catch {
41
+ return null;
42
+ }
43
+ finally {
44
+ clearTimeout(timeout);
45
+ }
46
+ }
47
+ export async function getUpdateNotice(currentVersion, fetchImpl = fetch) {
48
+ const now = Date.now();
49
+ if (cachedUpdateNotice && now - lastCheckedAt < UPDATE_CACHE_TTL_MS) {
50
+ return cachedUpdateNotice.current === currentVersion ? cachedUpdateNotice : null;
51
+ }
52
+ const latestVersion = await fetchLatestPublishedVersion(fetchImpl);
53
+ lastCheckedAt = now;
54
+ if (!latestVersion || !isVersionNewer(latestVersion, currentVersion)) {
55
+ cachedUpdateNotice = null;
56
+ return null;
57
+ }
58
+ cachedUpdateNotice = {
59
+ current: currentVersion,
60
+ latest: latestVersion,
61
+ message: `Update available for ${PACKAGE_NAME}: ${currentVersion} -> ${latestVersion}`,
62
+ };
63
+ return cachedUpdateNotice;
64
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dinoxx/dinox-cli",
3
- "version": "1.0.17",
3
+ "version": "1.0.19",
4
4
  "description": "Dinox CLI",
5
5
  "main": "dist/dinox.js",
6
6
  "scripts": {
@@ -9,6 +9,8 @@
9
9
  "prepublishOnly": "npm run build",
10
10
  "publish:npm": "sh ./publish-npm.sh",
11
11
  "publish:npm:dry-run": "sh ./publish-npm.sh --dry-run",
12
+ "skills:check": "tsx scripts/check-skills.ts",
13
+ "skills:sync": "tsx scripts/sync-skills-reference.ts",
12
14
  "start": "node dist/dinox.js",
13
15
  "test": "node --test --import tsx test/*.test.ts"
14
16
  },
@@ -30,21 +32,41 @@
30
32
  "node": ">=20"
31
33
  },
32
34
  "dependencies": {
35
+ "@aws-sdk/client-s3": "^3.1021.0",
33
36
  "@node-rs/jieba": "^2.0.1",
34
37
  "@powersync/common": "^1.47.0",
35
38
  "@powersync/node": "^0.17.1",
36
39
  "@tiptap/core": "^3.20.0",
40
+ "@tiptap/extension-blockquote": "^3.20.0",
41
+ "@tiptap/extension-bold": "^3.20.0",
42
+ "@tiptap/extension-bullet-list": "^3.20.0",
43
+ "@tiptap/extension-code": "^3.20.0",
44
+ "@tiptap/extension-code-block": "^3.20.0",
45
+ "@tiptap/extension-document": "^3.20.0",
46
+ "@tiptap/extension-hard-break": "^3.20.0",
47
+ "@tiptap/extension-heading": "^3.20.0",
48
+ "@tiptap/extension-highlight": "^3.20.0",
49
+ "@tiptap/extension-horizontal-rule": "^3.20.0",
37
50
  "@tiptap/extension-image": "^3.20.0",
51
+ "@tiptap/extension-italic": "^3.20.0",
52
+ "@tiptap/extension-link": "^3.20.0",
38
53
  "@tiptap/extension-list": "^3.20.0",
54
+ "@tiptap/extension-mathematics": "^3.20.0",
55
+ "@tiptap/extension-paragraph": "^3.20.0",
56
+ "@tiptap/extension-strike": "^3.20.0",
39
57
  "@tiptap/extension-table": "^3.20.0",
40
- "@tiptap/extension-unique-id": "^3.20.0",
58
+ "@tiptap/extension-table-cell": "^3.20.0",
59
+ "@tiptap/extension-table-header": "^3.20.0",
60
+ "@tiptap/extension-table-row": "^3.20.0",
61
+ "@tiptap/extension-text": "^3.20.0",
62
+ "@tiptap/extension-underline": "^3.20.0",
41
63
  "@tiptap/markdown": "^3.20.0",
42
- "@tiptap/starter-kit": "^3.20.0",
43
64
  "better-sqlite3": "^12.6.2",
44
65
  "commander": "^14.0.3",
45
66
  "remark-gfm": "^4.0.1",
46
67
  "remark-parse": "^11.0.0",
47
68
  "remark-stringify": "^11.0.0",
69
+ "sharp": "^0.34.5",
48
70
  "strip-markdown": "^6.0.0",
49
71
  "unified": "^11.0.5",
50
72
  "uuidv7": "^1.0.2",