@duckcodeailabs/dql-cli 1.0.4 → 1.2.2

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 (99) hide show
  1. package/dist/args.d.ts +1 -0
  2. package/dist/args.d.ts.map +1 -1
  3. package/dist/args.js +4 -0
  4. package/dist/args.js.map +1 -1
  5. package/dist/assets/dql-notebook/assets/index-DWPIGGBJ.js +628 -0
  6. package/dist/assets/dql-notebook/index.html +1 -1
  7. package/dist/commands/app.d.ts +3 -0
  8. package/dist/commands/app.d.ts.map +1 -0
  9. package/dist/commands/app.js +191 -0
  10. package/dist/commands/app.js.map +1 -0
  11. package/dist/commands/build.d.ts.map +1 -1
  12. package/dist/commands/build.js +30 -2
  13. package/dist/commands/build.js.map +1 -1
  14. package/dist/commands/fmt.d.ts.map +1 -1
  15. package/dist/commands/fmt.js +26 -9
  16. package/dist/commands/fmt.js.map +1 -1
  17. package/dist/commands/init.d.ts.map +1 -1
  18. package/dist/commands/init.js +1 -1
  19. package/dist/commands/init.js.map +1 -1
  20. package/dist/commands/mcp.d.ts +7 -0
  21. package/dist/commands/mcp.d.ts.map +1 -0
  22. package/dist/commands/mcp.js +16 -0
  23. package/dist/commands/mcp.js.map +1 -0
  24. package/dist/commands/schedule.d.ts +3 -0
  25. package/dist/commands/schedule.d.ts.map +1 -0
  26. package/dist/commands/schedule.js +215 -0
  27. package/dist/commands/schedule.js.map +1 -0
  28. package/dist/digest.d.ts +10 -0
  29. package/dist/digest.d.ts.map +1 -0
  30. package/dist/digest.js +83 -0
  31. package/dist/digest.js.map +1 -0
  32. package/dist/index.js +16 -1
  33. package/dist/index.js.map +1 -1
  34. package/dist/llm/index.d.ts +4 -0
  35. package/dist/llm/index.d.ts.map +1 -0
  36. package/dist/llm/index.js +16 -0
  37. package/dist/llm/index.js.map +1 -0
  38. package/dist/llm/providers/claude-agent-sdk.d.ts +3 -0
  39. package/dist/llm/providers/claude-agent-sdk.d.ts.map +1 -0
  40. package/dist/llm/providers/claude-agent-sdk.js +174 -0
  41. package/dist/llm/providers/claude-agent-sdk.js.map +1 -0
  42. package/dist/llm/providers/claude-code.d.ts +8 -0
  43. package/dist/llm/providers/claude-code.d.ts.map +1 -0
  44. package/dist/llm/providers/claude-code.js +171 -0
  45. package/dist/llm/providers/claude-code.js.map +1 -0
  46. package/dist/llm/tools.d.ts +9 -0
  47. package/dist/llm/tools.d.ts.map +1 -0
  48. package/dist/llm/tools.js +112 -0
  49. package/dist/llm/tools.js.map +1 -0
  50. package/dist/llm/types.d.ts +70 -0
  51. package/dist/llm/types.d.ts.map +1 -0
  52. package/dist/llm/types.js +2 -0
  53. package/dist/llm/types.js.map +1 -0
  54. package/dist/local-runtime.d.ts +6 -0
  55. package/dist/local-runtime.d.ts.map +1 -1
  56. package/dist/local-runtime.js +174 -3
  57. package/dist/local-runtime.js.map +1 -1
  58. package/dist/schedule/alerts.d.ts +5 -0
  59. package/dist/schedule/alerts.d.ts.map +1 -0
  60. package/dist/schedule/alerts.js +54 -0
  61. package/dist/schedule/alerts.js.map +1 -0
  62. package/dist/schedule/discovery.d.ts +4 -0
  63. package/dist/schedule/discovery.d.ts.map +1 -0
  64. package/dist/schedule/discovery.js +36 -0
  65. package/dist/schedule/discovery.js.map +1 -0
  66. package/dist/schedule/notifiers/email.d.ts +3 -0
  67. package/dist/schedule/notifiers/email.d.ts.map +1 -0
  68. package/dist/schedule/notifiers/email.js +76 -0
  69. package/dist/schedule/notifiers/email.js.map +1 -0
  70. package/dist/schedule/notifiers/file.d.ts +3 -0
  71. package/dist/schedule/notifiers/file.d.ts.map +1 -0
  72. package/dist/schedule/notifiers/file.js +50 -0
  73. package/dist/schedule/notifiers/file.js.map +1 -0
  74. package/dist/schedule/notifiers/index.d.ts +10 -0
  75. package/dist/schedule/notifiers/index.d.ts.map +1 -0
  76. package/dist/schedule/notifiers/index.js +33 -0
  77. package/dist/schedule/notifiers/index.js.map +1 -0
  78. package/dist/schedule/notifiers/slack.d.ts +3 -0
  79. package/dist/schedule/notifiers/slack.d.ts.map +1 -0
  80. package/dist/schedule/notifiers/slack.js +58 -0
  81. package/dist/schedule/notifiers/slack.js.map +1 -0
  82. package/dist/schedule/runner.d.ts +11 -0
  83. package/dist/schedule/runner.d.ts.map +1 -0
  84. package/dist/schedule/runner.js +109 -0
  85. package/dist/schedule/runner.js.map +1 -0
  86. package/dist/schedule/runs.d.ts +5 -0
  87. package/dist/schedule/runs.d.ts.map +1 -0
  88. package/dist/schedule/runs.js +41 -0
  89. package/dist/schedule/runs.js.map +1 -0
  90. package/dist/schedule/service.d.ts +12 -0
  91. package/dist/schedule/service.d.ts.map +1 -0
  92. package/dist/schedule/service.js +49 -0
  93. package/dist/schedule/service.js.map +1 -0
  94. package/dist/schedule/types.d.ts +64 -0
  95. package/dist/schedule/types.d.ts.map +1 -0
  96. package/dist/schedule/types.js +2 -0
  97. package/dist/schedule/types.js.map +1 -0
  98. package/package.json +16 -10
  99. package/dist/assets/dql-notebook/assets/index-dZVjj9xj.js +0 -623
@@ -4,7 +4,9 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, wat
4
4
  import { dirname, extname, join, normalize, relative, resolve } from 'node:path';
5
5
  import { buildExecutionPlan, createWelcomeNotebook, deserializeNotebook, getConnectorFormSchemas, hasSemanticRefs, resolveSemanticRefs, } from '@duckcodeailabs/dql-notebook';
6
6
  import { loadSemanticLayerFromDir, resolveSemanticLayerAsync, Parser, buildLineageGraph, buildManifest, analyzeImpact, buildTrustChain, detectDomainFlows, getDomainTrustOverview, queryLineage, queryCompleteLineagePaths, LineageGraph, canonicalize, canonicalizeNotebook, diffDQL, diffNotebook, } from '@duckcodeailabs/dql-core';
7
+ import { load as loadYaml } from 'js-yaml';
7
8
  import { listBlockTemplates } from './block-templates.js';
9
+ import { getRunner as getLLMRunner } from './llm/index.js';
8
10
  import { buildSemanticObjectDetail, buildSemanticTree, computeSyncDiff, loadSemanticImportManifest, performSemanticImport, previewSemanticImport, syncSemanticImport, } from './semantic-import.js';
9
11
  export async function startLocalServer(opts) {
10
12
  const { rootDir, executor, connection: rawConnection, preferredPort, projectRoot = process.cwd() } = opts;
@@ -304,8 +306,11 @@ export async function startLocalServer(opts) {
304
306
  res.end(serializeJSON(merged));
305
307
  }
306
308
  catch (error) {
307
- res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
308
- res.end(serializeJSON(scanDataFiles(projectRoot)));
309
+ const message = error instanceof Error ? error.message : String(error);
310
+ console.warn(`[dql] /api/schema introspection failed: ${message}`);
311
+ const fallback = scanDataFiles(projectRoot).map((f) => ({ ...f, source: 'file' }));
312
+ res.writeHead(500, { 'Content-Type': 'application/json; charset=utf-8' });
313
+ res.end(serializeJSON({ error: message, fallback }));
309
314
  }
310
315
  return;
311
316
  }
@@ -344,7 +349,7 @@ export async function startLocalServer(opts) {
344
349
  if (req.method === 'POST' && path === '/api/blocks/save-from-cell') {
345
350
  try {
346
351
  const body = await readJSON(req);
347
- const { name, domain, owner, content, description, tags, metricRefs, template, } = body;
352
+ const { name, domain, owner, content, description, tags, metricRefs, template, llmContext, examples, invariants, } = body;
348
353
  if (!name || typeof name !== 'string' || !content || typeof content !== 'string') {
349
354
  res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });
350
355
  res.end(serializeJSON({ error: 'name and content are required' }));
@@ -374,6 +379,9 @@ export async function startLocalServer(opts) {
374
379
  tags,
375
380
  metricRefs,
376
381
  template,
382
+ llmContext,
383
+ examples,
384
+ invariants,
377
385
  gitMetadata: readGitMetadata(projectRoot),
378
386
  });
379
387
  res.writeHead(201, { 'Content-Type': 'application/json; charset=utf-8' });
@@ -422,6 +430,7 @@ export async function startLocalServer(opts) {
422
430
  const parsedTags = tagsMatch
423
431
  ? tagsMatch[1].split(',').map((tag) => tag.trim().replace(/^"|"$/g, '')).filter(Boolean)
424
432
  : [];
433
+ const llmMatch = /llmContext\s*=\s*"((?:[^"\\]|\\.)*)"/.exec(source);
425
434
  blocks.push({
426
435
  name: nameMatch?.[1] ?? entry.name.replace('.dql', ''),
427
436
  domain: domainMatch?.[1] ?? 'uncategorized',
@@ -431,6 +440,7 @@ export async function startLocalServer(opts) {
431
440
  path: relPath,
432
441
  lastModified: stat.mtime.toISOString(),
433
442
  description: descMatch?.[1] ?? '',
443
+ llmContext: llmMatch?.[1] ?? null,
434
444
  });
435
445
  }
436
446
  catch { /* skip unreadable files */ }
@@ -449,6 +459,58 @@ export async function startLocalServer(opts) {
449
459
  }
450
460
  return;
451
461
  }
462
+ // ── Apps (App artifact listing for notebook AppsPanel) ────────────────
463
+ if (req.method === 'GET' && path === '/api/apps') {
464
+ try {
465
+ const appsRoot = join(projectRoot, 'apps');
466
+ const apps = [];
467
+ const listFilesByExt = (dir, ext) => {
468
+ const out = [];
469
+ try {
470
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
471
+ const full = join(dir, entry.name);
472
+ if (entry.isDirectory()) {
473
+ out.push(...listFilesByExt(full, ext).map((n) => `${entry.name}/${n}`));
474
+ }
475
+ else if (entry.isFile() && entry.name.endsWith(ext)) {
476
+ out.push(entry.name);
477
+ }
478
+ }
479
+ }
480
+ catch { /* dir missing; return [] */ }
481
+ return out;
482
+ };
483
+ if (existsSync(appsRoot)) {
484
+ for (const entry of readdirSync(appsRoot, { withFileTypes: true })) {
485
+ if (!entry.isDirectory() || !entry.name.endsWith('.dql-app'))
486
+ continue;
487
+ const appDir = join(appsRoot, entry.name);
488
+ try {
489
+ const raw = readFileSync(join(appDir, 'app.yml'), 'utf-8');
490
+ const manifest = loadYaml(raw);
491
+ if (!manifest || !manifest.name || !manifest.domain)
492
+ continue;
493
+ apps.push({
494
+ path: relative(projectRoot, appDir),
495
+ manifest,
496
+ notebooks: listFilesByExt(join(appDir, 'notebooks'), '.dqlnb'),
497
+ dashboards: listFilesByExt(join(appDir, 'dashboards'), '.dql'),
498
+ hasDigest: existsSync(join(appDir, 'digest.dql')),
499
+ });
500
+ }
501
+ catch { /* skip unreadable apps */ }
502
+ }
503
+ }
504
+ apps.sort((a, b) => a.manifest.name.localeCompare(b.manifest.name));
505
+ res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
506
+ res.end(serializeJSON({ apps }));
507
+ }
508
+ catch (error) {
509
+ res.writeHead(500, { 'Content-Type': 'application/json; charset=utf-8' });
510
+ res.end(serializeJSON({ error: error instanceof Error ? error.message : String(error) }));
511
+ }
512
+ return;
513
+ }
452
514
  // ── Block status update ──────────────────────────────────────────────
453
515
  if (req.method === 'POST' && path === '/api/blocks/status') {
454
516
  try {
@@ -512,6 +574,51 @@ export async function startLocalServer(opts) {
512
574
  }
513
575
  return;
514
576
  }
577
+ // ── Block body (re-read from disk, used by bound-cell refresh) ──────
578
+ if (req.method === 'GET' && path === '/api/blocks/body') {
579
+ try {
580
+ const blockPath = url.searchParams.get('path');
581
+ if (!blockPath) {
582
+ res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });
583
+ res.end(serializeJSON({ error: 'path parameter is required' }));
584
+ return;
585
+ }
586
+ const absolutePath = resolve(projectRoot, blockPath);
587
+ if (!absolutePath.startsWith(projectRoot + '/') && absolutePath !== projectRoot) {
588
+ res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });
589
+ res.end(serializeJSON({ error: 'path escapes project root' }));
590
+ return;
591
+ }
592
+ if (!existsSync(absolutePath)) {
593
+ res.writeHead(404, { 'Content-Type': 'application/json; charset=utf-8' });
594
+ res.end(serializeJSON({ error: 'block not found' }));
595
+ return;
596
+ }
597
+ const body = readFileSync(absolutePath, 'utf-8');
598
+ let commitSha = null;
599
+ try {
600
+ const { execSync } = await import('node:child_process');
601
+ const sha = execSync(`git log -1 --format=%H -- "${blockPath}"`, {
602
+ cwd: projectRoot,
603
+ encoding: 'utf-8',
604
+ stdio: ['ignore', 'pipe', 'ignore'],
605
+ timeout: 5000,
606
+ }).trim();
607
+ commitSha = sha.length > 0 ? sha : null;
608
+ }
609
+ catch {
610
+ commitSha = null;
611
+ }
612
+ res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
613
+ res.end(serializeJSON({ path: blockPath, body, commitSha }));
614
+ }
615
+ catch (error) {
616
+ const message = error instanceof Error ? error.message : String(error);
617
+ res.writeHead(500, { 'Content-Type': 'application/json; charset=utf-8' });
618
+ res.end(serializeJSON({ error: message }));
619
+ }
620
+ return;
621
+ }
515
622
  // ── Run block tests ────────────────────────────────────────────────
516
623
  if (req.method === 'POST' && path === '/api/blocks/run-tests') {
517
624
  try {
@@ -1293,6 +1400,42 @@ export async function startLocalServer(opts) {
1293
1400
  }
1294
1401
  return;
1295
1402
  }
1403
+ if (req.method === 'POST' && path === '/api/llm/run') {
1404
+ const body = await readJSON(req).catch(() => null);
1405
+ if (!body || typeof body !== 'object') {
1406
+ res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });
1407
+ res.end(serializeJSON({ error: 'Invalid JSON body' }));
1408
+ return;
1409
+ }
1410
+ const { provider, messages, upstream } = body;
1411
+ const runner = provider === 'claude-agent-sdk' || provider === 'claude-code' ? getLLMRunner(provider) : null;
1412
+ if (!runner) {
1413
+ res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });
1414
+ res.end(serializeJSON({ error: `Unknown provider: ${provider}` }));
1415
+ return;
1416
+ }
1417
+ if (!Array.isArray(messages) || messages.length === 0) {
1418
+ res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });
1419
+ res.end(serializeJSON({ error: 'messages[] required' }));
1420
+ return;
1421
+ }
1422
+ res.writeHead(200, {
1423
+ 'Content-Type': 'text/event-stream',
1424
+ 'Cache-Control': 'no-cache, no-transform',
1425
+ Connection: 'keep-alive',
1426
+ });
1427
+ const controller = new AbortController();
1428
+ req.on('close', () => controller.abort());
1429
+ const emit = (turn) => { res.write(`data: ${JSON.stringify(turn)}\n\n`); };
1430
+ try {
1431
+ await runner.run({ provider: provider, messages, upstream, projectRoot }, emit, controller.signal);
1432
+ }
1433
+ catch (err) {
1434
+ emit({ kind: 'error', message: err instanceof Error ? err.message : String(err) });
1435
+ }
1436
+ res.end();
1437
+ return;
1438
+ }
1296
1439
  if (req.method === 'POST' && path === '/api/query') {
1297
1440
  try {
1298
1441
  const body = await readJSON(req);
@@ -2826,6 +2969,9 @@ export function createBlockArtifacts(projectRoot, options) {
2826
2969
  owner: options.owner,
2827
2970
  description: options.description,
2828
2971
  tags: options.tags,
2972
+ llmContext: options.llmContext,
2973
+ examples: options.examples,
2974
+ invariants: options.invariants,
2829
2975
  content: options.content?.trim() || templateContent,
2830
2976
  }));
2831
2977
  writeFileSync(blockPath, fileContent, 'utf-8');
@@ -3069,6 +3215,9 @@ function normalizeBlockStudioContent(options) {
3069
3215
  owner: options.owner,
3070
3216
  description: options.description,
3071
3217
  tags: options.tags,
3218
+ llmContext: options.llmContext,
3219
+ examples: options.examples,
3220
+ invariants: options.invariants,
3072
3221
  sql: content || 'SELECT 1 AS value',
3073
3222
  });
3074
3223
  }
@@ -3081,6 +3230,28 @@ function buildBlankBlockContent(options) {
3081
3230
  ` owner = "${escapeDqlString(options.owner?.trim() ?? '')}"`,
3082
3231
  ];
3083
3232
  lines.push(` tags = [${(options.tags ?? []).map((tag) => `"${escapeDqlString(tag)}"`).join(', ')}]`);
3233
+ if (options.llmContext && options.llmContext.trim()) {
3234
+ lines.push(` llmContext = "${escapeDqlString(options.llmContext.trim())}"`);
3235
+ }
3236
+ if (options.invariants && options.invariants.length > 0) {
3237
+ lines.push(` invariants = [${options.invariants
3238
+ .filter((inv) => inv && inv.trim())
3239
+ .map((inv) => `"${escapeDqlString(inv.trim())}"`)
3240
+ .join(', ')}]`);
3241
+ }
3242
+ if (options.examples && options.examples.length > 0) {
3243
+ const items = options.examples.filter((ex) => ex.question && ex.question.trim());
3244
+ if (items.length > 0) {
3245
+ lines.push(' examples = [');
3246
+ for (const ex of items) {
3247
+ const parts = [`question = "${escapeDqlString(ex.question.trim())}"`];
3248
+ if (ex.sql && ex.sql.trim())
3249
+ parts.push(`sql = "${escapeDqlString(ex.sql.trim())}"`);
3250
+ lines.push(` { ${parts.join(', ')} },`);
3251
+ }
3252
+ lines.push(' ]');
3253
+ }
3254
+ }
3084
3255
  lines.push('');
3085
3256
  lines.push(' query = """');
3086
3257
  lines.push(...indentBlock(options.sql.trim(), 8).split('\n'));