@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,21 @@
1
+ import { type CommandSchema } from '../commands/schema/spec.js';
2
+ export type SkillCommandReferenceIssue = {
3
+ /** Path relative to the skills directory. */
4
+ file: string;
5
+ line: number;
6
+ snippet: string;
7
+ message: string;
8
+ };
9
+ type CommandIndex = {
10
+ byCommand: Map<string, CommandSchema>;
11
+ groups: Set<string>;
12
+ };
13
+ /** Extracts `dino ...` invocations from inline code spans and fenced code block lines. */
14
+ export declare function extractDinoInvocations(markdown: string): Array<{
15
+ line: number;
16
+ text: string;
17
+ }>;
18
+ export declare function validateDinoInvocation(text: string, index?: CommandIndex): string | null;
19
+ /** Verifies that every `dino ...` invocation in the skill markdown resolves against the command schemas. */
20
+ export declare function checkSkillCommandReferences(skillsDir: string): SkillCommandReferenceIssue[];
21
+ export {};
@@ -0,0 +1,132 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { listCommandSchemas } from '../commands/schema/spec.js';
4
+ // Global flags accepted by every command (see src/cli.ts) plus Commander builtins.
5
+ const GLOBAL_FLAGS = new Set([
6
+ '--json',
7
+ '--format',
8
+ '--offline',
9
+ '--require-sync',
10
+ '--sync-timeout',
11
+ '--verbose',
12
+ '--help',
13
+ '--version',
14
+ ]);
15
+ const SHELL_BOUNDARY = /\s(?:\||&&|\|\||;|>|2>|#)\s/;
16
+ function buildCommandIndex() {
17
+ const byCommand = new Map();
18
+ const groups = new Set();
19
+ for (const schema of listCommandSchemas()) {
20
+ const words = schema.command.split(/\s+/).slice(1);
21
+ byCommand.set(words.join(' '), schema);
22
+ if (words.length > 1) {
23
+ groups.add(words[0]);
24
+ }
25
+ }
26
+ return { byCommand, groups };
27
+ }
28
+ function optionFlags(schema) {
29
+ const flags = new Set();
30
+ for (const option of schema.options ?? []) {
31
+ for (const match of option.name.matchAll(/--[a-z0-9][a-z0-9-]*/gi)) {
32
+ flags.add(match[0]);
33
+ }
34
+ }
35
+ return flags;
36
+ }
37
+ /** Extracts `dino ...` invocations from inline code spans and fenced code block lines. */
38
+ export function extractDinoInvocations(markdown) {
39
+ const invocations = [];
40
+ const lines = markdown.split(/\r?\n/);
41
+ let inFence = false;
42
+ lines.forEach((rawLine, index) => {
43
+ const lineNumber = index + 1;
44
+ if (/^\s*(```|~~~)/.test(rawLine)) {
45
+ inFence = !inFence;
46
+ return;
47
+ }
48
+ if (inFence) {
49
+ const match = rawLine.match(/(?:^|\s|\$\s*)(dino\s+[^`]*)$/);
50
+ if (match?.[1]) {
51
+ invocations.push({ line: lineNumber, text: match[1] });
52
+ }
53
+ return;
54
+ }
55
+ for (const match of rawLine.matchAll(/`(dino\s+[^`]+)`/g)) {
56
+ if (match[1]) {
57
+ invocations.push({ line: lineNumber, text: match[1] });
58
+ }
59
+ }
60
+ });
61
+ return invocations;
62
+ }
63
+ export function validateDinoInvocation(text, index = buildCommandIndex()) {
64
+ const command = text.split(SHELL_BOUNDARY)[0]?.trim() ?? '';
65
+ const tokens = command.split(/\s+/).slice(1);
66
+ const first = tokens[0];
67
+ // Placeholders such as `dino <command>` or `dino ...` are prose, not invocations.
68
+ if (!first || !/^[a-z][a-z0-9-]*$/.test(first)) {
69
+ return null;
70
+ }
71
+ let schema;
72
+ let consumed = 0;
73
+ for (let length = Math.min(tokens.length, 3); length >= 1; length -= 1) {
74
+ const candidate = index.byCommand.get(tokens.slice(0, length).join(' '));
75
+ if (candidate) {
76
+ schema = candidate;
77
+ consumed = length;
78
+ break;
79
+ }
80
+ }
81
+ if (!schema) {
82
+ const second = tokens[1];
83
+ if (index.groups.has(first) && (!second || !/^[a-z][a-z0-9-]*$/.test(second))) {
84
+ return null;
85
+ }
86
+ return `unknown command \`dino ${tokens.slice(0, index.groups.has(first) ? 2 : 1).join(' ')}\``;
87
+ }
88
+ const known = optionFlags(schema);
89
+ for (const token of tokens.slice(consumed)) {
90
+ const flag = token.match(/^(--[a-z0-9][a-z0-9-]*)/i)?.[1];
91
+ if (!flag || GLOBAL_FLAGS.has(flag) || known.has(flag)) {
92
+ continue;
93
+ }
94
+ return `\`${schema.command}\` has no option \`${flag}\``;
95
+ }
96
+ return null;
97
+ }
98
+ function listMarkdownFiles(dir) {
99
+ const files = [];
100
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
101
+ if (entry.name.startsWith('.'))
102
+ continue;
103
+ const fullPath = path.join(dir, entry.name);
104
+ if (entry.isDirectory()) {
105
+ files.push(...listMarkdownFiles(fullPath));
106
+ }
107
+ else if (entry.name.endsWith('.md')) {
108
+ files.push(fullPath);
109
+ }
110
+ }
111
+ return files.sort();
112
+ }
113
+ /** Verifies that every `dino ...` invocation in the skill markdown resolves against the command schemas. */
114
+ export function checkSkillCommandReferences(skillsDir) {
115
+ const index = buildCommandIndex();
116
+ const issues = [];
117
+ for (const filePath of listMarkdownFiles(skillsDir)) {
118
+ const markdown = fs.readFileSync(filePath, 'utf8');
119
+ for (const invocation of extractDinoInvocations(markdown)) {
120
+ const message = validateDinoInvocation(invocation.text, index);
121
+ if (message) {
122
+ issues.push({
123
+ file: path.relative(skillsDir, filePath).split(path.sep).join('/'),
124
+ line: invocation.line,
125
+ snippet: invocation.text.trim(),
126
+ message,
127
+ });
128
+ }
129
+ }
130
+ }
131
+ return issues;
132
+ }
@@ -0,0 +1,13 @@
1
+ import { type GeneratedSkillSection } from './registry.js';
2
+ export type GeneratedSkillFile = {
3
+ skill: string;
4
+ /** Path relative to the skills directory. */
5
+ file: string;
6
+ marker: GeneratedSkillSection['marker'] | 'PORTABLE_RUNTIME';
7
+ render: () => string;
8
+ };
9
+ /** Every generated block in the published skill set, derived from the skill registry. */
10
+ export declare function listGeneratedSkillFiles(): GeneratedSkillFile[];
11
+ export declare function syncGeneratedSkills(skillsDir: string): void;
12
+ /** Returns human-readable issues; empty when every generated block is current. */
13
+ export declare function checkGeneratedSkills(skillsDir: string): string[];
@@ -0,0 +1,80 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { listGeneratedCommandSectionKeys, renderBundledSkillReference, renderErrorCodeReference, renderGeneratedCommandSection, renderPortableRuntimeContract, replaceGeneratedSection, } from '../commands/schema/renderSkills.js';
4
+ import { SKILL_REGISTRY } from './registry.js';
5
+ /** Every generated block in the published skill set, derived from the skill registry. */
6
+ export function listGeneratedSkillFiles() {
7
+ const files = [];
8
+ for (const entry of SKILL_REGISTRY) {
9
+ files.push({
10
+ skill: entry.name,
11
+ file: `${entry.name}/SKILL.md`,
12
+ marker: 'PORTABLE_RUNTIME',
13
+ render: renderPortableRuntimeContract,
14
+ });
15
+ for (const section of entry.generated) {
16
+ const key = section.key;
17
+ if (section.marker === 'GENERATED_COMMANDS' && !key) {
18
+ throw new Error(`${entry.name}/${section.file} GENERATED_COMMANDS section is missing a key`);
19
+ }
20
+ files.push({
21
+ skill: entry.name,
22
+ file: `${entry.name}/${section.file}`,
23
+ marker: section.marker,
24
+ render: section.marker === 'GENERATED_REFERENCE'
25
+ ? renderBundledSkillReference
26
+ : section.marker === 'GENERATED_ERRORS'
27
+ ? renderErrorCodeReference
28
+ : () => renderGeneratedCommandSection(key),
29
+ });
30
+ }
31
+ }
32
+ return files;
33
+ }
34
+ function applyGeneratedBlock(skillsDir, generated) {
35
+ const filePath = path.join(skillsDir, generated.file);
36
+ const current = fs.readFileSync(filePath, 'utf8');
37
+ return { current, next: replaceGeneratedSection(current, generated.marker, generated.render()) };
38
+ }
39
+ export function syncGeneratedSkills(skillsDir) {
40
+ for (const generated of listGeneratedSkillFiles()) {
41
+ const { current, next } = applyGeneratedBlock(skillsDir, generated);
42
+ if (next !== current) {
43
+ fs.writeFileSync(path.join(skillsDir, generated.file), next);
44
+ }
45
+ }
46
+ }
47
+ /** Returns human-readable issues; empty when every generated block is current. */
48
+ export function checkGeneratedSkills(skillsDir) {
49
+ const issues = [];
50
+ const usedKeys = new Set();
51
+ for (const entry of SKILL_REGISTRY) {
52
+ for (const section of entry.generated) {
53
+ if (section.key) {
54
+ if (usedKeys.has(section.key)) {
55
+ issues.push(`generated section key ${section.key} is used more than once`);
56
+ }
57
+ usedKeys.add(section.key);
58
+ }
59
+ }
60
+ }
61
+ for (const key of listGeneratedCommandSectionKeys()) {
62
+ if (!usedKeys.has(key)) {
63
+ issues.push(`generated section ${key} is configured but not registered for any skill file`);
64
+ }
65
+ }
66
+ for (const generated of listGeneratedSkillFiles()) {
67
+ let result;
68
+ try {
69
+ result = applyGeneratedBlock(skillsDir, generated);
70
+ }
71
+ catch (error) {
72
+ issues.push(`${generated.file}: ${error instanceof Error ? error.message : String(error)}`);
73
+ continue;
74
+ }
75
+ if (result.current !== result.next) {
76
+ issues.push(`${generated.file} ${generated.marker} block is stale; run pnpm skills:sync`);
77
+ }
78
+ }
79
+ return issues;
80
+ }
@@ -0,0 +1,13 @@
1
+ export type GeneratedSkillSection = Readonly<{
2
+ /** File path relative to the skill directory. */
3
+ file: string;
4
+ marker: 'GENERATED_COMMANDS' | 'GENERATED_REFERENCE' | 'GENERATED_ERRORS';
5
+ /** Section key in renderSkills; required for GENERATED_COMMANDS. */
6
+ key?: string;
7
+ }>;
8
+ export type SkillRegistryEntry = Readonly<{
9
+ name: string;
10
+ generated: readonly GeneratedSkillSection[];
11
+ }>;
12
+ export declare const SKILL_REGISTRY: readonly SkillRegistryEntry[];
13
+ export declare function listRegisteredSkillNames(): string[];
@@ -0,0 +1,58 @@
1
+ // Single source of truth for the published Dinox skill set. Generation
2
+ // (`pnpm skills:sync`), validation (`pnpm skills:check`), tests, and the
3
+ // collection manifest all derive their skill lists from this registry.
4
+ function commands(file, key) {
5
+ return Object.freeze({ file, marker: 'GENERATED_COMMANDS', key });
6
+ }
7
+ const REGISTRY_ENTRIES = [
8
+ { name: 'dino-auth', generated: [] },
9
+ { name: 'dino-config', generated: [] },
10
+ {
11
+ name: 'dino-dinox',
12
+ generated: [
13
+ { file: 'references/commands.md', marker: 'GENERATED_REFERENCE' },
14
+ { file: 'references/errors.md', marker: 'GENERATED_ERRORS' },
15
+ ],
16
+ },
17
+ {
18
+ name: 'dino-manage-boxes',
19
+ generated: [commands('SKILL.md', 'skill:dino-manage-boxes')],
20
+ },
21
+ {
22
+ name: 'dino-manage-prompts',
23
+ generated: [commands('SKILL.md', 'skill:dino-manage-prompts')],
24
+ },
25
+ {
26
+ name: 'dino-manage-tags',
27
+ generated: [commands('SKILL.md', 'skill:dino-manage-tags')],
28
+ },
29
+ {
30
+ name: 'dino-manage-todo',
31
+ generated: [
32
+ commands('references/todo-search.md', 'ref:dino-manage-todo:todo-search'),
33
+ commands('references/todo-mutations.md', 'ref:dino-manage-todo:todo-mutations'),
34
+ ],
35
+ },
36
+ {
37
+ name: 'dino-manage-views',
38
+ generated: [commands('SKILL.md', 'skill:dino-manage-views')],
39
+ },
40
+ {
41
+ name: 'dino-note',
42
+ generated: [
43
+ commands('references/search-and-read.md', 'ref:dino-note:search-and-read'),
44
+ commands('references/create.md', 'ref:dino-note:create'),
45
+ commands('references/update-and-delete.md', 'ref:dino-note:update-and-delete'),
46
+ ],
47
+ },
48
+ {
49
+ name: 'dino-storage',
50
+ generated: [commands('SKILL.md', 'skill:dino-storage')],
51
+ },
52
+ { name: 'dino-sync', generated: [] },
53
+ { name: 'dino-update-cli', generated: [] },
54
+ ];
55
+ export const SKILL_REGISTRY = Object.freeze(REGISTRY_ENTRIES.map((entry) => Object.freeze({ ...entry, generated: Object.freeze([...entry.generated]) })));
56
+ export function listRegisteredSkillNames() {
57
+ return SKILL_REGISTRY.map((entry) => entry.name);
58
+ }
@@ -0,0 +1,60 @@
1
+ import { SKILLS_REPO_SLUG } from '../constants/links.js';
2
+ export type RetiredSkill = Readonly<{
3
+ name: string;
4
+ replacement: string | null;
5
+ replacementNote?: string;
6
+ source: typeof SKILLS_REPO_SLUG;
7
+ skillFolderHash: string;
8
+ }>;
9
+ export type RetiredSkillsCleanupGuidance = Readonly<{
10
+ automaticRemoval: false;
11
+ inventoryCommand: string;
12
+ lockFile: string;
13
+ requiredMatchFields: readonly ['name', 'source', 'skillFolderHash'];
14
+ guidance: string;
15
+ }>;
16
+ export declare const RETIRED_SKILLS: readonly (Readonly<{
17
+ name: "create-note";
18
+ replacement: "dino-note";
19
+ source: "ryzencool/dinox-cli-skills";
20
+ skillFolderHash: "15a91b77e5032e614cbec95997de0f9697cee29c";
21
+ }> | Readonly<{
22
+ name: "dinox";
23
+ replacement: "dino-dinox";
24
+ source: "ryzencool/dinox-cli-skills";
25
+ skillFolderHash: "3089a4b076fffd8d6579db26c520f0d97e225a30";
26
+ }> | Readonly<{
27
+ name: "manage-boxes";
28
+ replacement: "dino-manage-boxes";
29
+ source: "ryzencool/dinox-cli-skills";
30
+ skillFolderHash: "49ffa648ab341bef20a9ea4696973d39c5c4e1c9";
31
+ }> | Readonly<{
32
+ name: "manage-tags";
33
+ replacement: "dino-manage-tags";
34
+ source: "ryzencool/dinox-cli-skills";
35
+ skillFolderHash: "801f6cc91d225503ad67054f66ac024cb12d01cb";
36
+ }> | Readonly<{
37
+ name: "search-notes";
38
+ replacement: "dino-note";
39
+ source: "ryzencool/dinox-cli-skills";
40
+ skillFolderHash: "88d3a95a3cb663b555e79be57d2135c0edbe8e0d";
41
+ }> | Readonly<{
42
+ name: "view-note";
43
+ replacement: "dino-note";
44
+ source: "ryzencool/dinox-cli-skills";
45
+ skillFolderHash: "639ce5941e19d4f5ffc3a4b5870486e741ab2937";
46
+ }> | Readonly<{
47
+ name: "dino-shared";
48
+ replacement: null;
49
+ replacementNote: "Runtime guidance is embedded in every current Dinox skill.";
50
+ source: "ryzencool/dinox-cli-skills";
51
+ skillFolderHash: "842fe8fd30020bf1b58718dcd438d78b4c7d8f33";
52
+ }>)[];
53
+ export declare const RETIRED_SKILLS_CLEANUP: Readonly<{
54
+ automaticRemoval: false;
55
+ inventoryCommand: string;
56
+ lockFile: string;
57
+ requiredMatchFields: readonly ["name", "source", "skillFolderHash"];
58
+ guidance: string;
59
+ }>;
60
+ export declare function formatRetiredSkillsSummary(): string;
@@ -0,0 +1,58 @@
1
+ import { SKILLS_INSTALLER_NAME, SKILLS_INSTALLER_VERSION, SKILLS_REPO_SLUG, } from '../constants/links.js';
2
+ export const RETIRED_SKILLS = Object.freeze([
3
+ Object.freeze({
4
+ name: 'create-note',
5
+ replacement: 'dino-note',
6
+ source: SKILLS_REPO_SLUG,
7
+ skillFolderHash: '15a91b77e5032e614cbec95997de0f9697cee29c',
8
+ }),
9
+ Object.freeze({
10
+ name: 'dinox',
11
+ replacement: 'dino-dinox',
12
+ source: SKILLS_REPO_SLUG,
13
+ skillFolderHash: '3089a4b076fffd8d6579db26c520f0d97e225a30',
14
+ }),
15
+ Object.freeze({
16
+ name: 'manage-boxes',
17
+ replacement: 'dino-manage-boxes',
18
+ source: SKILLS_REPO_SLUG,
19
+ skillFolderHash: '49ffa648ab341bef20a9ea4696973d39c5c4e1c9',
20
+ }),
21
+ Object.freeze({
22
+ name: 'manage-tags',
23
+ replacement: 'dino-manage-tags',
24
+ source: SKILLS_REPO_SLUG,
25
+ skillFolderHash: '801f6cc91d225503ad67054f66ac024cb12d01cb',
26
+ }),
27
+ Object.freeze({
28
+ name: 'search-notes',
29
+ replacement: 'dino-note',
30
+ source: SKILLS_REPO_SLUG,
31
+ skillFolderHash: '88d3a95a3cb663b555e79be57d2135c0edbe8e0d',
32
+ }),
33
+ Object.freeze({
34
+ name: 'view-note',
35
+ replacement: 'dino-note',
36
+ source: SKILLS_REPO_SLUG,
37
+ skillFolderHash: '639ce5941e19d4f5ffc3a4b5870486e741ab2937',
38
+ }),
39
+ Object.freeze({
40
+ name: 'dino-shared',
41
+ replacement: null,
42
+ replacementNote: 'Runtime guidance is embedded in every current Dinox skill.',
43
+ source: SKILLS_REPO_SLUG,
44
+ skillFolderHash: '842fe8fd30020bf1b58718dcd438d78b4c7d8f33',
45
+ }),
46
+ ]);
47
+ export const RETIRED_SKILLS_CLEANUP = Object.freeze({
48
+ automaticRemoval: false,
49
+ inventoryCommand: `npx --yes ${SKILLS_INSTALLER_NAME}@${SKILLS_INSTALLER_VERSION} list -g --json`,
50
+ lockFile: '~/.agents/.skill-lock.json',
51
+ requiredMatchFields: Object.freeze(['name', 'source', 'skillFolderHash']),
52
+ guidance: 'Use the inventory command to find candidates, then inspect the installer lock. Remove an installed skill only when its name, source, and skillFolderHash all match this official retired inventory. Never delete a skill directory or lock entry by name alone because unrelated skills can share an ID.',
53
+ });
54
+ export function formatRetiredSkillsSummary() {
55
+ return RETIRED_SKILLS.map((skill) => (skill.replacement
56
+ ? `${skill.name} -> ${skill.replacement}`
57
+ : `${skill.name} -> no direct replacement (${skill.replacementNote})`)).join('; ');
58
+ }
@@ -0,0 +1,8 @@
1
+ export type DeadlineOptions = {
2
+ deadlineAtMs?: number;
3
+ maximumTimeoutMs: number;
4
+ createTimeoutError: () => Error;
5
+ runWhenExpired?: boolean;
6
+ };
7
+ export declare function remainingDeadlineMs(deadlineAtMs: number | undefined, maximumTimeoutMs: number, now?: () => number): number;
8
+ export declare function runWithinDeadline<T>(run: () => Promise<T>, options: DeadlineOptions): Promise<T>;
@@ -0,0 +1,31 @@
1
+ export function remainingDeadlineMs(deadlineAtMs, maximumTimeoutMs, now = Date.now) {
2
+ const maximum = Number.isFinite(maximumTimeoutMs)
3
+ ? Math.max(0, Math.floor(maximumTimeoutMs))
4
+ : 0;
5
+ if (deadlineAtMs === undefined) {
6
+ return maximum;
7
+ }
8
+ return Math.max(0, Math.min(maximum, Math.floor(deadlineAtMs - now())));
9
+ }
10
+ export async function runWithinDeadline(run, options) {
11
+ if (options.deadlineAtMs === undefined) {
12
+ return run();
13
+ }
14
+ const remainingMs = remainingDeadlineMs(options.deadlineAtMs, options.maximumTimeoutMs);
15
+ if (remainingMs <= 0 && !options.runWhenExpired) {
16
+ throw options.createTimeoutError();
17
+ }
18
+ const operation = Promise.resolve().then(run);
19
+ let timer;
20
+ const timeout = new Promise((_resolve, reject) => {
21
+ timer = setTimeout(() => reject(options.createTimeoutError()), Math.max(1, remainingMs));
22
+ });
23
+ try {
24
+ return await Promise.race([operation, timeout]);
25
+ }
26
+ finally {
27
+ if (timer) {
28
+ clearTimeout(timer);
29
+ }
30
+ }
31
+ }
@@ -8,6 +8,25 @@ export type DryRunPreview = {
8
8
  inputs?: Record<string, unknown>;
9
9
  targets?: Array<Record<string, unknown>>;
10
10
  changes?: Record<string, unknown> | Array<Record<string, unknown>>;
11
+ stale?: boolean;
12
+ sync?: {
13
+ offline: boolean;
14
+ gate: {
15
+ ok: boolean;
16
+ reasons: string[];
17
+ } | null;
18
+ };
11
19
  };
20
+ export type DryRunExecutionState = {
21
+ offline: boolean;
22
+ stale: boolean;
23
+ sync?: {
24
+ gate?: {
25
+ ok: boolean;
26
+ reasons: string[];
27
+ } | null;
28
+ };
29
+ };
30
+ export declare function attachDryRunExecutionState(preview: DryRunPreview, state: DryRunExecutionState): DryRunPreview;
12
31
  export declare function formatDryRunPreview(preview: DryRunPreview): string;
13
- export declare function printDryRunPreview(preview: DryRunPreview): void;
32
+ export declare function printDryRunPreview(preview: DryRunPreview, state?: DryRunExecutionState): void;
@@ -1,4 +1,14 @@
1
1
  import { getRequestedStructuredOutputFormat, printHumanReadableBlock, printSuccess, } from './output.js';
2
+ export function attachDryRunExecutionState(preview, state) {
3
+ return {
4
+ ...preview,
5
+ stale: state.offline || state.stale,
6
+ sync: {
7
+ offline: state.offline,
8
+ gate: state.sync?.gate ?? null,
9
+ },
10
+ };
11
+ }
2
12
  function formatValue(value) {
3
13
  if (value === null || value === undefined) {
4
14
  return String(value);
@@ -36,6 +46,14 @@ export function formatDryRunPreview(preview) {
36
46
  `Risk: ${preview.risk}`,
37
47
  `Summary: ${preview.summary}`,
38
48
  ];
49
+ if (typeof preview.stale === 'boolean') {
50
+ lines.push(`Freshness: ${preview.stale ? 'stale' : 'fresh'}`);
51
+ }
52
+ if (preview.sync) {
53
+ const gate = preview.sync.gate;
54
+ const gateSummary = gate ? (gate.ok ? 'ok' : `blocked (${gate.reasons.join(', ')})`) : 'not evaluated';
55
+ lines.push(`Sync: ${preview.sync.offline ? 'offline' : 'online'}; gate ${gateSummary}`);
56
+ }
39
57
  if (preview.warnings && preview.warnings.length > 0) {
40
58
  lines.push('');
41
59
  lines.push('Warnings:');
@@ -60,10 +78,11 @@ export function formatDryRunPreview(preview) {
60
78
  }
61
79
  return `${lines.join('\n')}\n`;
62
80
  }
63
- export function printDryRunPreview(preview) {
81
+ export function printDryRunPreview(preview, state) {
82
+ const output = state ? attachDryRunExecutionState(preview, state) : preview;
64
83
  if (getRequestedStructuredOutputFormat()) {
65
- printSuccess(preview);
84
+ printSuccess(output);
66
85
  return;
67
86
  }
68
- printHumanReadableBlock(formatDryRunPreview(preview));
87
+ printHumanReadableBlock(formatDryRunPreview(output));
69
88
  }