@smartkomm/plexus-cli 0.1.4 → 0.1.5

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 (2) hide show
  1. package/dist/cli.mjs +2 -2
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -9698,7 +9698,7 @@ A task with --result closes only by recording it: freetext (text, always require
9698
9698
  `,"utf8");let w=[...r.rows,{step:"review",target:n.key,action:"written",detail:`expected of ${g.join(", ")} written into ${H.basename(n.file)} \u2014 review it, then run apply again to seal`}];return m.length>0&&w.push({step:"review",target:n.key,action:"differs",detail:`the draft now produces another output for ${m.join(", ")} than its reviewed expected \u2014 the seal will refuse it`}),{rows:w,revisionId:i,sealed:!1,reviewWritten:g}}await e.mutation(S.contractPackages.seal,{client:t,id:i,expectedSourceRevision:d});let u=await am(e,t,n);if(u.action!=="same")throw new Error(`${nt}: the sealed revision does not match the file (plan says ${u.action}).`);return{rows:r.rows,revisionId:i,sealed:!0,reviewWritten:[]}}s(h0,"applyPackageSetup");var ia=s(e=>e,"revisionId"),bx=s(e=>{let t=Number(e);if(!Number.isInteger(t)||t<0)throw new Error(`--source-revision must be a whole number (got ${e})`);return t},"sourceRevisionOf"),lm=s(e=>e.map(t=>({...t})),"tableRows"),kx=class extends Qe{static{s(this,"PackageListCommand")}static paths=[["generator","package","list"]];static usage=E.Usage({category:"Contracts",description:"List the tenant's contract packages with their current and draft revision",details:"Ids for `show`, `clone`, `seal` and `delete-draft` are revision ids; `archive` takes the package id.",examples:[["List packages","$0 --env staging --tenant <slug> generator package list"]]});async execute(){let{caller:t,client:n}=await this.loadContext(),i=(await t.query(S.contractPackages.model,{client:n})).map(o=>{let a=o.revisions.find(d=>d._id===o.currentRevisionId),l=o.revisions.find(d=>d.status==="draft");return{key:o.definition.key,packageId:o.definition._id,name:o.definition.name.de,current:a===void 0?null:{revisionId:a._id,revisionNumber:a.revisionNumber},draft:l===void 0?null:{revisionId:l._id,revisionNumber:l.revisionNumber,sourceRevision:l.sourceRevision},archived:o.definition.archivedAt!==void 0}});return this.print(i,o=>o.map(a=>({key:a.key,name:a.name,current:a.current===null?"\u2014":`${a.current.revisionNumber} (${a.current.revisionId})`,draft:a.draft===null?"\u2014":`${a.draft.revisionNumber} (${a.draft.revisionId}, source-revision ${a.draft.sourceRevision})`,archived:a.archived?"yes":""}))),0}},vx=class extends Qe{static{s(this,"PackageShowCommand")}static paths=[["generator","package","show"]];static usage=E.Usage({category:"Contracts",description:"Show one package revision: input mask, parts, scenarios and its source-revision counter",examples:[["Show a revision","$0 --env staging --tenant <slug> generator package show <revision-id>"]]});id=p.String({required:!0,name:"revision-id"});async execute(){let{caller:t,client:n}=await this.loadContext();return this.print(await t.query(S.contractPackages.detail,{client:n,id:ia(this.id)})),0}},xx=class extends Qe{static{s(this,"PackageCreateCommand")}static paths=[["generator","package","create"]];static usage=E.Usage({category:"Contracts",description:"Create an empty contract package (identity + draft revision 1)",details:"Usually `generator package apply --file` does this together with parts, code and scenarios. The key is 2\u201363 lowercase letters, digits or hyphens.",examples:[["Create a package","$0 --env staging --tenant <slug> generator package create --key school-with-care --name 'Schule mit Betreuung' --name-en 'School with care'"]]});key=p.String("--key",{required:!0,description:"Stable package key"});name=p.String("--name",{required:!0,description:"German name"});nameEn=p.String("--name-en",{required:!0,description:"English name"});description=p.String("--description","",{description:"German description (with --description-en, or neither)"});descriptionEn=p.String("--description-en","",{description:"English description"});async execute(){let{caller:t,client:n}=await this.loadContext();return this.print(await t.mutation(S.contractPackages.create,{client:n,key:this.key,name:{de:this.name,en:this.nameEn},description:{de:this.description,en:this.descriptionEn}})),0}},Sx=class extends Qe{static{s(this,"PackageCloneCommand")}static paths=[["generator","package","clone"]];static usage=E.Usage({category:"Contracts",description:"Start a new draft from a package revision (parts, mask, code and scenarios copied)",examples:[["Revise the current revision","$0 --env staging --tenant <slug> generator package clone <sealed-revision-id>"]]});id=p.String({required:!0,name:"source-revision-id"});async execute(){let{caller:t,client:n}=await this.loadContext();return this.print({revisionId:await t.mutation(S.contractPackages.cloneDraft,{client:n,id:ia(this.id)})}),0}},Ax=class extends Qe{static{s(this,"PackageTestCommand")}static paths=[["generator","package","test"]];static usage=E.Usage({category:"Contracts",description:"Resolve a package revision for one input file without creating anything (the scenario output)",details:"The input is `{ shared, parts, skip, meta }`. `scenarioOutput` is what a scenario's `expected` holds.",examples:[["Try an input","$0 --env staging --tenant <slug> generator package test <revision-id> --input ./input.json"]]});id=p.String({required:!0,name:"revision-id"});input=p.String("--input",{required:!0,description:"JSON file with the package input"});async execute(){let{caller:t,client:n}=await this.loadContext();return this.print(await t.query(S.contractPackages.resolve,{client:n,id:ia(this.id),input:JSON.parse(await Ln(this.input,"utf8"))})),0}},Ex=class extends Qe{static{s(this,"PackageSealCommand")}static paths=[["generator","package","seal"]];static usage=E.Usage({category:"Contracts",description:"Seal a package draft \u2014 it becomes the current revision new contracts are created from",details:"Sealing re-runs every scenario and refuses a different output. `--source-revision` is the draft's counter from `show`.",examples:[["Seal","$0 --env staging --tenant <slug> generator package seal <revision-id> --source-revision 4"]]});id=p.String({required:!0,name:"revision-id"});sourceRevision=p.String("--source-revision",{required:!0,description:"The draft's current source-revision counter"});async execute(){let{caller:t,client:n}=await this.loadContext();return await t.mutation(S.contractPackages.seal,{client:n,id:ia(this.id),expectedSourceRevision:bx(this.sourceRevision)}),this.print({sealed:this.id}),0}},Tx=class extends Qe{static{s(this,"PackageDeleteDraftCommand")}static paths=[["generator","package","delete-draft"]];static usage=E.Usage({category:"Contracts",description:"Discard a package draft (sealed revisions stay) \u2014 irreversible, plan unless --confirm",examples:[["Plan","$0 --env staging --tenant <slug> generator package delete-draft <revision-id> --source-revision 4"],["Discard","$0 --env staging --tenant <slug> generator package delete-draft <revision-id> --source-revision 4 --confirm"]]});id=p.String({required:!0,name:"revision-id"});sourceRevision=p.String("--source-revision",{required:!0,description:"The draft's current source-revision counter"});confirm=p.Boolean("--confirm",!1,{description:"Discard (without it, only the plan is printed)."});async execute(){let{caller:t,client:n}=await this.loadContext();return this.confirm?(await t.mutation(S.contractPackages.discardDraft,{client:n,id:ia(this.id),expectedSourceRevision:bx(this.sourceRevision)}),this.print({deleted:this.id}),0):(await t.query(S.contractPackages.detail,{client:n,id:ia(this.id)}),this.print({id:this.id,sourceRevision:bx(this.sourceRevision),deleted:!1}),this.context.stderr.write(`Would discard package draft ${this.id} \u2014 re-run with --confirm.
9699
9699
  `),0)}},$x=class extends Qe{static{s(this,"PackageArchiveCommand")}static paths=[["generator","package","archive"]];static usage=E.Usage({category:"Contracts",description:"Archive a contract package \u2014 it creates no new contracts; its key stays taken",examples:[["Archive","$0 --env staging --tenant <slug> generator package archive <package-id>"]]});id=p.String({required:!0,name:"package-id"});async execute(){let{caller:t,client:n}=await this.loadContext();return await t.mutation(S.contractPackages.archive,{client:n,id:this.id}),this.print({archived:this.id}),0}},g0="The file names the package and each part's generator by KEY: { key, name {de,en}, description {de,en}, inputSchema, parts [{ partKey, generator, position, optional, defaults, fixedValues }], source (the package code's .ts file, relative to the file, or null), scenarios [{ key, input, expected? }] }. A sealed revision equal to the file is left alone; otherwise the open draft \u2014 or a copy of the current revision \u2014 takes the file. A scenario without `expected` is evaluated on the draft and its output written into the file; apply then stops UNSEALED for review, and the next run seals.",Rx=class extends Qe{static{s(this,"PackagePlanCommand")}static paths=[["generator","package","plan"]];static usage=E.Usage({category:"Contracts",description:"Compare a package file with the environment: create, same or revise (no write)",details:g0,examples:[["Plan","$0 --env staging --tenant <slug> generator package plan --file ./package.json"]]});file=p.String("--file",{required:!0,description:"The package file (JSON)"});async execute(){let{caller:t,client:n}=await this.loadContext();return this.print(lm((await am(t,n,wx(this.file))).rows)),0}},Ix=class extends Qe{static{s(this,"PackageApplyCommand")}static paths=[["generator","package","apply"]];static usage=E.Usage({category:"Contracts",description:"Create or revise a contract package from a file and seal it once its scenarios are reviewed",details:`${g0} Exit code 1 while the run stopped for review.`,examples:[["First run: draft + scenario outputs into the file","$0 --env staging --tenant <slug> generator package apply --file ./package.json"],["After reviewing the file: seal","$0 --env staging --tenant <slug> generator package apply --file ./package.json"]]});file=p.String("--file",{required:!0,description:"The package file (JSON); reviewed scenario outputs are written into it"});async execute(){let{caller:t,client:n}=await this.loadContext(),r=await h0(t,n,wx(this.file));return this.print(r,i=>[...lm(i.rows),{step:"result",target:i.revisionId??"\u2014",action:i.sealed?"sealed":"NOT sealed",detail:i.sealed?"":"review the written expected outputs, then run apply again"}]),r.sealed?0:1}};async function dm(e){return await e.query(S.contractInputKeys.list,{})}s(dm,"registry");var yc="The registry is platform-wide (one vocabulary for every tenant) and needs a platform operator (_platform.config.manage). Every field a generator declares must be registered before the generator can be sealed. Entries are immutable: a key keeps its label, description and value type; a wrong one is deprecated and replaced by a new key.",Ox=class extends D{static{s(this,"InputKeyListCommand")}static paths=[["generator","input-key","list"]];static usage=E.Usage({category:"Contracts",description:"List the contract input registry",details:yc,examples:[["List","$0 --env staging generator input-key list"]]});async execute(){return this.print(await dm(await this.caller()),t=>t.map(n=>({key:n.key,type:n.valueKind==="entity"?`entity:${n.entityKind}`:String(n.scalarType),label:n.label.de,deprecated:n.deprecatedAt===void 0?"":"yes"}))),0}},Px=class extends D{static{s(this,"InputKeyCreateCommand")}static paths=[["generator","input-key","create"]];static usage=E.Usage({category:"Contracts",description:"Register one contract input key (camelCase; an entity key ends in PartyId or LegalEntityId)",details:yc,examples:[["A date",`$0 --env staging generator input-key create --key childBirthDate --label Geburtsdatum --label-en 'Date of birth' --description 'Geburtsdatum des Kindes' --description-en "The child's date of birth" --scalar date`],["A party reference","$0 --env staging generator input-key create --key payerPartyId --label Zahler --label-en Payer --description 'Wer zahlt' --description-en 'Who pays' --entity party"]]});key=p.String("--key",{required:!0,description:"camelCase key"});label=p.String("--label",{required:!0,description:"German label"});labelEn=p.String("--label-en",{required:!0,description:"English label"});description=p.String("--description",{required:!0,description:"German description"});descriptionEn=p.String("--description-en",{required:!0,description:"English description"});scalar=p.String("--scalar",{description:"Value type: string|number|boolean|date|enum|address"});entity=p.String("--entity",{description:"Entity reference: party|legalEntity"});async execute(){let t=sm(this.scalar,this.entity),r=await(await this.caller()).mutation(S.contractInputKeys.create,{key:this.key,label:{de:this.label,en:this.labelEn},description:{de:this.description,en:this.descriptionEn},value:t});return this.print({id:r,key:this.key}),0}},_x=class extends D{static{s(this,"InputKeyDeprecateCommand")}static paths=[["generator","input-key","deprecate"]];static usage=E.Usage({category:"Contracts",description:"Deprecate a contract input key by key \u2014 no new draft may use it; sealed revisions keep working",details:yc,examples:[["Deprecate","$0 --env staging generator input-key deprecate --key childBirthDate"]]});key=p.String("--key",{required:!0,description:"The registered key"});async execute(){let t=await this.caller(),n=p0(await dm(t),this.key);return await t.mutation(S.contractInputKeys.deprecate,{id:n.id}),this.print({deprecated:this.key,alreadyDeprecated:n.deprecatedAt!==void 0}),0}},y0='The file is a JSON array of { key, label {de,en}, description {de,en}, value: { valueKind: "scalar", scalarType } | { valueKind: "entity", entityKind } }.',Nx=class extends D{static{s(this,"InputKeyPlanCommand")}static paths=[["generator","input-key","plan"]];static usage=E.Usage({category:"Contracts",description:"Compare an input-key file with the registry: create, same, differs, deprecated (no write)",details:`${yc} ${y0}`,examples:[["Plan","$0 --env staging generator input-key plan --file ./input-keys.json"]]});file=p.String("--file",{required:!0,description:"The input-key file (JSON array)"});async execute(){let t=hx(JSON.parse(await Ln(this.file,"utf8"))),n=gx(t,await dm(await this.caller()));return this.print(lm(n)),n.some(yx)?1:0}},Cx=class extends D{static{s(this,"InputKeyApplyCommand")}static paths=[["generator","input-key","apply"]];static usage=E.Usage({category:"Contracts",description:"Register every key of a file that is missing; refuse the whole file when one differs or is deprecated",details:`${yc} ${y0} Nothing is written while any row differs from the registry or names a deprecated key.`,examples:[["Apply","$0 --env staging generator input-key apply --file ./input-keys.json"]]});file=p.String("--file",{required:!0,description:"The input-key file (JSON array)"});async execute(){let t=hx(JSON.parse(await Ln(this.file,"utf8"))),n=await this.caller(),r=gx(t,await dm(n)),i=r.filter(yx);if(i.length>0){for(let o of i)this.context.stderr.write(` \u2716 ${o.key}: ${o.detail}
9700
9700
  `);return this.context.stderr.write(` \u2192 nothing registered (fix the file or choose new keys)
9701
- `),1}for(let[o,a]of t.entries())r[o]?.action==="create"&&await n.mutation(S.contractInputKeys.create,a);return this.print(lm(r)),0}},w0=[kx,vx,xx,Sx,Ax,Ex,Tx,$x,Rx,Ix,Ox,Px,_x,Nx,Cx];var cm=s(e=>new Date(e).toISOString().slice(0,10),"isoDay");function um(e,t){return e.map(n=>({application:n.applicationId,classification:n.deleted?`${n.classification} (gel\xF6scht)`:n.classification,ended:cm(n.endedAt),due:cm(n.dueAt),test:n.testMode?"test":"",action:t}))}s(um,"retentionRows");async function fm(e,t){return await e.query(S.retention.planDue,{client:t})}s(fm,"planRetention");async function b0(e,t,n){let r=await fm(e,t);if(r.length!==n)throw new Error(`retention apply: ${r.length} Anmeldungen sind jetzt f\xE4llig, erwartet waren ${n} \u2014 nichts gel\xF6scht. Erst \`retention plan\` erneut lesen, dann mit der neuen Zahl best\xE4tigen.`);let i=[];for(let o of r){try{await e.mutation(S.retention.eraseDue,{client:t,applicationId:o.applicationId})}catch(a){throw new Error(`retention apply: ${o.applicationId} nicht gel\xF6scht (${a instanceof Error?a.message:String(a)}); davor gel\xF6scht: ${i.length} von ${r.length}${i.length===0?"":` (${i.map(l=>l.applicationId).join(", ")})`}.`,{cause:a})}i.push(o)}return i}s(b0,"applyRetention");var rJ=50;function pm(e,t){return e.map(n=>({party:n.partyId,name:`${n.name??"(ohne Namen)"}${n.deleted?" (gel\xF6scht)":""}`,due:n.deadline===null?"\u2014":cm(n.deadline),test:n.testMode?"test":"",action:n.blockedReason===null?t:`blocked: ${n.blockedReason.de}`}))}s(pm,"partyRetentionRows");async function mm(e,t){let n=[],r=null;for(;;){let i=await e.query(S.partyRetention.planDue,{client:t,paginationOpts:{cursor:r,numItems:rJ}});for(let o of i.page){let a=await e.query(S.partyRetention.checkDue,{client:t,partyId:o.partyId});n.push({...o,testMode:a.testMode,blockedReason:o.blockedReason??a.blockedReason})}if(i.isDone)break;r=i.continueCursor}return n}s(mm,"planPartyRetention");async function k0(e,t,n){let r=await mm(e,t),i=r.filter(a=>a.blockedReason===null);if(i.length!==n)throw new Error(`retention parties apply: ${i.length} Personen sind jetzt l\xF6schbar, erwartet waren ${n} \u2014 nichts gel\xF6scht. Erst \`retention parties plan\` erneut lesen, dann mit der neuen Zahl best\xE4tigen.`);let o=[];for(let a of i){try{await e.mutation(S.partyRetention.eraseDue,{client:t,partyId:a.partyId})}catch(l){throw new Error(`retention parties apply: ${a.partyId} nicht gel\xF6scht (${l instanceof Error?l.message:String(l)}); davor gel\xF6scht: ${o.length} von ${i.length}${o.length===0?"":` (${o.map(d=>d.partyId).join(", ")})`}.`,{cause:l})}o.push(a)}return r}s(k0,"applyPartyRetention");var Dx=["application","classification","ended","due","test","action"],Fx=class extends D{static{s(this,"RetentionPlanCommand")}static paths=[["retention","plan"]];static usage=E.Usage({category:"Admission",description:"Read-only: the tenant's applications whose retention period has ended (what `retention apply --confirm` would erase)."});async execute(){let t=await this.caller(),n=await fm(t,this.requireTenant(t));return this.print(n,r=>um(r,"would-erase"),Dx),0}},Lx=class extends D{static{s(this,"RetentionApplyCommand")}static paths=[["retention","apply"]];static usage=E.Usage({category:"Admission",description:"Erase (DSGVO redaction) every application of the tenant whose retention period has ended. Dry run unless --confirm; --confirm needs --expect <n>, the count `retention plan` showed."});confirm=p.Boolean("--confirm",!1,{description:"Actually erase (default: dry run)"});expect=p.String("--expect",{description:"With --confirm: how many applications you reviewed in `retention plan`; a different count erases nothing"});async execute(){let t=await this.caller(),n=this.requireTenant(t);if(!this.confirm)return this.print(await fm(t,n),r=>um(r,"would-erase"),Dx),0;if(this.expect===void 0||!/^\d+$/.test(this.expect))throw new Error("retention apply --confirm: --expect <n> fehlt \u2014 die Zahl der Anmeldungen, die `retention plan` gezeigt hat.");return this.print(await b0(t,n,Number(this.expect)),r=>um(r,"erased"),Dx),0}},Mx=["party","name","due","test","action"],qx=class extends D{static{s(this,"RetentionPartiesPlanCommand")}static paths=[["retention","parties","plan"]];static usage=E.Usage({category:"Stammdaten",description:"Read-only: the tenant's persons past its deletion rule, each with whether the hard delete may run (what `retention parties apply --confirm` would delete; blocked ones are skipped)."});async execute(){let t=await this.caller(),n=await mm(t,this.requireTenant(t));return this.print(n,r=>pm(r,"would-erase"),Mx),0}},Kx=class extends D{static{s(this,"RetentionPartiesApplyCommand")}static paths=[["retention","parties","apply"]];static usage=E.Usage({category:"Stammdaten",description:"Hard-delete (with history and files) every person past the tenant's deletion rule that nothing blocks. Dry run unless --confirm; --confirm needs --expect <n>, the would-erase count `retention parties plan` showed."});confirm=p.Boolean("--confirm",!1,{description:"Actually delete (default: dry run)"});expect=p.String("--expect",{description:"With --confirm: how many deletable persons you reviewed in `retention parties plan`; a different count deletes nothing"});async execute(){let t=await this.caller(),n=this.requireTenant(t);if(!this.confirm)return this.print(await mm(t,n),r=>pm(r,"would-erase"),Mx),0;if(this.expect===void 0||!/^\d+$/.test(this.expect))throw new Error("retention parties apply --confirm: --expect <n> fehlt \u2014 die Zahl der l\xF6schbaren Personen, die `retention parties plan` gezeigt hat.");return this.print(await k0(t,n,Number(this.expect)),r=>pm(r,"erased"),Mx),0}},v0=[Fx,Lx,qx,Kx];import{loadavg as gJ}from"node:os";var jx={fullSeedMs:78e4,applicantCallsMs:4e4,driveWaitMs:19e4};var Bx="drive:",iJ="driveWait:";function oJ(e){return{drive:`${Bx}${e}`,wait:`${iJ}${e}`}}s(oJ,"driveTimingKeys");function S0(e){let t=e.perPhaseMs??{},n=[],r=s((o,a,l)=>{a>l&&n.push({over:a/l,line:`${o} ${x0(a)} > budget ${x0(l)}`})},"check");e.full&&r("full seed",e.elapsedMs,jx.fullSeedMs);let i=0;for(let[o,a]of Object.entries(t)){if(!o.startsWith(Bx))continue;let l=o.slice(Bx.length),d=t[oJ(l).wait]??0;i+=d,r(`applicant ${l}: own calls`,a-d,jx.applicantCallsMs)}return e.full&&r("drive waits on scheduled work",i,jx.driveWaitMs),n.sort((o,a)=>a.over-o.over).map(o=>o.line)}s(S0,"seedBudgetBreaches");var x0=s(e=>`${(e/1e3).toFixed(1)} s`,"seconds");function Vx(e){return e.financeShowcase!==void 0?e.financeShowcase:e.applicantKeys!==void 0&&e.applicantKeys.length>0?"none":"full"}s(Vx,"resolveFinanceShowcase");async function Ux(e){let t=e.now??Date.now,n=e.sleep??(d=>new Promise(c=>setTimeout(c,d))),r=e.maxConsecutiveFailures??5,i=`seed run ${e.runId}`,o=s(d=>`${Math.round(d/1e3)}s`,"seconds"),a=0,l="";for(;;){let d;try{d=e.poll(),a=0}catch(c){if(a++,a>=r){let u=c instanceof Error?c.message:String(c);throw new Error(`could not read the status of ${i} ${a} times in a row (it may still be running); last error: ${u}`,{cause:c})}}if(d===null)throw new Error(`${i} not found in seed_runs.`);if(d!==void 0){if(d.phase&&d.phase!==l&&(l=d.phase,e.onPhase(d.phase,d.elapsedMs)),d.status==="completed")return d;if(d.status==="failed")throw new Error(`${i} FAILED in phase "${d.phase??"?"}" after ${o(d.elapsedMs)} \u2014 ${d.error??"no error recorded"}`);if(d.status==="unknown")throw new Error(`${i} has no status (phase "${d.phase??"?"}").`);if(!d.live)throw new Error(`${i} is no longer live: its owner died in phase "${d.phase??"?"}" after ${o(d.elapsedMs)}. Rebuild explicitly (pnpm seed / pnpm seed:lean).`)}if(t()>=e.deadline)throw new Error(`timed out waiting for ${i} (it may still be running \u2014 poll init/seed:seedStatus).`);await n(e.pollMs)}}s(Ux,"pollSeedRun");import{spawnSync as sJ}from"node:child_process";import{closeSync as Gx,ftruncateSync as aJ,mkdirSync as lJ,openSync as dJ,readFileSync as cJ,writeSync as uJ}from"node:fs";import{homedir as fJ}from"node:os";import A0 from"node:path";var pJ=2;function E0(e=process.env){let t=e.PLEXUS_SEED_SLOTS;if(t===void 0||t==="")return pJ;if(!/^[1-9][0-9]*$/.test(t))throw new Error(`PLEXUS_SEED_SLOTS must be a positive integer, got '${t}'.`);return Number.parseInt(t,10)}s(E0,"seedSlotCount");function T0(){return A0.join(fJ(),".cache","plexus","seed-slots")}s(T0,"seedSlotDir");function mJ(e,t){return A0.join(e,`slot-${t}.lock`)}s(mJ,"slotFile");function hJ(e){lJ(e.dir,{recursive:!0});let t=[];for(let n=0;n<e.slots;n++){let r=mJ(e.dir,n),i=dJ(r,"a+"),o=sJ("flock",["--nonblock","--exclusive","3"],{stdio:["ignore","ignore","pipe",i],encoding:"utf8"});if(o.error)throw Gx(i),new Error(`seed slot: cannot run flock(1) \u2014 ${o.error.message}`);if(o.status===0){aJ(i,0),uJ(i,`${e.holder}
9701
+ `),1}for(let[o,a]of t.entries())r[o]?.action==="create"&&await n.mutation(S.contractInputKeys.create,a);return this.print(lm(r)),0}},w0=[kx,vx,xx,Sx,Ax,Ex,Tx,$x,Rx,Ix,Ox,Px,_x,Nx,Cx];var cm=s(e=>new Date(e).toISOString().slice(0,10),"isoDay");function um(e,t){return e.map(n=>({application:n.applicationId,classification:n.deleted?`${n.classification} (gel\xF6scht)`:n.classification,ended:cm(n.endedAt),due:cm(n.dueAt),test:n.testMode?"test":"",action:t}))}s(um,"retentionRows");async function fm(e,t){return await e.query(S.retention.planDue,{client:t})}s(fm,"planRetention");async function b0(e,t,n){let r=await fm(e,t);if(r.length!==n)throw new Error(`retention apply: ${r.length} Anmeldungen sind jetzt f\xE4llig, erwartet waren ${n} \u2014 nichts gel\xF6scht. Erst \`retention plan\` erneut lesen, dann mit der neuen Zahl best\xE4tigen.`);let i=[];for(let o of r){try{await e.mutation(S.retention.eraseDue,{client:t,applicationId:o.applicationId})}catch(a){throw new Error(`retention apply: ${o.applicationId} nicht gel\xF6scht (${a instanceof Error?a.message:String(a)}); davor gel\xF6scht: ${i.length} von ${r.length}${i.length===0?"":` (${i.map(l=>l.applicationId).join(", ")})`}.`,{cause:a})}i.push(o)}return i}s(b0,"applyRetention");var rJ=50;function pm(e,t){return e.map(n=>({party:n.partyId,name:`${n.name??"(ohne Namen)"}${n.deleted?" (gel\xF6scht)":""}`,due:n.deadline===null?"\u2014":cm(n.deadline),test:n.testMode?"test":"",action:n.blockedReason===null?t:`blocked: ${n.blockedReason.de}`}))}s(pm,"partyRetentionRows");async function mm(e,t){let n=[],r=null;for(;;){let i=await e.query(S.partyRetention.planDue,{client:t,paginationOpts:{cursor:r,numItems:rJ}});for(let o of i.page){let a=await e.query(S.partyRetention.checkDue,{client:t,partyId:o.partyId});n.push({...o,testMode:a.testMode,blockedReason:o.blockedReason??a.blockedReason})}if(i.isDone)break;r=i.continueCursor}return n}s(mm,"planPartyRetention");async function k0(e,t,n){let r=await mm(e,t),i=r.filter(a=>a.blockedReason===null);if(i.length!==n)throw new Error(`retention parties apply: ${i.length} Personen sind jetzt l\xF6schbar, erwartet waren ${n} \u2014 nichts gel\xF6scht. Erst \`retention parties plan\` erneut lesen, dann mit der neuen Zahl best\xE4tigen.`);let o=[];for(let a of i){try{await e.mutation(S.partyRetention.eraseDue,{client:t,partyId:a.partyId})}catch(l){throw new Error(`retention parties apply: ${a.partyId} nicht gel\xF6scht (${l instanceof Error?l.message:String(l)}); davor gel\xF6scht: ${o.length} von ${i.length}${o.length===0?"":` (${o.map(d=>d.partyId).join(", ")})`}.`,{cause:l})}o.push(a)}return r}s(k0,"applyPartyRetention");var Dx=["application","classification","ended","due","test","action"],Fx=class extends D{static{s(this,"RetentionPlanCommand")}static paths=[["retention","plan"]];static usage=E.Usage({category:"Admission",description:"Read-only: the tenant's applications whose retention period has ended (what `retention apply --confirm` would erase)."});async execute(){let t=await this.caller(),n=await fm(t,this.requireTenant(t));return this.print(n,r=>um(r,"would-erase"),Dx),0}},Lx=class extends D{static{s(this,"RetentionApplyCommand")}static paths=[["retention","apply"]];static usage=E.Usage({category:"Admission",description:"Erase (DSGVO redaction) every application of the tenant whose retention period has ended. Dry run unless --confirm; --confirm needs --expect <n>, the count `retention plan` showed."});confirm=p.Boolean("--confirm",!1,{description:"Actually erase (default: dry run)"});expect=p.String("--expect",{description:"With --confirm: how many applications you reviewed in `retention plan`; a different count erases nothing"});async execute(){let t=await this.caller(),n=this.requireTenant(t);if(!this.confirm)return this.print(await fm(t,n),r=>um(r,"would-erase"),Dx),0;if(this.expect===void 0||!/^\d+$/.test(this.expect))throw new Error("retention apply --confirm: --expect <n> fehlt \u2014 die Zahl der Anmeldungen, die `retention plan` gezeigt hat.");return this.print(await b0(t,n,Number(this.expect)),r=>um(r,"erased"),Dx),0}},Mx=["party","name","due","test","action"],qx=class extends D{static{s(this,"RetentionPartiesPlanCommand")}static paths=[["retention","parties","plan"]];static usage=E.Usage({category:"Stammdaten",description:"Read-only: the tenant's persons past its deletion rule, each with whether the hard delete may run (what `retention parties apply --confirm` would delete; blocked ones are skipped)."});async execute(){let t=await this.caller(),n=await mm(t,this.requireTenant(t));return this.print(n,r=>pm(r,"would-erase"),Mx),0}},Kx=class extends D{static{s(this,"RetentionPartiesApplyCommand")}static paths=[["retention","parties","apply"]];static usage=E.Usage({category:"Stammdaten",description:"Hard-delete (with history and files) every person past the tenant's deletion rule that nothing blocks. Dry run unless --confirm; --confirm needs --expect <n>, the would-erase count `retention parties plan` showed."});confirm=p.Boolean("--confirm",!1,{description:"Actually delete (default: dry run)"});expect=p.String("--expect",{description:"With --confirm: how many deletable persons you reviewed in `retention parties plan`; a different count deletes nothing"});async execute(){let t=await this.caller(),n=this.requireTenant(t);if(!this.confirm)return this.print(await mm(t,n),r=>pm(r,"would-erase"),Mx),0;if(this.expect===void 0||!/^\d+$/.test(this.expect))throw new Error("retention parties apply --confirm: --expect <n> fehlt \u2014 die Zahl der l\xF6schbaren Personen, die `retention parties plan` gezeigt hat.");return this.print(await k0(t,n,Number(this.expect)),r=>pm(r,"erased"),Mx),0}},v0=[Fx,Lx,qx,Kx];import{loadavg as gJ}from"node:os";var jx={fullSeedMs:6e5,applicantCallsMs:4e4,driveWaitMs:75e3};var Bx="drive:",iJ="driveWait:";function oJ(e){return{drive:`${Bx}${e}`,wait:`${iJ}${e}`}}s(oJ,"driveTimingKeys");function S0(e){let t=e.perPhaseMs??{},n=[],r=s((o,a,l)=>{a>l&&n.push({over:a/l,line:`${o} ${x0(a)} > budget ${x0(l)}`})},"check");e.full&&r("full seed",e.elapsedMs,jx.fullSeedMs);let i=0;for(let[o,a]of Object.entries(t)){if(!o.startsWith(Bx))continue;let l=o.slice(Bx.length),d=t[oJ(l).wait]??0;i+=d,r(`applicant ${l}: own calls`,a-d,jx.applicantCallsMs)}return e.full&&r("drive waits on scheduled work",i,jx.driveWaitMs),n.sort((o,a)=>a.over-o.over).map(o=>o.line)}s(S0,"seedBudgetBreaches");var x0=s(e=>`${(e/1e3).toFixed(1)} s`,"seconds");function Vx(e){return e.financeShowcase!==void 0?e.financeShowcase:e.applicantKeys!==void 0&&e.applicantKeys.length>0?"none":"full"}s(Vx,"resolveFinanceShowcase");async function Ux(e){let t=e.now??Date.now,n=e.sleep??(d=>new Promise(c=>setTimeout(c,d))),r=e.maxConsecutiveFailures??5,i=`seed run ${e.runId}`,o=s(d=>`${Math.round(d/1e3)}s`,"seconds"),a=0,l="";for(;;){let d;try{d=e.poll(),a=0}catch(c){if(a++,a>=r){let u=c instanceof Error?c.message:String(c);throw new Error(`could not read the status of ${i} ${a} times in a row (it may still be running); last error: ${u}`,{cause:c})}}if(d===null)throw new Error(`${i} not found in seed_runs.`);if(d!==void 0){if(d.phase&&d.phase!==l&&(l=d.phase,e.onPhase(d.phase,d.elapsedMs)),d.status==="completed")return d;if(d.status==="failed")throw new Error(`${i} FAILED in phase "${d.phase??"?"}" after ${o(d.elapsedMs)} \u2014 ${d.error??"no error recorded"}`);if(d.status==="unknown")throw new Error(`${i} has no status (phase "${d.phase??"?"}").`);if(!d.live)throw new Error(`${i} is no longer live: its owner died in phase "${d.phase??"?"}" after ${o(d.elapsedMs)}. Rebuild explicitly (pnpm seed / pnpm seed:lean).`)}if(t()>=e.deadline)throw new Error(`timed out waiting for ${i} (it may still be running \u2014 poll init/seed:seedStatus).`);await n(e.pollMs)}}s(Ux,"pollSeedRun");import{spawnSync as sJ}from"node:child_process";import{closeSync as Gx,ftruncateSync as aJ,mkdirSync as lJ,openSync as dJ,readFileSync as cJ,writeSync as uJ}from"node:fs";import{homedir as fJ}from"node:os";import A0 from"node:path";var pJ=2;function E0(e=process.env){let t=e.PLEXUS_SEED_SLOTS;if(t===void 0||t==="")return pJ;if(!/^[1-9][0-9]*$/.test(t))throw new Error(`PLEXUS_SEED_SLOTS must be a positive integer, got '${t}'.`);return Number.parseInt(t,10)}s(E0,"seedSlotCount");function T0(){return A0.join(fJ(),".cache","plexus","seed-slots")}s(T0,"seedSlotDir");function mJ(e,t){return A0.join(e,`slot-${t}.lock`)}s(mJ,"slotFile");function hJ(e){lJ(e.dir,{recursive:!0});let t=[];for(let n=0;n<e.slots;n++){let r=mJ(e.dir,n),i=dJ(r,"a+"),o=sJ("flock",["--nonblock","--exclusive","3"],{stdio:["ignore","ignore","pipe",i],encoding:"utf8"});if(o.error)throw Gx(i),new Error(`seed slot: cannot run flock(1) \u2014 ${o.error.message}`);if(o.status===0){aJ(i,0),uJ(i,`${e.holder}
9702
9702
  `);let a=!1;return{index:n,release:s(()=>{a||(a=!0,Gx(i))},"release")}}if(Gx(i),o.status!==1)throw new Error(`seed slot: flock ${r} exited ${o.status} \u2014 ${(o.stderr??"").trim()}`);t.push(cJ(r,"utf8").trim()||"unknown holder")}return{busy:t}}s(hJ,"tryAcquireSeedSlot");async function $0(e){let t=e.now??Date.now,n=e.sleep??(i=>new Promise(o=>setTimeout(o,i))),r="";for(;;){let i=hJ(e);if("index"in i)return i;let o=`${i.busy.length} in use: ${i.busy.join(", ")}`;if(t()>=e.deadline)throw new Error(`no seed slot became free before the timeout (${o})`);let a=`waiting for a seed slot (${o})`;a!==r&&(e.onWait(a),r=a),await n(e.pollMs)}}s($0,"acquireSeedSlot");function I0(){let e=process.cwd();for(;;){if(Oe(H.join(e,"convex")))return e;let t=H.dirname(e);if(t===e)throw new Error("plexus seed: no Convex project found above the current directory \u2014 run this from inside the worktree (e.g. the app/ dir).");e=t}}s(I0,"findConvexProjectDir");function yJ(e,t,n=!1){let r=["convex","run",e];t!==void 0&&r.push(t),n&&r.push("--push");let i=GI("npx",r,{cwd:I0(),encoding:"utf8",stdio:["ignore","pipe","pipe"]});if(i.status!==0){let d=(i.stderr??"").trim();throw new Error(d||`convex run ${e} exited ${i.status}`)}let o=(i.stdout??"").trim();try{return JSON.parse(o)}catch{}let a=o.indexOf("{"),l=o.lastIndexOf("}");if(a<0||l<a)throw new Error(`convex run ${e}: no JSON in output:
9703
9703
  ${o}`);return JSON.parse(o.slice(a,l+1))}s(yJ,"convexRun");function zx(){return gJ().map(e=>e.toFixed(2)).join(" ")}s(zx,"loadAverage");var wJ={convexRun:yJ,now:Date.now,sleep:s(e=>new Promise(t=>setTimeout(t,e)),"sleep"),slotDir:T0,worktree:s(()=>H.basename(H.dirname(I0())),"worktree")},R0=s(e=>(e??"").split(",").map(t=>t.trim()).filter(t=>t.length>0),"splitList"),Wx=class extends Se{static{s(this,"SeedCommand")}static paths=[["seed"]];static usage=E.Usage({category:"Operations",description:"Kick off the destructive local reseed and poll its run marker to completion.",details:`Fires init/seed:kickoffSeed (returns immediately, holds a run-lock) and polls init/seed:seedStatus, printing live phase progress. Exit 0 on completed, 1 on failed. The client disconnect can no longer masquerade as a failure \u2014 the seed_runs marker is the only source of truth. Runs \`convex run\` in the current worktree (admin key), so invoke it from the app dir.
9704
9704
 
@@ -9761,6 +9761,6 @@ ${n.length} unusable ${o}:
9761
9761
  `),r.length>0&&this.context.stdout.write(` ${r.length} linkable \u2014 plexus-cli users relink-auth <email>
9762
9762
  `),i.length>0&&this.context.stdout.write(` ${i.length} without any login account \u2014 plexus-cli users provision --tenant <slug> --email <email> --name <name>
9763
9763
  `)}else this.context.stdout.write(`No unusable identities.
9764
- `);return n.length>0?1:0}},GS=class extends Sn{static{s(this,"UsersRelinkAuthCommand")}static paths=[["users","relink-auth"]];static usage=E.Usage({category:"Users",description:"Relink a user's identity row to its live Better Auth account (heals an orphan)."});email=p.String({required:!0});async execute(){let n=await(await this.caller()).mutation(S.platformAdmin.relinkAuthAccount,{email:this.email}),r=n.changed?`Relinked ${this.email} to live auth account ${n.authId}.`:`${this.email} already linked to the live auth account (no change).`;return this.report(n,r),0}};function Y0(e,t){if(e===t)throw new Error("Pass exactly one of --on or --off.");return e}s(Y0,"requireOnOff");var J0=[TS,$S,RS,IS,OS,PS,_S,NS,CS,DS,FS,LS,wc,MS,qS,KS,jS,BS,VS,US,GS];function Q0(e){return e.de??e.en??Object.values(e)[0]??""}s(Q0,"titleDe");function KJ(e){return{id:e._id,kind:e.kind,status:e.status,title:Q0(e.title).slice(0,50),assignee:e.assigneeUserId??"",group:e.queueGroupId??"",outcome:e.outcome??""}}s(KJ,"row");var jJ=["id","kind","status","title","assignee","group","outcome"],WS=class extends D{static{s(this,"WorkItemsListCommand")}static paths=[["work-items","list"]];static usage=E.Usage({category:"Work-Items",description:"List work-items for the active tenant (filter by --mine/--application/--group)."});mine=p.Boolean("--mine",!1,{description:"Only items assigned to me."});application=p.String("--application",{description:"Filter by application id."});group=p.String("--group",{description:"Filter by team (permission-group) id."});assignee=p.String("--assignee",{description:"Filter by assignee users._id."});openOnly=p.Boolean("--open-only",!1,{description:"Only open items."});async execute(){let t=await this.caller(),n=this.requireTenant(t),r=await t.query(S.workItems.list,{client:n,...this.mine?{mine:!0}:{},...this.application?{applicationId:this.application}:{},...this.group?{queueGroupId:this.group}:{},...this.assignee?{assigneeUserId:this.assignee}:{},...this.openOnly?{openOnly:!0}:{}});return this.print(r,i=>i.map(KJ),jJ),0}},HS=class extends D{static{s(this,"WorkItemsShowCommand")}static paths=[["work-items","show"]];static usage=E.Usage({category:"Work-Items",description:"Show one work-item by id."});workItemId=p.String({required:!0,name:"workItemId"});async execute(){let t=await this.caller(),n=this.requireTenant(t),r=await t.query(S.workItems.get,{client:n,workItemId:this.workItemId});if(r===null)throw new Error(`work-item ${this.workItemId} not found in tenant ${n}.`);return this.print(r,i=>[{field:"id",value:i._id},{field:"kind",value:i.kind},{field:"status",value:i.status},{field:"title",value:Q0(i.title)},{field:"assignee",value:i.assigneeUserId??""},{field:"group",value:i.queueGroupId??""},{field:"application",value:i.applicationId??""},{field:"node",value:i.nodeId??""},{field:"outcome",value:i.outcome??""}]),0}},YS=class extends D{static{s(this,"WorkItemsCreateCommand")}static paths=[["work-items","create"]];static usage=E.Usage({category:"Work-Items",description:"Create a manual task work-item."});title=p.String("--title",{required:!0,description:"Task title."});description=p.String("--description",{description:"Task description."});application=p.String("--application",{description:"Link to an application id."});group=p.String("--group",{description:"Team (permission-group) id whose queue holds the task."});assignee=p.String("--assignee",{description:"Assignee users._id."});async execute(){let t=await this.caller(),n=this.requireTenant(t),r=await t.mutation(S.workItems.createManual,{client:n,title:this.title,...this.description?{description:this.description}:{},...this.application?{applicationId:this.application}:{},...this.group?{queueGroupId:this.group}:{},...this.assignee?{assigneeUserId:this.assignee}:{}});return this.print({workItemId:r.workItemId},i=>[{field:"workItemId",value:i.workItemId}]),0}},JS=class extends D{static{s(this,"WorkItemsCompleteCommand")}static paths=[["work-items","complete"]];static usage=E.Usage({category:"Work-Items",description:"Complete a work-item (optionally with an outcome)."});workItemId=p.String({required:!0,name:"workItemId"});outcome=p.String("--outcome",{description:"Outcome id to record."});async execute(){let t=await this.caller(),n=this.requireTenant(t),r=await t.mutation(S.workItems.complete,{client:n,workItemId:this.workItemId,...this.outcome?{outcome:this.outcome}:{}});return this.print({workItemId:r.workItemId,status:"done"},i=>[{field:"workItemId",value:i.workItemId},{field:"status",value:i.status}]),0}},QS=class extends D{static{s(this,"WorkItemsAssignCommand")}static paths=[["work-items","assign"]];static usage=E.Usage({category:"Work-Items",description:"Assign a work-item to a user (omit --user to unassign)."});workItemId=p.String({required:!0,name:"workItemId"});user=p.String("--user",{description:"Assignee users._id (omit to clear)."});async execute(){let t=await this.caller(),n=this.requireTenant(t),r=await t.mutation(S.workItems.assign,{client:n,workItemId:this.workItemId,...this.user?{userId:this.user}:{}});return this.print({workItemId:r.workItemId,assignee:this.user??"(cleared)"},i=>[{field:"workItemId",value:i.workItemId},{field:"assignee",value:i.assignee}]),0}},Z0=[WS,HS,YS,JS,QS];var Am=[...OT,...yR,...LI,...FI,...dO,...xO,...vO,...W0,...J0,...l0,...nR,...oO,...B0,...RT,...t$,...X$,...EO,...AO,...RO,...IO,...rO,...VI,...Z0,...lF,...WF,...s0,...HF,...O0,...M0,...d0,...w0,...v0,...j0,...z0,...WT];var X0="0.1.4";function eM(){return Am.flatMap(e=>(e.paths??[]).map(t=>{let n=t.join(" "),r=AT[Na(n)];return{path:n,effect:eo(n),host:r===void 0?"shared":"terminal",...r===void 0?{}:{reason:r}}})).sort((e,t)=>e.path.localeCompare(t.path))}s(eM,"plexusCommandCatalog");import Fo from"node:path";function BJ(e){let t=st()?.workspaceRoot??process.cwd(),n=Fo.resolve(t,e),r=Fo.relative(t,n);if(Fo.isAbsolute(e)||r===".."||r.startsWith(`..${Fo.sep}`))throw new Error("plexus: use a relative path inside the current workspace.");return{absolute:n,relative:r}}s(BJ,"workspacePath");function VJ(e){let{absolute:t,relative:n}=BJ(e.path??".");if(e.operation==="list"){if(!Oe(t))return{files:[]};let r=[],i=s(o=>{for(let a of Vi(o,{withFileTypes:!0})){if(a.isSymbolicLink())throw new Error("plexus: workspace symlinks are not supported.");let l=Fo.join(o,a.name);if(a.isDirectory()?i(l):r.push(Fo.relative(t,l)),r.length>200)throw new Error("plexus: the workspace contains too many files. List a subdirectory.")}},"visit");return i(t),{files:r.sort()}}if(!n)throw new Error("plexus: name a workspace file.");if(["read","search","edit"].includes(e.operation)){let r=ke(t);if(r.length>10*1024*1024)throw new Error("plexus: the workspace file exceeds 10 MB.");let i=new TextDecoder("utf-8",{fatal:!0}).decode(r);if(e.operation==="read"){let l=e.offset??0,d=e.maxChars??8e3,c=i.slice(l,l+d);return{path:n,content:c,...l||c.length<i.length?{offset:l,nextOffset:l+c.length<i.length?l+c.length:null,totalCharacters:i.length}:{}}}if(e.operation==="search"){if(!e.query)throw new Error("plexus: search needs a nonempty query.");let l=[],d=e.offset??0;for(;l.length<10;){let c=i.indexOf(e.query,d);if(c<0)break;l.push({offset:c,text:i.slice(Math.max(0,c-160),c+e.query.length+240)}),d=c+e.query.length}return{path:n,matches:l,nextOffset:l.length===10?d:null}}if(!e.oldText||typeof e.content!="string")throw new Error("plexus: edit needs oldText and replacement content.");let o=i.indexOf(e.oldText);if(o<0||o!==i.lastIndexOf(e.oldText))throw new Error("plexus: oldText must match exactly once. Read the current file and choose unique context.");let a=i.slice(0,o)+e.content+i.slice(o+e.oldText.length);if(Buffer.byteLength(a)>10*1024*1024)throw new Error("plexus: the edited file exceeds 10 MB.");return ht(t,a,"utf8"),{path:n,sizeBytes:Buffer.byteLength(a)}}if(e.operation==="write"){if(typeof e.content!="string"||Buffer.byteLength(e.content)>1e6)throw new Error("plexus: file content is missing or too large.");return Wt(Fo.dirname(t),{recursive:!0}),ht(t,e.content,"utf8"),{path:n,sizeBytes:Buffer.byteLength(e.content)}}if(e.operation==="remove")return Ko(t),{path:n,removed:!0};throw new Error("plexus: unknown workspace operation.")}s(VJ,"plexusWorkspace");function tM(e){return s(async function(n,r){if(!r||typeof r!="object"||Array.isArray(r))throw new Error("plexus: tool input must be an object.");let i=r,o=Da[n];if(!o||!Object.hasOwn(Da,n))throw new Error("plexus: unknown agent tool.");if(Object.keys(i).some(a=>!Object.hasOwn(o.inputSchema.properties,a)))throw new Error("plexus: unexpected tool argument.");if(n==="plexus"){if(!Array.isArray(i.argv)||i.argv.some(a=>typeof a!="string")||i.stdin!==void 0&&typeof i.stdin!="string")throw new Error("plexus: invalid command input.");return e.inspectCommand(i.argv),e.executeCommand({argv:i.argv,...i.stdin===void 0?{}:{stdin:i.stdin}})}if(n==="plexus_skill"){if(typeof i.path!="string"||i.path.length>240||!Object.hasOwn(Kh,i.path))throw new Error("plexus: unknown skill reference. Start with SKILL.md.");return{path:i.path,content:Kh[i.path],skillHash:mu}}if(typeof i.operation!="string"||!["list","read","search","edit","write","remove"].includes(i.operation)||i.path!==void 0&&(typeof i.path!="string"||i.path.length>500)||i.content!==void 0&&(typeof i.content!="string"||i.content.length>1e6)||i.oldText!==void 0&&(typeof i.oldText!="string"||i.oldText.length>1e6)||i.query!==void 0&&(typeof i.query!="string"||!i.query.length||i.query.length>1e3)||i.offset!==void 0&&(typeof i.offset!="number"||!Number.isSafeInteger(i.offset)||i.offset<0)||i.maxChars!==void 0&&(typeof i.maxChars!="number"||!Number.isSafeInteger(i.maxChars)||i.maxChars<1||i.maxChars>24e3))throw new Error("plexus: invalid workspace input.");return VJ(i)},"executePlexusAgentTool")}s(tM,"createPlexusAgentToolExecutor");var Em=tM({inspectCommand:rM,executeCommand:iM});function Tm(){let e=new Uo({binaryLabel:"Plexus CLI",binaryName:"plexus-cli",binaryVersion:X0});e.register(ya.HelpCommand),e.register(ya.VersionCommand);for(let n of Am)e.register(n);async function t(n,r){let i;try{i=e.process(n,r)}catch(o){return(r.stderr??process.stderr).write(e.error(o,{colored:!1})),2}return zJ(i,r.stderr??process.stderr),e.run(i,r)}return s(t,"run"),{process(n,r){return e.process(n,r)},run:t,async runExit(n,r){process.exitCode=await t(n,r)}}}s(Tm,"createPlexusCli");function zJ(e,t){let n=e.path.join(" "),r=e.constructor.paths?.[0]?.join(" ");r!==void 0&&n!==r&&_a[n]===r&&dt(t,n,r),n in _a&&eo(n)==="confirm"&&!Ca(e)&&t.write(`plexus-cli: \`${_a[n]}\` only prints its plan without --confirm \u2014 nothing was changed.
9764
+ `);return n.length>0?1:0}},GS=class extends Sn{static{s(this,"UsersRelinkAuthCommand")}static paths=[["users","relink-auth"]];static usage=E.Usage({category:"Users",description:"Relink a user's identity row to its live Better Auth account (heals an orphan)."});email=p.String({required:!0});async execute(){let n=await(await this.caller()).mutation(S.platformAdmin.relinkAuthAccount,{email:this.email}),r=n.changed?`Relinked ${this.email} to live auth account ${n.authId}.`:`${this.email} already linked to the live auth account (no change).`;return this.report(n,r),0}};function Y0(e,t){if(e===t)throw new Error("Pass exactly one of --on or --off.");return e}s(Y0,"requireOnOff");var J0=[TS,$S,RS,IS,OS,PS,_S,NS,CS,DS,FS,LS,wc,MS,qS,KS,jS,BS,VS,US,GS];function Q0(e){return e.de??e.en??Object.values(e)[0]??""}s(Q0,"titleDe");function KJ(e){return{id:e._id,kind:e.kind,status:e.status,title:Q0(e.title).slice(0,50),assignee:e.assigneeUserId??"",group:e.queueGroupId??"",outcome:e.outcome??""}}s(KJ,"row");var jJ=["id","kind","status","title","assignee","group","outcome"],WS=class extends D{static{s(this,"WorkItemsListCommand")}static paths=[["work-items","list"]];static usage=E.Usage({category:"Work-Items",description:"List work-items for the active tenant (filter by --mine/--application/--group)."});mine=p.Boolean("--mine",!1,{description:"Only items assigned to me."});application=p.String("--application",{description:"Filter by application id."});group=p.String("--group",{description:"Filter by team (permission-group) id."});assignee=p.String("--assignee",{description:"Filter by assignee users._id."});openOnly=p.Boolean("--open-only",!1,{description:"Only open items."});async execute(){let t=await this.caller(),n=this.requireTenant(t),r=await t.query(S.workItems.list,{client:n,...this.mine?{mine:!0}:{},...this.application?{applicationId:this.application}:{},...this.group?{queueGroupId:this.group}:{},...this.assignee?{assigneeUserId:this.assignee}:{},...this.openOnly?{openOnly:!0}:{}});return this.print(r,i=>i.map(KJ),jJ),0}},HS=class extends D{static{s(this,"WorkItemsShowCommand")}static paths=[["work-items","show"]];static usage=E.Usage({category:"Work-Items",description:"Show one work-item by id."});workItemId=p.String({required:!0,name:"workItemId"});async execute(){let t=await this.caller(),n=this.requireTenant(t),r=await t.query(S.workItems.get,{client:n,workItemId:this.workItemId});if(r===null)throw new Error(`work-item ${this.workItemId} not found in tenant ${n}.`);return this.print(r,i=>[{field:"id",value:i._id},{field:"kind",value:i.kind},{field:"status",value:i.status},{field:"title",value:Q0(i.title)},{field:"assignee",value:i.assigneeUserId??""},{field:"group",value:i.queueGroupId??""},{field:"application",value:i.applicationId??""},{field:"node",value:i.nodeId??""},{field:"outcome",value:i.outcome??""}]),0}},YS=class extends D{static{s(this,"WorkItemsCreateCommand")}static paths=[["work-items","create"]];static usage=E.Usage({category:"Work-Items",description:"Create a manual task work-item."});title=p.String("--title",{required:!0,description:"Task title."});description=p.String("--description",{description:"Task description."});application=p.String("--application",{description:"Link to an application id."});group=p.String("--group",{description:"Team (permission-group) id whose queue holds the task."});assignee=p.String("--assignee",{description:"Assignee users._id."});async execute(){let t=await this.caller(),n=this.requireTenant(t),r=await t.mutation(S.workItems.createManual,{client:n,title:this.title,...this.description?{description:this.description}:{},...this.application?{applicationId:this.application}:{},...this.group?{queueGroupId:this.group}:{},...this.assignee?{assigneeUserId:this.assignee}:{}});return this.print({workItemId:r.workItemId},i=>[{field:"workItemId",value:i.workItemId}]),0}},JS=class extends D{static{s(this,"WorkItemsCompleteCommand")}static paths=[["work-items","complete"]];static usage=E.Usage({category:"Work-Items",description:"Complete a work-item (optionally with an outcome)."});workItemId=p.String({required:!0,name:"workItemId"});outcome=p.String("--outcome",{description:"Outcome id to record."});async execute(){let t=await this.caller(),n=this.requireTenant(t),r=await t.mutation(S.workItems.complete,{client:n,workItemId:this.workItemId,...this.outcome?{outcome:this.outcome}:{}});return this.print({workItemId:r.workItemId,status:"done"},i=>[{field:"workItemId",value:i.workItemId},{field:"status",value:i.status}]),0}},QS=class extends D{static{s(this,"WorkItemsAssignCommand")}static paths=[["work-items","assign"]];static usage=E.Usage({category:"Work-Items",description:"Assign a work-item to a user (omit --user to unassign)."});workItemId=p.String({required:!0,name:"workItemId"});user=p.String("--user",{description:"Assignee users._id (omit to clear)."});async execute(){let t=await this.caller(),n=this.requireTenant(t),r=await t.mutation(S.workItems.assign,{client:n,workItemId:this.workItemId,...this.user?{userId:this.user}:{}});return this.print({workItemId:r.workItemId,assignee:this.user??"(cleared)"},i=>[{field:"workItemId",value:i.workItemId},{field:"assignee",value:i.assignee}]),0}},Z0=[WS,HS,YS,JS,QS];var Am=[...OT,...yR,...LI,...FI,...dO,...xO,...vO,...W0,...J0,...l0,...nR,...oO,...B0,...RT,...t$,...X$,...EO,...AO,...RO,...IO,...rO,...VI,...Z0,...lF,...WF,...s0,...HF,...O0,...M0,...d0,...w0,...v0,...j0,...z0,...WT];var X0="0.1.5";function eM(){return Am.flatMap(e=>(e.paths??[]).map(t=>{let n=t.join(" "),r=AT[Na(n)];return{path:n,effect:eo(n),host:r===void 0?"shared":"terminal",...r===void 0?{}:{reason:r}}})).sort((e,t)=>e.path.localeCompare(t.path))}s(eM,"plexusCommandCatalog");import Fo from"node:path";function BJ(e){let t=st()?.workspaceRoot??process.cwd(),n=Fo.resolve(t,e),r=Fo.relative(t,n);if(Fo.isAbsolute(e)||r===".."||r.startsWith(`..${Fo.sep}`))throw new Error("plexus: use a relative path inside the current workspace.");return{absolute:n,relative:r}}s(BJ,"workspacePath");function VJ(e){let{absolute:t,relative:n}=BJ(e.path??".");if(e.operation==="list"){if(!Oe(t))return{files:[]};let r=[],i=s(o=>{for(let a of Vi(o,{withFileTypes:!0})){if(a.isSymbolicLink())throw new Error("plexus: workspace symlinks are not supported.");let l=Fo.join(o,a.name);if(a.isDirectory()?i(l):r.push(Fo.relative(t,l)),r.length>200)throw new Error("plexus: the workspace contains too many files. List a subdirectory.")}},"visit");return i(t),{files:r.sort()}}if(!n)throw new Error("plexus: name a workspace file.");if(["read","search","edit"].includes(e.operation)){let r=ke(t);if(r.length>10*1024*1024)throw new Error("plexus: the workspace file exceeds 10 MB.");let i=new TextDecoder("utf-8",{fatal:!0}).decode(r);if(e.operation==="read"){let l=e.offset??0,d=e.maxChars??8e3,c=i.slice(l,l+d);return{path:n,content:c,...l||c.length<i.length?{offset:l,nextOffset:l+c.length<i.length?l+c.length:null,totalCharacters:i.length}:{}}}if(e.operation==="search"){if(!e.query)throw new Error("plexus: search needs a nonempty query.");let l=[],d=e.offset??0;for(;l.length<10;){let c=i.indexOf(e.query,d);if(c<0)break;l.push({offset:c,text:i.slice(Math.max(0,c-160),c+e.query.length+240)}),d=c+e.query.length}return{path:n,matches:l,nextOffset:l.length===10?d:null}}if(!e.oldText||typeof e.content!="string")throw new Error("plexus: edit needs oldText and replacement content.");let o=i.indexOf(e.oldText);if(o<0||o!==i.lastIndexOf(e.oldText))throw new Error("plexus: oldText must match exactly once. Read the current file and choose unique context.");let a=i.slice(0,o)+e.content+i.slice(o+e.oldText.length);if(Buffer.byteLength(a)>10*1024*1024)throw new Error("plexus: the edited file exceeds 10 MB.");return ht(t,a,"utf8"),{path:n,sizeBytes:Buffer.byteLength(a)}}if(e.operation==="write"){if(typeof e.content!="string"||Buffer.byteLength(e.content)>1e6)throw new Error("plexus: file content is missing or too large.");return Wt(Fo.dirname(t),{recursive:!0}),ht(t,e.content,"utf8"),{path:n,sizeBytes:Buffer.byteLength(e.content)}}if(e.operation==="remove")return Ko(t),{path:n,removed:!0};throw new Error("plexus: unknown workspace operation.")}s(VJ,"plexusWorkspace");function tM(e){return s(async function(n,r){if(!r||typeof r!="object"||Array.isArray(r))throw new Error("plexus: tool input must be an object.");let i=r,o=Da[n];if(!o||!Object.hasOwn(Da,n))throw new Error("plexus: unknown agent tool.");if(Object.keys(i).some(a=>!Object.hasOwn(o.inputSchema.properties,a)))throw new Error("plexus: unexpected tool argument.");if(n==="plexus"){if(!Array.isArray(i.argv)||i.argv.some(a=>typeof a!="string")||i.stdin!==void 0&&typeof i.stdin!="string")throw new Error("plexus: invalid command input.");return e.inspectCommand(i.argv),e.executeCommand({argv:i.argv,...i.stdin===void 0?{}:{stdin:i.stdin}})}if(n==="plexus_skill"){if(typeof i.path!="string"||i.path.length>240||!Object.hasOwn(Kh,i.path))throw new Error("plexus: unknown skill reference. Start with SKILL.md.");return{path:i.path,content:Kh[i.path],skillHash:mu}}if(typeof i.operation!="string"||!["list","read","search","edit","write","remove"].includes(i.operation)||i.path!==void 0&&(typeof i.path!="string"||i.path.length>500)||i.content!==void 0&&(typeof i.content!="string"||i.content.length>1e6)||i.oldText!==void 0&&(typeof i.oldText!="string"||i.oldText.length>1e6)||i.query!==void 0&&(typeof i.query!="string"||!i.query.length||i.query.length>1e3)||i.offset!==void 0&&(typeof i.offset!="number"||!Number.isSafeInteger(i.offset)||i.offset<0)||i.maxChars!==void 0&&(typeof i.maxChars!="number"||!Number.isSafeInteger(i.maxChars)||i.maxChars<1||i.maxChars>24e3))throw new Error("plexus: invalid workspace input.");return VJ(i)},"executePlexusAgentTool")}s(tM,"createPlexusAgentToolExecutor");var Em=tM({inspectCommand:rM,executeCommand:iM});function Tm(){let e=new Uo({binaryLabel:"Plexus CLI",binaryName:"plexus-cli",binaryVersion:X0});e.register(ya.HelpCommand),e.register(ya.VersionCommand);for(let n of Am)e.register(n);async function t(n,r){let i;try{i=e.process(n,r)}catch(o){return(r.stderr??process.stderr).write(e.error(o,{colored:!1})),2}return zJ(i,r.stderr??process.stderr),e.run(i,r)}return s(t,"run"),{process(n,r){return e.process(n,r)},run:t,async runExit(n,r){process.exitCode=await t(n,r)}}}s(Tm,"createPlexusCli");function zJ(e,t){let n=e.path.join(" "),r=e.constructor.paths?.[0]?.join(" ");r!==void 0&&n!==r&&_a[n]===r&&dt(t,n,r),n in _a&&eo(n)==="confirm"&&!Ca(e)&&t.write(`plexus-cli: \`${_a[n]}\` only prints its plan without --confirm \u2014 nothing was changed.
9765
9765
  `)}s(zJ,"noteRetiredPath");function rM(e){let t=Tm().process(la(e),{executePlexusAgentTool:Em}),n=t.path.join(" ");if(n.startsWith("agent "))throw new Error("plexus: nested agent transports are not allowed.");let r=eM().find(l=>l.path===n);if(!r){if(n===""||n==="--help"||n==="--version")return{path:n,writes:!1,host:"shared"};throw new Error(`plexus: command ${n} has no host classification.`)}let i=t,o=r.effect==="callKind"?xf(xs(Ss),i.fn??"",i.kind):void 0,a=fu(n,{confirm:Ca(t),callKind:o});return{...r,writes:a}}s(rM,"inspectPlexusCommand");async function iM(e,t){if(t)return eA(t,()=>iM(e));if(!Array.isArray(e.argv)||e.argv.length===0||e.argv.length>128||e.argv.some(l=>typeof l!="string"||l.length>128e3)||(e.stdin?.length??0)>1e6)throw new Error("plexus: invalid command invocation.");let n="",r="",i=Tm();if(st()){let l=rM(e.argv);if(l.host==="terminal")throw new Error(`plexus: this command requires a local machine. ${l.reason??""}`)}return{exitCode:await i.run(la(e.argv),{executePlexusAgentTool:Em,stdin:GJ.from(e.stdin===void 0?[]:[e.stdin]),stdout:new nM({write(l,d,c){n+=String(l),c()}}),stderr:new nM({write(l,d,c){r+=String(l),c()}})}),stdout:n,stderr:r}}s(iM,"executePlexusCommand");oA({source:WJ.join(import.meta.dirname,"skill")});Tm().runExit(la(process.argv.slice(2)),{executePlexusAgentTool:Em});
9766
9766
  //# sourceMappingURL=cli.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartkomm/plexus-cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Unified Plexus admin + admission-offer config CLI (Convex backend).",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",