@zibby/cli 0.2.1 → 0.4.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 (44) hide show
  1. package/README.md +117 -16
  2. package/dist/bin/zibby.js +3 -3
  3. package/dist/commands/chat-agents.js +1 -1
  4. package/dist/commands/chat.js +62 -62
  5. package/dist/commands/credentials-api.js +1 -1
  6. package/dist/commands/credentials-file.js +1 -1
  7. package/dist/commands/creds.js +1 -1
  8. package/dist/commands/init.js +180 -82
  9. package/dist/commands/memory.js +48 -20
  10. package/dist/commands/run.js +52 -55
  11. package/dist/commands/template.js +9 -0
  12. package/dist/commands/uninstall.js +15 -14
  13. package/dist/commands/workflows/agent-helpers.js +7 -7
  14. package/dist/commands/workflows/generate.js +54 -32
  15. package/dist/commands/workflows/run-local.js +19 -19
  16. package/dist/commands/workflows/run.js +5 -5
  17. package/dist/commands/workflows/start.js +12 -12
  18. package/dist/package.json +2 -2
  19. package/dist/templates/zibby-workflow-claude/agents-md-block.md +65 -5
  20. package/dist/templates/zibby-workflow-claude/claude/agents/zibby-test-author.md +16 -1
  21. package/dist/templates/zibby-workflow-claude/claude/agents/zibby-workflow-builder.md +22 -2
  22. package/dist/templates/zibby-workflow-claude/claude/commands/zibby-add-node.md +1 -1
  23. package/dist/templates/zibby-workflow-claude/claude/commands/zibby-debug.md +1 -1
  24. package/dist/templates/zibby-workflow-claude/claude/commands/zibby-delete.md +1 -1
  25. package/dist/templates/zibby-workflow-claude/claude/commands/zibby-deploy.md +24 -14
  26. package/dist/templates/zibby-workflow-claude/claude/commands/zibby-list.md +2 -2
  27. package/dist/templates/zibby-workflow-claude/claude/commands/zibby-memory-cost.md +39 -0
  28. package/dist/templates/zibby-workflow-claude/claude/commands/zibby-memory-pull.md +47 -0
  29. package/dist/templates/zibby-workflow-claude/claude/commands/zibby-memory-remote-use-hosted.md +61 -0
  30. package/dist/templates/zibby-workflow-claude/claude/commands/zibby-memory-stats.md +38 -0
  31. package/dist/templates/zibby-workflow-claude/claude/commands/zibby-static-ip.md +8 -6
  32. package/dist/templates/zibby-workflow-claude/claude/commands/zibby-tail.md +1 -1
  33. package/dist/templates/zibby-workflow-claude/claude/commands/zibby-test-debug.md +2 -2
  34. package/dist/templates/zibby-workflow-claude/claude/commands/zibby-test-generate.md +1 -1
  35. package/dist/templates/zibby-workflow-claude/claude/commands/zibby-test-run.md +3 -2
  36. package/dist/templates/zibby-workflow-claude/claude/commands/zibby-test-write.md +1 -1
  37. package/dist/templates/zibby-workflow-claude/claude/commands/zibby-trigger.md +10 -6
  38. package/dist/templates/zibby-workflow-claude/cursor/rules/zibby-workflows.mdc +76 -13
  39. package/dist/templates/zibby-workflow-claude/manifest.json +5 -1
  40. package/dist/utils/agent-credentials.js +4 -3
  41. package/dist/utils/apply-memory-sync-config.js +1 -0
  42. package/dist/utils/credentials-loader.js +1 -1
  43. package/dist/utils/hosted-memory-sync.js +1 -0
  44. package/package.json +2 -2
@@ -1,46 +1,106 @@
1
- <!-- zibby-template-version: 2 -->
1
+ <!-- zibby-template-version: 4 -->
2
2
  ---
3
- description: Help the user build, test, and deploy Zibby agent workflows
3
+ description: Help the user build, test, and deploy Zibby agent workflows + browser tests
4
4
  globs:
5
5
  - "**/.zibby/workflows/**"
6
6
  - ".zibby.config.mjs"
7
7
  - "**/workflow.json"
8
8
  - "**/graph.mjs"
9
+ - "test-specs/**"
10
+ - ".zibby/memory/**"
9
11
  alwaysApply: false
10
12
  ---
11
13
 
12
- # Zibby agent workflows
14
+ # Zibby workflows + tests
13
15
 
14
- This project contains one or more **Zibby workflows** graphs of AI-agent-driven steps that run inside an ECS Fargate sandbox in Zibby Cloud.
16
+ This project uses **Zibby**. Two surfaces share `.zibby.config.mjs` at the project root.
15
17
 
16
- ## Anatomy
18
+ ## Workflows
19
+
20
+ A graph of AI-agent-driven steps that runs inside an ECS Fargate sandbox.
17
21
 
18
22
  ```
19
23
  <workflowsBasePath>/<workflow-name>/
20
- ├── workflow.json # name, entryClass, triggers, schemas
24
+ ├── workflow.json # name, entryClass, triggers, schemas (manifest)
21
25
  ├── graph.mjs # exports the graph (nodes + edges)
22
- ├── nodes/ # one .mjs file per node
26
+ ├── nodes/ # one .mjs file per node, plus index.mjs barrel
23
27
  └── package.json # deps bundled at deploy time
24
28
  ```
25
29
 
26
30
  Each node exports `{ id, description, async run(ctx) }`. `ctx` provides `input`, `agent({prompt, schema})`, `shell(cmd)`, `log(...)`.
27
31
 
28
- ## Common dev loop
32
+ ### Common dev loop
29
33
 
30
34
  ```
31
- zibby workflow run <name> # one-shot local run (mirrors trigger flags)
32
- zibby workflow deploy <name> # build + push to cloud
33
- zibby workflow trigger <uuid> # invoke the cloud workflow
34
- zibby workflow logs <uuid> -t # tail live logs (docker-compose style for concurrent runs)
35
+ zibby workflow new <name> # scaffold
36
+ zibby workflow run <name> # one-shot local run (preferred for the dev loop)
37
+ zibby workflow deploy <name> # build + push to cloud
38
+ zibby workflow trigger <uuid> # invoke the cloud workflow
39
+ zibby workflow logs <uuid> -t # tail live logs (docker-compose-style for concurrent runs)
40
+ zibby workflow list # local + cloud
41
+ zibby workflow download <uuid> # pull cloud source back to .zibby/workflows/
42
+ zibby workflow delete <uuid> # remove a deployed workflow
35
43
  ```
36
44
 
37
- ## Adding a new node
45
+ `run` (one-shot) vs `start` (long-lived dev server, port 3848 — Studio integration). For plain CLI iteration always use `run`.
46
+
47
+ `run` and `trigger` accept the same input flags: `-p key=value` (highest precedence, repeatable), `--input '<json>'`, `--input-file path.json` (lowest precedence).
48
+
49
+ ### Adding a new node
38
50
 
39
51
  1. Create `<workflow>/nodes/<name>.mjs` (mirror existing `example.mjs` pattern)
40
52
  2. Register in `<workflow>/nodes/index.mjs`
41
53
  3. Wire into `<workflow>/graph.mjs` (add to `nodes` array and connect via edges)
42
54
  4. `zibby workflow run <name>` to test locally; `zibby workflow deploy` to push
43
55
 
56
+ ### Per-workflow env vars
57
+
58
+ Each deployed workflow has its own encrypted env-var bag (KMS-backed); workflow env wins over project secrets on conflict.
59
+
60
+ ```
61
+ zibby workflow env list <uuid> # show key names (values never returned)
62
+ zibby workflow env set <uuid> ANTHROPIC_API_KEY=sk-… # add or rotate one
63
+ zibby workflow env unset <uuid> OLD_KEY # remove one
64
+ zibby workflow env push <uuid> --file .env [--file .env.prod] # bulk replace
65
+ ```
66
+
67
+ Fast path on first deploy: `zibby workflow deploy my-pipeline --env .env` deploys, then auto-pushes the .env into the new UUID.
68
+
69
+ ## Tests (`zibby test`)
70
+
71
+ Plain-language `.txt` specs at `test-specs/`. The runner drives a real browser via MCP, generates Playwright, produces a video.
72
+
73
+ ```
74
+ zibby test test-specs/<name>.txt # run a spec
75
+ zibby test "go to example.com and ..." # inline, no file
76
+ zibby test <spec> --agent claude # override agent (claude|cursor|codex|gemini)
77
+ zibby test --sources <ids> --execution <id> # cloud test cases
78
+ ```
79
+
80
+ When debugging, `test-results/<spec>/video.webm` usually tells you what went wrong faster than logs.
81
+
82
+ ### Test memory (`.zibby/memory/.dolt/`)
83
+
84
+ Local-first Dolt SQL DB that learns selectors, page model, navigation, history from every run. Keyed **per-domain** (cross-spec). Auto-pulls before runs, auto-pushes after passing runs.
85
+
86
+ When `zibby test` runs and `.dolt/` exists, the agent gets 5 MCP tools auto-exposed:
87
+ - `memory_get_test_history` — recent runs (filter by spec-path substring)
88
+ - `memory_get_selectors` — known selectors per page with stability metrics
89
+ - `memory_get_page_model` — page elements, roles, accessible names
90
+ - `memory_get_navigation` — page-to-page transitions
91
+ - `memory_save_insight` — save observations (`selector_tip | timing | navigation | workaround | flaky | general`)
92
+
93
+ **After completing a test, the agent MUST call `memory_save_insight` at least once** — record reliable selectors, timing quirks, workarounds.
94
+
95
+ Local CLI: `zibby memory stats | cost | compact | reset`.
96
+
97
+ Team sync (BYO or hosted):
98
+ ```
99
+ zibby memory remote add aws://my-bucket/team/proj/main # BYO (S3 / GCS / DoltHub / file:///)
100
+ zibby memory remote use --hosted # OR: Zibby-managed S3 (signed-in only)
101
+ ```
102
+ Set `memorySync.remote` in `.zibby.config.mjs` (`'hosted'` or `'aws://...'`) so teammates running `zibby init` plug into the same memory automatically.
103
+
44
104
  ## Reference
45
105
 
46
106
  Canonical, evolving docs: **https://docs.zibby.app/workflows**
@@ -49,8 +109,11 @@ Topics:
49
109
  - Node SDK (ctx.agent / ctx.shell / ctx.log): https://docs.zibby.app/workflows/sdk
50
110
  - Deploying & bundling: https://docs.zibby.app/workflows/deploying
51
111
  - Triggering & inputs: https://docs.zibby.app/workflows/triggers
112
+ - Per-workflow env vars: https://docs.zibby.app/cloud/env-vars
52
113
  - Live log streaming: https://docs.zibby.app/workflows/logs
53
114
  - Egress proxy / static IPs: https://docs.zibby.app/workflows/egress
54
115
  - Security & secrets: https://docs.zibby.app/workflows/security
116
+ - Test memory: https://docs.zibby.app/tests/memory
117
+ - Tests — running: https://docs.zibby.app/tests/running
55
118
 
56
119
  Prefer the docs URL for anything you're unsure about — they're updated more frequently than these rules.
@@ -1,5 +1,5 @@
1
1
  {
2
- "templateVersion": 3,
2
+ "templateVersion": 4,
3
3
  "description": "Canonical agent helpers for Zibby workflows. Each shipped file carries '<!-- zibby-template-version: N -->' for idempotent upgrades. Bumped on breaking content changes.",
4
4
  "agents": {
5
5
  "claude": {
@@ -16,6 +16,10 @@
16
16
  ".claude/commands/zibby-test-write.md",
17
17
  ".claude/commands/zibby-test-generate.md",
18
18
  ".claude/commands/zibby-test-debug.md",
19
+ ".claude/commands/zibby-memory-stats.md",
20
+ ".claude/commands/zibby-memory-cost.md",
21
+ ".claude/commands/zibby-memory-pull.md",
22
+ ".claude/commands/zibby-memory-remote-use-hosted.md",
19
23
  ".claude/agents/zibby-workflow-builder.md",
20
24
  ".claude/agents/zibby-test-author.md"
21
25
  ],
@@ -1,3 +1,4 @@
1
- import{existsSync as a,readFileSync as f,writeFileSync as b,mkdirSync as h}from"fs";import{join as i}from"path";import{homedir as u}from"os";var m={cursor:{envVar:"CURSOR_API_KEY",label:"Cursor API Key",url:"https://cursor.com/settings"},claude:{envVar:"ANTHROPIC_API_KEY",label:"Anthropic API Key",url:"https://console.anthropic.com/settings/keys"},codex:{envVar:"OPENAI_API_KEY",label:"OpenAI API Key",url:"https://platform.openai.com/api-keys"},gemini:{envVar:"GEMINI_API_KEY",label:"Gemini API Key",url:"https://aistudio.google.com/app/apikey"}};function v(){return i(u(),".zibby","config.json")}function A(){try{let n=v();return a(n)?JSON.parse(f(n,"utf-8")):{}}catch{return{}}}function V(n,r){let o=i(u(),".zibby");h(o,{recursive:!0});let t=v(),e=A(),s=r?m[r]:null;s&&((!e.agentKeys||typeof e.agentKeys!="object")&&(e.agentKeys={}),e.agentKeys[s.envVar]=String(n).trim()),delete e.agentApiKey,b(t,`${JSON.stringify(e,null,2)}
2
- `,"utf-8")}function I(n){let r=[i(n,".zibby.config.mjs"),i(u(),".zibby.config.mjs")];for(let o of r)if(a(o))try{let t=f(o,"utf-8");for(let e of["cursor","claude","codex","gemini"])if(new RegExp(`agent\\s*:\\s*\\{[^}]*${e}\\s*:`,"s").test(t))return e}catch{}return null}function _(n){let r=n||process.cwd(),o=I(r);if(!o)return;let t=m[o];if(!t||process.env[t.envVar])return;let e=[i(r,".env.local"),i(r,".env")];for(let l of e)if(a(l))try{for(let d of f(l,"utf-8").split(`
3
- `)){let c=d.trim();if(c.startsWith("#")||!c.includes("="))continue;let y=c.indexOf("="),K=c.slice(0,y).trim(),g=c.slice(y+1).trim();if(K===t.envVar&&g){process.env[t.envVar]=g;return}}}catch{}let p=A().agentKeys?.[t.envVar];p&&(process.env[t.envVar]=p)}export{m as AGENT_KEY_MAP,_ as bootstrapAgentEnv,I as detectAgentType,A as readGlobalConfig,V as saveAgentApiKey};
1
+ import{existsSync as _,readFileSync as l,writeFileSync as P,mkdirSync as I}from"fs";import{join as s}from"path";import{homedir as A}from"os";var u={cursor:{envVar:"CURSOR_API_KEY",label:"Cursor API Key",url:"https://cursor.com/settings"},claude:{envVar:"ANTHROPIC_API_KEY",label:"Anthropic API Key",url:"https://console.anthropic.com/settings/keys"},codex:{envVar:"OPENAI_API_KEY",label:"OpenAI API Key",url:"https://platform.openai.com/api-keys"},gemini:{envVar:"GEMINI_API_KEY",label:"Gemini API Key",url:"https://aistudio.google.com/app/apikey"}};function g(){return s(A(),".zibby","config.json")}function p(){try{let e=g();return _(e)?JSON.parse(l(e,"utf-8")):{}}catch{return{}}}function h(e,t){let n=t?u[t]:null;n&&d(n.envVar,e)}function d(e,t){if(!e||typeof e!="string"||!t||typeof t!="string")return;let n=s(A(),".zibby");I(n,{recursive:!0});let i=g(),o=p();(!o.agentKeys||typeof o.agentKeys!="object")&&(o.agentKeys={}),o.agentKeys[e]=String(t).trim(),delete o.agentApiKey,P(i,`${JSON.stringify(o,null,2)}
2
+ `,"utf-8")}function R(e){let t=p();return!t.agentKeys||!(e in t.agentKeys)?!1:(delete t.agentKeys[e],P(g(),`${JSON.stringify(t,null,2)}
3
+ `,"utf-8"),!0)}var m={claude:["ANTHROPIC_API_KEY","ANTHROPIC_API_KEY_POOL","CLAUDE_CODE_OAUTH_TOKEN","CLAUDE_CODE_OAUTH_TOKEN_POOL","ANTHROPIC_AUTH_TOKEN","ANTHROPIC_AUTH_TOKEN_POOL"],cursor:["CURSOR_API_KEY","CURSOR_API_KEY_POOL"],codex:["OPENAI_API_KEY","OPENAI_API_KEY_POOL"],gemini:["GEMINI_API_KEY","GEMINI_API_KEY_POOL","GOOGLE_API_KEY"]};function N(e){let t=[s(e,".zibby.config.mjs"),s(A(),".zibby.config.mjs")];for(let n of t)if(_(n))try{let i=l(n,"utf-8");for(let o of["cursor","claude","codex","gemini"])if(new RegExp(`agent\\s*:\\s*\\{[^}]*${o}\\s*:`,"s").test(i))return o}catch{}return null}function Y(e){let t=e||process.cwd(),n=N(t);if(!n)return;let i=m[n]||(u[n]?[u[n].envVar]:[]);if(i.length===0)return;let o=(r,a)=>{!process.env[r]&&a&&(process.env[r]=String(a).trim())},y=[s(t,".env.local"),s(t,".env")];for(let r of y)if(_(r))try{for(let a of l(r,"utf-8").split(`
4
+ `)){let c=a.trim();if(c.startsWith("#")||!c.includes("="))continue;let O=c.indexOf("="),K=c.slice(0,O).trim(),E=c.slice(O+1).trim();i.includes(K)&&E&&o(K,E)}}catch{}let f=p();if(f.agentKeys&&typeof f.agentKeys=="object")for(let r of i)f.agentKeys[r]&&o(r,f.agentKeys[r])}export{u as AGENT_KEY_MAP,Y as bootstrapAgentEnv,N as detectAgentType,p as readGlobalConfig,R as removeCredential,h as saveAgentApiKey,d as saveCredential};
@@ -0,0 +1 @@
1
+ var m=[null,void 0,"","none","off",!1],f="hosted",d=["aws://","gs://","https://","http://","file://"];function y(r){if(!r||typeof r!="object")return{ok:!0,kind:"noop"};let e=r.remote;return m.includes(e)?{ok:!0,kind:"noop"}:typeof e!="string"?{ok:!1,error:`memorySync.remote must be null or a string, got ${typeof e}`}:e===f?{ok:!0,kind:"hosted"}:d.some(n=>e.startsWith(n))?{ok:!0,kind:"byo",remote:e}:{ok:!1,error:`memorySync.remote = ${JSON.stringify(e)} is not recognized. Use null, 'hosted', or a URL beginning with one of: ${d.join(" / ")}.`}}async function c({cwd:r,projectId:e,block:n,memoryApi:t,hostedSetup:i,getSessionToken:s,logger:u=console}){let o=y(n);if(!o.ok)return u.warn?.(`[memory-sync] config invalid: ${o.error}`),{action:"error",reason:o.error};if(o.kind==="noop")return{action:"skipped",reason:"memorySync.remote not set"};if(o.kind==="byo")return t?.memoryRemoteAdd?t.memoryRemoteAdd(r,o.remote)?{action:"byo",remote:o.remote}:{action:"error",reason:"memoryRemoteAdd returned false (memory DB not initialized?)"}:{action:"error",reason:"@zibby/ui-memory not loaded"};if(o.kind==="hosted"){if(typeof s=="function"&&!s())return{action:"pending-login",reason:'memorySync.remote = "hosted" but the user is not logged in. Run `zibby login` then `zibby memory remote use --hosted`.'};if(typeof i!="function")return{action:"error",reason:"hostedSetup function not provided"};try{return await i({cwd:r,projectId:e}),{action:"hosted"}}catch(a){return{action:"error",reason:`hosted setup failed: ${a.message}`}}}return{action:"error",reason:`unhandled kind: ${o.kind}`}}export{c as applyMemorySyncConfig,y as validateMemorySyncConfig};
@@ -1 +1 @@
1
- import O from"node:fs/promises";import C from"node:path";import v from"node:os";var E=C.join(v.homedir(),".zibby","credentials.env"),_={CLAUDE_CODE_OAUTH_TOKEN:"oauth",CLAUDE_CODE_OAUTH_TOKEN_POOL:"oauth",ANTHROPIC_AUTH_TOKEN:"oauth",ANTHROPIC_API_KEY:"api",ANTHROPIC_API_KEY_POOL:"api"};function m(a){if(!a)return[];let s=[],i=new Set,f=String(a).split(/\r?\n/);for(let u of f){let e=u.trim();if(!e||e.startsWith("#"))continue;let l=e.indexOf("=");if(l<1)continue;let o=e.slice(0,l).trim(),n=e.slice(l+1).trim();if((n.startsWith('"')&&n.endsWith('"')||n.startsWith("'")&&n.endsWith("'"))&&(n=n.slice(1,-1)),!n)continue;let r=_[o];if(!r)continue;let d=o.endsWith("_POOL")?n.split(",").map(t=>t.trim()).filter(Boolean):[n];for(let t of d)t.length<8||i.has(t)||(i.add(t),s.push({type:r,token:t,source_var:o}))}return s}async function A(a=E){let s;try{s=await O.readFile(a,"utf8")}catch(i){if(i.code==="ENOENT")return[];throw i}return m(s)}async function h({filepath:a,env:s=process.env}={}){let i=await A(a),f=new Set(i.map(e=>e.token)),u=[];for(let[e,l]of Object.entries(_)){let o=s[e];if(!o)continue;let n=e.endsWith("_POOL")?o.split(",").map(r=>r.trim()).filter(Boolean):[o];for(let r of n)r.length<8||f.has(r)||(f.add(r),u.push({type:l,token:r,source_var:e,source:"process.env"}))}return{file:i.map(e=>({...e,source:"file"})),env:u,all:[...i.map(e=>({...e,source:"file"})),...u]}}var p=!1,c=null;async function N(a={}){let{verbose:s=!1,force:i=!1,filepath:f}=a;if(p&&!i)return c;if(!!(process.env.CLAUDE_CODE_OAUTH_TOKEN_POOL||process.env.ANTHROPIC_API_KEY_POOL||process.env.CLAUDE_CODE_OAUTH_TOKEN||process.env.ANTHROPIC_API_KEY))return p=!0,c={oauthCount:0,apiCount:0,source:"cloud-env"},s&&console.log("[credentials-loader] env vars already set \u2014 skipping local discovery"),c;let e;try{e=await h(f?{filepath:f}:void 0)}catch(t){return s&&console.warn(`[credentials-loader] discovery failed: ${t.message}`),p=!0,c={oauthCount:0,apiCount:0,source:"none"},c}let l=e.all.filter(t=>t.type==="oauth").map(t=>t.token),o=e.all.filter(t=>t.type==="api").map(t=>t.token);l.length>0&&(process.env.CLAUDE_CODE_OAUTH_TOKEN_POOL=l.join(",")),o.length>0&&(process.env.ANTHROPIC_API_KEY_POOL=o.join(","));let n=e.file.length,r=e.env.length,d=n>0&&r>0?"local-file+shell-env":n>0?"local-file":r>0?"shell-env":"none";return p=!0,c={oauthCount:l.length,apiCount:o.length,source:d},s&&(l.length||o.length)&&console.log(`[credentials-loader] loaded ${l.length} OAuth + ${o.length} API from ${d} (~/.zibby/credentials.env)`),c}function I(){p=!1,c=null}export{I as _resetLoaderCacheForTests,N as loadCredentialsIntoEnv};
1
+ import A from"node:fs";import d from"node:path";import T from"node:os";var _=!1,s=null,C=["CLAUDE_CODE_OAUTH_TOKEN","CLAUDE_CODE_OAUTH_TOKEN_POOL","ANTHROPIC_AUTH_TOKEN","ANTHROPIC_AUTH_TOKEN_POOL"],E=["ANTHROPIC_API_KEY","ANTHROPIC_API_KEY_POOL"];async function u(){if(!(process.env.__ZIBBY_CLAUDE_PLAN||process.platform!=="darwin"||!(process.env.CLAUDE_CODE_OAUTH_TOKEN||process.env.CLAUDE_CODE_OAUTH_TOKEN_POOL||process.env.ANTHROPIC_AUTH_TOKEN)))try{let{execSync:n}=await import("node:child_process"),t=n('security find-generic-password -s "Claude Code-credentials" -w',{encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim();if(t){let O=JSON.parse(t)?.claudeAiOauth?.subscriptionType;O&&(process.env.__ZIBBY_CLAUDE_PLAN=O)}}catch{}}function N(r){try{if(!A.existsSync(r))return{};let n=A.readFileSync(r,"utf-8"),t=JSON.parse(n);return t&&t.agentKeys&&typeof t.agentKeys=="object"?t.agentKeys:{}}catch{return{}}}async function y(r={}){let{verbose:n=!1,force:t=!1,configPath:l}=r;if(_&&!t)return s;if(!!(process.env.CLAUDE_CODE_OAUTH_TOKEN_POOL||process.env.ANTHROPIC_API_KEY_POOL||process.env.CLAUDE_CODE_OAUTH_TOKEN||process.env.ANTHROPIC_API_KEY||process.env.ANTHROPIC_AUTH_TOKEN))return await u(),_=!0,s={oauthCount:0,apiCount:0,source:"cloud-env"},n&&console.log("[credentials-loader] env vars already set \u2014 skipping local discovery"),s;let p=l||d.join(T.homedir(),".zibby","config.json"),o=N(p),a="none",i=0,c=0;for(let e of C)o[e]&&!process.env[e]&&(process.env[e]=String(o[e]).trim(),a="config.json",e.endsWith("_POOL")?i+=String(o[e]).split(",").filter(f=>f.trim()).length:i+=1);for(let e of E)o[e]&&!process.env[e]&&(process.env[e]=String(o[e]).trim(),a="config.json",e.endsWith("_POOL")?c+=String(o[e]).split(",").filter(f=>f.trim()).length:c+=1);return await u(),_=!0,s={oauthCount:i,apiCount:c,source:a},n&&i+c>0&&console.log(`[credentials-loader] loaded ${i} OAuth + ${c} API from ${a} (~/.zibby/config.json)`),s}function K(){_=!1,s=null}export{K as _resetLoaderCacheForTests,y as loadCredentialsIntoEnv};
@@ -0,0 +1 @@
1
+ import{readFileSync as y,writeFileSync as f,existsSync as d,mkdirSync as S,chmodSync as w}from"fs";import{join as u}from"path";var x="memory-sync.json",C="memory-sync-creds.json",h=120*1e3;function c(r){let e=u(r,".zibby");return{dir:e,config:u(e,x),creds:u(e,C)}}function p(r){let{config:e}=c(r);if(!d(e))return null;try{let t=JSON.parse(y(e,"utf-8"));return t.mode!=="hosted"?null:t}catch{return null}}function K(r){return!!p(r)}function T(r,e){let{dir:t,config:n}=c(r);S(t,{recursive:!0}),f(n,JSON.stringify({mode:"hosted",projectId:e.projectId,bucket:e.bucket,prefix:e.prefix,doltUrl:e.doltUrl,configuredAt:new Date().toISOString()},null,2),"utf-8")}function b(r){let{config:e,creds:t}=c(r);for(let n of[e,t])if(d(n))try{f(n,"")}catch{}}function l(r){let{creds:e}=c(r);if(!d(e))return null;try{let t=JSON.parse(y(e,"utf-8"));return!t?.accessKeyId||!t?.secretAccessKey||!t?.sessionToken?null:t}catch{return null}}function m(r,e){let{dir:t,creds:n}=c(r);S(t,{recursive:!0}),f(n,JSON.stringify(e,null,2),"utf-8");try{w(n,384)}catch{}}function E(r){return r?.expiration?new Date(r.expiration).getTime()-Date.now()<h:!0}async function I({cwd:r,projectId:e,apiUrl:t,sessionToken:n,fetch:s=globalThis.fetch}){if(!e)throw new Error("refreshCredentials: projectId required");if(!t)throw new Error("refreshCredentials: apiUrl required");if(!n)throw new Error("refreshCredentials: sessionToken required (run `zibby login`)");let i=`${String(t).replace(/\/+$/,"")}/memory/sync-credentials`,a=await s(i,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({projectId:e})});if(!a.ok){let g=await a.text().catch(()=>"");throw new Error(`memory-sync credentials request failed (${a.status}): ${g||"no body"}`)}let o=await a.json();if(!o?.accessKeyId||!o?.secretAccessKey||!o?.sessionToken)throw new Error("memory-sync credentials response missing required fields");return m(r,{accessKeyId:o.accessKeyId,secretAccessKey:o.secretAccessKey,sessionToken:o.sessionToken,expiration:o.expiration||null,refreshedAt:new Date().toISOString()}),l(r)}async function A({cwd:r,apiUrl:e,sessionToken:t,fetch:n}){let s=p(r);if(!s)return null;let i=l(r);return(!i||E(i))&&(i=await I({cwd:r,projectId:s.projectId,apiUrl:e,sessionToken:t,fetch:n})),i}async function N({cwd:r,apiUrl:e,sessionToken:t,fetch:n}){let s=await A({cwd:r,apiUrl:e,sessionToken:t,fetch:n});return s?{AWS_ACCESS_KEY_ID:s.accessKeyId,AWS_SECRET_ACCESS_KEY:s.secretAccessKey,AWS_SESSION_TOKEN:s.sessionToken,AWS_REGION:process.env.AWS_REGION||"ap-southeast-2"}:null}var j={paths:c,readCreds:l,writeCreds:m,isExpiringSoon:E,REFRESH_HEADROOM_MS:h};export{j as __testing,N as buildDoltEnv,b as clearConfig,A as getActiveCredentials,K as isHosted,p as readConfig,I as refreshCredentials,T as writeConfig};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/cli",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "Zibby CLI - Test automation generator and runner",
5
5
  "type": "module",
6
6
  "bin": {
@@ -35,7 +35,7 @@
35
35
  "@aws-sdk/client-sqs": "^3.1038.0",
36
36
  "@zibby/agent-workflow": "^0.3.0",
37
37
  "@zibby/core": "^0.3.0",
38
- "@zibby/memory": "^0.1.5",
38
+ "@zibby/ui-memory": "^1.0.0",
39
39
  "@zibby/skills": "^0.1.11",
40
40
  "adm-zip": "^0.5.17",
41
41
  "chalk": "^5.3.0",