@vpxa/aikit 0.1.160 → 0.1.161
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/package.json +2 -1
- package/packages/blocks-core/dist/index.d.ts +2 -1
- package/packages/blocks-core/dist/index.js +22 -23
- package/packages/present/dist/index.html +19 -20
- package/packages/server/dist/index.js +1 -1
- package/packages/server/dist/{server-DKj9yfXg.js → server--D-DJ9_g.js} +41 -41
- package/packages/server/viewers/architecture-static.html +877 -0
- package/packages/server/viewers/c4-viewer.html +79 -0
- package/packages/server/viewers/canvas.html +1361 -0
- package/packages/server/viewers/process-flow-static.html +764 -0
- package/packages/server/viewers/report-template.html +724 -0
- package/packages/server/viewers/task-plan-static.html +1081 -0
- package/packages/server/viewers/tour-viewer.html +764 -0
- package/packages/store/dist/index.js +1 -1
- package/scaffold/dist/definitions/bodies.mjs +7 -0
- package/scaffold/dist/definitions/flows.mjs +13 -0
- package/scaffold/dist/definitions/skills/present.mjs +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{createRequire as e}from"node:module";import{existsSync as t,mkdirSync as n,readFileSync as r,renameSync as i,unlinkSync as a,writeFileSync as o}from"node:fs";import{dirname as s,join as c}from"node:path";import{AIKIT_PATHS as l,EMBEDDING_DEFAULTS as u,SEARCH_DEFAULTS as d,STORE_DEFAULTS as f,createLogger as p,serializeError as m,sourceTypeContentTypes as h}from"../../core/dist/index.js";var g=e(import.meta.url);const _=p(`sqlite-adapter`),v=e(import.meta.url);var y=class{type=`better-sqlite3`;vectorCapable=!1;db=null;stmtCache=new Map;dbPath=``;DatabaseCtor=null;recovering=!1;async open(e){let t;try{t=v(`better-sqlite3`)}catch(e){throw Error(`better-sqlite3 native binding unavailable: ${e instanceof Error?e.message:String(e)}`)}this.db=new t(e),this.dbPath=e,this.DatabaseCtor=t,this.db.pragma(`journal_mode = WAL`),this.db.pragma(`foreign_keys = ON`),this.db.pragma(`synchronous = NORMAL`),this.runIntegrityCheck(e,t)||(this.db?.pragma(`journal_mode = WAL`),this.db?.pragma(`foreign_keys = ON`),this.db?.pragma(`synchronous = NORMAL`));try{v(`sqlite-vec`).load(this.db),this.vectorCapable=!0,_.info(`sqlite-vec extension loaded`)}catch(e){this.vectorCapable=!1,_.warn(`sqlite-vec extension failed to load; vector search disabled`,m(e))}}exec(e){try{this.getDb().exec(e)}catch(t){if(this.isCorruptionError(t)){this.recover(),this.getDb().exec(e);return}throw t}}pragma(e){this.getDb().pragma(e)}queryAll(e,t=[]){try{let n=this.prepareCached(e);return t.length>0?n.all(...t):n.all()}catch(n){if(this.isCorruptionError(n))return this.recover(),this.queryAll(e,t);throw n}}run(e,t=[]){try{let n=this.prepareCached(e);t.length>0?n.run(...t):n.run()}catch(n){if(this.isCorruptionError(n)){this.recover(),this.run(e,t);return}throw n}}flush(){}close(){this.db&&=(this.stmtCache.clear(),this.db.close(),null)}runIntegrityCheck(e,t){try{let t=this.db?.pragma(`integrity_check`);if(t.length===1&&t[0]?.integrity_check===`ok`)return!0;let n=t.map(e=>e.integrity_check).slice(0,5).join(`; `);_.warn(`Database integrity check failed — recreating`,{dbPath:e,issues:n})}catch(t){_.warn(`Integrity check query failed — recreating database`,{dbPath:e,error:m(t)})}try{this.db?.close()}catch{}this.db=null,this.stmtCache.clear();try{a(e)}catch{}try{a(`${e}-wal`)}catch{}try{a(`${e}-shm`)}catch{}return this.db=new t(e),_.info(`Database recreated successfully — full reindex required`,{dbPath:e}),!1}isCorruptionError(e){if(this.recovering)return!1;let t=e instanceof Error?e.message:String(e);return/database disk image is malformed|file is not a database|database or disk is full/.test(t)}recover(){if(this.recovering)throw Error(`BetterSqlite3Adapter: recovery already in progress`);this.recovering=!0;try{_.warn(`Runtime corruption detected — recovering database`,{dbPath:this.dbPath});try{this.db?.close()}catch{}this.db=null,this.stmtCache.clear();try{a(this.dbPath)}catch{}try{a(`${this.dbPath}-wal`)}catch{}try{a(`${this.dbPath}-shm`)}catch{}this.db=this.DatabaseCtor(this.dbPath),this.db.pragma(`journal_mode = WAL`),this.db.pragma(`foreign_keys = ON`),this.db.pragma(`synchronous = NORMAL`);try{v(`sqlite-vec`).load(this.db),this.vectorCapable=!0}catch{this.vectorCapable=!1}_.info(`Database recovered — full reindex required`,{dbPath:this.dbPath})}finally{this.recovering=!1}}getDb(){if(!this.db)throw Error(`BetterSqlite3Adapter: database not opened`);return this.db}prepareCached(e){let t=this.stmtCache.get(e);if(t)return t;let n=this.getDb().prepare(e);return this.stmtCache.set(e,n),n}};function b(e){return v.resolve(`sql.js/dist/${e}`)}var x=class{type=`sql.js`;vectorCapable=!1;db=null;dbPath=``;dirty=!1;inTransaction=!1;async open(e){this.dbPath=e;let n=(await import(`sql.js`)).default,i=await n({locateFile:e=>b(e)});if(t(e)){let t=r(e);this.db=new i.Database(t)}else this.db=new i.Database}exec(e){let t=e.trimStart().toUpperCase();this.getDb().run(e),t.startsWith(`BEGIN`)?this.inTransaction=!0:(t.startsWith(`COMMIT`)||t.startsWith(`ROLLBACK`))&&(this.inTransaction=!1),this.dirty=!0}pragma(e){this.getDb().exec(`PRAGMA ${e}`)}queryAll(e,t=[]){let n=this.getDb().prepare(e);try{t.length>0&&n.bind(t);let e=[];for(;n.step();)e.push(n.getAsObject());return e}finally{n.free()}}run(e,t=[]){let n=this.getDb(),r=e.trimStart().toUpperCase(),i=!this.inTransaction&&(r.startsWith(`INSERT`)||r.startsWith(`UPDATE`));i&&n.run(`SAVEPOINT fk_check`);try{if(t.length>0){let r=n.prepare(e);try{r.bind(t),r.step()}finally{r.free()}}else n.run(e);if(i){if(n.exec(`PRAGMA foreign_key_check`).length>0)throw n.run(`ROLLBACK TO fk_check`),n.run(`RELEASE fk_check`),Error(`FOREIGN KEY constraint failed`);n.run(`RELEASE fk_check`)}}catch(e){if(i)try{n.run(`ROLLBACK TO fk_check`),n.run(`RELEASE fk_check`)}catch{}throw e}this.dirty=!0}flush(){if(!this.dirty||!this.db)return;let e=this.db.export(),r=`${this.dbPath}.tmp`,a=s(this.dbPath);a&&!t(a)&&n(a,{recursive:!0}),o(r,Buffer.from(e)),i(r,this.dbPath),this.dirty=!1}close(){if(this.db){let e=this.db,t;try{this.flush()}catch(e){t=e;try{a(`${this.dbPath}.tmp`)}catch{}}try{e.close()}finally{this.db=null}if(t)throw t}}getDb(){if(!this.db)throw Error(`SqlJsAdapter: database not opened`);return this.db}};async function S(){try{let{execSync:e}=await import(`node:child_process`),{createRequire:t}=await import(`node:module`),n=t(import.meta.url).resolve(`better-sqlite3/package.json`).replace(/[\\/]package\.json$/,``).replace(/[\\/]node_modules[\\/]better-sqlite3$/,``);return _.info(`Attempting native module rebuild for better-sqlite3`,{cwd:n}),e(`npm rebuild better-sqlite3`,{cwd:n,stdio:`pipe`,timeout:6e4}),_.info(`Native module rebuild completed successfully`),!0}catch(e){return _.warn(`Native module rebuild failed — continuing with sql.js fallback`,m(e)),!1}}let C=!1;async function w(e){let t=new y;try{return await t.open(e),t}catch(t){let n=t instanceof Error?t.message:String(t);if(/NODE_MODULE_VERSION|Could not locate the bindings file|no native build was found/.test(n)&&await S()){let t=new y;try{return await t.open(e),_.info(`better-sqlite3 recovered after native module rebuild`),t}catch{}}C||(C=!0,_.warn(`[aikit] better-sqlite3 unavailable — falling back to sql.js (vector search disabled). Reinstall with prebuild support or rebuild from source to enable vector search.`,m(t)))}let n=new x;try{return await n.open(e),n}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`[aikit] SQLite adapter "sql.js" failed to load: ${t}`)}}async function T(e){let t=new x;return await t.open(e),t}var E=class{adapter=null;reopenPromise=null;dbPath;externalAdapter;constructor(e={}){if(e.adapter)this.adapter=e.adapter,this.externalAdapter=!0,this.dbPath=``;else{let t=e.path??l.data;this.dbPath=c(t,`graph.db`),this.externalAdapter=!1}}async initialize(){if(this.externalAdapter){let e=this.getAdapter();this.createTables(e),this.migrateSchema(e),e.flush();return}let e=s(this.dbPath);t(e)||n(e,{recursive:!0}),this.adapter=await w(this.dbPath),this.configureAdapter(this.adapter),this.createTables(this.adapter),this.migrateSchema(this.adapter),this.adapter.flush()}configureAdapter(e){e.pragma(`journal_mode = WAL`),e.pragma(`foreign_keys = ON`)}createTables(e){e.exec(`
|
|
1
|
+
import{createRequire as e}from"node:module";import{existsSync as t,mkdirSync as n,readFileSync as r,renameSync as i,unlinkSync as a,writeFileSync as o}from"node:fs";import{dirname as s,join as c}from"node:path";import{AIKIT_PATHS as l,EMBEDDING_DEFAULTS as u,SEARCH_DEFAULTS as d,STORE_DEFAULTS as f,createLogger as p,serializeError as m,sourceTypeContentTypes as h}from"../../core/dist/index.js";var g=e(import.meta.url);const _=p(`sqlite-adapter`),v=e(import.meta.url);var y=class{type=`better-sqlite3`;vectorCapable=!1;db=null;stmtCache=new Map;dbPath=``;DatabaseCtor=null;recovering=!1;async open(e){let t;try{t=v(`better-sqlite3`)}catch(e){throw Error(`better-sqlite3 native binding unavailable: ${e instanceof Error?e.message:String(e)}`)}this.db=new t(e),this.dbPath=e,this.DatabaseCtor=t,this.db.pragma(`journal_mode = WAL`),this.db.pragma(`foreign_keys = ON`),this.db.pragma(`synchronous = NORMAL`),this.runIntegrityCheck(e,t)||(this.db?.pragma(`journal_mode = WAL`),this.db?.pragma(`foreign_keys = ON`),this.db?.pragma(`synchronous = NORMAL`));try{v(`sqlite-vec`).load(this.db),this.vectorCapable=!0,_.info(`sqlite-vec extension loaded`)}catch(e){this.vectorCapable=!1,_.warn(`sqlite-vec extension failed to load; vector search disabled`,m(e))}}exec(e){try{this.getDb().exec(e)}catch(t){if(this.isCorruptionError(t)){this.recover(),this.getDb().exec(e);return}throw t}}pragma(e){this.getDb().pragma(e)}queryAll(e,t=[]){try{let n=this.prepareCached(e);return t.length>0?n.all(...t):n.all()}catch(n){if(this.isCorruptionError(n))return this.recover(),this.queryAll(e,t);throw n}}run(e,t=[]){try{let n=this.prepareCached(e);t.length>0?n.run(...t):n.run()}catch(n){if(this.isCorruptionError(n)){this.recover(),this.run(e,t);return}throw n}}flush(){}close(){this.db&&=(this.stmtCache.clear(),this.db.close(),null)}runIntegrityCheck(e,t){try{let t=this.db?.pragma(`integrity_check`);if(t.length===1&&t[0]?.integrity_check===`ok`)return!0;let n=t.map(e=>e.integrity_check).slice(0,5).join(`; `);_.warn(`Database integrity check failed — recreating`,{dbPath:e,issues:n})}catch(t){_.warn(`Integrity check query failed — recreating database`,{dbPath:e,error:m(t)})}try{this.db?.close()}catch{}this.db=null,this.stmtCache.clear();try{a(e)}catch{}try{a(`${e}-wal`)}catch{}try{a(`${e}-shm`)}catch{}return this.db=new t(e),_.info(`Database recreated successfully — full reindex required`,{dbPath:e}),!1}isCorruptionError(e){if(this.recovering)return!1;let t=e instanceof Error?e.message:String(e);return/database disk image is malformed|file is not a database|database or disk is full/.test(t)}recover(){if(this.recovering)throw Error(`BetterSqlite3Adapter: recovery already in progress`);this.recovering=!0;try{_.warn(`Runtime corruption detected — recovering database`,{dbPath:this.dbPath});try{this.db?.close()}catch{}this.db=null,this.stmtCache.clear();try{a(this.dbPath)}catch{}try{a(`${this.dbPath}-wal`)}catch{}try{a(`${this.dbPath}-shm`)}catch{}if(!this.DatabaseCtor)throw Error(`DatabaseCtor is not initialized`);this.db=this.DatabaseCtor(this.dbPath),this.db.pragma(`journal_mode = WAL`),this.db.pragma(`foreign_keys = ON`),this.db.pragma(`synchronous = NORMAL`);try{v(`sqlite-vec`).load(this.db),this.vectorCapable=!0}catch{this.vectorCapable=!1}_.info(`Database recovered — full reindex required`,{dbPath:this.dbPath})}finally{this.recovering=!1}}getDb(){if(!this.db)throw Error(`BetterSqlite3Adapter: database not opened`);return this.db}prepareCached(e){let t=this.stmtCache.get(e);if(t)return t;let n=this.getDb().prepare(e);return this.stmtCache.set(e,n),n}};function b(e){return v.resolve(`sql.js/dist/${e}`)}var x=class{type=`sql.js`;vectorCapable=!1;db=null;dbPath=``;dirty=!1;inTransaction=!1;async open(e){this.dbPath=e;let n=(await import(`sql.js`)).default,i=await n({locateFile:e=>b(e)});if(t(e)){let t=r(e);this.db=new i.Database(t)}else this.db=new i.Database}exec(e){let t=e.trimStart().toUpperCase();this.getDb().run(e),t.startsWith(`BEGIN`)?this.inTransaction=!0:(t.startsWith(`COMMIT`)||t.startsWith(`ROLLBACK`))&&(this.inTransaction=!1),this.dirty=!0}pragma(e){this.getDb().exec(`PRAGMA ${e}`)}queryAll(e,t=[]){let n=this.getDb().prepare(e);try{t.length>0&&n.bind(t);let e=[];for(;n.step();)e.push(n.getAsObject());return e}finally{n.free()}}run(e,t=[]){let n=this.getDb(),r=e.trimStart().toUpperCase(),i=!this.inTransaction&&(r.startsWith(`INSERT`)||r.startsWith(`UPDATE`));i&&n.run(`SAVEPOINT fk_check`);try{if(t.length>0){let r=n.prepare(e);try{r.bind(t),r.step()}finally{r.free()}}else n.run(e);if(i){if(n.exec(`PRAGMA foreign_key_check`).length>0)throw n.run(`ROLLBACK TO fk_check`),n.run(`RELEASE fk_check`),Error(`FOREIGN KEY constraint failed`);n.run(`RELEASE fk_check`)}}catch(e){if(i)try{n.run(`ROLLBACK TO fk_check`),n.run(`RELEASE fk_check`)}catch{}throw e}this.dirty=!0}flush(){if(!this.dirty||!this.db)return;let e=this.db.export(),r=`${this.dbPath}.tmp`,a=s(this.dbPath);a&&!t(a)&&n(a,{recursive:!0}),o(r,Buffer.from(e)),i(r,this.dbPath),this.dirty=!1}close(){if(this.db){let e=this.db,t;try{this.flush()}catch(e){t=e;try{a(`${this.dbPath}.tmp`)}catch{}}try{e.close()}finally{this.db=null}if(t)throw t}}getDb(){if(!this.db)throw Error(`SqlJsAdapter: database not opened`);return this.db}};async function S(){try{let{execSync:e}=await import(`node:child_process`),{createRequire:t}=await import(`node:module`),n=t(import.meta.url).resolve(`better-sqlite3/package.json`).replace(/[\\/]package\.json$/,``).replace(/[\\/]node_modules[\\/]better-sqlite3$/,``);return _.info(`Attempting native module rebuild for better-sqlite3`,{cwd:n}),e(`npm rebuild better-sqlite3`,{cwd:n,stdio:`pipe`,timeout:6e4}),_.info(`Native module rebuild completed successfully`),!0}catch(e){return _.warn(`Native module rebuild failed — continuing with sql.js fallback`,m(e)),!1}}let C=!1;async function w(e){let t=new y;try{return await t.open(e),t}catch(t){let n=t instanceof Error?t.message:String(t);if(/NODE_MODULE_VERSION|Could not locate the bindings file|no native build was found/.test(n)&&await S()){let t=new y;try{return await t.open(e),_.info(`better-sqlite3 recovered after native module rebuild`),t}catch{}}C||(C=!0,_.warn(`[aikit] better-sqlite3 unavailable — falling back to sql.js (vector search disabled). Reinstall with prebuild support or rebuild from source to enable vector search.`,m(t)))}let n=new x;try{return await n.open(e),n}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`[aikit] SQLite adapter "sql.js" failed to load: ${t}`)}}async function T(e){let t=new x;return await t.open(e),t}var E=class{adapter=null;reopenPromise=null;dbPath;externalAdapter;constructor(e={}){if(e.adapter)this.adapter=e.adapter,this.externalAdapter=!0,this.dbPath=``;else{let t=e.path??l.data;this.dbPath=c(t,`graph.db`),this.externalAdapter=!1}}async initialize(){if(this.externalAdapter){let e=this.getAdapter();this.createTables(e),this.migrateSchema(e),e.flush();return}let e=s(this.dbPath);t(e)||n(e,{recursive:!0}),this.adapter=await w(this.dbPath),this.configureAdapter(this.adapter),this.createTables(this.adapter),this.migrateSchema(this.adapter),this.adapter.flush()}configureAdapter(e){e.pragma(`journal_mode = WAL`),e.pragma(`foreign_keys = ON`)}createTables(e){e.exec(`
|
|
2
2
|
CREATE TABLE IF NOT EXISTS nodes (
|
|
3
3
|
id TEXT PRIMARY KEY,
|
|
4
4
|
type TEXT NOT NULL,
|
|
@@ -128,6 +128,12 @@ If a step is attempted ≥ 2 times with \`BLOCKED\` status, escalate with diagno
|
|
|
128
128
|
|
|
129
129
|
**Decomposition output format:** Batch N (parallel): Task: [agent] → [files] — [goal]
|
|
130
130
|
|
|
131
|
+
**Task Plan Visualization:** After producing the decomposition, present it visually using the \`task-plan@1\` template:
|
|
132
|
+
\`\`\`
|
|
133
|
+
present({ schemaVersion: 1, title: "Task Plan: <feature>", template: "task-plan@1", data: { title: "<feature>", phases: [{ id: "phase-1", label: "Phase 1: <name>", batches: [{ id: "batch-1", order: 1, parallel: true, tasks: [{ id: "t1", title: "<task>", agent: "<Agent>", files: ["<path>"], status: "pending" }] }] }] } })
|
|
134
|
+
\`\`\`
|
|
135
|
+
This gives the user a visual dependency graph of the execution plan before dispatch begins. Use \`task-plan-static@1\` for inline rendering without browser.
|
|
136
|
+
|
|
131
137
|
**Subagent prompt template:**
|
|
132
138
|
1. **Scope** — exact files + boundary
|
|
133
139
|
2. **Goal** — acceptance criteria, testable
|
|
@@ -194,6 +200,7 @@ Between phases: \`session_digest({ persist: true, focus: "<topic>" })\`. Carry f
|
|
|
194
200
|
- **Terse by default** — status updates, phase transitions, and confirmations in 1-3 sentences. No preamble, no filler.
|
|
195
201
|
- Batch completion summary: bullet list of agent status + files + decisions. NOT prose paragraphs.
|
|
196
202
|
- Structured data >3 rows → \`present({ format: "html" })\` (or \`format: "browser"\` in CLI mode)
|
|
203
|
+
- Task decomposition / execution plans → \`present({ template: "task-plan@1" })\`
|
|
197
204
|
- Charts, tables, dependency graphs → always \`present\`
|
|
198
205
|
- Short confirmations and questions → normal chat
|
|
199
206
|
- **CLI mode:** Always use \`format: "browser"\` — the \`html\` format's UIResource is invisible in terminal environments. The \`browser\` format auto-opens the system browser.
|
|
@@ -883,6 +883,19 @@ Template:
|
|
|
883
883
|
## Estimated Batches: <N>
|
|
884
884
|
\`\`\`
|
|
885
885
|
|
|
886
|
+
## Visualization
|
|
887
|
+
|
|
888
|
+
After writing \`tasks.md\`, present the task plan visually to the user for approval:
|
|
889
|
+
|
|
890
|
+
\`\`\`
|
|
891
|
+
present({ schemaVersion: 1, title: "Task Plan: <feature>", template: "task-plan@1", data: {
|
|
892
|
+
title: "<feature title>",
|
|
893
|
+
phases: [/* map each Phase to { id, label, outcome, batches: [{ id, order, parallel, tasks: [{ id, title, agent, files, status: "pending", dependsOn }] }] } */]
|
|
894
|
+
} })
|
|
895
|
+
\`\`\`
|
|
896
|
+
|
|
897
|
+
This renders an interactive dependency graph showing phases, parallel batches, and agent assignments. The user can visualize the execution order before approving.
|
|
898
|
+
|
|
886
899
|
## Agents
|
|
887
900
|
|
|
888
901
|
| Agent | Role |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function e(){return[{file:`SKILL.md`,content:'---\nname: present\ndescription: "Use the AI Kit `present` tool to display rich interactive dashboards, charts, timelines, status boards, and data visualizations in the browser or in-chat. Covers all block types, chart types, actions, composition patterns, and MCP Apps templates (list-sort, data-table, picker, flame-graph, form, timeline, kanban, tree, diff-view, dashboard). Load this skill before calling the present tool to ensure professional output."\nmetadata:\n category: cross-cutting\n domain: general\n applicability: always\n inputs: [data, analysis]\n outputs: [dashboards, charts, reports]\n requires: [aikit]\nargument-hint: "Content to present — data, analysis results, status report, comparison, or interactive MCP App"\n---\n\n# Present Tool — Rich Interactive Dashboards\n\n## 1. API Shape\n\n- `schemaVersion: 1` is always required.\n- `title: string` is always required; do not use unicode escapes like `\\u2014`, use the actual character.\n- Mode 1: block surface with `blocks: [{ type, title?, value }]`.\n- Mode 2: MCP App template with `template` + `data`.\n- Mode 3: viewer template with `template` + `data` for richer diagrams or flows.\n- No `actions` array means inline MCP App transport in the host client (except browser-only templates which auto-route to browser).\n- Any `actions` array means browser transport and opens the system browser.\n- CLI has no inline host; add a minimal action if you need the browser to open.\n\n```json\n{ "schemaVersion": 1, "title": "Release Review", "blocks": [{ "type": "metrics", "value": [] }] }\n```\n\n## 2. Content Blocks\n\nPass content as a `blocks` array of `{ type, title?, value }` objects.\n\n| Type | Value shape | Use for |\n|------|-------------|---------|\n| `markdown` | string | Prose, headings, code snippets |\n| `table` | `Record[]` or `{ headers, rows }` | Tabular data |\n| `chart` | `{ chartType, data, xKey?, yKeys? }` | Bar, line, area, pie, radar, scatter |\n| `metrics` | `[{ label, value, trend?, status? }]` | KPI cards |\n| `cards` | `[{ title, body?, badge?, status? }]` | Summary cards |\n| `mermaid` | string | Diagrams
|
|
1
|
+
function e(){return[{file:`SKILL.md`,content:'---\nname: present\ndescription: "Use the AI Kit `present` tool to display rich interactive dashboards, charts, timelines, status boards, and data visualizations in the browser or in-chat. Covers all block types, chart types, actions, composition patterns, and MCP Apps templates (list-sort, data-table, picker, flame-graph, form, timeline, kanban, tree, diff-view, dashboard). Load this skill before calling the present tool to ensure professional output."\nmetadata:\n category: cross-cutting\n domain: general\n applicability: always\n inputs: [data, analysis]\n outputs: [dashboards, charts, reports]\n requires: [aikit]\nargument-hint: "Content to present — data, analysis results, status report, comparison, or interactive MCP App"\n---\n\n# Present Tool — Rich Interactive Dashboards\n\n## 1. API Shape\n\n- `schemaVersion: 1` is always required.\n- `title: string` is always required; do not use unicode escapes like `\\u2014`, use the actual character.\n- Mode 1: block surface with `blocks: [{ type, title?, value }]`.\n- Mode 2: MCP App template with `template` + `data`.\n- Mode 3: viewer template with `template` + `data` for richer diagrams or flows.\n- No `actions` array means inline MCP App transport in the host client (except browser-only templates which auto-route to browser).\n- Any `actions` array means browser transport and opens the system browser.\n- CLI has no inline host; add a minimal action if you need the browser to open.\n\n```json\n{ "schemaVersion": 1, "title": "Release Review", "blocks": [{ "type": "metrics", "value": [] }] }\n```\n\n## 2. Content Blocks\n\nPass content as a `blocks` array of `{ type, title?, value }` objects.\n\n| Type | Value shape | Use for |\n|------|-------------|---------|\n| `markdown` | string | Prose, headings, code snippets |\n| `table` | `Record[]` or `{ headers, rows }` | Tabular data |\n| `chart` | `{ chartType, data, xKey?, yKeys? }` | Bar, line, area, pie, radar, scatter |\n| `metrics` | `[{ label, value, trend?, status? }]` | KPI cards |\n| `cards` | `[{ title, body?, badge?, status? }]` | Summary cards |\n| `mermaid` | string | Diagrams (works in both mcp-app and browser) |\n| `tree` | `{ name, children? }` | Hierarchies |\n| `timeline` | `[{ title, description?, timestamp?, status? }]` | Event sequences |\n| `checklist` | `[{ label, checked }]` | Task lists |\n| `code` | string | Code or diff excerpts |\n| `comparison` | `[{title, items}]` or `{columns: [{title, items}]}` | Side-by-side option comparisons |\n| `status-board` | `[{category, items}]` or `{items: [{category, items}]}` | Service health boards |\n| `progress` | `{label, value, max?}` or `{items: [{label, value, max?, color?}]}` | Progress bars |\n| `graph` | `{ nodes: [{id, label?}], edges: [{from, to, label?}] }` | Network graphs |\n| `docs-browser` | `{ files: [{path, title?, content?, status?}], title? }` | Documentation indexes |\n| `separator` | none | Visual divider between block groups |\n\n> Anti-patterns:\n> - No tables in `markdown`; use a `table` block.\n> - Use `{ chartType, data, xKey, yKeys }`, not Chart.js `{ labels, datasets }`.\n> - Keep `markdown` for prose, headings, and code, not UI structure.\n\n## 3. Actions\n\nAction shape: `{ type, id, label, variant?, options? }`\n\n- Types: `button` | `select` | `multi-select` | `form-submit` | `text-submit` | `confirm` | `custom`\n- Variants: `primary` (indigo) | `danger` (red) | `default` (neutral)\n\n```json\n{ "actions": [{ "type": "button", "id": "ack", "label": "Acknowledge", "variant": "primary" }] }\n```\n\n## 4. MCP App Templates\n\nUse templates for structured interactive widgets. They take `template` + `data`; returns depend on the widget.\n\n| Template | Purpose | Data shape | Returns |\n|----------|---------|------------|---------|\n| `list-sort` | Reorder a ranked list | `{ items: [{ id, label }] }` | Reordered items or IDs |\n| `data-table` | Inspect structured rows | `{ columns, rows, stats? }` | Current selection or filtered rows |\n| `picker` | Choose items from categories | `{ categories, items }` | Selected item IDs |\n| `flame-graph` | Explore hierarchical totals | `{ profile }` | Clicked node |\n| `form` | Collect field values | `{ fields }` | Submitted field map |\n| `kanban` | Move cards across columns | `{ columns, cards }` | Card move payload |\n| `timeline` | Show ordered milestones | `{ events }` | Display only |\n| `tree` | Browse nested nodes | `{ root }` | Display only |\n| `diff-view` | Show file diffs | `{ files, stats? }` | Display only |\n| `dashboard` | Show metric cards | `{ metrics }` | Display only |\n\n> **Auto-routing:** Browser-only templates (form, kanban, flame-graph, picker, list-sort) auto-route to browser transport even without explicit `actions`. No need to add a dummy action — the tool handles it.\n\n### `list-sort`\n`data`: `{ "items": [{ "id": "task-1", "label": "Fix auth bug" }] }`\n\n### `data-table`\n`data`: `{ "columns": [{ "key": "file", "label": "File" }], "rows": [{ "file": "auth.ts" }], "stats": [{ "label": "Files", "value": "1" }] }`\n\n### `picker`\n`data`: `{ "categories": [{ "id": "core", "label": "Core" }], "items": [{ "id": "auth", "label": "Auth", "category": "core", "tags": ["security"] }] }`\n\n### `flame-graph`\n`data`: `{ "profile": { "name": "root", "total": 100, "children": [{ "name": "packages/server", "total": 60 }] } }`\n\n### `form`\n`data`: `{ "fields": [{ "name": "projectName", "label": "Project Name", "type": "text", "value": "my-app" }] }`\n\n### `kanban`\n`data`: `{ "columns": [{ "id": "todo", "label": "To Do" }], "cards": [{ "id": "c1", "title": "Fix auth bug", "column": "todo" }] }`\n\n### `timeline`\n`data`: `{ "events": [{ "title": "v1.0 Release", "timestamp": "2026-05", "status": "complete" }] }`\n\nThe timeline template also accepts `entries` or `items` as the array field name (all three are equivalent).\n\n### `tree`\n`data`: `{ "root": { "label": "packages/", "children": [{ "label": "server/" }] } }`\n\n### `diff-view`\n`data`: `{ "files": [{ "path": "auth.ts", "status": "modified", "hunks": [{ "header": "@@ -1 +1 @@", "changes": [{ "type": "add", "content": "const ok = true;" }] }] }], "stats": { "filesChanged": 1 } }`\n\n### `dashboard`\n`data`: `{ "metrics": [{ "label": "Uptime", "value": "99.9%", "status": "success" }] }`\n\n## 5. Viewer Templates\n\nViewer templates render richer visual surfaces from `template` + `data`.\n\n| Template | Transport | Purpose |\n|----------|-----------|---------|\n| `c4-static@1` | mcp-app | Static architecture diagram |\n| `c4@1` | browser | Interactive architecture diagram |\n| `process-flow-static@1` | mcp-app | Static process flow |\n| `process-flow@1` | browser | Interactive process flow |\n| `tour@1` | browser | Guided walkthrough or code tour |\n| `task-plan-static@1` | mcp-app | Static task execution plan with phases, batches, agent assignments |\n| `task-plan@1` | browser | Interactive task plan with ReactFlow — drag/zoom/pan, dependency edges, ELK layout |\n\n`c4`: `{ "nodes": [{ "id": "web", "type": "container", "label": "Web App", "technology?": "React" }], "edges": [{ "source": "web", "target": "api", "label": "HTTPS" }] }`\n\n`process-flow`: `{ "nodes": [{ "id": "start", "label": "Start", "type": "start-end" }], "edges": [{ "source": "start", "target": "review", "type?": "standard" }] }`\n\nNode types: `start-end` | `manual` | `automated` | `integration` | `decision` | `prerequisite`. Default: `manual`.\nEdge types: `standard` | `loop-back` | `exception`. Default: `standard`. `loop-back` and `exception` edges animate.\n\n`tour`: `{ "steps": [{ "id": "overview", "title": "Overview", "file": "src/index.ts", "explanation": "Entry point", "code?": "...", "line?": 1 }] }`\n\n`task-plan`: `{ "title": "Feature Name", "description?": "Optional", "phases": [{ "id": "p1", "label": "Phase 1", "outcome?": "...", "batches": [{ "id": "b1", "order": 1, "parallel": true, "label?": "Parallel Research", "tasks": [{ "id": "t1", "title": "Research auth", "agent": "Researcher-Alpha", "files?": ["src/auth/"], "status?": "done", "description?": "...", "dependsOn?": [] }] }] }] }`\n\nGotcha: edges use `source` and `target`, not `from` and `to`.\n\nDecision tree:\n- Architecture, systems, containers, deployments: load the `c4-architecture` skill and use `c4@1` or `c4-static@1`.\n- Stateful workflows, approvals, or branching processes: use `process-flow@1` or `process-flow-static@1`.\n- Agent task decomposition, execution plans, or parallel batch visualization: use `task-plan@1` or `task-plan-static@1`.\n- Ordered walkthroughs, onboarding, or narrated analysis: use `tour@1`.\n\n## 6. Rules\n\n- Pick transport once: no `actions` for inline, any `actions` for browser.\n- Combine block types in one `blocks` array; metrics + chart + table + markdown is the normal composition pattern.\n- Use concise schemas in docs; do not expand to full `present()` calls unless behavior depends on them.\n- Use `table`, `comparison`, and `status-board` for structured data instead of formatting it inside markdown.\n- Architecture requests are delegated: load the `c4-architecture` skill for diagram guidance and data contracts.\n- If inline rendering only shows a title, raw JSON, or fallback text, switch to browser transport with a minimal action. (Browser-only templates now auto-route, so this mainly applies to custom block surfaces.)\n- For large or mixed-content surfaces, browser transport is usually easier to review and more reliable.\n'}]}export{e as default};
|