@lahat-group/cli 2.0.3 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +4 -4
- package/package.json +1 -1
- package/skill/SKILL.md +9 -8
package/dist/index.js
CHANGED
|
@@ -36,7 +36,7 @@ To authorize this CLI, visit:
|
|
|
36
36
|
`));return}catch(o){let a=(o instanceof j?await o.response.json().catch(()=>({})):{}).error;if(a==="authorization_pending")continue;if(a==="slow_down"||o instanceof j&&o.response.status===429){i+=5;continue}throw new Error(`Login failed: ${a??o.message}`)}}throw new Error("Login timed out. Run `wardrobe login` again.")}u();async function gt(n={}){let t=await C(x()?.accessToken??null).get("auth/me").json();p(t,!!n.json,()=>{process.stdout.write(`${t.displayName} <${t.email}> \u2014 account role: ${t.role}
|
|
37
37
|
`),t.agent&&process.stdout.write(`Agent key scopes: ${t.agent.scopes.join(", ")}
|
|
38
38
|
`)})}function bt(n={}){ht(),p({status:"logged_out"},!!n.json,()=>process.stdout.write(`Logged out.
|
|
39
|
-
`))}u();u();import{writeFileSync as Oe}from"fs";function w(){return C(x()?.accessToken??null)}function xe(n){let e=(n??"").replace(/\D/g,"");return e.startsWith("972")
|
|
39
|
+
`))}u();u();import{writeFileSync as Oe}from"fs";function w(){return C(x()?.accessToken??null)}function xe(n){let e=(n??"").replace(/\D/g,"");return e.startsWith("00")&&(e=e.slice(2)),e.startsWith("972")&&(e=e.slice(3)),e.replace(/^0+/,"")}async function yt(n,e={}){let t=await w().get(`projects/${n}`).json();p(t,!!e.json,()=>{process.stdout.write(`${t.id} ${t.name}
|
|
40
40
|
`),t.customer&&process.stdout.write(`customer: ${t.customer.customerName??"\u2014"} ${t.customer.phoneNumber??""}
|
|
41
41
|
`),t.createdBy&&process.stdout.write(`designer: ${t.createdBy.displayName??"\u2014"} (${t.createdBy.id??""})
|
|
42
42
|
`)})}async function wt(n,e={}){let t=await w().get(`projects/${n}/members`).json();p(t.members,!!e.json,()=>{for(let r of t.members)process.stdout.write(`${r.userId} ${r.role} ${r.displayName??r.email??""}
|
|
@@ -54,9 +54,9 @@ To authorize this CLI, visit:
|
|
|
54
54
|
`))}async function vt(n,e={}){let t=e.revision;t===void 0&&(t=(await w().get(`quotations/project/${n}`).json()).revisionNumber);let r=e.out??`quotation-${n}-rev${t}.pdf`,i=Buffer.from(await w().get(`quotations/project/${n}/revisions/${t}/pdf`).arrayBuffer());Oe(r,i),p({path:r,bytes:i.length},!!e.json,()=>process.stdout.write(`${r} ${i.length} bytes
|
|
55
55
|
`))}async function At(n,e={}){let t=e.out??`design-${n}.jpg`,r=Buffer.from(await w().get(`designs/${n}/thumbnail`).arrayBuffer());Oe(t,r),p({path:t,bytes:r.length},!!e.json,()=>process.stdout.write(`${t} ${r.length} bytes
|
|
56
56
|
`))}async function Et(n={}){let e={};n.limit!==void 0&&(e.limit=n.limit),n.since!==void 0&&(e.createdSince=n.since);let t=await w().get("users",{searchParams:e}).json();p(t.users,!!n.json,()=>{if(t.users.length===0){process.stdout.write(`no users
|
|
57
|
-
`);return}for(let r of t.users)process.stdout.write(`${r.id??""} ${r.email??""} ${r.displayName??""} ${r.role??""} ${r.createdAt??""}
|
|
57
|
+
`);return}for(let r of t.users)process.stdout.write(`${r.id??""} ${r.email??""} ${r.displayName??""} ${r.role??""} ${r.createdAt??""} ${r.phone??""}
|
|
58
58
|
`)})}async function St(n,e={}){if(!n)throw new Error("phone is required.");let t=await w().get("users/by-phone",{searchParams:{phone:n}}).json();p(t.users,!!e.json,()=>{if(t.users.length===0){process.stdout.write(`no matching user
|
|
59
|
-
`);return}for(let r of t.users)process.stdout.write(`${r.id??""} ${r.email??""} ${r.displayName??""} ${r.role??""}
|
|
59
|
+
`);return}for(let r of t.users)process.stdout.write(`${r.id??""} ${r.email??""} ${r.displayName??""} ${r.role??""} ${r.phone??""}
|
|
60
60
|
`)})}async function Pt(n={}){let e=await w().get("help-texts").json();p(e,!!n.json,()=>process.stdout.write(`${Object.keys(e).length} help text(s)
|
|
61
61
|
`))}function L(){return C(x()?.accessToken??null)}async function kt(n,e={}){let t=await v(n),r=await L().post("price",{json:{config:t}}).json();p(r,!!e.json,()=>process.stdout.write(`${r.total} ${r.currency}
|
|
62
62
|
`))}async function Rt(n={}){let e={};n.project?e.projectId=n.project:(n.limit!==void 0&&(e.limit=n.limit),n.since!==void 0&&(e.updatedSince=n.since));let t=await L().get("designs",{searchParams:e}).json();p(t.designs,!!n.json,()=>{if(t.designs.length===0){process.stdout.write(`no designs
|
|
@@ -72,5 +72,5 @@ To authorize this CLI, visit:
|
|
|
72
72
|
`))}async function Ht(n,e={}){if(!e.file&&!e.name)throw new Error("Nothing to update \u2014 pass --file <config> and/or --name <name>.");let t=Ce(),r=await t.get(`designs/${n}`).json(),i={};e.file&&(i.config=await v(e.file)),e.name&&(i.name=e.name),r.version!==void 0&&(i.version=r.version);let s=await t.put(`designs/${n}`,{json:i}).json();p(s,!!e.json,()=>process.stdout.write(`${s.id} v${s.version??"?"}
|
|
73
73
|
`))}u();import{fileURLToPath as Rr}from"url";import{dirname as It,join as R}from"path";import{homedir as Tr}from"os";import{existsSync as Nr,mkdirSync as qr,readdirSync as Hr,copyFileSync as Ir,statSync as Vr}from"fs";function Dr(){let n=It(Rr(import.meta.url));for(let e=0;e<6;e++){let t=R(n,"skill");if(Nr(R(t,"SKILL.md")))return t;n=It(n)}throw new Error("Bundled SKILL.md not found next to the CLI package")}function Fr(n){let e=n?R(process.cwd(),".claude"):R(Tr(),".claude");return R(e,"skills","wardrobe-configurator")}function Lr(n={}){let e=n.sourceDir??Dr(),t=n.targetDir??Fr(!!n.project);qr(t,{recursive:!0});let r=[];for(let i of Hr(e)){let s=R(e,i);Vr(s).isFile()&&(Ir(s,R(t,i)),r.push(i))}return{target:t,files:r}}function Vt(n){let e=Lr({project:n.project});p(e,!!n.json,()=>{process.stdout.write(`Installed ${e.files.length} file(s) to ${e.target}
|
|
74
74
|
`),process.stdout.write(`Restart Claude Code, then invoke /wardrobe-configurator
|
|
75
|
-
`)})}u();async function Ur(n){if(!(n instanceof j))return null;try{return await n.response.json()}catch{return null}}async function Dt(n,e){let t=await Ur(n);if(e)return JSON.stringify(t?{error:t.error??"request_failed",...t}:{error:n.message},null,2);if(!t)return`Error: ${n.message}`;let r=[t.error??"Request failed"];return t.detail&&r.push(t.detail),t.fix_hint&&r.push(`fix: ${t.fix_hint}`),t.issues&&r.push(JSON.stringify(t.issues)),`Error: ${r.join(" \u2014 ")}`}u();var Ft="2.0.
|
|
75
|
+
`)})}u();async function Ur(n){if(!(n instanceof j))return null;try{return await n.response.json()}catch{return null}}async function Dt(n,e){let t=await Ur(n);if(e)return JSON.stringify(t?{error:t.error??"request_failed",...t}:{error:n.message},null,2);if(!t)return`Error: ${n.message}`;let r=[t.error??"Request failed"];return t.detail&&r.push(t.detail),t.fix_hint&&r.push(`fix: ${t.fix_hint}`),t.issues&&r.push(JSON.stringify(t.issues)),`Error: ${r.join(" \u2014 ")}`}u();var Ft="2.0.4";y.name("wardrobe").description("Wardrobe configurator CLI").version(Ft);y.command("login").description("Authenticate via the OAuth device flow").option("--json","machine-readable output").action(n=>ft(n));y.command("whoami").description("Show the authenticated user").option("--json","machine-readable output").action(n=>gt(n));y.command("logout").description("Remove the stored agent key").option("--json","machine-readable output").action(n=>bt(n));y.command("init").description("Emit a fresh, valid WardrobeConfig JSON (via the API)").option("--width <cm>","total width in cm",n=>Number(n)).option("--height <cm>","height in cm",n=>Number(n)).option("--depth <cm>","depth in cm",n=>Number(n)).action(n=>dt(n));y.command("validate <file>").description("Validate a config against the live rules (file or - for stdin)").option("--json","machine-readable output").action((n,e)=>mt(n,e));y.command("describe <idOrFile>").description("Describe a config (local file/-) or saved design (id), via the API").option("--locale <locale>","en or he","en").option("--json","machine-readable output").action((n,e)=>pt(n,e));y.command("price <file>").description("Price a config via the API (file or - for stdin)").option("--json","machine-readable output").action((n,e)=>kt(n,e));y.command("plan <file>").description("Dry-run: price a config + BOM preview (mutates nothing)").option("--json","machine-readable output").action((n,e)=>qt(n,e));y.command("apply <file>").description("Save a config as a design (file or - for stdin)").requiredOption("--project <id>","project id").option("--name <name>","design name").option("--json","machine-readable output").action((n,e)=>$e(n,e));var K=y.command("designs").description("Manage saved designs");K.command("list").description("List designs in a project, or the newest across every project with --project omitted").option("--project <id>","project id").option("--limit <n>","cross-project mode only: max rows (default 20, max 100)",n=>Number(n)).option("--since <iso>","cross-project mode only: only designs updated at/after this ISO 8601 timestamp").option("--json","machine-readable output").action(n=>Rt(n));K.command("create <file>").description("Save a config as a new design in a project (same as `apply`)").requiredOption("--project <id>","project id").option("--name <name>","design name").option("--json","machine-readable output").action((n,e)=>$e(n,e));K.command("update <id>").description("Revise a saved design (config and/or name)").option("--file <file>","new config JSON (file or - for stdin)").option("--name <name>","new design name").option("--json","machine-readable output").action((n,e)=>Ht(n,e));K.command("thumbnail <id>").description("Download a design's thumbnail image").option("--out <file>","destination path").option("--json","machine-readable output").action((n,e)=>At(n,e));var ve=y.command("projects").description("Manage projects");ve.command("list").description("List accessible projects").option("--phone <number>","filter by the customer's phone number").option("--designer <idOrName>","filter by the designer who owns the project").option("--json","machine-readable output").action(n=>Nt(n));ve.command("get <id>").description("Show one project").option("--json","machine-readable output").action((n,e)=>yt(n,e));ve.command("members <id>").description("List a project's owner and members").option("--json","machine-readable output").action((n,e)=>wt(n,e));var Ae=y.command("customers").description("Read customers");Ae.command("list").description("List your customers").option("--json","machine-readable output").action(n=>_t(n));Ae.command("get <id>").description("Show one customer").option("--json","machine-readable output").action((n,e)=>jt(n,e));Ae.command("projects <id>").description("List a customer's projects").option("--json","machine-readable output").action((n,e)=>Ot(n,e));var Ee=y.command("orders").description("Read orders");Ee.command("list").description("List a project's orders, or the newest-updated across every project with --project omitted").option("--project <id>","project id").option("--open","only the project's active (non-cancelled) order (requires --project)").option("--limit <n>","cross-project mode only: max rows (default 20, max 100)",n=>Number(n)).option("--since <iso>","cross-project mode only: only orders updated at/after this ISO 8601 timestamp").option("--json","machine-readable output").action(n=>xt(n));Ee.command("get <id>").description("Show one order, with its designs embedded").option("--json","machine-readable output").action((n,e)=>Ct(n,e));Ee.command("pdf <id>").description("Download an order PDF").option("--out <file>","destination path").option("--json","machine-readable output").action((n,e)=>$t(n,e));var Lt=y.command("quotations").description("Read quotations (requires quotations:read)");Lt.command("list").description("Show a project's quote history, or the newest-generated across every project with --project omitted").option("--project <id>","project id").option("--limit <n>","cross-project mode only: max rows (default 20, max 100)",n=>Number(n)).option("--since <iso>","cross-project mode only: only quotations generated at/after this ISO 8601 timestamp").option("--json","machine-readable output").action(n=>Tt(n));Lt.command("pdf <projectId>").description("Download a quotation PDF (default: the project's current revision) \u2014 never mints a new one").option("--revision <n>","a specific historical revision instead of the current one",n=>Number(n)).option("--out <file>","destination path").option("--json","machine-readable output").action((n,e)=>vt(n,e));var Ut=y.command("users").description("Read registered accounts (requires staff:read)");Ut.command("list").description("List registered users, newest-registered first").option("--limit <n>","max rows (default 20, max 100)",n=>Number(n)).option("--since <iso>","only users registered at/after this ISO 8601 timestamp").option("--json","machine-readable output").action(n=>Et(n));Ut.command("by-phone <phone>").description("Find the account(s) whose own phone is this number (+972\u2026 and 05\u2026 forms match)").option("--json","machine-readable output").action((n,e)=>St(n,e));y.command("help-texts").description("Read the help-text table").option("--json","machine-readable output").action(n=>Pt(n));var Mr=y.command("skill").description("Manage the bundled Claude Skill");Mr.command("install").description("Install the wardrobe-configurator Skill for Claude Code").option("--project","install into ./.claude/skills instead of ~/.claude/skills").option("--json","machine-readable output").action(n=>Vt(n));y.parseAsync().catch(async n=>{let e=await Dt(n,process.argv.includes("--json"));process.stderr.write(`${e}
|
|
76
76
|
`),process.exit(1)});
|
package/package.json
CHANGED
package/skill/SKILL.md
CHANGED
|
@@ -102,7 +102,7 @@ answer `403 insufficient_scope` whoever signed in).
|
|
|
102
102
|
| `wardrobe quotations pdf <projectId> --revision <n> --out f.pdf` | A specific historical revision's PDF instead |
|
|
103
103
|
| `wardrobe users list` | Registered accounts, **newest-registered first** — staff only, see below |
|
|
104
104
|
| `wardrobe users list --limit <n>` `--since <ISO>` | Same, paged (`--since` filters by `createdAt >=`) — `--limit 5` with no `--since` is "the latest registered users"; omit both, paging with `--since` off the last row's timestamp, for "every user in the system" |
|
|
105
|
-
| `wardrobe users by-phone <number>` | The account(s)
|
|
105
|
+
| `wardrobe users by-phone <number>` | The account(s) whose **own** phone is that number (`+972…`, `05…`, `052-…` all match) — staff only |
|
|
106
106
|
| `wardrobe help-texts` | The help-text table |
|
|
107
107
|
|
|
108
108
|
`projects list` already returns each project's **customer and owning designer inline** —
|
|
@@ -143,13 +143,14 @@ your key isn't staff at all), `404` means it is gone.
|
|
|
143
143
|
|
|
144
144
|
`users list` / `users by-phone` read the `User` **account** table — designers, admins,
|
|
145
145
|
support and self-serve clients who can sign in — not the per-project `Customer` contact
|
|
146
|
-
card `wardrobe customers` reads.
|
|
147
|
-
|
|
148
|
-
**
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
146
|
+
card `wardrobe customers` reads. Each row carries the account's own `phone` (empty until
|
|
147
|
+
that user passes the onboarding phone step; staff never do). `users by-phone` matches
|
|
148
|
+
**only** that field: a customer's number never resolves to the designer who serves them,
|
|
149
|
+
so its answer is "who is this person", safe to act on as the caller's identity. Numbers
|
|
150
|
+
match as the national number, so `+972526665153` and `0526665153` are the same. More than
|
|
151
|
+
one row means the number is ambiguous (the field is self-declared, not unique) — say so
|
|
152
|
+
rather than picking one. Zero rows is normal and not an error; for the customer side of
|
|
153
|
+
the same number use `wardrobe projects list --phone <number>`.
|
|
153
154
|
|
|
154
155
|
### Not available here
|
|
155
156
|
|