@smartkomm/plexus-cli 0.1.9 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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
|
|
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
|
|
@@ -9599,7 +9599,7 @@ Der Link gilt {{gueltigkeit}} und funktioniert einmal. Danach werden Sie \xFCber
|
|
|
9599
9599
|
|
|
9600
9600
|
{{passwortLink}}
|
|
9601
9601
|
|
|
9602
|
-
The link is valid for {{gueltigkeit}} and works once. Afterwards you are signed out everywhere. Until then your current password keeps working \u2014 if you want nothing changed, ignore this email.`}}]},GU=b.object({}),zU={id:"account.emailChanged",category:"security",label:"Anmelde-Adresse ge\xE4ndert",occasion:{de:"Wenn jemand anderes als der Kontoinhaber die Anmelde-Adresse \xE4ndert \u2014 an die bisherige Adresse",en:"When someone other than the account holder changes the login address \u2014 to the previous address"},audience:"external",frame:"letter",timeline:"hidden",paramsValidator:GU,channels:["email"],lockedReason:{de:"Dieser Hinweis sch\xFCtzt Familien davor, dass jemand unbemerkt ihr Konto \xFCbernimmt. Sein Wortlaut ist deshalb fest.",en:"This notice protects families from someone taking over their account unnoticed, so its wording is fixed."},maxAttempts:4,portalVisible:!1},oy=[TV,_V,DV,FV,LV,KV,YV,QV,lU,cU,fU,hU,wU,kU,SU,TU,IU,PU,ZV,XV,eU,_U,NU,CU,jV,BV,UV,WV,oU,RV,OV,FU,MU,KU,BU,UU,zU];function sy(e){let t=oy.find(n=>n.id===e);return t===void 0&&_(`notifications: unknown letter "${e}"`),t}s(sy,"letterDefFor");function ay(e){return oy.some(t=>t.id===e)}s(ay,"hasLetterDef");var Ai=1024*1024,el=["application/pdf","image/jpeg","image/png","image/webp"];var af=["application/pdf","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/msword","application/vnd.oasis.opendocument.text","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","image/jpeg","image/png"],WR={docRef:{maxBytes:25*Ai,allowedMime:el},partyFile:{maxBytes:25*Ai,allowedMime:el},import:{maxBytes:500*Ai,allowedMime:null},signedContract:{maxBytes:25*Ai,allowedMime:el},artifactVersion:{maxBytes:25*Ai,allowedMime:el},chatAttachment:{maxBytes:25*Ai,allowedMime:el},tenantFile:{maxBytes:20*Ai,allowedMime:af},documentTemplate:{maxBytes:25*Ai,allowedMime:null}};var ly=/^[a-z0-9][a-z0-9-]*$/;function bs(e){return ly.test(e)}s(bs,"isFileKey");function uo(e){return e.trim()===""?"is empty":e==="."||e===".."?"is not a file name":/[/\\]/.test(e)?"must not contain a path separator":/[\u0000-\u001f]/.test(e)?"must not contain control characters":null}s(uo,"fileNameDefect");var HR=b.object({family:b.string()}),YR=b.object({family:b.string(),url:b.optional(b.string())}),yae=b.object({heading:b.optional(YR),body:b.optional(YR)}),WU=b.union(b.literal("sharp"),b.literal("rounded"),b.literal("soft")),HU=b.union(b.literal("light"),b.literal("dark")),YU=b.union(b.literal("sm"),b.literal("md"),b.literal("lg"),b.literal("max")),JU=b.union(b.literal("compact"),b.literal("normal"),b.literal("spacious")),QU=b.object({primary:b.optional(b.string()),accent:b.optional(b.string()),background:b.optional(b.string()),foreground:b.optional(b.string())}),ZU=b.object({heading:b.optional(HR),body:b.optional(HR)}),wae=b.object({colors:b.optional(QU),radius:b.optional(WU),logoSize:b.optional(YU),bannerDensity:b.optional(JU),logoGround:b.optional(HU),filledHeader:b.optional(b.boolean()),websiteUrl:b.optional(b.string()),fonts:b.optional(ZU)}),bae=b.object({primaryUrl:b.union(b.null(),b.string())}),kae=b.literal("primary"),vae=b.object({headingUrl:b.union(b.null(),b.string()),bodyUrl:b.union(b.null(),b.string())}),xae=b.union(b.literal("heading"),b.literal("body")),lf=["logo","fontHeading","fontBody"],JR={logo:null,fontHeading:"heading",fontBody:"body"};function QR(e){let{contentType:t,size:n}=e;return t==null||!t.startsWith("image/")?{de:`Das Logo muss ein Bild sein (erhalten: \u201E${t??"unbekannt"}\u201C).`,en:`The logo must be an image (received: "${t??"unknown"}").`}:t.startsWith("image/svg")?{de:"Das Logo muss eine Rastergrafik sein (PNG, JPEG oder GIF) \u2013 E-Mail-Programme zeigen SVG nicht an.",en:"The logo must be a raster image (PNG, JPEG or GIF) \u2013 email clients do not display SVG."}:n>3e6?{de:`Das Logo ist zu gro\xDF (${n} Byte, h\xF6chstens 3000000 Byte).`,en:`The logo is too large (${n} bytes, at most 3000000 bytes).`}:null}s(QR,"logoFileProblem");var dy="font/woff2";var XU=["Inter Variable","Azeret Mono Variable","Source Sans 3 Variable"];function ZR(e){return e?.trim()?XU.some(t=>t.toLowerCase()===e.trim().toLowerCase())?{de:`\u201E${e}\u201C ist die Schrift von Plexus selbst \u2013 w\xE4hlen Sie f\xFCr eine eigene Datei einen anderen Familiennamen.`,en:`"${e}" is Plexus's own typeface \u2013 choose a different family name for your own file.`}:null:{de:"Speichern Sie zuerst die Schriftfamilie \u2013 die Datei wird unter diesem Namen eingebunden.",en:"Save the font family first \u2013 the file is registered under that name."}}s(ZR,"fontFamilyProblem");var eG=["login","security","admission","tasks","schoolMessages","staffTasks","staffAppointments","staffDeadlines","familyMessages","mentions"],Oae=b.union(...eG.map(e=>b.literal(e)));var Pae=b.union(b.literal("admission"),b.literal("tasks"),b.literal("staff"),b.literal("chat")),cy=["loginOnly","all"],_ae=b.union(b.literal("loginOnly"),b.literal("all"));function XR(e){return typeof e=="string"&&cy.includes(e)}s(XR,"isMailLevel");var tG=["ad","ae","af","ag","ai","al","am","ao","aq","ar","as","at","au","aw","ax","az","ba","bb","bd","be","bf","bg","bh","bi","bj","bl","bm","bn","bo","bq","br","bs","bt","bv","bw","by","bz","ca","cc","cd","cf","cg","ch","ci","ck","cl","cm","cn","co","cr","cu","cv","cw","cx","cy","cz","de","dj","dk","dm","do","dz","ec","ee","eg","eh","er","es","et","fi","fj","fk","fm","fo","fr","ga","gb","gd","ge","gf","gg","gh","gi","gl","gm","gn","gp","gq","gr","gs","gt","gu","gw","gy","hk","hm","hn","hr","ht","hu","id","ie","il","im","in","io","iq","ir","is","it","je","jm","jo","jp","ke","kg","kh","ki","km","kn","kp","kr","kw","ky","kz","la","lb","lc","li","lk","lr","ls","lt","lu","lv","ly","ma","mc","md","me","mf","mg","mh","mk","ml","mm","mn","mo","mp","mq","mr","ms","mt","mu","mv","mw","mx","my","mz","na","nc","ne","nf","ng","ni","nl","no","np","nr","nu","nz","om","pa","pe","pf","pg","ph","pk","pl","pm","pn","pr","ps","pt","pw","py","qa","re","ro","rs","ru","rw","sa","sb","sc","sd","se","sg","sh","si","sj","sk","sl","sm","sn","so","sr","ss","st","sv","sx","sy","sz","tc","td","tf","tg","th","tj","tk","tl","tm","tn","to","tr","tt","tv","tw","tz","ua","ug","um","us","uy","uz","va","vc","ve","vg","vi","vn","vu","wf","ws","xk","ye","yt","za","zm","zw"],nG=new Set(tG);function df(e){return nG.has(e)}s(df,"isCountryCode");var uy=["off","always","deviating"],eI={mode:"deviating",defaultCountryCode:"de"};var rG=["street","plz","ort"];function iG(e){return rG.filter(t=>!e.has(t))}s(iG,"missingInvoiceAddressParts");var oG=new Set(["0-1-select","0-n-select"]);function tI(e){return e===void 0?null:new Set(e.properties.flatMap(t=>t.addressPart!==void 0&&b$(t.addressPart)?[t.addressPart]:[]))}s(tI,"declaredAddressParts");function sG(e){return oG.has(e)}s(sG,"isSelectFieldKind");function nI(e){let t=[];for(let o of e)if(o.isNationality&&(sG(o.kind)?o.listKind!=="country"&&t.push({code:"nationality/notCountryList",fieldKey:o.key}):t.push({code:"nationality/wrongFieldKind",fieldKey:o.key})),o.isAccountEmail&&o.kind!=="email"&&t.push({code:"accountEmail/wrongFieldKind",fieldKey:o.key}),o.isContactPhone&&o.kind!=="tel"&&t.push({code:"contactPhone/wrongFieldKind",fieldKey:o.key}),o.isInvoiceAddress)if(o.addressParts===null)t.push({code:"invoiceAddress/wrongFieldKind",fieldKey:o.key});else{let a=iG(o.addressParts);a.length>0&&t.push({code:"invoiceAddress/missingPart",fieldKey:o.key,parts:a})}let n=e.filter(o=>o.isAccountEmail);if(n.length>1)for(let o of n)t.push({code:"accountEmail/multiple",fieldKey:o.key});let r=e.filter(o=>o.isContactPhone);if(r.length>1)for(let o of r)t.push({code:"contactPhone/multiple",fieldKey:o.key});let i=e.filter(o=>o.isInvoiceAddress);if(i.length>1)for(let o of i)t.push({code:"invoiceAddress/multiple",fieldKey:o.key});return t}s(nI,"fieldRoleFindings");function rI(e,t,...n){let r=e[t.code];return r(t,...n)}s(rI,"wordListElementFinding");function iI(e,t){let n=[];for(let r of t){if(e.kind==="plain"){r.countryCode!==void 0&&n.push({code:"list/countryCodeOnPlain",elementKey:r.key,countryCode:r.countryCode});continue}r.countryCode===void 0?n.push({code:"list/countryCodeMissing",elementKey:r.key}):r.countryCode!==null&&!df(r.countryCode)&&n.push({code:"list/unknownCountryCode",elementKey:r.key,countryCode:r.countryCode})}return n}s(iI,"listElementCountryFindings");var lG={key:!0,tenant:!0,foundation:!0,source:!0,displayGroups:!0,lists:!0,roles:!0,fields:!0,roleFields:!0,contractRoleMappings:!0,templatePlaceholders:!0,searchTargets:!0,searchFilters:!0,partyResultIcons:!0,notificationLetters:!0,admission:!0,files:!0,agent:!0,deferredColumns:!0,ignoredColumns:!0},dG={slug:!0,name:!0,enabledModules:!0,permissions:!0,defaultApplicantGroupKey:!0,defaultEnrolleeRoleKey:!0,priceCriteriaFacts:!0,defaultInteressentRoleKey:!0,admissionFieldDisplayGroupKey:!0,defaultStartInProxy:!0,terms:!0,mailLevel:!0,notificationChrome:!0,hideMailLevelNotice:!0,magicLinkLogin:!0,externalSignIn:!0,nationalityFlag:!0,bankImportScope:!0,branding:!0,brandingAssets:!0,partyRetention:!0},cG=new Set(["enabledMailCategories","mailEnabled"]);function uG(e){let t=s((n,r,i)=>n.filter(o=>!Object.hasOwn(r,o)&&!(i==="tenant."&&cG.has(o))).map(o=>`[config/unknownKey] ${i}${o} is not a config field of this release \u2014 a typo, or a field a newer release introduced.`),"unknown");return[...t(Object.keys(e),lG,""),...t(Object.keys(e.tenant),dG,"tenant.")]}s(uG,"unknownKeyFindings");var oI=["plain","country"],fG={"list/countryCodeMissing":s(({elementKey:e},t)=>`Element "${t}.${e}" of a country list must state countryCode (null for no state).`,"list/countryCodeMissing"),"list/countryCodeOnPlain":s(({elementKey:e},t)=>`Element "${t}.${e}" carries countryCode, but list "${t}" is not kind "country".`,"list/countryCodeOnPlain"),"list/unknownCountryCode":s(({elementKey:e,countryCode:t},n)=>`Element "${n}.${e}" has unknown countryCode ${JSON.stringify(t)}.`,"list/unknownCountryCode")},pG={"nationality/wrongFieldKind":s(({fieldKey:e})=>`Field "${e}" is isNationality but not a 0-1-select / 0-n-select.`,"nationality/wrongFieldKind"),"nationality/notCountryList":s(({fieldKey:e})=>`Field "${e}" is isNationality but its list is not kind "country".`,"nationality/notCountryList"),"accountEmail/wrongFieldKind":s(({fieldKey:e})=>`Field "${e}" is isAccountEmail but not an email field.`,"accountEmail/wrongFieldKind"),"accountEmail/multiple":s(({fieldKey:e})=>`Field "${e}" is one of several isAccountEmail fields \u2014 at most one per tenant.`,"accountEmail/multiple"),"contactPhone/wrongFieldKind":s(({fieldKey:e})=>`Field "${e}" is isContactPhone but not a tel field.`,"contactPhone/wrongFieldKind"),"contactPhone/multiple":s(({fieldKey:e})=>`Field "${e}" is one of several isContactPhone fields \u2014 at most one per tenant.`,"contactPhone/multiple"),"invoiceAddress/wrongFieldKind":s(({fieldKey:e})=>`Field "${e}" is isInvoiceAddress but not an object field.`,"invoiceAddress/wrongFieldKind"),"invoiceAddress/missingPart":s(({fieldKey:e,parts:t})=>`Field "${e}" is isInvoiceAddress but declares no property for the address part(s) ${t.join(", ")} (objectSchema.properties[].addressPart) \u2014 an invoice cannot print its address without them.`,"invoiceAddress/missingPart"),"invoiceAddress/multiple":s(({fieldKey:e})=>`Field "${e}" is one of several isInvoiceAddress fields \u2014 at most one per tenant.`,"invoiceAddress/multiple")};function mG(e){let t=pG[e.code];return t(e)}s(mG,"roleText");function hG(e){let t=[],n=e.tenant.nationalityFlag,r=typeof n=="object"&&n!==null?n:{},i=r.mode;if(uy.includes(i)||t.push(`[nationality/flagMode] tenant.nationalityFlag.mode must be one of ${uy.join(", ")} (got ${n===void 0?"no tenant.nationalityFlag":JSON.stringify(i??null)}).`),n!==void 0){let l=r.defaultCountryCode;(typeof l!="string"||!df(l))&&t.push(`[nationality/defaultCountryCode] tenant.nationalityFlag.defaultCountryCode must be a lowercase ISO 3166-1 alpha-2 code (got ${JSON.stringify(l??null)}).`)}let o=new Map;for(let l of e.lists){let d=l.kind;if(!oI.includes(d)){t.push(`[list/kind] List "${l.key}" has kind ${JSON.stringify(d??null)} \u2014 one of ${oI.join(", ")}.`);continue}o.set(l.key,l.kind);for(let c of iI({key:l.key,kind:l.kind},l.elements))t.push(`[${c.code}] ${rI(fG,c,l.key)}`)}let a=nI(e.fields.map(l=>({key:l.key,kind:l.type,listKind:l.listKey===void 0?null:o.get(l.listKey)??null,isNationality:l.isNationality===!0,isAccountEmail:l.isAccountEmail===!0,isContactPhone:l.isContactPhone===!0,isInvoiceAddress:l.isInvoiceAddress===!0,addressParts:l.type==="object"?tI(l.objectSchema??{properties:[]}):null})));for(let l of a)t.push(`[${l.code}] ${mG(l)}`);return t}s(hG,"nationalityFindings");function sI(e){return di(e)?.message.de??(e instanceof Error?e.message:String(e))}s(sI,"errorText");function aI(e,t={}){let n=[...uG(e)],r=[];try{xR(e.fields.map(k=>k.key),[])}catch(k){n.push(sI(k))}e.tenant.terms!==void 0&&n.push(...NR(e.tenant.terms)),XR(e.tenant.mailLevel)?e.tenant.mailLevel==="all"&&!Gu(e.tenant.enabledModules,"notifications")&&n.push('[notification/levelWithoutModule] tenant.mailLevel is "all" but the notifications module is not enabled \u2014 only sign-in and security mail would go out. Enable the module or set "loginOnly".'):n.push(`[notification/mailLevel] tenant.mailLevel must be one of ${cy.join(", ")} (got ${e.tenant.mailLevel===void 0?"nothing":JSON.stringify(e.tenant.mailLevel)}).`),"enabledMailCategories"in e.tenant&&n.push('[notification/mailCategoriesRetired] tenant.enabledMailCategories was replaced by tenant.mailLevel \u2014 "all" for every mail, "loginOnly" for sign-in mail only to families (staff mail follows personal settings).'),"mailEnabled"in e.tenant&&n.push('[notification/mailEnabledRetired] tenant.mailEnabled was replaced by tenant.mailLevel \u2014 "all" for every mail, "loginOnly" for sign-in mail only to families (staff mail follows personal settings).'),St(e.displayGroups.map(k=>k.key),"display group",n),St(e.lists.map(k=>k.key),"list",n),St(e.roles.map(k=>k.key),"role",n),St(e.fields.map(k=>k.key),"field",n),St(e.foundation.legalEntities.map(k=>k.key),"legal entity",n),St(e.foundation.units.map(k=>k.key),"unit",n),St(e.foundation.permissionGroups.map(k=>k.key),"permission group",n),"teams"in e.foundation&&n.push("foundation.teams is retired: a team is a permission group \u2014 move each team to foundation.permissionGroups (same key) and remove the block.");for(let k of e.foundation.users)"teamKeys"in k&&n.push(`User "${k.email}" carries teamKeys, retired: team membership is the user's permission-group membership.`);St(e.foundation.users.map(k=>k.key),"user",n),St((e.searchFilters??[]).map(k=>k.key),"search filter",n),St((e.searchTargets??[]).map(k=>k.objectPropertyKey===void 0?k.fieldKey:`${k.fieldKey}.${k.objectPropertyKey}`),"search target",n),St((e.partyResultIcons??[]).map(k=>k.key),"party result icon",n),St((e.templatePlaceholders??[]).map(k=>k.key),"template placeholder",n),St((e.notificationLetters??[]).map(lI),"notification letter",n),SG(e.notificationLetters??[],n),AG(e.tenant.notificationChrome,n),e.tenant.bankImportScope!==void 0&&!["sepa_only","full_statement"].includes(e.tenant.bankImportScope)&&n.push("tenant.bankImportScope must be sepa_only or full_statement."),e.tenant.hideMailLevelNotice!==void 0&&typeof e.tenant.hideMailLevelNotice!="boolean"&&n.push("tenant.hideMailLevelNotice must be true or false (the dashboard's mail-level notice)."),typeof e.tenant.magicLinkLogin!="boolean"&&n.push("tenant.magicLinkLogin must be true or false (the login page's sign-in link option)."),bR(e.tenant.externalSignIn)||n.push(`[auth/externalSignIn] tenant.externalSignIn must be { mode: "permanentLink" }, { mode: "oneTimeLink" } or { mode: "periodLink", validDays: 1\u2013${Bg} } (how families sign in).`);let i=new Set(e.displayGroups.map(k=>k.key)),o=new Set(e.lists.map(k=>k.key)),a=new Set(e.roles.map(k=>k.key)),l=new Set(e.fields.map(k=>k.key)),d=new Map(e.fields.map(k=>[k.key,k])),c=new Set(e.foundation.legalEntities.map(k=>k.key)),u=new Set(e.foundation.units.map(k=>k.key)),f=new Set(e.foundation.permissionGroups.map(k=>k.key));Gu(e.tenant.enabledModules,"bewerbungsmanagement")&&e.tenant.defaultApplicantGroupKey!==void 0&&(e.foundation.permissionGroups.find(A=>A.key===e.tenant.defaultApplicantGroupKey)?.permissions.includes("bewerbungsmanagement.applications.submitOwn")||n.push(`Default applicant group "${e.tenant.defaultApplicantGroupKey}" must grant submitOwn.`));let m=e.tenant.admissionFieldDisplayGroupKey;m!==void 0&&!i.has(m)&&n.push(`tenant.admissionFieldDisplayGroupKey "${m}" names no display group of this config.`),m===void 0&&(Gu(e.tenant.enabledModules,"bewerbungsmanagement")||(e.admission?.fields.length??0)>0)&&n.push("tenant.admissionFieldDisplayGroupKey is required when admissions is enabled or admission.fields declares fields: it names the display group the fields an offer creates land in."),n.push(...hG(e)),St(e.fields.flatMap(k=>(k.relationshipKinds??[]).map(A=>A.key)),"relationship kind",n);for(let k of e.fields){i.has(k.displayGroupKey)||n.push(`Field "${k.key}" references missing display group "${k.displayGroupKey}".`),yG(k,n),k.formWritable===!0&&!Wg[k.type].fieldMapTarget&&n.push(`Field "${k.key}" is formWritable, but a form cannot write a "${k.type}" field.`),k.type==="auto-string"?wG(k,d,n):k.autoString!==void 0&&n.push(`Non-automatic field "${k.key}" must not define autoString.`),(!Number.isFinite(k.sortOrder)||k.sortOrder<0)&&n.push(`Field "${k.key}" has invalid sortOrder "${k.sortOrder}" (must be a non-negative number).`),(k.type==="0-1-select"||k.type==="0-n-select")&&!k.listKey&&n.push(`Select field "${k.key}" must define listKey.`),k.type!=="0-1-select"&&k.type!=="0-n-select"&&k.listKey!==void 0&&n.push(`Non-select field "${k.key}" must not define listKey.`),k.listKey&&!o.has(k.listKey)&&n.push(`Field "${k.key}" references missing list "${k.listKey}".`),(k.type==="object"||k.type==="relationship")&&!k.objectSchema&&n.push(`Field "${k.key}" must define objectSchema.`),k.type!=="object"&&k.type!=="relationship"&&k.objectSchema&&n.push(`Non-object field "${k.key}" must not define objectSchema.`);for(let A of k.objectSchema?.properties??[])(A.type==="0-1-select"||A.type==="0-n-select")&&!A.listKey&&n.push(`Object select property "${k.key}.${A.key}" must define listKey.`),A.listKey&&!o.has(A.listKey)&&n.push(`Object property "${k.key}.${A.key}" references missing list "${A.listKey}".`);gG(k,n)}let g=e.tenant.priceCriteriaFacts;if(g){let k=e.fields.find(A=>A.key===g.birthDateFieldKey);(!k||k.type!=="date")&&n.push("Price criteria require a configured date field for birth dates."),a.has(g.studentRoleKey)||n.push("Price criteria require a configured Student eligibility role.");for(let A of Object.keys(g))A!=="birthDateFieldKey"&&A!=="studentRoleKey"&&n.push(`Unknown price criteria fact setting "${A}".`)}let w=e.tenant.defaultEnrolleeRoleKey;w&&!a.has(w)&&n.push(`Default enrollment role "${w}" does not exist.`),w&&e.roles.some(k=>k.parentRoleKey===w)&&n.push(`Default enrollment role "${w}" must be a leaf role.`);for(let k of e.roles){(typeof k.icon!="string"||k.icon.trim().length===0)&&n.push(`Role "${k.key}" must define an icon.`),k.parentRoleKey&&!a.has(k.parentRoleKey)&&n.push(`Role "${k.key}" references missing parent role "${k.parentRoleKey}".`);for(let A of k.listDisplayFieldKeys??[])l.has(A)||n.push(`Role "${k.key}" list display references missing field "${A}".`)}let y=new Map(e.roles.map(k=>[k.key,k.parentRoleKey])),v=new Map;for(let k of e.roleFields){let A=v.get(k.roleKey)??[];A.push({roleId:k.roleKey,customFieldId:k.fieldKey}),v.set(k.roleKey,A)}for(let k of e.roles)try{kR(k.key,y,v)}catch(A){n.push(sI(A))}for(let k of e.roleFields){a.has(k.roleKey)||n.push(`Role field references missing role "${k.roleKey}" for field "${k.fieldKey}".`),l.has(k.fieldKey)||n.push(`Role field references missing field "${k.fieldKey}" for role "${k.roleKey}".`);for(let A of k.targetRequirementFieldKeys??[])l.has(A)||n.push(`Role field "${k.roleKey}.${k.fieldKey}" references missing target requirement field "${A}".`)}xG(e.contractRoleMappings??[],a,n);for(let k of e.templatePlaceholders??[])lR.test(k.key)||n.push(`Template placeholder "${k.key}" must use lower_snake_case segments, optionally separated by dots.`),k.source.kind==="customField"?cf(k.source,d,n,`Template placeholder "${k.key}"`):k.source.kind==="relationshipTargetField"&&bG(k,d,n);for(let k of e.searchTargets??[])cf(k,d,n,"Search target");for(let k of e.fields)OR(k.key)&&(k.defaultValue!==void 0||k.validations!==void 0)&&n.push(`System field "${k.key}" takes no defaultValue or validations.`);for(let k of e.lists)St(k.elements.map((A,q)=>String(A.sortOrder??(q+1)*10)),`sortOrder of an element of list "${k.key}"`,n);for(let k of e.searchFilters??[])St((k.options??[]).map((A,q)=>String(A.sortOrder??(q+1)*10)),`sortOrder of an option of search filter "${k.key}"`,n);for(let k of e.foundation.permissionGroups){k.grantAllCustomFields===!0&&k.customFieldPermissions!==void 0&&n.push(`Permission group "${k.key}" states both grantAllCustomFields and customFieldPermissions \u2014 one of them.`),St((k.customFieldPermissions??[]).map(A=>A.displayGroupKey),`display group of a field permission of group "${k.key}"`,n);for(let A of k.customFieldPermissions??[]){i.has(A.displayGroupKey)||n.push(`Permission group "${k.key}" grants field permissions on missing display group "${A.displayGroupKey}".`);for(let q of A.permissions)$R.includes(q)||n.push(`Permission group "${k.key}" grants unknown field permission "${q}".`)}}let T=e.tenant.partyRetention;T!==void 0&&(IR(T.days)||n.push(`tenant.partyRetention.days must be a whole number of days from 1 to ${36500} (got ${JSON.stringify(T.days)}).`),Number.isFinite(T.enabledAt)||n.push("tenant.partyRetention.enabledAt must be a timestamp (epoch ms)."),T.formerRoleKey!==void 0&&!a.has(T.formerRoleKey)&&n.push(`tenant.partyRetention references missing role "${T.formerRoleKey}".`));for(let k of e.searchFilters??[]){(k.kind==="chips"||k.kind==="select")&&(k.options?.length??0)===0&&n.push(`Search filter "${k.key}" must define options.`),(k.kind==="text"||k.kind==="numberRange")&&k.target===void 0&&n.push(`Search filter "${k.key}" must define a target field.`),k.options!==void 0&&St(k.options.map(A=>A.key),`search filter option for "${k.key}"`,n),cf(k.target,d,n,`Search filter "${k.key}"`);for(let A of k.options??[]){A.predicates.length===0&&n.push(`Search filter option "${k.key}.${A.key}" must define at least one predicate.`);for(let q of A.predicates){if(q.kind==="role"){a.has(q.roleKey)||n.push(`Search filter option "${k.key}.${A.key}" references missing role "${q.roleKey}".`);continue}cf(q,d,n,`Search filter option "${k.key}.${A.key}"`)}}}for(let k of e.partyResultIcons??[])kG(k,d,n);for(let k of e.foundation.legalEntities)if(k.signatoryUserKey!==void 0&&k.type==="school_group"&&n.push(`[config/signatoryOnGroup] Legal entity "${k.key}" is a school_group \u2014 only a Tr\xE4ger (school_operator, service_entity) declares an Unterschriftsperson.`),k.parentLegalEntityKey&&!c.has(k.parentLegalEntityKey)&&n.push(`Legal entity "${k.key}" references missing parent "${k.parentLegalEntityKey}".`),k.address!==void 0){let A=k.address,q=["street","hausnr","plz","ort"];k.type==="school_group"?n.push(`Legal entity "${k.key}" is a school_group \u2014 only a Tr\xE4ger (school_operator, service_entity) has an address.`):(typeof A!="object"||A===null||Array.isArray(A)||Object.keys(A).some(P=>!q.includes(P))||q.some(P=>typeof A[P]!="string"||(A[P]??"").trim()===""))&&n.push(`Legal entity "${k.key}" has an invalid address \u2014 expected { street, hausnr, plz, ort }, each non-empty.`)}let $=new Map;for(let k of e.foundation.units){if(k.slug!==void 0){let A=typeof k.slug=="string"?ER(k.slug):"must be a string";A!==void 0&&n.push(`Unit "${k.key}" has invalid slug "${k.slug}" (${A}).`);let q=$.get(k.slug);q!==void 0&&n.push(`Units "${q}" and "${k.key}" both declare slug "${k.slug}" (unit slugs are unique per tenant).`),$.set(k.slug,k.key)}c.has(k.legalEntityKey)||n.push(`Unit "${k.key}" references missing legal entity "${k.legalEntityKey}".`),k.parentUnitKey&&!u.has(k.parentUnitKey)&&n.push(`Unit "${k.key}" references missing parent unit "${k.parentUnitKey}".`),k.chargeReviewEnabled!==void 0&&typeof k.chargeReviewEnabled!="boolean"&&n.push(`Unit "${k.key}": chargeReviewEnabled must be true or false.`),k.sortOrder!==void 0&&(!Number.isFinite(k.sortOrder)||k.sortOrder<0)&&n.push(`Unit "${k.key}" has invalid sortOrder "${k.sortOrder}" (must be a non-negative number).`)}let O=/^[0-9a-f]{32}:[0-9a-f]{128}$/;for(let k of e.foundation.users){f.has(k.permissionGroupKey)||n.push(`User "${k.email}" references missing permission group "${k.permissionGroupKey}".`),k.unitKey&&!u.has(k.unitKey)&&n.push(`User "${k.email}" references missing unit "${k.unitKey}".`);let A=[k,...k.additionalMemberships??[]];for(let P of k.additionalMemberships??[])f.has(P.permissionGroupKey)||n.push(`User "${k.email}" references missing permission group "${P.permissionGroupKey}".`),P.unitKey&&!u.has(P.unitKey)&&n.push(`User "${k.email}" references missing unit "${P.unitKey}".`);St(A.map(P=>`${P.permissionGroupKey}/${P.unitKey??""}`),`membership (permission group/unit) of user "${k.email}"`,n);for(let P of A)P.validFrom!==void 0&&P.validTo!==void 0&&P.validTo<=P.validFrom&&n.push(`User "${k.email}": membership "${P.permissionGroupKey}" ends (validTo) before it starts (validFrom).`);let q=[k.firstName,k.lastName];q.some(P=>P!==void 0)&&q.some(P=>typeof P!="string"||P.trim()==="")&&n.push(`[config/userNameIncomplete] User "${k.email}" states only part of firstName/lastName (or an empty one) \u2014 set both or neither.`);for(let P of["staging","prod"]){let Y=k.passwordHashes?.[P];Y!==void 0&&!O.test(Y)&&n.push(`User "${k.email}" passwordHashes.${P} is not in Better Auth scrypt format "<32hex>:<128hex>".`)}}EG(e.tenant.branding,n),TG(e.tenant,n);let N=dI(e.fields.flatMap(k=>k.sourceColumns));for(let k of N)r.push(`Source column "${k}" is mapped by more than one field.`);IG(e,n);let L=t.sourceColumns===void 0||e.source===void 0?void 0:$G(e,t.sourceColumns,n);return{ok:n.length===0,errors:n,warnings:r,coverage:L}}s(aI,"validateTenantConfig");function gG(e,t){let n=new Map;for(let r of e.objectSchema?.properties??[]){let i=r.addressPart;if(i===void 0)continue;let o=`Object property "${e.key}.${r.key}"`;if(!ug.includes(i)){t.push(`${o}: addressPart "${i}" is none of ${ug.join(", ")}.`);continue}e.type!=="object"&&t.push(`${o}: only an object field stores an address (addressPart).`),r.type!=="string"&&t.push(`${o}: addressPart "${i}" needs a string property, not "${r.type}".`);let a=n.get(i);a!==void 0&&t.push(`${o}: addressPart "${i}" is already declared by "${e.key}.${a}".`),n.set(i,r.key)}}s(gG,"validateAddressParts");function yG(e,t){let n=e.relationshipKinds;if(n===void 0)return;if(e.type!=="relationship"){t.push(`Field "${e.key}" declares relationshipKinds, but only a relationship field carries them.`);return}let r=new Map((e.objectSchema?.properties??[]).map(i=>[i.key,i]));for(let i of n){let o=`Field "${e.key}" relationship kind "${i.key}"`;if(typeof i.key!="string"||i.key.trim()===""){t.push(`Field "${e.key}": a relationship kind needs a key.`);continue}for(let l of["de","en"])(i.label?.[l]??"").trim()===""&&t.push(`${o}: label.${l} is required \u2014 [i18n/missingTranslation] every shown text needs German and English.`);if(i.edge===null||typeof i.edge!="object"||Array.isArray(i.edge)){t.push(`${o}: edge must be an object.`);continue}i.sibling!==void 0&&i.sibling!==!0&&t.push(`${o}: sibling must be true or absent.`),i.sibling===!0&&i.mergeInto!==void 0&&t.push(`${o}: a sibling kind's edge is its identity \u2014 it cannot declare mergeInto.`);let a=n.flatMap(l=>l.mergeInto!==void 0?[l.mergeInto]:[]);if(i.sibling===!0&&a.some(l=>l in i.edge)&&t.push(`${o}: a sibling kind's edge is its identity \u2014 it cannot declare a property another kind of the field merges into.`),i.sibling===!0&&Object.keys(i.edge).length===0&&t.push(`${o}: a sibling kind's edge is its identity \u2014 an empty edge would count every edge of the field.`),i.mergeInto!==void 0){let l=r.get(i.mergeInto);l===void 0||l.type!=="0-n-select"?t.push(`${o}: mergeInto "${i.mergeInto}" must name a 0-n-select property of the field's objectSchema.`):Array.isArray(i.edge[i.mergeInto])||t.push(`${o}: mergeInto "${i.mergeInto}" must be set to a list in the edge.`)}}}s(yG,"validateRelationshipKinds");function wG(e,t,n){if(e.autoString===void 0){n.push(`Automatic field "${e.key}" must define autoString.`);return}e.allowMultiple===!0&&n.push(`Automatic field "${e.key}" must not allow multiple values.`),e.shareable===!0&&n.push(`Automatic field "${e.key}" must not be shareable.`),e.autoString.segments.length===0&&n.push(`Automatic field "${e.key}" must define at least one segment.`),e.autoString.segments.filter(i=>i.kind==="sequence").length!==1&&n.push(`Automatic field "${e.key}" must define exactly one sequence segment.`);for(let i of e.autoString.segments)if(i.kind==="literal"&&i.value.length===0&&n.push(`Automatic field "${e.key}" has an empty literal segment.`),i.kind==="sequence"&&(i.startAt!==void 0&&(!Number.isInteger(i.startAt)||i.startAt<1)&&n.push(`Automatic field "${e.key}" sequence startAt must be an integer >= 1.`),i.minDigits!==void 0&&(!Number.isInteger(i.minDigits)||i.minDigits<0)&&n.push(`Automatic field "${e.key}" sequence minDigits must be an integer >= 0.`)),i.kind==="field"){let o=t.get(i.fieldKey);if(o===void 0){n.push(`Automatic field "${e.key}" references missing field "${i.fieldKey}".`);continue}i.objectPropertyKey!==void 0&&o.objectSchema?.properties.find(l=>l.key===i.objectPropertyKey)===void 0&&n.push(`Automatic field "${e.key}" references missing object property "${i.fieldKey}.${i.objectPropertyKey}".`)}}s(wG,"validateAutomaticStringField");function cf(e,t,n,r){if(e===void 0)return;let i=t.get(e.fieldKey);if(i===void 0){n.push(`${r} references missing field "${e.fieldKey}".`);return}if(e.objectPropertyKey===void 0)return;(i.objectSchema?.properties.some(a=>a.key===e.objectPropertyKey)??!1)||n.push(`${r} references missing object property "${e.fieldKey}.${e.objectPropertyKey}".`)}s(cf,"validateSearchTarget");function bG(e,t,n){if(e.source.kind!=="relationshipTargetField")return;let r=`Template placeholder "${e.key}"`,i=t.get(e.source.relationshipFieldKey);if(i===void 0)n.push(`${r} references missing relationship field "${e.source.relationshipFieldKey}".`);else if(i.type!=="relationship")n.push(`${r} relationship field "${e.source.relationshipFieldKey}" must be a relationship field.`);else{for(let a of e.source.edgeFilters??[])fy(i,a.propertyKey,n,`${r} edge filter`);e.source.selection?.sortPropertyKey!==void 0&&fy(i,e.source.selection.sortPropertyKey,n,`${r} selection sort`)}let o=t.get(e.source.targetFieldKey);if(o===void 0){n.push(`${r} references missing target field "${e.source.targetFieldKey}".`);return}o.type==="relationship"&&n.push(`${r} target field "${e.source.targetFieldKey}" must not be a relationship field.`),e.source.targetObjectPropertyKey!==void 0&&fy(o,e.source.targetObjectPropertyKey,n,`${r} target`)}s(bG,"validateRelationshipTemplatePlaceholder");function fy(e,t,n,r){(e.objectSchema?.properties.some(o=>o.key===t)??!1)||n.push(`${r} references missing object property "${e.key}.${t}".`)}s(fy,"validateObjectPropertyReference");function kG(e,t,n){let r=`Party result icon "${e.key}"`,i=t.get(e.when.fieldKey);if(i===void 0){n.push(`${r} references missing field "${e.when.fieldKey}".`);return}if(e.when.objectPropertyKey===void 0){i.type!=="boolean"&&n.push(`${r} must target a Boolean field or object property.`);return}let o=i.objectSchema?.properties.find(a=>a.key===e.when.objectPropertyKey);if(o===void 0){n.push(`${r} references missing object property "${e.when.fieldKey}.${e.when.objectPropertyKey}".`);return}o.type!=="boolean"&&n.push(`${r} must target a Boolean field or object property.`)}s(kG,"validatePartyResultIconTarget");function lI(e){return`${e.templateId}:${e.locale}:${e.scopeKey}`}s(lI,"letterIdentity");function vG(e){return`${e.generatorKey??"*"}/${e.partyKind}/${e.roleKey}`}s(vG,"contractRoleMappingIdentity");function xG(e,t,n){let r=new Set;for(let i of e){let o=vG(i),a=`Contract role mapping "${o}"`;Vg.includes(i.partyKind)||n.push(`${a}: partyKind must be one of ${Vg.join(", ")}.`),t.has(i.roleKey)||n.push(`${a} references missing role "${i.roleKey}".`),i.generatorKey!==void 0&&i.generatorKey.trim()===""&&n.push(`${a}: generatorKey must not be blank \u2014 omit it for the tenant default.`),r.has(o)&&n.push(`${a} is declared twice.`),r.add(o)}}s(xG,"validateContractRoleMappings");function SG(e,t){for(let n of e){let r=`Notification letter "${lI(n)}"`;if(!Qu(n.locale)){t.push(`${r} declares locale "${String(n.locale)}" \u2014 letters are written in ${Je.map(i=>`"${i}"`).join(" and ")} only, so no mail would ever read this deviation.`);continue}if(n.scopeKey!==zu){t.push(`${r} declares scopeKey "${n.scopeKey}" \u2014 the only scope is "${zu}" (the whole school).`);continue}if(Object.keys(n.slots).length===0){t.push(`${r} overrides no block. A deviation that deviates in nothing is not an entry \u2014 remove it.`);continue}if(!ay(n.templateId)){t.push(`${r} references no registered letter \u2014 "${n.templateId}" is not in the letter catalog.`);continue}for(let i of FR(sy(n.templateId),n.slots,n.locale))t.push(`${r}, block "${i.slotKey}" [${i.code}]: ${i.message.de}`)}}s(SG,"validateNotificationLetters");function AG(e,t){if(e!==void 0)for(let n of LR(e))t.push(`Notification chrome: ${n.de}`)}s(AG,"validateNotificationChrome");function EG(e,t){if(e===void 0)return;let n=/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,r=/^(?:rgb|rgba|hsl|hsla)\(.+\)$/i,i=s(c=>n.test(c.trim())||r.test(c.trim()),"isColor");for(let[c,u]of Object.entries(e.colors??{}))u!==void 0&&(i(u)||t.push(`Branding color "colors.${c}" has invalid value "${u}" (expected hex "#rgb"/"#rrggbb"/"#rrggbbaa" or rgb()/rgba()/hsl()/hsla()).`));let o=["sharp","rounded","soft"];e.radius!==void 0&&!o.includes(e.radius)&&t.push(`Branding radius "${e.radius}" is invalid (expected "sharp", "rounded", or "soft").`);let a=["sm","md","lg","max"];e.logoSize!==void 0&&!a.includes(e.logoSize)&&t.push(`Branding logoSize "${e.logoSize}" is invalid (expected "sm", "md", "lg", or "max").`);let l=["compact","normal","spacious"];e.bannerDensity!==void 0&&!l.includes(e.bannerDensity)&&t.push(`Branding bannerDensity "${e.bannerDensity}" is invalid (expected "compact", "normal", or "spacious").`);let d=["light","dark"];e.logoGround!==void 0&&!d.includes(e.logoGround)&&t.push(`Branding logoGround "${e.logoGround}" is invalid (expected "light" or "dark").`),e.websiteUrl!==void 0&&!e.websiteUrl.startsWith("https://")&&t.push(`Branding websiteUrl must be an https:// URL (got "${e.websiteUrl}").`);for(let c of["heading","body"]){let u=e.fonts?.[c];u!==void 0&&((typeof u.family!="string"||u.family.trim().length===0)&&t.push(`Branding font "fonts.${c}" must define a non-empty family.`),Object.hasOwn(u,"url")&&t.push(`Branding font "fonts.${c}.url" is no longer supported \u2014 the font file is uploaded (plexus-cli branding set-font --slot ${c} --file <woff2>) and config carries the family only.`))}}s(EG,"validateBranding");function TG(e,t){let n=e.brandingAssets;if(n!==void 0){if(typeof n!="object"||n===null||Array.isArray(n)){t.push(`tenant.brandingAssets must be an object keyed by slot (${lf.join(", ")}).`);return}for(let[r,i]of Object.entries(n)){let o=`tenant.brandingAssets.${r}`;if(!lf.includes(r)){t.push(`${o}: unknown slot (expected ${lf.join(", ")}).`);continue}if(typeof i!="object"||i===null){t.push(`${o}: must be { sha256, sizeBytes, mimeType }.`);continue}if("size"in i){t.push(`[config/fileRefRenamed] ${o} still names size \u2014 this bundle was exported before the file-field rename, or by a plexus-cli older than this release (now sizeBytes). Update plexus-cli, export it again (plexus-cli --env <env> config export) and re-apply.`);continue}cI.test(i.sha256??"")||t.push(`${o}: sha256 must be 64 lowercase hex chars.`),(!Number.isInteger(i.sizeBytes)||i.sizeBytes<=0)&&t.push(`${o}: sizeBytes must be a positive integer.`);let a=JR[r];if(a===null){let l=QR({contentType:i.mimeType,size:i.sizeBytes});l!==null&&t.push(`${o}: ${l.de}`)}else{i.mimeType!==dy&&t.push(`${o}: mimeType must be "${dy}" (got "${i.mimeType}").`);let l=ZR(e.branding?.fonts?.[a]?.family);l!==null&&t.push(`${o}: [branding/fontFamilyMissing] tenant.branding.fonts.${a}: ${l.de}`)}"path"in i&&t.push(`${o}: "path" is a CLI snapshot field \u2014 resolve it with plexus-cli config apply.`)}}}s(TG,"validateBrandingAssets");function $G(e,t,n){let{source:r}=e;r===void 0&&_("validateSourceCoverage: called without a `source` block.");let i=new Set(t),o=new Set(e.fields.flatMap(w=>w.sourceColumns)),a=new Set(e.deferredColumns.map(w=>w.column)),l=new Set(e.ignoredColumns.map(w=>w.column)),d=new Set([...o,...a,...l]),c=r.requiredColumns.filter(w=>!i.has(w)),u=t.filter(w=>!d.has(w)),f=[...o].filter(w=>!i.has(w)),m=[...a].filter(w=>!i.has(w)),g=[...l].filter(w=>!i.has(w));for(let w of c)n.push(`Required source column "${w}" is missing from ${r.primaryTable}.`);for(let w of u)n.push(`Source column "${w}" is neither mapped nor explicitly deferred/ignored.`);for(let w of f)n.push(`Mapped source column "${w}" does not exist in the source schema.`);for(let w of m)n.push(`Deferred source column "${w}" does not exist in the source schema.`);for(let w of g)n.push(`Ignored source column "${w}" does not exist in the source schema.`);return{table:r.primaryTable,availableColumns:t.length,mappedColumns:[...o].filter(w=>i.has(w)).length,deferredColumns:[...a].filter(w=>i.has(w)).length,ignoredColumns:[...l].filter(w=>i.has(w)).length,missingRequiredColumns:c,unmappedColumns:u,unknownMappedColumns:f,unknownDeferredColumns:m,unknownIgnoredColumns:g}}s($G,"validateSourceCoverage");function St(e,t,n){for(let r of dI(e))n.push(`Duplicate ${t} key "${r}".`)}s(St,"requireUnique");function dI(e){let t=new Set,n=new Set;for(let r of e)t.has(r)&&n.add(r),t.add(r);return[...n]}s(dI,"duplicates");var cI=/^[0-9a-f]{64}$/,RG=["fileName","size"];function IG(e,t){if(!Array.isArray(e.files)){t.push('"files" is missing \u2014 declare the file library (an empty list is fine).');return}St(e.files.map(n=>n.key),"file",t);for(let n of e.files){let r=`files["${n.key}"]`;bs(n.key)||t.push(`${r}: key must match ${ly}.`);for(let o of["de","en"])(n.label?.[o]??"").trim()===""&&t.push(`${r}: label.${o} is required \u2014 [i18n/missingTranslation] every shown text needs German and English.`);let i=RG.filter(o=>o in n);if(i.length>0){t.push(`[config/fileRefRenamed] ${r} still names ${i.join(", ")} \u2014 this bundle was exported before the file-field rename, or by a plexus-cli older than this release (now filename / sizeBytes). Update plexus-cli, export it again (plexus-cli --env <env> config export) and re-apply.`);continue}if(typeof n.filename!="string")t.push(`${r}: filename is missing.`);else{let o=uo(n.filename);o!==null&&t.push(`${r}: filename ${o}.`)}af.includes(n.mimeType)||t.push(`${r}: mimeType "${n.mimeType}" is not allowed (${af.join(", ")}).`),cI.test(n.sha256??"")||t.push(`${r}: sha256 must be 64 lowercase hex chars.`),(!Number.isInteger(n.sizeBytes)||n.sizeBytes<=0)&&t.push(`${r}: sizeBytes must be a positive integer.`),"path"in n&&t.push(`${r}: "path" is a CLI snapshot field \u2014 resolve it with plexus-cli config apply.`)}}s(IG,"validateFiles");var OG=new WeakMap,PG=new WeakSet;function py(e,t){t(e);let r=e.asOptional.bind(e);return Object.defineProperty(e,"asOptional",{value:s(()=>py(r(),t),"value"),enumerable:!1}),e}s(py,"carry");function ks(e,t){return py(e,n=>OG.set(n,t))}s(ks,"tagged");var _G="tenant teardown drains every table explicitly (config/wipe.ts)",qt={belongsTo:s(e=>ks(e,{kind:"belongsTo"}),"belongsTo"),owns:s(e=>ks(e,{kind:"owns"}),"owns"),holds:s(e=>ks(e,{kind:"holds"}),"holds"),restrict:s((e,t)=>ks(e,t?{kind:"restrict",unindexed:t.unindexed}:{kind:"restrict"}),"restrict"),history:s(e=>ks(e,{kind:"history"}),"history"),tenant:s(e=>ks(e,{kind:"restrict",unindexed:_G}),"tenant"),historyOf:s(e=>py(e,t=>PG.add(t)),"historyOf")};var NG=b.object({street:b.string(),hausnr:b.string(),plz:b.string(),ort:b.string()}),uI=b.union(b.literal("school_operator"),b.literal("school_group"),b.literal("service_entity")),vr=uI.members.map(e=>e.value),CG={tenantId:qt.tenant(b.id("tenants")),name:b.optional(b.string()),type:uI,parentLegalEntityId:b.optional(qt.restrict(b.id("legal_entities"))),configKey:b.optional(b.string()),partyId:b.optional(qt.restrict(b.id("parties"))),address:b.optional(NG),signatoryUserId:b.optional(qt.restrict(b.id("users")))},Tle=Mr(CG).index("by_tenantId",["tenantId"]).index("by_parentLegalEntityId",["parentLegalEntityId"]).index("by_tenantId_and_configKey",["tenantId","configKey"]).index("by_partyId",["partyId"]).index("by_signatoryUserId",["signatoryUserId"]);var DG=b.union(b.literal("school"),b.literal("kindergarten"),b.literal("after_school_care"),b.literal("department"),b.literal("site"),b.literal("other")),In=DG.members.map(e=>e.value),Ile=b.union(b.literal("school"),b.literal("vocational"),b.literal("care"),b.literal("seminar"),b.literal("other")),Ole=b.union(b.literal("none"),b.literal("manual"),b.literal("annual_rollover")),Ple=b.union(b.literal("grade_level"),b.literal("module"),b.literal("phase"),b.literal("other")),_le=b.union(b.literal("school_year"),b.literal("cohort"),b.literal("seminar"),b.literal("care_period"),b.literal("other")),Nle=b.union(b.literal("planned"),b.literal("active"),b.literal("completed"),b.literal("archived")),Cle=b.union(b.literal("class"),b.literal("course"),b.literal("care_group"),b.literal("seminar_group"),b.literal("mixed_age_group"),b.literal("other")),Dle=b.union(b.literal("planned"),b.literal("active"),b.literal("completed"),b.literal("withdrawn"),b.literal("candidate")),Fle=b.union(b.literal("planned"),b.literal("active"),b.literal("completed"),b.literal("cancelled")),Lle=b.union(b.literal("class_teacher"),b.literal("teacher"),b.literal("mentor"),b.literal("instructor"),b.literal("assistant"),b.literal("other")),Mle=b.union(b.literal("units"),b.literal("unit_profiles"),b.literal("programs"),b.literal("program_stages"),b.literal("program_runs"),b.literal("learning_groups"),b.literal("enrollments"),b.literal("learning_group_staff_assignments")),qle=b.union(b.literal("open"),b.literal("mapped"),b.literal("ignored"));function pI(e){let t=["street","hausnr","plz","ort"].filter(n=>e[n]!==void 0);if(t.length!==0){if(t.length!==4)throw new Error(`config legal-entity add: an address needs all of --street, --hausnr, --plz and --ort (got ${t.map(n=>`--${n}`).join(", ")})`);return{street:e.street,hausnr:e.hausnr,plz:e.plz,ort:e.ort}}}s(pI,"addressFrom");function mI(e){if(!vr.includes(e))throw new Error(`config legal-entity add: --type "${e}" is none of ${vr.join(", ")}`);return e}s(mI,"legalEntityType");function hI(e){if(!In.includes(e))throw new Error(`config unit add: --kind "${e}" is none of ${In.join(", ")}`);return e}s(hI,"unitKind");function gI(e,t,n){let r=e.find(i=>i.key===t.key);if(r===void 0)return e.push(t),"create";if(Pe(r)===Pe(t))return"same";throw new Error(`${n} "${t.key}" already exists with other values \u2014 decide by hand, nothing written.
|
|
9602
|
+
The link is valid for {{gueltigkeit}} and works once. Afterwards you are signed out everywhere. Until then your current password keeps working \u2014 if you want nothing changed, ignore this email.`}}]},GU=b.object({}),zU={id:"account.emailChanged",category:"security",label:"Anmelde-Adresse ge\xE4ndert",occasion:{de:"Wenn jemand anderes als der Kontoinhaber die Anmelde-Adresse \xE4ndert \u2014 an die bisherige Adresse",en:"When someone other than the account holder changes the login address \u2014 to the previous address"},audience:"external",frame:"letter",timeline:"hidden",paramsValidator:GU,channels:["email"],lockedReason:{de:"Dieser Hinweis sch\xFCtzt Familien davor, dass jemand unbemerkt ihr Konto \xFCbernimmt. Sein Wortlaut ist deshalb fest.",en:"This notice protects families from someone taking over their account unnoticed, so its wording is fixed."},maxAttempts:4,portalVisible:!1},oy=[TV,_V,DV,FV,LV,KV,YV,QV,lU,cU,fU,hU,wU,kU,SU,TU,IU,PU,ZV,XV,eU,_U,NU,CU,jV,BV,UV,WV,oU,RV,OV,FU,MU,KU,BU,UU,zU];function sy(e){let t=oy.find(n=>n.id===e);return t===void 0&&_(`notifications: unknown letter "${e}"`),t}s(sy,"letterDefFor");function ay(e){return oy.some(t=>t.id===e)}s(ay,"hasLetterDef");var Ai=1024*1024,el=["application/pdf","image/jpeg","image/png","image/webp"];var af=["application/pdf","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/msword","application/vnd.oasis.opendocument.text","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","image/jpeg","image/png"],WR={docRef:{maxBytes:25*Ai,allowedMime:el},partyFile:{maxBytes:25*Ai,allowedMime:el},import:{maxBytes:500*Ai,allowedMime:null},signedContract:{maxBytes:25*Ai,allowedMime:el},artifactVersion:{maxBytes:25*Ai,allowedMime:el},chatAttachment:{maxBytes:25*Ai,allowedMime:el},tenantFile:{maxBytes:20*Ai,allowedMime:af},documentTemplate:{maxBytes:25*Ai,allowedMime:null}};var ly=/^[a-z0-9][a-z0-9-]*$/;function bs(e){return ly.test(e)}s(bs,"isFileKey");function uo(e){return e.trim()===""?"is empty":e==="."||e===".."?"is not a file name":/[/\\]/.test(e)?"must not contain a path separator":/[\u0000-\u001f]/.test(e)?"must not contain control characters":null}s(uo,"fileNameDefect");var HR=b.object({family:b.string()}),YR=b.object({family:b.string(),url:b.optional(b.string())}),yae=b.object({heading:b.optional(YR),body:b.optional(YR)}),WU=b.union(b.literal("sharp"),b.literal("rounded"),b.literal("soft")),HU=b.union(b.literal("light"),b.literal("dark")),YU=b.union(b.literal("sm"),b.literal("md"),b.literal("lg"),b.literal("max")),JU=b.union(b.literal("compact"),b.literal("normal"),b.literal("spacious")),QU=b.object({primary:b.optional(b.string()),accent:b.optional(b.string()),background:b.optional(b.string()),foreground:b.optional(b.string())}),ZU=b.object({heading:b.optional(HR),body:b.optional(HR)}),wae=b.object({colors:b.optional(QU),radius:b.optional(WU),logoSize:b.optional(YU),bannerDensity:b.optional(JU),logoGround:b.optional(HU),filledHeader:b.optional(b.boolean()),websiteUrl:b.optional(b.string()),fonts:b.optional(ZU)}),bae=b.object({primaryUrl:b.union(b.null(),b.string())}),kae=b.literal("primary"),vae=b.object({headingUrl:b.union(b.null(),b.string()),bodyUrl:b.union(b.null(),b.string())}),xae=b.union(b.literal("heading"),b.literal("body")),lf=["logo","fontHeading","fontBody"],JR={logo:null,fontHeading:"heading",fontBody:"body"};function QR(e){let{contentType:t,size:n}=e;return t==null||!t.startsWith("image/")?{de:`Das Logo muss ein Bild sein (erhalten: \u201E${t??"unbekannt"}\u201C).`,en:`The logo must be an image (received: "${t??"unknown"}").`}:t.startsWith("image/svg")?{de:"Das Logo muss eine Rastergrafik sein (PNG, JPEG oder GIF) \u2013 E-Mail-Programme zeigen SVG nicht an.",en:"The logo must be a raster image (PNG, JPEG or GIF) \u2013 email clients do not display SVG."}:n>3e6?{de:`Das Logo ist zu gro\xDF (${n} Byte, h\xF6chstens 3000000 Byte).`,en:`The logo is too large (${n} bytes, at most 3000000 bytes).`}:null}s(QR,"logoFileProblem");var dy="font/woff2";var XU=["Inter Variable","Azeret Mono Variable","Source Sans 3 Variable"];function ZR(e){return e?.trim()?XU.some(t=>t.toLowerCase()===e.trim().toLowerCase())?{de:`\u201E${e}\u201C ist die Schrift von Plexus selbst \u2013 w\xE4hlen Sie f\xFCr eine eigene Datei einen anderen Familiennamen.`,en:`"${e}" is Plexus's own typeface \u2013 choose a different family name for your own file.`}:null:{de:"Speichern Sie zuerst die Schriftfamilie \u2013 die Datei wird unter diesem Namen eingebunden.",en:"Save the font family first \u2013 the file is registered under that name."}}s(ZR,"fontFamilyProblem");var eG=["login","security","admission","tasks","schoolMessages","staffTasks","staffAppointments","staffDeadlines","familyMessages","mentions"],Oae=b.union(...eG.map(e=>b.literal(e)));var Pae=b.union(b.literal("admission"),b.literal("tasks"),b.literal("staff"),b.literal("chat")),cy=["loginOnly","all"],_ae=b.union(b.literal("loginOnly"),b.literal("all"));function XR(e){return typeof e=="string"&&cy.includes(e)}s(XR,"isMailLevel");var tG=["ad","ae","af","ag","ai","al","am","ao","aq","ar","as","at","au","aw","ax","az","ba","bb","bd","be","bf","bg","bh","bi","bj","bl","bm","bn","bo","bq","br","bs","bt","bv","bw","by","bz","ca","cc","cd","cf","cg","ch","ci","ck","cl","cm","cn","co","cr","cu","cv","cw","cx","cy","cz","de","dj","dk","dm","do","dz","ec","ee","eg","eh","er","es","et","fi","fj","fk","fm","fo","fr","ga","gb","gd","ge","gf","gg","gh","gi","gl","gm","gn","gp","gq","gr","gs","gt","gu","gw","gy","hk","hm","hn","hr","ht","hu","id","ie","il","im","in","io","iq","ir","is","it","je","jm","jo","jp","ke","kg","kh","ki","km","kn","kp","kr","kw","ky","kz","la","lb","lc","li","lk","lr","ls","lt","lu","lv","ly","ma","mc","md","me","mf","mg","mh","mk","ml","mm","mn","mo","mp","mq","mr","ms","mt","mu","mv","mw","mx","my","mz","na","nc","ne","nf","ng","ni","nl","no","np","nr","nu","nz","om","pa","pe","pf","pg","ph","pk","pl","pm","pn","pr","ps","pt","pw","py","qa","re","ro","rs","ru","rw","sa","sb","sc","sd","se","sg","sh","si","sj","sk","sl","sm","sn","so","sr","ss","st","sv","sx","sy","sz","tc","td","tf","tg","th","tj","tk","tl","tm","tn","to","tr","tt","tv","tw","tz","ua","ug","um","us","uy","uz","va","vc","ve","vg","vi","vn","vu","wf","ws","xk","ye","yt","za","zm","zw"],nG=new Set(tG);function df(e){return nG.has(e)}s(df,"isCountryCode");var uy=["off","always","deviating"],eI={mode:"deviating",defaultCountryCode:"de"};var rG=["street","plz","ort"];function iG(e){return rG.filter(t=>!e.has(t))}s(iG,"missingInvoiceAddressParts");var oG=new Set(["0-1-select","0-n-select"]);function tI(e){return e===void 0?null:new Set(e.properties.flatMap(t=>t.addressPart!==void 0&&b$(t.addressPart)?[t.addressPart]:[]))}s(tI,"declaredAddressParts");function sG(e){return oG.has(e)}s(sG,"isSelectFieldKind");function nI(e){let t=[];for(let o of e)if(o.isNationality&&(sG(o.kind)?o.listKind!=="country"&&t.push({code:"nationality/notCountryList",fieldKey:o.key}):t.push({code:"nationality/wrongFieldKind",fieldKey:o.key})),o.isAccountEmail&&o.kind!=="email"&&t.push({code:"accountEmail/wrongFieldKind",fieldKey:o.key}),o.isContactPhone&&o.kind!=="tel"&&t.push({code:"contactPhone/wrongFieldKind",fieldKey:o.key}),o.isInvoiceAddress)if(o.addressParts===null)t.push({code:"invoiceAddress/wrongFieldKind",fieldKey:o.key});else{let a=iG(o.addressParts);a.length>0&&t.push({code:"invoiceAddress/missingPart",fieldKey:o.key,parts:a})}let n=e.filter(o=>o.isAccountEmail);if(n.length>1)for(let o of n)t.push({code:"accountEmail/multiple",fieldKey:o.key});let r=e.filter(o=>o.isContactPhone);if(r.length>1)for(let o of r)t.push({code:"contactPhone/multiple",fieldKey:o.key});let i=e.filter(o=>o.isInvoiceAddress);if(i.length>1)for(let o of i)t.push({code:"invoiceAddress/multiple",fieldKey:o.key});return t}s(nI,"fieldRoleFindings");function rI(e,t,...n){let r=e[t.code];return r(t,...n)}s(rI,"wordListElementFinding");function iI(e,t){let n=[];for(let r of t){if(e.kind==="plain"){r.countryCode!==void 0&&n.push({code:"list/countryCodeOnPlain",elementKey:r.key,countryCode:r.countryCode});continue}r.countryCode===void 0?n.push({code:"list/countryCodeMissing",elementKey:r.key}):r.countryCode!==null&&!df(r.countryCode)&&n.push({code:"list/unknownCountryCode",elementKey:r.key,countryCode:r.countryCode})}return n}s(iI,"listElementCountryFindings");var lG={key:!0,tenant:!0,foundation:!0,source:!0,displayGroups:!0,lists:!0,roles:!0,fields:!0,roleFields:!0,contractRoleMappings:!0,templatePlaceholders:!0,searchTargets:!0,searchFilters:!0,partyResultIcons:!0,notificationLetters:!0,admission:!0,files:!0,agent:!0,deferredColumns:!0,ignoredColumns:!0},dG={slug:!0,name:!0,enabledModules:!0,permissions:!0,defaultApplicantGroupKey:!0,defaultEnrolleeRoleKey:!0,priceCriteriaFacts:!0,defaultInteressentRoleKey:!0,admissionFieldDisplayGroupKey:!0,defaultStartInProxy:!0,terms:!0,mailLevel:!0,notificationChrome:!0,hideMailLevelNotice:!0,magicLinkLogin:!0,externalSignIn:!0,nationalityFlag:!0,bankImportScope:!0,branding:!0,brandingAssets:!0,partyRetention:!0},cG=new Set(["enabledMailCategories","mailEnabled"]);function uG(e){let t=s((n,r,i)=>n.filter(o=>!Object.hasOwn(r,o)&&!(i==="tenant."&&cG.has(o))).map(o=>`[config/unknownKey] ${i}${o} is not a config field of this release \u2014 a typo, or a field a newer release introduced.`),"unknown");return[...t(Object.keys(e),lG,""),...t(Object.keys(e.tenant),dG,"tenant.")]}s(uG,"unknownKeyFindings");var oI=["plain","country"],fG={"list/countryCodeMissing":s(({elementKey:e},t)=>`Element "${t}.${e}" of a country list must state countryCode (null for no state).`,"list/countryCodeMissing"),"list/countryCodeOnPlain":s(({elementKey:e},t)=>`Element "${t}.${e}" carries countryCode, but list "${t}" is not kind "country".`,"list/countryCodeOnPlain"),"list/unknownCountryCode":s(({elementKey:e,countryCode:t},n)=>`Element "${n}.${e}" has unknown countryCode ${JSON.stringify(t)}.`,"list/unknownCountryCode")},pG={"nationality/wrongFieldKind":s(({fieldKey:e})=>`Field "${e}" is isNationality but not a 0-1-select / 0-n-select.`,"nationality/wrongFieldKind"),"nationality/notCountryList":s(({fieldKey:e})=>`Field "${e}" is isNationality but its list is not kind "country".`,"nationality/notCountryList"),"accountEmail/wrongFieldKind":s(({fieldKey:e})=>`Field "${e}" is isAccountEmail but not an email field.`,"accountEmail/wrongFieldKind"),"accountEmail/multiple":s(({fieldKey:e})=>`Field "${e}" is one of several isAccountEmail fields \u2014 at most one per tenant.`,"accountEmail/multiple"),"contactPhone/wrongFieldKind":s(({fieldKey:e})=>`Field "${e}" is isContactPhone but not a tel field.`,"contactPhone/wrongFieldKind"),"contactPhone/multiple":s(({fieldKey:e})=>`Field "${e}" is one of several isContactPhone fields \u2014 at most one per tenant.`,"contactPhone/multiple"),"invoiceAddress/wrongFieldKind":s(({fieldKey:e})=>`Field "${e}" is isInvoiceAddress but not an object field.`,"invoiceAddress/wrongFieldKind"),"invoiceAddress/missingPart":s(({fieldKey:e,parts:t})=>`Field "${e}" is isInvoiceAddress but declares no property for the address part(s) ${t.join(", ")} (objectSchema.properties[].addressPart) \u2014 an invoice cannot print its address without them.`,"invoiceAddress/missingPart"),"invoiceAddress/multiple":s(({fieldKey:e})=>`Field "${e}" is one of several isInvoiceAddress fields \u2014 at most one per tenant.`,"invoiceAddress/multiple")};function mG(e){let t=pG[e.code];return t(e)}s(mG,"roleText");function hG(e){let t=[],n=e.tenant.nationalityFlag,r=typeof n=="object"&&n!==null?n:{},i=r.mode;if(uy.includes(i)||t.push(`[nationality/flagMode] tenant.nationalityFlag.mode must be one of ${uy.join(", ")} (got ${n===void 0?"no tenant.nationalityFlag":JSON.stringify(i??null)}).`),n!==void 0){let l=r.defaultCountryCode;(typeof l!="string"||!df(l))&&t.push(`[nationality/defaultCountryCode] tenant.nationalityFlag.defaultCountryCode must be a lowercase ISO 3166-1 alpha-2 code (got ${JSON.stringify(l??null)}).`)}let o=new Map;for(let l of e.lists){let d=l.kind;if(!oI.includes(d)){t.push(`[list/kind] List "${l.key}" has kind ${JSON.stringify(d??null)} \u2014 one of ${oI.join(", ")}.`);continue}o.set(l.key,l.kind);for(let c of iI({key:l.key,kind:l.kind},l.elements))t.push(`[${c.code}] ${rI(fG,c,l.key)}`)}let a=nI(e.fields.map(l=>({key:l.key,kind:l.type,listKind:l.listKey===void 0?null:o.get(l.listKey)??null,isNationality:l.isNationality===!0,isAccountEmail:l.isAccountEmail===!0,isContactPhone:l.isContactPhone===!0,isInvoiceAddress:l.isInvoiceAddress===!0,addressParts:l.type==="object"?tI(l.objectSchema??{properties:[]}):null})));for(let l of a)t.push(`[${l.code}] ${mG(l)}`);return t}s(hG,"nationalityFindings");function sI(e){return di(e)?.message.de??(e instanceof Error?e.message:String(e))}s(sI,"errorText");function aI(e,t={}){let n=[...uG(e)],r=[];try{xR(e.fields.map(k=>k.key),[])}catch(k){n.push(sI(k))}e.tenant.terms!==void 0&&n.push(...NR(e.tenant.terms)),XR(e.tenant.mailLevel)?e.tenant.mailLevel==="all"&&!Gu(e.tenant.enabledModules,"notifications")&&n.push('[notification/levelWithoutModule] tenant.mailLevel is "all" but the notifications module is not enabled \u2014 only sign-in and security mail would go out. Enable the module or set "loginOnly".'):n.push(`[notification/mailLevel] tenant.mailLevel must be one of ${cy.join(", ")} (got ${e.tenant.mailLevel===void 0?"nothing":JSON.stringify(e.tenant.mailLevel)}).`),"enabledMailCategories"in e.tenant&&n.push('[notification/mailCategoriesRetired] tenant.enabledMailCategories was replaced by tenant.mailLevel \u2014 "all" for every mail, "loginOnly" for sign-in mail only to families (staff mail follows personal settings).'),"mailEnabled"in e.tenant&&n.push('[notification/mailEnabledRetired] tenant.mailEnabled was replaced by tenant.mailLevel \u2014 "all" for every mail, "loginOnly" for sign-in mail only to families (staff mail follows personal settings).'),St(e.displayGroups.map(k=>k.key),"display group",n),St(e.lists.map(k=>k.key),"list",n),St(e.roles.map(k=>k.key),"role",n),St(e.fields.map(k=>k.key),"field",n),St(e.foundation.legalEntities.map(k=>k.key),"legal entity",n),St(e.foundation.units.map(k=>k.key),"unit",n),St(e.foundation.permissionGroups.map(k=>k.key),"permission group",n),"teams"in e.foundation&&n.push("foundation.teams is retired: a team is a permission group \u2014 move each team to foundation.permissionGroups (same key) and remove the block.");for(let k of e.foundation.users)"teamKeys"in k&&n.push(`User "${k.email}" carries teamKeys, retired: team membership is the user's permission-group membership.`);St(e.foundation.users.map(k=>k.key),"user",n),St((e.searchFilters??[]).map(k=>k.key),"search filter",n),St((e.searchTargets??[]).map(k=>k.objectPropertyKey===void 0?k.fieldKey:`${k.fieldKey}.${k.objectPropertyKey}`),"search target",n),St((e.partyResultIcons??[]).map(k=>k.key),"party result icon",n),St((e.templatePlaceholders??[]).map(k=>k.key),"template placeholder",n),St((e.notificationLetters??[]).map(lI),"notification letter",n),SG(e.notificationLetters??[],n),AG(e.tenant.notificationChrome,n),e.tenant.bankImportScope!==void 0&&!["sepa_only","full_statement"].includes(e.tenant.bankImportScope)&&n.push("tenant.bankImportScope must be sepa_only or full_statement."),e.tenant.hideMailLevelNotice!==void 0&&typeof e.tenant.hideMailLevelNotice!="boolean"&&n.push("tenant.hideMailLevelNotice must be true or false (the dashboard's mail-level notice)."),typeof e.tenant.magicLinkLogin!="boolean"&&n.push("tenant.magicLinkLogin must be true or false (the login page's sign-in link option)."),bR(e.tenant.externalSignIn)||n.push(`[auth/externalSignIn] tenant.externalSignIn must be { mode: "permanentLink" }, { mode: "oneTimeLink" } or { mode: "periodLink", validDays: 1\u2013${Bg} } (how families sign in).`);let i=new Set(e.displayGroups.map(k=>k.key)),o=new Set(e.lists.map(k=>k.key)),a=new Set(e.roles.map(k=>k.key)),l=new Set(e.fields.map(k=>k.key)),d=new Map(e.fields.map(k=>[k.key,k])),c=new Set(e.foundation.legalEntities.map(k=>k.key)),u=new Set(e.foundation.units.map(k=>k.key)),f=new Set(e.foundation.permissionGroups.map(k=>k.key));Gu(e.tenant.enabledModules,"bewerbungsmanagement")&&e.tenant.defaultApplicantGroupKey!==void 0&&(e.foundation.permissionGroups.find(A=>A.key===e.tenant.defaultApplicantGroupKey)?.permissions.includes("bewerbungsmanagement.applications.submitOwn")||n.push(`Default applicant group "${e.tenant.defaultApplicantGroupKey}" must grant submitOwn.`));let m=e.tenant.admissionFieldDisplayGroupKey;m!==void 0&&!i.has(m)&&n.push(`tenant.admissionFieldDisplayGroupKey "${m}" names no display group of this config.`),m===void 0&&(Gu(e.tenant.enabledModules,"bewerbungsmanagement")||(e.admission?.fields.length??0)>0)&&n.push("tenant.admissionFieldDisplayGroupKey is required when admissions is enabled or admission.fields declares fields: it names the display group the fields an offer creates land in."),n.push(...hG(e)),St(e.fields.flatMap(k=>(k.relationshipKinds??[]).map(A=>A.key)),"relationship kind",n);for(let k of e.fields){i.has(k.displayGroupKey)||n.push(`Field "${k.key}" references missing display group "${k.displayGroupKey}".`),yG(k,n),k.formWritable===!0&&!Wg[k.type].fieldMapTarget&&n.push(`Field "${k.key}" is formWritable, but a form cannot write a "${k.type}" field.`),k.type==="auto-string"?wG(k,d,n):k.autoString!==void 0&&n.push(`Non-automatic field "${k.key}" must not define autoString.`),(!Number.isFinite(k.sortOrder)||k.sortOrder<0)&&n.push(`Field "${k.key}" has invalid sortOrder "${k.sortOrder}" (must be a non-negative number).`),(k.type==="0-1-select"||k.type==="0-n-select")&&!k.listKey&&n.push(`Select field "${k.key}" must define listKey.`),k.type!=="0-1-select"&&k.type!=="0-n-select"&&k.listKey!==void 0&&n.push(`Non-select field "${k.key}" must not define listKey.`),k.listKey&&!o.has(k.listKey)&&n.push(`Field "${k.key}" references missing list "${k.listKey}".`),(k.type==="object"||k.type==="relationship")&&!k.objectSchema&&n.push(`Field "${k.key}" must define objectSchema.`),k.type!=="object"&&k.type!=="relationship"&&k.objectSchema&&n.push(`Non-object field "${k.key}" must not define objectSchema.`);for(let A of k.objectSchema?.properties??[])(A.type==="0-1-select"||A.type==="0-n-select")&&!A.listKey&&n.push(`Object select property "${k.key}.${A.key}" must define listKey.`),A.listKey&&!o.has(A.listKey)&&n.push(`Object property "${k.key}.${A.key}" references missing list "${A.listKey}".`);gG(k,n)}let g=e.tenant.priceCriteriaFacts;if(g){let k=e.fields.find(A=>A.key===g.birthDateFieldKey);(!k||k.type!=="date")&&n.push("Price criteria require a configured date field for birth dates."),a.has(g.studentRoleKey)||n.push("Price criteria require a configured Student eligibility role.");for(let A of Object.keys(g))A!=="birthDateFieldKey"&&A!=="studentRoleKey"&&n.push(`Unknown price criteria fact setting "${A}".`)}let w=e.tenant.defaultEnrolleeRoleKey;w&&!a.has(w)&&n.push(`Default enrollment role "${w}" does not exist.`),w&&e.roles.some(k=>k.parentRoleKey===w)&&n.push(`Default enrollment role "${w}" must be a leaf role.`);for(let k of e.roles){(typeof k.icon!="string"||k.icon.trim().length===0)&&n.push(`Role "${k.key}" must define an icon.`),k.parentRoleKey&&!a.has(k.parentRoleKey)&&n.push(`Role "${k.key}" references missing parent role "${k.parentRoleKey}".`);for(let A of k.listDisplayFieldKeys??[])l.has(A)||n.push(`Role "${k.key}" list display references missing field "${A}".`)}let y=new Map(e.roles.map(k=>[k.key,k.parentRoleKey])),v=new Map;for(let k of e.roleFields){let A=v.get(k.roleKey)??[];A.push({roleId:k.roleKey,customFieldId:k.fieldKey}),v.set(k.roleKey,A)}for(let k of e.roles)try{kR(k.key,y,v)}catch(A){n.push(sI(A))}for(let k of e.roleFields){a.has(k.roleKey)||n.push(`Role field references missing role "${k.roleKey}" for field "${k.fieldKey}".`),l.has(k.fieldKey)||n.push(`Role field references missing field "${k.fieldKey}" for role "${k.roleKey}".`);for(let A of k.targetRequirementFieldKeys??[])l.has(A)||n.push(`Role field "${k.roleKey}.${k.fieldKey}" references missing target requirement field "${A}".`)}xG(e.contractRoleMappings??[],a,n);for(let k of e.templatePlaceholders??[])lR.test(k.key)||n.push(`Template placeholder "${k.key}" must use lower_snake_case segments, optionally separated by dots.`),k.source.kind==="customField"?cf(k.source,d,n,`Template placeholder "${k.key}"`):k.source.kind==="relationshipTargetField"&&bG(k,d,n);for(let k of e.searchTargets??[])cf(k,d,n,"Search target");for(let k of e.fields)OR(k.key)&&(k.defaultValue!==void 0||k.validations!==void 0)&&n.push(`System field "${k.key}" takes no defaultValue or validations.`);for(let k of e.lists)St(k.elements.map((A,q)=>String(A.sortOrder??(q+1)*10)),`sortOrder of an element of list "${k.key}"`,n);for(let k of e.searchFilters??[])St((k.options??[]).map((A,q)=>String(A.sortOrder??(q+1)*10)),`sortOrder of an option of search filter "${k.key}"`,n);for(let k of e.foundation.permissionGroups){k.grantAllCustomFields===!0&&k.customFieldPermissions!==void 0&&n.push(`Permission group "${k.key}" states both grantAllCustomFields and customFieldPermissions \u2014 one of them.`),St((k.customFieldPermissions??[]).map(A=>A.displayGroupKey),`display group of a field permission of group "${k.key}"`,n);for(let A of k.customFieldPermissions??[]){i.has(A.displayGroupKey)||n.push(`Permission group "${k.key}" grants field permissions on missing display group "${A.displayGroupKey}".`);for(let q of A.permissions)$R.includes(q)||n.push(`Permission group "${k.key}" grants unknown field permission "${q}".`)}}let T=e.tenant.partyRetention;T!==void 0&&(IR(T.days)||n.push(`tenant.partyRetention.days must be a whole number of days from 1 to ${36500} (got ${JSON.stringify(T.days)}).`),Number.isFinite(T.enabledAt)||n.push("tenant.partyRetention.enabledAt must be a timestamp (epoch ms)."),T.formerRoleKey!==void 0&&!a.has(T.formerRoleKey)&&n.push(`tenant.partyRetention references missing role "${T.formerRoleKey}".`));for(let k of e.searchFilters??[]){(k.kind==="chips"||k.kind==="select")&&(k.options?.length??0)===0&&n.push(`Search filter "${k.key}" must define options.`),(k.kind==="text"||k.kind==="numberRange")&&k.target===void 0&&n.push(`Search filter "${k.key}" must define a target field.`),k.options!==void 0&&St(k.options.map(A=>A.key),`search filter option for "${k.key}"`,n),cf(k.target,d,n,`Search filter "${k.key}"`);for(let A of k.options??[]){A.predicates.length===0&&n.push(`Search filter option "${k.key}.${A.key}" must define at least one predicate.`);for(let q of A.predicates){if(q.kind==="role"){a.has(q.roleKey)||n.push(`Search filter option "${k.key}.${A.key}" references missing role "${q.roleKey}".`);continue}cf(q,d,n,`Search filter option "${k.key}.${A.key}"`)}}}for(let k of e.partyResultIcons??[])kG(k,d,n);for(let k of e.foundation.legalEntities)if(k.signatoryUserKey!==void 0&&k.type==="school_group"&&n.push(`[config/signatoryOnGroup] Legal entity "${k.key}" is a school_group \u2014 only a Tr\xE4ger (school_operator, service_entity) declares an Unterschriftsperson.`),k.parentLegalEntityKey&&!c.has(k.parentLegalEntityKey)&&n.push(`Legal entity "${k.key}" references missing parent "${k.parentLegalEntityKey}".`),k.address!==void 0){let A=k.address,q=["street","hausnr","plz","ort"];k.type==="school_group"?n.push(`Legal entity "${k.key}" is a school_group \u2014 only a Tr\xE4ger (school_operator, service_entity) has an address.`):(typeof A!="object"||A===null||Array.isArray(A)||Object.keys(A).some(P=>!q.includes(P))||q.some(P=>typeof A[P]!="string"||(A[P]??"").trim()===""))&&n.push(`Legal entity "${k.key}" has an invalid address \u2014 expected { street, hausnr, plz, ort }, each non-empty.`)}let $=new Map;for(let k of e.foundation.units){if(k.slug!==void 0){let A=typeof k.slug=="string"?ER(k.slug):"must be a string";A!==void 0&&n.push(`Unit "${k.key}" has invalid slug "${k.slug}" (${A}).`);let q=$.get(k.slug);q!==void 0&&n.push(`Units "${q}" and "${k.key}" both declare slug "${k.slug}" (unit slugs are unique per tenant).`),$.set(k.slug,k.key)}c.has(k.legalEntityKey)||n.push(`Unit "${k.key}" references missing legal entity "${k.legalEntityKey}".`),k.parentUnitKey&&!u.has(k.parentUnitKey)&&n.push(`Unit "${k.key}" references missing parent unit "${k.parentUnitKey}".`),k.chargeReviewEnabled!==void 0&&typeof k.chargeReviewEnabled!="boolean"&&n.push(`Unit "${k.key}": chargeReviewEnabled must be true or false.`),k.sortOrder!==void 0&&(!Number.isFinite(k.sortOrder)||k.sortOrder<0)&&n.push(`Unit "${k.key}" has invalid sortOrder "${k.sortOrder}" (must be a non-negative number).`)}let O=/^[0-9a-f]{32}:[0-9a-f]{128}$/;for(let k of e.foundation.users){f.has(k.permissionGroupKey)||n.push(`User "${k.email}" references missing permission group "${k.permissionGroupKey}".`),k.unitKey&&!u.has(k.unitKey)&&n.push(`User "${k.email}" references missing unit "${k.unitKey}".`),k.status!==void 0&&k.status!=="deactivated"&&n.push(`User "${k.email}": status must be "deactivated" or absent, not "${String(k.status)}".`);let A=[k,...k.additionalMemberships??[]];for(let P of k.additionalMemberships??[])f.has(P.permissionGroupKey)||n.push(`User "${k.email}" references missing permission group "${P.permissionGroupKey}".`),P.unitKey&&!u.has(P.unitKey)&&n.push(`User "${k.email}" references missing unit "${P.unitKey}".`);St(A.map(P=>`${P.permissionGroupKey}/${P.unitKey??""}`),`membership (permission group/unit) of user "${k.email}"`,n);for(let P of A)P.validFrom!==void 0&&P.validTo!==void 0&&P.validTo<=P.validFrom&&n.push(`User "${k.email}": membership "${P.permissionGroupKey}" ends (validTo) before it starts (validFrom).`);let q=[k.firstName,k.lastName];q.some(P=>P!==void 0)&&q.some(P=>typeof P!="string"||P.trim()==="")&&n.push(`[config/userNameIncomplete] User "${k.email}" states only part of firstName/lastName (or an empty one) \u2014 set both or neither.`);for(let P of["staging","prod"]){let Y=k.passwordHashes?.[P];Y!==void 0&&!O.test(Y)&&n.push(`User "${k.email}" passwordHashes.${P} is not in Better Auth scrypt format "<32hex>:<128hex>".`)}}EG(e.tenant.branding,n),TG(e.tenant,n);let N=dI(e.fields.flatMap(k=>k.sourceColumns));for(let k of N)r.push(`Source column "${k}" is mapped by more than one field.`);IG(e,n);let L=t.sourceColumns===void 0||e.source===void 0?void 0:$G(e,t.sourceColumns,n);return{ok:n.length===0,errors:n,warnings:r,coverage:L}}s(aI,"validateTenantConfig");function gG(e,t){let n=new Map;for(let r of e.objectSchema?.properties??[]){let i=r.addressPart;if(i===void 0)continue;let o=`Object property "${e.key}.${r.key}"`;if(!ug.includes(i)){t.push(`${o}: addressPart "${i}" is none of ${ug.join(", ")}.`);continue}e.type!=="object"&&t.push(`${o}: only an object field stores an address (addressPart).`),r.type!=="string"&&t.push(`${o}: addressPart "${i}" needs a string property, not "${r.type}".`);let a=n.get(i);a!==void 0&&t.push(`${o}: addressPart "${i}" is already declared by "${e.key}.${a}".`),n.set(i,r.key)}}s(gG,"validateAddressParts");function yG(e,t){let n=e.relationshipKinds;if(n===void 0)return;if(e.type!=="relationship"){t.push(`Field "${e.key}" declares relationshipKinds, but only a relationship field carries them.`);return}let r=new Map((e.objectSchema?.properties??[]).map(i=>[i.key,i]));for(let i of n){let o=`Field "${e.key}" relationship kind "${i.key}"`;if(typeof i.key!="string"||i.key.trim()===""){t.push(`Field "${e.key}": a relationship kind needs a key.`);continue}for(let l of["de","en"])(i.label?.[l]??"").trim()===""&&t.push(`${o}: label.${l} is required \u2014 [i18n/missingTranslation] every shown text needs German and English.`);if(i.edge===null||typeof i.edge!="object"||Array.isArray(i.edge)){t.push(`${o}: edge must be an object.`);continue}i.sibling!==void 0&&i.sibling!==!0&&t.push(`${o}: sibling must be true or absent.`),i.sibling===!0&&i.mergeInto!==void 0&&t.push(`${o}: a sibling kind's edge is its identity \u2014 it cannot declare mergeInto.`);let a=n.flatMap(l=>l.mergeInto!==void 0?[l.mergeInto]:[]);if(i.sibling===!0&&a.some(l=>l in i.edge)&&t.push(`${o}: a sibling kind's edge is its identity \u2014 it cannot declare a property another kind of the field merges into.`),i.sibling===!0&&Object.keys(i.edge).length===0&&t.push(`${o}: a sibling kind's edge is its identity \u2014 an empty edge would count every edge of the field.`),i.mergeInto!==void 0){let l=r.get(i.mergeInto);l===void 0||l.type!=="0-n-select"?t.push(`${o}: mergeInto "${i.mergeInto}" must name a 0-n-select property of the field's objectSchema.`):Array.isArray(i.edge[i.mergeInto])||t.push(`${o}: mergeInto "${i.mergeInto}" must be set to a list in the edge.`)}}}s(yG,"validateRelationshipKinds");function wG(e,t,n){if(e.autoString===void 0){n.push(`Automatic field "${e.key}" must define autoString.`);return}e.allowMultiple===!0&&n.push(`Automatic field "${e.key}" must not allow multiple values.`),e.shareable===!0&&n.push(`Automatic field "${e.key}" must not be shareable.`),e.autoString.segments.length===0&&n.push(`Automatic field "${e.key}" must define at least one segment.`),e.autoString.segments.filter(i=>i.kind==="sequence").length!==1&&n.push(`Automatic field "${e.key}" must define exactly one sequence segment.`);for(let i of e.autoString.segments)if(i.kind==="literal"&&i.value.length===0&&n.push(`Automatic field "${e.key}" has an empty literal segment.`),i.kind==="sequence"&&(i.startAt!==void 0&&(!Number.isInteger(i.startAt)||i.startAt<1)&&n.push(`Automatic field "${e.key}" sequence startAt must be an integer >= 1.`),i.minDigits!==void 0&&(!Number.isInteger(i.minDigits)||i.minDigits<0)&&n.push(`Automatic field "${e.key}" sequence minDigits must be an integer >= 0.`)),i.kind==="field"){let o=t.get(i.fieldKey);if(o===void 0){n.push(`Automatic field "${e.key}" references missing field "${i.fieldKey}".`);continue}i.objectPropertyKey!==void 0&&o.objectSchema?.properties.find(l=>l.key===i.objectPropertyKey)===void 0&&n.push(`Automatic field "${e.key}" references missing object property "${i.fieldKey}.${i.objectPropertyKey}".`)}}s(wG,"validateAutomaticStringField");function cf(e,t,n,r){if(e===void 0)return;let i=t.get(e.fieldKey);if(i===void 0){n.push(`${r} references missing field "${e.fieldKey}".`);return}if(e.objectPropertyKey===void 0)return;(i.objectSchema?.properties.some(a=>a.key===e.objectPropertyKey)??!1)||n.push(`${r} references missing object property "${e.fieldKey}.${e.objectPropertyKey}".`)}s(cf,"validateSearchTarget");function bG(e,t,n){if(e.source.kind!=="relationshipTargetField")return;let r=`Template placeholder "${e.key}"`,i=t.get(e.source.relationshipFieldKey);if(i===void 0)n.push(`${r} references missing relationship field "${e.source.relationshipFieldKey}".`);else if(i.type!=="relationship")n.push(`${r} relationship field "${e.source.relationshipFieldKey}" must be a relationship field.`);else{for(let a of e.source.edgeFilters??[])fy(i,a.propertyKey,n,`${r} edge filter`);e.source.selection?.sortPropertyKey!==void 0&&fy(i,e.source.selection.sortPropertyKey,n,`${r} selection sort`)}let o=t.get(e.source.targetFieldKey);if(o===void 0){n.push(`${r} references missing target field "${e.source.targetFieldKey}".`);return}o.type==="relationship"&&n.push(`${r} target field "${e.source.targetFieldKey}" must not be a relationship field.`),e.source.targetObjectPropertyKey!==void 0&&fy(o,e.source.targetObjectPropertyKey,n,`${r} target`)}s(bG,"validateRelationshipTemplatePlaceholder");function fy(e,t,n,r){(e.objectSchema?.properties.some(o=>o.key===t)??!1)||n.push(`${r} references missing object property "${e.key}.${t}".`)}s(fy,"validateObjectPropertyReference");function kG(e,t,n){let r=`Party result icon "${e.key}"`,i=t.get(e.when.fieldKey);if(i===void 0){n.push(`${r} references missing field "${e.when.fieldKey}".`);return}if(e.when.objectPropertyKey===void 0){i.type!=="boolean"&&n.push(`${r} must target a Boolean field or object property.`);return}let o=i.objectSchema?.properties.find(a=>a.key===e.when.objectPropertyKey);if(o===void 0){n.push(`${r} references missing object property "${e.when.fieldKey}.${e.when.objectPropertyKey}".`);return}o.type!=="boolean"&&n.push(`${r} must target a Boolean field or object property.`)}s(kG,"validatePartyResultIconTarget");function lI(e){return`${e.templateId}:${e.locale}:${e.scopeKey}`}s(lI,"letterIdentity");function vG(e){return`${e.generatorKey??"*"}/${e.partyKind}/${e.roleKey}`}s(vG,"contractRoleMappingIdentity");function xG(e,t,n){let r=new Set;for(let i of e){let o=vG(i),a=`Contract role mapping "${o}"`;Vg.includes(i.partyKind)||n.push(`${a}: partyKind must be one of ${Vg.join(", ")}.`),t.has(i.roleKey)||n.push(`${a} references missing role "${i.roleKey}".`),i.generatorKey!==void 0&&i.generatorKey.trim()===""&&n.push(`${a}: generatorKey must not be blank \u2014 omit it for the tenant default.`),r.has(o)&&n.push(`${a} is declared twice.`),r.add(o)}}s(xG,"validateContractRoleMappings");function SG(e,t){for(let n of e){let r=`Notification letter "${lI(n)}"`;if(!Qu(n.locale)){t.push(`${r} declares locale "${String(n.locale)}" \u2014 letters are written in ${Je.map(i=>`"${i}"`).join(" and ")} only, so no mail would ever read this deviation.`);continue}if(n.scopeKey!==zu){t.push(`${r} declares scopeKey "${n.scopeKey}" \u2014 the only scope is "${zu}" (the whole school).`);continue}if(Object.keys(n.slots).length===0){t.push(`${r} overrides no block. A deviation that deviates in nothing is not an entry \u2014 remove it.`);continue}if(!ay(n.templateId)){t.push(`${r} references no registered letter \u2014 "${n.templateId}" is not in the letter catalog.`);continue}for(let i of FR(sy(n.templateId),n.slots,n.locale))t.push(`${r}, block "${i.slotKey}" [${i.code}]: ${i.message.de}`)}}s(SG,"validateNotificationLetters");function AG(e,t){if(e!==void 0)for(let n of LR(e))t.push(`Notification chrome: ${n.de}`)}s(AG,"validateNotificationChrome");function EG(e,t){if(e===void 0)return;let n=/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,r=/^(?:rgb|rgba|hsl|hsla)\(.+\)$/i,i=s(c=>n.test(c.trim())||r.test(c.trim()),"isColor");for(let[c,u]of Object.entries(e.colors??{}))u!==void 0&&(i(u)||t.push(`Branding color "colors.${c}" has invalid value "${u}" (expected hex "#rgb"/"#rrggbb"/"#rrggbbaa" or rgb()/rgba()/hsl()/hsla()).`));let o=["sharp","rounded","soft"];e.radius!==void 0&&!o.includes(e.radius)&&t.push(`Branding radius "${e.radius}" is invalid (expected "sharp", "rounded", or "soft").`);let a=["sm","md","lg","max"];e.logoSize!==void 0&&!a.includes(e.logoSize)&&t.push(`Branding logoSize "${e.logoSize}" is invalid (expected "sm", "md", "lg", or "max").`);let l=["compact","normal","spacious"];e.bannerDensity!==void 0&&!l.includes(e.bannerDensity)&&t.push(`Branding bannerDensity "${e.bannerDensity}" is invalid (expected "compact", "normal", or "spacious").`);let d=["light","dark"];e.logoGround!==void 0&&!d.includes(e.logoGround)&&t.push(`Branding logoGround "${e.logoGround}" is invalid (expected "light" or "dark").`),e.websiteUrl!==void 0&&!e.websiteUrl.startsWith("https://")&&t.push(`Branding websiteUrl must be an https:// URL (got "${e.websiteUrl}").`);for(let c of["heading","body"]){let u=e.fonts?.[c];u!==void 0&&((typeof u.family!="string"||u.family.trim().length===0)&&t.push(`Branding font "fonts.${c}" must define a non-empty family.`),Object.hasOwn(u,"url")&&t.push(`Branding font "fonts.${c}.url" is no longer supported \u2014 the font file is uploaded (plexus-cli branding set-font --slot ${c} --file <woff2>) and config carries the family only.`))}}s(EG,"validateBranding");function TG(e,t){let n=e.brandingAssets;if(n!==void 0){if(typeof n!="object"||n===null||Array.isArray(n)){t.push(`tenant.brandingAssets must be an object keyed by slot (${lf.join(", ")}).`);return}for(let[r,i]of Object.entries(n)){let o=`tenant.brandingAssets.${r}`;if(!lf.includes(r)){t.push(`${o}: unknown slot (expected ${lf.join(", ")}).`);continue}if(typeof i!="object"||i===null){t.push(`${o}: must be { sha256, sizeBytes, mimeType }.`);continue}if("size"in i){t.push(`[config/fileRefRenamed] ${o} still names size \u2014 this bundle was exported before the file-field rename, or by a plexus-cli older than this release (now sizeBytes). Update plexus-cli, export it again (plexus-cli --env <env> config export) and re-apply.`);continue}cI.test(i.sha256??"")||t.push(`${o}: sha256 must be 64 lowercase hex chars.`),(!Number.isInteger(i.sizeBytes)||i.sizeBytes<=0)&&t.push(`${o}: sizeBytes must be a positive integer.`);let a=JR[r];if(a===null){let l=QR({contentType:i.mimeType,size:i.sizeBytes});l!==null&&t.push(`${o}: ${l.de}`)}else{i.mimeType!==dy&&t.push(`${o}: mimeType must be "${dy}" (got "${i.mimeType}").`);let l=ZR(e.branding?.fonts?.[a]?.family);l!==null&&t.push(`${o}: [branding/fontFamilyMissing] tenant.branding.fonts.${a}: ${l.de}`)}"path"in i&&t.push(`${o}: "path" is a CLI snapshot field \u2014 resolve it with plexus-cli config apply.`)}}}s(TG,"validateBrandingAssets");function $G(e,t,n){let{source:r}=e;r===void 0&&_("validateSourceCoverage: called without a `source` block.");let i=new Set(t),o=new Set(e.fields.flatMap(w=>w.sourceColumns)),a=new Set(e.deferredColumns.map(w=>w.column)),l=new Set(e.ignoredColumns.map(w=>w.column)),d=new Set([...o,...a,...l]),c=r.requiredColumns.filter(w=>!i.has(w)),u=t.filter(w=>!d.has(w)),f=[...o].filter(w=>!i.has(w)),m=[...a].filter(w=>!i.has(w)),g=[...l].filter(w=>!i.has(w));for(let w of c)n.push(`Required source column "${w}" is missing from ${r.primaryTable}.`);for(let w of u)n.push(`Source column "${w}" is neither mapped nor explicitly deferred/ignored.`);for(let w of f)n.push(`Mapped source column "${w}" does not exist in the source schema.`);for(let w of m)n.push(`Deferred source column "${w}" does not exist in the source schema.`);for(let w of g)n.push(`Ignored source column "${w}" does not exist in the source schema.`);return{table:r.primaryTable,availableColumns:t.length,mappedColumns:[...o].filter(w=>i.has(w)).length,deferredColumns:[...a].filter(w=>i.has(w)).length,ignoredColumns:[...l].filter(w=>i.has(w)).length,missingRequiredColumns:c,unmappedColumns:u,unknownMappedColumns:f,unknownDeferredColumns:m,unknownIgnoredColumns:g}}s($G,"validateSourceCoverage");function St(e,t,n){for(let r of dI(e))n.push(`Duplicate ${t} key "${r}".`)}s(St,"requireUnique");function dI(e){let t=new Set,n=new Set;for(let r of e)t.has(r)&&n.add(r),t.add(r);return[...n]}s(dI,"duplicates");var cI=/^[0-9a-f]{64}$/,RG=["fileName","size"];function IG(e,t){if(!Array.isArray(e.files)){t.push('"files" is missing \u2014 declare the file library (an empty list is fine).');return}St(e.files.map(n=>n.key),"file",t);for(let n of e.files){let r=`files["${n.key}"]`;bs(n.key)||t.push(`${r}: key must match ${ly}.`);for(let o of["de","en"])(n.label?.[o]??"").trim()===""&&t.push(`${r}: label.${o} is required \u2014 [i18n/missingTranslation] every shown text needs German and English.`);let i=RG.filter(o=>o in n);if(i.length>0){t.push(`[config/fileRefRenamed] ${r} still names ${i.join(", ")} \u2014 this bundle was exported before the file-field rename, or by a plexus-cli older than this release (now filename / sizeBytes). Update plexus-cli, export it again (plexus-cli --env <env> config export) and re-apply.`);continue}if(typeof n.filename!="string")t.push(`${r}: filename is missing.`);else{let o=uo(n.filename);o!==null&&t.push(`${r}: filename ${o}.`)}af.includes(n.mimeType)||t.push(`${r}: mimeType "${n.mimeType}" is not allowed (${af.join(", ")}).`),cI.test(n.sha256??"")||t.push(`${r}: sha256 must be 64 lowercase hex chars.`),(!Number.isInteger(n.sizeBytes)||n.sizeBytes<=0)&&t.push(`${r}: sizeBytes must be a positive integer.`),"path"in n&&t.push(`${r}: "path" is a CLI snapshot field \u2014 resolve it with plexus-cli config apply.`)}}s(IG,"validateFiles");var OG=new WeakMap,PG=new WeakSet;function py(e,t){t(e);let r=e.asOptional.bind(e);return Object.defineProperty(e,"asOptional",{value:s(()=>py(r(),t),"value"),enumerable:!1}),e}s(py,"carry");function ks(e,t){return py(e,n=>OG.set(n,t))}s(ks,"tagged");var _G="tenant teardown drains every table explicitly (config/wipe.ts)",qt={belongsTo:s(e=>ks(e,{kind:"belongsTo"}),"belongsTo"),owns:s(e=>ks(e,{kind:"owns"}),"owns"),holds:s(e=>ks(e,{kind:"holds"}),"holds"),restrict:s((e,t)=>ks(e,t?{kind:"restrict",unindexed:t.unindexed}:{kind:"restrict"}),"restrict"),history:s(e=>ks(e,{kind:"history"}),"history"),tenant:s(e=>ks(e,{kind:"restrict",unindexed:_G}),"tenant"),historyOf:s(e=>py(e,t=>PG.add(t)),"historyOf")};var NG=b.object({street:b.string(),hausnr:b.string(),plz:b.string(),ort:b.string()}),uI=b.union(b.literal("school_operator"),b.literal("school_group"),b.literal("service_entity")),vr=uI.members.map(e=>e.value),CG={tenantId:qt.tenant(b.id("tenants")),name:b.optional(b.string()),type:uI,parentLegalEntityId:b.optional(qt.restrict(b.id("legal_entities"))),configKey:b.optional(b.string()),partyId:b.optional(qt.restrict(b.id("parties"))),address:b.optional(NG),signatoryUserId:b.optional(qt.restrict(b.id("users")))},Tle=Mr(CG).index("by_tenantId",["tenantId"]).index("by_parentLegalEntityId",["parentLegalEntityId"]).index("by_tenantId_and_configKey",["tenantId","configKey"]).index("by_partyId",["partyId"]).index("by_signatoryUserId",["signatoryUserId"]);var DG=b.union(b.literal("school"),b.literal("kindergarten"),b.literal("after_school_care"),b.literal("department"),b.literal("site"),b.literal("other")),In=DG.members.map(e=>e.value),Ile=b.union(b.literal("school"),b.literal("vocational"),b.literal("care"),b.literal("seminar"),b.literal("other")),Ole=b.union(b.literal("none"),b.literal("manual"),b.literal("annual_rollover")),Ple=b.union(b.literal("grade_level"),b.literal("module"),b.literal("phase"),b.literal("other")),_le=b.union(b.literal("school_year"),b.literal("cohort"),b.literal("seminar"),b.literal("care_period"),b.literal("other")),Nle=b.union(b.literal("planned"),b.literal("active"),b.literal("completed"),b.literal("archived")),Cle=b.union(b.literal("class"),b.literal("course"),b.literal("care_group"),b.literal("seminar_group"),b.literal("mixed_age_group"),b.literal("other")),Dle=b.union(b.literal("planned"),b.literal("active"),b.literal("completed"),b.literal("withdrawn"),b.literal("candidate")),Fle=b.union(b.literal("planned"),b.literal("active"),b.literal("completed"),b.literal("cancelled")),Lle=b.union(b.literal("class_teacher"),b.literal("teacher"),b.literal("mentor"),b.literal("instructor"),b.literal("assistant"),b.literal("other")),Mle=b.union(b.literal("units"),b.literal("unit_profiles"),b.literal("programs"),b.literal("program_stages"),b.literal("program_runs"),b.literal("learning_groups"),b.literal("enrollments"),b.literal("learning_group_staff_assignments")),qle=b.union(b.literal("open"),b.literal("mapped"),b.literal("ignored"));function pI(e){let t=["street","hausnr","plz","ort"].filter(n=>e[n]!==void 0);if(t.length!==0){if(t.length!==4)throw new Error(`config legal-entity add: an address needs all of --street, --hausnr, --plz and --ort (got ${t.map(n=>`--${n}`).join(", ")})`);return{street:e.street,hausnr:e.hausnr,plz:e.plz,ort:e.ort}}}s(pI,"addressFrom");function mI(e){if(!vr.includes(e))throw new Error(`config legal-entity add: --type "${e}" is none of ${vr.join(", ")}`);return e}s(mI,"legalEntityType");function hI(e){if(!In.includes(e))throw new Error(`config unit add: --kind "${e}" is none of ${In.join(", ")}`);return e}s(hI,"unitKind");function gI(e,t,n){let r=e.find(i=>i.key===t.key);if(r===void 0)return e.push(t),"create";if(Pe(r)===Pe(t))return"same";throw new Error(`${n} "${t.key}" already exists with other values \u2014 decide by hand, nothing written.
|
|
9603
9603
|
in the file: ${JSON.stringify(r)}
|
|
9604
9604
|
requested: ${JSON.stringify(t)}`)}s(gI,"addRow");function fI(e){return new Set(aI(e).errors)}s(fI,"findings");function yI(e,t){let n=s(()=>JSON.parse(ke(e,"utf8")),"read"),r=n();if(typeof r!="object"||r===null||typeof r.foundation!="object")throw new Error(`config: ${e} is no exported tenant config (no "foundation" block) \u2014 export one with \`config export --out <file>\``);let i=fI(r),o=n(),a=t(o),l=[...fI(o)].filter(d=>!i.has(d));if(l.length>0)throw new Error(`config: the edit is refused by the config validator, nothing written:
|
|
9605
9605
|
${l.join(`
|
|
@@ -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.11";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
|