@design-ai/cli 4.57.0 → 4.59.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.
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +59 -0
- package/README.ko.md +5 -4
- package/README.md +5 -4
- package/cli/commands/route.mjs +13 -1
- package/cli/lib/recall.mjs +2 -2
- package/cli/lib/route.mjs +62 -5
- package/cli/lib/search-ranked.mjs +33 -1
- package/cli/sdk/check-adapter.mjs +36 -0
- package/cli/sdk/index.mjs +22 -0
- package/cli/sdk/pack-adapter.mjs +55 -0
- package/cli/sdk/prompt-adapter.mjs +49 -0
- package/cli/sdk/recall-adapter.mjs +39 -0
- package/cli/sdk/route-adapter.mjs +45 -0
- package/cli/sdk/search-adapter.mjs +55 -0
- package/cli/sdk/validate.mjs +48 -0
- package/cli/sdk/version-adapter.mjs +17 -0
- package/docs/AGENT-SDK.md +98 -0
- package/docs/ROADMAP.md +68 -0
- package/docs/SDK.md +162 -0
- package/docs/external-status.md +6 -6
- package/knowledge/COVERAGE.md +9 -7
- package/knowledge/i18n/korean-density-conventions.md +108 -0
- package/knowledge/i18n/korean-product-conventions.md +2 -0
- package/knowledge/patterns/async-control.md +233 -0
- package/knowledge/patterns/error-states.md +1 -0
- package/knowledge/patterns/form-design.md +2 -0
- package/package.json +6 -2
- package/tools/audit/package-smoke.py +62 -0
- package/tools/audit/registry-smoke.py +5 -5
- package/tools/audit/smoke_assertions.py +3 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "design-ai",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.59.0",
|
|
4
4
|
"description": "Senior product designer for any AI coding agent. 20 skills, 17 commands, 4 review agents covering UI/UX, website improvement, design systems, motion, illustration, print, video, game UI, conversational, and spatial design. Korean market depth.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Sungjin Park",
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,65 @@
|
|
|
2
2
|
|
|
3
3
|
User-facing release notes for design-ai. Versions follow semver.
|
|
4
4
|
|
|
5
|
+
## v4.59.0 — Agent SDK Phase A (2026-07)
|
|
6
|
+
|
|
7
|
+
Adds a curated, semver-stable programmatic surface — `@design-ai/cli/sdk` — so an external Node.js program can call design-ai's deterministic design verbs as importable functions, without shelling out to the CLI or spawning the MCP server. The SDK is a thin adapter over the same `cli/lib` functions the CLI and MCP already call, so no design behavior changes. Phase A is read-only: no file writes, no network, no runtime dependencies. All additions are additive and backward-compatible.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- `@design-ai/cli/sdk` — eight read-only adapter verbs with their own stable signatures: `route(brief, opts)`, `prompt(brief, opts)`, `pack(brief, opts)`, `search(query, opts)`, `recall(query, opts)`, `check(artifact, opts)`, `routes()`, and `version()`. Each validates its inputs, resolves the package root the same way the CLI does, and returns the same JSON-serializable shape the CLI's `--json` mode emits. `check` operates on artifact content (not a path), so it reads and writes nothing.
|
|
11
|
+
- `package.json` `exports` map exposing `./sdk` (and `./package.json`) as the only public import paths; `cli/lib/*` stays internal and unstable, refactorable behind the adapter seam.
|
|
12
|
+
- `docs/SDK.md` — the public SDK reference (surface, return shapes, semver stability contract) — plus a "Node.js / Agent SDK" row in the README install tables and an Agent SDK mkdocs nav section.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- `npm test` now also runs `cli/sdk/*.test.mjs` (61 new SDK tests, 540 total), including a contract test (`cli/sdk/index.test.mjs`) that pins the eight exported names and their return-shape keys — the semver anchor — and asserts Phase A writes no `learningUsage` sidecar.
|
|
16
|
+
- `tools/audit/package-smoke.py` now imports `@design-ai/cli/sdk` from the installed tarball and exercises the eight verbs, asserting determinism and the read-only guarantee.
|
|
17
|
+
|
|
18
|
+
### Verified
|
|
19
|
+
- All 8 audits passed.
|
|
20
|
+
- `npm run release:check`.
|
|
21
|
+
- `npm run release:metadata`.
|
|
22
|
+
- `git diff --check`.
|
|
23
|
+
- Main-branch GitHub Actions (`Design-AI audit`, `Deploy doc site`) passed for the constituent commits.
|
|
24
|
+
|
|
25
|
+
### Versions
|
|
26
|
+
- `package.json` + `.claude-plugin/plugin.json`: 4.58.0 → 4.59.0.
|
|
27
|
+
- `vscode-extension/package.json`: remains 0.4.1.
|
|
28
|
+
|
|
29
|
+
### What this enables
|
|
30
|
+
- Agent runtimes, build scripts, and custom tools can consume design-ai's routing, prompt/pack generation, ranked search, recall, and artifact checks as plain functions — deterministic, in-process, zero-dependency — with a semver-stable contract independent of the internal `cli/lib` shapes.
|
|
31
|
+
|
|
32
|
+
## v4.58.0 — Retrieval Across Surfaces and Corpus Depth (2026-07)
|
|
33
|
+
|
|
34
|
+
Completes the retrieval integration started in v4.57.0 by bringing it to the last untouched surface (`route --explain`), refines recall quality so injected knowledge is real design guidance rather than index files, and closes the remaining dogfood-named corpus gaps. All additions are additive and backward-compatible; default output is unchanged unless a flag is passed.
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
- `route --explain` now includes an advisory "Related knowledge" section — brief-relevant corpus knowledge recalled by the shared lexical scorer, excluding what the route already curates. This is advisory only: route ids, scores, and curated knowledge are unchanged, and default `route` output is byte-unchanged. `design_ai_route`'s existing `explain` parameter carries it to MCP automatically. Retrieval now spans every surface: `search --ranked`, `prompt`/`pack --with-recall`, `learn --recall`, and `route --explain`.
|
|
38
|
+
- `knowledge/patterns/async-control.md` — the async action in-flight lifecycle: pending states, double-submit prevention, duration-matched loading affordances, optimistic updates with rollback, debounce/throttle, cancellation and out-of-order handling, concurrency policy, timeouts, and the accessibility floor.
|
|
39
|
+
- `knowledge/i18n/korean-density-conventions.md` — Korean B2B/enterprise density: the density ladder, table-first layouts, label-left multi-column forms, dense navigation, typography at density, and where density must yield to accessibility.
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
- Recall injection surfaces (`prompt`/`pack --with-recall`, `learn --recall`, `route --explain`) now exclude generated index/meta files (`COVERAGE.md`, `INDEX.md`, `docs/reference/*`) so injected context is real design knowledge; raw `search --ranked` still returns those files when explicitly searched.
|
|
43
|
+
- Knowledge corpus is now 94 files (from 92).
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
- `tools/audit/registry-smoke.py`'s learn-relevance assertion expected a stale token order (`keyboard, accessibility`) after the v4.57 shared-scorer change sorted matched tokens; aligned it with `package-smoke.py` and the real CLI output so the live post-publish registry smoke matches the published package.
|
|
47
|
+
|
|
48
|
+
### Verified
|
|
49
|
+
- All 8 audits passed.
|
|
50
|
+
- `npm run release:check`.
|
|
51
|
+
- `npm run release:metadata`.
|
|
52
|
+
- `git diff --check`.
|
|
53
|
+
- Main-branch GitHub Actions (`Design-AI audit`, `Deploy doc site`) passed for the constituent commits.
|
|
54
|
+
|
|
55
|
+
### Versions
|
|
56
|
+
- `package.json` + `.claude-plugin/plugin.json`: 4.57.0 → 4.58.0.
|
|
57
|
+
- `vscode-extension/package.json`: remains 0.4.1.
|
|
58
|
+
|
|
59
|
+
### What this enables
|
|
60
|
+
- Agents routing a brief now see additional relevant knowledge beyond the route's curated set, and every retrieval surface injects real design guidance rather than index tables.
|
|
61
|
+
- The Korean-market corpus gains async-control and B2B density coverage that dogfood runs specifically named as missing.
|
|
62
|
+
- Publishing v4.58.0 realigns `main` with the published package so the live registry smoke verifies cleanly again.
|
|
63
|
+
|
|
5
64
|
## v4.57.0 — Local Retrieval Memory: Ranked Search and Optional Embeddings (2026-07)
|
|
6
65
|
|
|
7
66
|
Ships the Phase 754 AI-learning retrieval work: a deterministic, zero-dependency local retrieval layer over the knowledge corpus and the local learning profile, plus an opt-in local embedding rerank backend. Defaults are unchanged — `search`, `route`, `prompt`, and `pack` behave exactly as before unless a new flag is passed — so this release is additive and backward-compatible. It also moves `refs/` source links behind generated reference pages and hardens the docs deploy against intermittent GitHub Pages failures.
|
package/README.ko.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/sungjin9288/design-ai/actions/workflows/audit.yml)
|
|
4
4
|
[](https://sungjin9288.github.io/design-ai/ko/)
|
|
5
|
-
[](knowledge/PRINCIPLES.md)
|
|
6
6
|
[](examples/README.md)
|
|
7
7
|
[](skills/README.md)
|
|
8
8
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
> **모델이 아니에요. 파인튜닝도 아니에요.** 디자인 전문 지식을 구조화한 코퍼스 + 에이전트가 바로 실행할 수 있는 지시문이에요. 범용 LLM을 이번 세션에서만큼은 시니어 디자이너로 바꿔주는 셈이에요.
|
|
14
14
|
|
|
15
|
-
> **배포 상태, 2026-07-
|
|
15
|
+
> **배포 상태, 2026-07-04 확인:** 로컬 `npm run release:check`는 통과했고, GitHub Pages 문서는 live 상태이며, GitHub Release `v4.58.0`과 npm `@design-ai/cli@4.58.0`(`latest`) publish가 provenance와 함께 확인됐어요. 수정 후 live `npm run registry:smoke`가 published `@design-ai/cli@4.58.0`에 대해 깨끗이 통과했어요(retrieval 표면과 route enrichment 포함). Homebrew formula는 `v4.58.0`에 pinning되어 있고, VS Code Marketplace에는 `sungjin.design-ai-vscode@0.4.1`이 공개되어 있어요. 자세한 내용은 [`docs/external-status.md`](docs/external-status.md)를 확인하세요.
|
|
16
16
|
|
|
17
17
|
## 한눈에 보는 커버리지
|
|
18
18
|
|
|
@@ -88,6 +88,7 @@ CLI 명령어: `design-ai install [--json]`, `update [--dry-run] [--json]`, `uni
|
|
|
88
88
|
| **Cursor** | 이 폴더를 열고 `AGENTS.md`를 `.cursorrules`로 심볼릭 링크하거나 복사해요. [워크스루](docs/integrations/cursor-walkthrough.md). |
|
|
89
89
|
| **Aider** | `AGENTS.md`를 시스템 프롬프트로 전달해요. [워크스루](docs/integrations/aider-walkthrough.md). |
|
|
90
90
|
| **Anthropic / OpenAI SDK** | 관련 스킬 `PLAYBOOK.md` 파일을 프롬프트에 포함시켜요. [워크스루](docs/integrations/sdk-walkthrough.md). |
|
|
91
|
+
| **Node.js / Agent SDK** | `import { route, prompt, pack, search, recall, check, routes, version } from "@design-ai/cli/sdk"` — CLI 셸 실행이나 MCP 서버 없이 design-ai의 결정적 기능을 함수로 바로 호출해요. 읽기 전용(Phase A). [SDK 레퍼런스](docs/SDK.md). |
|
|
91
92
|
| **일반 프롬프트** | 어떤 `skills/*/PLAYBOOK.md` 본문이든 붙여넣으세요 — 각각 자기 완결적이에요. |
|
|
92
93
|
|
|
93
94
|
에이전트별 설치 방법은 [`docs/USING.md`](docs/USING.md)를, 구체적인 사용 예시는 위 워크스루 링크를 참고하세요.
|
|
@@ -107,7 +108,7 @@ design-ai/
|
|
|
107
108
|
│
|
|
108
109
|
├── refs/ # Sparse-clone된 업스트림 소스 (gitignored)
|
|
109
110
|
│
|
|
110
|
-
├── knowledge/ #
|
|
111
|
+
├── knowledge/ # 94개 손으로 쓴 + 추출된 지식 파일
|
|
111
112
|
│ ├── design-tokens/ # W3C DTCG, OKLCH, HCT
|
|
112
113
|
│ ├── components/ # Ant + MUI + shadcn 합성
|
|
113
114
|
│ ├── patterns/ # 인증, 가격, 랜딩 히어로, 브랜드, 이메일 등
|
|
@@ -171,7 +172,7 @@ design-ai는 한국 시장을 1순위로 만들어졌고, 글로벌 시장 패
|
|
|
171
172
|
|
|
172
173
|
## 상태
|
|
173
174
|
|
|
174
|
-
전체 단계 로그는 [`docs/ROADMAP.md`](docs/ROADMAP.md), 현재 완료 범위는 [`docs/PRODUCT-READINESS.md`](docs/PRODUCT-READINESS.md)에서 확인하세요. 현재 **v4.
|
|
175
|
+
전체 단계 로그는 [`docs/ROADMAP.md`](docs/ROADMAP.md), 현재 완료 범위는 [`docs/PRODUCT-READINESS.md`](docs/PRODUCT-READINESS.md)에서 확인하세요. 현재 **v4.58.0**: public npm publish, provenance-backed GitHub Actions release, public registry smoke, Website Console MCP readiness, workspace learning restore/eval coverage, handoff bundle verification, 90%+ component coverage가 완료됐어요.
|
|
175
176
|
|
|
176
177
|
핵심 디자인 컨설팅 워크플로우는 로컬 릴리스 기준으로 준비되어 있어요. 웹사이트 개선 컨트롤 타워는 zero-dependency static Web App과 `website-improvement` route/skill/command로 제공되고, Site Profile, audit checklist, MCP readiness, refactor prompt, handoff evidence tracking, bundle export/verify/repair를 한 번에 다뤄요. 로컬 학습 선호도는 `design-ai learn`으로 관리해요 — profile bootstrap, feedback 캡처, 읽기 전용 signal registry, 반복 QA 신호에서 만드는 skill 제안, 그리고 backup/restore/curate/audit까지 전부 로컬에서만 동작하는 opt-in 기능이에요. AI 모델 학습이나 fine-tuning은 여전히 현재 배포 범위 밖이에요.
|
|
177
178
|
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/sungjin9288/design-ai/actions/workflows/audit.yml)
|
|
4
4
|
[](https://sungjin9288.github.io/design-ai/)
|
|
5
|
-
[](knowledge/PRINCIPLES.md)
|
|
6
6
|
[](examples/README.md)
|
|
7
7
|
[](skills/README.md)
|
|
8
8
|
|
|
@@ -12,7 +12,7 @@ A model-agnostic design knowledge base + skill system. Drop it in front of any A
|
|
|
12
12
|
|
|
13
13
|
> **Not a model. Not a fine-tune.** A structured corpus of design expertise + agent-ready instructions that turn a general-purpose LLM into an expert.
|
|
14
14
|
|
|
15
|
-
> **Distribution status, checked 2026-07-
|
|
15
|
+
> **Distribution status, checked 2026-07-04:** local `npm run release:check` passes, GitHub Pages docs are live, GitHub Release `v4.58.0` is published, `@design-ai/cli@4.58.0` is public on npm (`latest`) with provenance, and the live `npm run registry:smoke` passes cleanly against `@design-ai/cli@4.58.0`. The Homebrew formula is pinned to `v4.58.0`, and `sungjin.design-ai-vscode@0.4.1` is public on the VS Code Marketplace. See [`docs/external-status.md`](docs/external-status.md).
|
|
16
16
|
|
|
17
17
|
## Coverage at a glance
|
|
18
18
|
|
|
@@ -89,6 +89,7 @@ See [`docs/DISTRIBUTION.md`](docs/DISTRIBUTION.md) for the full distribution gui
|
|
|
89
89
|
| **Aider** | Pass `AGENTS.md` as system prompt. [Walkthrough](docs/integrations/aider-walkthrough.md). |
|
|
90
90
|
| **Anthropic / OpenAI SDK** | Embed relevant skill `PLAYBOOK.md` files in your prompt. [Walkthrough](docs/integrations/sdk-walkthrough.md). |
|
|
91
91
|
| **VS Code** | Install the public Marketplace extension for sidebar trees + quick-pick commands. [Walkthrough](docs/integrations/vscode-walkthrough.md). |
|
|
92
|
+
| **Node.js / Agent SDK** | `import { route, prompt, pack, search, recall, check, routes, version } from "@design-ai/cli/sdk"` — call design-ai's deterministic verbs as functions, no CLI shell-out or MCP server needed. Read-only (Phase A). [SDK reference](docs/SDK.md). |
|
|
92
93
|
| **Plain prompt** | Paste any `skills/*/PLAYBOOK.md` body — each is self-contained. |
|
|
93
94
|
|
|
94
95
|
See [`docs/USING.md`](docs/USING.md) for per-agent setup details, or the linked walkthroughs for concrete example sessions.
|
|
@@ -107,7 +108,7 @@ design-ai/
|
|
|
107
108
|
│
|
|
108
109
|
├── refs/ # Sparse-cloned upstream sources (gitignored)
|
|
109
110
|
│
|
|
110
|
-
├── knowledge/ #
|
|
111
|
+
├── knowledge/ # 94 hand-written + extracted knowledge files
|
|
111
112
|
│ ├── design-tokens/ # Token systems (W3C DTCG, OKLCH, HCT)
|
|
112
113
|
│ ├── components/ # Component synthesis (Ant + MUI + shadcn)
|
|
113
114
|
│ ├── patterns/ # Auth, pricing, landing hero, brand, email, ...
|
|
@@ -213,7 +214,7 @@ Refresh refs/ on demand: `./tools/extractors/run-all.sh`.
|
|
|
213
214
|
|
|
214
215
|
## Status
|
|
215
216
|
|
|
216
|
-
See [`docs/ROADMAP.md`](docs/ROADMAP.md) for the full phase log and [`docs/PRODUCT-READINESS.md`](docs/PRODUCT-READINESS.md) for the current completion boundary. Currently at **v4.
|
|
217
|
+
See [`docs/ROADMAP.md`](docs/ROADMAP.md) for the full phase log and [`docs/PRODUCT-READINESS.md`](docs/PRODUCT-READINESS.md) for the current completion boundary. Currently at **v4.58.0**: public npm publish, provenance-backed GitHub Actions release, public registry smoke, Website Console MCP readiness, workspace learning restore/eval coverage, handoff bundle verification, and 90%+ component coverage are complete.
|
|
217
218
|
|
|
218
219
|
Core design consulting workflows are locally release-ready. The website improvement control tower ships as a zero-dependency static Web App plus a `website-improvement` route/skill/command, covering Site Profiles, audit checklists, MCP readiness, refactor prompts, handoff evidence tracking, and bundle export/verify/repair. Local learning preferences are available through `design-ai learn` — profile bootstrap, feedback capture, a read-only signals registry, skill-proposal generation from repeated QA signals, and full backup/restore/curate/audit tooling, all local-only and opt-in. AI model training or fine-tuning remains outside the shipped scope.
|
|
219
220
|
|
package/cli/commands/route.mjs
CHANGED
|
@@ -28,7 +28,7 @@ function printHelp() {
|
|
|
28
28
|
console.log(" --stdin Read the task brief, or route eval JSON with --eval, from standard input");
|
|
29
29
|
console.log(" --list List route ids without scoring a brief");
|
|
30
30
|
console.log(" --limit N Maximum route recommendations to return, 1-10. Default: 3");
|
|
31
|
-
console.log(" --explain Include route scoring
|
|
31
|
+
console.log(" --explain Include route scoring, reference coverage, and related knowledge");
|
|
32
32
|
console.log(" --eval-template Generate a runnable route eval checkpoint JSON template");
|
|
33
33
|
console.log(" --eval Run deterministic route-selection checkpoint cases");
|
|
34
34
|
console.log(" --strict With --eval, exit non-zero on warning or failure");
|
|
@@ -78,6 +78,17 @@ function printRoute(route, index, explain = false) {
|
|
|
78
78
|
for (const knowledge of route.knowledge) {
|
|
79
79
|
console.log(` read: ${formatPath(knowledge)}`);
|
|
80
80
|
}
|
|
81
|
+
|
|
82
|
+
if (explain) {
|
|
83
|
+
const related = route.relatedKnowledge || [];
|
|
84
|
+
if (related.length === 0) {
|
|
85
|
+
console.log(" related: (none)");
|
|
86
|
+
} else {
|
|
87
|
+
for (const item of related) {
|
|
88
|
+
console.log(` related: ${item.id} ${dim(`(score ${item.score.toFixed(2)})`)}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
81
92
|
}
|
|
82
93
|
|
|
83
94
|
function printCatalogRoute(route, index) {
|
|
@@ -211,6 +222,7 @@ export async function runRoute(args) {
|
|
|
211
222
|
brief,
|
|
212
223
|
sourceRoot: DESIGN_AI_HOME,
|
|
213
224
|
limit: parsed.limit,
|
|
225
|
+
explain: parsed.explain,
|
|
214
226
|
});
|
|
215
227
|
|
|
216
228
|
const payload = {
|
package/cli/lib/recall.mjs
CHANGED
|
@@ -109,7 +109,7 @@ export function buildRecallContext({
|
|
|
109
109
|
const candidateCount = collectCorpusDocuments({ designAiPath, dirs }).length;
|
|
110
110
|
|
|
111
111
|
const hits = query
|
|
112
|
-
? rankedSearchCorpus({ query, designAiPath, dirs, limit: recallLimit }).hits
|
|
112
|
+
? rankedSearchCorpus({ query, designAiPath, dirs, limit: recallLimit, excludeGeneratedIndex: true }).hits
|
|
113
113
|
: [];
|
|
114
114
|
|
|
115
115
|
const selected = hits.map((hit) => ({
|
|
@@ -150,7 +150,7 @@ export function buildLearnRecall({
|
|
|
150
150
|
|
|
151
151
|
const corpusCandidateCount = collectCorpusDocuments({ designAiPath, dirs }).length;
|
|
152
152
|
const corpusHits = normalizedQuery
|
|
153
|
-
? rankedSearchCorpus({ query: normalizedQuery, designAiPath, dirs, limit }).hits
|
|
153
|
+
? rankedSearchCorpus({ query: normalizedQuery, designAiPath, dirs, limit, excludeGeneratedIndex: true }).hits
|
|
154
154
|
: [];
|
|
155
155
|
const corpusSelected = corpusHits.map((hit) => ({
|
|
156
156
|
id: hit.relPath,
|
package/cli/lib/route.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
|
|
9
9
|
import { parseBriefSourceFlag } from "./brief.mjs";
|
|
10
|
+
import { rankedSearchCorpus } from "./search-ranked.mjs";
|
|
10
11
|
import { suggestNearest, unknownOptionMessage } from "./suggest.mjs";
|
|
11
12
|
|
|
12
13
|
function exists(p) {
|
|
@@ -35,6 +36,17 @@ const ROUTE_OPTIONS = [
|
|
|
35
36
|
];
|
|
36
37
|
const ROUTE_EVAL_VERSION = 1;
|
|
37
38
|
const ROUTE_EVAL_DEFAULT_LIMIT = 3;
|
|
39
|
+
// Advisory "Related knowledge" recall (docs/AI-LEARNING-PHASE2.md, "Phase A
|
|
40
|
+
// implementation review" Q3): under `--explain` only, surface the top corpus
|
|
41
|
+
// knowledge/ files recalled by the shipped deterministic lexical scorer that the
|
|
42
|
+
// route's curated `knowledge` list does NOT already point to. Purely additive —
|
|
43
|
+
// it never changes route selection, ids, scores, or the curated list. Restricted
|
|
44
|
+
// to knowledge/ so it surfaces design knowledge, not docs/QUICKSTART. The recall
|
|
45
|
+
// pulls RELATED_KNOWLEDGE_RECALL_LIMIT candidates then keeps the top
|
|
46
|
+
// RELATED_KNOWLEDGE_KEEP after excluding the curated set.
|
|
47
|
+
const RELATED_KNOWLEDGE_DIRS = ["knowledge"];
|
|
48
|
+
const RELATED_KNOWLEDGE_RECALL_LIMIT = 10;
|
|
49
|
+
const RELATED_KNOWLEDGE_KEEP = 3;
|
|
38
50
|
const CONFIDENCE_ORDER = {
|
|
39
51
|
low: 1,
|
|
40
52
|
medium: 2,
|
|
@@ -456,6 +468,35 @@ function routeExplanation({ hits, command, skills, agents, knowledge, forced = f
|
|
|
456
468
|
};
|
|
457
469
|
}
|
|
458
470
|
|
|
471
|
+
// Advisory related-knowledge recall for a single route. REUSES rankedSearchCorpus
|
|
472
|
+
// (the shipped deterministic lexical scorer — score desc, id asc) scoped to
|
|
473
|
+
// knowledge/, excludes the route's curated knowledge relPaths, and keeps the top
|
|
474
|
+
// RELATED_KNOWLEDGE_KEEP remaining. Returns [] on empty brief or no hits.
|
|
475
|
+
function relatedKnowledgeFor({ brief, sourceRoot, curatedRelPaths }) {
|
|
476
|
+
const query = String(brief || "").trim();
|
|
477
|
+
if (!query) return [];
|
|
478
|
+
|
|
479
|
+
const curated = new Set(curatedRelPaths);
|
|
480
|
+
const { hits } = rankedSearchCorpus({
|
|
481
|
+
query,
|
|
482
|
+
dirs: RELATED_KNOWLEDGE_DIRS,
|
|
483
|
+
limit: RELATED_KNOWLEDGE_RECALL_LIMIT,
|
|
484
|
+
designAiPath: sourceRoot,
|
|
485
|
+
// Recall/injection surface: keep generated index/meta docs (COVERAGE.md,
|
|
486
|
+
// INDEX.md, docs/reference/*) out of the advisory related-knowledge list.
|
|
487
|
+
excludeGeneratedIndex: true,
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
return hits
|
|
491
|
+
.filter((hit) => !curated.has(hit.relPath))
|
|
492
|
+
.slice(0, RELATED_KNOWLEDGE_KEEP)
|
|
493
|
+
.map((hit) => ({
|
|
494
|
+
id: hit.relPath,
|
|
495
|
+
score: hit.score,
|
|
496
|
+
matchedTokens: hit.matchedTokens,
|
|
497
|
+
}));
|
|
498
|
+
}
|
|
499
|
+
|
|
459
500
|
function routeToResult(route, sourceRoot, hits, options = {}) {
|
|
460
501
|
const command = route.command
|
|
461
502
|
? { path: route.command, exists: exists(path.join(sourceRoot, route.command)) }
|
|
@@ -467,6 +508,17 @@ function routeToResult(route, sourceRoot, hits, options = {}) {
|
|
|
467
508
|
const fallback = Boolean(options.fallback);
|
|
468
509
|
const catalog = Boolean(options.catalog);
|
|
469
510
|
|
|
511
|
+
// Advisory related-knowledge is attached ONLY when explain is requested, so the
|
|
512
|
+
// default `route` JSON stays byte-unchanged. `knowledge` already merges
|
|
513
|
+
// COMMON_KNOWLEDGE + route.knowledge, so its relPaths are the dedupe set.
|
|
514
|
+
const relatedKnowledge = options.explain
|
|
515
|
+
? relatedKnowledgeFor({
|
|
516
|
+
brief: options.brief || "",
|
|
517
|
+
sourceRoot,
|
|
518
|
+
curatedRelPaths: knowledge.map((entry) => entry.path),
|
|
519
|
+
})
|
|
520
|
+
: null;
|
|
521
|
+
|
|
470
522
|
return {
|
|
471
523
|
id: route.id,
|
|
472
524
|
label: route.label,
|
|
@@ -479,6 +531,7 @@ function routeToResult(route, sourceRoot, hits, options = {}) {
|
|
|
479
531
|
knowledge,
|
|
480
532
|
keywords: route.keywords,
|
|
481
533
|
explanation: routeExplanation({ hits, command, skills, agents, knowledge, forced, fallback, catalog }),
|
|
534
|
+
...(relatedKnowledge ? { relatedKnowledge } : {}),
|
|
482
535
|
...(forced ? { forced: true } : {}),
|
|
483
536
|
...(fallback ? { fallback: true } : {}),
|
|
484
537
|
};
|
|
@@ -501,18 +554,22 @@ export function routeById({ routeId, sourceRoot }) {
|
|
|
501
554
|
};
|
|
502
555
|
}
|
|
503
556
|
|
|
504
|
-
function fallbackResult(sourceRoot) {
|
|
557
|
+
function fallbackResult(sourceRoot, options = {}) {
|
|
505
558
|
const route = ROUTES.find((item) => item.id === "design-from-brief");
|
|
506
559
|
return {
|
|
507
|
-
...routeToResult(route, sourceRoot, [], { fallback: true }),
|
|
560
|
+
...routeToResult(route, sourceRoot, [], { fallback: true, ...options }),
|
|
508
561
|
confidence: "low",
|
|
509
562
|
};
|
|
510
563
|
}
|
|
511
564
|
|
|
512
|
-
export function routeBrief({ brief, sourceRoot, limit = 3 }) {
|
|
565
|
+
export function routeBrief({ brief, sourceRoot, limit = 3, explain = false }) {
|
|
513
566
|
const normalized = brief.trim();
|
|
514
567
|
if (!normalized) return [];
|
|
515
568
|
|
|
569
|
+
// Only compute advisory related-knowledge under --explain; keep the default
|
|
570
|
+
// routing (keyword scoring, ordering, selection) completely unchanged.
|
|
571
|
+
const resultOptions = explain ? { explain: true, brief: normalized } : {};
|
|
572
|
+
|
|
516
573
|
const scored = ROUTES
|
|
517
574
|
.map((route) => ({ route, hits: keywordHits(normalized, route.keywords) }))
|
|
518
575
|
.filter((item) => item.hits.length > 0)
|
|
@@ -521,10 +578,10 @@ export function routeBrief({ brief, sourceRoot, limit = 3 }) {
|
|
|
521
578
|
return a.route.label.localeCompare(b.route.label);
|
|
522
579
|
})
|
|
523
580
|
.slice(0, limit)
|
|
524
|
-
.map((item) => routeToResult(item.route, sourceRoot, item.hits));
|
|
581
|
+
.map((item) => routeToResult(item.route, sourceRoot, item.hits, resultOptions));
|
|
525
582
|
|
|
526
583
|
if (scored.length > 0) return scored;
|
|
527
|
-
return [fallbackResult(sourceRoot)];
|
|
584
|
+
return [fallbackResult(sourceRoot, resultOptions)];
|
|
528
585
|
}
|
|
529
586
|
|
|
530
587
|
function isoTimestamp(now = new Date()) {
|
|
@@ -24,6 +24,22 @@ import { DEFAULT_SEARCH_DIRS } from "./search.mjs";
|
|
|
24
24
|
|
|
25
25
|
const RANKED_PREVIEW_LEN = 120;
|
|
26
26
|
|
|
27
|
+
// Predicate for GENERATED index/meta docs that must be kept out of the RECALL /
|
|
28
|
+
// context-injection layer (pack/prompt --with-recall, learn --recall corpus side,
|
|
29
|
+
// route --explain related knowledge). These files rank on keyword density but are
|
|
30
|
+
// meta/index tables, not design knowledge worth injecting into an agent's context.
|
|
31
|
+
// Rule: true when the basename is `COVERAGE.md` or `INDEX.md` (generated coverage
|
|
32
|
+
// table / component index), OR the forward-slash-normalized path starts with
|
|
33
|
+
// `docs/reference/` (generated upstream-reference pages). Raw `search --ranked`
|
|
34
|
+
// does NOT apply this — a user explicitly searching may legitimately want an index.
|
|
35
|
+
export function isGeneratedIndexDoc(relPath) {
|
|
36
|
+
const normalized = String(relPath || "").replace(/\\/g, "/");
|
|
37
|
+
const basename = normalized.slice(normalized.lastIndexOf("/") + 1);
|
|
38
|
+
return basename === "COVERAGE.md"
|
|
39
|
+
|| basename === "INDEX.md"
|
|
40
|
+
|| normalized.startsWith("docs/reference/");
|
|
41
|
+
}
|
|
42
|
+
|
|
27
43
|
// N = max(limit*5, 25): the number of top lexical candidates handed to the embedding
|
|
28
44
|
// reranker. Documented constant (docs/AI-LEARNING-PHASE2.md, Phase B CLI wiring).
|
|
29
45
|
export function embeddingCandidateCount(limit) {
|
|
@@ -66,12 +82,28 @@ export function rankedSearchCorpus({
|
|
|
66
82
|
dirs = DEFAULT_SEARCH_DIRS,
|
|
67
83
|
limit = 20,
|
|
68
84
|
indexDir = defaultIndexDir(),
|
|
85
|
+
// Opt-in RECALL filter: when true, drop generated index/meta docs
|
|
86
|
+
// (isGeneratedIndexDoc) BEFORE applying `limit`, so the limit fills with real
|
|
87
|
+
// knowledge instead of index files. Default false keeps raw `search --ranked`
|
|
88
|
+
// byte-unchanged. Filtering before the limit preserves determinism (score desc,
|
|
89
|
+
// id asc) — the rank pass already orders fully, we only remove excluded ids.
|
|
90
|
+
excludeGeneratedIndex = false,
|
|
69
91
|
} = {}) {
|
|
70
92
|
const documents = collectCorpusDocuments({ designAiPath, dirs });
|
|
71
93
|
const stats = buildLexicalStats(documents.map(({ id, text }) => ({ id, text })));
|
|
72
94
|
const textById = new Map(documents.map((doc) => [doc.id, doc.text]));
|
|
73
95
|
|
|
74
|
-
|
|
96
|
+
// When excluding, rank the FULL candidate pool first (limit = documents.length)
|
|
97
|
+
// so that filtering out index docs cannot let a real-knowledge hit fall off the
|
|
98
|
+
// pre-limit cutoff; then re-apply `limit`. Ordering is unchanged (score desc, id asc).
|
|
99
|
+
const ranked = rankLexical(query, stats, {
|
|
100
|
+
limit: excludeGeneratedIndex ? documents.length : limit,
|
|
101
|
+
});
|
|
102
|
+
const filtered = excludeGeneratedIndex
|
|
103
|
+
? ranked.filter((hit) => !isGeneratedIndexDoc(hit.id)).slice(0, limit)
|
|
104
|
+
: ranked;
|
|
105
|
+
|
|
106
|
+
const hits = filtered.map((hit) => ({
|
|
75
107
|
relPath: hit.id,
|
|
76
108
|
file: path.join(designAiPath, hit.id),
|
|
77
109
|
score: hit.score,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// SDK adapter: check(artifact, opts). See docs/AGENT-SDK.md.
|
|
2
|
+
//
|
|
3
|
+
// Read-only: capture is never enabled from the SDK in Phase A (the CLI's
|
|
4
|
+
// `--learn` writes a local learning-profile capture; there is no equivalent
|
|
5
|
+
// opt-in here, consistent with "no file writes" for Phase A).
|
|
6
|
+
|
|
7
|
+
import { checkArtifactContent } from "../lib/check.mjs";
|
|
8
|
+
import { assertKnownRouteId } from "../lib/route.mjs";
|
|
9
|
+
import { optionalBoolean, optionalString, requireNonEmptyString, requireOptions } from "./validate.mjs";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Check a generated design Markdown artifact for grounding, accessibility,
|
|
13
|
+
* responsive, unresolved-marker, and route-specific requirements. Pure,
|
|
14
|
+
* read-only adapter over `checkArtifactContent` from cli/lib/check.mjs.
|
|
15
|
+
*
|
|
16
|
+
* @param {string} artifact - Markdown artifact content to check.
|
|
17
|
+
* @param {{routeId?: string, strict?: boolean}} [opts]
|
|
18
|
+
* @returns {object} CheckReport — the same shape as `design-ai check --json`.
|
|
19
|
+
*/
|
|
20
|
+
export function check(artifact, opts = {}) {
|
|
21
|
+
requireNonEmptyString(artifact, "artifact");
|
|
22
|
+
const options = requireOptions(opts, "check");
|
|
23
|
+
|
|
24
|
+
const routeId = optionalString(options.routeId, "routeId");
|
|
25
|
+
if (routeId) assertKnownRouteId(routeId, { allowEmpty: false });
|
|
26
|
+
// `strict` only affects CLI exit-code behavior; validated for type safety,
|
|
27
|
+
// but the SDK returns the report as-is and lets the caller decide what to
|
|
28
|
+
// do with report.status — there is no process exit code to influence here.
|
|
29
|
+
optionalBoolean(options.strict, "strict", false);
|
|
30
|
+
|
|
31
|
+
return checkArtifactContent({
|
|
32
|
+
content: artifact,
|
|
33
|
+
filePath: "sdk",
|
|
34
|
+
routeId,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// design-ai Agent SDK — Phase A (read-only). See docs/AGENT-SDK.md and docs/SDK.md.
|
|
2
|
+
//
|
|
3
|
+
// A curated, semver-stable adapter over the same cli/lib functions the CLI and
|
|
4
|
+
// MCP server call. Each verb validates its inputs, resolves the package root
|
|
5
|
+
// the same way the CLI does, and returns a plain JSON-serializable object —
|
|
6
|
+
// the same shape the CLI's --json mode emits. No network calls, no runtime
|
|
7
|
+
// dependencies. Phase A performs no file writes: no learning-usage sidecar
|
|
8
|
+
// writes, even from prompt/pack's withLearning option.
|
|
9
|
+
//
|
|
10
|
+
// Import path: `@design-ai/cli/sdk` (see the "exports" map in package.json).
|
|
11
|
+
// `cli/lib/*` stays internal and unstable; this barrel is the only supported
|
|
12
|
+
// public surface. Do not import `cli/lib/*.mjs` directly from outside this
|
|
13
|
+
// package — only the 8 named exports below are covered by the semver
|
|
14
|
+
// stability contract described in docs/SDK.md.
|
|
15
|
+
|
|
16
|
+
export { check } from "./check-adapter.mjs";
|
|
17
|
+
export { pack } from "./pack-adapter.mjs";
|
|
18
|
+
export { prompt } from "./prompt-adapter.mjs";
|
|
19
|
+
export { recall } from "./recall-adapter.mjs";
|
|
20
|
+
export { route, routes } from "./route-adapter.mjs";
|
|
21
|
+
export { search } from "./search-adapter.mjs";
|
|
22
|
+
export { version } from "./version-adapter.mjs";
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// SDK adapter: pack(brief, opts). See docs/AGENT-SDK.md.
|
|
2
|
+
//
|
|
3
|
+
// Phase A is read-only: like the prompt adapter, this never records the
|
|
4
|
+
// learning-usage sidecar, even when withLearning is requested.
|
|
5
|
+
|
|
6
|
+
import { DESIGN_AI_HOME, SYMLINK_PREFIX } from "../lib/paths.mjs";
|
|
7
|
+
import { buildPromptPack } from "../lib/pack.mjs";
|
|
8
|
+
import {
|
|
9
|
+
optionalBoolean,
|
|
10
|
+
optionalInteger,
|
|
11
|
+
optionalString,
|
|
12
|
+
requireNonEmptyString,
|
|
13
|
+
requireOptions,
|
|
14
|
+
} from "./validate.mjs";
|
|
15
|
+
|
|
16
|
+
const DEFAULT_MAX_BYTES = 120_000;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Build a ready-to-use prompt plus bounded context-file bundle from a task
|
|
20
|
+
* brief. Pure, read-only adapter over `buildPromptPack` from cli/lib/pack.mjs.
|
|
21
|
+
* Never records learning-usage, even with withLearning: true.
|
|
22
|
+
*
|
|
23
|
+
* @param {string} brief - Task brief text.
|
|
24
|
+
* @param {{routeId?: string, maxBytes?: number, withLearning?: boolean, learningCategory?: string, learningLimit?: number, withRecall?: boolean, recallLimit?: number}} [opts]
|
|
25
|
+
* @returns {object} Pack — the same shape as `design-ai pack --json` (minus learningUsage).
|
|
26
|
+
*/
|
|
27
|
+
export function pack(brief, opts = {}) {
|
|
28
|
+
requireNonEmptyString(brief, "brief");
|
|
29
|
+
const options = requireOptions(opts, "pack");
|
|
30
|
+
|
|
31
|
+
const routeId = optionalString(options.routeId, "routeId");
|
|
32
|
+
const maxBytes = optionalInteger(options.maxBytes, "maxBytes", {
|
|
33
|
+
fallback: DEFAULT_MAX_BYTES,
|
|
34
|
+
min: 1000,
|
|
35
|
+
max: 1_000_000,
|
|
36
|
+
});
|
|
37
|
+
const withLearning = optionalBoolean(options.withLearning, "withLearning", false);
|
|
38
|
+
const learningCategory = optionalString(options.learningCategory, "learningCategory");
|
|
39
|
+
const learningLimit = optionalInteger(options.learningLimit, "learningLimit", { fallback: 0, min: 1, max: 100, zeroMeansUnset: true });
|
|
40
|
+
const withRecall = optionalBoolean(options.withRecall, "withRecall", false);
|
|
41
|
+
const recallLimit = optionalInteger(options.recallLimit, "recallLimit", { fallback: 0, min: 1, max: 20, zeroMeansUnset: true });
|
|
42
|
+
|
|
43
|
+
return buildPromptPack({
|
|
44
|
+
brief,
|
|
45
|
+
sourceRoot: DESIGN_AI_HOME,
|
|
46
|
+
prefix: SYMLINK_PREFIX,
|
|
47
|
+
maxBytes,
|
|
48
|
+
routeId,
|
|
49
|
+
withLearning,
|
|
50
|
+
learningCategory,
|
|
51
|
+
learningLimit,
|
|
52
|
+
withRecall,
|
|
53
|
+
recallLimit,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// SDK adapter: prompt(brief, opts). See docs/AGENT-SDK.md.
|
|
2
|
+
//
|
|
3
|
+
// Phase A is read-only: unlike the CLI's `--with-learning` (which records a
|
|
4
|
+
// local usage sidecar entry via recordLearningUsage), the SDK adapter never
|
|
5
|
+
// writes the learning-usage sidecar, even when withLearning is requested. It
|
|
6
|
+
// only reads the local learning profile to build the learning context.
|
|
7
|
+
|
|
8
|
+
import { DESIGN_AI_HOME, SYMLINK_PREFIX } from "../lib/paths.mjs";
|
|
9
|
+
import { buildPromptPlan } from "../lib/prompt.mjs";
|
|
10
|
+
import {
|
|
11
|
+
optionalBoolean,
|
|
12
|
+
optionalInteger,
|
|
13
|
+
optionalString,
|
|
14
|
+
requireNonEmptyString,
|
|
15
|
+
requireOptions,
|
|
16
|
+
} from "./validate.mjs";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Build a ready-to-use agent prompt plan from a task brief. Pure, read-only
|
|
20
|
+
* adapter over `buildPromptPlan` from cli/lib/prompt.mjs. Never records
|
|
21
|
+
* learning-usage, even with withLearning: true (Phase A is read-only).
|
|
22
|
+
*
|
|
23
|
+
* @param {string} brief - Task brief text.
|
|
24
|
+
* @param {{routeId?: string, withLearning?: boolean, learningCategory?: string, learningLimit?: number, withRecall?: boolean, recallLimit?: number}} [opts]
|
|
25
|
+
* @returns {object|null} PromptPlan — the same shape as `design-ai prompt --json` (minus learningUsage).
|
|
26
|
+
*/
|
|
27
|
+
export function prompt(brief, opts = {}) {
|
|
28
|
+
requireNonEmptyString(brief, "brief");
|
|
29
|
+
const options = requireOptions(opts, "prompt");
|
|
30
|
+
|
|
31
|
+
const routeId = optionalString(options.routeId, "routeId");
|
|
32
|
+
const withLearning = optionalBoolean(options.withLearning, "withLearning", false);
|
|
33
|
+
const learningCategory = optionalString(options.learningCategory, "learningCategory");
|
|
34
|
+
const learningLimit = optionalInteger(options.learningLimit, "learningLimit", { fallback: 0, min: 1, max: 100, zeroMeansUnset: true });
|
|
35
|
+
const withRecall = optionalBoolean(options.withRecall, "withRecall", false);
|
|
36
|
+
const recallLimit = optionalInteger(options.recallLimit, "recallLimit", { fallback: 0, min: 1, max: 20, zeroMeansUnset: true });
|
|
37
|
+
|
|
38
|
+
return buildPromptPlan({
|
|
39
|
+
brief,
|
|
40
|
+
sourceRoot: DESIGN_AI_HOME,
|
|
41
|
+
prefix: SYMLINK_PREFIX,
|
|
42
|
+
routeId,
|
|
43
|
+
withLearning,
|
|
44
|
+
learningCategory,
|
|
45
|
+
learningLimit,
|
|
46
|
+
withRecall,
|
|
47
|
+
recallLimit,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// SDK adapter: recall(query, opts). See docs/AGENT-SDK.md.
|
|
2
|
+
//
|
|
3
|
+
// Combined recall view: brief-relevant shipped corpus knowledge (`corpus`) plus
|
|
4
|
+
// brief-relevant local learning-profile entries (`learning`), both ranked by the
|
|
5
|
+
// same shipped deterministic lexical scorer used by `search --ranked`. Read-only:
|
|
6
|
+
// reads the local corpus and `DESIGN_AI_LEARNING_FILE` learning profile, exactly
|
|
7
|
+
// as `design-ai learn --recall` does, and never writes either.
|
|
8
|
+
|
|
9
|
+
import { DESIGN_AI_HOME } from "../lib/paths.mjs";
|
|
10
|
+
import { buildLearnRecall, DEFAULT_RECALL_LIMIT } from "../lib/recall.mjs";
|
|
11
|
+
import { optionalInteger, optionalString, requireNonEmptyString, requireOptions } from "./validate.mjs";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Recall brief-relevant corpus knowledge and local learning-profile entries for
|
|
15
|
+
* a query. Pure, read-only adapter over `buildLearnRecall` from cli/lib/recall.mjs.
|
|
16
|
+
*
|
|
17
|
+
* @param {string} query - Recall query text.
|
|
18
|
+
* @param {{limit?: number, category?: string}} [opts]
|
|
19
|
+
* @returns {{corpus: object, learning: object}} combined recall view.
|
|
20
|
+
*/
|
|
21
|
+
export function recall(query, opts = {}) {
|
|
22
|
+
requireNonEmptyString(query, "query");
|
|
23
|
+
const options = requireOptions(opts, "recall");
|
|
24
|
+
|
|
25
|
+
const limit = optionalInteger(options.limit, "limit", { fallback: DEFAULT_RECALL_LIMIT, min: 1, max: 20 });
|
|
26
|
+
const category = optionalString(options.category, "category");
|
|
27
|
+
|
|
28
|
+
const result = buildLearnRecall({
|
|
29
|
+
query,
|
|
30
|
+
limit,
|
|
31
|
+
category,
|
|
32
|
+
designAiPath: DESIGN_AI_HOME,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
corpus: result.corpus,
|
|
37
|
+
learning: result.learning,
|
|
38
|
+
};
|
|
39
|
+
}
|