@design-ai/cli 4.59.0 → 4.61.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/docs/ROADMAP.md CHANGED
@@ -1,5 +1,100 @@
1
1
  # Roadmap
2
2
 
3
+ ## Phase 763 — Ranked-search Eval Checkpoint Release (v4.61.0) ✓ ready
4
+
5
+ Ships the FU-3 ranked-search eval checkpoint (Phase 762) as an npm version: `search --eval-template` / `search --eval [--strict]` over the shipped BM25 path, with the Korean particle-form regression cases in the default template. Additive and backward-compatible; default `search` behavior is unchanged. With this release the AI-learning Phase A follow-ups (FU-1–FU-4) are all closed and published.
6
+
7
+ ### Verified
8
+ - All 8 audits passed.
9
+ - `npm run release:check` (unit tests incl. search-eval and search-command suites, strict audits, whitespace, package contents, release metadata, release self-tests, packed-tarball smoke).
10
+ - `npm run release:metadata`.
11
+ - `git diff --check`.
12
+ - Main-branch GitHub Actions (`Design-AI audit`, `Deploy doc site`) passed for the constituent commits.
13
+
14
+ ### Versions
15
+ - `package.json` + `.claude-plugin/plugin.json`: 4.60.0 → 4.61.0.
16
+ - `vscode-extension/package.json`: remains 0.4.1.
17
+
18
+ ### What this enables
19
+ - The `--ranked` default-promotion decision becomes evidence-backed for npm users too: the published CLI carries the checkpoint tooling, so the eval can be re-run against any installed version — including Korean agglutinative-query regressions — before and after such a change.
20
+
21
+ ### What's still ahead
22
+ - The `--ranked` default-promotion decision itself (separate, evidence-backed call).
23
+ - Next-surface re-evaluation per the updated decision record in [NEXT-SURFACE-DECISION.md](NEXT-SURFACE-DECISION.md).
24
+
25
+ ## Phase 762 — Ranked-search eval checkpoint (FU-3, implemented, unreleased)
26
+
27
+ Closes the last open follow-up from the AI-learning Phase A review ([AI-LEARNING-PHASE2.md](AI-LEARNING-PHASE2.md), FU-3): `design-ai search` gains `--eval-template` / `--eval [--strict]` checkpoint modes mirroring the route/prompt/pack/learn eval pattern, run through the shipped ranked (BM25) search path. This is the standing evidence artifact for any future decision to promote `--ranked` to the default; with FU-1/FU-2/FU-4 already annotated done, all four Phase A follow-ups are now closed.
28
+
29
+ ### Delivered
30
+ - [x] `cli/lib/search-eval.mjs` — `SEARCH_EVAL_VERSION = 1`, `buildSearchEvalTemplate()`, `searchEvalReport()` over `rankedSearchCorpus`; route-style payload normalization and error messages. Case schema: `id`, `query`, optional `dirs`/`limit`, assertions `expectRelPathIn` / `minHits` / `matchedTokenIncludes`.
31
+ - [x] Default template includes the FU-1 Korean particle-form regression cases (`버튼`, `버튼을`, `접근성이`) plus three English cases — so the eval doubles as the retrieval-level Hangul-bigram regression. All six verified passing against the shipped corpus (`--strict` exit 0).
32
+ - [x] CLI wiring in `cli/lib/search.mjs` / `cli/commands/search.mjs` (`--eval-template`, `--eval`, `--strict`, `--from-file`, `--stdin`, mutual-exclusivity validation), help topic usage line, and the shared `smoke_assertions.py` pins (4 spots — shared constants, so both package and registry smokes stay aligned).
33
+ - [x] Tests: `search-eval.test.mjs` (template, pass/warn/fail reports, malformed payloads) and `search-command.test.mjs` (CLI-level, strict exit semantics). 578/578 total.
34
+ - [x] `docs/AI-LEARNING-PHASE2.md` FU-3 and FU-4 done annotations.
35
+
36
+ ### Remaining
37
+ - [ ] Release: bundle into the next npm version.
38
+ - [ ] The `--ranked` default-promotion decision itself — a future, separate call that this checkpoint now makes evidence-backed.
39
+
40
+ ## Phase 761 — Agent SDK types + Phase B Release (v4.60.0) ✓ ready
41
+
42
+ Ships the Agent SDK TypeScript declarations (Phase 759) and the `learn.*` local-write namespace (Phase 760) together as one npm version. Both are additive and backward-compatible: the eight Phase A verbs stay read-only and unchanged, and TypeScript types resolve automatically for `@design-ai/cli/sdk` with no build step on either side.
43
+
44
+ ### Verified
45
+ - All 8 audits passed.
46
+ - `npm run release:check` (unit tests incl. SDK type-sync guard and `learn.*` write tests, strict audits, whitespace, package contents, release metadata, release self-tests, packed-tarball smoke that imports `@design-ai/cli/sdk` and exercises `learn.remember`).
47
+ - `npm run release:metadata`.
48
+ - `git diff --check`.
49
+ - The declarations compile under `tsc --strict` against a real consumer (transient check; TypeScript is not a package dependency).
50
+ - Main-branch GitHub Actions (`Design-AI audit`, `Deploy doc site`) passed for the constituent commits.
51
+
52
+ ### Versions
53
+ - `package.json` + `.claude-plugin/plugin.json`: 4.59.0 → 4.60.0.
54
+ - `vscode-extension/package.json`: remains 0.4.1.
55
+
56
+ ### What this enables
57
+ - TypeScript/editor tooling resolves the full SDK surface (verbs, option interfaces, return types) with zero `@types` install and zero build step, and agents gain an explicit, opt-in `learn.*` write namespace for recording preferences, feedback, and check-derived learnings — while every read-only verb keeps its no-write guarantee.
58
+
59
+ ### What's still ahead
60
+ - SDK surface is feature-complete for the planned phases; further verbs are demand-driven. Remaining roadmap work returns to other surfaces (see later phases).
61
+
62
+ ## Phase 760 — Agent SDK Phase B (local writes, implemented, unreleased)
63
+
64
+ Adds the Phase B local-write surface described in [AGENT-SDK.md](AGENT-SDK.md#phase-b--explicit-local-writes-shipped): a single `learn` namespace export grouping three explicit, opt-in local-write verbs (`learn.remember`, `learn.feedback`, `learn.captureFromCheck`). This is the only place the SDK writes files; the 8 Phase A verbs are unchanged and stay read-only — `check()` in particular gets no capture option, so its read-only contract test still holds. Landed in `main` as `cli/sdk/learn-adapter.mjs`; code-complete and gated but not yet released as an npm version.
65
+
66
+ ### Delivered
67
+ - [x] `learn.remember(text, opts?)` — records a local learning-profile preference. Adapter over `rememberLearning` from `cli/lib/learn-profile.mjs`; always writes `source: "sdk"`.
68
+ - [x] `learn.feedback(text, opts?)` — records keep/avoid/improve feedback as a learning-profile entry. Adapter over `recordLearningFeedback`; the library normalizes `outcome` and folds it into the stored entry's `text` and `source`.
69
+ - [x] `learn.captureFromCheck(artifact, opts?)` — checks a Markdown artifact, then captures its non-pass results as learning-profile entries. Adapter over `checkArtifactContent` + `buildCheckLearningCapture` from `cli/lib/check.mjs` — the SDK equivalent of the CLI's `check --learn --yes`. Duplicate captures are skipped (`reason: "duplicate-entry-text"`).
70
+ - [x] All three write **only** the local learning profile (`DESIGN_AI_LEARNING_FILE` / `defaultLearningFile()`), never the network; no `filePath` or `now`/timestamp option on any of them — consumers target a profile via the env var, exactly like the CLI.
71
+ - [x] `learn` is a frozen object (`Object.freeze`); `cli/sdk/index.mjs` re-exports it alongside the 8 unchanged Phase A verbs.
72
+ - [x] Input validation reused from `cli/sdk/validate.mjs` (`requireNonEmptyString`, `requireOptions`, `optionalString`); `routeId` validated with the same `assertKnownRouteId` helper the read-only `check` adapter uses.
73
+ - [x] `cli/sdk/learn-adapter.test.mjs` — per-verb coverage: persistence (re-reading the written profile), `remember`'s `source: "sdk"`, `feedback`'s outcome-to-text/source mapping, `captureFromCheck`'s added/skipped results and duplicate-capture skip, and bad-input rejection. 16 new tests.
74
+ - [x] `cli/sdk/index.test.mjs` contract test updated: the 8 read-only function verbs are pinned unchanged; `learn` is pinned as a frozen object export with exactly `["captureFromCheck", "feedback", "remember"]`, plus return-shape keys for each verb (including the full `captureLearningEntries` result shape: `file, dryRun, applied, source, candidateCount, addedCount, skippedCount, count, entries, skipped`).
75
+ - [x] `cli/sdk/types.test.mjs` unchanged and passing (it filters to `typeof === "function"`, so the `learn` object export is naturally excluded); a new assertion added confirming `index.d.ts` declares `export declare const learn:`.
76
+ - [x] `cli/sdk/index.d.ts` — hand-written types for `LearnRememberOptions`, `LearnFeedbackOptions`, `LearnCaptureOptions`, `LearningProfileEntry`, `LearningProfile`, `RememberResult`, `CaptureSkippedEntry`, `CaptureResult`, and the `learn` const declaration. Verified to compile under `tsc --strict` against a transient consumer (zero-toolchain stance preserved — TypeScript is not added to `package.json`).
77
+ - [x] `docs/SDK.md` — "Phase B — local writes" section replaces the "not yet shipped" placeholder: full reference for all three verbs, options, return shapes, the `DESIGN_AI_LEARNING_FILE` target, and the write-boundary rationale.
78
+ - [x] `docs/AGENT-SDK.md` Phase B section updated from "only if demand" to shipped.
79
+ - [x] `npm test` (563/563), `npm run audit` (8/8), `npm run release:metadata` all pass.
80
+
81
+ ### Remaining
82
+ - [ ] Release decision: bundle Phase B into the next npm version alongside or after Phase 759's TypeScript declarations.
83
+ - [ ] Optional follow-up: extend the packed-tarball SDK smoke (`tools/audit/package-smoke.py`) to exercise `learn.remember` against a temp `DESIGN_AI_LEARNING_FILE`.
84
+
85
+ ## Phase 759 — Agent SDK TypeScript declarations (implemented, unreleased)
86
+
87
+ Ships hand-written type declarations for the eight SDK verbs so TypeScript and editor tooling resolve `@design-ai/cli/sdk` with full types — no `@types` package, no build step (the `.d.ts` is maintained by hand to preserve the zero-toolchain stance). Landed in `main` as `cli/sdk/index.d.ts`; additive (types only), pending bundling into the next npm version.
88
+
89
+ ### Delivered
90
+ - [x] `cli/sdk/index.d.ts` — precise signatures + return interfaces for all eight verbs (incl. `search` ranked/plain overloads, the `RouteConfidence` union, and optional `learningContext`/`recall`/`relatedKnowledge` fields), derived from the runtime shapes the contract test pins.
91
+ - [x] `exports` `types` condition (`"./sdk": { "types": …, "default": … }`) so the subpath resolves declarations under `moduleResolution: node16`/`nodenext`/`bundler`.
92
+ - [x] `cli/sdk/types.test.mjs` — zero-dependency guard asserting the `.d.ts` declares exactly the runtime-exported verbs (drift anchor). Declarations independently verified to compile under `tsc --strict` against a real consumer.
93
+ - [x] `docs/SDK.md` TypeScript section.
94
+
95
+ ### Remaining
96
+ - [ ] Release: bundle into the next npm version (with Phase B, or standalone).
97
+
3
98
  ## Phase 758 — Agent SDK Phase A Release (v4.59.0) ✓ ready
4
99
 
5
100
  Ships the Agent SDK Phase A work (Phase 757) as an npm version: the curated, semver-stable `@design-ai/cli/sdk` surface — eight read-only adapter verbs (`route`, `prompt`, `pack`, `search`, `recall`, `check`, `routes`, `version`) over the same `cli/lib` functions the CLI and MCP already call. No new capabilities, no runtime dependencies, no network, no telemetry; read-only, deterministic, backward-compatible.
@@ -19,7 +114,8 @@ Ships the Agent SDK Phase A work (Phase 757) as an npm version: the curated, sem
19
114
  - design-ai's routing, prompt/pack generation, ranked search, recall, and artifact checks become plain importable functions for agent runtimes, build scripts, and custom tools — deterministic, in-process, zero-dependency — behind a semver-stable contract that insulates callers from internal `cli/lib` refactors.
20
115
 
21
116
  ### What's still ahead
22
- - Optional `cli/sdk/index.d.ts` hand-written type declarations (zero-build), and Phase B explicit local-write adapters — both deferred until an adopter needs them.
117
+ - Phase B explicit local-write adapters (`learn.remember`/`feedback`, capture) implemented and landed in `main` (see Phase 760); pending release.
118
+ - Hand-written `cli/sdk/index.d.ts` TypeScript declarations shipped after this release (see Phase 759).
23
119
 
24
120
  ## Phase 757 — Agent SDK (Phase A implemented, unreleased)
25
121
 
package/docs/SDK.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # Agent SDK reference
2
2
 
3
- > Status: shipped (Phase A) — read-only verbs, semver-stable surface
3
+ > Status: shipped (Phase A + Phase B) — 8 read-only verbs plus the opt-in `learn.*` local-write namespace, semver-stable surface
4
4
 
5
5
  `@design-ai/cli/sdk` lets an external Node.js program — an agent runtime, a build script, a custom tool — use design-ai's deterministic design capabilities as importable functions, without shelling out to the CLI or spawning the MCP server. It is a thin, curated adapter over the same `cli/lib` functions the CLI and MCP server already call, so a capability that ships in the CLI is instantly available to an SDK consumer.
6
6
 
7
- See [`AGENT-SDK.md`](AGENT-SDK.md) for the full design rationale, phased plan, and open questions. This page is the public reference for the shipped Phase A surface.
7
+ See [`AGENT-SDK.md`](AGENT-SDK.md) for the full design rationale, phased plan, and open questions. This page is the public reference for the shipped Phase A (read-only) and Phase B (local-write) surface.
8
8
 
9
9
  ## Install and import
10
10
 
@@ -20,6 +20,16 @@ import { route, prompt, pack, search, recall, check, routes, version } from "@de
20
20
 
21
21
  Only the `./sdk` subpath is exported — `import "@design-ai/cli"` (the bare package root) is intentionally not exported, so importing the SDK is always an explicit `@design-ai/cli/sdk` import. `cli/lib/*` is internal and unstable; do not import it directly.
22
22
 
23
+ ### TypeScript
24
+
25
+ Hand-written type declarations ship with the package at `cli/sdk/index.d.ts` and are wired through the `exports` `types` condition, so TypeScript and editors resolve them automatically for `@design-ai/cli/sdk` — no `@types` install, and no build step on our side (the declarations are maintained by hand to preserve the zero-toolchain stance). Use `moduleResolution: node16`/`nodenext` (or `bundler`) so the subpath `types` condition is honored. All exported types (`RouteResult`, `PromptPlan`, `Pack`, `SearchHit`, `RankedSearchHit`, `RecallResult`, `CheckReport`, option interfaces, …) are importable:
26
+
27
+ ```ts
28
+ import { route, type RouteResult, type SearchOptions } from "@design-ai/cli/sdk";
29
+ ```
30
+
31
+ A `node --test` guard (`cli/sdk/types.test.mjs`) asserts the declaration file stays in exact sync with the runtime exports.
32
+
23
33
  ## Phase A: read-only
24
34
 
25
35
  Every verb below is a pure, read-only adapter:
@@ -57,7 +67,7 @@ prompt(brief: string, opts?: {
57
67
  learningLimit?: number,
58
68
  withRecall?: boolean,
59
69
  recallLimit?: number,
60
- }): PromptPlan | null
70
+ }): PromptPlan
61
71
  ```
62
72
 
63
73
  - `routeId` — force a route id instead of scoring the brief.
@@ -153,10 +163,87 @@ version(): { cli: string, corpus: string }
153
163
 
154
164
  - Additive changes (new optional fields, new opt-in options) are minor version bumps.
155
165
  - Signature or return-shape changes are major version bumps.
156
- - The 8 exported names (`route`, `prompt`, `pack`, `search`, `recall`, `check`, `routes`, `version`) and their return-shape key sets are pinned by an SDK contract test (`cli/sdk/index.test.mjs`) — this is the semver anchor. If a name or a top-level key drifts unintentionally, that test fails.
166
+ - The 8 read-only function exports (`route`, `prompt`, `pack`, `search`, `recall`, `check`, `routes`, `version`) plus the frozen `learn` namespace object (`learn.remember`, `learn.feedback`, `learn.captureFromCheck`) and their return-shape key sets are pinned by an SDK contract test (`cli/sdk/index.test.mjs`) — this is the semver anchor. If a name or a top-level key drifts unintentionally, that test fails.
157
167
  - `cli/lib/*` remains internal and unstable. Only `@design-ai/cli/sdk` is a supported import path.
158
168
  - Determinism: the same inputs always produce the same outputs, with no randomness or time-dependence added by the adapter layer.
159
169
 
160
- ## Phase B (not yet shipped)
170
+ ## Phase B local writes
171
+
172
+ Phase A (above) is read-only by design: the 8 verbs never write a file. Phase B adds a single namespace export, `learn`, grouping the three explicit, opt-in **LOCAL-WRITE** verbs. This is the only place the SDK writes files — every Phase A verb stays read-only and unchanged.
173
+
174
+ ```js
175
+ import { learn } from "@design-ai/cli/sdk";
176
+
177
+ learn.remember(text, opts?) // opts: { category?: string }
178
+ learn.feedback(text, opts?) // opts: { outcome?: string, category?: string }
179
+ learn.captureFromCheck(artifact, opts?) // opts: { routeId?: string }
180
+ ```
181
+
182
+ **Write boundary rationale:** an SDK consumer should never be surprised by a file write. Phase A's 8 verbs are safe to call from any context — a build script, a read path, a CI check — with zero side effects. `learn.*` is the deliberate, narrow exception: three verbs, one destination, no ambiguity about what gets written or where.
183
+
184
+ All three verbs write **only** the local learning profile — `DESIGN_AI_LEARNING_FILE` if set, otherwise the CLI's `defaultLearningFile()` default path — and never touch the network. There is no `filePath` option and no `now`/timestamp option on any of them: target a specific profile the same way the CLI does, by setting the `DESIGN_AI_LEARNING_FILE` environment variable before calling. The underlying library functions supply their own defaults (the env var and `new Date()`).
185
+
186
+ ### `learn.remember(text, opts)`
187
+
188
+ Record a local learning-profile preference. Adapter over `rememberLearning` from `cli/lib/learn-profile.mjs`.
189
+
190
+ ```js
191
+ learn.remember(text: string, opts?: { category?: string }): RememberResult
192
+ ```
193
+
194
+ - `text` — required, non-empty string.
195
+ - `category` — one of the learning-profile categories (e.g. `preference`, `brand`, `workflow`, `constraint`, `accessibility`, `korean`, `other`); the library normalizes and validates it. Default: `"preference"`.
196
+
197
+ Returns a `RememberResult`: `{ file, entry, profile }`, where `entry` is `{ id, category, text, source, createdAt }` (`source` is always `"sdk"`) and `profile` is the full updated learning profile `{ version, updatedAt, entries }`.
198
+
199
+ ### `learn.feedback(text, opts)`
200
+
201
+ Record feedback (keep/avoid/improve) as a local learning-profile entry. Adapter over `recordLearningFeedback` from `cli/lib/learn-profile.mjs`.
202
+
203
+ ```js
204
+ learn.feedback(text: string, opts?: { outcome?: string, category?: string }): RememberResult
205
+ ```
206
+
207
+ - `text` — required, non-empty string.
208
+ - `outcome` — any string; the library normalizes it (`normalizeFeedbackOutcome`) to one of `keep` / `avoid` / `improve` and folds it into both the stored entry's `text` (e.g. `"Avoid in future outputs: …"`) and its `source` (e.g. `"feedback:avoid"`). Default: `"improve"`.
209
+ - `category` — same category enum as `remember`. Default: `"workflow"`.
210
+
211
+ Returns the same `RememberResult` shape as `learn.remember`.
212
+
213
+ ### `learn.captureFromCheck(artifact, opts)`
214
+
215
+ Check a Markdown artifact, then capture its non-pass results as local learning-profile entries — the SDK equivalent of the CLI's `check --learn --yes`. Adapter over `checkArtifactContent` + `buildCheckLearningCapture` from `cli/lib/check.mjs`.
216
+
217
+ ```js
218
+ learn.captureFromCheck(artifact: string, opts?: { routeId?: string }): CaptureResult
219
+ ```
220
+
221
+ - `artifact` — required, non-empty Markdown string.
222
+ - `routeId` — add route-specific check requirements before capturing; must be a known route id (validated with the same `assertKnownRouteId` helper the read-only `check` adapter uses).
223
+
224
+ Returns a `CaptureResult` — the `captureLearningEntries` return shape:
225
+
226
+ ```
227
+ {
228
+ file: string, // the learning profile file written to
229
+ dryRun: false, // always false; captureFromCheck always applies
230
+ applied: true, // always true when dryRun is false
231
+ source: string, // "check:<routeId>" or "check:artifact"
232
+ candidateCount: number, // non-pass check results considered
233
+ addedCount: number, // entries newly written
234
+ skippedCount: number, // entries skipped as duplicates of existing entries
235
+ count: number, // total entries in the profile after this call
236
+ entries: LearningProfileEntry[], // the entries that were added
237
+ skipped: Array<{ category, text, source, reason }>, // reason is "duplicate-entry-text"
238
+ }
239
+ ```
240
+
241
+ Calling `captureFromCheck` twice with the same artifact adds nothing the second time — every candidate is skipped with `reason: "duplicate-entry-text"`.
242
+
243
+ ### Validation
244
+
245
+ All three verbs use the same `cli/sdk/validate.mjs` helpers as Phase A: `requireNonEmptyString` for `text`/`artifact`, `requireOptions` for the options bag, and `optionalString` for string options. `routeId` is validated with `assertKnownRouteId`, exactly like the read-only `check` adapter. Bad input throws a plain `Error` with a clear message — no process exit code, no silent fallback.
246
+
247
+ ### What stays unchanged
161
248
 
162
- Phase A is read-only by design. A future Phase B may add opt-in, explicit local-write adapters mirroring the CLI's local-write commands (`learn.remember`, `learn.feedback`, `check` with capture) deferred until an adopter needs it. See [`AGENT-SDK.md`](AGENT-SDK.md#phase-b-optional-explicit-local-writes) for the current plan.
249
+ `check()` (the Phase A read-only verb) is untouched: it still never writes, and it has no capture option. Capture is exclusively reached through `learn.captureFromCheck`, which is a separate, explicitly-named write verb this keeps the read/write boundary visible at the call site rather than hidden behind an option flag on a read-only function.
@@ -1,22 +1,22 @@
1
1
  # External Publication Status
2
2
 
3
- > Checked: 2026-07-04
3
+ > Checked: 2026-07-05
4
4
  > Scope: npm registry, GitHub Pages, Homebrew tap, VS Code Marketplace, Claude/Codex MCP
5
5
 
6
6
  ## Summary
7
7
 
8
- npm is publicly published at `@design-ai/cli@4.58.0` (npm dist-tag `latest` = `4.58.0`); publish run from tag `v4.58.0` succeeded with provenance and all pre-publish gates green. After fixing the remaining stale learn-relevance score-type assertions in `tools/audit/registry-smoke.py` (`16e97aa`), the live `npm run registry:smoke` passes cleanly against published `@design-ai/cli@4.58.0` ("Registry smoke passed"), covering the retrieval surfaces (index/ranked/embeddings/recall) and route enrichment. GitHub Release `v4.58.0` is published, and the Homebrew tap formula points at the `v4.58.0` release source tarball with a verified SHA-256. The VS Code extension `sungjin.design-ai-vscode` remains published at `0.4.1`. GitHub Pages docs are publicly reachable.
8
+ npm is publicly published at `@design-ai/cli@4.60.0` (npm dist-tag `latest` = `4.60.0`); publish run from tag `v4.60.0` succeeded with provenance and all pre-publish gates green. This release extends the Agent SDK (`@design-ai/cli/sdk`) with shipped TypeScript declarations (via an `exports` `types` condition) and the opt-in `learn.*` local-write namespace; the eight read-only verbs are unchanged, so CLI output is unchanged. The live `npm run registry:smoke` passes cleanly against published `@design-ai/cli@4.60.0` ("Registry smoke passed"), covering the retrieval surfaces (index/ranked/embeddings/recall) and route enrichment. GitHub Release `v4.60.0` is published, and the Homebrew tap formula points at the `v4.60.0` release source tarball with a verified SHA-256. The VS Code extension `sungjin.design-ai-vscode` remains published at `0.4.1`. GitHub Pages docs are publicly reachable.
9
9
 
10
10
  ## Results
11
11
 
12
12
  | Surface | Checked target | Result | Evidence |
13
13
  |---|---|---|---|
14
- | npm registry | `@design-ai/cli` | Published latest is `4.58.0` (tag `v4.58.0`, provenance). Pre-publish packed-tarball smoke and post-fix live `npm run registry:smoke` both pass for `@design-ai/cli@4.58.0`. | `npm view @design-ai/cli version` → `4.58.0`; live registry smoke "Registry smoke passed" |
14
+ | npm registry | `@design-ai/cli` | Published latest is `4.60.0` (tag `v4.60.0`, provenance). Pre-publish packed-tarball smoke (incl. SDK import + `learn.remember` write) and live `npm run registry:smoke` both pass for `@design-ai/cli@4.60.0`. | `npm view @design-ai/cli version` → `4.60.0`; live registry smoke "Registry smoke passed" |
15
15
  | GitHub Pages | `https://sungjin9288.github.io/design-ai/` | Published and reachable: HTTP `200`, design-ai MkDocs page rendered | `evidence/cli-logs/github-pages-status.log` |
16
- | Homebrew tap | `Formula/design-ai.rb` | Formula pinned to `v4.58.0` release source tarball with SHA-256 `45ec7fa4e82e7af38cdf948e1ad056a3758be848e5541013144e8d93d4c9da37` (recomputed from the published tag tarball) | `Formula/design-ai.rb` |
16
+ | Homebrew tap | `Formula/design-ai.rb` | Formula pinned to `v4.60.0` release source tarball with SHA-256 `fa34af51c32d8e59dba4c1d293746688820e85ae03efa3b0bae4f3b3b2a34583` (recomputed from the published tag tarball) | `Formula/design-ai.rb` |
17
17
  | VS Code Marketplace | `sungjin.design-ai-vscode` | Published: run `28431571256` published `v0.4.1`, and the Marketplace Gallery API returned visible version `0.4.1` on 2026-07-02. | `evidence/cli-logs/vscode-marketplace-status.log`, `evidence/cli-logs/vscode-marketplace-secret-status.log`, `evidence/cli-logs/vscode-extension-vsce-package.log`, `evidence/cli-logs/vscode-publish-workflow-status.log` |
18
- | GitHub Release | `v4.58.0` | Published for tag `v4.58.0` at commit `22dc8a9` | `gh release view v4.58.0` |
19
- | MCP server | `@design-ai/cli@4.58.0` / local clone | Public npm `design-ai-mcp` responds to initialize and tools/list with 10 tools; local Codex and Claude Code both report `design-ai` MCP as configured and connected. | `evidence/cli-logs/npm-registry-smoke.log`, `evidence/cli-logs/design-ai-mcp-client-status.log` |
18
+ | GitHub Release | `v4.60.0` | Published for tag `v4.60.0` at commit `2d73c42` | `gh release view v4.60.0` |
19
+ | MCP server | `@design-ai/cli@4.60.0` / local clone | Public npm `design-ai-mcp` responds to initialize and tools/list with 10 tools; local Codex and Claude Code both report `design-ai` MCP as configured and connected. | `evidence/cli-logs/npm-registry-smoke.log`, `evidence/cli-logs/design-ai-mcp-client-status.log` |
20
20
 
21
21
  ## Interpretation
22
22
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@design-ai/cli",
3
- "version": "4.59.0",
3
+ "version": "4.61.0",
4
4
  "description": "Senior product designer for any AI coding agent. Installs design-ai (20 skills, 17 commands, 4 agents) into Claude Code globally. Korean market depth plus website improvement control tower.",
5
5
  "bin": {
6
6
  "design-ai": "cli/bin/design-ai.mjs",
@@ -8,7 +8,10 @@
8
8
  },
9
9
  "type": "module",
10
10
  "exports": {
11
- "./sdk": "./cli/sdk/index.mjs",
11
+ "./sdk": {
12
+ "types": "./cli/sdk/index.d.ts",
13
+ "default": "./cli/sdk/index.mjs"
14
+ },
12
15
  "./package.json": "./package.json"
13
16
  },
14
17
  "engines": {
@@ -763,15 +763,20 @@ def assert_version_json_smoke(cmd: list[str], *, env: dict[str, str], cwd: Path
763
763
  assert_version_json(result.stdout, context=context, cmd=cmd)
764
764
 
765
765
 
766
- # Phase A Agent SDK packed-tarball smoke (docs/AGENT-SDK.md, docs/SDK.md): imports
766
+ # Agent SDK packed-tarball smoke (docs/AGENT-SDK.md, docs/SDK.md): imports
767
767
  # `@design-ai/cli/sdk` from the installed package (proving the package.json
768
768
  # "exports" map resolves) and exercises route/search(ranked)/recall, asserting
769
769
  # each call is deterministic (same input -> same JSON-serialized output) and
770
770
  # that Phase A's read-only contract holds (prompt/pack never include
771
- # learningUsage). This is a Node script, not a design-ai CLI invocation, so it
772
- # is run directly rather than through npm_exec_cmd/design-ai bin helpers.
771
+ # learningUsage). Also exercises Phase B's `learn.remember` against a temp
772
+ # DESIGN_AI_LEARNING_FILE and asserts it actually wrote the profile. This is a
773
+ # Node script, not a design-ai CLI invocation, so it is run directly rather
774
+ # than through npm_exec_cmd/design-ai bin helpers.
773
775
  SDK_SMOKE_SCRIPT = """
774
- import { check, pack, prompt, recall, route, routes, search, version } from "@design-ai/cli/sdk";
776
+ import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
777
+ import { tmpdir } from "node:os";
778
+ import path from "node:path";
779
+ import { check, learn, pack, prompt, recall, route, routes, search, version } from "@design-ai/cli/sdk";
775
780
 
776
781
  const brief = "Spec a Button component API with variants, props, and keyboard accessibility";
777
782
 
@@ -808,6 +813,23 @@ const ck = check(
808
813
  );
809
814
  if (typeof ck.status !== "string") throw new Error("check() bad shape");
810
815
 
816
+ // Phase B: learn.remember must write only DESIGN_AI_LEARNING_FILE.
817
+ const smokeDir = mkdtempSync(path.join(tmpdir(), "design-ai-sdk-learn-smoke-"));
818
+ const learningFile = path.join(smokeDir, "learning.json");
819
+ process.env.DESIGN_AI_LEARNING_FILE = learningFile;
820
+ try {
821
+ const result = learn.remember("Package smoke: prefer 8px spacing grid.", { category: "preference" });
822
+ if (result.entry.source !== "sdk") throw new Error("learn.remember() entry.source must be 'sdk'");
823
+ if (!existsSync(learningFile)) throw new Error("learn.remember() did not write DESIGN_AI_LEARNING_FILE");
824
+ const onDisk = JSON.parse(readFileSync(learningFile, "utf8"));
825
+ if (!Array.isArray(onDisk.entries) || onDisk.entries.length !== 1) {
826
+ throw new Error("learn.remember() did not persist exactly one entry");
827
+ }
828
+ } finally {
829
+ rmSync(smokeDir, { recursive: true, force: true });
830
+ delete process.env.DESIGN_AI_LEARNING_FILE;
831
+ }
832
+
811
833
  console.log("design-ai sdk smoke passed");
812
834
  """.strip()
813
835
 
@@ -160,7 +160,7 @@ EXPECTED_HELP_TOPIC_USAGES = {
160
160
  "uninstall": "design-ai uninstall [--json]",
161
161
  "status": "design-ai status [--json]",
162
162
  "list": "design-ai list [skills|commands|agents] [--json]",
163
- "search": "design-ai search <query> [--dir kind] [--limit N] [--ranked] [--embeddings [--provider \"cmd args\"]] [--json]",
163
+ "search": "design-ai search <query|--eval-template|--eval> [--dir kind] [--limit N] [--ranked] [--embeddings [--provider \"cmd args\"]] [--strict] [--json]",
164
164
  "index": "design-ai index [--build|--status|--verify] [--json] [--embeddings [--provider \"cmd args\"]]",
165
165
  "show": "design-ai show <file[:line]> [--lines N:M] [--context N] [--json]",
166
166
  "route": "design-ai route <brief|--from-file file|--stdin|--list|--eval-template|--eval> [--limit N]",
@@ -184,7 +184,12 @@ EXPECTED_HELP_TOPIC_FRAGMENTS = {
184
184
  "uninstall": ("Usage:", "design-ai uninstall [--json]"),
185
185
  "status": ("Usage:", "design-ai status [--json]"),
186
186
  "list": ("Usage:", "design-ai list [skills|commands|agents]"),
187
- "search": ("Usage:", "design-ai search <query> [--limit N] [--dir kind] [--ranked] [--embeddings [--provider \"cmd args\"]] [--json]"),
187
+ "search": (
188
+ "Usage:",
189
+ "design-ai search <query> [--limit N] [--dir kind] [--ranked] [--embeddings [--provider \"cmd args\"]] [--json]",
190
+ "design-ai search --eval-template [--json]",
191
+ "design-ai search --eval --from-file search-eval.json [--strict] [--json]",
192
+ ),
188
193
  "index": ("Usage:", "design-ai index [--build|--status|--verify] [--json] [--embeddings [--provider \"cmd args\"]]"),
189
194
  "show": ("Usage:", "design-ai show <file[:line|start-end]> [--lines N:M] [--context N] [--json]"),
190
195
  "route": ("Usage:", "design-ai route <brief>", "design-ai route --list [--json]", "design-ai route --eval-template [--json]"),
@@ -364,7 +369,7 @@ EXPECTED_MAIN_HELP_FRAGMENTS = (
364
369
  "Usage: design-ai <command> [args]",
365
370
  "design-ai help [command|--json]",
366
371
  "install",
367
- "search <query>",
372
+ "search <query|--eval-template|--eval>",
368
373
  "show <file[:line]>",
369
374
  "route <brief|--from-file file|--stdin|--list|--eval-template|--eval>",
370
375
  "improve homepage conversion and SEO",
@@ -4669,8 +4674,8 @@ def passing_main_help_output() -> str:
4669
4674
  " design-ai help [command|--json]",
4670
4675
  "",
4671
4676
  " install Symlink design-ai into Claude Code (~/.claude)",
4672
- " search <query> [--dir kind] [--limit N] [--ranked] [--embeddings [--provider \"cmd args\"]] [--json]",
4673
- " Search the local markdown corpus",
4677
+ " search <query|--eval-template|--eval> [--dir kind] [--limit N] [--ranked] [--embeddings [--provider \"cmd args\"]] [--strict] [--json]",
4678
+ " Search the local markdown corpus and ranked-search eval checkpoints",
4674
4679
  " index [--build|--status|--verify] [--json] [--embeddings [--provider \"cmd args\"]]",
4675
4680
  " Build, inspect, and verify the local retrieval index",
4676
4681
  " show <file[:line]> [--lines N:M] [--context N] [--json] Print a corpus file or line range",