@tenonhq/dovetail-core 0.0.94 → 0.0.95
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/dist/commander.js +26 -3
- package/dist/schemaCommand.js +101 -7
- package/package.json +2 -2
- package/release-manifest.json +109 -1
package/dist/commander.js
CHANGED
|
@@ -334,10 +334,10 @@ async function initCommands() {
|
|
|
334
334
|
}, async (args) => {
|
|
335
335
|
await (0, dashboardCommand_1.dashboardCommand)(args);
|
|
336
336
|
})
|
|
337
|
-
.command("schema <subcommand>", "Manage ServiceNow table schemas (subcommands: pull)", (cmdArgs) => {
|
|
337
|
+
.command("schema <subcommand>", "Manage ServiceNow table schemas (subcommands: pull, diff, snapshots)", (cmdArgs) => {
|
|
338
338
|
cmdArgs.positional("subcommand", {
|
|
339
339
|
describe: "Schema subcommand to run",
|
|
340
|
-
choices: ["pull"],
|
|
340
|
+
choices: ["pull", "diff", "snapshots"],
|
|
341
341
|
});
|
|
342
342
|
cmdArgs.options({
|
|
343
343
|
...sharedOptions,
|
|
@@ -349,7 +349,24 @@ async function initCommands() {
|
|
|
349
349
|
scope: {
|
|
350
350
|
alias: "s",
|
|
351
351
|
type: "string",
|
|
352
|
-
describe: "
|
|
352
|
+
describe: "Single scope (default: all scopes from dove.config.js)",
|
|
353
|
+
},
|
|
354
|
+
snapshot: {
|
|
355
|
+
type: "string",
|
|
356
|
+
describe: "pull: also save an immutable snapshot with this label (timestamp-only if no label)",
|
|
357
|
+
},
|
|
358
|
+
from: {
|
|
359
|
+
type: "string",
|
|
360
|
+
describe: "diff: baseline ref — a snapshot label, snapshot dir name, or directory path (default: newest snapshot)",
|
|
361
|
+
},
|
|
362
|
+
to: {
|
|
363
|
+
type: "string",
|
|
364
|
+
describe: 'diff: comparison ref — "live" for a fresh pull, or a snapshot ref (default: live)',
|
|
365
|
+
},
|
|
366
|
+
format: {
|
|
367
|
+
type: "string",
|
|
368
|
+
choices: ["text", "json"],
|
|
369
|
+
describe: "diff: output format (default: text)",
|
|
353
370
|
},
|
|
354
371
|
});
|
|
355
372
|
return cmdArgs;
|
|
@@ -357,6 +374,12 @@ async function initCommands() {
|
|
|
357
374
|
if (args.subcommand === "pull") {
|
|
358
375
|
await (0, schemaCommand_1.schemaPullCommand)(args);
|
|
359
376
|
}
|
|
377
|
+
else if (args.subcommand === "diff") {
|
|
378
|
+
await (0, schemaCommand_1.schemaDiffCommand)(args);
|
|
379
|
+
}
|
|
380
|
+
else if (args.subcommand === "snapshots") {
|
|
381
|
+
await (0, schemaCommand_1.schemaSnapshotsCommand)(args);
|
|
382
|
+
}
|
|
360
383
|
})
|
|
361
384
|
.command("init-claude", "Install Dovetail Claude Code skills to .claude/commands/", (cmdArgs) => {
|
|
362
385
|
cmdArgs.options({
|
package/dist/schemaCommand.js
CHANGED
|
@@ -37,32 +37,46 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.schemaPullCommand = schemaPullCommand;
|
|
40
|
+
exports.schemaDiffCommand = schemaDiffCommand;
|
|
41
|
+
exports.schemaSnapshotsCommand = schemaSnapshotsCommand;
|
|
40
42
|
const dovetail_schema_1 = require("@tenonhq/dovetail-schema");
|
|
41
43
|
const Logger_1 = require("./Logger");
|
|
42
44
|
const ConfigManager = __importStar(require("./config"));
|
|
43
45
|
const path_1 = __importDefault(require("path"));
|
|
44
|
-
|
|
46
|
+
const os_1 = __importDefault(require("os"));
|
|
47
|
+
const fs_1 = require("fs");
|
|
48
|
+
function requireCreds() {
|
|
45
49
|
const { SN_USER = "", SN_PASSWORD = "", SN_INSTANCE = "" } = process.env;
|
|
46
50
|
if (!SN_USER || !SN_PASSWORD || !SN_INSTANCE) {
|
|
47
51
|
throw new Error("Missing ServiceNow credentials. Ensure SN_INSTANCE, SN_USER, and SN_PASSWORD are set in your .env file or environment.");
|
|
48
52
|
}
|
|
53
|
+
return { SN_USER, SN_PASSWORD, SN_INSTANCE };
|
|
54
|
+
}
|
|
55
|
+
function normalizeInstance(instance) {
|
|
56
|
+
return instance.replace(/^https?:\/\//, "").replace(/\/$/, "");
|
|
57
|
+
}
|
|
58
|
+
function resolveScopes(args) {
|
|
49
59
|
const config = ConfigManager.getConfig();
|
|
50
60
|
const configScopes = config.scopes ? Object.keys(config.scopes) : [];
|
|
51
61
|
if (configScopes.length === 0) {
|
|
52
62
|
throw new Error("No scopes configured in dove.config.js. Add scopes to the 'scopes' object in your configuration.");
|
|
53
63
|
}
|
|
54
|
-
// If --scope flag is provided, filter to that single scope
|
|
55
|
-
let scopes = configScopes;
|
|
56
64
|
if (args.scope) {
|
|
57
65
|
if (!configScopes.includes(args.scope)) {
|
|
58
66
|
throw new Error(`Scope "${args.scope}" is not configured in dove.config.js. Available scopes: ${configScopes.join(", ")}`);
|
|
59
67
|
}
|
|
60
|
-
|
|
68
|
+
return [args.scope];
|
|
61
69
|
}
|
|
70
|
+
return configScopes;
|
|
71
|
+
}
|
|
72
|
+
function outputDirFor(args) {
|
|
62
73
|
const rootDir = ConfigManager.getRootDir();
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
74
|
+
return args.output ? path_1.default.resolve(args.output) : path_1.default.join(rootDir, "schema");
|
|
75
|
+
}
|
|
76
|
+
async function schemaPullCommand(args) {
|
|
77
|
+
const { SN_USER, SN_PASSWORD, SN_INSTANCE } = requireCreds();
|
|
78
|
+
const scopes = resolveScopes(args);
|
|
79
|
+
const outputDir = outputDirFor(args);
|
|
66
80
|
try {
|
|
67
81
|
const index = await (0, dovetail_schema_1.pullSchema)({
|
|
68
82
|
instance: SN_INSTANCE,
|
|
@@ -72,6 +86,18 @@ async function schemaPullCommand(args) {
|
|
|
72
86
|
scopes,
|
|
73
87
|
});
|
|
74
88
|
Logger_1.logger.success(`Schema pull complete! ${index.total_tables} tables across ${index.applications.length} applications written to ${outputDir}`);
|
|
89
|
+
if (args.snapshot !== undefined && args.snapshot !== false) {
|
|
90
|
+
const label = typeof args.snapshot === "string" && args.snapshot.length > 0
|
|
91
|
+
? args.snapshot
|
|
92
|
+
: null;
|
|
93
|
+
const info = await (0, dovetail_schema_1.writeSnapshot)({
|
|
94
|
+
outputDir,
|
|
95
|
+
index,
|
|
96
|
+
label,
|
|
97
|
+
now: new Date().toISOString(),
|
|
98
|
+
});
|
|
99
|
+
Logger_1.logger.success("Snapshot saved" + (label ? ` (${label})` : "") + ": " + info.dir);
|
|
100
|
+
}
|
|
75
101
|
}
|
|
76
102
|
catch (e) {
|
|
77
103
|
let message;
|
|
@@ -83,3 +109,71 @@ async function schemaPullCommand(args) {
|
|
|
83
109
|
throw e;
|
|
84
110
|
}
|
|
85
111
|
}
|
|
112
|
+
// Resolve a diff ref to a directory of schema files. `live` triggers a fresh
|
|
113
|
+
// pull into a temp dir; everything else resolves to a snapshot/baseline dir.
|
|
114
|
+
async function resolveRefDir(options) {
|
|
115
|
+
const { ref, outputDir, instance, scopes, creds } = options;
|
|
116
|
+
if (ref === "live") {
|
|
117
|
+
const tmpDir = await fs_1.promises.mkdtemp(path_1.default.join(os_1.default.tmpdir(), "dove-schema-live-"));
|
|
118
|
+
await (0, dovetail_schema_1.pullSchema)({
|
|
119
|
+
instance: creds.SN_INSTANCE,
|
|
120
|
+
username: creds.SN_USER,
|
|
121
|
+
password: creds.SN_PASSWORD,
|
|
122
|
+
outputDir: tmpDir,
|
|
123
|
+
scopes,
|
|
124
|
+
});
|
|
125
|
+
return tmpDir;
|
|
126
|
+
}
|
|
127
|
+
return (0, dovetail_schema_1.resolveSnapshotDir)({ ref, outputDir, instance });
|
|
128
|
+
}
|
|
129
|
+
async function schemaDiffCommand(args) {
|
|
130
|
+
const creds = requireCreds();
|
|
131
|
+
const instance = normalizeInstance(creds.SN_INSTANCE);
|
|
132
|
+
const outputDir = outputDirFor(args);
|
|
133
|
+
const scopes = resolveScopes(args);
|
|
134
|
+
const scope = args.scope || null;
|
|
135
|
+
const format = args.format === "json" ? "json" : "text";
|
|
136
|
+
// Default `from` = newest snapshot for this instance; default `to` = live.
|
|
137
|
+
let fromRef = args.from;
|
|
138
|
+
if (!fromRef) {
|
|
139
|
+
const snapshots = await (0, dovetail_schema_1.listSnapshots)({ outputDir, instance });
|
|
140
|
+
if (snapshots.length === 0) {
|
|
141
|
+
throw new Error("No --from given and no snapshots found for " +
|
|
142
|
+
instance +
|
|
143
|
+
". Create one with `dove schema pull --snapshot <label>`, or pass --from <path>.");
|
|
144
|
+
}
|
|
145
|
+
fromRef = path_1.default.basename(snapshots[0].dir);
|
|
146
|
+
}
|
|
147
|
+
const toRef = args.to || "live";
|
|
148
|
+
const fromDir = await resolveRefDir({ ref: fromRef, outputDir, instance, scopes, creds });
|
|
149
|
+
const toDir = await resolveRefDir({ ref: toRef, outputDir, instance, scopes, creds });
|
|
150
|
+
const from = await (0, dovetail_schema_1.readSchemaTree)({ dir: fromDir, scope });
|
|
151
|
+
const to = await (0, dovetail_schema_1.readSchemaTree)({ dir: toDir, scope });
|
|
152
|
+
const diff = (0, dovetail_schema_1.diffSchemas)({ from, to, fromRef, toRef, scope });
|
|
153
|
+
// Print with console.log so formatDiff's own severity colors survive (the
|
|
154
|
+
// winston logger re-wraps every line in a single color).
|
|
155
|
+
console.log((0, dovetail_schema_1.formatDiff)(diff, { format }));
|
|
156
|
+
// Non-zero exit on breaking drift, for CI gating.
|
|
157
|
+
process.exitCode = diff.exit_code;
|
|
158
|
+
}
|
|
159
|
+
async function schemaSnapshotsCommand(args) {
|
|
160
|
+
const creds = requireCreds();
|
|
161
|
+
const instance = normalizeInstance(creds.SN_INSTANCE);
|
|
162
|
+
const outputDir = outputDirFor(args);
|
|
163
|
+
const snapshots = await (0, dovetail_schema_1.listSnapshots)({ outputDir, instance });
|
|
164
|
+
if (snapshots.length === 0) {
|
|
165
|
+
Logger_1.logger.info("No snapshots for " +
|
|
166
|
+
instance +
|
|
167
|
+
". Create one with `dove schema pull --snapshot <label>`.");
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
Logger_1.logger.info("Snapshots for " + instance + ":");
|
|
171
|
+
for (const snap of snapshots) {
|
|
172
|
+
console.log(" " +
|
|
173
|
+
path_1.default.basename(snap.dir) +
|
|
174
|
+
" " +
|
|
175
|
+
snap.total_tables +
|
|
176
|
+
" tables" +
|
|
177
|
+
(snap.label ? " [" + snap.label + "]" : ""));
|
|
178
|
+
}
|
|
179
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tenonhq/dovetail-core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.95",
|
|
4
4
|
"description": "Next-gen file syncer",
|
|
5
5
|
"license": "GPL-3.0",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@tenonhq/dovetail-clickup": "^0.0.10",
|
|
42
|
-
"@tenonhq/dovetail-schema": "^0.0.
|
|
42
|
+
"@tenonhq/dovetail-schema": "^0.0.9",
|
|
43
43
|
"axios": "^1.5.1",
|
|
44
44
|
"axios-cookiejar-support": "^4.0.7",
|
|
45
45
|
"axios-rate-limit": "^1.3.0",
|
package/release-manifest.json
CHANGED
|
@@ -1,7 +1,115 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "dovetail-manifest/v1",
|
|
3
|
-
"generated_at": "2026-05-
|
|
3
|
+
"generated_at": "2026-05-29T16:55:37.736Z",
|
|
4
4
|
"events": [
|
|
5
|
+
{
|
|
6
|
+
"$schema": "dovetail-release-event/v1",
|
|
7
|
+
"event_id": "dovetail-dashboard@0.0.33",
|
|
8
|
+
"package": "@tenonhq/dovetail-dashboard",
|
|
9
|
+
"version": "0.0.33",
|
|
10
|
+
"prev_version": "0.0.32",
|
|
11
|
+
"published_at": "2026-05-29T16:55:37.729Z",
|
|
12
|
+
"git": {
|
|
13
|
+
"sha": "3aaef1ba92364c119ece69369c5cc3379da0ed73",
|
|
14
|
+
"tag": "dovetail-dashboard@0.0.33"
|
|
15
|
+
},
|
|
16
|
+
"semver_bump": "patch",
|
|
17
|
+
"commits": [
|
|
18
|
+
{
|
|
19
|
+
"sha": "3aaef1ba9",
|
|
20
|
+
"subject": "fix: legible inline code in Claude Plans dark mode (#120)",
|
|
21
|
+
"pr": 120
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"sha": "92213e1f8",
|
|
25
|
+
"subject": "chore(release): publish 2 packages [skip ci]"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"exports_delta": null,
|
|
29
|
+
"narrative": null
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"$schema": "dovetail-release-event/v1",
|
|
33
|
+
"event_id": "dovetail-claude-plans@0.0.20",
|
|
34
|
+
"package": "@tenonhq/dovetail-claude-plans",
|
|
35
|
+
"version": "0.0.20",
|
|
36
|
+
"prev_version": "0.0.19",
|
|
37
|
+
"published_at": "2026-05-29T02:18:11.229Z",
|
|
38
|
+
"git": {
|
|
39
|
+
"sha": "6a12c10733b64732855a8125c84f0d4846ced256",
|
|
40
|
+
"tag": "dovetail-claude-plans@0.0.20"
|
|
41
|
+
},
|
|
42
|
+
"semver_bump": "patch",
|
|
43
|
+
"commits": [
|
|
44
|
+
{
|
|
45
|
+
"sha": "6a12c1073",
|
|
46
|
+
"subject": "feat: claude-plans version history, feature score, selected-state + deep-link hardening (#118)",
|
|
47
|
+
"pr": 118
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"sha": "578d6fb2a",
|
|
51
|
+
"subject": "chore(release): publish 2 packages [skip ci]"
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
"exports_delta": null,
|
|
55
|
+
"narrative": null
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"$schema": "dovetail-release-event/v1",
|
|
59
|
+
"event_id": "dovetail-dashboard@0.0.32",
|
|
60
|
+
"package": "@tenonhq/dovetail-dashboard",
|
|
61
|
+
"version": "0.0.32",
|
|
62
|
+
"prev_version": "0.0.31",
|
|
63
|
+
"published_at": "2026-05-29T02:18:11.229Z",
|
|
64
|
+
"git": {
|
|
65
|
+
"sha": "6a12c10733b64732855a8125c84f0d4846ced256",
|
|
66
|
+
"tag": "dovetail-dashboard@0.0.32"
|
|
67
|
+
},
|
|
68
|
+
"semver_bump": "patch",
|
|
69
|
+
"commits": [
|
|
70
|
+
{
|
|
71
|
+
"sha": "6a12c1073",
|
|
72
|
+
"subject": "feat: claude-plans version history, feature score, selected-state + deep-link hardening (#118)",
|
|
73
|
+
"pr": 118
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"sha": "578d6fb2a",
|
|
77
|
+
"subject": "chore(release): publish 2 packages [skip ci]"
|
|
78
|
+
}
|
|
79
|
+
],
|
|
80
|
+
"exports_delta": null,
|
|
81
|
+
"narrative": null
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"$schema": "dovetail-release-event/v1",
|
|
85
|
+
"event_id": "dovetail-core@0.0.94",
|
|
86
|
+
"package": "@tenonhq/dovetail-core",
|
|
87
|
+
"version": "0.0.94",
|
|
88
|
+
"prev_version": "0.0.93",
|
|
89
|
+
"published_at": "2026-05-28T23:46:03.175Z",
|
|
90
|
+
"git": {
|
|
91
|
+
"sha": "8a76deffc38892321c92ae538fee3bc6b8f90d76",
|
|
92
|
+
"tag": "dovetail-core@0.0.94"
|
|
93
|
+
},
|
|
94
|
+
"semver_bump": "patch",
|
|
95
|
+
"commits": [
|
|
96
|
+
{
|
|
97
|
+
"sha": "8a76deffc",
|
|
98
|
+
"subject": "fix: filesystem-safe record folder names (sys_id fallback for Windows) (#117)",
|
|
99
|
+
"pr": 117
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"sha": "578d6fb2a",
|
|
103
|
+
"subject": "chore(release): publish 2 packages [skip ci]"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"sha": "3faeec43f",
|
|
107
|
+
"subject": "chore(release): @tenonhq/dovetail-core@0.0.93 [skip ci]"
|
|
108
|
+
}
|
|
109
|
+
],
|
|
110
|
+
"exports_delta": null,
|
|
111
|
+
"narrative": null
|
|
112
|
+
},
|
|
5
113
|
{
|
|
6
114
|
"$schema": "dovetail-release-event/v1",
|
|
7
115
|
"event_id": "dovetail-claude-plans@0.0.19",
|