@smartkomm/plexus-cli 0.1.9 → 0.1.10

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/README.md CHANGED
@@ -887,8 +887,11 @@ is refused (`FORBIDDEN`, naming the field) when it would create a tenant, use
887
887
  `tenant.*` key except `branding`, `brandingAssets`, `notificationChrome` (modules,
888
888
  `defaultApplicantGroupKey`, `mailLevel`, `magicLinkLogin`, `externalSignIn`, terms, …) or the import `source`
889
889
  — name a `foundation.users` address that is not an active member with a login, or put a
890
- `_platform.*` right in a group; changing groups or `foundation.users` additionally needs
891
- `administration.permissions.manage` / `administration.users.manage`. `wipe`, `prune-offers`, `--scope platform` and setup mode
890
+ `_platform.*` right in a group; changing groups needs `administration.permissions.manage`,
891
+ changing `foundation.users` needs `administration.users.manage`, and giving, moving or taking a
892
+ user's group there (a user new to the config, `permissionGroupKey`, `unitKey`, validity,
893
+ `additionalMemberships`) needs `administration.permissions.manage` as well — the rule the
894
+ Rechteverwaltung asks. `wipe`, `prune-offers`, `--scope platform` and setup mode
892
895
  stay platform-only. Recipe:
893
896
  [playbooks/users/cli-access-for-tenant-admin.md](./playbooks/users/cli-access-for-tenant-admin.md).
894
897
 
package/dist/cli.mjs CHANGED
@@ -8973,7 +8973,7 @@ plexus-cli --env <env> users show <old@domain> # \u2192 No user with email \
8973
8973
  ## Related
8974
8974
  - [Set (rotate) a user's password](./set-password.md)
8975
8975
  - [Debug a mail delivery](../notifications/debug-mail-delivery.md)
8976
- `,"references/users/cli-access-for-tenant-admin.md":'# CLI access for a tenant admin\n\n**When to use:** a school\'s own administrator (no platform rights) should run\n`plexus-cli` for **exactly their tenant**: export, plan and apply its config\n(`config export|apply|set`) and its admission offers (`offer \u2026`). Example: the\nadministrator of one school group onboarding their own offers.\n\nThe person gets a `plx_\u2026` token that acts **as them**. It reaches exactly the\ntenants their own login reaches \u2014 no other tenant, no platform surface. **A token\nworks only while its owner holds `administration.apiTokens.manage`** (platform:\n`_platform.apiTokens.manage`): every CLI call asks the right again, and the\nchange that takes the right away revokes the person\'s tokens.\n\n## Prerequisites\n- **The person is a tenant member with a login.** No login yet \u2192\n [Add a tenant admin](./add-tenant-admin.md) first.\n- **Every `tenant_admin` holds the three CLI rights** \u2014 `administration.apiTokens.manage`\n (mint a token), `administration.config.read` / `.manage` (config, held\n **tenant-wide**). They are part of the derived `tenant_admin` and reach existing\n tenants on every deploy; nothing to grant. Someone outside `tenant_admin` needs a\n group holding them.\n- **Offer commands** need `bewerbungsmanagement.forms.configure` (in `tenant_admin`).\n A config change to groups or members also needs\n `administration.permissions.manage` / `.users.manage` (in `tenant_admin`).\n- **Your auth (issuing for them):** a platform token with `_platform.users.manage`\n **and** `_platform.apiTokens.manage` \u2014 the token acts as the person.\n- `--env` is required for the write; prod also needs `--allow-prod`.\n\n## Steps\n\n**0 \u2014 check the person is a `tenant_admin`:**\n\n```bash\nplexus-cli --env <env> users show <email> # groups: tenant_admin, \u2026\n```\n\n**A \u2014 the administrator mints it themselves:** in the app, *Einstellungen \u2192\nAPI-Token* (\u201EToken erstellen"), or with a token they already have:\n`plexus-cli --env <env> tokens create laptop`.\n\n**B \u2014 the platform issues it for them** (to hand over directly):\n\n```bash\nplexus-cli --env <env> tokens create cli --for <email> --out /tmp/token-<slug>.csv --quiet\n```\n\n- The token is shown **once**. `--out` appends `email,token` to the CSV (never overwrites it ;\n a file with a different header, e.g. a password file, is refused); `--quiet` keeps it\n out of stdout. Without `--out`, it is printed.\n- Refused when the address has no account (`kein Konto`), no login, or holds\n `administration.apiTokens.manage` in no tenant (`in keinem Mandanten`) \u2014 including\n platform operators, who are tenant-less.\n- The token records who issued it.\n\n**The administrator\'s setup** (`~/.config/agent-tools/plexus.yml`; see SKILL.md \u2192\nConnect, or `plexus-cli --help`). The platform operator provides the staging URLs:\n\n```yaml\nplexus:\n default_env: staging\n default_tenant: <slug>\n environments:\n staging: { convex_url: "https://<staging-convex-url>", site_url: "https://<staging-site-url>", token: "plx_\u2026" }\n # Required even without a prod token: every write compares its target with\n # the prod URL (refused otherwise: "names no environments.prod.convex_url").\n prod: { convex_url: "https://db.plexus.swop.schule", site_url: "https://actions.db.plexus.swop.schule" }\n```\n\n## Verify\n\nAs the administrator\'s token:\n\n```bash\nplexus-cli --env <env> whoami\nplexus-cli --env <env> config export --tenant <slug> --out ./<slug>/config.json # passes\nplexus-cli --env <env> config export --tenant <other-slug> --out /tmp/x.json # FORBIDDEN / NOT_FOUND\nplexus-cli --env <env> config apply --tenant <slug> --from snapshot:./<slug>/config.json # dry run passes\n```\n\n## What a tenant-scoped apply refuses (FORBIDDEN, naming the field)\n- a tenant that does not exist (no onboarding), `--from blueprint`, `--allow-destructive`;\n- any `tenant.*` setting except `branding`, `brandingAssets`, `notificationChrome`\n differing from live \u2014 modules (`enabledModules` decides the permission allowlist),\n `defaultApplicantGroupKey`, `mailLevel`, `magicLinkLogin`, terms, \u2026;\n- the import `source`;\n- a `foundation.users` address that is not an **active** member with a login (no new\n accounts, no other tenant\'s people, no revoked member brought back);\n- a `_platform.*` right in any permission group.\n\nA change to the permission groups additionally needs `administration.permissions.manage`,\na change to `foundation.users` (who sits in which group) `administration.users.manage` \u2014\nthe rights the app asks for the same act (`tenant_admin` holds both).\n\nCopy those values from `config export` unchanged; a change to them is a platform task.\nPlatform-only regardless: `config wipe`, `config prune-offers`, `config apply --scope\nplatform`, setup mode (Load N / wipe), `offer delete` (the hard delete).\n\n## Idempotency / gotchas\n- Minting again makes a **second** token; revoke the old one with `tokens list` \u2192\n `tokens revoke <id> --confirm`. Without the right, the CLI refuses every call \u2014 listing and\n revoking your own tokens then works in the app (Settings \u2192 API-Token) only.\n- Taking the right away (group removed or narrowed, tenant access ended, user\n deactivated, module dropped by `config apply` or the deploy, platform right\n dropped) **revokes** the person\'s tokens in the same change. Giving the\n right back does not revive them \u2014 mint a new one. The exchange then answers 401\n \u201EDas API-Token \u201E\u2026\u201C wurde am <Datum> widerrufen: <Grund>\u201C. A right that lapses without a\n write is still caught: every CLI call asks it and refuses with 403 \u201EIhr Konto hat\n das Recht \u201EAPI-Tokens: Verwalten\u201C nicht mehr \u2026\u201C.\n- A tenant member cannot be made platform admin (`users set-platform-admin`):\n platform rights and tenant access exclude each other \u2014 an inactive access row\n counts too.\n- A unit-scoped membership does not count for config: the right must be held\n tenant-wide.\n\n## Related\n- [Add a tenant admin](./add-tenant-admin.md) \u2014 the login itself.\n- [Edit a live tenant\'s offer](../offer/edit-live-tenant-offer.md).\n',"references/users/delete-permission-group.md":`# Delete a tenant permission group
8976
+ `,"references/users/cli-access-for-tenant-admin.md":'# CLI access for a tenant admin\n\n**When to use:** a school\'s own administrator (no platform rights) should run\n`plexus-cli` for **exactly their tenant**: export, plan and apply its config\n(`config export|apply|set`) and its admission offers (`offer \u2026`). Example: the\nadministrator of one school group onboarding their own offers.\n\nThe person gets a `plx_\u2026` token that acts **as them**. It reaches exactly the\ntenants their own login reaches \u2014 no other tenant, no platform surface. **A token\nworks only while its owner holds `administration.apiTokens.manage`** (platform:\n`_platform.apiTokens.manage`): every CLI call asks the right again, and the\nchange that takes the right away revokes the person\'s tokens.\n\n## Prerequisites\n- **The person is a tenant member with a login.** No login yet \u2192\n [Add a tenant admin](./add-tenant-admin.md) first.\n- **Every `tenant_admin` holds the three CLI rights** \u2014 `administration.apiTokens.manage`\n (mint a token), `administration.config.read` / `.manage` (config, held\n **tenant-wide**). They are part of the derived `tenant_admin` and reach existing\n tenants on every deploy; nothing to grant. Someone outside `tenant_admin` needs a\n group holding them.\n- **Offer commands** need `bewerbungsmanagement.forms.configure` (in `tenant_admin`).\n A config change to groups needs `administration.permissions.manage`, to members\n `.users.manage`, and one that changes a member\'s group both (all in `tenant_admin`).\n- **Your auth (issuing for them):** a platform token with `_platform.users.manage`\n **and** `_platform.apiTokens.manage` \u2014 the token acts as the person.\n- `--env` is required for the write; prod also needs `--allow-prod`.\n\n## Steps\n\n**0 \u2014 check the person is a `tenant_admin`:**\n\n```bash\nplexus-cli --env <env> users show <email> # groups: tenant_admin, \u2026\n```\n\n**A \u2014 the administrator mints it themselves:** in the app, *Einstellungen \u2192\nAPI-Token* (\u201EToken erstellen"), or with a token they already have:\n`plexus-cli --env <env> tokens create laptop`.\n\n**B \u2014 the platform issues it for them** (to hand over directly):\n\n```bash\nplexus-cli --env <env> tokens create cli --for <email> --out /tmp/token-<slug>.csv --quiet\n```\n\n- The token is shown **once**. `--out` appends `email,token` to the CSV (never overwrites it ;\n a file with a different header, e.g. a password file, is refused); `--quiet` keeps it\n out of stdout. Without `--out`, it is printed.\n- Refused when the address has no account (`kein Konto`), no login, or holds\n `administration.apiTokens.manage` in no tenant (`in keinem Mandanten`) \u2014 including\n platform operators, who are tenant-less.\n- The token records who issued it.\n\n**The administrator\'s setup** (`~/.config/agent-tools/plexus.yml`; see SKILL.md \u2192\nConnect, or `plexus-cli --help`). The platform operator provides the staging URLs:\n\n```yaml\nplexus:\n default_env: staging\n default_tenant: <slug>\n environments:\n staging: { convex_url: "https://<staging-convex-url>", site_url: "https://<staging-site-url>", token: "plx_\u2026" }\n # Required even without a prod token: every write compares its target with\n # the prod URL (refused otherwise: "names no environments.prod.convex_url").\n prod: { convex_url: "https://db.plexus.swop.schule", site_url: "https://actions.db.plexus.swop.schule" }\n```\n\n## Verify\n\nAs the administrator\'s token:\n\n```bash\nplexus-cli --env <env> whoami\nplexus-cli --env <env> config export --tenant <slug> --out ./<slug>/config.json # passes\nplexus-cli --env <env> config export --tenant <other-slug> --out /tmp/x.json # FORBIDDEN / NOT_FOUND\nplexus-cli --env <env> config apply --tenant <slug> --from snapshot:./<slug>/config.json # dry run passes\n```\n\n## What a tenant-scoped apply refuses (FORBIDDEN, naming the field)\n- a tenant that does not exist (no onboarding), `--from blueprint`, `--allow-destructive`;\n- any `tenant.*` setting except `branding`, `brandingAssets`, `notificationChrome`\n differing from live \u2014 modules (`enabledModules` decides the permission allowlist),\n `defaultApplicantGroupKey`, `mailLevel`, `magicLinkLogin`, terms, \u2026;\n- the import `source`;\n- a `foundation.users` address that is not an **active** member with a login (no new\n accounts, no other tenant\'s people, no revoked member brought back);\n- a `_platform.*` right in any permission group.\n\nA change to the permission groups additionally needs `administration.permissions.manage`,\na change to `foundation.users` (who sits in which group) `administration.users.manage` \u2014\nthe rights the app asks for the same act (`tenant_admin` holds both).\n\nCopy those values from `config export` unchanged; a change to them is a platform task.\nPlatform-only regardless: `config wipe`, `config prune-offers`, `config apply --scope\nplatform`, setup mode (Load N / wipe), `offer delete` (the hard delete).\n\n## Idempotency / gotchas\n- Minting again makes a **second** token; revoke the old one with `tokens list` \u2192\n `tokens revoke <id> --confirm`. Without the right, the CLI refuses every call \u2014 listing and\n revoking your own tokens then works in the app (Settings \u2192 API-Token) only.\n- Taking the right away (group removed or narrowed, tenant access ended, user\n deactivated, module dropped by `config apply` or the deploy, platform right\n dropped) **revokes** the person\'s tokens in the same change. Giving the\n right back does not revive them \u2014 mint a new one. The exchange then answers 401\n \u201EDas API-Token \u201E\u2026\u201C wurde am <Datum> widerrufen: <Grund>\u201C. A right that lapses without a\n write is still caught: every CLI call asks it and refuses with 403 \u201EIhr Konto hat\n das Recht \u201EAPI-Tokens: Verwalten\u201C nicht mehr \u2026\u201C.\n- A tenant member cannot be made platform admin (`users set-platform-admin`):\n platform rights and tenant access exclude each other \u2014 an inactive access row\n counts too.\n- A unit-scoped membership does not count for config: the right must be held\n tenant-wide.\n\n## Related\n- [Add a tenant admin](./add-tenant-admin.md) \u2014 the login itself.\n- [Edit a live tenant\'s offer](../offer/edit-live-tenant-offer.md).\n',"references/users/delete-permission-group.md":`# Delete a tenant permission group
8977
8977
 
8978
8978
  Remove a permission group that should not exist \u2014 typically one created by an
8979
8979
  accidental click in Administration \u2192 Berechtigungen, which the admin UI can
@@ -9374,7 +9374,7 @@ plexus-cli --env prod jobs list --status running # nothing unexpectedly in
9374
9374
  ## Related
9375
9375
  - Command reference: \`plexus-cli jobs list --help\`, \`plexus-cli workers reap --help\`,
9376
9376
  \`plexus-cli imports cleanup-orphaned --help\`.
9377
- `};var mu="5a0fb71b57eb1ad6e95597654e221c5a712d0efc05ec1268c91ac66458ed1e0d",jh=OT;var Bh=class extends Se{static{s(this,"AgentToolsCommand")}static paths=[["agent","tools"]];static usage=E.Usage({category:"Agents",description:"Show the shared platform/CLI agent tool schemas and skill revision."});async execute(){return this.print({skillHash:mu,tools:Da}),0}},Vh=class extends Se{static{s(this,"AgentInvokeCommand")}static paths=[["agent","invoke"]];static usage=E.Usage({category:"Agents",description:"Invoke a shared agent tool; pipe its JSON input on stdin."});tool=p.String("--tool",{required:!0,description:"plexus|plexus_skill|plexus_workspace"});async execute(){if("isTTY"in this.context.stdin&&this.context.stdin.isTTY===!0)throw new Error("plexus: pipe the tool's JSON input on stdin.");let t=JSON.parse(await Kh(this.context.stdin)),n=await this.context.executePlexusAgentTool(this.tool,t);return this.print(n),0}},PT=[Bh,Vh];var Uh=[{key:"fixture_test",email:"test@example.com",firstName:"Test",lastName:"Bewerber"}],Uee=new Set(Uh.map(e=>e.key));function NT(e,t,n,r){let i=e.flatMap(l=>l.angebote).find(l=>l.offerKey===t);if(i===void 0){let l=e.flatMap(d=>d.angebote.map(c=>c.offerKey));throw new Error(`applications start-test: no offer "${t}" (offers: ${l.join(", ")||"none"})`)}let o=i.stages.find(l=>l.stageKey===r||l.stageId===r);if(o===void 0){let l=i.stages.map(d=>`${d.stageKey} (${d.stageId})`);throw new Error(`applications start-test: no level "${r}" in ${t} \u2014 name it by key or id: ${l.join(", ")}`)}let a=o.runs.find(l=>l.runKey===n||l.runId===n);if(a===void 0){let l=o.runs.map(d=>`${d.runKey} (${d.runId})`);throw new Error(`applications start-test: no school year "${n}" for level ${o.stageKey} \u2014 name it by key or id: ${l.join(", ")}`)}if(!a.isOpen)throw new Error(`applications start-test: school year ${a.runKey} is closed for level ${o.stageKey}`);return{programRunId:a.runId,programStageId:o.stageId}}s(NT,"resolveStartTarget");function Rj(e){return e.kind==="named"?e.name:`(${e.standIn??e.fallback})`}s(Rj,"applicantText");function CT(e){return e.map(t=>({id:t.application._id,status:t.deletedAt?`${t.application.status} (gel\xF6scht)`:t.application.status,state:t.currentProcessStateId??"",applicant:Rj(t.applicantName),test:t.application.testMode===!0?"test":""}))}s(CT,"applicationRows");var _T=Uh.map(e=>e.email);function DT(e,t,n,r){if(n===void 0&&r===void 0)throw new Error("applications start-test: name the applicant \u2014 --party <partyId> or --applicant <email>");if(n!==void 0&&r!==void 0)throw new Error("applications start-test: --party or --applicant, not both");if(Fh(e,t)&&(r===void 0||!_T.includes(r.trim().toLowerCase())))throw new Error(`applications start-test: on prod only for the test account ${_T.join(", ")} (--applicant) \u2014 never a real family's`)}s(DT,"assertStartApplicant");function FT(e){let t={};for(let{address:n,...r}of e.entries)t[n]=r;return{applicationId:e.applicationId,store:t}}s(FT,"processStoreJson");function Ij(e){switch(e.kind){case"form":return`form ${e.formInstanceId} (${e.state})`;case"document":return e.file===null?`document ${e.slotKey} (leer)`:`document ${e.slotKey} \xB7 v${e.file.versionNumber} ${e.file.filename??e.file.artifactId}`;case"contract":return`contract ${e.contractId} \xB7 ${e.revision===null?"keine Fassung":`Fassung ${e.revision.revisionNumber}`} \xB7 ${e.contractStatus}`;case"contracts":return e.contracts.map(t=>`${t.partKey}: contract ${t.contractId} \xB7 ${t.revision===null?"keine Fassung":`Fassung ${t.revision.revisionNumber}`} \xB7 ${t.contractStatus}`).join("; ")}}s(Ij,"refText");function Oj(e){return e.state!=="present"?e.reason?.de??"":e.ref!==void 0?Ij(e.ref):JSON.stringify(e.value)}s(Oj,"holds");function LT(e){return e.entries.map(t=>({address:t.address,state:t.state,holds:Oj(t),producer:t.producer?.label??"",written:t.writtenAt===void 0?"":new Date(t.writtenAt).toISOString()}))}s(LT,"storeRows");function hu(e){let t={},n={};for(let r of e){let i=r.indexOf("=");if(i<=0)throw new Error(`Expected key=value, got '${r}'.`);let o=r.slice(0,i);if(Object.hasOwn(n,o))throw new Error(`'${o}' is given twice.`);let a=r.slice(i+1);n[o]=a;try{t[o]=JSON.parse(a)}catch{t[o]=a}}return{values:t,raw:n}}s(hu,"parseKv");var MT="started",gu="submitted",qT="submitted",KT="load-scenario:";var jT="(Bewerbung)";function BT(e){return{nodeId:jT,actions:e.map(t=>({id:t.id,label:{de:`${t.label??t.id}${t.count===void 0?"":` (${t.count})`}`,en:`${t.label??t.id}${t.count===void 0?"":` (${t.count})`}`},...t.disabledReason===void 0?{}:{disabledReason:t.disabledReason}}))}}s(BT,"sharedAsList");function VT(e){return e.disabledReason===void 0?"":e.disabledCount===void 0?e.disabledReason:`${e.disabledReason} (${e.disabledCount})`}s(VT,"disabledText");function UT(e){return e.flatMap(({nodeId:t,actions:n})=>n.map(r=>({node:t,action:r.id,label:r.label.de,disabled:VT(r)})))}s(UT,"actionRows");function GT(e,t,n=[]){let r=e.filter(({actions:d})=>d.some(c=>c.id===t));if(r.length===0){let d=[...new Set(e.flatMap(({actions:c})=>c.map(u=>u.id)))];throw new Error(`test-actions run: no current node offers "${t}" (offered: ${d.join(", ")||"nothing"})`)}if(r.length>1)throw new Error(`test-actions run: "${t}" is offered by ${r.map(d=>d.nodeId).join(", ")} \u2014 pass --node`);let{nodeId:i,actions:o}=r[0],a=o.find(d=>d.id===t);if(a.disabledReason!==void 0)throw new Error(`test-actions run: "${t}" on ${i} is disabled: ${VT(a)}`);if(i!==jT)return i;let l=n[0];if(l===void 0)throw new Error(`test-actions run: "${t}" needs a current node \u2014 the application has none`);return l}s(GT,"nodeOfferingAction");function zT(e,t,n){if(e.startsWith(KT)){if(Object.hasOwn(n,"autoSubmit"))throw new Error(`test-actions run: ${e}: a scenario's autoSubmit is set by --auto-submit / --no-auto-submit, not --param`);return{autoSubmit:t,...n}}return Object.keys(n).length===0?void 0:{...n}}s(zT,"runParams");async function Pj(e,t){let n=await e.query(S.workflow.getInstance,{applicationId:t});if(n===null)throw new Error(`test-actions: application ${t} has no workflow instance`);return n.instance.currentNodeIds}s(Pj,"currentNodeIds");function _j(e,t){switch(t){case"notTestApplication":return`${e} is not a test application`;case"completed":case"aborted":case"deleted":return`${e} is ${t} \u2014 test actions run only on an active application`;case"missingPermission":return"the caller lacks bewerbungsmanagement.testActions.run"}}s(_j,"refusalText");async function yu(e,t,n){let r=await e.query(S.workflow.listSharedTestActions,{applicationId:t});if(!r.permitted)throw new Error(`test-actions: not permitted \u2014 ${_j(t,r.reason)}`);let i=[];for(let o of n){let a=await e.query(S.workflow.listTestActions,{applicationId:t,nodeId:o});if(a===null)throw new Error(`test-actions: node "${o}" is not in this application's workflow (or it has no instance)`);i.push({nodeId:o,actions:a})}return[...i,BT(r.actions)]}s(yu,"actionsOf");async function WT(e,t,n){return n!==void 0?[n]:await Pj(e,t)}s(WT,"nodesOf");var Gh=class extends D{static{s(this,"TestActionsListCommand")}static paths=[["test-actions","list"]];static usage=E.Usage({category:"Admission",description:"List the test-mode actions of the application's current node(s) (scenarios, auto-fill-files, submit, \u2026) and the application-wide ones"});application=p.String("--application",{required:!0,description:"Application id (a test application)"});node=p.String("--node",{description:"Node id (default: the application's current nodes)"});async execute(){let t=await this.caller(),n=await yu(t,this.application,await WT(t,this.application,this.node));return this.print(n,UT,["node","action","label","disabled"]),0}},zh=class extends D{static{s(this,"TestActionsRunCommand")}application=p.String("--application",{required:!0,description:"Application id (a test application)"});node=p.String("--node",{description:"Node id (default: the application's current nodes)"});static paths=[["test-actions","run"]];static usage=E.Usage({category:"Admission",description:"Run one test-mode action; a scenario (load-scenario:<id>) also submits unless --no-auto-submit"});action=p.String("--action",{required:!0,description:"Action id, e.g. load-scenario:standard, auto-fill-files, submit-form"});autoSubmit=p.Boolean("--auto-submit",!0,{description:"Scenario only: stub the file fields and submit after loading (default on; --no-auto-submit only loads)"});param=p.Array("--param",{description:"Action parameter key=value (repeatable; the value is JSON where it parses, else text), e.g. --param confirmed=true for an action that asks a question first (upload-signed-document)"});async execute(){let t=zT(this.action,this.autoSubmit,hu(this.param??[]).values),n=await this.caller(),r=this.application,i=await WT(n,this.application,this.node),o=GT(await yu(n,r,i),this.action,i);return await n.mutation(S.workflow.runTestAction,{applicationId:r,nodeId:o,actionId:this.action,...t===void 0?{}:{params:t}}),this.print({ran:this.action,on:o},a=>[{key:"ran",value:a.ran},{key:"on",value:a.on},{key:"next",value:"test-actions list \u2014 file fills and the submit after them run asynchronously"}]),0}},HT=[Gh,zh];var Je=["de","en"];function Xo(e,t){return Je.every(n=>e[n]===t[n])}s(Xo,"sameText");function yt(e){if(e===null||typeof e!="object"||Array.isArray(e))return"not-localized";let t=e;return Object.keys(t).some(r=>!Je.includes(r))?"not-localized":Je.filter(r=>{let i=t[r];return typeof i!="string"||i.trim()===""})}s(yt,"missingLocales");function mi(e){let t=yt(e);return t!=="not-localized"&&t.length===0}s(mi,"isLocalizedText");function Fa(e,t){let n={};for(let r of Je){let i=e.map(o=>o[r]);n[r]=i.every(o=>typeof o=="string"&&o.trim()!=="")?t(i,r):""}return n}s(Fa,"composeTexts");var er=/^[a-z][A-Za-z0-9]*$/;function Wh(e){return typeof e=="string"&&er.test(e)}s(Wh,"isNodeId");function es(e,t){Wh(e)||_(`[graph/nodeIdFormat] "${e}" cannot name a node: a node id is ${er.source}.`);let n=new Set(t);if(!n.has(e))return e;let r=2;for(;n.has(`${e}${r}`);)r++;return`${e}${r}`}s(es,"makeNodeId");var hi="$env";function se(e){if(e.scope==="env")return`${hi}.${e.key}`;let t=e.scope==="derived"?`$derived.${e.key}`:`$${e.scope}.${e.owner}.${e.key}`;return e.path===void 0?t:`${t}.${e.path}`}s(se,"formatAddress");var wr=/^[a-z][a-zA-Z0-9_]*$/,Nj=/^[A-Za-z_][A-Za-z0-9_]*$/;function to(e){return typeof e=="string"&&e.split(".").every(t=>Nj.test(t))}s(to,"isPath");function qr(e){if(!e.startsWith("$"))return null;let t=e.slice(1).split("."),[n,...r]=t;switch(n){case"env":{let i=r.join(".");return r.length>0&&to(i)?{scope:"env",key:i}:null}case"derived":{let[i,...o]=r;return i===void 0||!wr.test(i)?null:YT({scope:"derived",key:i},o)}case"node":case"task":{let[i,o,...a]=r;return i===void 0||o===void 0||!wr.test(o)||(n==="node"?!er.test(i):!wr.test(i))?null:YT({scope:n,owner:i,key:o},a)}default:return null}}s(qr,"tryParseAddress");function YT(e,t){if(t.length===0)return e;let n=t.join(".");return to(n)?{...e,path:n}:null}s(YT,"withPath");function ve(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;let t=e,n=t.scope==="env"?["scope","key"]:t.scope==="derived"?["scope","key","path"]:["scope","owner","key","path"];if(Object.keys(t).some(r=>!n.includes(r))||t.path!==void 0&&!to(t.path))return!1;switch(t.scope){case"env":return to(t.key);case"derived":return typeof t.key=="string"&&wr.test(t.key);case"node":return typeof t.owner=="string"&&er.test(t.owner)&&typeof t.key=="string"&&wr.test(t.key);case"task":return typeof t.owner=="string"&&wr.test(t.owner)&&typeof t.key=="string"&&wr.test(t.key);default:return!1}}s(ve,"isAddress");var Kr={offer:{key:"string",title:"string"},unit:{key:"string",name:"string"},stage:{key:"string",name:"string",gradeLevel:"number"},run:{key:"string",name:"string",startDate:"date"},applicant:{language:"enum",channel:"enum"}},ts=Object.keys(Kr);function ns(e){return Object.hasOwn(Kr,e)}s(ns,"isEnvKey");var Cj=["self-service","staff"];function JT(e,t){return{kind:"fixed",values:e,labels:t}}s(JT,"fixedSet");var wu={of:"applicant.language",withoutValue:"de"},jr={"offer.key":{valueSet:{kind:"live"},nullable:!1,label:{de:"Angebot",en:"Offer"}},"offer.title":{valueSet:{kind:"unstable"},nullable:!1,label:{de:"Titel des Angebots",en:"Offer title"},nameLanguage:wu},"unit.key":{valueSet:{kind:"live"},nullable:!1,label:{de:"Einheit",en:"Unit"}},"unit.name":{valueSet:{kind:"unstable"},nullable:!1,label:{de:"Name der Einheit",en:"Unit name"},nameLanguage:wu},"stage.key":{valueSet:{kind:"unstable"},nullable:!1,label:{de:"Klassenstufe (Schl\xFCssel)",en:"Grade (key)"},cohortBound:!0},"stage.name":{valueSet:{kind:"unstable"},nullable:!1,label:{de:"Name der Klassenstufe",en:"Grade name"},cohortBound:!0,nameLanguage:wu},"stage.gradeLevel":{valueSet:{kind:"open"},nullable:!0,absent:{de:"Die Stufe hat keine Klassenstufe (Kindergarten).",en:"The stage has no grade level (Kindergarten)."},label:{de:"Klassenstufe",en:"Grade level"},cohortBound:!0},"run.key":{valueSet:{kind:"unstable"},nullable:!1,label:{de:"Schuljahr",en:"School year"},cohortBound:!0},"run.name":{valueSet:{kind:"unstable"},nullable:!1,label:{de:"Name des Schuljahrs",en:"School year name"},cohortBound:!0,nameLanguage:wu},"run.startDate":{valueSet:{kind:"open"},nullable:!0,absent:{de:"F\xFCr das Schuljahr ist kein Beginn erfasst.",en:"The school year has no start date."},label:{de:"Beginn des Schuljahrs",en:"School year start"},cohortBound:!0},"applicant.language":{valueSet:JT(Je,{de:{de:"Deutsch",en:"German"},en:{de:"Englisch",en:"English"}}),nullable:!0,absent:{de:"Die Bewerbung hat kein Bewerberkonto (intern angelegt).",en:"The application has no applicant account (started by staff)."},label:{de:"Bewerbersprache",en:"Applicant language"}},"applicant.channel":{valueSet:JT(Cj,{staff:{de:"intern",en:"in-house"},"self-service":{de:"online (Familie)",en:"online (family)"}}),nullable:!1,label:{de:"Eingangsweg",en:"Intake channel"}}},bu={types:Kr,fields:jr},ku=ts.flatMap(e=>Object.keys(Kr[e]).map(t=>`${e}.${t}`));function tr(e){return Object.hasOwn(jr,e)}s(tr,"isEnvLeaf");function vu(e){return`${hi}.${e}`}s(vu,"envIdentifier");function no(e){let t=jr[e],[n,r]=e.split("."),i=Kr[n][r];i===void 0&&_(`[env] leaf "${e}" has no type`);let o=t.valueSet;return{leaf:e,type:i,label:t.label,nullable:t.nullable,...t.absent===void 0?{}:{absent:t.absent},...t.nameLanguage===void 0?{}:{nameLanguage:t.nameLanguage},...t.cohortBound===void 0?{}:{cohortBound:t.cohortBound},...o.kind==="fixed"?{enumOptions:o.values.map(a=>{let l=o.labels[a];return l===void 0&&_(`[env] "${e}" names the value "${a}" without a label`),{value:a,label:l}})}:{}}}s(no,"envLeaf");var QT="staffInput";var Dj=["boolean"],La=/^[a-z][A-Za-z0-9]*$/;function xu(e){return e.staffInputs??[]}s(xu,"staffInputsOf");function Su(e){return`${QT}.${e}`}s(Su,"staffInputLeaf");function ZT(e){return`${hi}.${Su(e)}`}s(ZT,"staffInputIdentifier");function Fj(e){let t=`${QT}.`;return e.startsWith(t)?e.slice(t.length):null}s(Fj,"staffInputKeyOfLeaf");function Ma(e,t){let n=Fj(t);return n===null?void 0:xu(e).find(r=>r.key===n)}s(Ma,"declaredStaffInput");function Lj(e){return[...xu(e).map(t=>({leaf:Su(t.key),type:t.type,label:t.label,valueSet:{kind:"open"},nullable:!1,cohortBound:!1})),...ku.map(t=>{let n=no(t);return{leaf:t,type:n.type,label:n.label,valueSet:jr[t].valueSet,nullable:n.nullable,cohortBound:n.cohortBound===!0}})]}s(Lj,"envLeavesFor");function XT(e){return Lj(e).filter(t=>!t.cohortBound)}s(XT,"conditionEnvLeaves");function e$(e){let t={},n={};for(let{leaf:r,type:i,valueSet:o,nullable:a}of XT(e)){let[l="",d=""]=r.split(".");t[l]={...t[l]??{},[d]:i},n[r]={valueSet:o,nullable:a}}return{types:t,fields:n}}s(e$,"envConditionSchemaFor");function t$(e){let t=e.staffInputs;if(t===void 0)return[];if(!Array.isArray(t))return[{path:"staffInputs",reason:{de:"[staffInput/shape] graph.staffInputs muss eine Liste sein.",en:"[staffInput/shape] graph.staffInputs must be a list."}}];let n=[],r=new Set;return t.forEach((i,o)=>{let a=`staffInputs[${o}]`,l=i;if(l===null||typeof l!="object"||typeof l.key!="string"){n.push({path:a,reason:{de:"[staffInput/shape] Eine interne Angabe braucht key, type und label ({ de, en }).",en:"[staffInput/shape] An internal entry needs key, type and label ({ de, en })."}});return}let d={de:`Interne Angabe "${l.key}"`,en:`Internal entry "${l.key}"`};La.test(l.key)||n.push({path:`${a}.key`,reason:{de:`[staffInput/keyFormat] ${d.de}: Schl\xFCssel beginnt mit einem Kleinbuchstaben und enth\xE4lt nur Buchstaben und Ziffern.`,en:`[staffInput/keyFormat] ${d.en}: the key starts with a lowercase letter and contains only letters and digits.`}}),r.has(l.key)&&n.push({path:`${a}.key`,reason:{de:`[staffInput/duplicateKey] ${d.de}: Schl\xFCssel ist doppelt vergeben.`,en:`[staffInput/duplicateKey] ${d.en}: the key is used twice.`}}),r.add(l.key),Dj.includes(l.type)||n.push({path:`${a}.type`,reason:{de:`[staffInput/unknownType] ${d.de}: Typ "${String(l.type)}" \u2014 erlaubt ist nur "boolean" (K\xE4stchen).`,en:`[staffInput/unknownType] ${d.en}: type "${String(l.type)}" \u2014 only "boolean" (checkbox) is allowed.`}});let c=yt(l.label);c==="not-localized"?n.push({path:`${a}.label`,reason:{de:`[staffInput/shape] ${d.de}: label muss { de, en } sein.`,en:`[staffInput/shape] ${d.en}: label must be { de, en }.`}}):c.length>0&&n.push({path:`${a}.label`,reason:{de:`[i18n/missingTranslation] ${d.de}: Beschriftung fehlt in ${c.join(", ")}.`,en:`[i18n/missingTranslation] ${d.en}: label is missing in ${c.join(", ")}.`}})}),n}s(t$,"staffInputIssues");var ng={required:!0,description:"Offer slug (its offerKey)"},Hh=class extends D{static{s(this,"ApplicationsListCommand")}static paths=[["applications","list"]];static usage=E.Usage({category:"Admission",description:"List an offer's applications (id, status, board state, applicant, test)"});offer=p.String("--offer",ng);testOnly=p.Boolean("--test-only",!1,{description:"Only test applications"});async execute(){let t=await this.caller(),n=await t.query(S.admission.listForAngebot,{client:this.requireTenant(t),offerKey:this.offer}),r=CT(n).filter(i=>!this.testOnly||i.test==="test");return this.print(r,i=>i,["id","status","state","applicant","test"]),0}},Yh=class extends D{static{s(this,"ApplicationsCountsCommand")}static paths=[["applications","counts"]];static usage=E.Usage({category:"Admission",description:"Count an offer's applications per list"});offer=p.String("--offer",ng);async execute(){let t=await this.caller(),n=await t.query(S.admission.getCountsByListForAngebot,{client:this.requireTenant(t),offerKey:this.offer});return this.print(n,r=>[...Object.entries(r.counts).map(([i,o])=>({list:i,count:String(o)})),{list:"total",count:String(r.total)}],["list","count"]),0}},Jh=class extends D{static{s(this,"ApplicationsShowCommand")}static paths=[["applications","show"]];static usage=E.Usage({category:"Admission",description:"One application: status, test flag, offer, current workflow nodes"});application=p.String({required:!0});async execute(){let t=await this.caller(),n=this.application,r=await t.query(S.admission.get,{applicationId:n});if(r===null)throw new Error(`applications show: no application ${n} (or not visible to you)`);let i=await t.query(S.workflow.getInstance,{applicationId:n});return this.print({application:r,currentNodes:i?.instance.currentNodeIds??[]},o=>[{key:"id",value:n},{key:"status",value:o.application.status},{key:"test",value:o.application.testMode?"ja":"nein"},{key:"offer",value:o.application.offerKey},{key:"current nodes",value:o.currentNodes.join(", ")}]),0}},Qh=class extends D{static{s(this,"ApplicationsStoreCommand")}static paths=[["applications","store"]];static usage=E.Usage({category:"Admission",description:"One application's process store: every address of its pinned graph, resolved (present / pending / absent)",details:"Staff only (applications.manage). --json prints one object keyed by the canonical address ($node\u2026, $task\u2026, $derived\u2026, $env\u2026). Values are shown whatever their audience \u2014 never hand the output to the family. Recipe: playbooks/applications/inspect-process-store.md."});application=p.String({required:!0});async execute(){let n=await(await this.caller()).query(S.processStoreView.get,{applicationId:this.application});return this.print(FT(n),()=>LT(n),["address","state","holds","producer","written"]),0}},Zh=class extends D{static{s(this,"ApplicationsStartTestCommand")}static paths=[["applications","start-test"]];static usage=E.Usage({category:"Admission",description:"Start a TEST application for an applicant (school year and level by key or id) and show what test mode offers next",details:"Always test mode. --applicant names the account by its login address (on prod only the tenant's test account); --party names the applicant party directly. Without --version it runs on the live generation, like the cockpit."});offer=p.String("--offer",ng);run=p.String("--run",{required:!0,description:"School year: its key or id (never its name)"});stage=p.String("--stage",{required:!0,description:"Level: its key or id (never its name)"});party=p.String("--party",{description:"Applicant party id"});applicant=p.String("--applicant",{description:"Applicant account login address (e.g. the test account test@example.com)"});version=p.String("--version",{description:"Offer version id to test (default: the live generation)"});staffInput=p.Array("--staff-input",{description:"A staff input the offer declares, as key=true|false \u2014 repeat it once per input; a staff start must set every one"});proxy=p.Boolean("--proxy",{description:"Start in Stellvertretung (--proxy) or not (--no-proxy); left out, the tenant's default applies, as in the cockpit"});async execute(){let t=await this.caller();DT(this.resolvedTarget(),this.prodUrls(),this.party,this.applicant);let n=this.requireTenant(t),r=NT(await t.query(S.admission.listAdmissionTree,{client:n}),this.offer,this.run,this.stage),i=this.party;if(this.applicant!==void 0){let d=await t.query(S.applicants.partyByEmail,{client:n,email:this.applicant});if(d===null)throw new Error(`applications start-test: no applicant account ${this.applicant} at this school (create it in the cockpit first)`);i=d}let o=await t.mutation(S.admission.staffStartApplicationForParty,{client:n,offerKey:this.offer,partyId:i,programRunId:r.programRunId,programStageId:r.programStageId,...this.proxy===void 0?{}:{startInProxy:this.proxy},staffInputs:r$(this.staffInput??[]),testMode:!0,...this.version===void 0?{}:{offerVersionId:this.version}}),a,l;try{let d=await t.query(S.workflow.getInstance,{applicationId:o.applicationId});if(d===null)throw new Error("the started application has no workflow instance");a=d.instance.currentNodeIds,l=(await yu(t,o.applicationId,a)).flatMap(c=>c.actions.map(u=>u.id))}catch(d){throw new Error(`applications start-test: started ${o.applicationId}, but reading its state failed: ${d instanceof Error?d.message:String(d)}`,{cause:d})}return this.print({applicationId:o.applicationId,currentNodes:a,testActions:l},d=>[{key:"application",value:d.applicationId},{key:"current nodes",value:d.currentNodes.join(", ")},{key:"test actions",value:d.testActions.join(", ")},{key:"next",value:`test-actions run --application ${d.applicationId} --action <id>`}]),0}},Xh=class extends D{static{s(this,"ApplicationsDiscardTestCommand")}static paths=[["applications","discard-test"]];static usage=E.Usage({category:"Admission",description:"Discard a TEST application (the server refuses a real one)"});application=p.String({required:!0});async execute(){return await(await this.caller()).mutation(S.admission.discardTest,{applicationId:this.application}),this.print({discarded:this.application},n=>[{key:"discarded",value:n.discarded}]),0}},eg=class extends D{static{s(this,"ApplicationsStaffInputListCommand")}static paths=[["applications","staff-input","list"]];static usage=E.Usage({category:"Admission",description:"An application's internal inputs (set at the start): value, and why one can no longer be corrected"});application=p.String({required:!0});async execute(){let n=await(await this.caller()).query(S.admission.staffInputsOfApplication,{applicationId:this.application});return this.print(n,r=>r.map(i=>({key:i.key,label:i.label.de,value:String(i.value),correctable:i.block===null?"ja":i.block.de})),["key","label","value","correctable"]),0}},tg=class extends D{static{s(this,"ApplicationsStaffInputSetCommand")}static paths=[["applications","staff-input","set"]];static usage=E.Usage({category:"Admission",description:"Correct one internal input of an application, with a reason \u2014 refused once a node that reads it was entered",examples:[["Untick \u201EKind von Mitarbeitenden\u201C",'plexus-cli --env prod --tenant <t> --allow-prod applications staff-input set <id> --input staffApplication=false --reason "falsch angehakt"']]});application=p.String({required:!0});input=p.String("--input",{required:!0,description:"key=true|false"});reason=p.String("--reason",{required:!0,description:"Why \u2014 recorded on the application's activity feed"});async execute(){let t=await this.caller(),[{key:n,value:r}]=r$([this.input]);return await t.mutation(S.admission.correctStaffInput,{applicationId:this.application,key:n,value:r,reason:this.reason}),this.print({application:this.application,key:n,value:r},i=>[{key:"application",value:i.application},{key:i.key,value:String(i.value)}]),0}},n$=[Hh,Yh,Jh,Qh,Zh,Xh,eg,tg];function r$(e){return e.map(t=>{let[n="",r,...i]=t.split("=");if(!La.test(n)||r!=="true"&&r!=="false"||i.length>0)throw new Error(`--staff-input "${t}": expected key=true or key=false`);return{key:n,value:r==="true"}})}s(r$,"parseStaffInputs");var ig="bundle.yaml",i$="manifest.json",og="smartforms",o$="workflow.json";function rg(e){return JSON.parse(ke(e,"utf8"))}s(rg,"readJson");function Pe(e){return JSON.stringify(sg(e),null,2)+`
9377
+ `};var mu="cb3c97259e64d88091913224a34bd4ff7df83cbc7a0ea8e88514b56a09dbf91d",jh=OT;var Bh=class extends Se{static{s(this,"AgentToolsCommand")}static paths=[["agent","tools"]];static usage=E.Usage({category:"Agents",description:"Show the shared platform/CLI agent tool schemas and skill revision."});async execute(){return this.print({skillHash:mu,tools:Da}),0}},Vh=class extends Se{static{s(this,"AgentInvokeCommand")}static paths=[["agent","invoke"]];static usage=E.Usage({category:"Agents",description:"Invoke a shared agent tool; pipe its JSON input on stdin."});tool=p.String("--tool",{required:!0,description:"plexus|plexus_skill|plexus_workspace"});async execute(){if("isTTY"in this.context.stdin&&this.context.stdin.isTTY===!0)throw new Error("plexus: pipe the tool's JSON input on stdin.");let t=JSON.parse(await Kh(this.context.stdin)),n=await this.context.executePlexusAgentTool(this.tool,t);return this.print(n),0}},PT=[Bh,Vh];var Uh=[{key:"fixture_test",email:"test@example.com",firstName:"Test",lastName:"Bewerber"}],Uee=new Set(Uh.map(e=>e.key));function NT(e,t,n,r){let i=e.flatMap(l=>l.angebote).find(l=>l.offerKey===t);if(i===void 0){let l=e.flatMap(d=>d.angebote.map(c=>c.offerKey));throw new Error(`applications start-test: no offer "${t}" (offers: ${l.join(", ")||"none"})`)}let o=i.stages.find(l=>l.stageKey===r||l.stageId===r);if(o===void 0){let l=i.stages.map(d=>`${d.stageKey} (${d.stageId})`);throw new Error(`applications start-test: no level "${r}" in ${t} \u2014 name it by key or id: ${l.join(", ")}`)}let a=o.runs.find(l=>l.runKey===n||l.runId===n);if(a===void 0){let l=o.runs.map(d=>`${d.runKey} (${d.runId})`);throw new Error(`applications start-test: no school year "${n}" for level ${o.stageKey} \u2014 name it by key or id: ${l.join(", ")}`)}if(!a.isOpen)throw new Error(`applications start-test: school year ${a.runKey} is closed for level ${o.stageKey}`);return{programRunId:a.runId,programStageId:o.stageId}}s(NT,"resolveStartTarget");function Rj(e){return e.kind==="named"?e.name:`(${e.standIn??e.fallback})`}s(Rj,"applicantText");function CT(e){return e.map(t=>({id:t.application._id,status:t.deletedAt?`${t.application.status} (gel\xF6scht)`:t.application.status,state:t.currentProcessStateId??"",applicant:Rj(t.applicantName),test:t.application.testMode===!0?"test":""}))}s(CT,"applicationRows");var _T=Uh.map(e=>e.email);function DT(e,t,n,r){if(n===void 0&&r===void 0)throw new Error("applications start-test: name the applicant \u2014 --party <partyId> or --applicant <email>");if(n!==void 0&&r!==void 0)throw new Error("applications start-test: --party or --applicant, not both");if(Fh(e,t)&&(r===void 0||!_T.includes(r.trim().toLowerCase())))throw new Error(`applications start-test: on prod only for the test account ${_T.join(", ")} (--applicant) \u2014 never a real family's`)}s(DT,"assertStartApplicant");function FT(e){let t={};for(let{address:n,...r}of e.entries)t[n]=r;return{applicationId:e.applicationId,store:t}}s(FT,"processStoreJson");function Ij(e){switch(e.kind){case"form":return`form ${e.formInstanceId} (${e.state})`;case"document":return e.file===null?`document ${e.slotKey} (leer)`:`document ${e.slotKey} \xB7 v${e.file.versionNumber} ${e.file.filename??e.file.artifactId}`;case"contract":return`contract ${e.contractId} \xB7 ${e.revision===null?"keine Fassung":`Fassung ${e.revision.revisionNumber}`} \xB7 ${e.contractStatus}`;case"contracts":return e.contracts.map(t=>`${t.partKey}: contract ${t.contractId} \xB7 ${t.revision===null?"keine Fassung":`Fassung ${t.revision.revisionNumber}`} \xB7 ${t.contractStatus}`).join("; ")}}s(Ij,"refText");function Oj(e){return e.state!=="present"?e.reason?.de??"":e.ref!==void 0?Ij(e.ref):JSON.stringify(e.value)}s(Oj,"holds");function LT(e){return e.entries.map(t=>({address:t.address,state:t.state,holds:Oj(t),producer:t.producer?.label??"",written:t.writtenAt===void 0?"":new Date(t.writtenAt).toISOString()}))}s(LT,"storeRows");function hu(e){let t={},n={};for(let r of e){let i=r.indexOf("=");if(i<=0)throw new Error(`Expected key=value, got '${r}'.`);let o=r.slice(0,i);if(Object.hasOwn(n,o))throw new Error(`'${o}' is given twice.`);let a=r.slice(i+1);n[o]=a;try{t[o]=JSON.parse(a)}catch{t[o]=a}}return{values:t,raw:n}}s(hu,"parseKv");var MT="started",gu="submitted",qT="submitted",KT="load-scenario:";var jT="(Bewerbung)";function BT(e){return{nodeId:jT,actions:e.map(t=>({id:t.id,label:{de:`${t.label??t.id}${t.count===void 0?"":` (${t.count})`}`,en:`${t.label??t.id}${t.count===void 0?"":` (${t.count})`}`},...t.disabledReason===void 0?{}:{disabledReason:t.disabledReason}}))}}s(BT,"sharedAsList");function VT(e){return e.disabledReason===void 0?"":e.disabledCount===void 0?e.disabledReason:`${e.disabledReason} (${e.disabledCount})`}s(VT,"disabledText");function UT(e){return e.flatMap(({nodeId:t,actions:n})=>n.map(r=>({node:t,action:r.id,label:r.label.de,disabled:VT(r)})))}s(UT,"actionRows");function GT(e,t,n=[]){let r=e.filter(({actions:d})=>d.some(c=>c.id===t));if(r.length===0){let d=[...new Set(e.flatMap(({actions:c})=>c.map(u=>u.id)))];throw new Error(`test-actions run: no current node offers "${t}" (offered: ${d.join(", ")||"nothing"})`)}if(r.length>1)throw new Error(`test-actions run: "${t}" is offered by ${r.map(d=>d.nodeId).join(", ")} \u2014 pass --node`);let{nodeId:i,actions:o}=r[0],a=o.find(d=>d.id===t);if(a.disabledReason!==void 0)throw new Error(`test-actions run: "${t}" on ${i} is disabled: ${VT(a)}`);if(i!==jT)return i;let l=n[0];if(l===void 0)throw new Error(`test-actions run: "${t}" needs a current node \u2014 the application has none`);return l}s(GT,"nodeOfferingAction");function zT(e,t,n){if(e.startsWith(KT)){if(Object.hasOwn(n,"autoSubmit"))throw new Error(`test-actions run: ${e}: a scenario's autoSubmit is set by --auto-submit / --no-auto-submit, not --param`);return{autoSubmit:t,...n}}return Object.keys(n).length===0?void 0:{...n}}s(zT,"runParams");async function Pj(e,t){let n=await e.query(S.workflow.getInstance,{applicationId:t});if(n===null)throw new Error(`test-actions: application ${t} has no workflow instance`);return n.instance.currentNodeIds}s(Pj,"currentNodeIds");function _j(e,t){switch(t){case"notTestApplication":return`${e} is not a test application`;case"completed":case"aborted":case"deleted":return`${e} is ${t} \u2014 test actions run only on an active application`;case"missingPermission":return"the caller lacks bewerbungsmanagement.testActions.run"}}s(_j,"refusalText");async function yu(e,t,n){let r=await e.query(S.workflow.listSharedTestActions,{applicationId:t});if(!r.permitted)throw new Error(`test-actions: not permitted \u2014 ${_j(t,r.reason)}`);let i=[];for(let o of n){let a=await e.query(S.workflow.listTestActions,{applicationId:t,nodeId:o});if(a===null)throw new Error(`test-actions: node "${o}" is not in this application's workflow (or it has no instance)`);i.push({nodeId:o,actions:a})}return[...i,BT(r.actions)]}s(yu,"actionsOf");async function WT(e,t,n){return n!==void 0?[n]:await Pj(e,t)}s(WT,"nodesOf");var Gh=class extends D{static{s(this,"TestActionsListCommand")}static paths=[["test-actions","list"]];static usage=E.Usage({category:"Admission",description:"List the test-mode actions of the application's current node(s) (scenarios, auto-fill-files, submit, \u2026) and the application-wide ones"});application=p.String("--application",{required:!0,description:"Application id (a test application)"});node=p.String("--node",{description:"Node id (default: the application's current nodes)"});async execute(){let t=await this.caller(),n=await yu(t,this.application,await WT(t,this.application,this.node));return this.print(n,UT,["node","action","label","disabled"]),0}},zh=class extends D{static{s(this,"TestActionsRunCommand")}application=p.String("--application",{required:!0,description:"Application id (a test application)"});node=p.String("--node",{description:"Node id (default: the application's current nodes)"});static paths=[["test-actions","run"]];static usage=E.Usage({category:"Admission",description:"Run one test-mode action; a scenario (load-scenario:<id>) also submits unless --no-auto-submit"});action=p.String("--action",{required:!0,description:"Action id, e.g. load-scenario:standard, auto-fill-files, submit-form"});autoSubmit=p.Boolean("--auto-submit",!0,{description:"Scenario only: stub the file fields and submit after loading (default on; --no-auto-submit only loads)"});param=p.Array("--param",{description:"Action parameter key=value (repeatable; the value is JSON where it parses, else text), e.g. --param confirmed=true for an action that asks a question first (upload-signed-document)"});async execute(){let t=zT(this.action,this.autoSubmit,hu(this.param??[]).values),n=await this.caller(),r=this.application,i=await WT(n,this.application,this.node),o=GT(await yu(n,r,i),this.action,i);return await n.mutation(S.workflow.runTestAction,{applicationId:r,nodeId:o,actionId:this.action,...t===void 0?{}:{params:t}}),this.print({ran:this.action,on:o},a=>[{key:"ran",value:a.ran},{key:"on",value:a.on},{key:"next",value:"test-actions list \u2014 file fills and the submit after them run asynchronously"}]),0}},HT=[Gh,zh];var Je=["de","en"];function Xo(e,t){return Je.every(n=>e[n]===t[n])}s(Xo,"sameText");function yt(e){if(e===null||typeof e!="object"||Array.isArray(e))return"not-localized";let t=e;return Object.keys(t).some(r=>!Je.includes(r))?"not-localized":Je.filter(r=>{let i=t[r];return typeof i!="string"||i.trim()===""})}s(yt,"missingLocales");function mi(e){let t=yt(e);return t!=="not-localized"&&t.length===0}s(mi,"isLocalizedText");function Fa(e,t){let n={};for(let r of Je){let i=e.map(o=>o[r]);n[r]=i.every(o=>typeof o=="string"&&o.trim()!=="")?t(i,r):""}return n}s(Fa,"composeTexts");var er=/^[a-z][A-Za-z0-9]*$/;function Wh(e){return typeof e=="string"&&er.test(e)}s(Wh,"isNodeId");function es(e,t){Wh(e)||_(`[graph/nodeIdFormat] "${e}" cannot name a node: a node id is ${er.source}.`);let n=new Set(t);if(!n.has(e))return e;let r=2;for(;n.has(`${e}${r}`);)r++;return`${e}${r}`}s(es,"makeNodeId");var hi="$env";function se(e){if(e.scope==="env")return`${hi}.${e.key}`;let t=e.scope==="derived"?`$derived.${e.key}`:`$${e.scope}.${e.owner}.${e.key}`;return e.path===void 0?t:`${t}.${e.path}`}s(se,"formatAddress");var wr=/^[a-z][a-zA-Z0-9_]*$/,Nj=/^[A-Za-z_][A-Za-z0-9_]*$/;function to(e){return typeof e=="string"&&e.split(".").every(t=>Nj.test(t))}s(to,"isPath");function qr(e){if(!e.startsWith("$"))return null;let t=e.slice(1).split("."),[n,...r]=t;switch(n){case"env":{let i=r.join(".");return r.length>0&&to(i)?{scope:"env",key:i}:null}case"derived":{let[i,...o]=r;return i===void 0||!wr.test(i)?null:YT({scope:"derived",key:i},o)}case"node":case"task":{let[i,o,...a]=r;return i===void 0||o===void 0||!wr.test(o)||(n==="node"?!er.test(i):!wr.test(i))?null:YT({scope:n,owner:i,key:o},a)}default:return null}}s(qr,"tryParseAddress");function YT(e,t){if(t.length===0)return e;let n=t.join(".");return to(n)?{...e,path:n}:null}s(YT,"withPath");function ve(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;let t=e,n=t.scope==="env"?["scope","key"]:t.scope==="derived"?["scope","key","path"]:["scope","owner","key","path"];if(Object.keys(t).some(r=>!n.includes(r))||t.path!==void 0&&!to(t.path))return!1;switch(t.scope){case"env":return to(t.key);case"derived":return typeof t.key=="string"&&wr.test(t.key);case"node":return typeof t.owner=="string"&&er.test(t.owner)&&typeof t.key=="string"&&wr.test(t.key);case"task":return typeof t.owner=="string"&&wr.test(t.owner)&&typeof t.key=="string"&&wr.test(t.key);default:return!1}}s(ve,"isAddress");var Kr={offer:{key:"string",title:"string"},unit:{key:"string",name:"string"},stage:{key:"string",name:"string",gradeLevel:"number"},run:{key:"string",name:"string",startDate:"date"},applicant:{language:"enum",channel:"enum"}},ts=Object.keys(Kr);function ns(e){return Object.hasOwn(Kr,e)}s(ns,"isEnvKey");var Cj=["self-service","staff"];function JT(e,t){return{kind:"fixed",values:e,labels:t}}s(JT,"fixedSet");var wu={of:"applicant.language",withoutValue:"de"},jr={"offer.key":{valueSet:{kind:"live"},nullable:!1,label:{de:"Angebot",en:"Offer"}},"offer.title":{valueSet:{kind:"unstable"},nullable:!1,label:{de:"Titel des Angebots",en:"Offer title"},nameLanguage:wu},"unit.key":{valueSet:{kind:"live"},nullable:!1,label:{de:"Einheit",en:"Unit"}},"unit.name":{valueSet:{kind:"unstable"},nullable:!1,label:{de:"Name der Einheit",en:"Unit name"},nameLanguage:wu},"stage.key":{valueSet:{kind:"unstable"},nullable:!1,label:{de:"Klassenstufe (Schl\xFCssel)",en:"Grade (key)"},cohortBound:!0},"stage.name":{valueSet:{kind:"unstable"},nullable:!1,label:{de:"Name der Klassenstufe",en:"Grade name"},cohortBound:!0,nameLanguage:wu},"stage.gradeLevel":{valueSet:{kind:"open"},nullable:!0,absent:{de:"Die Stufe hat keine Klassenstufe (Kindergarten).",en:"The stage has no grade level (Kindergarten)."},label:{de:"Klassenstufe",en:"Grade level"},cohortBound:!0},"run.key":{valueSet:{kind:"unstable"},nullable:!1,label:{de:"Schuljahr",en:"School year"},cohortBound:!0},"run.name":{valueSet:{kind:"unstable"},nullable:!1,label:{de:"Name des Schuljahrs",en:"School year name"},cohortBound:!0,nameLanguage:wu},"run.startDate":{valueSet:{kind:"open"},nullable:!0,absent:{de:"F\xFCr das Schuljahr ist kein Beginn erfasst.",en:"The school year has no start date."},label:{de:"Beginn des Schuljahrs",en:"School year start"},cohortBound:!0},"applicant.language":{valueSet:JT(Je,{de:{de:"Deutsch",en:"German"},en:{de:"Englisch",en:"English"}}),nullable:!0,absent:{de:"Die Bewerbung hat kein Bewerberkonto (intern angelegt).",en:"The application has no applicant account (started by staff)."},label:{de:"Bewerbersprache",en:"Applicant language"}},"applicant.channel":{valueSet:JT(Cj,{staff:{de:"intern",en:"in-house"},"self-service":{de:"online (Familie)",en:"online (family)"}}),nullable:!1,label:{de:"Eingangsweg",en:"Intake channel"}}},bu={types:Kr,fields:jr},ku=ts.flatMap(e=>Object.keys(Kr[e]).map(t=>`${e}.${t}`));function tr(e){return Object.hasOwn(jr,e)}s(tr,"isEnvLeaf");function vu(e){return`${hi}.${e}`}s(vu,"envIdentifier");function no(e){let t=jr[e],[n,r]=e.split("."),i=Kr[n][r];i===void 0&&_(`[env] leaf "${e}" has no type`);let o=t.valueSet;return{leaf:e,type:i,label:t.label,nullable:t.nullable,...t.absent===void 0?{}:{absent:t.absent},...t.nameLanguage===void 0?{}:{nameLanguage:t.nameLanguage},...t.cohortBound===void 0?{}:{cohortBound:t.cohortBound},...o.kind==="fixed"?{enumOptions:o.values.map(a=>{let l=o.labels[a];return l===void 0&&_(`[env] "${e}" names the value "${a}" without a label`),{value:a,label:l}})}:{}}}s(no,"envLeaf");var QT="staffInput";var Dj=["boolean"],La=/^[a-z][A-Za-z0-9]*$/;function xu(e){return e.staffInputs??[]}s(xu,"staffInputsOf");function Su(e){return`${QT}.${e}`}s(Su,"staffInputLeaf");function ZT(e){return`${hi}.${Su(e)}`}s(ZT,"staffInputIdentifier");function Fj(e){let t=`${QT}.`;return e.startsWith(t)?e.slice(t.length):null}s(Fj,"staffInputKeyOfLeaf");function Ma(e,t){let n=Fj(t);return n===null?void 0:xu(e).find(r=>r.key===n)}s(Ma,"declaredStaffInput");function Lj(e){return[...xu(e).map(t=>({leaf:Su(t.key),type:t.type,label:t.label,valueSet:{kind:"open"},nullable:!1,cohortBound:!1})),...ku.map(t=>{let n=no(t);return{leaf:t,type:n.type,label:n.label,valueSet:jr[t].valueSet,nullable:n.nullable,cohortBound:n.cohortBound===!0}})]}s(Lj,"envLeavesFor");function XT(e){return Lj(e).filter(t=>!t.cohortBound)}s(XT,"conditionEnvLeaves");function e$(e){let t={},n={};for(let{leaf:r,type:i,valueSet:o,nullable:a}of XT(e)){let[l="",d=""]=r.split(".");t[l]={...t[l]??{},[d]:i},n[r]={valueSet:o,nullable:a}}return{types:t,fields:n}}s(e$,"envConditionSchemaFor");function t$(e){let t=e.staffInputs;if(t===void 0)return[];if(!Array.isArray(t))return[{path:"staffInputs",reason:{de:"[staffInput/shape] graph.staffInputs muss eine Liste sein.",en:"[staffInput/shape] graph.staffInputs must be a list."}}];let n=[],r=new Set;return t.forEach((i,o)=>{let a=`staffInputs[${o}]`,l=i;if(l===null||typeof l!="object"||typeof l.key!="string"){n.push({path:a,reason:{de:"[staffInput/shape] Eine interne Angabe braucht key, type und label ({ de, en }).",en:"[staffInput/shape] An internal entry needs key, type and label ({ de, en })."}});return}let d={de:`Interne Angabe "${l.key}"`,en:`Internal entry "${l.key}"`};La.test(l.key)||n.push({path:`${a}.key`,reason:{de:`[staffInput/keyFormat] ${d.de}: Schl\xFCssel beginnt mit einem Kleinbuchstaben und enth\xE4lt nur Buchstaben und Ziffern.`,en:`[staffInput/keyFormat] ${d.en}: the key starts with a lowercase letter and contains only letters and digits.`}}),r.has(l.key)&&n.push({path:`${a}.key`,reason:{de:`[staffInput/duplicateKey] ${d.de}: Schl\xFCssel ist doppelt vergeben.`,en:`[staffInput/duplicateKey] ${d.en}: the key is used twice.`}}),r.add(l.key),Dj.includes(l.type)||n.push({path:`${a}.type`,reason:{de:`[staffInput/unknownType] ${d.de}: Typ "${String(l.type)}" \u2014 erlaubt ist nur "boolean" (K\xE4stchen).`,en:`[staffInput/unknownType] ${d.en}: type "${String(l.type)}" \u2014 only "boolean" (checkbox) is allowed.`}});let c=yt(l.label);c==="not-localized"?n.push({path:`${a}.label`,reason:{de:`[staffInput/shape] ${d.de}: label muss { de, en } sein.`,en:`[staffInput/shape] ${d.en}: label must be { de, en }.`}}):c.length>0&&n.push({path:`${a}.label`,reason:{de:`[i18n/missingTranslation] ${d.de}: Beschriftung fehlt in ${c.join(", ")}.`,en:`[i18n/missingTranslation] ${d.en}: label is missing in ${c.join(", ")}.`}})}),n}s(t$,"staffInputIssues");var ng={required:!0,description:"Offer slug (its offerKey)"},Hh=class extends D{static{s(this,"ApplicationsListCommand")}static paths=[["applications","list"]];static usage=E.Usage({category:"Admission",description:"List an offer's applications (id, status, board state, applicant, test)"});offer=p.String("--offer",ng);testOnly=p.Boolean("--test-only",!1,{description:"Only test applications"});async execute(){let t=await this.caller(),n=await t.query(S.admission.listForAngebot,{client:this.requireTenant(t),offerKey:this.offer}),r=CT(n).filter(i=>!this.testOnly||i.test==="test");return this.print(r,i=>i,["id","status","state","applicant","test"]),0}},Yh=class extends D{static{s(this,"ApplicationsCountsCommand")}static paths=[["applications","counts"]];static usage=E.Usage({category:"Admission",description:"Count an offer's applications per list"});offer=p.String("--offer",ng);async execute(){let t=await this.caller(),n=await t.query(S.admission.getCountsByListForAngebot,{client:this.requireTenant(t),offerKey:this.offer});return this.print(n,r=>[...Object.entries(r.counts).map(([i,o])=>({list:i,count:String(o)})),{list:"total",count:String(r.total)}],["list","count"]),0}},Jh=class extends D{static{s(this,"ApplicationsShowCommand")}static paths=[["applications","show"]];static usage=E.Usage({category:"Admission",description:"One application: status, test flag, offer, current workflow nodes"});application=p.String({required:!0});async execute(){let t=await this.caller(),n=this.application,r=await t.query(S.admission.get,{applicationId:n});if(r===null)throw new Error(`applications show: no application ${n} (or not visible to you)`);let i=await t.query(S.workflow.getInstance,{applicationId:n});return this.print({application:r,currentNodes:i?.instance.currentNodeIds??[]},o=>[{key:"id",value:n},{key:"status",value:o.application.status},{key:"test",value:o.application.testMode?"ja":"nein"},{key:"offer",value:o.application.offerKey},{key:"current nodes",value:o.currentNodes.join(", ")}]),0}},Qh=class extends D{static{s(this,"ApplicationsStoreCommand")}static paths=[["applications","store"]];static usage=E.Usage({category:"Admission",description:"One application's process store: every address of its pinned graph, resolved (present / pending / absent)",details:"Staff only (applications.manage). --json prints one object keyed by the canonical address ($node\u2026, $task\u2026, $derived\u2026, $env\u2026). Values are shown whatever their audience \u2014 never hand the output to the family. Recipe: playbooks/applications/inspect-process-store.md."});application=p.String({required:!0});async execute(){let n=await(await this.caller()).query(S.processStoreView.get,{applicationId:this.application});return this.print(FT(n),()=>LT(n),["address","state","holds","producer","written"]),0}},Zh=class extends D{static{s(this,"ApplicationsStartTestCommand")}static paths=[["applications","start-test"]];static usage=E.Usage({category:"Admission",description:"Start a TEST application for an applicant (school year and level by key or id) and show what test mode offers next",details:"Always test mode. --applicant names the account by its login address (on prod only the tenant's test account); --party names the applicant party directly. Without --version it runs on the live generation, like the cockpit."});offer=p.String("--offer",ng);run=p.String("--run",{required:!0,description:"School year: its key or id (never its name)"});stage=p.String("--stage",{required:!0,description:"Level: its key or id (never its name)"});party=p.String("--party",{description:"Applicant party id"});applicant=p.String("--applicant",{description:"Applicant account login address (e.g. the test account test@example.com)"});version=p.String("--version",{description:"Offer version id to test (default: the live generation)"});staffInput=p.Array("--staff-input",{description:"A staff input the offer declares, as key=true|false \u2014 repeat it once per input; a staff start must set every one"});proxy=p.Boolean("--proxy",{description:"Start in Stellvertretung (--proxy) or not (--no-proxy); left out, the tenant's default applies, as in the cockpit"});async execute(){let t=await this.caller();DT(this.resolvedTarget(),this.prodUrls(),this.party,this.applicant);let n=this.requireTenant(t),r=NT(await t.query(S.admission.listAdmissionTree,{client:n}),this.offer,this.run,this.stage),i=this.party;if(this.applicant!==void 0){let d=await t.query(S.applicants.partyByEmail,{client:n,email:this.applicant});if(d===null)throw new Error(`applications start-test: no applicant account ${this.applicant} at this school (create it in the cockpit first)`);i=d}let o=await t.mutation(S.admission.staffStartApplicationForParty,{client:n,offerKey:this.offer,partyId:i,programRunId:r.programRunId,programStageId:r.programStageId,...this.proxy===void 0?{}:{startInProxy:this.proxy},staffInputs:r$(this.staffInput??[]),testMode:!0,...this.version===void 0?{}:{offerVersionId:this.version}}),a,l;try{let d=await t.query(S.workflow.getInstance,{applicationId:o.applicationId});if(d===null)throw new Error("the started application has no workflow instance");a=d.instance.currentNodeIds,l=(await yu(t,o.applicationId,a)).flatMap(c=>c.actions.map(u=>u.id))}catch(d){throw new Error(`applications start-test: started ${o.applicationId}, but reading its state failed: ${d instanceof Error?d.message:String(d)}`,{cause:d})}return this.print({applicationId:o.applicationId,currentNodes:a,testActions:l},d=>[{key:"application",value:d.applicationId},{key:"current nodes",value:d.currentNodes.join(", ")},{key:"test actions",value:d.testActions.join(", ")},{key:"next",value:`test-actions run --application ${d.applicationId} --action <id>`}]),0}},Xh=class extends D{static{s(this,"ApplicationsDiscardTestCommand")}static paths=[["applications","discard-test"]];static usage=E.Usage({category:"Admission",description:"Discard a TEST application (the server refuses a real one)"});application=p.String({required:!0});async execute(){return await(await this.caller()).mutation(S.admission.discardTest,{applicationId:this.application}),this.print({discarded:this.application},n=>[{key:"discarded",value:n.discarded}]),0}},eg=class extends D{static{s(this,"ApplicationsStaffInputListCommand")}static paths=[["applications","staff-input","list"]];static usage=E.Usage({category:"Admission",description:"An application's internal inputs (set at the start): value, and why one can no longer be corrected"});application=p.String({required:!0});async execute(){let n=await(await this.caller()).query(S.admission.staffInputsOfApplication,{applicationId:this.application});return this.print(n,r=>r.map(i=>({key:i.key,label:i.label.de,value:String(i.value),correctable:i.block===null?"ja":i.block.de})),["key","label","value","correctable"]),0}},tg=class extends D{static{s(this,"ApplicationsStaffInputSetCommand")}static paths=[["applications","staff-input","set"]];static usage=E.Usage({category:"Admission",description:"Correct one internal input of an application, with a reason \u2014 refused once a node that reads it was entered",examples:[["Untick \u201EKind von Mitarbeitenden\u201C",'plexus-cli --env prod --tenant <t> --allow-prod applications staff-input set <id> --input staffApplication=false --reason "falsch angehakt"']]});application=p.String({required:!0});input=p.String("--input",{required:!0,description:"key=true|false"});reason=p.String("--reason",{required:!0,description:"Why \u2014 recorded on the application's activity feed"});async execute(){let t=await this.caller(),[{key:n,value:r}]=r$([this.input]);return await t.mutation(S.admission.correctStaffInput,{applicationId:this.application,key:n,value:r,reason:this.reason}),this.print({application:this.application,key:n,value:r},i=>[{key:"application",value:i.application},{key:i.key,value:String(i.value)}]),0}},n$=[Hh,Yh,Jh,Qh,Zh,Xh,eg,tg];function r$(e){return e.map(t=>{let[n="",r,...i]=t.split("=");if(!La.test(n)||r!=="true"&&r!=="false"||i.length>0)throw new Error(`--staff-input "${t}": expected key=true or key=false`);return{key:n,value:r==="true"}})}s(r$,"parseStaffInputs");var ig="bundle.yaml",i$="manifest.json",og="smartforms",o$="workflow.json";function rg(e){return JSON.parse(ke(e,"utf8"))}s(rg,"readJson");function Pe(e){return JSON.stringify(sg(e),null,2)+`
9378
9378
  `}s(Pe,"canonicalJson");function sg(e){return Array.isArray(e)?e.map(sg):e&&typeof e=="object"?Object.fromEntries(Object.keys(e).sort().map(t=>[t,sg(e[t])])):e}s(sg,"sortKeys");function Ie(e){let t=H.resolve(e),n=H.join(t,ig);if(!Oe(n))throw new Error(`offer: no ${ig} in ${t}`);let r=Zi.load(ke(n,"utf8"));Mj(r,n);let i=H.join(t,o$),o,a=Object.keys(r.smartforms??{});if(a.length>0){o={};for(let l of a){let d=H.join(t,og,`${l}.json`);if(!Oe(d))throw new Error(`offer: bundle.yaml declares smartform "${l}" but ${og}/${l}.json is missing`);o[l]=rg(d)}}return{dir:t,index:r,manifest:rg(H.join(t,i$)),...o?{smartforms:o}:{},...Oe(i)?{workflow:rg(i)}:{}}}s(Ie,"readBundle");function Au(e,t,n,r){Oe(e)&&Pe(r(ke(e,"utf8")))===Pe(t)||ht(e,n,"utf8")}s(Au,"writeIfChanged");function Bn(e){if(Wt(e.dir,{recursive:!0}),Au(H.join(e.dir,ig),e.index,Zi.dump(e.index,{lineWidth:100,sortKeys:!1}),t=>Zi.load(t)),Au(H.join(e.dir,i$),e.manifest,Pe(e.manifest),JSON.parse),e.smartforms!==void 0){let t=H.join(e.dir,og);Wt(t,{recursive:!0});for(let[n,r]of Object.entries(e.smartforms))Au(H.join(t,`${n}.json`),r,Pe(r),JSON.parse)}e.workflow!==void 0&&Au(H.join(e.dir,o$),e.workflow,Pe(e.workflow),JSON.parse)}s(Bn,"writeBundle");function Mj(e,t){let n=[];if(e?.module||n.push("module"),e?.tenant||n.push("tenant"),e?.label||n.push("label"),e?.slugs?.manifest||n.push("slugs.manifest"),n.length>0)throw new Error(`offer: ${t} is missing required keys: ${n.join(", ")}`)}s(Mj,"assertIndex");var qj=new Set(["if","else","in","true","false","null"]),Kj=new Set(["==","!=","<=",">=","&&","||"]);function jj(e){return e>="0"&&e<="9"}s(jj,"isDigit");function Bj(e){return/[a-zA-Z_$]/.test(e)}s(Bj,"isIdentStart");function Vj(e){return/[a-zA-Z0-9_.$]/.test(e)}s(Vj,"isIdentCont");function Uj(e){let t=[],n=0;for(;n<e.length;){let r=e.charAt(n);if(r===" "||r===" "||r===`
9379
9379
  `||r==="\r"){n++;continue}if(r==="'"){let o=n+1,a="";for(;o<e.length&&e.charAt(o)!=="'";)e.charAt(o)==="\\"&&o+1<e.length?(a+=e.charAt(o+1),o+=2):(a+=e.charAt(o),o++);o>=e.length&&_(`Unterminated string at ${n}`),t.push({t:"str",v:a}),n=o+1;continue}if(jj(r)){let o=n;for(;o<e.length&&/[0-9.]/.test(e.charAt(o));)o++;t.push({t:"num",v:Number(e.slice(n,o))}),n=o;continue}if(Bj(r)){let o=n;for(;o<e.length&&Vj(e.charAt(o));)o++;let a=e.slice(n,o);qj.has(a)?t.push({t:"kw",v:a}):t.push({t:"ident",v:a}),n=o;continue}let i=e.slice(n,n+2);if(Kj.has(i)){t.push({t:"op",v:i}),n+=2;continue}if("<>!".includes(r)){t.push({t:"op",v:r}),n++;continue}if("()[],".includes(r)){t.push({t:"punct",v:r}),n++;continue}_(`Unexpected char '${r}' at ${n}`)}return t}s(Uj,"tokenise");var s$=1e4,a$=128;function rs(e){e.depth++,e.depth>a$&&_(`Expression nesting too deep (> ${a$})`)}s(rs,"enterDepth");function p$(e){return e.pos<e.tokens.length?e.tokens[e.pos]:null}s(p$,"peek");function Dt(e){let t=e.tokens[e.pos];return t||_(`Unexpected end at ${e.pos}`),e.pos++,t}s(Dt,"take");function Ft(e,t,n){let r=p$(e);return!(!r||r.t!==t||n!==void 0&&r.v!==n)}s(Ft,"match");function ro(e,t,n){return Ft(e,t,n)||_(`Expected ${t}${n?`:${n}`:""} at ${e.pos}`),Dt(e)}s(ro,"expect");function Vr(e){rs(e);try{return Ft(e,"kw","if")?Gj(e):zj(e)}finally{e.depth--}}s(Vr,"parseExpr");function Gj(e){ro(e,"kw","if"),ro(e,"punct","(");let t=Vr(e);ro(e,"punct",")");let n=Vr(e);ro(e,"kw","else");let r=Vr(e);return{kind:"if",cond:t,then:n,else:r}}s(Gj,"parseIf");function zj(e){let t=l$(e),n=0;try{for(;Ft(e,"op","||");){Dt(e),rs(e),n++;let r=l$(e);t={kind:"binary",op:"||",left:t,right:r}}}finally{e.depth-=n}return t}s(zj,"parseLogicOr");function l$(e){let t=d$(e),n=0;try{for(;Ft(e,"op","&&");){Dt(e),rs(e),n++;let r=d$(e);t={kind:"binary",op:"&&",left:t,right:r}}}finally{e.depth-=n}return t}s(l$,"parseLogicAnd");function d$(e){let t=c$(e),n=0;try{for(;Ft(e,"op","==")||Ft(e,"op","!=");){let r=Dt(e).v;rs(e),n++;let i=c$(e);t={kind:"binary",op:r,left:t,right:i}}}finally{e.depth-=n}return t}s(d$,"parseEquality");function c$(e){let t=lg(e),n=0;try{for(;Ft(e,"op","<")||Ft(e,"op","<=")||Ft(e,"op",">")||Ft(e,"op",">=")||Ft(e,"kw","in");){let r=Dt(e),i=r.t==="kw"?"in":r.v;rs(e),n++;let o=lg(e);t={kind:"binary",op:i,left:t,right:o}}}finally{e.depth-=n}return t}s(c$,"parseCompare");function lg(e){if(Ft(e,"op","!")){Dt(e),rs(e);try{return{kind:"unary",op:"!",operand:lg(e)}}finally{e.depth--}}return Wj(e)}s(lg,"parseUnary");function Wj(e){let t=p$(e);if(t||_("Unexpected end"),t.t==="num")return Dt(e),{kind:"num",value:t.v};if(t.t==="str")return Dt(e),{kind:"str",value:t.v};if(t.t==="kw"&&t.v==="true")return Dt(e),{kind:"bool",value:!0};if(t.t==="kw"&&t.v==="false")return Dt(e),{kind:"bool",value:!1};if(t.t==="kw"&&t.v==="null")return Dt(e),{kind:"null"};if(t.t==="punct"&&t.v==="("){Dt(e);let n=Vr(e);return ro(e,"punct",")"),n}if(t.t==="punct"&&t.v==="["){Dt(e);let n=[];if(!Ft(e,"punct","]"))for(n.push(Vr(e));Ft(e,"punct",",");)Dt(e),n.push(Vr(e));return ro(e,"punct","]"),{kind:"arr",items:n}}if(t.t==="ident"){let n=t.v;if(Dt(e),Ft(e,"punct","(")){Dt(e);let r=[];if(!Ft(e,"punct",")"))for(r.push(Vr(e));Ft(e,"punct",",");)Dt(e),r.push(Vr(e));return ro(e,"punct",")"),{kind:"call",name:n,args:r}}return{kind:"ident",path:n}}_(`Unexpected token at ${e.pos}`)}s(Wj,"parsePrimary");function Lt(e){e.length>s$&&_(`Expression too long (${e.length} > ${s$})`);let t={tokens:Uj(e),pos:0,depth:0},n=Vr(t);return t.pos<t.tokens.length&&_(`Unexpected trailing token at ${t.pos}`),n}s(Lt,"parseExpression");var Hj=new Map([["today",()=>new Date().toISOString().slice(0,10)],["years_between",(e,t)=>{if(typeof e!="string"||typeof t!="string")return null;let n=new Date(e),r=new Date(t);if(isNaN(n.getTime())||isNaN(r.getTime()))return null;let i=r.getFullYear()-n.getFullYear(),o=r.getMonth()-n.getMonth();return(o<0||o===0&&r.getDate()<n.getDate())&&i--,i}],["length",e=>typeof e=="string"||Array.isArray(e)?e.length:0]]);function mt(e,t){switch(e.kind){case"num":return e.value;case"str":return e.value;case"bool":return e.value;case"null":return null;case"ident":{let n=Object.hasOwn(t.values,e.path)?t.values[e.path]:void 0;return n===void 0?null:n}case"arr":return e.items.map(n=>mt(n,t));case"unary":{let n=mt(e.operand,t);return!gi(n)}case"call":{let n=t.functions!==void 0&&Object.hasOwn(t.functions,e.name)?t.functions[e.name]:Hj.get(e.name);n||_(`Unknown function '${e.name}'`);let r=e.args.map(i=>mt(i,t));return n(...r)}case"binary":return Yj(e.op,e.left,e.right,t);case"if":return gi(mt(e.cond,t))?mt(e.then,t):mt(e.else,t)}}s(mt,"evaluate");function Yj(e,t,n,r){if(e==="&&"){let a=mt(t,r);return gi(a)?gi(mt(n,r)):!1}if(e==="||"){let a=mt(t,r);return gi(a)?!0:gi(mt(n,r))}let i=mt(t,r),o=mt(n,r);switch(e){case"==":return ag(i,o);case"!=":return!ag(i,o);case"<":{let[a,l]=Eu(i,o);return a!==null&&l!==null&&a<l}case"<=":{let[a,l]=Eu(i,o);return a!==null&&l!==null&&a<=l}case">":{let[a,l]=Eu(i,o);return a!==null&&l!==null&&a>l}case">=":{let[a,l]=Eu(i,o);return a!==null&&l!==null&&a>=l}case"in":return Array.isArray(o)?o.some(a=>ag(a,i)):!1}}s(Yj,"evalBinary");function Eu(e,t){return[u$(e),u$(t)]}s(Eu,"orderedOperands");function u$(e){if(typeof e=="number")return Number.isFinite(e)?e:null;if(typeof e=="string"){if(e.trim()==="")return null;let t=Number(e);return Number.isFinite(t)?t:null}return null}s(u$,"numericOperand");function ag(e,t){return e===t?!0:e==null||t==null?!1:typeof e=="number"&&typeof t=="string"?e===Number(t):typeof e=="string"&&typeof t=="number"?Number(e)===t:!1}s(ag,"looseEq");function gi(e){return!(e==null||e===!1||e===0||e===""||Array.isArray(e)&&e.length===0)}s(gi,"truthy");function wt(e){let t=new Set;return Br(e,t),[...t]}s(wt,"dependencies");function Br(e,t){switch(e.kind){case"ident":t.add(e.path);return;case"call":e.args.forEach(n=>Br(n,t));return;case"arr":e.items.forEach(n=>Br(n,t));return;case"unary":Br(e.operand,t);return;case"binary":Br(e.left,t),Br(e.right,t);return;case"if":Br(e.cond,t),Br(e.then,t),Br(e.else,t);return;default:return}}s(Br,"walk");var f$=new Map;function nr(e){let t=f$.get(e);return t||(t=Lt(e),f$.set(e,t)),t}s(nr,"parseCached");function Jj(e,t){return mt(nr(e),t)}s(Jj,"evalExpression");function m$(e,t){return gi(Jj(e,t))}s(m$,"evalBoolean");var is={team:{label:{de:"Team",en:"Team"},optionSource:"tenantTeams",existence:{check:"generic",catalog:"teamKeys"}},roleKey:{label:{de:"Rolle",en:"Role"},optionSource:"tenantRoles",existence:{check:"node",codes:["roleAssign/unknownRoleKey","completenessCheck/unknownRole"]}},article:{label:{de:"Artikel",en:"Article"},optionSource:"programArticles",existence:{check:"node",codes:["collectPayment/unknownArticle"]}},legalEntity:{label:{de:"Tr\xE4ger",en:"Legal entity"},optionSource:"tenantTraeger",existence:{check:"node",codes:["governedDocument/unknownTraeger","collectPayment/unknownPayee"]}},contractGenerator:{label:{de:"Vertragsgenerator",en:"Contract generator"},optionSource:"tenantGenerators",existence:{check:"publish",by:"admittedGeneratorByKey"}},documentTemplate:{label:{de:"Dokumentvorlage",en:"Document template"},optionSource:"tenantDocumentTemplates",existence:{check:"publish",by:"governedDocument/unknownTemplate"}},smartForm:{label:{de:"Formular",en:"Form"},optionSource:"offerSmartForms",existence:{check:"publish",by:"form/unknownSmartForm"}},unit:{label:{de:"Einrichtung",en:"Unit"},optionSource:"tenantUnits",existence:{check:"generic",catalog:"unitKeys"}},formFlag:{label:{de:"Merkmal im Formular",en:"Flag in the form"},optionSource:"targetFormFlags",existence:{check:"node",codes:["setFlag/unknownFlag"]}}};function Tu(e){return typeof e=="string"&&Object.hasOwn(is,e)}s(Tu,"isResourceType");var ene=Object.keys(is).filter(e=>is[e].existence.check==="generic");var Tn="contractGenerator",dg="documentTemplate";function qa(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;let t=e,n=Object.keys(t);return(t.kind==="generator"||t.kind==="package")&&typeof t.key=="string"&&t.key.length>0&&(t.revision===void 0||typeof t.revision=="number"&&Number.isInteger(t.revision)&&t.revision>0)&&n.every(r=>r==="kind"||r==="key"||r==="revision")}s(qa,"isGeneratorRef");function h$(e,t){let n=e.inputs?.[t];return n?.kind==="literal"?n.value:void 0}s(h$,"literalOf");function Ur(e){let t=h$(e,Tn);return qa(t)?t:null}s(Ur,"generatorRefOfNode");function rr(e){let t=h$(e,dg);return typeof t=="string"&&t.length>0?t:null}s(rr,"documentTemplateKeyOfNode");function g$(e){return`${e.kind}:${e.key}${e.revision===void 0?"":`@${e.revision}`}`}s(g$,"generatorRefLabel");var y$=/^\d{4}-\d{2}-\d{2}$/;function ir(e,t){return{de:e,en:t}}s(ir,"issue");function io(e){if(typeof e!="object"||e===null)return ir("keine Reduktion","not a reduction");let t=e;if(t.kind==="none")return Object.keys(t).length===1?null:ir('\u201Ekeine Reduktion" tr\xE4gt keine weiteren Angaben','"no reduction" carries no further details');if(t.kind!=="amount")return ir(`unbekannte Art ${JSON.stringify(t.kind)}`,`unknown kind ${JSON.stringify(t.kind)}`);let{amount:n,activeFrom:r,activeTo:i}=t;return typeof n!="number"||!Number.isFinite(n)||n<=0?ir("der Betrag muss gr\xF6\xDFer als 0 \u20AC sein","the amount must be greater than \u20AC0"):Number.isInteger(Number((n*100).toFixed(6)))?typeof r!="string"||!y$.test(r)?ir("der Beginn fehlt (JJJJ-MM-TT)","the start is missing (YYYY-MM-DD)"):typeof i!="string"||!y$.test(i)?ir("das Ende fehlt (JJJJ-MM-TT)","the end is missing (YYYY-MM-DD)"):i<r?ir("das Ende liegt vor dem Beginn","the end is before the start"):t.floorTotal!==void 0&&(typeof t.floorTotal!="number"||!Number.isSafeInteger(t.floorTotal)||t.floorTotal<0)?ir("die Untergrenze muss ein nichtnegativer Centbetrag sein","the floor must be a non-negative amount in cents"):t.pricePeriod!==void 0&&!["month","year","once","unit"].includes(String(t.pricePeriod))?ir("ung\xFCltige Preisperiode","invalid price period"):Object.keys(t).some(o=>!["kind","amount","activeFrom","activeTo","floorTotal","pricePeriod"].includes(o))?ir("unbekannte Angaben","unknown details"):null:ir("der Betrag hat mehr als zwei Nachkommastellen","the amount has more than two decimal places")}s(io,"reductionShapeIssue");function w$(e){if(typeof e!="object"||e===null)return!1;let t=e;return typeof t.groupKey=="string"&&t.groupKey.length>0&&Array.isArray(t.grantKeys)&&t.grantKeys.every(n=>typeof n=="string"&&n.length>0)&&(t.reduction===void 0||io(t.reduction)===null&&t.reduction.kind==="amount")&&Object.keys(t).every(n=>n==="groupKey"||n==="grantKeys"||n==="reduction")}s(w$,"isPricedGroupValue");var cg=["street","hausnr","plz","ort","land"];function b$(e){return cg.includes(e)}s(b$,"isAddressPart");var Qj=["municipality","municipalityKey","district","districtKey"],ug=[...cg,...Qj],fg={string:"text",email:"text",tel:"text",number:"number",date:"date",boolean:"boolean",enum:"option",address:"composite",docRef:"file",party:"edge",personRef:"edge",personList:"edge",roleKey:"roleKey",pricedItem:"pricedItem",pricedGroup:"pricedGroup",reduction:"reduction",article:"article",legalEntity:"legalEntity",contractGenerator:"contractGenerator",documentTemplate:"documentTemplate",localizedText:"localizedText"},os=Object.keys(fg);function yi(e){return typeof e=="string"&&e in fg}s(yi,"isValueType");function mn(e){return e===void 0?void 0:fg[e]}s(mn,"dataTypeOf");function $u(e,t){let n=mn(e),r=mn(t);return n!==void 0&&n===r}s($u,"valueTypesCompatible");function pg(e){return e===null?"null is not a text in both languages":Ka(e,{type:"localizedText"})}s(pg,"completeLocalizedTextIssue");function Ka(e,t){if(Tu(t.type)&&!yi(t.type))return typeof e=="string"&&e.length>0?null:`${JSON.stringify(e)} is not a ${t.type} key`;let n=mn(t.type),r=JSON.stringify(e),i=`slot type "${t.type}" takes a binding, not a literal`;if(n===void 0||n==="composite"||n==="file"||n==="edge")return i;if(e===null)return null;switch(n){case"text":return typeof e=="string"?null:`${r} is not a text (slot type "${t.type}")`;case"date":return typeof e=="string"&&/^\d{4}-\d{2}-\d{2}$/.test(e)?null:`${r} is not a date YYYY-MM-DD`;case"number":return typeof e=="number"&&Number.isFinite(e)?null:`${r} is not a number`;case"boolean":return typeof e=="boolean"?null:`${r} is not true/false`;case"option":{if(typeof e!="string")return`${r} is not an option value`;let o=(t.enumOptions??[]).map(a=>a.value);return o.length===0||o.includes(e)?null:`${r} is not one of the options ${o.join(", ")}`}case"pricedItem":{let o=e;return typeof o=="object"&&typeof o.itemKey=="string"&&o.itemKey.length>0&&Array.isArray(o.grantKeys)&&o.grantKeys.every(a=>typeof a=="string")?null:`${r} is not a priced item {"itemKey":\u2026,"grantKeys":[\u2026]}`}case"pricedGroup":return w$(e)?null:`${r} is not a priced group {"groupKey":\u2026,"grantKeys":[\u2026]}`;case"article":return typeof e=="string"&&e.length>0?null:`${r} is not an article key`;case"legalEntity":return typeof e=="string"&&e.length>0?null:`${r} is not a legal entity key`;case"contractGenerator":return qa(e)?null:`${r} is not a contract generator {"kind":"generator"|"package","key":\u2026,"revision"?:n}`;case"documentTemplate":return typeof e=="string"&&e.length>0?null:`${r} is not a document template key`;case"roleKey":return typeof e=="string"&&e.length>0?null:`${r} is not a role key`;case"localizedText":{let o=e,a=s(l=>typeof l=="string"&&l.trim().length>0,"filled");return typeof o=="object"&&Object.keys(o).sort().join(",")==="de,en"&&a(o.de)&&a(o.en)?null:`${r} is not a text in both languages {"de":\u2026,"en":\u2026}`}case"reduction":{let o=io(e);return o===null?null:`${r} is not a reduction \u2014 ${o.en}`}}}s(Ka,"literalTypeIssue");var k$=hi,wi=`${k$}.`,Zj=new Set(["text","number","date","boolean","option","edge"]);function Ru(e,t){let n=e[t];return n===void 0&&_(`[env/unknownKey] no environment key '${t}'`),typeof n=="string"?null:Object.keys(n)}s(Ru,"contextFields");function v$(e,t){return Object.hasOwn(e,t)}s(v$,"isContextKey");function x$(e){let t=[];for(let n of Object.keys(e)){let r=Ru(e,n);if(r===null)t.push(n);else for(let i of r)t.push(`${n}.${i}`)}return t}s(x$,"leafPaths");function ja(e,t){let[n="",r,...i]=t.split(".");if(!v$(e,n)||i.length>0)return;let o=e[n];if(typeof o=="string")return r===void 0?o:void 0;if(!(r===void 0||!Object.hasOwn(o,r)))return o[r]}s(ja,"leafType");function S$(e){let t=new Set;for(let n of e){let r=ss(n);r!==null&&t.add(r.split(".")[0])}return[...t]}s(S$,"contextKeysOf");function ss(e){return e.startsWith(wi)?e.slice(wi.length):null}s(ss,"contextPathOf");function Ba(e){return e===k$||e.startsWith(wi)}s(Ba,"isContextIdentifier");function Iu(e,t){let n=ss(t)??"",[r=""]=n.split("."),i=Object.keys(e);if(!v$(e,r))return{code:"env/unknownKey",message:{de:`'${t}' nennt keinen Umgebungsschl\xFCssel \u2014 bekannt: ${i.join(", ")}.`,en:`'${t}' names no environment key \u2014 known: ${i.join(", ")}.`}};if(ja(e,n)!==void 0)return null;let o=Ru(e,r);return{code:"env/unknownKey",message:o===null?{de:`'${t}': der Umgebungsschl\xFCssel '${r}' ist ein einzelner Wert \u2014 lies ihn als '${wi}${r}'.`,en:`'${t}': environment key '${r}' is a single value \u2014 read it as '${wi}${r}'.`}:{de:`'${t}': der Umgebungsschl\xFCssel '${r}' hat die Felder ${o.join(", ")}.`,en:`'${t}': environment key '${r}' has the fields ${o.join(", ")}.`}}}s(Iu,"identifierIssue");function Ou(e,t,n=Object.keys(e)){let r={};for(let i of n){let o=Ru(e,i),a=Object.hasOwn(t,i)?t[i]:void 0;if(a===void 0&&_(`[env/missing] context key '${i}' was not supplied`),o===null){r[`${wi}${i}`]=a;continue}for(let l of o){let d=typeof a=="object"&&a!==null&&Object.hasOwn(a,l)?a[l]:void 0;d===void 0&&_(`[env/missing] context key '${i}' carries no '${l}'`),r[`${wi}${i}.${l}`]=d}}return r}s(Ou,"flatten");function A$(e,t,n){if(n===void 0)return!1;let r=Ru(e,t);return r===null?!0:typeof n=="object"&&n!==null&&r.every(i=>n[i]!==void 0)}s(A$,"contextValueComplete");function Xj(e,t){switch(t){case"number":return typeof e=="number"&&Number.isFinite(e);case"boolean":return typeof e=="boolean";case"date":return typeof e=="string"&&/^\d{4}-\d{2}-\d{2}/.test(e);default:return typeof e=="string"}}s(Xj,"valueMatchesDataType");function E$(e,t,n=Object.keys(e.types)){let r=new Set(n);for(let i of x$(e.types)){if(!r.has(i.split(".")[0]))continue;let o=t[`${wi}${i}`];o===void 0&&_(`[env/missing] context path '${i}' was not supplied`);let a=e.fields[i];if(o===null){a.nullable||_(`[env/null] context path '${i}' is not nullable but carries null`);continue}let l=mn(ja(e.types,i));Xj(o,l)||_(`[env/type] context path '${i}' expects ${l}, got ${JSON.stringify(o)}`),a.valueSet.kind==="fixed"&&!a.valueSet.values.includes(o)&&_(`[env/value] context path '${i}' carries '${String(o)}', outside ${a.valueSet.values.join(" | ")}`)}}s(E$,"assertContextValues");function eB(e){let t=[],n=x$(e.types);for(let r of n){let i=ja(e.types,r),o=mn(i);if(!yi(i)||o===void 0||!Zj.has(o)){t.push(`'${r}' has type '${String(i)}', not a scalar value type`);continue}let a=Object.hasOwn(e.fields,r)?e.fields[r]:void 0;if(a===void 0){t.push(`'${r}' has no field spec (value set + nullability)`);continue}a.valueSet.kind==="fixed"&&(a.valueSet.values.length===0&&t.push(`'${r}' has an empty fixed value set`),o!=="text"&&o!=="option"&&t.push(`'${r}' is ${o}; a fixed value set needs a text or option leaf`))}for(let r of Object.keys(e.fields))n.includes(r)||t.push(`field spec '${r}' names no leaf of the schema`);return t}s(eB,"schemaIssues");function as(e){let t=eB(e);t.length>0&&_(`[env/schema] ${t.join("; ")}`)}s(as,"assertSchema");var Pu={length:{params:["text"],returns:"number"},years_between:{params:["date","date"],returns:"number"}};function bi(e){return JSON.stringify(e)}s(bi,"canonical");function ds(e){return e.kind==="binary"&&e.op==="&&"?[...ds(e.left),...ds(e.right)]:[e]}s(ds,"conjuncts");function R$(e,t){let n;try{n=Lt(e)}catch{return!1}let r=bi(Lt(t));return ds(n).some(i=>bi(i)===r)}s(R$,"hasConjunct");function I$(e,t){try{return bi(Lt(e))===bi(Lt(t))}catch{return!1}}s(I$,"sameCondition");function O$(e){let t=[];for(let n of e)t.push(...wt(nr(n)));return S$(t)}s(O$,"contextKeysRead");function P$(e){try{return wt(Lt(e)).some(Ba)}catch{return!1}}s(P$,"readsContext");var tB=/^\d{4}-\d{2}-\d{2}$/,nB=new Set(["==","!=","<","<=",">",">=","in"]),rB=new Set(["<","<=",">",">="]);function Nu(e,t,n=[]){as(t);let r;try{r=Lt(e)}catch(a){let l=a.message;return[Mt("condition/parse",`Bedingung '${e}' ist nicht lesbar: ${l}`,`condition '${e}' does not parse: ${l}`)]}let i=[];for(let a of wt(r)){if(!Ba(a)){i.push(Mt("condition/foreignIdentifier",`'${a}' ist kein Umgebungswert \u2014 Bedingungen lesen nur '$env.*'`,`'${a}' is not a context identifier \u2014 conditions read only '$env.*'`));continue}let l=Iu(t.types,a);l!==null&&i.push(Mt("condition/unknownIdentifier",l.message.de,l.message.en))}if(i.length>0)return i;let o=br(r,t,i);Va(o)||i.push(Mt("condition/notBoolean",`Bedingung '${e}' ist kein Ja/Nein-Ausdruck`,`condition '${e}' is not a yes/no expression`)),aB(r,t,i);for(let{identifier:a,op:l}of gg(r,t))i.push(Mt("condition/unguardedNullable",`'${l}' \xFCber '${a}', das leer sein kann, braucht davor eine Absicherung '${a} != null &&'`,`'${l}' over '${a}', which may be null, needs a guard '${a} != null &&' before it`));return i.push(...iB(r,n)),i}s(Nu,"conditionIssues");function iB(e,t){let n=ds(e).map(bi);return t.flatMap(r=>{let i=Lt(r),o=oB(i);return o===null||!n.includes(bi(o))?[]:[{severity:"info",code:"condition/guardForm",message:{de:`[condition/guardForm] eine gespiegelte Absicherung z\xE4hlt nicht \u2014 schreibe sie genau als '${r}'`,en:`[condition/guardForm] a mirrored guard does not count \u2014 write it exactly as '${r}'`}}]})}s(iB,"guardFormHints");function oB(e){if(e.kind!=="binary"||e.op!=="=="&&e.op!=="!=")return null;let t={...e,left:e.right,right:e.left};return bi(t)===bi(e)?null:t}s(oB,"mirror");function Va(e){return e.t==="unknown"||e.t==="data"&&e.dt==="boolean"}s(Va,"isBooleanish");function _$(e){let t=ss(e);return t===null&&_(`[condition/invariant] '${e}' reached a pass that only sees $env identifiers`),t}s(_$,"contextPath");function N$(e,t){let n=ss(t);return n!==null&&e.fields[n]?.nullable===!0}s(N$,"isNullableLeaf");function sB(e,t){let n=mn(ja(e.types,_$(t)));return n===void 0?{t:"unknown"}:{t:"data",dt:n}}s(sB,"identType");function _u(e,t){return e.t==="unknown"||t.t==="unknown"||e.t==="null"||t.t==="null"?!0:e.t==="array"||t.t==="array"?!1:e.t==="str"&&t.t==="str"?!0:e.t==="str"?T$(e.value,t.dt):t.t==="str"?T$(t.value,e.dt):e.dt===t.dt}s(_u,"fits");function T$(e,t){return t==="text"||t==="option"||t==="edge"?!0:t==="date"?tB.test(e):!1}s(T$,"strFits");function $$(e){return e.t==="unknown"?"unknown":e.t==="data"&&e.dt==="number"?"number":null}s($$,"orderedCategory");function br(e,t,n){switch(e.kind){case"num":return{t:"data",dt:"number"};case"bool":return{t:"data",dt:"boolean"};case"str":return{t:"str",value:e.value};case"null":return{t:"null"};case"ident":return sB(t,e.path);case"arr":for(let r of e.items)br(r,t,n);return{t:"array"};case"unary":{let r=br(e.operand,t,n);return Va(r)||n.push(Mt("condition/notBoolean","'!' braucht einen Ja/Nein-Operanden","'!' needs a yes/no operand")),{t:"data",dt:"boolean"}}case"call":{let r=Object.hasOwn(Pu,e.name)?Pu[e.name]:void 0,i=e.args.map(l=>br(l,t,n));return r===void 0?(n.push(Mt("condition/functionNotAllowed",`Funktion '${e.name}' ist nicht erlaubt \u2014 erlaubt: ${Object.keys(Pu).join(", ")}`,`function '${e.name}' is not allowed \u2014 allowed: ${Object.keys(Pu).join(", ")}`)),{t:"unknown"}):(i.length===r.params.length&&i.every((l,d)=>l.t!=="null"&&_u(l,{t:"data",dt:r.params[d]}))||n.push(Mt("condition/typeMismatch",`'${e.name}' nimmt (${r.params.join(", ")})`,`'${e.name}' takes (${r.params.join(", ")})`)),{t:"data",dt:r.returns})}case"if":{let r=br(e.cond,t,n);Va(r)||n.push(Mt("condition/notBoolean","'if' braucht eine Ja/Nein-Bedingung","'if' needs a yes/no condition"));let i=br(e.then,t,n),o=br(e.else,t,n);return _u(i,o)||n.push(Mt("condition/typeMismatch","die beiden Zweige von 'if' haben verschiedene Typen","the two arms of 'if' differ in type")),i.t==="null"?o:i}case"binary":{let r=br(e.left,t,n),i=br(e.right,t,n);if(e.op==="&&"||e.op==="||")(!Va(r)||!Va(i))&&n.push(Mt("condition/notBoolean",`'${e.op}' braucht Ja/Nein-Operanden`,`'${e.op}' needs yes/no operands`));else if(e.op==="in")e.right.kind!=="arr"?n.push(Mt("condition/inWithoutArray","'in' braucht rechts eine Liste, z. B. ['a', 'b']","'in' needs a list on its right, e.g. ['a', 'b']")):e.right.items.every(o=>_u(r,br(o,t,[])))||n.push(Mt("condition/typeMismatch","ein Listeneintrag von 'in' passt nicht zum Typ des linken Operanden","a list item of 'in' does not match the left operand's type"));else if(rB.has(e.op)){let o=$$(r),a=$$(i);(o===null||a===null||o!=="unknown"&&a!=="unknown"&&o!==a)&&n.push(Mt("condition/orderedComparison",`'${e.op}' vergleicht nur Zahlen \u2014 f\xFCr Daten years_between(\u2026) verwenden`,`'${e.op}' compares only numbers \u2014 for dates use years_between(\u2026)`))}else _u(r,i)||n.push(Mt("condition/typeMismatch",`'${e.op}' vergleicht Werte verschiedener Typen`,`'${e.op}' compares values of different types`));return{t:"data",dt:"boolean"}}}}s(br,"typeOf");function mg(e){return e.kind==="str"||e.kind==="num"||e.kind==="bool"}s(mg,"isLiteral");function C$(e){let t=[],n=s(r=>{if(r.kind==="binary"&&nB.has(r.op)){if(r.left.kind==="ident"){let i=r.op==="in"&&r.right.kind==="arr"?r.right.items.filter(mg):mg(r.right)?[r.right]:[];i.length>0&&t.push({ident:r.left.path,literals:i})}r.right.kind==="ident"&&mg(r.left)&&t.push({ident:r.right.path,literals:[r.left]})}D$(r,n)},"visit");return n(e),t}s(C$,"comparedLiterals");function aB(e,t,n){for(let{ident:r,literals:i}of C$(e)){let o=lB(r,i,t);o!==null&&n.push(o)}}s(aB,"literalIssues");function hg(e,t){let n;try{n=Lt(e)}catch{return[]}let r=[];for(let{ident:i,literals:o}of C$(n)){let a=ss(i);if(!(a===null||t.fields[a]?.valueSet.kind!=="live"))for(let l of o)l.kind==="str"&&r.push({path:a,value:l.value})}return r}s(hg,"liveLiterals");function lB(e,t,n){let r=n.fields[_$(e)]?.valueSet;if(r?.kind==="unstable")return Mt("condition/literalOnUnstable",`'${e}' ist nicht \xFCber Umgebungen stabil \u2014 vergleiche ihn mit keinem festen Wert; verzweige stattdessen \xFCber ein stabiles Merkmal`,`'${e}' is not stable across environments \u2014 compare it to no literal; branch on a stable attribute instead`);if(r?.kind!=="fixed")return null;let i=t.flatMap(a=>a.kind==="str"&&!r.values.includes(a.value)?[`'${a.value}'`]:[]);if(i.length===0)return null;let o=r.values.map(a=>`'${a}'`).join(", ");return Mt("condition/literalOutsideSet",`'${e}' kennt nur ${o} \u2014 nicht ${i.join(", ")}`,`'${e}' takes only ${o} \u2014 not ${i.join(", ")}`)}s(lB,"valueSetIssue");function D$(e,t){switch(e.kind){case"binary":t(e.left),t(e.right);return;case"unary":t(e.operand);return;case"call":e.args.forEach(t);return;case"arr":e.items.forEach(t);return;case"if":t(e.cond),t(e.then),t(e.else);return;default:return}}s(D$,"forEachChild");function F$(e){return e.kind==="binary"&&(e.op==="=="||e.op==="!=")&&(e.left.kind==="ident"&&e.right.kind==="null"||e.left.kind==="null"&&e.right.kind==="ident")}s(F$,"isNullTest");function L$(e){return ds(e).flatMap(t=>{let n=M$(t);return n===null?[]:[n]})}s(L$,"guardsOf");function Ua(e,t,n){switch(e.kind){case"ident":return N$(t,e.path)&&!n.has(e.path)?e.path:null;case"call":for(let r of e.args){let i=Ua(r,t,n);if(i!==null)return i}return null;case"if":return Ua(e.then,t,new Set([...n,...L$(e.cond)]))??Ua(e.else,t,n);default:return null}}s(Ua,"unguardedNullSource");function M$(e){return!F$(e)||e.kind!=="binary"||e.op!=="!="?null:e.left.kind==="ident"?e.left.path:e.right.kind==="ident"?e.right.path:null}s(M$,"guardedIdent");function ls(e,t,n,r){if(e.kind==="binary"&&e.op==="&&"){let i=new Set(n);for(let o of ds(e)){ls(o,t,i,r);let a=M$(o);a!==null&&i.add(a)}return}if(e.kind==="if"){ls(e.cond,t,n,r),ls(e.then,t,new Set([...n,...L$(e.cond)]),r),ls(e.else,t,n,r);return}if(e.kind==="binary"&&e.op==="!="&&e.left.kind!=="null"&&e.right.kind!=="null"){let i=Ua(e.left,t,n)??Ua(e.right,t,n);i!==null&&r(i,"!=")}if(e.kind==="unary"&&!F$(e.operand)){let i=wt(e.operand).filter(o=>N$(t,o)&&!n.has(o));i.length>0&&r(i[0],"!")}D$(e,i=>ls(i,t,n,r))}s(ls,"nullableReads");function gg(e,t){as(t);let n=[];return ls(e,t,new Set,(r,i)=>{n.some(o=>o.identifier===r)||n.push({identifier:r,op:i})}),n}s(gg,"unguardedNullableReads");function Mt(e,t,n){return{severity:"error",code:e,message:{de:`[${e}] ${t}`,en:`[${e}] ${n}`}}}s(Mt,"error");function ki(e){if(typeof e!="object"||e===null)return!1;let t=e;return typeof t.itemKey=="string"&&t.itemKey.length>0&&Array.isArray(t.grantKeys)&&t.grantKeys.every(n=>typeof n=="string"&&n.length>0)&&(t.reduction===void 0||io(t.reduction)===null&&t.reduction.kind==="amount")}s(ki,"isPricedItemValue");var cs=["freetext","recommendation","choice","pricedItem","record","reduction"],us=[...cs,"appointment"];function K$(e){return typeof e=="string"&&us.includes(e)}s(K$,"isTaskResultKind");function vi(e){return typeof e=="string"&&cs.includes(e)}s(vi,"isRecordedTaskResultKind");function fs(e){return vi(e.kind)}s(fs,"isRecordedTaskResult");var Cu=["number","boolean","enum"];function yg(e){return typeof e=="string"&&Cu.includes(e)}s(yg,"isRecordFieldType");var wg=["form","siblingRank"];var Gr={freetext:{choiceValueType:null,valueType:null,textValueType:"string",label:{de:"Freitext",en:"Free text"}},recommendation:{choiceValueType:"enum",valueType:null,textValueType:"string",label:{de:"Empfehlung",en:"Recommendation"}},choice:{choiceValueType:"enum",valueType:"enum",textValueType:"string",label:{de:"Auswahl",en:"Choice"}},pricedItem:{choiceValueType:"enum",valueType:"pricedItem",textValueType:"string",label:{de:"Preisposition",en:"Priced item"}},reduction:{choiceValueType:null,valueType:"reduction",textValueType:"string",label:{de:"Reduktion",en:"Reduction"}},record:{choiceValueType:null,valueType:null,textValueType:"string",label:{de:"Erfassung",en:"Record"}},appointment:{choiceValueType:null,valueType:null,textValueType:null,label:{de:"Termin",en:"Appointment"}}};function oo(e){return(e.kind==="freetext"||e.kind==="recommendation"||e.kind==="choice")&&e.writes===void 0}s(oo,"isProseResult");function Du(e){return e.kind==="record"?(e.fields??[]).filter(t=>typeof t.writes=="string"&&t.writes.length>0&&yg(t.type)).map(t=>({key:t.writes,valueType:t.type,field:t})):dB(e)}s(Du,"draftResultStoreWrites");function dB(e){let t=Gr[e.kind].valueType;return e.writes===void 0||t===null?[]:[{key:e.writes,valueType:t}]}s(dB,"singleStoreWrite");var q$="team:";function ps(e){if(e==="all")return{kind:"all"};if(e==="external"||e.length===0)return null;if(e.startsWith(q$)){let t=e.slice(q$.length);return t.length===0?null:{kind:"team",groupKey:t}}return{kind:"channel",channelKey:e}}s(ps,"parseTaskResultChat");var We={unknownKind:"[taskResult/unknownKind]",onApproval:"[taskResult/onApproval]",unknownField:"[taskResult/unknownField]",choiceOptions:"[taskResult/choiceOptions]",textRequiredOnFreetext:"[taskResult/textRequiredOnFreetext]",chatMissing:"[taskResult/chatMissing]",chatExternal:"[taskResult/chatExternal]",chatUnknownChannel:"[taskResult/chatUnknownChannel]",appointmentMissingTitle:"[taskResult/appointmentMissingTitle]",pricedItemMissingItem:"[taskResult/pricedItemMissingItem]",pricedItemUnknownItem:"[taskResult/pricedItemUnknownItem]",pricedItemNotInProgram:"[taskResult/pricedItemNotInProgram]",pricedItemOfferWithoutProgram:"[taskResult/pricedItemOfferWithoutProgram]",itemOnNonPricedItem:"[taskResult/itemOnNonPricedItem]",writesOnProse:"[taskResult/writesOnProse]",filesOnKind:"[taskResult/filesOnKind]",labelMissing:"[taskResult/labelMissing]",appointmentInvalidDuration:"[taskResult/appointmentInvalidDuration]",recordFields:"[taskResult/recordFields]",fieldsOnNonRecord:"[taskResult/fieldsOnNonRecord]",recordSuggest:"[taskResult/recordSuggest]",reductionPrices:"[taskResult/reductionPrices]",pricesOnNonReduction:"[taskResult/pricesOnNonReduction]"};var ms={"assign{}":{kind:"team",codec:"key",involves:!0,required:!1,what:{de:"Team der Knoten-Aufgabe",en:"team of the node task"},consequence:{de:"beim Betreten des Knotens entsteht die Aufgabe f\xFCr niemanden",en:"entering the node creates the task for nobody"}},"tasks[].assign.group":{kind:"team",codec:"key",involves:!0,required:!0,what:{de:"Team der Aufgabe",en:"team of the task"},consequence:{de:"die Aufgabe kann nicht angelegt werden, und der Prozess bleibt stehen",en:"the task cannot be created and the process stops"}},"tasks[].params.revisionGroup":{kind:"team",codec:"key",involves:!0,required:!1,what:{de:"Team der \xDCberarbeitung",en:"revision team"},consequence:{de:"eine Ablehnung findet niemanden, der \xFCberarbeitet",en:"a rejection finds nobody to revise"}},"tasks[].result.chat":{kind:"team",codec:"chatTarget",involves:!1,required:!1,what:{de:"Chat des Ergebnisses",en:"chat of the result"},consequence:{de:"das Ergebnis l\xE4sst sich nicht im Chat ablegen",en:"the result cannot be posted to the chat"}},"optionalActions[].trigger":{kind:"team",codec:"key",involves:!1,required:!1,what:{de:"Team, das die Aktion ausl\xF6sen darf",en:"team that may trigger the action"},consequence:{de:"niemand au\xDFer der Prozessverantwortung kann die Aktion ausl\xF6sen",en:"nobody but the process owner can trigger the action"}}},bg=s(e=>typeof e=="object"&&e!==null&&!Array.isArray(e)?e:null,"record");function j$(e,t){if(typeof t!="string"||t.length===0)return null;if(e==="key")return t;let n=ps(t);return n?.kind==="team"?n.groupKey:null}s(j$,"decodeKey");function cB(e){let t=/^(tasks|optionalActions)\[\](?:\.([a-zA-Z]+))?\.([a-zA-Z]+)$/.exec(e);return t===null&&_(`[resource] unreadable reference leaf "${e}"`),{list:t[1],field:t[2]??null,key:t[3]}}s(cB,"locate");function Fu(e){let t=[],n=e;for(let[r,i]of Object.entries(bg(n.assign)??{})){let o=j$("key",i);t.push({path:`assign.${r}`,leaf:"assign{}",owner:r,key:o,missing:typeof i!="string"||i.length===0})}for(let r of Object.keys(ms)){if(r==="assign{}")continue;let i=ms[r],{list:o,field:a,key:l}=cB(r);for(let d of Array.isArray(n[o])?n[o]:[]){let c=bg(d);if(c===null||typeof c.key!="string")continue;let f=(a===null?c:bg(c[a]))?.[l];if(f===void 0&&!i.required)continue;let m=typeof f!="string"||f.length===0;t.push({path:`${o}.${c.key}${a===null?"":`.${a}`}.${l}`,leaf:r,owner:c.key,key:j$(i.codec,f),missing:m})}}return t}s(Fu,"nodeResourceReferences");function Ga(e){let t=Array.isArray(e.nodes)?e.nodes:[],n=new Set;for(let r of t)for(let i of Fu(r))i.key!==null&&ms[i.leaf].involves&&n.add(i.key);return n}s(Ga,"declaredGroupKeys");var kt="responsible",kg="team:";function vg(e){return`${kg}${e}`}s(vg,"teamSlot");function xg(e){return e.startsWith(kg)?e.slice(kg.length):null}s(xg,"teamKeyOfSlot");var hs=bu;var uB="unit.key",fB="offer.key";function B$(e,t){return e===uB?t.unitKeys:e===fB?t.offerKeys:null}s(B$,"liveKeyUniverse");function Lu(e){return[kt,...[...Ga(e)].sort((t,n)=>t.localeCompare(n)).map(vg)]}s(Lu,"requiredSlots");var xi=`${vu("applicant.channel")} == 'staff'`;var Ag=["strict","leastLoaded"];var Sg=2;function V$(e){return e.some(t=>t.length===0)?{de:"nennt einen leeren Personenschl\xFCssel",en:"names an empty person key"}:new Set(e).size!==e.length?{de:"nennt eine Person zweimal",en:"names a person twice"}:e.length<Sg?{de:`braucht mindestens ${Sg} Personen`,en:`needs at least ${Sg} people`}:null}s(V$,"rotationPoolProblem");function pB(e,t){let n=t===null?-1:e.indexOf(t);return[...e.slice(n+1),...e.slice(0,n+1)]}s(pB,"strictOrder");function U$(e){let t=pB(e.pool,e.previous).filter(i=>e.eligible.has(i));if(t.length===0)return null;if(e.mode==="strict")return t[0];let n=e.openCounts;n===void 0&&_("[assignment/rotation] leastLoaded needs the open counts");let r=s(i=>{let o=n.get(i);return o===void 0&&_(`[assignment/rotation] no open count for '${i}'`),o},"load");return t.reduce((i,o)=>r(o)<r(i)?o:i)}s(U$,"pickFromPool");function z$(e,t){let n=e?.assignmentRules;n===void 0&&_(`[assignment/noRules] ${t}: the workflow has no assignment rule`);let r=J$(n);return r.length>0&&_(`${r.join("; ")} (${t})`),n}s(z$,"rulesOfGraph");function mB(e){return e===kt?{slot:e,rules:[{when:xi,assign:{kind:"creator"}},{when:null,assign:{kind:"unassigned"}}]}:{slot:e,rules:[{when:null,assign:{kind:"queue"}}]}}s(mB,"defaultSlotRules");function W$(e,t){let n=new Set(e.map(o=>o.slot)),r=t.filter(o=>!n.has(o)).map(mB);return[...r.filter(o=>o.slot===kt),...e,...r.filter(o=>o.slot!==kt)]}s(W$,"withRequiredSlots");function Tt(e,t){return t===void 0?`slot '${e}'`:`slot '${e}' row #${t+1}`}s(Tt,"where");function $n(e,t){return t===void 0?`Liste '${e}'`:`Liste '${e}', Zeile #${t+1}`}s($n,"whereDe");function hn(e,t,n={},r="error"){return{severity:r,code:e,message:{de:`[${e}] ${t.de}`,en:`[${e}] ${t.en}`},...n}}s(hn,"issue");function G$(e){if(e===kt)return!0;let t=xg(e);return t!==null&&t.length>0}s(G$,"isKnownSlot");function hB(e,t){as(hs);let n=[],r=new Set;e.forEach((o,a)=>{let{slot:l}=o;G$(l)||n.push(hn("assignment/unknownSlot",{de:`'${l}' ist keine Liste \u2014 'responsible' oder 'team:<teamKey>'`,en:`'${l}' is no slot \u2014 'responsible' or 'team:<teamKey>'`},{slot:l})),r.has(l)&&n.push(hn("assignment/duplicateSlot",{de:`${$n(l)} steht zweimal da`,en:`${Tt(l)} is listed twice`},{slot:l})),r.add(l),l===kt&&a!==0&&n.push(hn("assignment/responsibleFirst",{de:`'${kt}' muss die erste Liste sein \u2014 Team-Zeilen \xFCbernehmen sie`,en:`'${kt}' must be the first slot \u2014 team rows copy it`},{slot:l})),n.push(...gB(o))});for(let o of t)r.has(o)||n.push(hn("assignment/slotMissing",{de:`${$n(o)} hat keine Regeln \u2014 der Workflow braucht sie`,en:`${Tt(o)} has no rule list \u2014 the workflow needs it`},{slot:o}));let i=new Set(t);for(let{slot:o}of e)o!==kt&&!i.has(o)&&G$(o)&&n.push(hn("assignment/unusedSlot",{de:`${$n(o)} wird hier nicht gebraucht \u2014 erlaubt, und nicht ausgewertet`,en:`${Tt(o)} is not needed here \u2014 allowed, and not evaluated`},{slot:o},"info"));return n}s(hB,"validateRules");function gB({slot:e,rules:t}){let n=[];return(t.length===0||t[t.length-1].when!==null)&&n.push(hn("assignment/defaultRowMissing",{de:`${$n(e)} muss mit einer Zeile ohne Bedingung enden (\u201Esonst\u201C)`,en:`${Tt(e)} must end with a row without condition ("otherwise")`},{slot:e})),t.forEach((r,i)=>{let o={slot:e,row:i},{when:a,assign:l}=r;if(a===null&&i<t.length-1&&n.push(hn("assignment/ruleAfterDefault",{de:`${$n(e,i)} hat keine Bedingung, aber es folgen Zeilen \u2014 sie treffen nie zu`,en:`${Tt(e,i)} has no condition, but rows follow it \u2014 they can never match`},o)),a!==null){let d=Nu(a,hs,[xi]);for(let c of d)n.push({...c,message:{de:`${c.message.de} (${$n(e,i)})`,en:`${c.message.en} (${Tt(e,i)})`},...o});if(d.every(c=>c.severity!=="error")){P$(a)||n.push(hn("assignment/shadowedRule",{de:`${$n(e,i)} liest nichts aus dem Vorgang \u2014 sie gilt immer oder nie`,en:`${Tt(e,i)} reads nothing of the application \u2014 it holds for every application or for none`},o));let c=t.slice(0,i).findIndex(u=>u.when!==null&&I$(u.when,a));c!==-1&&n.push(hn("assignment/shadowedRule",{de:`${$n(e,i)} wiederholt die Bedingung von Zeile #${c+1} \u2014 sie trifft nie zu`,en:`${Tt(e,i)} repeats the condition of row #${c+1} \u2014 it can never match`},o))}}if(e===kt&&l.kind==="slot"&&n.push(hn("assignment/slotForwardRef",{de:`${$n(e,i)} \xFCbernimmt '${l.slot}' \u2014 das darf nur eine Team-Liste nach '${kt}'`,en:`${Tt(e,i)} copies '${l.slot}' \u2014 only a team slot after '${kt}' may`},o)),e===kt&&l.kind==="queue"&&n.push(hn("assignment/queueOnProcessSlot",{de:`${$n(e,i)} weist die Queue zu \u2014 die Prozesszust\xE4ndigkeit ist immer eine Person`,en:`${Tt(e,i)} assigns the queue \u2014 the responsible slot is always a person`},o)),l.kind==="unassigned"&&n.push(hn("assignment/targetMissing",{de:`${$n(e,i)} nennt noch niemanden \u2014 Person w\xE4hlen`,en:`${Tt(e,i)} names no one yet \u2014 choose a person`},o)),l.kind==="rotation"){let d=V$(l.configKeys);d!==null&&n.push(hn("assignment/rotationPool",{de:`${$n(e,i)}: die Reihum-Liste ${d.de}`,en:`${Tt(e,i)} rotates over a pool that ${d.en}`},o))}l.kind==="creator"&&(a===null||!R$(a,xi))&&n.push(hn("assignment/unguardedTarget",{de:`${$n(e,i)} weist die anlegende Person zu \u2014 die gibt es nur, wenn die Bedingung der Zeile '${xi}' ist (oder enth\xE4lt)`,en:`${Tt(e,i)} assigns the creator, which exists only when the row's condition is (or has the conjunct) '${xi}'`},o))}),n}s(gB,"rowIssues");function H$(e,t){for(let r of t)e.some(i=>i.slot===r)||_(`[assignment/slotMissing] ${Tt(r)} has no rule list`);let n=new Set(t);return e.filter(r=>n.has(r.slot))}s(H$,"selectSlots");function yB(e,t){return O$(H$(e,t).flatMap(n=>n.rules.flatMap(r=>r.when===null?[]:[r.when])))}s(yB,"contextKeysOfRules");function Y$(e,t,n,r){as(hs);let i=H$(e,n),o=yB(e,n),a=Ou(hs.types,t,o);E$(hs,a,o);let l=[];for(let{slot:d,rules:c}of i){let u=c.findIndex((m,g)=>{if(m.when===null)return!0;for(let w of wt(nr(m.when)))Object.hasOwn(a,w)||_(`[condition/unknownIdentifier] ${Tt(d,g)} reads '${w}', which the context does not carry`);return m$(m.when,{values:a})});u===-1&&_(`[assignment/defaultRowMissing] ${Tt(d)}: no row matched and there is no default row`);let f=c[u].assign;l.push({slot:d,ruleIndex:u,assign:f,value:wB(d,u,f,l,r)})}return l}s(Y$,"evaluateRules");function wB(e,t,n,r,i){switch(n.kind){case"person":return{kind:"value",value:i.person(n.configKey)};case"creator":return{kind:"value",value:i.creator()};case"rotation":return{kind:"value",value:i.rotation(n,{slot:e,row:t})};case"unassigned":return _(`[assignment/targetMissing] ${Tt(e,t)} names no one`);case"queue":return e===kt&&_(`[assignment/queueOnProcessSlot] ${Tt(e,t)} assigns the queue`),{kind:"queue"};case"slot":{let o=e===kt?void 0:r.find(a=>a.slot===n.slot);return o===void 0&&_(`[assignment/slotForwardRef] ${Tt(e,t)} copies '${n.slot}', which is not decided before it`),o.value}}}s(wB,"resolveTarget");var Eg={person:["kind","configKey"],creator:["kind"],slot:["kind","slot"],queue:["kind"],rotation:["kind","configKeys","mode"],unassigned:["kind"]};function J$(e){let t=[],n=s((r,i)=>t.push(`[assignment/shape] ${r}: ${i}`),"bad");return Array.isArray(e)?(e.forEach((r,i)=>{let o=`slots[${i}]`;if(typeof r!="object"||r===null)return n(o,"must be { slot, rules }");let{slot:a,rules:l,...d}=r;if(Object.keys(d).length>0&&n(o,`unknown field(s) ${Object.keys(d).join(", ")}`),typeof a!="string"&&n(o,"slot must be a string"),!Array.isArray(l))return n(o,"rules must be a list");l.forEach((c,u)=>{let f=`${o}.rules[${u}]`;if(typeof c!="object"||c===null)return n(f,"must be { when, assign }");let{when:m,assign:g,...w}=c;Object.keys(w).length>0&&n(f,`unknown field(s) ${Object.keys(w).join(", ")}`),m!==null&&typeof m!="string"&&n(f,"when must be a condition string or null (\u201Esonst\u201C)");let y=g?.kind;if(typeof g!="object"||g===null||typeof y!="string"||!Object.hasOwn(Eg,y))return n(f,`assign must be one of ${Object.keys(Eg).map(O=>`{kind:'${O}'}`).join(", ")}`);let v=Eg[y],T=Object.keys(g);(T.some(O=>!v.includes(O))||v.some(O=>!T.includes(O)))&&n(f,`a '${y}' target has exactly the field(s) ${v.join(", ")}`);let $=g;if(y==="person"&&(typeof $.configKey!="string"||$.configKey.length===0)&&n(f,"a 'person' target needs a non-empty configKey"),y==="rotation"){let O=$.configKeys;(!Array.isArray(O)||O.some(N=>typeof N!="string"))&&n(f,"a 'rotation' target needs configKeys, a list of person keys"),Ag.includes($.mode)||n(f,`a 'rotation' target's mode is one of ${Ag.map(N=>`'${N}'`).join(", ")}`)}y==="slot"&&$.slot!==kt&&n(f,`a 'slot' target copies '${kt}' and nothing else`)})}),t):(n("slots","must be a list of { slot, rules }"),t)}s(J$,"ruleShapeIssues");function Q$(e){let t=e??{},n=[];if(t.teamOwnerBindings!==void 0&&n.push({de:"[assignment/legacyBindings] der Workflow tr\xE4gt noch teamOwnerBindings \u2014 die Zust\xE4ndigkeitsregel ersetzt sie; das Feld entfernen",en:"[assignment/legacyBindings] the workflow still carries teamOwnerBindings \u2014 the assignment rule replaces them; remove the field"}),t.assignmentRules===void 0)return n.push({de:"[assignment/noRules] der Workflow hat keine Zust\xE4ndigkeitsregel (graph.assignmentRules) \u2014 jeder Workflow muss sagen, wer zust\xE4ndig wird",en:"[assignment/noRules] the workflow has no assignment rule (graph.assignmentRules) \u2014 every workflow must say who becomes responsible"}),n;let r=J$(t.assignmentRules);if(r.length>0)return[...n,...r.map(o=>({de:o,en:o}))];let i=Lu({nodes:Array.isArray(t.nodes)?t.nodes:[]});for(let o of hB(t.assignmentRules,i))o.severity==="error"&&n.push(o.message);return n}s(Q$,"workflowAssignmentIssues");function Z$(e,t,n={}){let r=new Map;return{slots:Y$(e,t,n.slots??e.map(o=>o.slot),{person:s(o=>`person:${o}`,"person"),creator:s(()=>(n.creator===void 0&&fe("INVALID",{de:"[assignment/noCreator] Die zutreffende Zeile weist die anlegende Person zu, aber es wurde kein --creator angegeben (ein Selbststart hat keine).",en:"[assignment/noCreator] The matching row assigns the creating person, but no --creator was given (a self-start has none)."}),`creator:${n.creator}`),"creator"),rotation:s((o,{slot:a})=>{let l=n.rotationPrevious?.[a]??null,d=U$({pool:o.configKeys,mode:o.mode,previous:l,eligible:new Set(o.configKeys.filter(c=>!(n.left??[]).includes(c))),openCounts:new Map(o.configKeys.map(c=>[c,n.openCounts?.[c]??0]))});return d===null&&fe("INVALID",{de:`[assignment/rotationEmpty] Platz \u201E${a}\u201C: alle aus dem Pool sind ausgeschieden`,en:`[assignment/rotationEmpty] slot '${a}': everyone in the pool has left`}),r.set(a,{pool:[...o.configKeys],mode:o.mode,previous:l,picked:d}),`person:${d}`},"rotation")}).map(o=>{let a=r.get(o.slot);return{slot:o.slot,row:o.ruleIndex+1,assign:o.assign,value:o.value.kind==="queue"?"queue":o.value.value,...a!==void 0?{rotation:a}:{}}})}}s(Z$,"simulateRules");function X$(e,t){let n={};for(let r of t??[]){let i=r.lastIndexOf("=");if(i<=0||i===r.length-1)throw new Error(`assignment simulate: ${e} takes <key>=<value>, got '${r}'`);let o=r.slice(0,i);if(Object.hasOwn(n,o))throw new Error(`assignment simulate: ${e} names '${o}' twice`);n[o]=r.slice(i+1)}return n}s(X$,"parsePairs");function bB(e){let t={};for(let[n,r]of Object.entries(X$("--open",e))){let i=Number(r);if(!Number.isInteger(i)||i<0)throw new Error(`assignment simulate: --open ${n}=${r} is no count`);t[n]=i}return t}s(bB,"parseCounts");function kB(e,t){if(e===void 0==(t===void 0))throw new Error("assignment simulate: pass exactly one of --env-json '<json>' or --env-file <path>");let n=e??ke(t,"utf8"),r=JSON.parse(n);if(typeof r!="object"||r===null||Array.isArray(r))throw new Error("assignment simulate: the environment must be a JSON object");return r}s(kB,"parseEnv");var Tg=class extends Se{static{s(this,"AssignmentSimulateCommand")}static paths=[["assignment","simulate"]];static usage=E.Usage({category:"Admission",description:"Evaluate an offer bundle's assignment rule over an application's environment ($env), offline",details:`
9380
9380
  The environment carries every key the rule reads ($env): offer
@@ -9771,6 +9771,6 @@ ${n.length} unusable ${o}:
9771
9771
  `),r.length>0&&this.context.stdout.write(` ${r.length} linkable \u2014 plexus-cli users relink-auth <email>
9772
9772
  `),i.length>0&&this.context.stdout.write(` ${i.length} without any login account \u2014 plexus-cli users provision --tenant <slug> --email <email> --name <name>
9773
9773
  `)}else this.context.stdout.write(`No unusable identities.
9774
- `);return n.length>0?1:0}},zS=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 X0(e,t){if(e===t)throw new Error("Pass exactly one of --on or --off.");return e}s(X0,"requireOnOff");var eM=[$S,RS,IS,OS,PS,_S,NS,CS,DS,FS,LS,MS,wc,qS,KS,jS,BS,VS,US,GS,zS];function tM(e){return e.de??e.en??Object.values(e)[0]??""}s(tM,"titleDe");function HJ(e){return{id:e._id,kind:e.kind,status:e.status,title:tM(e.title).slice(0,50),assignee:e.assigneeUserId??"",group:e.queueGroupId??"",outcome:e.outcome??""}}s(HJ,"row");var YJ=["id","kind","status","title","assignee","group","outcome"],HS=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(HJ),YJ),0}},YS=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:tM(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}},JS=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}},QS=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}},ZS=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}},nM=[HS,YS,JS,QS,ZS];var Em=[...PT,...wR,...MI,...LI,...cO,...SO,...xO,...Q0,...eM,...d0,...rR,...sO,...z0,...IT,...n$,...eR,...TO,...EO,...IO,...OO,...iO,...UI,...nM,...dF,...HF,...a0,...YF,...C0,...B0,...c0,...b0,...x0,...G0,...J0,...HT];var rM="0.1.9";function iM(){return Em.flatMap(e=>(e.paths??[]).map(t=>{let n=t.join(" "),r=ET[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(iM,"plexusCommandCatalog");import Fo from"node:path";function JJ(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(JJ,"workspacePath");function QJ(e){let{absolute:t,relative:n}=JJ(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(QJ,"plexusWorkspace");function oM(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(jh,i.path))throw new Error("plexus: unknown skill reference. Start with SKILL.md.");return{path:i.path,content:jh[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 QJ(i)},"executePlexusAgentTool")}s(oM,"createPlexusAgentToolExecutor");var Tm=oM({inspectCommand:aM,executeCommand:lM});function $m(){let e=new Uo({binaryLabel:"Plexus CLI",binaryName:"plexus-cli",binaryVersion:rM});e.register(ya.HelpCommand),e.register(ya.VersionCommand);for(let n of Em)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 e4(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($m,"createPlexusCli");function e4(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.
9774
+ `);return n.length>0?1:0}},zS=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 X0(e,t){if(e===t)throw new Error("Pass exactly one of --on or --off.");return e}s(X0,"requireOnOff");var eM=[$S,RS,IS,OS,PS,_S,NS,CS,DS,FS,LS,MS,wc,qS,KS,jS,BS,VS,US,GS,zS];function tM(e){return e.de??e.en??Object.values(e)[0]??""}s(tM,"titleDe");function HJ(e){return{id:e._id,kind:e.kind,status:e.status,title:tM(e.title).slice(0,50),assignee:e.assigneeUserId??"",group:e.queueGroupId??"",outcome:e.outcome??""}}s(HJ,"row");var YJ=["id","kind","status","title","assignee","group","outcome"],HS=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(HJ),YJ),0}},YS=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:tM(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}},JS=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}},QS=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}},ZS=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}},nM=[HS,YS,JS,QS,ZS];var Em=[...PT,...wR,...MI,...LI,...cO,...SO,...xO,...Q0,...eM,...d0,...rR,...sO,...z0,...IT,...n$,...eR,...TO,...EO,...IO,...OO,...iO,...UI,...nM,...dF,...HF,...a0,...YF,...C0,...B0,...c0,...b0,...x0,...G0,...J0,...HT];var rM="0.1.10";function iM(){return Em.flatMap(e=>(e.paths??[]).map(t=>{let n=t.join(" "),r=ET[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(iM,"plexusCommandCatalog");import Fo from"node:path";function JJ(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(JJ,"workspacePath");function QJ(e){let{absolute:t,relative:n}=JJ(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(QJ,"plexusWorkspace");function oM(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(jh,i.path))throw new Error("plexus: unknown skill reference. Start with SKILL.md.");return{path:i.path,content:jh[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 QJ(i)},"executePlexusAgentTool")}s(oM,"createPlexusAgentToolExecutor");var Tm=oM({inspectCommand:aM,executeCommand:lM});function $m(){let e=new Uo({binaryLabel:"Plexus CLI",binaryName:"plexus-cli",binaryVersion:rM});e.register(ya.HelpCommand),e.register(ya.VersionCommand);for(let n of Em)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 e4(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($m,"createPlexusCli");function e4(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.
9775
9775
  `)}s(e4,"noteRetiredPath");function aM(e){let t=$m().process(la(e),{executePlexusAgentTool:Tm}),n=t.path.join(" ");if(n.startsWith("agent "))throw new Error("plexus: nested agent transports are not allowed.");let r=iM().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(aM,"inspectPlexusCommand");async function lM(e,t){if(t)return tA(t,()=>lM(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=$m();if(st()){let l=aM(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:Tm,stdin:XJ.from(e.stdin===void 0?[]:[e.stdin]),stdout:new sM({write(l,d,c){n+=String(l),c()}}),stderr:new sM({write(l,d,c){r+=String(l),c()}})}),stdout:n,stderr:r}}s(lM,"executePlexusCommand");sA({source:t4.join(import.meta.dirname,"skill")});$m().runExit(la(process.argv.slice(2)),{executePlexusAgentTool:Tm});
9776
9776
  //# sourceMappingURL=cli.mjs.map
@@ -1 +1 @@
1
- 5a0fb71b57eb1ad6e95597654e221c5a712d0efc05ec1268c91ac66458ed1e0d
1
+ cb3c97259e64d88091913224a34bd4ff7df83cbc7a0ea8e88514b56a09dbf91d
@@ -20,8 +20,8 @@ change that takes the right away revokes the person's tokens.
20
20
  tenants on every deploy; nothing to grant. Someone outside `tenant_admin` needs a
21
21
  group holding them.
22
22
  - **Offer commands** need `bewerbungsmanagement.forms.configure` (in `tenant_admin`).
23
- A config change to groups or members also needs
24
- `administration.permissions.manage` / `.users.manage` (in `tenant_admin`).
23
+ A config change to groups needs `administration.permissions.manage`, to members
24
+ `.users.manage`, and one that changes a member's group both (all in `tenant_admin`).
25
25
  - **Your auth (issuing for them):** a platform token with `_platform.users.manage`
26
26
  **and** `_platform.apiTokens.manage` — the token acts as the person.
27
27
  - `--env` is required for the write; prod also needs `--allow-prod`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartkomm/plexus-cli",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Unified Plexus admin + admission-offer config CLI (Convex backend).",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",