@duckcodeailabs/dql-agent 1.13.2 → 1.13.3

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.
@@ -1026,6 +1026,7 @@ export function buildMetadataSnapshot(projectRoot, manifest, semanticLayer, skil
1026
1026
  }
1027
1027
  }
1028
1028
  addManifestBlockDetails(manifest, objects);
1029
+ addManifestBlockSourceObjects(projectRoot, manifest, objects);
1029
1030
  addManifestKnowledgeGraph(materializeIndexedKnowledgeGraph(projectRoot, manifest), objects, edges);
1030
1031
  addSkillObjects(skills, objects, edges);
1031
1032
  addDbtDagObjects(manifest, objects, edges, diagnostics);
@@ -2018,6 +2019,58 @@ export class MetadataCatalog {
2018
2019
  snippet: row.snip ?? undefined,
2019
2020
  }));
2020
2021
  }
2022
+ /**
2023
+ * Bounded, index-only catalog query for inventory surfaces such as App
2024
+ * Studio. Unlike `searchObjects`, this contract owns pagination and a total
2025
+ * count so browsers never have to download an arbitrary top-N subset and
2026
+ * pretend it is the complete catalog.
2027
+ */
2028
+ queryObjectsPage(options) {
2029
+ const offset = Math.max(0, Math.floor(options.offset ?? 0));
2030
+ const limit = Math.min(100, Math.max(1, Math.floor(options.limit ?? 50)));
2031
+ const filters = [];
2032
+ const params = [];
2033
+ if (options.objectTypes?.length) {
2034
+ filters.push(`o.object_type IN (${options.objectTypes.map(() => '?').join(', ')})`);
2035
+ params.push(...options.objectTypes);
2036
+ }
2037
+ if (options.domains?.length) {
2038
+ filters.push(`COALESCE(o.domain, '') IN (${options.domains.map(() => '?').join(', ')})`);
2039
+ params.push(...options.domains);
2040
+ }
2041
+ if (options.statuses?.length) {
2042
+ filters.push(`COALESCE(o.status, 'unknown') IN (${options.statuses.map(() => '?').join(', ')})`);
2043
+ params.push(...options.statuses);
2044
+ }
2045
+ const match = buildFtsMatch(options.query ?? '', { prefix: true });
2046
+ const useFts = Boolean(match.or);
2047
+ const from = useFts
2048
+ ? 'FROM metadata_fts JOIN metadata_objects AS o ON o.object_key = metadata_fts.object_key'
2049
+ : 'FROM metadata_objects AS o';
2050
+ const where = [
2051
+ ...(useFts ? ['metadata_fts MATCH ?'] : []),
2052
+ ...filters,
2053
+ ];
2054
+ const queryParams = [...(useFts ? [match.or] : []), ...params];
2055
+ const whereSql = where.length ? `WHERE ${where.join(' AND ')}` : '';
2056
+ const total = Number(this.db.prepare(`SELECT COUNT(*) AS count ${from} ${whereSql}`).get(...queryParams).count);
2057
+ const rankSql = useFts ? ', bm25(metadata_fts) AS rank' : '';
2058
+ const orderSql = useFts ? 'ORDER BY rank, o.object_key' : 'ORDER BY o.object_key';
2059
+ const rows = this.db.prepare(`
2060
+ SELECT o.*${rankSql}
2061
+ ${from}
2062
+ ${whereSql}
2063
+ ${orderSql}
2064
+ LIMIT ? OFFSET ?
2065
+ `).all(...queryParams, limit, offset);
2066
+ const items = rows.map((row) => {
2067
+ const item = rowToObject(row);
2068
+ if (!useFts || row.rank === undefined || row.rank === null)
2069
+ return item;
2070
+ return { ...item, score: Number((1 / (1 + Math.abs(row.rank))).toFixed(6)) };
2071
+ });
2072
+ return { items, total };
2073
+ }
2021
2074
  /** Replace the snapshot vector lane with an explicitly configured provider. */
2022
2075
  async rebuildVectorIndex(provider, batchSize = 96) {
2023
2076
  const objects = [];
@@ -3395,6 +3448,108 @@ function addManifestBlockDetails(manifest, objects) {
3395
3448
  }));
3396
3449
  }
3397
3450
  }
3451
+ /**
3452
+ * App Studio needs an inventory, not the legacy name-keyed execution
3453
+ * projection in `manifest.blocks`. Keep every executable declaration and give
3454
+ * it a path-qualified immutable identity. This object class is additive so Ask
3455
+ * AI's certified block routing continues to use `dql_block` unchanged.
3456
+ */
3457
+ function addManifestBlockSourceObjects(projectRoot, manifest, objects) {
3458
+ const declarations = manifest.blockDeclarations ?? Object.values(manifest.blocks ?? {});
3459
+ for (const block of declarations) {
3460
+ if (!block.sql?.trim() || !block.filePath)
3461
+ continue;
3462
+ const sourceRevision = manifestBlockSourceRevision(projectRoot, block);
3463
+ const domain = block.domain?.trim() || undefined;
3464
+ const pathIdentity = sha256(`${block.filePath}\u0000${block.name}`).slice(0, 20);
3465
+ const sourceId = `app:block:${domain ?? 'global'}:${pathIdentity}`;
3466
+ const lifecycle = normalizeBlockSourceLifecycle(block.status);
3467
+ const outputs = block.declaredOutputs
3468
+ ?? block.outputContract?.map((output) => output.name).filter(Boolean)
3469
+ ?? block.outputs?.map((output) => output.name).filter(Boolean)
3470
+ ?? [];
3471
+ const measures = Array.from(new Set([
3472
+ ...(block.metricRefs ?? []),
3473
+ ...(block.metricsRef ?? []),
3474
+ ...(block.metricRef ? [block.metricRef] : []),
3475
+ ...((block.outputContract ?? []).filter((output) => output.role === 'metric').map((output) => output.name)),
3476
+ ])).sort();
3477
+ const dimensions = Array.from(new Set([
3478
+ ...(block.dimensions ?? []),
3479
+ ...(block.dimensionRefs ?? []),
3480
+ ...(block.dimensionsRef ?? []),
3481
+ ...((block.outputContract ?? []).filter((output) => output.role === 'dimension').map((output) => output.name)),
3482
+ ])).sort();
3483
+ const allowedVisualizations = Array.from(new Set([
3484
+ ...(block.displayHints?.allowedVisualizations ?? []),
3485
+ ...(block.displayHints?.defaultVisualization ? [block.displayHints.defaultVisualization] : []),
3486
+ ...(block.chartType ? [block.chartType] : []),
3487
+ ])).sort();
3488
+ objects.set(sourceId, {
3489
+ objectKey: sourceId,
3490
+ objectType: 'dql_block_source',
3491
+ name: block.name,
3492
+ fullName: `${domain ?? 'global'}::block::${block.name}`,
3493
+ domain,
3494
+ owner: block.owner,
3495
+ status: lifecycle,
3496
+ description: block.description,
3497
+ sourcePath: block.filePath,
3498
+ sourceSystem: 'dql',
3499
+ payload: compactObject({
3500
+ sourceId,
3501
+ qualifiedId: `${domain ?? 'global'}::block::${block.name}::${pathIdentity}`,
3502
+ kind: 'block',
3503
+ lifecycle,
3504
+ trust: lifecycle === 'certified' ? 'certified' : 'review_required',
3505
+ executionRef: block.filePath,
3506
+ sourceRevision,
3507
+ fingerprint: sourceRevision,
3508
+ tags: block.tags,
3509
+ blockType: block.blockType,
3510
+ chartType: block.chartType,
3511
+ allowedVisualizations,
3512
+ measures,
3513
+ dimensions,
3514
+ declaredOutputs: outputs,
3515
+ allowedFilters: block.allowedFilters,
3516
+ filterBindings: block.filterBindings,
3517
+ grain: block.grain,
3518
+ parameters: (block.parameters ?? []).map((parameter) => ({
3519
+ name: parameter.name,
3520
+ type: parameter.type,
3521
+ required: parameter.required,
3522
+ hasDefault: parameter.default !== undefined,
3523
+ })),
3524
+ dataState: block.dataState,
3525
+ dataStateDetail: block.dataStateDetail,
3526
+ }),
3527
+ });
3528
+ }
3529
+ }
3530
+ function normalizeBlockSourceLifecycle(status) {
3531
+ const normalized = status?.trim().toLowerCase();
3532
+ if (normalized === 'certified')
3533
+ return 'certified';
3534
+ if (normalized === 'review' || normalized === 'review_required')
3535
+ return 'review';
3536
+ if (normalized === 'pending_recertification')
3537
+ return 'pending_recertification';
3538
+ if (normalized === 'deprecated')
3539
+ return 'deprecated';
3540
+ return 'draft';
3541
+ }
3542
+ function manifestBlockSourceRevision(projectRoot, block) {
3543
+ const path = join(projectRoot, block.filePath);
3544
+ try {
3545
+ if (existsSync(path))
3546
+ return `sha256:${sha256(readFileSync(path, 'utf8'))}`;
3547
+ }
3548
+ catch {
3549
+ // The manifest object remains enough for a deterministic snapshot identity.
3550
+ }
3551
+ return `sha256:${sha256(stableStringify(block))}`;
3552
+ }
3398
3553
  function addDataLexManifestObjects(projectRoot, manifest, objects, edges, diagnostics) {
3399
3554
  const manifestPath = resolveDataLexManifestPath(projectRoot);
3400
3555
  if (!manifestPath)