@zibby/skills 0.1.95 → 0.2.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.
Files changed (78) hide show
  1. package/README.md +1 -1
  2. package/dist/artifact.d.ts +1 -115
  3. package/dist/browser.d.ts +10 -19
  4. package/dist/chartRender.d.ts +46 -57
  5. package/dist/chartRender.js +1 -1
  6. package/dist/chat-memory.d.ts +26 -330
  7. package/dist/chat-notify.d.ts +30 -409
  8. package/dist/chat-notify.js +3 -3
  9. package/dist/chatProgress.d.ts +28 -47
  10. package/dist/code-scan.d.ts +52 -58
  11. package/dist/codeStats.d.ts +36 -136
  12. package/dist/codeStats.js +1 -1
  13. package/dist/codebaseMemory.d.ts +52 -32
  14. package/dist/codebaseMemory.js +2 -2
  15. package/dist/core-tools.d.ts +10 -131
  16. package/dist/datasetStore.d.ts +52 -179
  17. package/dist/datasetStore.js +12 -3
  18. package/dist/discord.d.ts +32 -68
  19. package/dist/figma.d.ts +5 -408
  20. package/dist/function-skill.d.ts +23 -135
  21. package/dist/function-skill.js +1 -1
  22. package/dist/gbrain.d.ts +46 -114
  23. package/dist/git-write.d.ts +45 -137
  24. package/dist/git-write.js +6 -6
  25. package/dist/git.d.ts +2 -73
  26. package/dist/github.d.ts +2 -1202
  27. package/dist/gitlab.d.ts +55 -1059
  28. package/dist/gitlab.js +2 -2
  29. package/dist/googleDocs.d.ts +39 -175
  30. package/dist/hubspot.d.ts +1 -381
  31. package/dist/index.d.ts +19 -12
  32. package/dist/index.js +157 -148
  33. package/dist/integrations.d.ts +2 -2
  34. package/dist/jira.d.ts +2 -532
  35. package/dist/jira.js +4 -4
  36. package/dist/kvMemory.d.ts +47 -78
  37. package/dist/lark.d.ts +2 -161
  38. package/dist/lark.js +1 -1
  39. package/dist/larkDocs.d.ts +35 -236
  40. package/dist/linear.d.ts +36 -343
  41. package/dist/linkedin.d.ts +10 -120
  42. package/dist/llm-billing.d.ts +92 -180
  43. package/dist/llm-billing.js +1 -1
  44. package/dist/memory.d.ts +11 -137
  45. package/dist/notion.d.ts +28 -276
  46. package/dist/notion.js +4 -4
  47. package/dist/opendesign.d.ts +24 -202
  48. package/dist/opendesign.js +2 -2
  49. package/dist/package.json +3 -2
  50. package/dist/plane.d.ts +40 -24
  51. package/dist/report.d.ts +153 -110
  52. package/dist/review-dedup.d.ts +8 -8
  53. package/dist/review.d.ts +12 -2
  54. package/dist/reviewMemoryIo.d.ts +37 -3
  55. package/dist/reviewRecord.d.ts +41 -47
  56. package/dist/sentry.d.ts +25 -22
  57. package/dist/skill-installer.d.ts +11 -86
  58. package/dist/slack.d.ts +1 -284
  59. package/dist/socialCard.d.ts +35 -89
  60. package/dist/test-runner.d.ts +1 -220
  61. package/dist/trackers/github-adapter.d.ts +39 -94
  62. package/dist/trackers/index.d.ts +25 -18
  63. package/dist/trackers/jira-adapter.d.ts +20 -88
  64. package/dist/trackers/linear-adapter.d.ts +24 -87
  65. package/dist/trackers/plane-adapter.d.ts +29 -85
  66. package/dist/trackers/plane-adapter.js +1 -1
  67. package/dist/trackers/types.d.ts +1 -186
  68. package/dist/triggerAgent.d.ts +26 -42
  69. package/dist/triggerAgent.js +1 -1
  70. package/dist/workflow-builder.d.ts +11 -245
  71. package/docs/cli-reference.md +33 -0
  72. package/docs/concepts/designing-agents.md +201 -0
  73. package/docs/self-host/backup-restore.md +52 -0
  74. package/docs/self-host/index.md +75 -0
  75. package/docs/self-host/storage.md +50 -0
  76. package/docs/self-host/troubleshooting.md +48 -0
  77. package/docs/self-host/upgrade.md +81 -0
  78. package/package.json +3 -2
@@ -1,179 +1,52 @@
1
- export function __clearEnsuredStores(): void;
2
- export namespace datasetStoreSkill {
3
- let id: string;
4
- let serverName: string;
5
- let allowedTools: string[];
6
- let description: string;
7
- let promptFragment: string;
8
- function resolve(): {
9
- command: any;
10
- args: any[];
11
- env: {};
12
- description: string;
13
- type?: undefined;
14
- alwaysLoad?: undefined;
15
- } | {
16
- type: string;
17
- command: string;
18
- args: any[];
19
- env: {};
20
- description: string;
21
- alwaysLoad: boolean;
22
- };
23
- function handleToolCall(name: any, args: any): Promise<string>;
24
- let tools: ({
25
- name: string;
26
- description: string;
27
- input_schema: {
28
- type: string;
29
- properties: {
30
- store: {
31
- type: string;
32
- description: string;
33
- };
34
- record: {
35
- type: string;
36
- description: string;
37
- };
38
- description: {
39
- type: string;
40
- description: string;
41
- };
42
- agent: {
43
- type: string;
44
- description: string;
45
- };
46
- select?: undefined;
47
- where?: undefined;
48
- groupBy?: undefined;
49
- orderBy?: undefined;
50
- limit?: undefined;
51
- since?: undefined;
52
- until?: undefined;
53
- name?: undefined;
54
- type?: undefined;
55
- sql?: undefined;
56
- params?: undefined;
57
- };
58
- required: string[];
59
- };
60
- } | {
61
- name: string;
62
- description: string;
63
- input_schema: {
64
- type: string;
65
- properties: {
66
- store: {
67
- type: string;
68
- description: string;
69
- };
70
- select: {
71
- type: string;
72
- description: string;
73
- };
74
- where: {
75
- type: string;
76
- description: string;
77
- };
78
- groupBy: {
79
- type: string;
80
- description: string;
81
- };
82
- orderBy: {
83
- type: string;
84
- description: string;
85
- };
86
- limit: {
87
- type: string;
88
- description: string;
89
- };
90
- since: {
91
- type: string;
92
- description: string;
93
- };
94
- until: {
95
- type: string;
96
- description: string;
97
- };
98
- agent: {
99
- type: string;
100
- description: string;
101
- };
102
- record?: undefined;
103
- description?: undefined;
104
- name?: undefined;
105
- type?: undefined;
106
- sql?: undefined;
107
- params?: undefined;
108
- };
109
- required: any[];
110
- };
111
- } | {
112
- name: string;
113
- description: string;
114
- input_schema: {
115
- type: string;
116
- properties: {
117
- name: {
118
- type: string;
119
- description: string;
120
- };
121
- type: {
122
- type: string;
123
- enum: string[];
124
- description: string;
125
- };
126
- description: {
127
- type: string;
128
- description: string;
129
- };
130
- store?: undefined;
131
- record?: undefined;
132
- agent?: undefined;
133
- select?: undefined;
134
- where?: undefined;
135
- groupBy?: undefined;
136
- orderBy?: undefined;
137
- limit?: undefined;
138
- since?: undefined;
139
- until?: undefined;
140
- sql?: undefined;
141
- params?: undefined;
142
- };
143
- required: string[];
144
- };
145
- } | {
146
- name: string;
147
- description: string;
148
- input_schema: {
149
- type: string;
150
- properties: {
151
- store: {
152
- type: string;
153
- description: string;
154
- };
155
- sql: {
156
- type: string;
157
- description: string;
158
- };
159
- params: {
160
- type: string;
161
- description: string;
162
- };
163
- record?: undefined;
164
- description?: undefined;
165
- agent?: undefined;
166
- select?: undefined;
167
- where?: undefined;
168
- groupBy?: undefined;
169
- orderBy?: undefined;
170
- limit?: undefined;
171
- since?: undefined;
172
- until?: undefined;
173
- name?: undefined;
174
- type?: undefined;
175
- };
176
- required: string[];
177
- };
178
- })[];
179
- }
1
+ /**
2
+ * datasetStore.js — durable, queryable structured-artifact store skill.
3
+ *
4
+ * WHAT IT IS
5
+ * ──────────
6
+ * A hand-written multi-tool skill (same shape as kvMemory.js / reviewMemory.js /
7
+ * github.js): `serverName`, `allowedTools`, `tools[]`, `handleToolCall`, and a
8
+ * `resolve()` that spawns the GENERIC bin/mcp-skill.mjs. Unlike kv-memory (a
9
+ * key→value MEMORY for picking up where a prior run left off), this is a durable
10
+ * STRUCTURED-RECORD store: an agent appends arbitrary JSON records to a named
11
+ * store and later runs SQL-style queries/aggregations over them — e.g. to
12
+ * accumulate metrics across runs and produce a report.
13
+ *
14
+ * STORES v2 — NAME-BASED RESOLUTION (the shared contract)
15
+ * ────────────────────────────────────────────────────────
16
+ * Stores are auto-provisioned at DEPLOY and resolved at runtime BY NAME via env:
17
+ * - The run carries one `ZIBBY_STORE__<name> = <storeId>` per bound store.
18
+ * - The agent reads the injected "AVAILABLE STORES" prompt catalog (name +
19
+ * description), picks one, and passes the chosen logical `name` to the tool.
20
+ * - This name→storeId env map is BOTH the allowlist AND the resolver: the
21
+ * agent can only ever write to a declared/bound name (anti-fragmentation).
22
+ *
23
+ * BACKEND (already built NO change here)
24
+ * ─────────────────────────────────────────
25
+ * Two routes on the SAME base URL kv-memory uses (getAccountApiUrl(), prod
26
+ * https://api-prod.zibby.app), authed with the SAME Bearer project token
27
+ * (getSessionToken()):
28
+ * - POST {base}/datasets/stores/{storeId}/append body { record, agent }
29
+ * → { ok, id, ts }
30
+ * - POST {base}/datasets/stores/{storeId}/query body { select?, where?,
31
+ * groupBy?, orderBy?, limit?, since?, until?, agent? }
32
+ * → { ok, rowCount, columns, rows }
33
+ * Plus the per-type data routes on the same base: /sql (sqlite stores) and
34
+ * /put /get /list /delete (file stores — blob storage by relative path).
35
+ * The `storeId` lives in the URL path. Tenancy (account + project) is enforced
36
+ * SERVER-SIDE from the Bearer token — the skill NEVER sends account/project.
37
+ *
38
+ * AUTOMATIC PER-AGENT TAGGING
39
+ * ────────────────────────────
40
+ * Appends default `agent` to the writing agent's namespace (WORKFLOW_TYPE,
41
+ * falling back to the literal 'agent'), so records are auto-tagged with who
42
+ * wrote them and `query`'s optional `agent` filter can scope to one writer.
43
+ *
44
+ * AUTH — identical to kvMemory.js / reviewMemory.js
45
+ * ──────────────────────────────────────────────────
46
+ * Calls ZIBBY'S OWN backend with PROJECT_API_TOKEN (Bearer) against
47
+ * ZIBBY_ACCOUNT_API_URL (default api-prod.zibby.app). Mirrors
48
+ * @zibby/core/backend-client.js getSessionToken()/getAccountApiUrl() rather than
49
+ * importing a non-existent helper, so the auth model stays identical.
50
+ */
51
+ export declare function __clearEnsuredStores(): void;
52
+ export declare const datasetStoreSkill: any;
@@ -1,4 +1,4 @@
1
- import{existsSync as p,readFileSync as m}from"node:fs";import{homedir as f}from"node:os";import{join as h,dirname as E,resolve as g}from"node:path";import{fileURLToPath as T}from"node:url";function S(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let r=E(T(import.meta.url)),t=g(r,"..","bin","mcp-skill.mjs");return p(t)?t:null}function l(){if(process.env.PROJECT_API_TOKEN)return process.env.PROJECT_API_TOKEN;if(process.env.ZIBBY_USER_TOKEN)return process.env.ZIBBY_USER_TOKEN;try{let r=h(f(),".zibby","config.json");return p(r)&&JSON.parse(m(r,"utf-8")).sessionToken||null}catch{return null}}function u(){return process.env.ZIBBY_ACCOUNT_API_URL?process.env.ZIBBY_ACCOUNT_API_URL.replace(/\/$/,""):(process.env.ZIBBY_ENV||"prod")==="local"?"http://localhost:3001":process.env.ZIBBY_PROD_ACCOUNT_API_URL||"https://api-prod.zibby.app"}function d(){return(typeof process.env.WORKFLOW_TYPE=="string"?process.env.WORKFLOW_TYPE.trim():"")||"agent"}function O(){let r={};for(let[t,e]of Object.entries(process.env)){let o=/^ZIBBY_STORE__(.+)$/.exec(t);if(!o)continue;let n=typeof e=="string"?e.trim():"";n&&(r[o[1]]=n)}return r}var a={};function I(){for(let r of Object.keys(a))delete a[r]}function i(r){let t={...O(),...a},e=Object.keys(t),o=typeof r=="string"?r.trim():"";return o?Object.prototype.hasOwnProperty.call(t,o)?{storeId:t[o],name:o}:{error:`unknown store '${o}'; available: ${e.join(", ")}`}:e.length===1?{storeId:t[e[0]],name:e[0]}:e.length===0?{error:"no stores bound to this agent"}:{error:`multiple stores are bound; pass \`store\` (one of: ${e.join(", ")})`}}async function b(r){let t=l();if(!t)throw new Error("No backend credential (PROJECT_API_TOKEN). Stores are only available inside a Zibby run.");let e=await fetch(`${u()}/datasets/stores/ensure`,{method:"POST",headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"},body:JSON.stringify(r)});if(!e.ok){let o=await e.text().catch(()=>"");throw new Error(`ensure_store failed (${e.status}): ${o.slice(0,300)}`)}return e.json()}async function c(r,t,e){let o=l();if(!o)throw new Error("No backend credential (PROJECT_API_TOKEN). Dataset store is only available inside a Zibby run.");let n=`${u()}/datasets/stores/${encodeURIComponent(r)}/${t}`,s=await fetch(n,{method:"POST",headers:{Authorization:`Bearer ${o}`,"Content-Type":"application/json"},body:JSON.stringify(e)});if(!s.ok){let y=await s.text().catch(()=>"");throw new Error(`Store ${t} failed (${s.status}): ${y.slice(0,300)}`)}return s.json()}var L={id:"dataset-store",serverName:"dataset_store",allowedTools:["mcp__dataset_store__*"],description:"Dataset store \u2014 a durable, queryable store for structured JSON records; append rows now, run SQL-style aggregations/reports later",promptFragment:`## Dataset Store (durable, queryable structured-record store)
1
+ import{existsSync as l,readFileSync as f}from"node:fs";import{homedir as m}from"node:os";import{join as h,dirname as g,resolve as E}from"node:path";import{fileURLToPath as b}from"node:url";function T(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let o=g(b(import.meta.url)),e=E(o,"..","bin","mcp-skill.mjs");return l(e)?e:null}function u(){if(process.env.PROJECT_API_TOKEN)return process.env.PROJECT_API_TOKEN;if(process.env.ZIBBY_USER_TOKEN)return process.env.ZIBBY_USER_TOKEN;try{let o=h(m(),".zibby","config.json");return l(o)&&JSON.parse(f(o,"utf-8")).sessionToken||null}catch{return null}}function y(){return process.env.ZIBBY_ACCOUNT_API_URL?process.env.ZIBBY_ACCOUNT_API_URL.replace(/\/$/,""):(process.env.ZIBBY_ENV||"prod")==="local"?"http://localhost:3001":process.env.ZIBBY_PROD_ACCOUNT_API_URL||"https://api-prod.zibby.app"}function d(){return(typeof process.env.WORKFLOW_TYPE=="string"?process.env.WORKFLOW_TYPE.trim():"")||"agent"}function S(){let o={};for(let[e,t]of Object.entries(process.env)){let r=/^ZIBBY_STORE__(.+)$/.exec(e);if(!r)continue;let s=typeof t=="string"?t.trim():"";s&&(o[r[1]]=s)}return o}var p={};function w(){for(let o of Object.keys(p))delete p[o]}function a(o){let e={...S(),...p},t=Object.keys(e),r=typeof o=="string"?o.trim():"";return r?Object.prototype.hasOwnProperty.call(e,r)?{storeId:e[r],name:r}:{error:`unknown store '${r}'; available: ${t.join(", ")}`}:t.length===1?{storeId:e[t[0]],name:t[0]}:t.length===0?{error:"no stores bound to this agent"}:{error:`multiple stores are bound; pass \`store\` (one of: ${t.join(", ")})`}}async function O(o){let e=u();if(!e)throw new Error("No backend credential (PROJECT_API_TOKEN). Stores are only available inside a Zibby run.");let t=await fetch(`${y()}/datasets/stores/ensure`,{method:"POST",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"},body:JSON.stringify(o)});if(!t.ok){let r=await t.text().catch(()=>"");throw new Error(`ensure_store failed (${t.status}): ${r.slice(0,300)}`)}return t.json()}async function c(o,e,t){let r=u();if(!r)throw new Error("No backend credential (PROJECT_API_TOKEN). Dataset store is only available inside a Zibby run.");let s=`${y()}/datasets/stores/${encodeURIComponent(o)}/${e}`,i=await fetch(s,{method:"POST",headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!i.ok){let n=await i.text().catch(()=>"");throw new Error(`Store ${e} failed (${i.status}): ${n.slice(0,300)}`)}return i.json()}var L={id:"dataset-store",serverName:"dataset_store",allowedTools:["mcp__dataset_store__*"],description:"Dataset store \u2014 a durable, queryable store for structured JSON records; append rows now, run SQL-style aggregations/reports later",promptFragment:`## Dataset Store (durable, queryable structured-record store)
2
2
  You have one or more durable stores for STRUCTURED records that survive across
3
3
  your stateless runs. Unlike key-value memory (for picking up where you left
4
4
  off), this is for accumulating DATA you want to QUERY and AGGREGATE later \u2014 e.g.
@@ -11,12 +11,15 @@ omit \`store\` and it defaults to that one. You can ONLY write to a bound store
11
11
  name; any other name is rejected. Each appended record is an arbitrary JSON
12
12
  object, auto-tagged with YOUR agent type so you can later filter to your writes.
13
13
 
14
- There are TWO kinds of bound store (shown as TYPE in AVAILABLE STORES):
14
+ There are THREE kinds of bound store (shown as TYPE in AVAILABLE STORES):
15
15
  \u2022 dataset \u2014 append-only structured records you QUERY/AGGREGATE later (analytics).
16
16
  \u2022 sqlite \u2014 a real, MUTABLE relational database (a SQLite file per store): CREATE
17
17
  TABLE on the fly, INSERT/UPDATE/DELETE, SELECT. Schema + data persist across
18
18
  runs. Use this when you need to UPDATE rows / track changing state (e.g. a
19
19
  queue with a status column), not just append.
20
+ \u2022 file \u2014 arbitrary FILE/BLOB storage addressed by relative path: stash raw
21
+ JSON dumps, CSVs, images, snapshots as-is and fetch them back in later runs.
22
+ Use this when the data is a document/blob, not rows.
20
23
 
21
24
  You can also CREATE your own store on demand (no deploy needed) with
22
25
  ensure_store \u2014 e.g. an agent that needs a private sqlite DB to track drafts/
@@ -33,5 +36,11 @@ Tools:
33
36
  NOT EXISTS. Returns { rowsModified, wrote }.
34
37
  - sqlite_query: (sqlite stores) Run a SELECT (optionally with \`params\` for safe
35
38
  binding). Returns { columns, rows }. Read-only \u2014 never changes data.
39
+ - file_put: (file stores) Write/overwrite ONE file at a relative path (text or
40
+ base64 binary; max 4 MiB).
41
+ - file_get: (file stores) Read a file back (text returned as text, binary as
42
+ base64).
43
+ - file_list: (file stores) List stored files (optionally by path prefix).
44
+ - file_delete: (file stores) Delete ONE file by path.
36
45
  Pick the tool that matches the store's TYPE; using a dataset tool on a sqlite
37
- store (or vice-versa) is rejected.`,resolve(){let r=S();if(!r)return{command:null,args:[],env:{},description:this.description};let t={};for(let e of["PROJECT_API_TOKEN","ZIBBY_ACCOUNT_API_URL","ZIBBY_ENV","ZIBBY_PROD_ACCOUNT_API_URL","ZIBBY_USER_TOKEN","WORKFLOW_TYPE"])process.env[e]&&(t[e]=process.env[e]);for(let e of Object.keys(process.env))/^ZIBBY_STORE__.+$/.test(e)&&process.env[e]&&(t[e]=process.env[e]);return{type:"stdio",command:"node",args:[r,"../dist/datasetStore.js","datasetStoreSkill"],env:t,description:this.description,alwaysLoad:!1}},async handleToolCall(r,t){try{switch(r){case"dataset_append":{if(t?.record==null||typeof t.record!="object"||Array.isArray(t.record))return JSON.stringify({error:"record is required (a JSON object)"});let e=i(t?.store);if(e.error)return JSON.stringify({error:e.error});let o=typeof t?.agent=="string"&&t.agent.trim()?t.agent.trim():d(),n={record:t.record,agent:o};typeof t?.description=="string"&&t.description.trim()&&(n.description=t.description.trim());let s=await c(e.storeId,"append",n);return JSON.stringify({...s,store:e.name,storeId:e.storeId})}case"dataset_query":{let e=i(t?.store);if(e.error)return JSON.stringify({error:e.error});let o={};for(let s of["select","where","groupBy","orderBy","limit","since","until","agent"])t?.[s]!=null&&(o[s]=t[s]);let n=await c(e.storeId,"query",o);return JSON.stringify({...n,store:e.name,storeId:e.storeId})}case"ensure_store":{let e=typeof t?.name=="string"?t.name.trim():"";if(!e)return JSON.stringify({error:"name is required"});let o=typeof t?.type=="string"&&t.type.trim()?t.type.trim().toLowerCase():"sqlite",n=typeof t?.description=="string"?t.description.trim():"",s=await b({name:e,type:o,description:n,namespace:d()});return s?.storeId&&(a[e]=s.storeId),JSON.stringify({...s,store:e})}case"sqlite_exec":case"sqlite_query":{let e=i(t?.store);if(e.error)return JSON.stringify({error:e.error});if(typeof t?.sql!="string"||!t.sql.trim())return JSON.stringify({error:"sql is required (a non-empty SQL string)"});let o={sql:t.sql};Array.isArray(t?.params)&&(o.params=t.params);let n=await c(e.storeId,"sql",o);return JSON.stringify({...n,store:e.name,storeId:e.storeId})}default:return JSON.stringify({error:`Unknown tool: ${r}`})}}catch(e){return JSON.stringify({error:e.message})}},tools:[{name:"dataset_append",description:"Append ONE structured JSON record to a bound store, durably. Records persist across your stateless runs and are auto-tagged with your agent type so you can filter to your own writes later. Use to accumulate data you will query/aggregate (e.g. per-run metrics, processed items). Append ONE record per call.",input_schema:{type:"object",properties:{store:{type:"string",description:'The logical store NAME to write to (e.g. "scorecards"), taken from the AVAILABLE STORES list \u2014 pick by description. NOT an id. If exactly one store is bound you may omit this and it defaults to that store; you can ONLY write to a bound store name.'},record:{type:"object",description:'An arbitrary JSON object \u2014 one row of data. Its keys become queryable fields (e.g. {"repo":"owner/x","stars":1200}). One record per call.'},description:{type:"string",description:"Optional, informational note about this write. The store already exists from deploy, so this is not required and does not create anything."},agent:{type:"string",description:"Optional writing-agent tag. Defaults to your own agent type \u2014 leave unset to auto-tag."}},required:["record"]}},{name:"dataset_query",description:"Run a SQL-style query over a bound store to build reports: select/aggregate (count|sum|avg|min|max), filter, group, order, limit, and bound by month. Returns { columns, rows }. Use this to compute summaries/aggregations from records you appended earlier.",input_schema:{type:"object",properties:{store:{type:"string",description:'The logical store NAME to query (e.g. "scorecards"), taken from the AVAILABLE STORES list \u2014 pick by description. NOT an id. If exactly one store is bound you may omit this and it defaults to that store.'},select:{type:"array",description:"Columns to return. Each item is { field?, agg?, as? }. agg \u2208 count|sum|avg|min|max; omit field for count(*). Omit `select` entirely to return raw rows."},where:{type:"array",description:"Filters, ANDed. Each item is { field, op, value }; op \u2208 eq|ne|gt|gte|lt|lte|like. `field` is a JSON key of the stored record."},groupBy:{type:"array",description:"Field names to group by (array of strings) for aggregation."},orderBy:{type:"array",description:"Sort spec. Each item is { field|as, dir }; dir \u2208 asc|desc."},limit:{type:"number",description:"Maximum number of rows to return."},since:{type:"string",description:"Inclusive lower bound month, 'yyyy-MM' (e.g. '2026-01')."},until:{type:"string",description:"Inclusive upper bound month, 'yyyy-MM' (e.g. '2026-06')."},agent:{type:"string",description:"Filter to records written by one agent namespace. Omit to query across all writers."}},required:[]}},{name:"ensure_store",description:'Create (or reuse) a store ON DEMAND for THIS agent \u2014 use when you need a store that was NOT declared/bound at deploy. Idempotent by name and private to this agent: calling again with the same name returns the SAME store (safe to call at the start of every run). Returns { storeId }. For type "sqlite" you then define schema with sqlite_exec (CREATE TABLE IF NOT EXISTS) and read/write via sqlite_exec/sqlite_query using this name.',input_schema:{type:"object",properties:{name:{type:"string",description:'A short logical name for the store (e.g. "linkedin_posts"). Letters, digits, _ and - only.'},type:{type:"string",enum:["sqlite","dataset"],description:'Store type. "sqlite" (default) = a mutable relational DB whose schema YOU define with SQL. "dataset" = append-only JSON records for later aggregation/analytics.'},description:{type:"string",description:"What this store is for (shown in the Storage UI)."}},required:["name"]}},{name:"sqlite_exec",description:"For SQLITE-type stores: run SQL that CHANGES data \u2014 CREATE TABLE (use IF NOT EXISTS), INSERT, UPDATE, DELETE (one or more statements in one call). The store is a real, mutable SQLite database that persists across your stateless runs. Returns { rowsModified, wrote }. Use this to build schema on the fly and to update rows / track changing state (e.g. a queue with a status column).",input_schema:{type:"object",properties:{store:{type:"string",description:"The logical store NAME (a sqlite-type store from AVAILABLE STORES) \u2014 pick by description. NOT an id. If exactly one store is bound you may omit this."},sql:{type:"string",description:'The SQL to run. May contain multiple statements separated by ";". Prefer CREATE TABLE IF NOT EXISTS for idempotent schema.'},params:{type:"array",description:'Optional positional bind params for a SINGLE parameterized statement (safe binding of values), e.g. sql "UPDATE t SET s=? WHERE id=?" with params ["done", 1].'}},required:["sql"]}},{name:"sqlite_query",description:"For SQLITE-type stores: run a read-only SELECT (optionally with `params` for safe binding) against the store's SQLite database. Returns { columns, rows }. Never changes data. Use to read back rows/state you stored earlier.",input_schema:{type:"object",properties:{store:{type:"string",description:"The logical store NAME (a sqlite-type store from AVAILABLE STORES) \u2014 pick by description. NOT an id. If exactly one store is bound you may omit this."},sql:{type:"string",description:"A single SELECT statement. Use ? placeholders + `params` for any values."},params:{type:"array",description:'Optional positional bind params for the SELECT, e.g. ["linkedin_personal"].'}},required:["sql"]}}]};export{I as __clearEnsuredStores,L as datasetStoreSkill};
46
+ store (or a file tool on either, etc.) is rejected.`,resolve(){let o=T();if(!o)return{command:null,args:[],env:{},description:this.description};let e={};for(let t of["PROJECT_API_TOKEN","ZIBBY_ACCOUNT_API_URL","ZIBBY_ENV","ZIBBY_PROD_ACCOUNT_API_URL","ZIBBY_USER_TOKEN","WORKFLOW_TYPE"])process.env[t]&&(e[t]=process.env[t]);for(let t of Object.keys(process.env))/^ZIBBY_STORE__.+$/.test(t)&&process.env[t]&&(e[t]=process.env[t]);return{type:"stdio",command:"node",args:[o,"../dist/datasetStore.js","datasetStoreSkill"],env:e,description:this.description,alwaysLoad:!1}},async handleToolCall(o,e){try{switch(o){case"dataset_append":{if(e?.record==null||typeof e.record!="object"||Array.isArray(e.record))return JSON.stringify({error:"record is required (a JSON object)"});let t=a(e?.store);if(t.error)return JSON.stringify({error:t.error});let r=typeof e?.agent=="string"&&e.agent.trim()?e.agent.trim():d(),s={record:e.record,agent:r};typeof e?.description=="string"&&e.description.trim()&&(s.description=e.description.trim());let i=await c(t.storeId,"append",s);return JSON.stringify({...i,store:t.name,storeId:t.storeId})}case"dataset_query":{let t=a(e?.store);if(t.error)return JSON.stringify({error:t.error});let r={};for(let i of["select","where","groupBy","orderBy","limit","since","until","agent"])e?.[i]!=null&&(r[i]=e[i]);let s=await c(t.storeId,"query",r);return JSON.stringify({...s,store:t.name,storeId:t.storeId})}case"ensure_store":{let t=typeof e?.name=="string"?e.name.trim():"";if(!t)return JSON.stringify({error:"name is required"});let r=typeof e?.type=="string"&&e.type.trim()?e.type.trim().toLowerCase():"sqlite",s=typeof e?.description=="string"?e.description.trim():"",i=await O({name:t,type:r,description:s,namespace:d()});return i?.storeId&&(p[t]=i.storeId),JSON.stringify({...i,store:t})}case"file_put":{let t=a(e?.store);if(t.error)return JSON.stringify({error:t.error});if(typeof e?.path!="string"||!e.path.trim())return JSON.stringify({error:'path is required (a relative file path like "reports/2026-07.json")'});let r=typeof e?.content=="string",s=typeof e?.contentBase64=="string"&&e.contentBase64.length>0;if(!r&&!s)return JSON.stringify({error:"content (text) or contentBase64 (base64 bytes) is required"});let i={path:e.path.trim()};r?i.content=e.content:i.contentBase64=e.contentBase64,typeof e?.contentType=="string"&&e.contentType.trim()&&(i.contentType=e.contentType.trim());let n=await c(t.storeId,"put",i);return JSON.stringify({...n,store:t.name,storeId:t.storeId})}case"file_get":{let t=a(e?.store);if(t.error)return JSON.stringify({error:t.error});if(typeof e?.path!="string"||!e.path.trim())return JSON.stringify({error:"path is required"});let r=await c(t.storeId,"get",{path:e.path.trim()}),s={ok:!0,store:t.name,storeId:t.storeId,path:r.path,size:r.size,contentType:r.contentType,lastModified:r.lastModified},i=Buffer.from(r.contentBase64||"","base64"),n=i.toString("utf8");return Buffer.compare(Buffer.from(n,"utf8"),i)===0&&!n.includes("\0")?(s.content=n,s.encoding="utf8"):(s.contentBase64=r.contentBase64,s.encoding="base64"),JSON.stringify(s)}case"file_list":{let t=a(e?.store);if(t.error)return JSON.stringify({error:t.error});let r={};typeof e?.prefix=="string"&&e.prefix.trim()&&(r.prefix=e.prefix.trim()),e?.limit!=null&&(r.limit=e.limit),typeof e?.cursor=="string"&&e.cursor&&(r.cursor=e.cursor);let s=await c(t.storeId,"list",r);return JSON.stringify({...s,store:t.name,storeId:t.storeId})}case"file_delete":{let t=a(e?.store);if(t.error)return JSON.stringify({error:t.error});if(typeof e?.path!="string"||!e.path.trim())return JSON.stringify({error:"path is required"});let r=await c(t.storeId,"delete",{path:e.path.trim()});return JSON.stringify({...r,store:t.name,storeId:t.storeId})}case"sqlite_exec":case"sqlite_query":{let t=a(e?.store);if(t.error)return JSON.stringify({error:t.error});if(typeof e?.sql!="string"||!e.sql.trim())return JSON.stringify({error:"sql is required (a non-empty SQL string)"});let r={sql:e.sql};Array.isArray(e?.params)&&(r.params=e.params);let s=await c(t.storeId,"sql",r);return JSON.stringify({...s,store:t.name,storeId:t.storeId})}default:return JSON.stringify({error:`Unknown tool: ${o}`})}}catch(t){return JSON.stringify({error:t.message})}},tools:[{name:"dataset_append",description:"Append ONE structured JSON record to a bound store, durably. Records persist across your stateless runs and are auto-tagged with your agent type so you can filter to your own writes later. Use to accumulate data you will query/aggregate (e.g. per-run metrics, processed items). Append ONE record per call.",input_schema:{type:"object",properties:{store:{type:"string",description:'The logical store NAME to write to (e.g. "scorecards"), taken from the AVAILABLE STORES list \u2014 pick by description. NOT an id. If exactly one store is bound you may omit this and it defaults to that store; you can ONLY write to a bound store name.'},record:{type:"object",description:'An arbitrary JSON object \u2014 one row of data. Its keys become queryable fields (e.g. {"repo":"owner/x","stars":1200}). One record per call.'},description:{type:"string",description:"Optional, informational note about this write. The store already exists from deploy, so this is not required and does not create anything."},agent:{type:"string",description:"Optional writing-agent tag. Defaults to your own agent type \u2014 leave unset to auto-tag."}},required:["record"]}},{name:"dataset_query",description:"Run a SQL-style query over a bound store to build reports: select/aggregate (count|sum|avg|min|max), filter, group, order, limit, and bound by month. Returns { columns, rows }. Use this to compute summaries/aggregations from records you appended earlier.",input_schema:{type:"object",properties:{store:{type:"string",description:'The logical store NAME to query (e.g. "scorecards"), taken from the AVAILABLE STORES list \u2014 pick by description. NOT an id. If exactly one store is bound you may omit this and it defaults to that store.'},select:{type:"array",description:"Columns to return. Each item is { field?, agg?, as? }. agg \u2208 count|sum|avg|min|max; omit field for count(*). Omit `select` entirely to return raw rows."},where:{type:"array",description:"Filters, ANDed. Each item is { field, op, value }; op \u2208 eq|ne|gt|gte|lt|lte|like. `field` is a JSON key of the stored record."},groupBy:{type:"array",description:"Field names to group by (array of strings) for aggregation."},orderBy:{type:"array",description:"Sort spec. Each item is { field|as, dir }; dir \u2208 asc|desc."},limit:{type:"number",description:"Maximum number of rows to return."},since:{type:"string",description:"Inclusive lower bound month, 'yyyy-MM' (e.g. '2026-01')."},until:{type:"string",description:"Inclusive upper bound month, 'yyyy-MM' (e.g. '2026-06')."},agent:{type:"string",description:"Filter to records written by one agent namespace. Omit to query across all writers."}},required:[]}},{name:"ensure_store",description:'Create (or reuse) a store ON DEMAND for THIS agent \u2014 use when you need a store that was NOT declared/bound at deploy. Idempotent by name and private to this agent: calling again with the same name returns the SAME store (safe to call at the start of every run). Returns { storeId }. For type "sqlite" you then define schema with sqlite_exec (CREATE TABLE IF NOT EXISTS) and read/write via sqlite_exec/sqlite_query using this name.',input_schema:{type:"object",properties:{name:{type:"string",description:'A short logical name for the store (e.g. "linkedin_posts"). Letters, digits, _ and - only.'},type:{type:"string",enum:["sqlite","dataset","file"],description:'Store type. "sqlite" (default) = a mutable relational DB whose schema YOU define with SQL. "dataset" = append-only JSON records for later aggregation/analytics. "file" = arbitrary file/blob storage by relative path (file_put/file_get/file_list/file_delete).'},description:{type:"string",description:"What this store is for (shown in the Storage UI)."}},required:["name"]}},{name:"sqlite_exec",description:"For SQLITE-type stores: run SQL that CHANGES data \u2014 CREATE TABLE (use IF NOT EXISTS), INSERT, UPDATE, DELETE (one or more statements in one call). The store is a real, mutable SQLite database that persists across your stateless runs. Returns { rowsModified, wrote }. Use this to build schema on the fly and to update rows / track changing state (e.g. a queue with a status column).",input_schema:{type:"object",properties:{store:{type:"string",description:"The logical store NAME (a sqlite-type store from AVAILABLE STORES) \u2014 pick by description. NOT an id. If exactly one store is bound you may omit this."},sql:{type:"string",description:'The SQL to run. May contain multiple statements separated by ";". Prefer CREATE TABLE IF NOT EXISTS for idempotent schema.'},params:{type:"array",description:'Optional positional bind params for a SINGLE parameterized statement (safe binding of values), e.g. sql "UPDATE t SET s=? WHERE id=?" with params ["done", 1].'}},required:["sql"]}},{name:"sqlite_query",description:"For SQLITE-type stores: run a read-only SELECT (optionally with `params` for safe binding) against the store's SQLite database. Returns { columns, rows }. Never changes data. Use to read back rows/state you stored earlier.",input_schema:{type:"object",properties:{store:{type:"string",description:"The logical store NAME (a sqlite-type store from AVAILABLE STORES) \u2014 pick by description. NOT an id. If exactly one store is bound you may omit this."},sql:{type:"string",description:"A single SELECT statement. Use ? placeholders + `params` for any values."},params:{type:"array",description:'Optional positional bind params for the SELECT, e.g. ["linkedin_personal"].'}},required:["sql"]}},{name:"file_put",description:"For FILE-type stores: write (or overwrite) ONE file at a relative path \u2014 raw JSON dumps, CSVs, images, snapshots, any blob you want to keep across your stateless runs. Text goes in `content`; binary goes base64-encoded in `contentBase64` (pass exactly one). Max 4 MiB per file. Overwriting the same path UPDATES the file. Returns { ok, path, size }.",input_schema:{type:"object",properties:{store:{type:"string",description:"The logical store NAME (a file-type store from AVAILABLE STORES) \u2014 pick by description. NOT an id. If exactly one store is bound you may omit this."},path:{type:"string",description:'Relative file path, e.g. "dumps/run-42.json" or "img/chart.png". Letters, digits, ".", "_", "-" and "/" only; no "..", no leading "/".'},content:{type:"string",description:"Text content (UTF-8). Use for JSON/CSV/text files."},contentBase64:{type:"string",description:"Base64-encoded binary content (images etc.). Alternative to `content`."},contentType:{type:"string",description:'Optional MIME type (e.g. "application/json", "image/png"). Defaults sensibly.'}},required:["path"]}},{name:"file_get",description:'For FILE-type stores: read ONE stored file back by its relative path. Text files come back as `content` (encoding "utf8"); binary files come back as `contentBase64` (encoding "base64"). Returns { path, size, contentType, lastModified, content|contentBase64, encoding }.',input_schema:{type:"object",properties:{store:{type:"string",description:"The logical store NAME (a file-type store from AVAILABLE STORES). If exactly one store is bound you may omit this."},path:{type:"string",description:"The relative file path to fetch (as listed by file_list / used in file_put)."}},required:["path"]}},{name:"file_list",description:'For FILE-type stores: list the stored files \u2014 each entry has { path, size, lastModified }. Optionally filter by a path `prefix` (e.g. "dumps/"). Paginated via `cursor` when there are more results.',input_schema:{type:"object",properties:{store:{type:"string",description:"The logical store NAME (a file-type store from AVAILABLE STORES). If exactly one store is bound you may omit this."},prefix:{type:"string",description:'Optional path prefix filter, e.g. "dumps/" or "reports/2026".'},limit:{type:"number",description:"Max entries to return (default/max 1000)."},cursor:{type:"string",description:"Pagination cursor from a previous file_list response (nextCursor)."}},required:[]}},{name:"file_delete",description:"For FILE-type stores: delete ONE stored file by its relative path. Returns { ok, path, deleted }. Errors if the path does not exist.",input_schema:{type:"object",properties:{store:{type:"string",description:"The logical store NAME (a file-type store from AVAILABLE STORES). If exactly one store is bound you may omit this."},path:{type:"string",description:"The relative file path to delete."}},required:["path"]}}]};export{w as __clearEnsuredStores,L as datasetStoreSkill};
package/dist/discord.d.ts CHANGED
@@ -1,3 +1,33 @@
1
+ /**
2
+ * Discord integration — low-level API-wrapper skill.
3
+ *
4
+ * Lets an agent post messages into a Discord server the user's bot has been
5
+ * invited to, and discover the channels it can post to. Talks the Discord
6
+ * REST API (v10) directly with a static BOT token — no MCP server of its own;
7
+ * served over the GENERIC skill MCP binary (bin/mcp-skill.mjs), exactly like
8
+ * linear.js / github.js.
9
+ *
10
+ * AUTH (single chokepoint: resolveDiscordAuth):
11
+ * 1. resolveIntegrationToken('discord') — the Zibby-cloud path. The backend
12
+ * stores the bot token on the account's provider='discord' integration
13
+ * row (paste-based connect) and returns { token, guildId } from
14
+ * GET /integrations/token/discord.
15
+ * 2. DISCORD_BOT_TOKEN env — the self-host / local fallback (same pattern
16
+ * as linear.js's LINEAR_API_KEY): when the env token is present it wins,
17
+ * so a self-hosted run never needs the Zibby cloud at all.
18
+ *
19
+ * Discord auth header semantics (https://discord.com/developers/docs):
20
+ * Authorization: Bot <token>
21
+ * A raw token pasted without the "Bot " prefix gets it added here.
22
+ *
23
+ * FAIL-SOFT: handleToolCall never throws — every error path returns
24
+ * JSON.stringify({ ok:false, error }) so a notify step can't crash a workflow.
25
+ *
26
+ * Discord hard limit: message `content` is capped at 2000 chars — longer text
27
+ * is CHUNKED into sequential messages (split on line boundaries when possible)
28
+ * rather than truncated or rejected.
29
+ */
30
+ export declare const DISCORD_MAX_CONTENT = 2000;
1
31
  /**
2
32
  * Split `text` into Discord-postable chunks of <= DISCORD_MAX_CONTENT chars.
3
33
  * Prefers newline boundaries so code blocks / paragraphs stay readable; falls
@@ -7,71 +37,5 @@
7
37
  * @param {number} [max=DISCORD_MAX_CONTENT]
8
38
  * @returns {string[]} non-empty chunks (empty input → []).
9
39
  */
10
- export function chunkDiscordContent(text: string, max?: number): string[];
11
- export const DISCORD_MAX_CONTENT: 2000;
12
- export namespace discordSkill {
13
- let id: string;
14
- let serverName: string;
15
- let allowedTools: string[];
16
- let requiresIntegration: "discord";
17
- let envKeys: string[];
18
- let description: string;
19
- let promptFragment: string;
20
- /**
21
- * Spawn spec for the GENERIC skill MCP server (bin/mcp-skill.mjs) pointed at
22
- * this module's discordSkill export — the model gets real mcp__discord__*
23
- * tools. Mirrors linear.js resolve() (see its docblock for the dist-relative
24
- * module-path rationale). Env allow-list: the self-host token/guild vars +
25
- * the backend-client vars resolveIntegrationToken needs in the child.
26
- */
27
- function resolve(): {
28
- command: any;
29
- args: any[];
30
- env: {};
31
- description: string;
32
- type?: undefined;
33
- alwaysLoad?: undefined;
34
- } | {
35
- type: string;
36
- command: string;
37
- args: any[];
38
- env: {};
39
- description: string;
40
- alwaysLoad: boolean;
41
- };
42
- function handleToolCall(name: any, args?: {}): Promise<string>;
43
- let tools: ({
44
- name: string;
45
- description: string;
46
- input_schema: {
47
- type: string;
48
- properties: {
49
- channelId: {
50
- type: string;
51
- description: string;
52
- };
53
- text: {
54
- type: string;
55
- description: string;
56
- };
57
- guildId?: undefined;
58
- };
59
- required: string[];
60
- };
61
- } | {
62
- name: string;
63
- description: string;
64
- input_schema: {
65
- type: string;
66
- properties: {
67
- guildId: {
68
- type: string;
69
- description: string;
70
- };
71
- channelId?: undefined;
72
- text?: undefined;
73
- };
74
- required?: undefined;
75
- };
76
- })[];
77
- }
40
+ export declare function chunkDiscordContent(text: any, max?: number): any[];
41
+ export declare const discordSkill: any;