@culvii/cli 0.0.7 → 0.0.8

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 (70) hide show
  1. package/COMMANDS.md +5 -5
  2. package/README.md +15 -6
  3. package/USAGE.md +11 -10
  4. package/dist/DeployView-D4UEXMDJ.js +2 -0
  5. package/dist/DevView-GPKSSOLA.js +2 -0
  6. package/dist/EnvView-3ZURMIZS.js +2 -0
  7. package/dist/{HelpView-YLCEPIFY.js → HelpView-E7HS4SVF.js} +1 -1
  8. package/dist/WhoamiView-TKSYSHQ2.js +2 -0
  9. package/dist/{WorkspaceView-RNFALIPM.js → WorkspaceView-ID7ZMBHV.js} +1 -1
  10. package/dist/{chunk-IRZMWFC3.js → chunk-IPETC2TK.js} +1 -1
  11. package/dist/index.js +33 -683
  12. package/dist/lib/evaluator.js +2 -2
  13. package/dist/login-OGOHEHFE.js +39 -0
  14. package/dist/{logout-TDZA462P.js → logout-BRUJBFUK.js} +1 -1
  15. package/dist/skill-bundle-7KYK5GBL.js +1377 -0
  16. package/package.json +9 -5
  17. package/skills/culvii/.culvii-skill.json +59 -0
  18. package/skills/culvii/SKILL.md +73 -0
  19. package/skills/culvii/agents/openai.yaml +4 -0
  20. package/skills/culvii/examples/agent-workflow.culvii.ts +24 -0
  21. package/skills/culvii/examples/complete-workflow.culvii.ts +37 -0
  22. package/skills/culvii/examples/output-surface.culvii.ts +45 -0
  23. package/skills/culvii/examples/wait-surface.culvii.ts +24 -0
  24. package/skills/culvii/references/agents.md +29 -0
  25. package/skills/culvii/references/authoring-files.md +21 -0
  26. package/skills/culvii/references/cli-guide.md +22 -0
  27. package/skills/culvii/references/cli-reference.md +184 -0
  28. package/skills/culvii/references/feedback-cycle.md +43 -0
  29. package/skills/culvii/references/integrations.md +13 -0
  30. package/skills/culvii/references/kit-api.md +35 -0
  31. package/skills/culvii/references/node-core-agent.md +27 -0
  32. package/skills/culvii/references/node-core-browser-automation.md +53 -0
  33. package/skills/culvii/references/node-core-code.md +28 -0
  34. package/skills/culvii/references/node-core-http.md +42 -0
  35. package/skills/culvii/references/node-core-if.md +26 -0
  36. package/skills/culvii/references/node-core-jwt.md +31 -0
  37. package/skills/culvii/references/node-core-set.md +24 -0
  38. package/skills/culvii/references/node-cron-trigger.md +25 -0
  39. package/skills/culvii/references/node-elasticsearch.md +39 -0
  40. package/skills/culvii/references/node-gmail-trigger.md +44 -0
  41. package/skills/culvii/references/node-gmail.md +57 -0
  42. package/skills/culvii/references/node-google-calendar.md +51 -0
  43. package/skills/culvii/references/node-google-docs.md +46 -0
  44. package/skills/culvii/references/node-manual-trigger.md +24 -0
  45. package/skills/culvii/references/node-microsoft-outlook-trigger.md +41 -0
  46. package/skills/culvii/references/node-microsoft-outlook.md +55 -0
  47. package/skills/culvii/references/node-microsoft-sharepoint.md +40 -0
  48. package/skills/culvii/references/node-s3.md +40 -0
  49. package/skills/culvii/references/node-slack-trigger.md +40 -0
  50. package/skills/culvii/references/node-slack.md +38 -0
  51. package/skills/culvii/references/node-twilio.md +39 -0
  52. package/skills/culvii/references/node-wait-timer.md +24 -0
  53. package/skills/culvii/references/node-webhook-trigger.md +24 -0
  54. package/skills/culvii/references/nodes-index.md +27 -0
  55. package/skills/culvii/references/runtime-values.md +36 -0
  56. package/skills/culvii/references/surface-authoring.md +27 -0
  57. package/skills/culvii/references/surface-display.md +390 -0
  58. package/skills/culvii/references/surface-feedback.md +41 -0
  59. package/skills/culvii/references/surface-input-actions.md +143 -0
  60. package/skills/culvii/references/surface-layout.md +97 -0
  61. package/skills/culvii/references/validation.md +18 -0
  62. package/skills/culvii/references/workflows.md +30 -0
  63. package/dist/DeployView-GEJNL26A.js +0 -2
  64. package/dist/DevView-SOPAMSZ4.js +0 -2
  65. package/dist/EnvView-MCZC2NBO.js +0 -2
  66. package/dist/WhoamiView-67HV2L5J.js +0 -2
  67. package/dist/chunk-MPKGJC7N.js +0 -2
  68. package/dist/login-G5QUR55L.js +0 -36
  69. /package/dist/{chunk-5NBKYMD7.js → chunk-56C3DFV2.js} +0 -0
  70. /package/dist/{chunk-JFIFRAAR.js → chunk-RS5GDTRN.js} +0 -0
@@ -0,0 +1,30 @@
1
+ # Workflows
2
+
3
+ Create steps with `new Step(config)`, connect them with `connectTo`, then pass every step to `new Workflow({ id, name, active?, steps })`. Step IDs and names must be unique within a workflow. Steps support `disabled`, `credentials`, `onError`, and `ui`; workflows and steps do not have a `description` field.
4
+
5
+ ```ts
6
+ const trigger = new Step({ id: 'trigger', name: 'Manual Trigger', type: 'manualTrigger' });
7
+ const set = new Step({
8
+ id: 'prepare', name: 'Prepare', type: 'core.set',
9
+ params: { values: { request: 'Review this account' } },
10
+ onError: 'stopWorkflow',
11
+ });
12
+ trigger.connectTo(set);
13
+ new Workflow({ id: 'review-workflow', name: 'Review Workflow', steps: [trigger, set] });
14
+ ```
15
+
16
+ `connectTo(next, { fromPort?, fromOutputIndex?, toInputIndex? })` defaults to port `main` and indexes `0`. For an `core.if`, output index `0` is true and `1` is false. List all connected steps in the workflow even when the graph branches.
17
+
18
+ Credentialed integration nodes require `credentials: { name, id }` on the Step. `pauseAfterExecution: true` pauses after any node; assigning a wait surface also enables it.
19
+
20
+ Workflow-tool target rules:
21
+
22
+ - Exactly one `manualTrigger`, unless `triggerNodeName` selects among multiple manual triggers.
23
+ - No `core.agent` step in a workflow invoked as a tool.
24
+ - Trigger workflows such as cron, webhook, and polling triggers are not workflow-tool targets.
25
+ - Every `workflowId` and `agentReferenceKey` must resolve in the collected resource graph.
26
+ - Maximum resource reference depth is 3. Valid examples are workflow → agent → workflow and agent → workflow → agent.
27
+
28
+ See [nodes-index.md](nodes-index.md) before choosing a node and open that node's page for exact props.
29
+
30
+ Further reading: [Workflow API](https://culvii.com/docs/sdk-reference/api-reference/workflow-api/) and [Executing workflows](https://culvii.com/docs/sdk-reference/workflows/execution/).
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import {a as a$4}from'./chunk-5NBKYMD7.js';import {a}from'./chunk-R67TA4FU.js';import {a as a$3}from'./chunk-FQVHJUX4.js';import {a as a$1}from'./chunk-JYNOILCD.js';import'./chunk-57XLDHK6.js';import {o,l,c,a as a$2,e,y,d,w}from'./chunk-YKFGEPLO.js';import'./chunk-YPLDPHHD.js';import'./chunk-7UWDMECF.js';import {useState,useEffect}from'react';import {useApp,useInput,Box,Text}from'ink';import {jsxs,jsx}from'react/jsx-runtime';function P(e){if(e.type==="surface")return "Marks inactive; published versions are retained.";let p=e.versionCount??1,a=e.activeVersion??e.previousVersion;return `Deletes all ${p} ${p===1?"version":"versions"}${a?`; active is v${a}`:""}.`}function I(e){if(e.type==="surface"){let d=e.activeVersion??e.previousVersion;return d?`active v${d}`:"active"}let p=e.executions??0,a=e.activeExecutions??0,c=e.activeVersion??e.previousVersion;return `${p} total, active${c?` v${c}`:""}: ${a} executions`}function G({state:e$1,onConfirm:p}){let{exit:a$5}=useApp(),[c$1,d$1]=useState(false);return useEffect(()=>{e$1.type==="confirming"&&d$1(e$1.allowDestroy);},[e$1]),useEffect(()=>{if(e$1.type==="success"||e$1.type==="no_changes"||e$1.type==="aborted"||e$1.type==="error"){let o=setTimeout(()=>a$5(),100);return ()=>clearTimeout(o)}},[e$1.type,a$5]),useInput((o,k)=>{e$1.type==="confirming"&&(o.toLowerCase()==="y"?p?.(true,c$1):o.toLowerCase()==="n"||k.escape?p?.(false,c$1):o.toLowerCase()==="d"&&e$1.plan.destroyed.length>0?d$1(true):o.toLowerCase()==="k"&&e$1.plan.destroyed.length>0&&d$1(false));}),jsxs(Box,{flexDirection:"column",children:[jsx(a,{command:"culvii",subcommand:"deploy"}),e$1.type==="planning"&&jsx(Box,{paddingLeft:2,children:jsx(a$1,{label:"Planning deploy\u2026"})}),e$1.type==="confirming"&&jsxs(Box,{flexDirection:"column",paddingLeft:2,gap:1,children:[jsxs(Box,{flexDirection:"column",children:[jsxs(Text,{color:o,children:["Plan for ",jsx(Text,{color:l,bold:true,children:e$1.env}),":"]}),jsxs(Box,{flexDirection:"column",marginTop:1,children:[e$1.plan.created.map(o$1=>jsxs(Box,{flexDirection:"row",gap:1,children:[jsx(Text,{color:c,children:"+"}),jsx(Text,{color:l,children:o$1.slug}),jsx(Text,{color:o,children:"CREATED"})]},o$1.slug)),e$1.plan.versioned.map(o$1=>jsxs(Box,{flexDirection:"row",gap:1,children:[jsx(Text,{color:a$2,children:"~"}),jsx(Text,{color:l,children:o$1.slug}),jsxs(Text,{color:o,children:["VERSIONED (",I(o$1),")"]})]},o$1.slug)),e$1.plan.destroyed.map(o$1=>jsxs(Box,{flexDirection:"column",children:[jsxs(Box,{flexDirection:"row",gap:1,children:[jsx(Text,{color:e,children:"-"}),jsx(Text,{color:l,children:o$1.slug}),jsxs(Text,{color:o,children:[o$1.type==="surface"?"DEACTIVATE":"DELETE"," CANDIDATE (",I(o$1),")"]})]}),o$1.renameHint&&jsx(Box,{paddingLeft:2,children:jsxs(Text,{color:d,children:[y," Rename hint: ",o$1.renameHint]})})]},o$1.slug))]})]}),e$1.plan.destroyed.length>0&&jsxs(Box,{flexDirection:"column",children:[jsxs(Box,{flexDirection:"row",gap:1,children:[jsx(Text,{color:d,children:y}),jsx(Text,{color:l,children:"Missing resources:"}),jsx(Text,{color:c$1?e:c,bold:true,children:c$1?"delete":"keep active"})]}),!e$1.allowDestroy&&jsx(Text,{color:o,children:"Press d to delete all, k to keep active."}),c$1&&jsx(Box,{flexDirection:"column",marginTop:1,children:e$1.plan.destroyed.map(o=>jsxs(Text,{color:e,children:["- ",o.slug,": ",P(o)]},`delete-detail-${o.slug}`))})]}),jsxs(Box,{flexDirection:"row",gap:1,children:[jsx(Text,{color:o,children:"Deploy to "}),jsx(Text,{color:l,bold:true,children:e$1.env}),jsx(Text,{color:o,children:"?"}),jsx(Text,{color:a$2,bold:true,children:"[y/N]"})]})]}),e$1.type==="applying"&&jsx(Box,{paddingLeft:2,children:jsx(a$1,{label:"Applying\u2026"})}),e$1.type==="no_changes"&&jsx(Box,{paddingLeft:2,children:jsx(a$3.Dim,{children:"Nothing to deploy. All resources are up to date."})}),e$1.type==="aborted"&&e$1.reason==="user_cancelled"&&jsx(Box,{paddingLeft:2,children:jsx(a$3.Dim,{children:"Deployment cancelled."})}),e$1.type==="aborted"&&e$1.reason==="allow_destroy_required"&&jsx(Box,{paddingLeft:2,children:jsx(a$3.Dim,{children:"Aborted. Re-run with --allow-destroy to confirm destructive changes."})}),e$1.type==="error"&&jsxs(Box,{flexDirection:"column",paddingLeft:2,children:[jsx(a$3.Err,{children:e$1.message}),e$1.detail&&jsx(a$3.Dim,{children:e$1.detail})]}),e$1.type==="success"&&jsxs(Box,{flexDirection:"column",paddingLeft:2,gap:1,children:[jsxs(Box,{flexDirection:"row",gap:1,children:[jsx(Text,{color:c,children:w}),jsxs(Text,{color:l,bold:true,children:["Deployed to ",e$1.env]})]}),jsx(a$4,{variant:"ok",content:[{k:"created",v:jsxs(Text,{color:l,children:[e$1.created," resource(s)"]})},{k:"versioned",v:jsxs(Text,{color:l,children:[e$1.versioned," resource(s)"]})},{k:"destroyed",v:jsxs(Text,{color:l,children:[e$1.destroyed," resource(s)"]})}]}),jsxs(Box,{flexDirection:"column",children:[(e$1.createdItems||[]).map(o=>jsxs(Text,{color:c,children:["+ ",o.slug]},`created-${o.slug}`)),(e$1.versionedItems||[]).map(o=>jsxs(Text,{color:a$2,children:["~ ",o.slug]},`versioned-${o.slug}`)),(e$1.destroyedItems||[]).map(o=>jsxs(Text,{color:e,children:["- ",o.slug]},`destroyed-${o.slug}`)),(e$1.skippedDestroyedItems||[]).map(o$1=>jsxs(Text,{color:o,children:["k ",o$1.slug]},`skipped-${o$1.slug}`))]})]})]})}export{G as DeployView};
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import {a}from'./chunk-R67TA4FU.js';import {a as a$2}from'./chunk-FQVHJUX4.js';import {a as a$1}from'./chunk-JYNOILCD.js';import'./chunk-57XLDHK6.js';import {w,c,l,o,a as a$3,y,d}from'./chunk-YKFGEPLO.js';import'./chunk-YPLDPHHD.js';import'./chunk-7UWDMECF.js';import {useEffect}from'react';import {useApp,Box,Text}from'ink';import {jsxs,jsx}from'react/jsx-runtime';function C({state:o$1}){let{exit:g}=useApp();return useEffect(()=>{if(o$1.type==="error"||o$1.type==="disconnected"){let r=setTimeout(()=>g(),100);return ()=>clearTimeout(r)}},[o$1.type,g]),jsxs(Box,{flexDirection:"column",children:[jsx(a,{command:"culvii",subcommand:"dev"}),o$1.type==="provisioning"&&jsx(Box,{paddingLeft:2,children:jsx(a$1,{label:o$1.message})}),o$1.type==="error"&&jsx(Box,{flexDirection:"column",paddingLeft:2,children:jsx(a$2.Err,{children:o$1.message})}),o$1.type==="disconnected"&&jsx(Box,{paddingLeft:2,children:jsx(a$2.Dim,{children:"Disconnected. Draft state discarded."})}),o$1.type==="connected"&&jsxs(Box,{flexDirection:"column",paddingLeft:2,gap:1,children:[jsxs(Box,{flexDirection:"row",gap:1,children:[jsx(Text,{color:c,children:w}),jsx(Text,{color:l,bold:true,children:o$1.workspace}),jsx(Text,{color:o,children:"\xB7"}),jsx(Text,{color:a$3,children:o$1.env})]}),jsxs(Box,{flexDirection:"row",gap:1,children:[jsx(Text,{color:o,children:"Console:"}),jsx(Text,{color:a$3,children:o$1.consoleUrl})]}),jsx(a$2.Dim,{children:"Watching ./..."}),jsx(Box,{flexDirection:"column",gap:0,children:o$1.log.map((r,y$1)=>jsxs(Box,{flexDirection:"row",gap:1,children:[r.type==="synced"&&jsx(Text,{color:c,children:w}),r.type==="orphaned"&&jsx(Text,{color:c,children:w}),(r.type==="warning"||r.type==="error")&&jsx(Text,{color:d,children:y}),r.type==="info"&&jsx(Text,{color:o,children:"\xB7"}),r.timestamp&&jsxs(Text,{color:o,children:["[",r.timestamp,"]"]}),jsx(Text,{color:r.type==="warning"||r.type==="error"?d:o,children:r.message})]},y$1))})]})]})}export{C as DevView};
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import {a as a$2}from'./chunk-MPKGJC7N.js';import {a}from'./chunk-R67TA4FU.js';import {a as a$1}from'./chunk-FQVHJUX4.js';import {l,e,o,w as w$1,c,x as x$1}from'./chunk-YKFGEPLO.js';import'./chunk-YPLDPHHD.js';import'./chunk-7UWDMECF.js';import {useEffect}from'react';import {useApp,Box,Text}from'ink';import {jsxs,jsx}from'react/jsx-runtime';function D(e){return e==="prod"?"allow":e==="sandbox"?"warn":"info"}function x({env:e}){return jsx(a$2,{variant:D(e),children:e})}function w({envs:e}){return e.length===0?jsx(Text,{color:o,children:"none"}):jsx(Box,{flexDirection:"row",gap:1,children:e.map(t=>jsx(x,{env:t},t))})}function C({state:e$1}){let{exit:t}=useApp();return useEffect(()=>{let v=setTimeout(()=>t(),100);return ()=>clearTimeout(v)},[t]),jsxs(Box,{flexDirection:"column",children:[jsx(a,{command:"culvii",subcommand:"env"}),e$1.type==="show"&&jsxs(Box,{flexDirection:"column",paddingLeft:2,gap:1,children:[jsxs(Box,{flexDirection:"row",gap:1,children:[jsx(Text,{color:l,children:"current"}),jsx(x,{env:e$1.current}),!e$1.accessible.includes(e$1.current)&&jsx(Text,{color:e,children:"(no access)"})]}),jsxs(Box,{flexDirection:"row",gap:1,children:[jsx(Text,{color:o,children:"tenant:"}),jsx(Text,{color:l,children:e$1.tenant})]}),jsxs(Box,{flexDirection:"row",gap:1,children:[jsx(Text,{color:o,children:"available:"}),jsx(w,{envs:e$1.accessible})]}),!e$1.accessible.includes(e$1.current)&&e$1.accessible.length>0&&jsxs(a$1.Dim,{children:["To switch, run: culvii env ",e$1.accessible[0]]})]}),e$1.type==="success"&&jsxs(Box,{flexDirection:"column",paddingLeft:2,gap:1,children:[jsxs(Box,{flexDirection:"row",gap:1,children:[jsx(Text,{color:c,children:w$1}),jsx(Text,{color:l,bold:true,children:"Switched environment to"}),jsx(x,{env:e$1.env})]}),jsxs(a$1.Dim,{children:["tenant: ",e$1.tenant]})]}),e$1.type==="error"&&jsxs(Box,{flexDirection:"column",paddingLeft:2,children:[jsxs(Box,{flexDirection:"row",gap:1,children:[jsx(Text,{color:e,children:x$1}),jsx(Text,{color:l,children:e$1.message})]}),e$1.detail&&jsx(Box,{paddingLeft:2,children:jsx(a$1.Dim,{children:e$1.detail})})]})]})}export{C as EnvView};
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import {a as a$4}from'./chunk-MPKGJC7N.js';import {a as a$3}from'./chunk-5NBKYMD7.js';import {a}from'./chunk-R67TA4FU.js';import {a as a$2}from'./chunk-FQVHJUX4.js';import {a as a$1}from'./chunk-JYNOILCD.js';import'./chunk-57XLDHK6.js';import {x,e,l,w,c,o}from'./chunk-YKFGEPLO.js';import'./chunk-YPLDPHHD.js';import'./chunk-7UWDMECF.js';import {useEffect}from'react';import {useApp,Box,Text}from'ink';import {jsxs,jsx}from'react/jsx-runtime';function B(o){return o==="prod"?"allow":o==="sandbox"?"warn":"info"}function G({state:o$1}){let{exit:a$5}=useApp();return useEffect(()=>{if(o$1.type!=="loading"){let u=setTimeout(()=>a$5(),100);return ()=>clearTimeout(u)}},[o$1.type,a$5]),jsxs(Box,{flexDirection:"column",children:[jsx(a,{command:"culvii",subcommand:"whoami"}),o$1.type==="loading"&&jsx(Box,{paddingLeft:2,children:jsx(a$1,{label:"Fetching identity\u2026"})}),o$1.type==="error"&&jsxs(Box,{flexDirection:"column",paddingLeft:2,children:[jsxs(Box,{flexDirection:"row",gap:1,children:[jsx(Text,{color:e,children:x}),jsx(Text,{color:l,children:o$1.message})]}),o$1.detail&&jsx(Box,{paddingLeft:2,children:jsx(a$2.Dim,{children:o$1.detail})})]}),o$1.type==="success"&&jsxs(Box,{flexDirection:"column",gap:1,children:[jsxs(Box,{flexDirection:"row",gap:1,children:[jsx(Text,{color:c,children:w}),jsx(Text,{color:l,children:o$1.email})]}),jsx(a$3,{variant:"default",compact:true,content:[{k:"tenant",v:jsxs(Text,{color:l,children:[o$1.tenantName," ",jsxs(Text,{color:o,children:["(",o$1.tenant,")"]})]})},{k:"workspace",v:jsx(Text,{color:l,children:o$1.workspace||jsx(Text,{color:o,children:"none"})})},{k:"env",v:jsxs(Box,{flexDirection:"row",gap:1,children:[jsx(a$4,{variant:B(o$1.env),children:o$1.env}),!o$1.envAccessible&&jsx(Text,{color:e,children:"(no access)"})]})},{k:"access",v:o$1.accessibleEnvs.length>0?jsx(Text,{color:l,children:o$1.accessibleEnvs.join(", ")}):jsx(Text,{color:o,children:"none"})},{k:"roles",v:o$1.roles.length>0?jsx(Text,{color:l,children:o$1.roles.join(", ")}):jsx(Text,{color:o,children:"none"})}]})]})]})}export{G as WhoamiView};
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import {p,o,j,f as f$1,k,a,h,d,i,e,g,c}from'./chunk-YKFGEPLO.js';import {Box,Text}from'ink';import {jsx}from'react/jsx-runtime';var f={allow:{color:c,backgroundColor:g},healthy:{color:c,backgroundColor:g},deny:{color:e,backgroundColor:i},blocked:{color:e,backgroundColor:i},warn:{color:d,backgroundColor:h},throttled:{color:d,backgroundColor:h},accent:{color:a,backgroundColor:k},info:{color:f$1,backgroundColor:j},draft:{color:o,backgroundColor:p}};function T({variant:G,children:N}){let e=f[G];return jsx(Box,{flexDirection:"row",children:jsx(Box,{paddingX:1,backgroundColor:e.backgroundColor,children:jsx(Text,{color:e.color,bold:true,children:N})})})}export{T as a};
@@ -1,36 +0,0 @@
1
- #!/usr/bin/env node
2
- import {a as a$4}from'./chunk-JFIFRAAR.js';import {b,c,a as a$2}from'./chunk-KZG5CFSB.js';import {e,a,j,q,l,m,b as b$1,h,g,i,c as c$1,f}from'./chunk-IRZMWFC3.js';import {a as a$3}from'./chunk-HX54IFSD.js';import {a as a$1}from'./chunk-JYNOILCD.js';import'./chunk-57XLDHK6.js';import'./chunk-YKFGEPLO.js';import'./chunk-YPLDPHHD.js';import'./chunk-7UWDMECF.js';import ue from'open';import s from'react';import {render}from'ink';import j$1,{timingSafeEqual}from'crypto';import se from'http';import {jsx}from'react/jsx-runtime';function z(a){return a.toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function ne(){let a=j$1.randomBytes(64);return z(a)}function ae(a){let E=j$1.createHash("sha256").update(a).digest();return z(E)}function oe(){let a=j$1.randomBytes(32);return z(a)}var de=`<!DOCTYPE html>
3
- <html>
4
- <head>
5
- <meta charset="utf-8">
6
- <title>Login Successful</title>
7
- <style>
8
- body { font-family: system-ui, sans-serif; background: #000; color: #fff; text-align: center; padding: 4rem; }
9
- .success { color: #10B981; font-size: 48px; margin-bottom: 1rem; }
10
- p { color: #C4CAD4; }
11
- </style>
12
- </head>
13
- <body>
14
- <div class="success">\u2713</div>
15
- <h2>Authentication Successful</h2>
16
- <p>You can close this window and return to your terminal.</p>
17
- <script>window.close()</script>
18
- </body>
19
- </html>`,ie=`<!DOCTYPE html>
20
- <html>
21
- <head>
22
- <meta charset="utf-8">
23
- <title>Login Failed</title>
24
- <style>
25
- body { font-family: system-ui, sans-serif; background: #000; color: #fff; text-align: center; padding: 4rem; }
26
- .error { color: #EF4444; font-size: 48px; margin-bottom: 1rem; }
27
- p { color: #C4CAD4; }
28
- </style>
29
- </head>
30
- <body>
31
- <div class="error">\u2717</div>
32
- <h2>Authentication Failed</h2>
33
- <p>An error occurred during login. Check your terminal for details.</p>
34
- </body>
35
- </html>`;async function ce(){return new Promise((a,E)=>{let C=0,t=se.createServer(),_=()=>{if(C>=q.callbackPorts.length)return E(new Error("All callback ports are in use (52700\u201352709). Check for conflicting processes."));let p=q.callbackPorts[C];t.listen(p,"127.0.0.1");},F=p=>{p.code==="EADDRINUSE"?(C++,t.removeAllListeners(),t.close(),t=se.createServer(),t.on("error",F),t.once("listening",f),_()):E(p);},f=()=>{let p=t.address();if(!p||typeof p=="string")return t.close(),E(new Error("Failed to get server address"));let h=p.port,A=null,P=null,I=false,k=null;t.on("request",(c,o)=>{if(!I)try{let L=new URL(c.url||"/",`http://${c.headers.host}`);if(L.pathname===q.callbackPath){I=!0,k&&clearTimeout(k);let T=L.searchParams.get("code"),y=L.searchParams.get("state"),e=L.searchParams.get("error");if(e&&y){o.writeHead(200,{"Content-Type":"text/html",Connection:"close"}),o.end(ie),A?.({error:e,state:y}),t.close();return}if(T&&y){o.writeHead(200,{"Content-Type":"text/html",Connection:"close"}),o.end(de),A?.({code:T,state:y}),t.close();return}o.writeHead(400,{"Content-Type":"text/html",Connection:"close"}),o.end(ie),P?.(new Error("Invalid callback parameters")),t.close();}else o.writeHead(404),o.end();}catch{o.writeHead(500),o.end();}}),a({port:h,waitForCallback:()=>new Promise((c,o)=>{A=c,P=o,k=setTimeout(()=>{I||(I=true,t.close(),o(new Error("Callback timeout")));},300*1e3);})});};t.on("error",F),t.once("listening",f),_();})}function le({tenants:a,onSelect:E}){let C=a.map((t,_)=>({key:String(_+1),label:t.name||t.slug}));return jsx(a$4,{label:"You belong to multiple tenants. Please select one to set as active:",options:C,onSubmit:t=>{let _=a[parseInt(t)-1];_&&E(_);}})}async function Ue(){b.info("Login flow started"),await e(a.LOGIN_STARTED);try{let a$4=ne(),E=ae(a$4),C=oe(),t;try{t=await ce();}catch(e$1){b.error("Failed to start callback server",{error:e$1.message}),render(s.createElement(c,{state:{type:"login_error",message:"Login failed",detail:"Couldn't start local listener \u2014 check firewall or sandbox restrictions"}})),await e(a.LOGIN_FAILED,{reason:"callback_server_failed"}),await j(),process.exit(1);}let{port:_,waitForCallback:F}=t,f$1=new URL(`https://${q.cognitoDomain}/oauth2/authorize`);f$1.searchParams.set("client_id",q.clientId),f$1.searchParams.set("response_type","code"),f$1.searchParams.set("redirect_uri",`http://127.0.0.1:${_}/callback`),f$1.searchParams.set("code_challenge",E),f$1.searchParams.set("code_challenge_method","S256"),f$1.searchParams.set("state",C),f$1.searchParams.set("scope",q.scopes.join(" ")),await ue(f$1.toString()),b.info("Browser opened");let{unmount:p}=render(s.createElement(a$1,{label:"Waiting for browser authentication\u2026"})),h$1;try{h$1=await F(),b.info("Callback received");}catch(e){p(),b.error("Callback error",{error:e.message}),render(s.createElement(c,{state:{type:"login_error",message:"Login failed",detail:e.message}})),await j(),process.exit(1);}p(),"error"in h$1&&(h$1.error==="access_denied"?(b.warn("Login cancelled by user"),render(s.createElement(c,{state:{type:"login_error",message:"Login cancelled"}}))):(b.error("Auth server returned error",{error:h$1.error}),render(s.createElement(c,{state:{type:"login_error",message:"Login failed",detail:h$1.error}}))),await e(a.LOGIN_FAILED,{reason:h$1.error==="access_denied"?"user_cancelled":h$1.error}),await j(),process.exit(1));let A=Buffer.from(h$1.state),P=Buffer.from(C);(A.length!==P.length||!timingSafeEqual(A,P))&&(b.error("State mismatch in callback"),render(s.createElement(c,{state:{type:"login_error",message:"Login failed",detail:"Auth response mismatch \u2014 possible CSRF, aborting"}})),await e(a.LOGIN_FAILED,{reason:"state_mismatch"}),await j(),process.exit(1)),b.info("Token exchange initiated");let I=`https://${q.cognitoDomain}/oauth2/token`,k=new URLSearchParams;k.set("grant_type","authorization_code"),k.set("code",h$1.code),k.set("redirect_uri",`http://127.0.0.1:${_}/callback`),k.set("client_id",q.clientId),k.set("code_verifier",a$4);let R;try{R=await fetch(I,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:k.toString()});}catch(e$1){b.error("Network error during token exchange",{error:e$1.message}),render(s.createElement(c,{state:{type:"login_error",message:"Login failed",detail:"Could not reach auth server \u2014 check your connection"}})),await e(a.LOGIN_FAILED,{reason:"network_error"}),await j(),process.exit(1);}let c$2=await R.json();if(!R.ok||c$2.error==="invalid_grant"){let e$1=c$2.error_description||c$2.error||"Unknown error";b.error("Token exchange failed",{reason:e$1}),render(s.createElement(c,{state:{type:"login_error",message:"Login failed",detail:`Token exchange failed: ${e$1}`}})),await e(a.LOGIN_FAILED,{reason:"token_exchange_failed"}),await j(),process.exit(1);}let o=Date.now(),L=o+c$2.expires_in*1e3;b.info("Token exchange succeeded",{expiresAt:L});let T=new a$2;await T.withLock(async()=>{await T.set({accessToken:c$2.access_token,refreshToken:c$2.refresh_token,idToken:c$2.id_token,expiresAt:L,tokenType:"Bearer",scope:q.scopes.join(" "),issuedAt:o,issuer:`https://${q.cognitoDomain}`});}),b.info("Tokens persisted"),b.info("/auth/me called");let y;try{y=await fetch(`${q.apiBaseUrl}/auth/me`,{headers:{Authorization:`Bearer ${c$2.access_token}`}});}catch(e){b.warn("Network error fetching identity details",{error:e.message}),render(s.createElement(c,{state:{type:"login_warning",message:"Logged in \u2014 could not verify identity with backend"}})),await j(),process.exit(0);}if(b.info("/auth/me result",{status:y.status}),y.status===401&&(render(s.createElement(c,{state:{type:"login_warning",message:"Logged in \u2014 could not verify identity with backend"}})),await j(),process.exit(0)),y.status===403&&(b.warn("Login rejected \u2014 user not invited"),await T.delete(),render(s.createElement(c,{state:{type:"login_error",message:"Login failed",detail:"You must be invited to use Culvii CLI. Contact your administrator."}})),await e(a.LOGIN_FAILED,{reason:"not_invited"}),await j(),process.exit(1)),y.ok){let e$1=await y.json(),N=e$1.tenants||(e$1.tenant?[e$1.tenant]:[]),l$1=N[0];if(N.length>1&&(l$1=await new Promise(S=>{let{unmount:O}=render(s.createElement(le,{tenants:N,onSelect:b=>{O(),S(b);}}));})),l$1){let S=new a$3;await S.withLock(async()=>{let b=null;try{b=await S.read({exitOnError:!1});}catch{b=null;}let r=b?.contexts||{};for(let x of N){let d=x.slug||x.id,V=(x.environments||[]).map(D=>D.slug),G=Object.fromEntries((x.environments||[]).map(D=>[l(D.slug)??D.slug,D.id])),$=m(V)??"dev";r[d]?(r[d].tenant_id=x.id,r[d].tenant_slug=d,r[d].environment_ids={...r[d].environment_ids||{},...G},V.some(M=>l(M)===r[d].environment)||(r[d].environment=$),r[d].environment_id=r[d].environment_ids?.[r[d].environment]??r[d].environment_id):r[d]={tenant_id:x.id,tenant_slug:d,workspace_id:null,workspace_slug:null,environment:$,environment_id:G[$],environment_ids:G,workspace_ids:{},workspace_slugs:{},api_keys:{}};}for(let x of Object.keys(r))e$1.user_id&&(r[x].user_id=e$1.user_id);let B=l$1.slug||l$1.id;await S.write({version:b?.version??1,active:B,contexts:r});});let O=await b$1();e$1.user_id?(await h(e$1.user_id,O),await g(e$1.user_id,{email:e$1.email,name:e$1.name}),l$1&&await i(e$1.user_id,l$1.id,{name:l$1.name,slug:l$1.slug}),c$1(),await f(a.LOGIN_SUCCEEDED,e$1.user_id,l$1?.id??null,{})):await e(a.LOGIN_SUCCEEDED),await j();}let Y=e$1.roles||[];if(l$1){let S=(l$1.environments||[]).map(r=>r.slug),O=m(S),b=(l$1.environments||[]).find(r=>l(r.slug)===O);if(b)try{let r=await fetch(`${q.apiBaseUrl}/auth/me`,{headers:{Authorization:`Bearer ${c$2.access_token}`,"x-tenant-id":l$1.id,"x-environment-id":b.id}});if(r.ok){let B=await r.json();Array.isArray(B.roles)&&(Y=B.roles);}}catch{}}render(s.createElement(c,{state:{type:"login_success",email:e$1.email||"N/A",tenant:l$1?.name||"N/A",roles:Y}}));}else render(s.createElement(c,{state:{type:"login_warning",message:"Logged in \u2014 could not verify identity with backend"}}));}catch(a$1){b.error("Unexpected error during login",{error:a$1.message}),render(s.createElement(c,{state:{type:"login_error",message:"Login failed",detail:"An unexpected error occurred during login."}})),await e(a.LOGIN_FAILED,{reason:"unexpected_error"}),await j(),process.exit(1);}}
36
- export{Ue as login};
File without changes
File without changes