@4pm/cli 1.30.0 → 1.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +368 -10
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -28569,6 +28569,344 @@ async function fetchCliVersion(serverUrl, version) {
28569
28569
  }
28570
28570
  }
28571
28571
 
28572
+ // vendor/@4pm/constants/error-codes.ts
28573
+ var ErrorCode = {
28574
+ // Common
28575
+ VALIDATION_FAILED: "VALIDATION_FAILED",
28576
+ UNAUTHORIZED: "UNAUTHORIZED",
28577
+ FORBIDDEN: "FORBIDDEN",
28578
+ IP_NOT_ALLOWED: "IP_NOT_ALLOWED",
28579
+ // A user's IP allowlist entry falls outside the org allowlist (ADR-0044).
28580
+ IP_OUTSIDE_ORG_ALLOWLIST: "IP_OUTSIDE_ORG_ALLOWLIST",
28581
+ // An allowlist entry falls outside its parent tier: a team/project outside the
28582
+ // org, or a user outside the union of their teams'/projects' allowlists (ADR-0050).
28583
+ IP_OUTSIDE_PARENT_ALLOWLIST: "IP_OUTSIDE_PARENT_ALLOWLIST",
28584
+ NOT_FOUND: "NOT_FOUND",
28585
+ CONFLICT: "CONFLICT",
28586
+ RATE_LIMITED: "RATE_LIMITED",
28587
+ FEATURE_NOT_AVAILABLE: "FEATURE_NOT_AVAILABLE",
28588
+ // Request body exceeded the HTTP gateway's JSON size limit (see HTTP_JSON_BODY_LIMIT_BYTES).
28589
+ PAYLOAD_TOO_LARGE: "PAYLOAD_TOO_LARGE",
28590
+ INTERNAL_ERROR: "INTERNAL_ERROR",
28591
+ // auth
28592
+ INVALID_CREDENTIALS: "INVALID_CREDENTIALS",
28593
+ EMAIL_NOT_VERIFIED: "EMAIL_NOT_VERIFIED",
28594
+ ACCOUNT_LOCKED: "ACCOUNT_LOCKED",
28595
+ TOKEN_INVALID: "TOKEN_INVALID",
28596
+ TOKEN_EXPIRED: "TOKEN_EXPIRED",
28597
+ TOKEN_USED: "TOKEN_USED",
28598
+ TOKEN_REVOKED: "TOKEN_REVOKED",
28599
+ /** The session is idle-locked (ADR-0204) — re-authenticate to continue (HTTP 423). */
28600
+ SESSION_LOCKED: "SESSION_LOCKED",
28601
+ PASSWORD_POLICY_VIOLATION: "PASSWORD_POLICY_VIOLATION",
28602
+ PASSWORD_CONFIRM_MISMATCH: "PASSWORD_CONFIRM_MISMATCH",
28603
+ PASSWORD_CURRENT_INVALID: "PASSWORD_CURRENT_INVALID",
28604
+ IDENTITY_REQUIRED: "IDENTITY_REQUIRED",
28605
+ MFA_CODE_INVALID: "MFA_CODE_INVALID",
28606
+ MFA_CODE_EXPIRED: "MFA_CODE_EXPIRED",
28607
+ // org · user · team · project
28608
+ USER_NOT_FOUND: "USER_NOT_FOUND",
28609
+ TEAM_NOT_FOUND: "TEAM_NOT_FOUND",
28610
+ PROJECT_NOT_FOUND: "PROJECT_NOT_FOUND",
28611
+ ORG_NOT_FOUND: "ORG_NOT_FOUND",
28612
+ // org login alias (ADR-0111): alias already used by another org, or a reserved word
28613
+ ORG_ALIAS_TAKEN: "ORG_ALIAS_TAKEN",
28614
+ // org template files (ADR-0113)
28615
+ TEMPLATE_NOT_FOUND: "TEMPLATE_NOT_FOUND",
28616
+ TEMPLATE_QUOTA_EXCEEDED: "TEMPLATE_QUOTA_EXCEEDED",
28617
+ TEMPLATE_FILE_TOO_LARGE: "TEMPLATE_FILE_TOO_LARGE",
28618
+ // skill/subagent marketplace (ADR-0185)
28619
+ MARKET_PACKAGE_NOT_FOUND: "MARKET_PACKAGE_NOT_FOUND",
28620
+ MARKET_VERSION_NOT_FOUND: "MARKET_VERSION_NOT_FOUND",
28621
+ MARKET_PACKAGE_EXISTS: "MARKET_PACKAGE_EXISTS",
28622
+ MARKET_VERSION_EXISTS: "MARKET_VERSION_EXISTS",
28623
+ MARKET_INVALID_PACKAGE: "MARKET_INVALID_PACKAGE",
28624
+ MARKET_SCOPE_FORBIDDEN: "MARKET_SCOPE_FORBIDDEN",
28625
+ MARKET_SCOPE_UNSUPPORTED: "MARKET_SCOPE_UNSUPPORTED",
28626
+ MARKET_VERSION_NOT_APPROVED: "MARKET_VERSION_NOT_APPROVED",
28627
+ MARKET_NOT_MODERATABLE: "MARKET_NOT_MODERATABLE",
28628
+ MARKET_UNAVAILABLE: "MARKET_UNAVAILABLE",
28629
+ MARKET_REVIEW_NOT_ELIGIBLE: "MARKET_REVIEW_NOT_ELIGIBLE",
28630
+ MARKET_PAYMENT_REQUIRED: "MARKET_PAYMENT_REQUIRED",
28631
+ MARKET_ORDER_NOT_FOUND: "MARKET_ORDER_NOT_FOUND",
28632
+ MARKET_ALREADY_PURCHASED: "MARKET_ALREADY_PURCHASED",
28633
+ KNOWLEDGE_POST_NOT_FOUND: "KNOWLEDGE_POST_NOT_FOUND",
28634
+ KNOWLEDGE_SCOPE_FORBIDDEN: "KNOWLEDGE_SCOPE_FORBIDDEN",
28635
+ // 4rum post / Messenger message missing or not visible — also a cursor anchor (ADR-0341/0361)
28636
+ POST_NOT_FOUND: "POST_NOT_FOUND",
28637
+ MESSAGE_NOT_FOUND: "MESSAGE_NOT_FOUND",
28638
+ PACKAGE_ALREADY_INSTALLED: "PACKAGE_ALREADY_INSTALLED",
28639
+ // org total hosted storage cap (ADR-0122/0365) — blocks text writes, uploads, memo/book writes and new AI runs
28640
+ STORAGE_QUOTA_EXCEEDED: "STORAGE_QUOTA_EXCEEDED",
28641
+ // Self-managed storage clear (ADR-0365): typed org-name confirmation mismatch; a kind the service
28642
+ // cannot clear; a clear already running for the org.
28643
+ STORAGE_CLEAR_CONFIRM_MISMATCH: "STORAGE_CLEAR_CONFIRM_MISMATCH",
28644
+ STORAGE_CLEAR_KIND_INVALID: "STORAGE_CLEAR_KIND_INVALID",
28645
+ STORAGE_CLEAR_RUNNING: "STORAGE_CLEAR_RUNNING",
28646
+ // project lifecycle (ADR-0092): invalid transition / operation on a paused|closed project
28647
+ PROJECT_STATE_INVALID: "PROJECT_STATE_INVALID",
28648
+ PROJECT_NOT_ACTIVE: "PROJECT_NOT_ACTIVE",
28649
+ // user pause (ADR-0093): user is paused (blocks login/API/token/WS) / invalid pause transition
28650
+ USER_PAUSED: "USER_PAUSED",
28651
+ USER_STATE_INVALID: "USER_STATE_INVALID",
28652
+ // org pause (ADR-0094 admin-0013): whole org paused ⇒ blocks all its users' login/API/token
28653
+ ORG_PAUSED: "ORG_PAUSED",
28654
+ // project-membership pause (ADR-0093): invalid membership pause transition
28655
+ MEMBER_STATE_INVALID: "MEMBER_STATE_INVALID",
28656
+ // soft-delete restore (ADR-0109): restore a record that is not currently deleted
28657
+ PROJECT_NOT_DELETED: "PROJECT_NOT_DELETED",
28658
+ TEAM_NOT_DELETED: "TEAM_NOT_DELETED",
28659
+ USER_NOT_DELETED: "USER_NOT_DELETED",
28660
+ USERNAME_TAKEN: "USERNAME_TAKEN",
28661
+ EMAIL_TAKEN: "EMAIL_TAKEN",
28662
+ // email omitted while the org disallows sub-accounts without email (ADR-0039)
28663
+ EMAIL_REQUIRED: "EMAIL_REQUIRED",
28664
+ // contact-change (self email/phone) verification (ADR-0046)
28665
+ // email and phone cannot be changed in the same request
28666
+ CONTACT_CHANGE_BOTH: "CONTACT_CHANGE_BOTH",
28667
+ // a contact-change is already pending — resolve it before editing again
28668
+ CONTACT_CHANGE_PENDING: "CONTACT_CHANGE_PENDING",
28669
+ // the verifying channel is missing (e.g. no phone on file to OTP an email change)
28670
+ CONTACT_CHANGE_CHANNEL_MISSING: "CONTACT_CHANGE_CHANNEL_MISSING",
28671
+ // the submitted OTP / link token is invalid or expired
28672
+ CONTACT_CHANGE_INVALID: "CONTACT_CHANGE_INVALID",
28673
+ // self email/phone must go through the contact-change flow (not a direct update)
28674
+ CONTACT_CHANGE_REQUIRED: "CONTACT_CHANGE_REQUIRED",
28675
+ ROLE_EXCLUSIVE: "ROLE_EXCLUSIVE",
28676
+ ROOT_IMMUTABLE: "ROOT_IMMUTABLE",
28677
+ // ADMIN role is reserved for the org root; it cannot be granted to sub-accounts
28678
+ ADMIN_ROLE_RESERVED: "ADMIN_ROLE_RESERVED",
28679
+ // a PM may only assign roles below PM (never PM/ADMIN/MACHINE) — anti-escalation (ADR-0051)
28680
+ USER_ROLE_ASSIGN_FORBIDDEN: "USER_ROLE_ASSIGN_FORBIDDEN",
28681
+ // an ADMIN account manages the org only — it cannot be attached to teams/projects
28682
+ ADMIN_NOT_ASSIGNABLE: "ADMIN_NOT_ASSIGNABLE",
28683
+ // a MACHINE account is a worker — it cannot be a project manager (ADR-0041)
28684
+ MACHINE_NOT_MANAGER: "MACHINE_NOT_MANAGER",
28685
+ // a MACHINE account may be a member of at most one project (ADR-0041)
28686
+ MACHINE_ALREADY_IN_PROJECT: "MACHINE_ALREADY_IN_PROJECT",
28687
+ // a MACHINE account is a worker, not a human member — it cannot join a team (ADR-0041)
28688
+ MACHINE_NOT_TEAM_MEMBER: "MACHINE_NOT_TEAM_MEMBER",
28689
+ ALREADY_ATTACHED: "ALREADY_ATTACHED",
28690
+ NOT_ATTACHED: "NOT_ATTACHED",
28691
+ SELF_DELETE_FORBIDDEN: "SELF_DELETE_FORBIDDEN",
28692
+ SELF_SET_PASSWORD_FORBIDDEN: "SELF_SET_PASSWORD_FORBIDDEN",
28693
+ AVATAR_INVALID_TYPE: "AVATAR_INVALID_TYPE",
28694
+ AVATAR_TOO_LARGE: "AVATAR_TOO_LARGE",
28695
+ // permission
28696
+ PERMISSION_CODE_INVALID: "PERMISSION_CODE_INVALID",
28697
+ SUBJECT_INVALID: "SUBJECT_INVALID",
28698
+ // machine
28699
+ HASHCODE_INVALID: "HASHCODE_INVALID",
28700
+ HASHCODE_EXPIRED: "HASHCODE_EXPIRED",
28701
+ LINK_REVOKED: "LINK_REVOKED",
28702
+ LINK_NOT_FOUND: "LINK_NOT_FOUND",
28703
+ WORKER_OFFLINE: "WORKER_OFFLINE",
28704
+ // command-0001 pick:"idle" (ADR-0171) — no idle cli in the project's pool
28705
+ ALL_CLIS_BUSY: "ALL_CLIS_BUSY",
28706
+ // worker pools (ADR-0284)
28707
+ WORKER_POOL_NOT_FOUND: "WORKER_POOL_NOT_FOUND",
28708
+ WORKER_POOL_NAME_TAKEN: "WORKER_POOL_NAME_TAKEN",
28709
+ WORKER_POOL_ATTACHED: "WORKER_POOL_ATTACHED",
28710
+ WORKER_POOL_ALREADY_ATTACHED: "WORKER_POOL_ALREADY_ATTACHED",
28711
+ MACHINE_ALREADY_IN_POOL: "MACHINE_ALREADY_IN_POOL",
28712
+ NOT_MACHINE_USER: "NOT_MACHINE_USER",
28713
+ // worker · physic project
28714
+ WORKER_NOT_FOUND: "WORKER_NOT_FOUND",
28715
+ PHYSIC_PROJECT_NOT_FOUND: "PHYSIC_PROJECT_NOT_FOUND",
28716
+ PHYSIC_PATH_OCCUPIED: "PHYSIC_PATH_OCCUPIED",
28717
+ AUTONOMOUS_CONFLICT: "AUTONOMOUS_CONFLICT",
28718
+ // A disruptive worker op (repo (re)provision / CLI update) was refused because the target
28719
+ // worker's autonomous mode is armed (installed && !paused) — stop it first (ADR-0317).
28720
+ AUTONOMOUS_ACTIVE: "AUTONOMOUS_ACTIVE",
28721
+ // Separation of duties (ADR-0320): a non-ADMIN tried to approve a row they wrote — the writer can't
28722
+ // be the approver of their own row (ADMIN may self-approve).
28723
+ APPROVAL_SELF: "APPROVAL_SELF",
28724
+ CLI_VERSION_UNSUPPORTED: "CLI_VERSION_UNSUPPORTED",
28725
+ // Admin cli version policy rejected (ADR-0363) — meta.reason: minAboveLatest | latestNotBlockable |
28726
+ // deadlinePast | invalidVersion.
28727
+ CLI_VERSION_POLICY_INVALID: "CLI_VERSION_POLICY_INVALID",
28728
+ ORCHESTRATOR_OFFLINE: "ORCHESTRATOR_OFFLINE",
28729
+ WS_TOKEN_INVALID: "WS_TOKEN_INVALID",
28730
+ // A newer cli session for the same link took over ⇒ the older one stops (ADR-0047).
28731
+ SESSION_REPLACED: "SESSION_REPLACED",
28732
+ PATH_INVALID: "PATH_INVALID",
28733
+ // project create/add
28734
+ SPEC_INVALID: "SPEC_INVALID",
28735
+ PATH_OCCUPIED: "PATH_OCCUPIED",
28736
+ GIT_ENV_MISSING: "GIT_ENV_MISSING",
28737
+ CLAUDE_CLI_MISSING: "CLAUDE_CLI_MISSING",
28738
+ SCAFFOLD_FAILED: "SCAFFOLD_FAILED",
28739
+ GIT_OPERATION_FAILED: "GIT_OPERATION_FAILED",
28740
+ AI_INIT_FAILED: "AI_INIT_FAILED",
28741
+ // AI spec-assist (suggest/review/compose) run failed on the worker cli (ADR-0100).
28742
+ AI_ASSIST_FAILED: "AI_ASSIST_FAILED",
28743
+ // Client-side guard (ADR-0255): the built AI prompt is longer than AI_PROMPT_MAX_LEN, so the
28744
+ // web blocks the dispatch and shows an actionable "spec too large" message instead of letting
28745
+ // the server reject it as a confusing VALIDATION_FAILED.
28746
+ AI_PROMPT_TOO_LARGE: "AI_PROMPT_TOO_LARGE",
28747
+ REPO_NOT_FOUND: "REPO_NOT_FOUND",
28748
+ // invitation
28749
+ INVITATION_TOKEN_INVALID: "INVITATION_TOKEN_INVALID",
28750
+ INVITATION_ALREADY_ACCEPTED: "INVITATION_ALREADY_ACCEPTED",
28751
+ INVITATION_ROLE_FORBIDDEN: "INVITATION_ROLE_FORBIDDEN",
28752
+ // notification
28753
+ NOTIFICATION_NOT_FOUND: "NOTIFICATION_NOT_FOUND",
28754
+ // sso (ADR-0024)
28755
+ SSO_IDENTITY_NOT_LINKED: "SSO_IDENTITY_NOT_LINKED",
28756
+ SSO_PROVIDER_INVALID: "SSO_PROVIDER_INVALID",
28757
+ // Cannot unlink the last remaining login method (SSO-only user, ADR-0161)
28758
+ SSO_LAST_LOGIN_METHOD: "SSO_LAST_LOGIN_METHOD",
28759
+ PASSWORD_NOT_SET: "PASSWORD_NOT_SET",
28760
+ // command · memo
28761
+ COMMAND_NOT_FOUND: "COMMAND_NOT_FOUND",
28762
+ // Stop requested for a command that already settled (done/failed/cancelled — ADR-0362).
28763
+ COMMAND_ALREADY_FINISHED: "COMMAND_ALREADY_FINISHED",
28764
+ COMMAND_DISPATCH_LIMITED: "COMMAND_DISPATCH_LIMITED",
28765
+ QUOTA_EXCEEDED: "QUOTA_EXCEEDED",
28766
+ // A single prompt's estimated tokens exceed project `settings.tokens.perPromptTokenLimit` (ADR-0081).
28767
+ PROMPT_TOKEN_LIMIT_EXCEEDED: "PROMPT_TOKEN_LIMIT_EXCEEDED",
28768
+ // An outbound cli evaluated the input as NG (secret/path/repo/environment) — ADR-0082.
28769
+ OUTBOUND_REVIEW_REJECTED: "OUTBOUND_REVIEW_REJECTED",
28770
+ // No outbound cli available (offline/busy/out-of-token) while review is on — ADR-0082.
28771
+ OUTBOUND_REVIEW_UNAVAILABLE: "OUTBOUND_REVIEW_UNAVAILABLE",
28772
+ // A saved outbound rule regex fails to compile or is ReDoS-unsafe (ADR-0087).
28773
+ OUTBOUND_RULE_INVALID: "OUTBOUND_RULE_INVALID",
28774
+ // Console image attachment blocked because the project has `outboundReview.blockImages` (ADR-0257).
28775
+ IMAGE_UPLOAD_BLOCKED: "IMAGE_UPLOAD_BLOCKED",
28776
+ MEMO_TOO_LONG: "MEMO_TOO_LONG",
28777
+ // plan entitlements (ADR-0105) — resource caps + feature gates per plan tier
28778
+ PLAN_USER_LIMIT: "PLAN_USER_LIMIT",
28779
+ PLAN_PROJECT_LIMIT: "PLAN_PROJECT_LIMIT",
28780
+ // Plan memo-item cap reached (`maxMemoItems` — ADR-0365).
28781
+ PLAN_MEMO_LIMIT: "PLAN_MEMO_LIMIT",
28782
+ // An autonomous book reached its monthly `autonomousRequestsPerMonth` cap (ADR-0365).
28783
+ AUTONOMOUS_BOOK_CAP_REACHED: "AUTONOMOUS_BOOK_CAP_REACHED",
28784
+ PLAN_FEATURE_UNAVAILABLE: "PLAN_FEATURE_UNAVAILABLE",
28785
+ // deployment license ceiling (ADR-0135) — a self-host license bounds orgs/seats/projects/
28786
+ // storage across the whole deployment, above the per-org plan caps
28787
+ LICENSE_LIMIT_EXCEEDED: "LICENSE_LIMIT_EXCEEDED",
28788
+ // billing add-ons & rented machine-users (ADR-0123/0126) — payment-server · admin-server
28789
+ // buying an add-on without an active paid plan (ADR-0123)
28790
+ ADDON_REQUIRES_PLAN: "ADDON_REQUIRES_PLAN",
28791
+ // renting a machine-user with no free pool slot (ADR-0126) — the org may be waitlisted
28792
+ NO_HOSTED_SLOT_AVAILABLE: "NO_HOSTED_SLOT_AVAILABLE",
28793
+ // admin changing a rented hosted slot without forceRelease (ADR-0126)
28794
+ SLOT_RENTED: "SLOT_RENTED",
28795
+ // re-renting a machine whose rental is already `releasing` — too late to undo (ADR-0210)
28796
+ RENTED_MACHINE_RELEASING: "RENTED_MACHINE_RELEASING",
28797
+ // credit wallet & coupons (ADR-0118/0119/0120) — served by payment-server
28798
+ CREDIT_INSUFFICIENT: "CREDIT_INSUFFICIENT",
28799
+ COUPON_NOT_FOUND: "COUPON_NOT_FOUND",
28800
+ COUPON_EXPIRED: "COUPON_EXPIRED",
28801
+ COUPON_DISABLED: "COUPON_DISABLED",
28802
+ COUPON_EXHAUSTED: "COUPON_EXHAUSTED",
28803
+ COUPON_ALREADY_REDEEMED: "COUPON_ALREADY_REDEEMED",
28804
+ // payment-server catalog completion (ADR-0207) — credit/addon/plan errors that previously
28805
+ // threw raw strings or literals duplicated inside payment-server; now first-class codes.
28806
+ // credit mutation validation (credit.service)
28807
+ INVALID_AMOUNT: "INVALID_AMOUNT",
28808
+ INVALID_DELTA: "INVALID_DELTA",
28809
+ TOPUP_NOT_FOUND: "TOPUP_NOT_FOUND",
28810
+ // storage add-on SKU management (addon.service — admin-0031/0032)
28811
+ STORAGE_SKU_INVALID: "STORAGE_SKU_INVALID",
28812
+ STORAGE_SKU_NOT_FOUND: "STORAGE_SKU_NOT_FOUND",
28813
+ STORAGE_SIZE_INVALID: "STORAGE_SIZE_INVALID",
28814
+ ADDON_CODE_EXISTS: "ADDON_CODE_EXISTS",
28815
+ ADDON_PRICE_INVALID: "ADDON_PRICE_INVALID",
28816
+ ADDON_PRODUCT_UNKNOWN: "ADDON_PRODUCT_UNKNOWN",
28817
+ ADDON_QUANTITY_INVALID: "ADDON_QUANTITY_INVALID",
28818
+ ADDON_NOT_FOUND: "ADDON_NOT_FOUND",
28819
+ // plan / subscription lifecycle (billing.service — ADR-0163/0142)
28820
+ PLAN_CODE_REQUIRED: "PLAN_CODE_REQUIRED",
28821
+ PLAN_UNCHANGED: "PLAN_UNCHANGED",
28822
+ PLAN_CHANGE_INVALID: "PLAN_CHANGE_INVALID",
28823
+ NO_ACTIVE_SUBSCRIPTION: "NO_ACTIVE_SUBSCRIPTION",
28824
+ NO_PROVIDER_SUBSCRIPTION: "NO_PROVIDER_SUBSCRIPTION",
28825
+ ENTERPRISE_PLAN_NOT_ASSIGNABLE: "ENTERPRISE_PLAN_NOT_ASSIGNABLE",
28826
+ PAYMENT_FAILED: "PAYMENT_FAILED",
28827
+ // support tickets (ADR-0167) + AI help agent (ADR-0168)
28828
+ SUPPORT_TICKET_NOT_FOUND: "SUPPORT_TICKET_NOT_FOUND",
28829
+ // managed legal documents (ADR-0350): unknown/disabled document; accepting a version that is not current
28830
+ LEGAL_DOCUMENT_NOT_FOUND: "LEGAL_DOCUMENT_NOT_FOUND",
28831
+ LEGAL_VERSION_OUTDATED: "LEGAL_VERSION_OUTDATED",
28832
+ SUPPORT_TICKET_CLOSED: "SUPPORT_TICKET_CLOSED",
28833
+ // public (guest) support create (ADR-0279): the self-hosted captcha answer was wrong/expired.
28834
+ CAPTCHA_INVALID: "CAPTCHA_INVALID",
28835
+ HELP_POOL_UNAVAILABLE: "HELP_POOL_UNAVAILABLE",
28836
+ // AI Help daily cap reached (ADR-0286): the asker (or their org) exceeded the per-day question
28837
+ // cap; meta carries { scope, limit, used, resetAt }. Thrown before any dispatch (0 token cost).
28838
+ HELP_RATE_LIMITED: "HELP_RATE_LIMITED",
28839
+ // AI Help admin moderation (ADR-0237): the user/org is blocked from the channel, or the whole
28840
+ // AI support service is toggled off platform-wide.
28841
+ HELP_BLOCKED: "HELP_BLOCKED",
28842
+ HELP_DISABLED: "HELP_DISABLED",
28843
+ // Project GitHub-App git-auth (ADR-0356): method set without a credential; a rejected credential
28844
+ // (App ID / PEM / host / CA); an ssh repo URL under the App method; the primary repo's host differs
28845
+ // from the credential host; the server has no SECRETS_ENC_KEY to store/read secrets.
28846
+ GIT_CREDENTIAL_MISSING: "GIT_CREDENTIAL_MISSING",
28847
+ GIT_CREDENTIAL_INVALID: "GIT_CREDENTIAL_INVALID",
28848
+ GIT_AUTH_REQUIRES_HTTPS: "GIT_AUTH_REQUIRES_HTTPS",
28849
+ GIT_HOST_MISMATCH: "GIT_HOST_MISMATCH",
28850
+ SECRETS_KEY_NOT_CONFIGURED: "SECRETS_KEY_NOT_CONFIGURED",
28851
+ // Org announcements (ADR-0367): a target outside the sender's PM/TL scope; targets resolving to
28852
+ // nobody; the org's daily recipient cap (`announcementDailyRecipients`); unknown history row /
28853
+ // draft; the per-user draft cap.
28854
+ ANNOUNCEMENT_TARGET_FORBIDDEN: "ANNOUNCEMENT_TARGET_FORBIDDEN",
28855
+ ANNOUNCEMENT_NO_RECIPIENTS: "ANNOUNCEMENT_NO_RECIPIENTS",
28856
+ ANNOUNCEMENT_DAILY_LIMIT: "ANNOUNCEMENT_DAILY_LIMIT",
28857
+ ANNOUNCEMENT_NOT_FOUND: "ANNOUNCEMENT_NOT_FOUND",
28858
+ ANNOUNCEMENT_DRAFT_NOT_FOUND: "ANNOUNCEMENT_DRAFT_NOT_FOUND",
28859
+ ANNOUNCEMENT_DRAFT_LIMIT: "ANNOUNCEMENT_DRAFT_LIMIT",
28860
+ // Worker-cli operation failures surfaced to the web/admin so they localize via `errors.*`
28861
+ // (see CLI_ERROR_CODE_MAP below): filesystem guards, RAG, agent/content validation, support
28862
+ // answer, FAQ compose, git host, autonomous base push.
28863
+ WORKER_PATH_ESCAPES_ROOT: "WORKER_PATH_ESCAPES_ROOT",
28864
+ WORKER_NO_PROJECT: "WORKER_NO_PROJECT",
28865
+ WORKER_PATH_EXISTS: "WORKER_PATH_EXISTS",
28866
+ WORKER_ROOT_PROTECTED: "WORKER_ROOT_PROTECTED",
28867
+ WORKER_NOT_A_FILE: "WORKER_NOT_A_FILE",
28868
+ WORKER_INVALID_PAYLOAD: "WORKER_INVALID_PAYLOAD",
28869
+ WORKER_INVALID_NAME: "WORKER_INVALID_NAME",
28870
+ WORKER_CONTENT_REQUIRED: "WORKER_CONTENT_REQUIRED",
28871
+ RAG_PYTHON_MISSING: "RAG_PYTHON_MISSING",
28872
+ RAG_NOT_INSTALLED: "RAG_NOT_INSTALLED",
28873
+ RAG_NO_INDEX: "RAG_NO_INDEX",
28874
+ RAG_INVALID_MODEL: "RAG_INVALID_MODEL",
28875
+ SUPPORT_KB_EMPTY: "SUPPORT_KB_EMPTY",
28876
+ SUPPORT_EMPTY_ANSWER: "SUPPORT_EMPTY_ANSWER",
28877
+ FAQ_NO_WRITE_TOKEN: "FAQ_NO_WRITE_TOKEN",
28878
+ GIT_UNKNOWN_HOST: "GIT_UNKNOWN_HOST",
28879
+ AUTONOMOUS_BASE_PUSH_FAILED: "AUTONOMOUS_BASE_PUSH_FAILED"
28880
+ };
28881
+ var CLI_ERROR_CODE_MAP = {
28882
+ "path escapes the project root": { code: ErrorCode.WORKER_PATH_ESCAPES_ROOT, status: 422 },
28883
+ "no project served": { code: ErrorCode.WORKER_NO_PROJECT, status: 409 },
28884
+ "no project": { code: ErrorCode.WORKER_NO_PROJECT, status: 409 },
28885
+ "This worker has no project folder.": { code: ErrorCode.WORKER_NO_PROJECT, status: 409 },
28886
+ "already exists": { code: ErrorCode.WORKER_PATH_EXISTS, status: 409 },
28887
+ "destination already exists": { code: ErrorCode.WORKER_PATH_EXISTS, status: 409 },
28888
+ "cannot move the project root": { code: ErrorCode.WORKER_ROOT_PROTECTED, status: 422 },
28889
+ "cannot delete the project root": { code: ErrorCode.WORKER_ROOT_PROTECTED, status: 422 },
28890
+ "not a file": { code: ErrorCode.WORKER_NOT_A_FILE, status: 422 },
28891
+ "invalid base64 payload": { code: ErrorCode.WORKER_INVALID_PAYLOAD, status: 422 },
28892
+ "invalid name": { code: ErrorCode.WORKER_INVALID_NAME, status: 422 },
28893
+ "content is required": { code: ErrorCode.WORKER_CONTENT_REQUIRED, status: 422 },
28894
+ "invalid slug": { code: ErrorCode.MARKET_INVALID_PACKAGE, status: 422 },
28895
+ "artifact not found": { code: ErrorCode.MARKET_PACKAGE_NOT_FOUND, status: 404 },
28896
+ "not installed": { code: ErrorCode.MARKET_PACKAGE_NOT_FOUND, status: 404 },
28897
+ "python3 not found": { code: ErrorCode.RAG_PYTHON_MISSING, status: 422 },
28898
+ "python3 not found on the worker": { code: ErrorCode.RAG_PYTHON_MISSING, status: 422 },
28899
+ "RAG is not installed": { code: ErrorCode.RAG_NOT_INSTALLED, status: 409 },
28900
+ "no index \u2014 reindex first": { code: ErrorCode.RAG_NO_INDEX, status: 409 },
28901
+ "invalid model name": { code: ErrorCode.RAG_INVALID_MODEL, status: 422 },
28902
+ "KB repo has no documentation": { code: ErrorCode.SUPPORT_KB_EMPTY, status: 422 },
28903
+ "empty answer": { code: ErrorCode.SUPPORT_EMPTY_ANSWER, status: 422 },
28904
+ "no write token": { code: ErrorCode.FAQ_NO_WRITE_TOKEN, status: 422 },
28905
+ "Unknown git host \u2014 no pull request opened.": { code: ErrorCode.GIT_UNKNOWN_HOST, status: 422 },
28906
+ "could not push the change to the base branch (retry)": { code: ErrorCode.AUTONOMOUS_BASE_PUSH_FAILED, status: 422 },
28907
+ "self-approval blocked": { code: ErrorCode.APPROVAL_SELF, status: 409 }
28908
+ };
28909
+
28572
28910
  // vendor/@4pm/constants/preferences.ts
28573
28911
  var Locale = {
28574
28912
  VI: "vi",
@@ -28930,7 +29268,11 @@ var en_default = {
28930
29268
  "autoRun.failed": "Autonomous cycle failed to dispatch: {note}",
28931
29269
  "autoRun.noDaemon": 'No running daemon for profile "{profile}" \u2014 start it first: 4pm start --profile {profile}',
28932
29270
  "autoRun.timeout": "Autonomous cycle exceeded the time limit \u2014 aborting.",
28933
- "autoRun.authFailed": "Control-channel authentication failed \u2014 the daemon rejected the token."
29271
+ "autoRun.authFailed": "Control-channel authentication failed \u2014 the daemon rejected the token.",
29272
+ "autonomous.cronMissing": "Could not install the autonomous cron: this worker has no working `crontab` (cron service). Autonomous scheduling requires cron on the worker machine.",
29273
+ "autonomous.settingsInvalidJson": "The autonomous settings are not valid JSON.",
29274
+ "config.notObject": "config.json must be a JSON object.",
29275
+ "config.invalidJson": "Invalid JSON: {message}"
28934
29276
  };
28935
29277
 
28936
29278
  // src/i18n/messages/vi.json
@@ -29115,7 +29457,11 @@ var vi_default = {
29115
29457
  "autoRun.failed": "Kh\xF4ng \u0111i\u1EC1u ph\u1ED1i \u0111\u01B0\u1EE3c chu k\u1EF3 t\u1EF1 \u0111\u1ED9ng: {note}",
29116
29458
  "autoRun.noDaemon": 'Kh\xF4ng c\xF3 ti\u1EBFn tr\xECnh n\u1EC1n n\xE0o cho h\u1ED3 s\u01A1 "{profile}" \u2014 h\xE3y kh\u1EDFi \u0111\u1ED9ng tr\u01B0\u1EDBc: 4pm start --profile {profile}',
29117
29459
  "autoRun.timeout": "Chu k\u1EF3 t\u1EF1 \u0111\u1ED9ng v\u01B0\u1EE3t qu\xE1 gi\u1EDBi h\u1EA1n th\u1EDDi gian \u2014 \u0111ang h\u1EE7y.",
29118
- "autoRun.authFailed": "X\xE1c th\u1EF1c k\xEAnh \u0111i\u1EC1u khi\u1EC3n th\u1EA5t b\u1EA1i \u2014 daemon t\u1EEB ch\u1ED1i token."
29460
+ "autoRun.authFailed": "X\xE1c th\u1EF1c k\xEAnh \u0111i\u1EC1u khi\u1EC3n th\u1EA5t b\u1EA1i \u2014 daemon t\u1EEB ch\u1ED1i token.",
29461
+ "autonomous.cronMissing": "Kh\xF4ng c\xE0i \u0111\u01B0\u1EE3c cron t\u1EF1 h\xE0nh: worker n\xE0y kh\xF4ng c\xF3 `crontab` ho\u1EA1t \u0111\u1ED9ng (d\u1ECBch v\u1EE5 cron). L\u1EADp l\u1ECBch t\u1EF1 h\xE0nh c\u1EA7n cron tr\xEAn m\xE1y worker.",
29462
+ "autonomous.settingsInvalidJson": "C\u1EA5u h\xECnh t\u1EF1 h\xE0nh kh\xF4ng ph\u1EA3i JSON h\u1EE3p l\u1EC7.",
29463
+ "config.notObject": "config.json ph\u1EA3i l\xE0 m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng JSON.",
29464
+ "config.invalidJson": "JSON kh\xF4ng h\u1EE3p l\u1EC7: {message}"
29119
29465
  };
29120
29466
 
29121
29467
  // src/i18n/messages/ja.json
@@ -29300,7 +29646,11 @@ var ja_default = {
29300
29646
  "autoRun.failed": "\u81EA\u5F8B\u30B5\u30A4\u30AF\u30EB\u306E\u30C7\u30A3\u30B9\u30D1\u30C3\u30C1\u306B\u5931\u6557\u3057\u307E\u3057\u305F: {note}",
29301
29647
  "autoRun.noDaemon": '\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB "{profile}" \u306E\u30C7\u30FC\u30E2\u30F3\u304C\u5B9F\u884C\u3055\u308C\u3066\u3044\u307E\u305B\u3093 \u2014 \u5148\u306B\u8D77\u52D5\u3057\u3066\u304F\u3060\u3055\u3044: 4pm start --profile {profile}',
29302
29648
  "autoRun.timeout": "\u81EA\u5F8B\u30B5\u30A4\u30AF\u30EB\u304C\u5236\u9650\u6642\u9593\u3092\u8D85\u3048\u307E\u3057\u305F \u2014 \u4E2D\u6B62\u3057\u307E\u3059\u3002",
29303
- "autoRun.authFailed": "\u30B3\u30F3\u30C8\u30ED\u30FC\u30EB\u30C1\u30E3\u30CD\u30EB\u306E\u8A8D\u8A3C\u306B\u5931\u6557\u3057\u307E\u3057\u305F \u2014 \u30C7\u30FC\u30E2\u30F3\u304C\u30C8\u30FC\u30AF\u30F3\u3092\u62D2\u5426\u3057\u307E\u3057\u305F\u3002"
29649
+ "autoRun.authFailed": "\u30B3\u30F3\u30C8\u30ED\u30FC\u30EB\u30C1\u30E3\u30CD\u30EB\u306E\u8A8D\u8A3C\u306B\u5931\u6557\u3057\u307E\u3057\u305F \u2014 \u30C7\u30FC\u30E2\u30F3\u304C\u30C8\u30FC\u30AF\u30F3\u3092\u62D2\u5426\u3057\u307E\u3057\u305F\u3002",
29650
+ "autonomous.cronMissing": "\u81EA\u5F8B cron \u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F: \u3053\u306E\u30EF\u30FC\u30AB\u30FC\u306B\u306F\u52D5\u4F5C\u3059\u308B `crontab`\uFF08cron \u30B5\u30FC\u30D3\u30B9\uFF09\u304C\u3042\u308A\u307E\u305B\u3093\u3002\u81EA\u5F8B\u30B9\u30B1\u30B8\u30E5\u30FC\u30EA\u30F3\u30B0\u306B\u306F\u30EF\u30FC\u30AB\u30FC\u30DE\u30B7\u30F3\u306E cron \u304C\u5FC5\u8981\u3067\u3059\u3002",
29651
+ "autonomous.settingsInvalidJson": "\u81EA\u5F8B\u8A2D\u5B9A\u304C\u6709\u52B9\u306A JSON \u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002",
29652
+ "config.notObject": "config.json \u306F JSON \u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002",
29653
+ "config.invalidJson": "\u7121\u52B9\u306A JSON: {message}"
29304
29654
  };
29305
29655
 
29306
29656
  // src/i18n/messages/zh.json
@@ -29485,7 +29835,11 @@ var zh_default = {
29485
29835
  "autoRun.failed": "\u81EA\u4E3B\u5FAA\u73AF\u8C03\u5EA6\u5931\u8D25\uFF1A{note}",
29486
29836
  "autoRun.noDaemon": "\u914D\u7F6E\u6587\u4EF6 \u201C{profile}\u201D \u6CA1\u6709\u6B63\u5728\u8FD0\u884C\u7684\u5B88\u62A4\u8FDB\u7A0B \u2014 \u8BF7\u5148\u542F\u52A8\uFF1A4pm start --profile {profile}",
29487
29837
  "autoRun.timeout": "\u81EA\u4E3B\u5FAA\u73AF\u8D85\u8FC7\u65F6\u95F4\u9650\u5236 \u2014 \u6B63\u5728\u4E2D\u6B62\u3002",
29488
- "autoRun.authFailed": "\u63A7\u5236\u901A\u9053\u8BA4\u8BC1\u5931\u8D25 \u2014 \u5B88\u62A4\u8FDB\u7A0B\u62D2\u7EDD\u4E86\u4EE4\u724C\u3002"
29838
+ "autoRun.authFailed": "\u63A7\u5236\u901A\u9053\u8BA4\u8BC1\u5931\u8D25 \u2014 \u5B88\u62A4\u8FDB\u7A0B\u62D2\u7EDD\u4E86\u4EE4\u724C\u3002",
29839
+ "autonomous.cronMissing": "\u65E0\u6CD5\u5B89\u88C5\u81EA\u4E3B cron\uFF1A\u6B64\u5DE5\u4F5C\u673A\u6CA1\u6709\u53EF\u7528\u7684 `crontab`\uFF08cron \u670D\u52A1\uFF09\u3002\u81EA\u4E3B\u8C03\u5EA6\u9700\u8981\u5DE5\u4F5C\u673A\u4E0A\u7684 cron\u3002",
29840
+ "autonomous.settingsInvalidJson": "\u81EA\u4E3B\u8BBE\u7F6E\u4E0D\u662F\u6709\u6548\u7684 JSON\u3002",
29841
+ "config.notObject": "config.json \u5FC5\u987B\u662F JSON \u5BF9\u8C61\u3002",
29842
+ "config.invalidJson": "\u65E0\u6548\u7684 JSON\uFF1A{message}"
29489
29843
  };
29490
29844
 
29491
29845
  // src/i18n/messages/index.ts
@@ -41276,7 +41630,7 @@ async function installCron(root, profileDir2) {
41276
41630
  await chmod(script, 493).catch(() => void 0);
41277
41631
  const kept = (await crontabList()).split("\n").filter((l) => l.trim() && !l.includes(script));
41278
41632
  kept.push(`${cfg.cronSchedule} ${script}`);
41279
- await crontabSet(kept.join("\n"));
41633
+ return crontabSet(kept.join("\n"));
41280
41634
  }
41281
41635
  async function syncCron(root, profileDir2) {
41282
41636
  if (await cronInstalled(root)) await installCron(root, profileDir2);
@@ -41353,12 +41707,16 @@ async function writeAutonomous(root, profileDir2, req, by) {
41353
41707
  try {
41354
41708
  if (req.kind === "settings") {
41355
41709
  const parsed = parseJson(req.settings);
41356
- if (!parsed) return { ok: false, error: "settings is not valid JSON" };
41710
+ if (!parsed) return { ok: false, error: t("autonomous.settingsInvalidJson") };
41357
41711
  await writeAutonomousConfig(profileDir2, parsed);
41358
41712
  await syncCron(root, profileDir2);
41359
41713
  } else if (req.kind === "cron") {
41360
- if (req.action === "install") await installCron(root, profileDir2);
41361
- else await uninstallCron(root);
41714
+ if (req.action === "install") {
41715
+ const wrote = await installCron(root, profileDir2);
41716
+ if (!wrote || !await cronInstalled(root)) {
41717
+ return { ok: false, error: t("autonomous.cronMissing") };
41718
+ }
41719
+ } else await uninstallCron(root);
41362
41720
  } else {
41363
41721
  const base = (await resolveBases(root).catch(() => null))?.root.base ?? "";
41364
41722
  let res;
@@ -46369,10 +46727,10 @@ function applyConfigText(profileDir2, text) {
46369
46727
  try {
46370
46728
  parsed = JSON.parse(text);
46371
46729
  } catch (err) {
46372
- return { ok: false, error: `Invalid JSON: ${err.message}` };
46730
+ return { ok: false, error: t("config.invalidJson", { message: err.message }) };
46373
46731
  }
46374
46732
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
46375
- return { ok: false, error: "config.json must be a JSON object." };
46733
+ return { ok: false, error: t("config.notObject") };
46376
46734
  }
46377
46735
  const next = { ...parsed };
46378
46736
  const current2 = readProfileConfig(profileDir2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@4pm/cli",
3
- "version": "1.30.0",
3
+ "version": "1.31.0",
4
4
  "private": false,
5
5
  "description": "4PM CLI — drives Claude/Codex CLIs on AI worker machines (Node + TypeScript)",
6
6
  "license": "LicenseRef-4PM-Source-Available",