@duckcodeailabs/dql-cli 1.5.3 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -9
- package/dist/apps-api.js +11 -4
- package/dist/apps-api.js.map +1 -1
- package/dist/args.d.ts +6 -0
- package/dist/args.d.ts.map +1 -1
- package/dist/args.js +9 -0
- package/dist/args.js.map +1 -1
- package/dist/assets/dql-notebook/assets/index-C-s-OCLW.css +1 -0
- package/dist/assets/dql-notebook/assets/{index-B5jI3I8Q.js → index-DZ_5zsCw.js} +123 -123
- package/dist/assets/dql-notebook/index.html +2 -2
- package/dist/commands/certify.d.ts.map +1 -1
- package/dist/commands/certify.js +55 -5
- package/dist/commands/certify.js.map +1 -1
- package/dist/commands/compile.d.ts.map +1 -1
- package/dist/commands/compile.js +3 -0
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +91 -4
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/doctor.test.js +1 -0
- package/dist/commands/doctor.test.js.map +1 -1
- package/dist/commands/info.d.ts.map +1 -1
- package/dist/commands/info.js +21 -6
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +2 -1
- package/dist/commands/migrate.js.map +1 -1
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +6 -5
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/verify.d.ts +1 -1
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +36 -6
- package/dist/commands/verify.js.map +1 -1
- package/dist/index.js +72 -4
- package/dist/index.js.map +1 -1
- package/dist/local-runtime.d.ts +2 -0
- package/dist/local-runtime.d.ts.map +1 -1
- package/dist/local-runtime.js +51 -12
- package/dist/local-runtime.js.map +1 -1
- package/dist/promote-from-draft.d.ts +40 -0
- package/dist/promote-from-draft.d.ts.map +1 -0
- package/dist/promote-from-draft.js +164 -0
- package/dist/promote-from-draft.js.map +1 -0
- package/dist/promote-from-draft.test.d.ts +2 -0
- package/dist/promote-from-draft.test.d.ts.map +1 -0
- package/dist/promote-from-draft.test.js +149 -0
- package/dist/promote-from-draft.test.js.map +1 -0
- package/dist/template-adoption.test.d.ts +2 -0
- package/dist/template-adoption.test.d.ts.map +1 -0
- package/dist/template-adoption.test.js +102 -0
- package/dist/template-adoption.test.js.map +1 -0
- package/package.json +12 -12
- package/dist/assets/dql-notebook/assets/index-cv-O4BEj.css +0 -1
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { CLIFlags } from './args.js';
|
|
2
|
+
export interface PromoteResult {
|
|
3
|
+
ok: boolean;
|
|
4
|
+
message: string;
|
|
5
|
+
/** The path the draft moved to (relative to projectRoot). */
|
|
6
|
+
certifiedPath?: string;
|
|
7
|
+
/** The patch the human still needs to apply to datalex-manifest.json. */
|
|
8
|
+
datalexManifestDiff?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Promote a Tier-2 draft block from `blocks/_drafts/<slug>.dql` to the
|
|
12
|
+
* canonical `blocks/<domain>/<slug>.dql` location, flipping `status` to
|
|
13
|
+
* `certified` and setting the `datalex_contract` reference.
|
|
14
|
+
*
|
|
15
|
+
* Companion to the dql-mcp `query_via_metadata` tool. Together they close
|
|
16
|
+
* the graduated-trust promotion loop:
|
|
17
|
+
*
|
|
18
|
+
* ask -> no Tier-1 hit -> query_via_metadata writes a draft
|
|
19
|
+
* -> human reviews / refines
|
|
20
|
+
* -> dql certify --from-draft <path>
|
|
21
|
+
* -> next ask hits Tier-1 forever
|
|
22
|
+
*
|
|
23
|
+
* Behavior:
|
|
24
|
+
* 1. Validates the draft exists, has status=draft, and has a sane
|
|
25
|
+
* `_proposed { proposed_contract_id = ... }` block.
|
|
26
|
+
* 2. Moves the file to blocks/<domain>/<slug>.dql.
|
|
27
|
+
* 3. Flips `status = "draft"` to `status = "certified"`.
|
|
28
|
+
* 4. Sets `datalex_contract = "<contract>"` (provided via --contract or
|
|
29
|
+
* taken from `_proposed.proposed_contract_id` with `@1` appended).
|
|
30
|
+
* 5. Sets `owner = "<owner>"` from --owner if provided.
|
|
31
|
+
* 6. Drops the `_proposed { ... }` provenance block (its job is done).
|
|
32
|
+
* 7. Computes the patch the human still needs to apply to
|
|
33
|
+
* datalex-manifest.json (or surfaces it for --open-pr).
|
|
34
|
+
*
|
|
35
|
+
* Does NOT auto-modify datalex-manifest.json. That file is hand-curated
|
|
36
|
+
* until the DataLex compiler ships its v1 emitter; this command shows
|
|
37
|
+
* the user the exact diff to apply.
|
|
38
|
+
*/
|
|
39
|
+
export declare function promoteFromDraft(projectRoot: string, flags: CLIFlags): PromoteResult;
|
|
40
|
+
//# sourceMappingURL=promote-from-draft.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promote-from-draft.d.ts","sourceRoot":"","sources":["../src/promote-from-draft.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yEAAyE;IACzE,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,QAAQ,GACd,aAAa,CAyEf"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join, resolve } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Promote a Tier-2 draft block from `blocks/_drafts/<slug>.dql` to the
|
|
5
|
+
* canonical `blocks/<domain>/<slug>.dql` location, flipping `status` to
|
|
6
|
+
* `certified` and setting the `datalex_contract` reference.
|
|
7
|
+
*
|
|
8
|
+
* Companion to the dql-mcp `query_via_metadata` tool. Together they close
|
|
9
|
+
* the graduated-trust promotion loop:
|
|
10
|
+
*
|
|
11
|
+
* ask -> no Tier-1 hit -> query_via_metadata writes a draft
|
|
12
|
+
* -> human reviews / refines
|
|
13
|
+
* -> dql certify --from-draft <path>
|
|
14
|
+
* -> next ask hits Tier-1 forever
|
|
15
|
+
*
|
|
16
|
+
* Behavior:
|
|
17
|
+
* 1. Validates the draft exists, has status=draft, and has a sane
|
|
18
|
+
* `_proposed { proposed_contract_id = ... }` block.
|
|
19
|
+
* 2. Moves the file to blocks/<domain>/<slug>.dql.
|
|
20
|
+
* 3. Flips `status = "draft"` to `status = "certified"`.
|
|
21
|
+
* 4. Sets `datalex_contract = "<contract>"` (provided via --contract or
|
|
22
|
+
* taken from `_proposed.proposed_contract_id` with `@1` appended).
|
|
23
|
+
* 5. Sets `owner = "<owner>"` from --owner if provided.
|
|
24
|
+
* 6. Drops the `_proposed { ... }` provenance block (its job is done).
|
|
25
|
+
* 7. Computes the patch the human still needs to apply to
|
|
26
|
+
* datalex-manifest.json (or surfaces it for --open-pr).
|
|
27
|
+
*
|
|
28
|
+
* Does NOT auto-modify datalex-manifest.json. That file is hand-curated
|
|
29
|
+
* until the DataLex compiler ships its v1 emitter; this command shows
|
|
30
|
+
* the user the exact diff to apply.
|
|
31
|
+
*/
|
|
32
|
+
export function promoteFromDraft(projectRoot, flags) {
|
|
33
|
+
const draftPathInput = flags.fromDraft;
|
|
34
|
+
const draftAbs = resolve(projectRoot, draftPathInput);
|
|
35
|
+
if (!existsSync(draftAbs)) {
|
|
36
|
+
return { ok: false, message: `Draft not found at ${draftPathInput}.` };
|
|
37
|
+
}
|
|
38
|
+
const content = readFileSync(draftAbs, 'utf-8');
|
|
39
|
+
if (!/status\s*=\s*"draft"/.test(content)) {
|
|
40
|
+
return {
|
|
41
|
+
ok: false,
|
|
42
|
+
message: `${draftPathInput} does not have status="draft". Use dql certify <path> (without --from-draft) to evaluate governance rules.`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const proposedContractId = pickField(content, 'proposed_contract_id') ?? '';
|
|
46
|
+
const contract = flags.contract || (proposedContractId ? `${proposedContractId}@1` : '');
|
|
47
|
+
if (!contract) {
|
|
48
|
+
return {
|
|
49
|
+
ok: false,
|
|
50
|
+
message: 'No --contract <id@version> provided and no proposed_contract_id in the draft. ' +
|
|
51
|
+
'Either pass --contract commerce.Customer.foo@1 or restore the _proposed block.',
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const domain = flags.domain || pickField(content, 'proposed_domain') || guessDomain(contract);
|
|
55
|
+
if (!domain) {
|
|
56
|
+
return {
|
|
57
|
+
ok: false,
|
|
58
|
+
message: 'No --domain provided and could not infer one from the contract id.',
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const slug = inferSlugFromPath(draftAbs);
|
|
62
|
+
const destAbs = join(projectRoot, 'blocks', domain, `${slug}.dql`);
|
|
63
|
+
if (existsSync(destAbs) && !flags.force) {
|
|
64
|
+
return {
|
|
65
|
+
ok: false,
|
|
66
|
+
message: `${shortPath(projectRoot, destAbs)} already exists. ` +
|
|
67
|
+
'Pass --force to overwrite, or rename the draft.',
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const promoted = renderPromoted(content, {
|
|
71
|
+
contract,
|
|
72
|
+
domain,
|
|
73
|
+
owner: flags.owner || pickField(content, 'owner') || '',
|
|
74
|
+
});
|
|
75
|
+
mkdirSync(dirname(destAbs), { recursive: true });
|
|
76
|
+
writeFileSync(destAbs, promoted);
|
|
77
|
+
// The draft and the certified copy must not coexist. Drop the draft now
|
|
78
|
+
// that the certified file is on disk.
|
|
79
|
+
unlinkSync(draftAbs);
|
|
80
|
+
const datalexManifestDiff = renderDataLexManifestDiff({
|
|
81
|
+
contract,
|
|
82
|
+
domain,
|
|
83
|
+
slug,
|
|
84
|
+
description: pickField(content, 'description') ?? '',
|
|
85
|
+
});
|
|
86
|
+
return {
|
|
87
|
+
ok: true,
|
|
88
|
+
message: `Promoted ${shortPath(projectRoot, draftAbs)} -> ${shortPath(projectRoot, destAbs)}.`,
|
|
89
|
+
certifiedPath: shortPath(projectRoot, destAbs),
|
|
90
|
+
datalexManifestDiff,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
// -- helpers ---------------------------------------------------------------
|
|
94
|
+
function pickField(content, key) {
|
|
95
|
+
const m = content.match(new RegExp(`${key}\\s*=\\s*"([^"]*)"`)) ||
|
|
96
|
+
content.match(new RegExp(`${key}\\s*=\\s*"""([\\s\\S]*?)"""`));
|
|
97
|
+
return m?.[1]?.trim();
|
|
98
|
+
}
|
|
99
|
+
function guessDomain(contractId) {
|
|
100
|
+
const head = contractId.split('.')[0];
|
|
101
|
+
return head && head !== contractId ? head : null;
|
|
102
|
+
}
|
|
103
|
+
function inferSlugFromPath(absPath) {
|
|
104
|
+
return absPath.replace(/.*\//, '').replace(/\.dql$/, '');
|
|
105
|
+
}
|
|
106
|
+
function shortPath(projectRoot, abs) {
|
|
107
|
+
const root = projectRoot.endsWith('/') ? projectRoot : projectRoot + '/';
|
|
108
|
+
return abs.startsWith(root) ? abs.slice(root.length) : abs;
|
|
109
|
+
}
|
|
110
|
+
function renderPromoted(source, fields) {
|
|
111
|
+
let out = source;
|
|
112
|
+
// Flip status.
|
|
113
|
+
out = out.replace(/status\s*=\s*"draft"/, 'status = "certified"');
|
|
114
|
+
// Set domain (overwrite the existing one).
|
|
115
|
+
out = out.replace(/(domain\s*=\s*)"[^"]*"/, `$1"${fields.domain}"`);
|
|
116
|
+
// Set datalex_contract. The draft template ships an empty value
|
|
117
|
+
// (`datalex_contract = ""`); replace with the provided id@version.
|
|
118
|
+
out = out.replace(/datalex_contract\s*=\s*"[^"]*"/, `datalex_contract = "${fields.contract}"`);
|
|
119
|
+
// Set owner if provided + the field exists in the file.
|
|
120
|
+
if (fields.owner) {
|
|
121
|
+
if (/owner\s*=\s*"[^"]*"/.test(out)) {
|
|
122
|
+
out = out.replace(/owner\s*=\s*"[^"]*"/, `owner = "${fields.owner}"`);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
// Insert owner right after the status line.
|
|
126
|
+
out = out.replace(/(status\s*=\s*"certified"\s*\n)/, `$1 owner = "${fields.owner}"\n`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Drop the _proposed { ... } provenance block. Its job is done; the
|
|
130
|
+
// certified block is the new source of truth and should not carry the
|
|
131
|
+
// capture metadata.
|
|
132
|
+
out = out.replace(/\n\s*_proposed\s*\{[^}]*\}\s*\n/, '\n');
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
function renderDataLexManifestDiff(fields) {
|
|
136
|
+
const [contractId, versionStr] = fields.contract.split('@');
|
|
137
|
+
const version = Number.parseInt(versionStr ?? '1', 10) || 1;
|
|
138
|
+
const parts = contractId.split('.');
|
|
139
|
+
const datalexDomain = parts[0] ?? fields.domain;
|
|
140
|
+
const entity = parts[1] ?? 'Unknown';
|
|
141
|
+
const contractName = parts[2] ?? fields.slug;
|
|
142
|
+
const safeDesc = fields.description.replace(/"/g, '\\"').replace(/\n/g, ' ');
|
|
143
|
+
return `Add the following entry under domains[name=${datalexDomain}].entities[name=${entity}].contracts in datalex-manifest.json:
|
|
144
|
+
|
|
145
|
+
{
|
|
146
|
+
"id": "${contractId}",
|
|
147
|
+
"name": "${contractName}",
|
|
148
|
+
"version": ${version},
|
|
149
|
+
"description": "${safeDesc}",
|
|
150
|
+
"signature": {
|
|
151
|
+
"inputs": [],
|
|
152
|
+
"outputs": []
|
|
153
|
+
},
|
|
154
|
+
"owner": "<owner>",
|
|
155
|
+
"tags": []
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
Then re-run \`dql compile\` to refresh dql-manifest.json. The DataLex compiler
|
|
159
|
+
will emit this entry automatically once the v1 manifest emitter ships;
|
|
160
|
+
until then, hand-edit \`datalex-manifest.json\` (or its source YAML) so the
|
|
161
|
+
DQL block's datalex_contract reference resolves.
|
|
162
|
+
`;
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=promote-from-draft.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promote-from-draft.js","sourceRoot":"","sources":["../src/promote-from-draft.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promote-from-draft.test.d.ts","sourceRoot":"","sources":["../src/promote-from-draft.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { promoteFromDraft } from './promote-from-draft.js';
|
|
6
|
+
function baseFlags(overrides = {}) {
|
|
7
|
+
return {
|
|
8
|
+
format: 'text',
|
|
9
|
+
verbose: false,
|
|
10
|
+
help: false,
|
|
11
|
+
version: false,
|
|
12
|
+
check: false,
|
|
13
|
+
open: null,
|
|
14
|
+
input: '',
|
|
15
|
+
outDir: '',
|
|
16
|
+
port: null,
|
|
17
|
+
host: null,
|
|
18
|
+
chart: '',
|
|
19
|
+
domain: '',
|
|
20
|
+
owner: '',
|
|
21
|
+
queryOnly: false,
|
|
22
|
+
template: '',
|
|
23
|
+
connection: '',
|
|
24
|
+
skipTests: false,
|
|
25
|
+
force: false,
|
|
26
|
+
http: false,
|
|
27
|
+
...overrides,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function writeDraft(root, slug, body) {
|
|
31
|
+
const draftDir = join(root, 'blocks', '_drafts');
|
|
32
|
+
mkdirSync(draftDir, { recursive: true });
|
|
33
|
+
const domain = body?.domain ?? 'customer';
|
|
34
|
+
const id = body?.proposedContractId ?? 'commerce.Customer.monthly_active_customers';
|
|
35
|
+
const status = body?.status ?? 'draft';
|
|
36
|
+
writeFileSync(join(draftDir, `${slug}.dql`), `block "${slug}" {
|
|
37
|
+
domain = "${domain}"
|
|
38
|
+
type = "custom"
|
|
39
|
+
status = "${status}"
|
|
40
|
+
description = """How many active customers each month?"""
|
|
41
|
+
datalex_contract = ""
|
|
42
|
+
|
|
43
|
+
_proposed {
|
|
44
|
+
asked_times = 3
|
|
45
|
+
first_asked = "2026-04-01T00:00:00Z"
|
|
46
|
+
last_asked = "2026-05-01T12:00:00Z"
|
|
47
|
+
proposed_contract_id = "${id}"
|
|
48
|
+
proposed_domain = "${domain}"
|
|
49
|
+
proposed_entity = "Customer"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
query = """SELECT 1"""
|
|
53
|
+
}
|
|
54
|
+
`);
|
|
55
|
+
}
|
|
56
|
+
describe('promoteFromDraft (dql certify --from-draft)', () => {
|
|
57
|
+
let tmp;
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
tmp = mkdtempSync(join(tmpdir(), 'promote-'));
|
|
60
|
+
});
|
|
61
|
+
afterEach(() => {
|
|
62
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
63
|
+
});
|
|
64
|
+
it('returns ok=false when the draft path does not exist', () => {
|
|
65
|
+
const out = promoteFromDraft(tmp, baseFlags({ fromDraft: 'blocks/_drafts/nope.dql' }));
|
|
66
|
+
expect(out.ok).toBe(false);
|
|
67
|
+
expect(out.message).toMatch(/not found/i);
|
|
68
|
+
});
|
|
69
|
+
it('refuses to promote a file whose status is not draft', () => {
|
|
70
|
+
writeDraft(tmp, 'mau', { status: 'certified' });
|
|
71
|
+
const out = promoteFromDraft(tmp, baseFlags({ fromDraft: 'blocks/_drafts/mau.dql' }));
|
|
72
|
+
expect(out.ok).toBe(false);
|
|
73
|
+
expect(out.message).toMatch(/status="draft"/);
|
|
74
|
+
});
|
|
75
|
+
it('promotes a draft to blocks/<domain>/<slug>.dql, flips status, sets contract, drops _proposed', () => {
|
|
76
|
+
writeDraft(tmp, 'mau');
|
|
77
|
+
const out = promoteFromDraft(tmp, baseFlags({
|
|
78
|
+
fromDraft: 'blocks/_drafts/mau.dql',
|
|
79
|
+
domain: 'customer',
|
|
80
|
+
contract: 'commerce.Customer.monthly_active_customers@1',
|
|
81
|
+
owner: 'growth@example.com',
|
|
82
|
+
}));
|
|
83
|
+
expect(out.ok).toBe(true);
|
|
84
|
+
expect(out.certifiedPath).toBe('blocks/customer/mau.dql');
|
|
85
|
+
const certified = readFileSync(join(tmp, 'blocks/customer/mau.dql'), 'utf-8');
|
|
86
|
+
expect(certified).toContain('status = "certified"');
|
|
87
|
+
expect(certified).toContain('datalex_contract = "commerce.Customer.monthly_active_customers@1"');
|
|
88
|
+
expect(certified).toContain('owner = "growth@example.com"');
|
|
89
|
+
expect(certified).not.toContain('_proposed');
|
|
90
|
+
expect(certified).not.toContain('asked_times');
|
|
91
|
+
expect(existsSync(join(tmp, 'blocks/_drafts/mau.dql'))).toBe(false);
|
|
92
|
+
});
|
|
93
|
+
it('falls back to the proposed contract id with @1 when --contract is omitted', () => {
|
|
94
|
+
writeDraft(tmp, 'mau', {
|
|
95
|
+
proposedContractId: 'commerce.Customer.monthly_active_customers',
|
|
96
|
+
});
|
|
97
|
+
const out = promoteFromDraft(tmp, baseFlags({ fromDraft: 'blocks/_drafts/mau.dql', domain: 'customer' }));
|
|
98
|
+
expect(out.ok).toBe(true);
|
|
99
|
+
const certified = readFileSync(join(tmp, 'blocks/customer/mau.dql'), 'utf-8');
|
|
100
|
+
expect(certified).toContain('datalex_contract = "commerce.Customer.monthly_active_customers@1"');
|
|
101
|
+
});
|
|
102
|
+
it('errors when no --contract and no proposed_contract_id available', () => {
|
|
103
|
+
writeDraft(tmp, 'mau', { proposedContractId: '' });
|
|
104
|
+
const out = promoteFromDraft(tmp, baseFlags({ fromDraft: 'blocks/_drafts/mau.dql', domain: 'customer' }));
|
|
105
|
+
expect(out.ok).toBe(false);
|
|
106
|
+
expect(out.message).toMatch(/contract/i);
|
|
107
|
+
});
|
|
108
|
+
it('refuses to overwrite an existing certified file unless --force', () => {
|
|
109
|
+
writeDraft(tmp, 'mau');
|
|
110
|
+
mkdirSync(join(tmp, 'blocks', 'customer'), { recursive: true });
|
|
111
|
+
writeFileSync(join(tmp, 'blocks', 'customer', 'mau.dql'), 'already here');
|
|
112
|
+
const out = promoteFromDraft(tmp, baseFlags({
|
|
113
|
+
fromDraft: 'blocks/_drafts/mau.dql',
|
|
114
|
+
domain: 'customer',
|
|
115
|
+
contract: 'commerce.Customer.monthly_active_customers@1',
|
|
116
|
+
}));
|
|
117
|
+
expect(out.ok).toBe(false);
|
|
118
|
+
expect(out.message).toMatch(/already exists/);
|
|
119
|
+
});
|
|
120
|
+
it('overwrites with --force', () => {
|
|
121
|
+
writeDraft(tmp, 'mau');
|
|
122
|
+
mkdirSync(join(tmp, 'blocks', 'customer'), { recursive: true });
|
|
123
|
+
writeFileSync(join(tmp, 'blocks', 'customer', 'mau.dql'), 'old content');
|
|
124
|
+
const out = promoteFromDraft(tmp, baseFlags({
|
|
125
|
+
fromDraft: 'blocks/_drafts/mau.dql',
|
|
126
|
+
domain: 'customer',
|
|
127
|
+
contract: 'commerce.Customer.monthly_active_customers@1',
|
|
128
|
+
force: true,
|
|
129
|
+
}));
|
|
130
|
+
expect(out.ok).toBe(true);
|
|
131
|
+
const content = readFileSync(join(tmp, 'blocks/customer/mau.dql'), 'utf-8');
|
|
132
|
+
expect(content).not.toBe('old content');
|
|
133
|
+
expect(content).toContain('status = "certified"');
|
|
134
|
+
});
|
|
135
|
+
it('surfaces a datalex-manifest.json patch with the contract entry to add', () => {
|
|
136
|
+
writeDraft(tmp, 'mau');
|
|
137
|
+
const out = promoteFromDraft(tmp, baseFlags({
|
|
138
|
+
fromDraft: 'blocks/_drafts/mau.dql',
|
|
139
|
+
domain: 'customer',
|
|
140
|
+
contract: 'commerce.Customer.monthly_active_customers@1',
|
|
141
|
+
}));
|
|
142
|
+
expect(out.datalexManifestDiff).toBeDefined();
|
|
143
|
+
expect(out.datalexManifestDiff).toContain('commerce.Customer.monthly_active_customers');
|
|
144
|
+
expect(out.datalexManifestDiff).toContain('"version": 1');
|
|
145
|
+
expect(out.datalexManifestDiff).toContain('domains[name=commerce]');
|
|
146
|
+
expect(out.datalexManifestDiff).toContain('entities[name=Customer]');
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
//# sourceMappingURL=promote-from-draft.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promote-from-draft.test.js","sourceRoot":"","sources":["../src/promote-from-draft.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-adoption.test.d.ts","sourceRoot":"","sources":["../src/template-adoption.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { cpSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join, resolve } from 'node:path';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import { analyze, buildManifest, parse } from '@duckcodeailabs/dql-core';
|
|
6
|
+
import { Certifier } from '@duckcodeailabs/dql-governance';
|
|
7
|
+
const repoRoot = resolve(process.cwd(), '../..');
|
|
8
|
+
const templatesRoot = join(repoRoot, 'packages/create-dql-app/templates');
|
|
9
|
+
const fixturesRoot = resolve(process.cwd(), 'test/fixtures');
|
|
10
|
+
const lineageFixture = join(fixturesRoot, 'lineage-app');
|
|
11
|
+
function collectFiles(dir, predicate, out = []) {
|
|
12
|
+
for (const entry of readdirSync(dir)) {
|
|
13
|
+
const abs = join(dir, entry);
|
|
14
|
+
const stat = statSync(abs);
|
|
15
|
+
if (stat.isDirectory())
|
|
16
|
+
collectFiles(abs, predicate, out);
|
|
17
|
+
else if (predicate(abs))
|
|
18
|
+
out.push(abs);
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
function copyProject(src, name) {
|
|
23
|
+
const base = mkdtempSync(join(tmpdir(), `dql-${name}-`));
|
|
24
|
+
const root = join(base, name);
|
|
25
|
+
cpSync(src, root, { recursive: true });
|
|
26
|
+
return { root, cleanup: () => rmSync(base, { recursive: true, force: true }) };
|
|
27
|
+
}
|
|
28
|
+
describe('OSS adoption templates and fixtures', () => {
|
|
29
|
+
it('all template and fixture .dql files parse and analyze with canonical block syntax', () => {
|
|
30
|
+
const dqlFiles = [
|
|
31
|
+
...collectFiles(templatesRoot, (path) => path.endsWith('.dql')),
|
|
32
|
+
...collectFiles(fixturesRoot, (path) => path.endsWith('.dql')),
|
|
33
|
+
];
|
|
34
|
+
expect(dqlFiles.length).toBeGreaterThan(0);
|
|
35
|
+
for (const filePath of dqlFiles) {
|
|
36
|
+
const source = readFileSync(filePath, 'utf-8');
|
|
37
|
+
expect(source, `${filePath} should not use block-level lifecycle`).not.toMatch(/\blifecycle\s*=/);
|
|
38
|
+
const ast = parse(source, filePath);
|
|
39
|
+
const diagnostics = analyze(ast);
|
|
40
|
+
const errors = diagnostics.filter((diagnostic) => diagnostic.severity === 'error');
|
|
41
|
+
expect(errors, `${filePath} should parse/analyze cleanly`).toEqual([]);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
it('fixture project compiles source-to-block-to-dashboard-to-App lineage', () => {
|
|
45
|
+
const { root, cleanup } = copyProject(lineageFixture, 'lineage-app');
|
|
46
|
+
try {
|
|
47
|
+
const manifest = buildManifest({ projectRoot: root, dqlVersion: '1.6.1' });
|
|
48
|
+
const nodeTypes = new Set(manifest.lineage.nodes.map((node) => node.type));
|
|
49
|
+
expect(Object.keys(manifest.blocks).length).toBeGreaterThan(0);
|
|
50
|
+
expect(Object.keys(manifest.apps ?? {}).length).toBeGreaterThan(0);
|
|
51
|
+
expect(Object.keys(manifest.dashboards ?? {}).length).toBeGreaterThan(0);
|
|
52
|
+
expect(nodeTypes.has('source_table')).toBe(true);
|
|
53
|
+
expect(nodeTypes.has('block')).toBe(true);
|
|
54
|
+
expect(nodeTypes.has('dashboard')).toBe(true);
|
|
55
|
+
expect(nodeTypes.has('app')).toBe(true);
|
|
56
|
+
expect(manifest.lineage.edges.some((edge) => edge.type === 'reads_from' && edge.target.startsWith('block:'))).toBe(true);
|
|
57
|
+
expect(manifest.lineage.edges.some((edge) => edge.type === 'contains' && edge.source.startsWith('block:') && edge.target.startsWith('dashboard:'))).toBe(true);
|
|
58
|
+
expect(manifest.lineage.edges.some((edge) => edge.type === 'contains' && edge.source.startsWith('dashboard:') && edge.target.startsWith('app:'))).toBe(true);
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
cleanup();
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
it('fixture card approval block is certifiable with passing local test results', () => {
|
|
65
|
+
const filePath = join(lineageFixture, 'blocks/card_approval_rate.dql');
|
|
66
|
+
const source = readFileSync(filePath, 'utf-8');
|
|
67
|
+
const ast = parse(source, filePath);
|
|
68
|
+
const block = ast.statements.find((statement) => statement.kind === 'BlockDecl');
|
|
69
|
+
expect(block).toBeTruthy();
|
|
70
|
+
const record = {
|
|
71
|
+
id: 'block:card_approval_rate',
|
|
72
|
+
name: block.name,
|
|
73
|
+
domain: block.domain,
|
|
74
|
+
type: block.blockType,
|
|
75
|
+
version: '1.0.0',
|
|
76
|
+
status: block.status,
|
|
77
|
+
gitRepo: '',
|
|
78
|
+
gitPath: 'blocks/card_approval_rate.dql',
|
|
79
|
+
gitCommitSha: '',
|
|
80
|
+
description: block.description,
|
|
81
|
+
owner: block.owner,
|
|
82
|
+
tags: block.tags ?? [],
|
|
83
|
+
dependencies: [],
|
|
84
|
+
usedInCount: 1,
|
|
85
|
+
llmContext: block.llmContext,
|
|
86
|
+
createdAt: new Date(),
|
|
87
|
+
updatedAt: new Date(),
|
|
88
|
+
};
|
|
89
|
+
const testResults = {
|
|
90
|
+
passed: 1,
|
|
91
|
+
failed: 0,
|
|
92
|
+
skipped: 0,
|
|
93
|
+
duration: 1,
|
|
94
|
+
assertions: [{ name: 'assert row_count == 1', passed: true, actual: 1 }],
|
|
95
|
+
runAt: new Date(),
|
|
96
|
+
};
|
|
97
|
+
const result = new Certifier().evaluate(record, testResults);
|
|
98
|
+
expect(result.certified).toBe(true);
|
|
99
|
+
expect(result.errors).toEqual([]);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
//# sourceMappingURL=template-adoption.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-adoption.test.js","sourceRoot":"","sources":["../src/template-adoption.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC3F,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAG3D,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;AACjD,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,EAAE,mCAAmC,CAAC,CAAC;AAC1E,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,eAAe,CAAC,CAAC;AAC7D,MAAM,cAAc,GAAG,IAAI,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;AAEzD,SAAS,YAAY,CAAC,GAAW,EAAE,SAAoC,EAAE,MAAgB,EAAE;IACzF,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7B,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC3B,IAAI,IAAI,CAAC,WAAW,EAAE;YAAE,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;aACrD,IAAI,SAAS,CAAC,GAAG,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,WAAW,CAAC,GAAW,EAAE,IAAY;IAC5C,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC;IACzD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9B,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;AACjF,CAAC;AAED,QAAQ,CAAC,qCAAqC,EAAE,GAAG,EAAE;IACnD,EAAE,CAAC,mFAAmF,EAAE,GAAG,EAAE;QAC3F,MAAM,QAAQ,GAAG;YACf,GAAG,YAAY,CAAC,aAAa,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC/D,GAAG,YAAY,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;SAC/D,CAAC;QACF,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAE3C,KAAK,MAAM,QAAQ,IAAI,QAAQ,EAAE,CAAC;YAChC,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC/C,MAAM,CAAC,MAAM,EAAE,GAAG,QAAQ,uCAAuC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;YAClG,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YACpC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;YACjC,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;YACnF,MAAM,CAAC,MAAM,EAAE,GAAG,QAAQ,+BAA+B,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACzE,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,WAAW,CAAC,cAAc,EAAE,aAAa,CAAC,CAAC;QACrE,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,aAAa,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;YAC3E,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAE3E,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YAC/D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YACnE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YACzE,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjD,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1C,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9C,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAExC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACzH,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/J,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/J,CAAC;gBAAS,CAAC;YACT,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,EAAE,+BAA+B,CAAC,CAAC;QACvE,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC/C,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACpC,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,SAAc,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,WAAW,CAAQ,CAAC;QAC7F,MAAM,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC;QAE3B,MAAM,MAAM,GAAgB;YAC1B,EAAE,EAAE,0BAA0B;YAC9B,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,IAAI,EAAE,KAAK,CAAC,SAAS;YACrB,OAAO,EAAE,OAAO;YAChB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,OAAO,EAAE,EAAE;YACX,OAAO,EAAE,+BAA+B;YACxC,YAAY,EAAE,EAAE;YAChB,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;YACtB,YAAY,EAAE,EAAE;YAChB,WAAW,EAAE,CAAC;YACd,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,SAAS,EAAE,IAAI,IAAI,EAAE;YACrB,SAAS,EAAE,IAAI,IAAI,EAAE;SACtB,CAAC;QACF,MAAM,WAAW,GAAsB;YACrC,MAAM,EAAE,CAAC;YACT,MAAM,EAAE,CAAC;YACT,OAAO,EAAE,CAAC;YACV,QAAQ,EAAE,CAAC;YACX,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,uBAAuB,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;YACxE,KAAK,EAAE,IAAI,IAAI,EAAE;SAClB,CAAC;QAEF,MAAM,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QAC7D,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@duckcodeailabs/dql-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.1",
|
|
4
4
|
"description": "Public CLI for parsing, formatting, testing, and certifying DQL blocks",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -19,15 +19,15 @@
|
|
|
19
19
|
"directory": "apps/cli"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@duckcodeailabs/dql-agent": "^1.
|
|
23
|
-
"@duckcodeailabs/dql-slack": "^1.
|
|
24
|
-
"@duckcodeailabs/dql-compiler": "^1.
|
|
25
|
-
"@duckcodeailabs/dql-connectors": "^1.
|
|
26
|
-
"@duckcodeailabs/dql-core": "^1.
|
|
27
|
-
"@duckcodeailabs/dql-governance": "^1.
|
|
28
|
-
"@duckcodeailabs/dql-mcp": "^1.
|
|
29
|
-
"@duckcodeailabs/dql-notebook": "^1.
|
|
30
|
-
"@duckcodeailabs/dql-project": "^1.
|
|
22
|
+
"@duckcodeailabs/dql-agent": "^1.6.1",
|
|
23
|
+
"@duckcodeailabs/dql-slack": "^1.6.1",
|
|
24
|
+
"@duckcodeailabs/dql-compiler": "^1.6.1",
|
|
25
|
+
"@duckcodeailabs/dql-connectors": "^1.6.1",
|
|
26
|
+
"@duckcodeailabs/dql-core": "^1.6.1",
|
|
27
|
+
"@duckcodeailabs/dql-governance": "^1.6.1",
|
|
28
|
+
"@duckcodeailabs/dql-mcp": "^1.6.1",
|
|
29
|
+
"@duckcodeailabs/dql-notebook": "^1.6.1",
|
|
30
|
+
"@duckcodeailabs/dql-project": "^1.6.1",
|
|
31
31
|
"isomorphic-git": "^1.27.0",
|
|
32
32
|
"js-yaml": "^4.1.0",
|
|
33
33
|
"node-cron": "^3.0.3",
|
|
@@ -40,10 +40,10 @@
|
|
|
40
40
|
"tsx": "^4.19.0",
|
|
41
41
|
"typescript": "^5.7.0",
|
|
42
42
|
"vitest": "^3.0.0",
|
|
43
|
-
"@duckcodeailabs/dql-notebook-app": "1.
|
|
43
|
+
"@duckcodeailabs/dql-notebook-app": "1.6.1"
|
|
44
44
|
},
|
|
45
45
|
"engines": {
|
|
46
|
-
"node": ">=
|
|
46
|
+
"node": ">=20 <23"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"build": "rm -rf dist tsconfig.tsbuildinfo && tsc -b && node ./scripts/copy-runtime-assets.mjs",
|