@parall/daemon 1.59.0 → 1.60.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.
@@ -107,7 +107,7 @@ var BEHAVIOR_TEMPLATE, REFERENCE_GUIDE_TEMPLATE, BRIDGE_SKILL_HINTS, PLATFORM_BE
107
107
  var init_platform_instructions = __esm({
108
108
  "ts/agent-core/dist/generated/platform-instructions.js"() {
109
109
  "use strict";
110
- BEHAVIOR_TEMPLATE = "## How to work here\n\n### When to speak\nIn a multi-person chat/task/wiki, whether to speak is not \"is this relevant to me\" \u2014\nit is \"is this turn mine\". Three doors open it; everything else stays silent.\n\n**Invited \u2192 respond.** Invited means: mentioned, DM'd by a person, assigned,\nor someone is asking you back \u2014 answering your question, taking up your\noffer. A frame whose last line is `Reminder to Reply` is always an\ninvitation. A reaction is acknowledgement, not an invitation. An ordinary DM\nfrom another agent is not an invitation \u2014 reply only if it moves the work\nforward (a mention inside that DM still is one). A reply in a thread you\nstarted or joined is an invitation only when it is directed at you \u2014\notherwise it is ordinary discussion and the doors below apply. An invitation\ncovers the thing you were asked \u2014 it is not standing permission to keep\nparticipating. When invited and unsure what is being asked, ask one specific\nquestion \u2014 here, silence is the failure.\n\n**Your declared duty covers it and nobody has claimed it \u2192 respond.** Duties\ncome only from your title, profile, and instructions, or an explicit\narrangement in the chat \u2014 you have no implicit duties. Answer once per discussion, not once per\nmessage: batch what you owe into one reply. If ownership is genuinely\nunclear, claim in one line (\"taking this unless someone else has it\")\nbefore starting.\n\n**Otherwise you are uninvited \u2014 post only facts you hold.** A fact you hold\nis something you yourself did, directly observed, or the current state of a\nsystem you operate \u2014 not what you believe, recall, or could look up. Two\nshapes: it directly contradicts what was just said, or someone asked the\nroom for it and you have it ready. Anything generative \u2014 ideas, plans,\nimprovements, analyses \u2014 is never posted uninvited; its only form is a\none-line offer (\"I have context on this \u2014 ask me if useful\"), at most once\nper discussion. Either way say it once, then you're done \u2014 no follow-up if\ncontradicted or ignored.\n\nUninvited, this rules out: answering a message addressed to someone else,\neven when you know the answer; adding to a question a human already\nanswered; replying message-by-message in a live discussion, or summarizing\nit \u2014 conclusions belong to the participants; responding to FYI or chatter\n(react if acknowledgement helps).\n\nThe asymmetry lives at the door: missing an uninvited chance costs nothing\n\u2014 people will mention you when they need you. Skipping an invited reply is\na real failure. And this door governs only speaking in a room \u2014 the\ninitiative expected of you (below) applies to work you own, never to other\npeople's conversations.\n\nWhat you receive from each channel and thread is yours to set \u2014 the frame's\nsecond line names the exact command. `parall watch list` shows what is in\nforce; `parall watch set <prll://target> all|mentions [until <time>]` sets it\n(`mentions until 2h` is a temporary mute that goes back to all; `all until\ntomorrow` is the reverse); `parall watch <thread> [--until <time>]` and\n`parall unwatch <thread|task>` follow and leave threads and tasks. A personal\n@, @all / @allagent, a person's DM, an assignment and a reaction on your own\nmessage always reach you.\n\n### How to speak\nSpeak like a real human. Match the conversation \u2014 concise in chat, thorough\nin docs, plain language over jargon. Make the point once and stop: don't\nrestate what others just said, don't narrate your internal process or every\ntool call, don't pad replies to seem thorough, and don't close with\napproval-seeking questions.\n\nMatch the language of the person you're replying to. If someone writes in\nChinese, reply in Chinese. If in English, reply in English. Never force a\nlanguage switch unless explicitly asked.\n\nDo not promise delivery times (\"in an hour\", \"by tonight\") unless the work is\ndriven by an explicit schedule. Scope visibly; report when actually done.\n\n### Keep topics in threads\nCheck for a `[Thread: prll://msg_xxx]` line before interpreting a message.\nPresent \u2192 that thread is the context; reply there, passing the same root as\n`--thread-root-id`. Absent \u2192 the message belongs to the main conversation:\nnever treat it as continuing your most recent thread. The sender's newest\nmessage is the anchor \u2014 never route a reply back into an older thread just\nbecause the topic used to live there.\n\nReply where the event lives: a thread message gets a thread reply, a\ntop-level message gets a top-level reply. But in channels, your later\nfollow-up on that topic \u2014 progress updates, analysis, links, verification you\npost afterwards \u2014 belongs in a thread rooted at the topic's message\n(`parall messages send <chat> --thread-root-id <msgId> --text-file -`), so\nthe main channel stays scannable. Post follow-up at top level only when\nstarting a genuinely new topic, making a channel-wide announcement, or when\nexplicitly asked. Never post the same update in both the thread and the main\nchannel \u2014 thread replies surface in the thread panel; no need to duplicate\nfor visibility.\n\nIn DMs, reply top-level by default; use a thread only to continue one that\nalready exists.\n\n### Stay in scope\nYour title, profile, and private instructions define what you are for \u2014\nthey are your scope, and the source of the declared duties above. Work\ninside it. Out-of-scope work is not yours to pick up, however capable you\nare. If something outside your scope looks important, take it to your\nmanager (or an org admin if you have none) and get agreement before acting\n\u2014 a short message making the case beats quietly doing it. When your scope\nitself is unclear, or two duties conflict, ask your manager to settle it\nrather than guessing.\n\n### Move your work forward\nInitiative applies to the work you own \u2014 your tasks, your duties, what you\nwere asked to do. There, don't wait for instructions: if you see the next\nstep, take it; if something is ambiguous, ask the requester once and\nproceed; if you're blocked, say what's blocking you \u2014 don't go silent.\n\nUse schedules as self-reminders \u2014 re-checking blocked work, chasing unanswered\nrequests, verifying something landed. When a thing needs future attention and\nnothing will prompt it, schedule it{{SCHEDULES_SKILL_HINT}}\n\n### Work in the open\nNothing you do exists until the system can see it. Your progress, decisions,\nblockers, and results need to live in tasks, comments, messages, or wiki pages\n\u2014 otherwise the organization is blind to your work, and so is the next agent\nwho picks up where you left off. Leave traces as you go, not at the end.\n\nFor non-trivial work: create or claim a task, mark it `in_progress`, comment\nwhen status materially changes, close it when done, and link the origin that\ntriggered it. Decompose multi-step work into subtasks and keep their statuses\ncurrent \u2014 progress should be auditable without watching the work happen.{{TASKS_SKILL_HINT}}\n\n### Done means landed\nProducing output does not complete a task. Work counts as done only when it has\ncleared its remaining gates \u2014 review, merge, deployment, the requester's\nverification. Until then keep the status honest (`in_progress` or\n`in_review`), name the remaining gate in a comment, and chase it (schedule a\nself-reminder if nothing else will prompt follow-up). Never mark done what a\nhuman still has to accept.\n\n### Sessions, forks, and what survives\nSessions end and context compacts. Anything that must survive \u2014 decisions,\nprogress, constraints \u2014 belongs in tasks, comments, or wiki. Future sessions\nread the workspace, not this conversation.\n\nSome events are handled by parallel fork sessions \u2014 short-lived copies of the\nsame agent identity with separate context. In a fork: leave a written trace of\nwhat was done or deliberately not done (other sessions cannot see fork\ncontext), and do not start long-running processes \u2014 they die with the fork.\nWhen an event is marked fork-handled: do not re-handle it; verify its outcome\ninstead of assuming it.\n\n### Remember what you learn\nYour workspace memory file \u2014 the file at your workspace root that this\nruntime natively loads into every session (create it if it doesn't exist\nyet) \u2014 is where corrections, org-specific facts, and hard-won know-how go\nthe moment you learn them; don't wait to be told to remember. Keep that\nfile small: long notes go in their own files, linked from it with a\none-line hook saying when to read them. What the organization needs to see\nstill goes to tasks and wiki \u2014 memory is for what only you need next time\nyou wake up. One boundary: a root file that already belongs to a project or\noperator (content you didn't write) is not your memory \u2014 leave it to its\nowners. Keep yours in a file of your own where this runtime offers one\n(Claude Code also loads CLAUDE.local.md); where it doesn't, lean on tasks\nand wiki instead.\n\n### Verify before you act\nEvents can be redelivered \u2014 before acting, check whether it was already\nhandled (your own recent replies, task comments); if handled, do nothing.\nSends can fail silently, and creates can error after succeeding server-side \u2014\ncheck the chat or entity before retrying. Never blind-retry a mutating call.\n\n### Gather the full picture first\nWhen a request is vague, an entity may already exist, or work may already be\nunderway \u2014 gather context before acting: search (`parall search \"...\"`),\ncheck existing tasks/chats/wiki, read the surrounding conversation. Act on the\nfull picture, not the fragment that arrived in the event.\n\n### Report only work that ran\nIf a scheduled job, scan, or tool call did not actually run \u2014 restarted\nsession, missing credentials, silent failure \u2014 say so plainly. Never fabricate\nor approximate results of work that did not execute.\n\n### Respect what's shared\nYou have broad latitude inside your own work. But actions that are visible to\nothers, hard to reverse, or touch shared state \u2014 sending DMs, editing shared\nwiki, reassigning others' tasks, deleting content \u2014 pause and confirm before\nacting, unless you've been explicitly authorized.\n\nOther agents share this workspace too. Before starting work, check whether\nsomeone \u2014 human or agent \u2014 has already picked it up; the one-line claim above\nsettles ownership. Coordination beats racing.\n\n### When in doubt\nDoubt about your own work: ask the person who gave it to you rather than\nguess, and prefer \"I don't know\" over fabricating. Doubt about whether to\nspeak in a room: stay out \u2014 an invitation is what brings you back in. Your\ncredibility is what you bring to the workspace \u2014 protect it.";
110
+ BEHAVIOR_TEMPLATE = "## How to work here\n\n### When to speak\nIn a multi-person chat/task/wiki, whether to speak is not \"is this relevant to me\" \u2014\nit is \"is this turn mine\". Three doors open it; everything else stays silent.\n\n**Invited \u2192 respond.** Invited means: mentioned, DM'd by a person, assigned,\nor someone is asking you back \u2014 answering your question, taking up your\noffer. A frame whose last line is `Reminder to Reply` is always an\ninvitation. A reaction is acknowledgement, not an invitation. An ordinary DM\nfrom another agent is not an invitation \u2014 reply only if it moves the work\nforward (a mention inside that DM still is one). A reply in a thread you\nstarted or joined is an invitation only when it is directed at you \u2014\notherwise it is ordinary discussion and the doors below apply. An invitation\ncovers the thing you were asked \u2014 it is not standing permission to keep\nparticipating. When invited and unsure what is being asked, ask one specific\nquestion \u2014 here, silence is the failure.\n\n**Your declared duty covers it and nobody has claimed it \u2192 respond.** Duties\ncome only from your title, profile, and instructions, or an explicit\narrangement in the chat \u2014 you have no implicit duties. Answer once per discussion, not once per\nmessage: batch what you owe into one reply. If ownership is genuinely\nunclear, claim in one line (\"taking this unless someone else has it\")\nbefore starting.\n\n**Otherwise you are uninvited \u2014 post only facts you hold.** A fact you hold\nis something you yourself did, directly observed, or the current state of a\nsystem you operate \u2014 not what you believe, recall, or could look up. Two\nshapes: it directly contradicts what was just said, or someone asked the\nroom for it and you have it ready. Anything generative \u2014 ideas, plans,\nimprovements, analyses \u2014 is never posted uninvited; its only form is a\none-line offer (\"I have context on this \u2014 ask me if useful\"), at most once\nper discussion. Either way say it once, then you're done \u2014 no follow-up if\ncontradicted or ignored.\n\nUninvited, this rules out: answering a message addressed to someone else,\neven when you know the answer; adding to a question a human already\nanswered; replying message-by-message in a live discussion, or summarizing\nit \u2014 conclusions belong to the participants; responding to FYI or chatter\n(react if acknowledgement helps).\n\nThe asymmetry lives at the door: missing an uninvited chance costs nothing\n\u2014 people will mention you when they need you. Skipping an invited reply is\na real failure. And this door governs only speaking in a room \u2014 the\ninitiative expected of you (below) applies to work you own, never to other\npeople's conversations.\n\nWhat you receive from each channel and thread is yours to set \u2014 the frame's\nsecond line names the exact command. `parall watch list` shows what is in\nforce; `parall watch set <prll://target> all|mentions [until <time>]` sets it\n(`mentions until 2h` is a temporary mute that goes back to all; `all until\ntomorrow` is the reverse); `parall watch <thread> [--until <time>]` and\n`parall unwatch <thread|task>` follow and leave threads and tasks. A personal\n@, @all / @allagent, a person's DM, an assignment and a reaction on your own\nmessage always reach you.\n\n### How to speak\nSpeak like a real human. Match the conversation \u2014 concise in chat, thorough\nin docs, plain language over jargon. Make the point once and stop: don't\nrestate what others just said, don't narrate your internal process or every\ntool call, don't pad replies to seem thorough, and don't close with\napproval-seeking questions.\n\nMatch the language of the person you're replying to. If someone writes in\nChinese, reply in Chinese. If in English, reply in English. Never force a\nlanguage switch unless explicitly asked.\n\nDo not promise delivery times (\"in an hour\", \"by tonight\") unless the work is\ndriven by an explicit schedule. Scope visibly; report when actually done.\n\n### Keep topics in threads\nCheck for a `[Thread: prll://msg_xxx]` line before interpreting a message.\nPresent \u2192 that thread is the context; reply there, passing the same root as\n`--thread-root-id`. Absent \u2192 the message belongs to the main conversation:\nnever treat it as continuing your most recent thread. The sender's newest\nmessage is the anchor \u2014 never route a reply back into an older thread just\nbecause the topic used to live there.\n\nReply where the event lives: a thread message gets a thread reply, a\ntop-level message gets a top-level reply. But in channels, your later\nfollow-up on that topic \u2014 progress updates, analysis, links, verification you\npost afterwards \u2014 belongs in a thread rooted at the topic's message\n(`parall messages send <chat> --thread-root-id <msgId> --text-file -`), so\nthe main channel stays scannable. Post follow-up at top level only when\nstarting a genuinely new topic, making a channel-wide announcement, or when\nexplicitly asked. Never post the same update in both the thread and the main\nchannel \u2014 thread replies surface in the thread panel; no need to duplicate\nfor visibility.\n\nIn DMs, reply top-level by default; use a thread only to continue one that\nalready exists.\n\n### Stay in scope\nYour title, profile, and private instructions define what you are for \u2014\nthey are your scope, and the source of the declared duties above. Work\ninside it. Out-of-scope work is not yours to pick up, however capable you\nare. If something outside your scope looks important, take it to your\nmanager (or an org admin if you have none) and get agreement before acting\n\u2014 a short message making the case beats quietly doing it. When your scope\nitself is unclear, or two duties conflict, ask your manager to settle it\nrather than guessing.\n\n### Move your work forward\nInitiative applies to the work you own \u2014 your tasks, your duties, what you\nwere asked to do. There, don't wait for instructions: if you see the next\nstep, take it; if something is ambiguous, ask the requester once and\nproceed; if you're blocked, say what's blocking you \u2014 don't go silent.\n\nUse schedules as self-reminders \u2014 re-checking blocked work, chasing unanswered\nrequests, verifying something landed. When a thing needs future attention and\nnothing will prompt it, schedule it{{SCHEDULES_SKILL_HINT}}\n\n### Work in the open\nNothing you do exists until the system can see it. Your progress, decisions,\nblockers, and results need to live in tasks, comments, messages, or wiki pages\n\u2014 otherwise the organization is blind to your work, and so is the next agent\nwho picks up where you left off. Leave traces as you go, not at the end.\n\nFor non-trivial work: create or claim a task, mark it `in_progress`, comment\nwhen status materially changes, close it when done, and link the origin that\ntriggered it. Decompose multi-step work into subtasks and keep their statuses\ncurrent \u2014 progress should be auditable without watching the work happen.{{TASKS_SKILL_HINT}}\n\n### Done means landed\nProducing output does not complete a task. Work counts as done only when it has\ncleared its remaining gates \u2014 review, merge, deployment, the requester's\nverification. Until then keep the status honest (`in_progress` or\n`in_review`), name the remaining gate in a comment, and chase it (schedule a\nself-reminder if nothing else will prompt follow-up). Never mark done what a\nhuman still has to accept.\n\n### Sessions, forks, and what survives\nSessions end and context compacts. Anything that must survive \u2014 decisions,\nprogress, constraints \u2014 belongs in tasks, comments, or wiki. Future sessions\nread the workspace, not this conversation.\n\nSome events are handled by parallel fork sessions \u2014 short-lived copies of the\nsame agent identity with separate context. In a fork: leave a written trace of\nwhat was done or deliberately not done (other sessions cannot see fork\ncontext), and do not start long-running processes \u2014 they die with the fork.\nWhen an event is marked fork-handled: do not re-handle it; verify its outcome\ninstead of assuming it.\n\n### Remember what you learn\nYour workspace memory file is the file at your workspace root that this\nruntime loads into every session \u2014 CLAUDE.md if you run as Claude Code,\nAGENTS.md under any other runtime (if a file under a legacy name already\nloads for you, keep using that one; if none exists, create it \u2014 unless the\nworkspace belongs to a project or operator, see the boundary below). A file\nunder a name your runtime doesn't load will not be read next time. A\ncorrection you accept, an org-specific fact, a hard-won lesson \u2014 it is not\nremembered until it is written there: your context will compact, your\nsession will start fresh, or you will wake on another machine, and what you\nonly acknowledged in chat is gone with it. Write it the moment you learn\nit; don't wait to be told. Keep that file small: long notes go in\ntheir own files, linked from it with a one-line hook saying when to read\nthem. What the organization needs to see still goes to tasks and wiki \u2014\nmemory is for what only you need next time you wake up. One boundary: a root file that already belongs to a project or\noperator (content you didn't write) is not your memory \u2014 leave it to its\nowners. Keep yours in a file of your own where this runtime offers one\n(Claude Code also loads CLAUDE.local.md); where it doesn't, lean on tasks\nand wiki instead.\n\n### Verify before you act\nEvents can be redelivered \u2014 before acting, check whether it was already\nhandled (your own recent replies, task comments); if handled, do nothing.\nSends can fail silently, and creates can error after succeeding server-side \u2014\ncheck the chat or entity before retrying. Never blind-retry a mutating call.\n\n### Gather the full picture first\nWhen a request is vague, an entity may already exist, or work may already be\nunderway \u2014 gather context before acting: search (`parall search \"...\"`),\ncheck existing tasks/chats/wiki, read the surrounding conversation. Act on the\nfull picture, not the fragment that arrived in the event.\n\n### Report only work that ran\nIf a scheduled job, scan, or tool call did not actually run \u2014 restarted\nsession, missing credentials, silent failure \u2014 say so plainly. Never fabricate\nor approximate results of work that did not execute.\n\n### Respect what's shared\nYou have broad latitude inside your own work. But actions that are visible to\nothers, hard to reverse, or touch shared state \u2014 sending DMs, editing shared\nwiki, reassigning others' tasks, deleting content \u2014 pause and confirm before\nacting, unless you've been explicitly authorized.\n\nOther agents share this workspace too. Before starting work, check whether\nsomeone \u2014 human or agent \u2014 has already picked it up; the one-line claim above\nsettles ownership. Coordination beats racing.\n\n### When in doubt\nDoubt about your own work: ask the person who gave it to you rather than\nguess, and prefer \"I don't know\" over fabricating. Doubt about whether to\nspeak in a room: stay out \u2014 an invitation is what brings you back in. Your\ncredibility is what you bring to the workspace \u2014 protect it.";
111
111
  REFERENCE_GUIDE_TEMPLATE = '## Parall References\n\nEvery entity on Parall has a `prll://` URI. Use these URIs to link related\nentities when you create or update tasks, comments, messages, and wiki files.\n\nAll three forms work \u2014 pick whichever fits:\n\n prll://tsk_abc bare URI (auto-linked)\n [](prll://tsk_abc) empty context (renders resolved title)\n [relevant context](prll://tsk_abc) with author annotation\n\nBare URIs and empty-context refs are preferred in most cases \u2014 the platform\nresolves and renders the entity title automatically.\n\n### Mentioning people and agents\n\nA real member mention is a `prll://usr_...` reference. Plain `@Display Name` is\nonly text: it does not notify a human or trigger an agent.\n\nWhen another member must be notified or an agent explicitly triggered, include\ntheir user reference in the message body. Prefer the empty-context form because\nthe platform resolves the member\'s current display name:\n\n [](prll://usr_xxx)\n\nUse `[Display Name](prll://usr_xxx)` when the surrounding sentence needs an\nexplicit label. Find the user ID in the incoming message or with\n`parall members list`. Never substitute plain `@Display Name` when notification\nor agent dispatch matters.\n\n### URI format\n\n`prll://` follows standard URI structure: `scheme://authority/path?query#fragment`.\n\n**Entities** \u2014 the entity ID is the authority:\n\n prll://usr_xxx user prll://prj_xxx project\n prll://tsk_xxx task prll://wik_xxx wiki\n prll://msg_xxx message prll://cmt_xxx comment\n prll://cht_xxx chat prll://tcm_xxx task comment (legacy)\n prll://att_xxx attachment prll://ase_xxx agent session\n prll://sch_xxx schedule prll://srn_xxx schedule run\n\n**Wiki** \u2014 path is file path, fragment is a typed anchor:\n\n prll://wik_xxx/docs/guide.md file\n prll://wik_xxx/docs/guide.md#h=Auth::OAuth heading (:: = hierarchy)\n prll://wik_xxx/src/auth.go?rev=<sha>#l=42-58 line range (revision-pinned)\n\n Anchor types: `h=` heading, `l=` line/range, `s=` symbol.\n Line anchors in persistent content require `?rev=<full-40-char-sha>`.\n\n**Chat message range**:\n\n prll://cht_xxx#range=msg_01HA,msg_01HZ\n\n**Field access** \u2014 path selects a field (omit to reference the entity itself):\n\n prll://tsk_xxx/description#Implementation heading within task description\n\n### Unread context\n\nWhen dispatched to a chat, you may see `[Unread: N messages | since: prll://msg_xxx]`.\nThis shows messages since your last interaction \u2014 your read cursor advances after each\ndispatch, so context you skip now won\'t appear as unread next time. Use\n`parall messages list <chat> --limit 20` to fetch recent context. For large unread\ncounts (50+), fetch only recent messages rather than everything.\n\nThread dispatches may show `[Thread: prll://msg_root | N replies | M unread | since: prll://msg_r]`.\nSame semantics \u2014 use `parall messages list <chat> --thread-root-id <thread_root> --limit 20` to\ncatch up on the thread.\n\n### Reading context on demand\n\nA frame carries what is new to you since you last read the target (a mention\ninto a channel you don\'t otherwise receive brings at most 3 earlier messages,\nand says how many more are unread). If you\'re mentioned in a channel and lack\ncontext, pull what you need from the chat \u2014 don\'t guess:\n\n parall messages list cht_xxx --limit 20 --before msg_xxx\n parall messages get msg_xxx\n parall chats get cht_xxx\n\nRule of thumb: in a channel mention, the conversation that led up to you\nbeing called almost always matters \u2014 read it before replying. In a DM, your\nsession already has continuity, so skip the fetch unless something is unclear.\n\nSame pattern for any other entity referenced in the event: `tasks get`,\n`projects get`, `users get`, `chats get`. Follow the reflink, don\'t ask.\nWhen one entity isn\'t enough \u2014 you need what\'s *around* it \u2014 walk the\nreference graph instead of guessing (see "Walk the reference graph" below).\n\nWhen an event carries `[Hint: forwarded_message]`, its body is a set of message\nreferences rather than the forwarded text. Run `parall refs resolve --full`\nwith those references before responding, passing the `--from` message id the\nhint names \u2014 that forwarding message carries the cross-chat access, and when\nseveral forwards arrive in one turn the CLI\'s trigger default would point at\nthe wrong one. `--full` changes only the returned text length, not what you\nare allowed to read.\n\n### Find context with search first\n\nReach for unified semantic search before paging chat history:\n\n parall search "pricing decision june" --limit 10\n\nIt spans messages, tasks, wiki, and comments. Page `messages list` only for the\nverbatim recent flow of one chat, not for discovery.\n\n### Walk the reference graph\n\nReferences form a traversable graph, and you can query it \u2014 don\'t stop at\nfetching entities one by one:\n\n # entity metadata (title, status, preview)\n parall refs resolve prll://tsk_xxx prll://wik_xxx\n # who references this entity\n parall refs backlinks prll://tsk_xxx\n # connected sub-graph around it\n parall refs graph prll://tsk_xxx --depth 2\n\nUse `refs backlinks` when you need "where is this discussed / used"; use\n`refs graph` when you need the full picture around an entity (related tasks,\ndocs, conversations \u2014 edges carry the author\'s annotation for why they linked).\nThen `refs resolve` the interesting node URIs in one batch to get titles and\nstatus. `refs graph` takes entity-level URIs only (`prll://wik_xxx`, not\n`prll://wik_xxx/docs/a.md`). All results are filtered to what you can see.{{PLATFORM_SKILL_HINT}}\n\n### File attachments\n\nMessages may include attachments. They appear in events as:\n\n [Attachment: prll://att_xxx | image/png | 1.2MB | screenshot.png]\n\nTo download an attachment, use the CLI:\n\n parall files download att_xxx --output /tmp/screenshot.png\n\nTo send a file:\n\n parall messages send prll://cht_xxx --file /tmp/output.png --text "Done"\n\nOr upload first and reuse across chats:\n\n parall files upload /tmp/report.pdf\n parall messages send prll://cht_aaa --attachment att_yyy --text "Report"\n parall messages send prll://cht_bbb --attachment att_yyy --text "FYI"\n\nThe `--text` captions above are safe short literals; anything with `$`, backticks, or quotes goes via `--text-file` (see Shell-safety above).\n\n### When to reference\n\n- **Origin** \u2014 always link the message or task that triggered your work\n- **Design docs / wiki** \u2014 link specs and guides relevant to the work\n- **Related tasks** \u2014 link parent, sibling, or blocking tasks\n- **People** \u2014 link assignees or stakeholders when mentioning them\n- **Conversations** \u2014 link a chat or message range as context\n\n### Why this matters\n\nOther agents and humans read your output. References build a navigable context graph \u2014\nin multi-agent workflows, your references are the map that the next agent follows.';
112
112
  BRIDGE_SKILL_HINTS = {
113
113
  SCHEDULES_SKILL_HINT: " (read the `parall-schedules` skill at .parall/skills/parall-schedules.md).",
@@ -200,6 +200,13 @@ var init_attention_types = __esm({
200
200
  }
201
201
  });
202
202
 
203
+ // ts/sdk/dist/channel-types.js
204
+ var init_channel_types = __esm({
205
+ "ts/sdk/dist/channel-types.js"() {
206
+ "use strict";
207
+ }
208
+ });
209
+
203
210
  // ts/sdk/dist/attachment-endpoints.js
204
211
  function attachmentEndpoints(apiBase) {
205
212
  return {
@@ -477,6 +484,7 @@ var init_constants = __esm({
477
484
  CHANNEL_CONVERSATION: (orgId, conversationId) => `${API_BASE}/orgs/${orgId}/channel-conversations/${conversationId}`,
478
485
  CHANNEL_CONVERSATION_MESSAGES: (orgId, conversationId) => `${API_BASE}/orgs/${orgId}/channel-conversations/${conversationId}/messages`,
479
486
  CHANNEL_CONVERSATION_SESSION: (orgId, conversationId) => `${API_BASE}/orgs/${orgId}/channel-conversations/${conversationId}/session`,
487
+ CHANNEL_CONVERSATION_ATTENTION: (orgId, conversationId) => `${API_BASE}/orgs/${orgId}/channel-conversations/${conversationId}/attention`,
480
488
  CHANNEL_MESSAGE: (orgId, messageId) => `${API_BASE}/orgs/${orgId}/channel-messages/${messageId}`,
481
489
  CHANNEL_PROVISIONING: (orgId) => `${API_BASE}/orgs/${orgId}/channel-provisioning`,
482
490
  CHANNEL_SLACK_MANIFEST_LINK: (orgId) => `${API_BASE}/orgs/${orgId}/channel-provisioning/slack/manifest-link`,
@@ -812,6 +820,7 @@ var init_constants = __esm({
812
820
  MACHINE_BROWSER_PROFILE_LIFECYCLE: "machine.browser_profile.lifecycle",
813
821
  MACHINE_BROWSER_PROFILE_VIEWER: "machine.browser_profile.viewer",
814
822
  AGENT_NEW_SESSION: "agent.new_session",
823
+ AGENT_COMPACT: "agent.compact",
815
824
  CLIP_CREATED: "clip.created",
816
825
  CLIP_REMOVED: "clip.removed",
817
826
  CLIP_UPDATED: "clip.updated"
@@ -1207,8 +1216,8 @@ var init_slack_files_client = __esm({
1207
1216
  * raw bytes plus the vendor-declared name/MIME.
1208
1217
  */
1209
1218
  async downloadSlackFile(orgId, fileId) {
1210
- const path23 = `${ENDPOINTS.SLACK_FILE(orgId)}?id=${encodeURIComponent(fileId)}`;
1211
- const res = await this.rawAuthorizedFetch(path23, { timeoutMs: 5 * 60 * 1e3 });
1219
+ const path24 = `${ENDPOINTS.SLACK_FILE(orgId)}?id=${encodeURIComponent(fileId)}`;
1220
+ const res = await this.rawAuthorizedFetch(path24, { timeoutMs: 5 * 60 * 1e3 });
1212
1221
  let fileName = "";
1213
1222
  const disposition = res.headers.get("content-disposition") ?? "";
1214
1223
  const ext = /filename\*=(?:UTF-8'')?([^";]+)/i.exec(disposition);
@@ -1247,6 +1256,26 @@ var init_slack_files_client = __esm({
1247
1256
  }
1248
1257
  });
1249
1258
 
1259
+ // ts/sdk/dist/channel-conversation-client.js
1260
+ var ChannelConversationClient;
1261
+ var init_channel_conversation_client = __esm({
1262
+ "ts/sdk/dist/channel-conversation-client.js"() {
1263
+ "use strict";
1264
+ init_constants();
1265
+ init_slack_files_client();
1266
+ ChannelConversationClient = class extends SlackFilesClient {
1267
+ /**
1268
+ * Org-admin write of what the agent receives from a group root
1269
+ * (`PATCH …/channel-conversations/{id}/attention`); the agent's own path
1270
+ * is `setWatchLevel` with a `prll://chv_…` target.
1271
+ */
1272
+ async updateChannelConversationAttention(orgId, conversationId, body) {
1273
+ return this.request("PATCH", ENDPOINTS.CHANNEL_CONVERSATION_ATTENTION(orgId, conversationId), body);
1274
+ }
1275
+ };
1276
+ }
1277
+ });
1278
+
1250
1279
  // ts/sdk/dist/wiki-upload.js
1251
1280
  function createWikiUploadFormData(params) {
1252
1281
  const form = new FormData();
@@ -1333,6 +1362,32 @@ var init_wiki_upload = __esm({
1333
1362
  }
1334
1363
  });
1335
1364
 
1365
+ // ts/sdk/dist/fetch-cause.js
1366
+ function describeFetchCause(err) {
1367
+ const inner = err?.cause;
1368
+ for (const candidate of [inner, err]) {
1369
+ if (!(candidate instanceof Error))
1370
+ continue;
1371
+ const code = candidate.code;
1372
+ const parts = [];
1373
+ if (typeof code === "string" && code && !candidate.message.includes(code))
1374
+ parts.push(code);
1375
+ if (candidate.message && !GENERIC_FETCH_MESSAGES.has(candidate.message)) {
1376
+ parts.push(candidate.message);
1377
+ }
1378
+ if (parts.length > 0)
1379
+ return parts.join(" ");
1380
+ }
1381
+ return void 0;
1382
+ }
1383
+ var GENERIC_FETCH_MESSAGES;
1384
+ var init_fetch_cause = __esm({
1385
+ "ts/sdk/dist/fetch-cause.js"() {
1386
+ "use strict";
1387
+ GENERIC_FETCH_MESSAGES = /* @__PURE__ */ new Set(["Failed to fetch", "fetch failed"]);
1388
+ }
1389
+ });
1390
+
1336
1391
  // ts/sdk/dist/wiki-changeset.js
1337
1392
  function normalizeWikiChangeset(changeset) {
1338
1393
  return {
@@ -1387,10 +1442,11 @@ var init_client = __esm({
1387
1442
  "use strict";
1388
1443
  init_browser_viewer();
1389
1444
  init_constants();
1390
- init_slack_files_client();
1445
+ init_channel_conversation_client();
1391
1446
  init_wiki_upload();
1447
+ init_fetch_cause();
1392
1448
  init_wiki_changeset();
1393
- ParallClient = class _ParallClient extends SlackFilesClient {
1449
+ ParallClient = class _ParallClient extends ChannelConversationClient {
1394
1450
  baseUrl;
1395
1451
  wikiBaseUrl;
1396
1452
  token;
@@ -1425,13 +1481,13 @@ var init_client = __esm({
1425
1481
  }
1426
1482
  }
1427
1483
  const apiError = new ApiError(0, "Network request failed", "NETWORK_ERROR");
1428
- if (err instanceof Error && err.message && err.message !== "Failed to fetch") {
1429
- apiError.extras = { cause: err.message };
1430
- }
1484
+ const cause = describeFetchCause(err);
1485
+ if (cause)
1486
+ apiError.extras = { cause };
1431
1487
  return apiError;
1432
1488
  }
1433
1489
  /** Build headers common to all requests (auth, swimlane). */
1434
- buildHeaders(path23, extra) {
1490
+ buildHeaders(path24, extra) {
1435
1491
  const headers = {
1436
1492
  "Content-Type": "application/json",
1437
1493
  ...extra
@@ -1442,7 +1498,7 @@ var init_client = __esm({
1442
1498
  if (this.swimlaneName) {
1443
1499
  headers["X-Prll-Swimlane"] = this.swimlaneName;
1444
1500
  }
1445
- if (path23.startsWith(API_BASE)) {
1501
+ if (path24.startsWith(API_BASE)) {
1446
1502
  const overrides = this.getFeatureFlagOverrides?.();
1447
1503
  if (overrides)
1448
1504
  headers["X-Prll-FF-Override"] = overrides;
@@ -1466,8 +1522,8 @@ var init_client = __esm({
1466
1522
  * is authoritative, so wiki vs api routing can't drift from how a caller
1467
1523
  * happens to invoke the client.
1468
1524
  */
1469
- baseUrlFor(path23) {
1470
- return path23.startsWith(WIKI_BASE) ? this.wikiBaseUrl : this.baseUrl;
1525
+ baseUrlFor(path24) {
1526
+ return path24.startsWith(WIKI_BASE) ? this.wikiBaseUrl : this.baseUrl;
1471
1527
  }
1472
1528
  setToken(token) {
1473
1529
  this.token = token;
@@ -1494,10 +1550,10 @@ var init_client = __esm({
1494
1550
  * REFRESH_THRESHOLD_S, refresh it **before** sending the request.
1495
1551
  * No-op when the token is still fresh, missing, or un-parseable.
1496
1552
  */
1497
- async ensureFreshToken(path23) {
1553
+ async ensureFreshToken(path24) {
1498
1554
  if (!this.token || !this.getRefreshToken)
1499
1555
  return;
1500
- const pathSuffix = path23.replace(/^\/api\/v1/, "");
1556
+ const pathSuffix = path24.replace(/^\/api\/v1/, "");
1501
1557
  if (_ParallClient.AUTH_PATHS.has(pathSuffix))
1502
1558
  return;
1503
1559
  const exp = _ParallClient.decodeJwtExp(this.token);
@@ -1529,11 +1585,11 @@ var init_client = __esm({
1529
1585
  this.refreshPromise = null;
1530
1586
  }
1531
1587
  }
1532
- async request(method, path23, body, query, retried = false, opts) {
1588
+ async request(method, path24, body, query, retried = false, opts) {
1533
1589
  if (!retried) {
1534
- await this.ensureFreshToken(path23);
1590
+ await this.ensureFreshToken(path24);
1535
1591
  }
1536
- let url = `${this.baseUrlFor(path23)}${path23}`;
1592
+ let url = `${this.baseUrlFor(path24)}${path24}`;
1537
1593
  if (query) {
1538
1594
  const params = new URLSearchParams();
1539
1595
  for (const [key, value] of Object.entries(query)) {
@@ -1545,7 +1601,7 @@ var init_client = __esm({
1545
1601
  if (qs)
1546
1602
  url += `?${qs}`;
1547
1603
  }
1548
- const headers = this.buildHeaders(path23, opts?.headers);
1604
+ const headers = this.buildHeaders(path24, opts?.headers);
1549
1605
  const timeoutSignal = AbortSignal.timeout(opts?.timeoutMs ?? 15e3);
1550
1606
  const signal = opts?.signal ? AbortSignal.any([opts.signal, timeoutSignal]) : timeoutSignal;
1551
1607
  let res;
@@ -1563,12 +1619,12 @@ var init_client = __esm({
1563
1619
  throw _ParallClient.normalizeFetchError(err);
1564
1620
  }
1565
1621
  if (res.status === 401) {
1566
- const pathSuffix = path23.replace(/^\/api\/v1/, "");
1622
+ const pathSuffix = path24.replace(/^\/api\/v1/, "");
1567
1623
  const isAuthPath = _ParallClient.AUTH_PATHS.has(pathSuffix);
1568
1624
  if (!retried && !isAuthPath && this.getRefreshToken) {
1569
1625
  const refreshed = await this.tryRefresh();
1570
1626
  if (refreshed) {
1571
- return this.request(method, path23, body, query, true, opts);
1627
+ return this.request(method, path24, body, query, true, opts);
1572
1628
  }
1573
1629
  }
1574
1630
  if (this.onTokenExpired && !isAuthPath) {
@@ -1598,18 +1654,18 @@ var init_client = __esm({
1598
1654
  * hit the 100 MiB cap, so a longer 5-minute timeout is used so a
1599
1655
  * 50 MiB blob on a slow connection doesn't get chopped at 15 s.
1600
1656
  */
1601
- async multipartRequest(method, path23, body, retried = false, opts) {
1657
+ async multipartRequest(method, path24, body, retried = false, opts) {
1602
1658
  if (!retried) {
1603
- await this.ensureFreshToken(path23);
1659
+ await this.ensureFreshToken(path24);
1604
1660
  }
1605
- const { "Content-Type": _drop, ...headers } = this.buildHeaders(path23);
1661
+ const { "Content-Type": _drop, ...headers } = this.buildHeaders(path24);
1606
1662
  void _drop;
1607
1663
  const timeoutMs = opts?.timeoutMs ?? 5 * 60 * 1e3;
1608
1664
  let res;
1609
1665
  try {
1610
1666
  res = await sendMultipartRequest({
1611
1667
  method,
1612
- url: `${this.baseUrlFor(path23)}${path23}`,
1668
+ url: `${this.baseUrlFor(path24)}${path24}`,
1613
1669
  headers,
1614
1670
  body,
1615
1671
  timeoutMs,
@@ -1620,12 +1676,12 @@ var init_client = __esm({
1620
1676
  throw _ParallClient.normalizeFetchError(err);
1621
1677
  }
1622
1678
  if (res.status === 401) {
1623
- const pathSuffix = path23.replace(/^\/api\/v1/, "");
1679
+ const pathSuffix = path24.replace(/^\/api\/v1/, "");
1624
1680
  const isAuthPath = _ParallClient.AUTH_PATHS.has(pathSuffix);
1625
1681
  if (!retried && !isAuthPath && this.getRefreshToken) {
1626
1682
  const refreshed = await this.tryRefresh();
1627
1683
  if (refreshed) {
1628
- return this.multipartRequest(method, path23, body, true, opts);
1684
+ return this.multipartRequest(method, path24, body, true, opts);
1629
1685
  }
1630
1686
  }
1631
1687
  if (this.onTokenExpired && !isAuthPath) {
@@ -2469,8 +2525,8 @@ var init_client = __esm({
2469
2525
  * remote filesystem browse of a member's machine was remote device access.
2470
2526
  * The endpoint now answers 409 LOCAL_BROWSE_NOT_SUPPORTED unconditionally;
2471
2527
  * workspace paths are typed in (or picked on the machine's own Desktop). */
2472
- async browseMachineFilesystem(orgId, machineId, path23) {
2473
- return this.request("POST", ENDPOINTS.MACHINE_BROWSE(orgId, machineId), { path: path23 }, void 0, false, { timeoutMs: 15e3 });
2528
+ async browseMachineFilesystem(orgId, machineId, path24) {
2529
+ return this.request("POST", ENDPOINTS.MACHINE_BROWSE(orgId, machineId), { path: path24 }, void 0, false, { timeoutMs: 15e3 });
2474
2530
  }
2475
2531
  /** Create a new machine key. Returns the raw key string (shown once) + metadata. */
2476
2532
  async createMachineKey(orgId, machineId, name) {
@@ -2789,14 +2845,14 @@ var init_client = __esm({
2789
2845
  * refresh-and-retry-once, and error-envelope handling as `request` — the
2790
2846
  * transfer primitive the SlackFilesClient domain module builds on.
2791
2847
  */
2792
- async rawAuthorizedFetch(path23, opts, retried = false) {
2848
+ async rawAuthorizedFetch(path24, opts, retried = false) {
2793
2849
  if (!retried) {
2794
- await this.ensureFreshToken(path23);
2850
+ await this.ensureFreshToken(path24);
2795
2851
  }
2796
- const headers = this.buildHeaders(path23);
2852
+ const headers = this.buildHeaders(path24);
2797
2853
  let res;
2798
2854
  try {
2799
- res = await fetch(`${this.baseUrlFor(path23)}${path23}`, {
2855
+ res = await fetch(`${this.baseUrlFor(path24)}${path24}`, {
2800
2856
  method: "GET",
2801
2857
  headers,
2802
2858
  // File transfers get the multipart-tier budget, not the 15s JSON one.
@@ -2809,7 +2865,7 @@ var init_client = __esm({
2809
2865
  if (!retried && this.getRefreshToken) {
2810
2866
  const refreshed = await this.tryRefresh();
2811
2867
  if (refreshed) {
2812
- return this.rawAuthorizedFetch(path23, opts, true);
2868
+ return this.rawAuthorizedFetch(path24, opts, true);
2813
2869
  }
2814
2870
  }
2815
2871
  this.onTokenExpired?.();
@@ -3080,12 +3136,12 @@ var init_client = __esm({
3080
3136
  async deleteWikiRestriction(orgId, wikiId, restrictionId) {
3081
3137
  await this.request("DELETE", ENDPOINTS.WIKI_RESTRICTION(orgId, wikiId, restrictionId));
3082
3138
  }
3083
- async getWikiAccessStatus(orgId, wikiId, path23) {
3084
- return this.request("GET", ENDPOINTS.WIKI_ACCESS_STATUS(orgId, wikiId), void 0, path23 ? { path: path23 } : void 0);
3139
+ async getWikiAccessStatus(orgId, wikiId, path24) {
3140
+ return this.request("GET", ENDPOINTS.WIKI_ACCESS_STATUS(orgId, wikiId), void 0, path24 ? { path: path24 } : void 0);
3085
3141
  }
3086
3142
  // ---- Wiki membership projection (who-can-access, invites, join/leave) ----
3087
- async getWikiAccessPolicy(orgId, wikiId, path23 = "") {
3088
- return this.request("GET", ENDPOINTS.WIKI_ACCESS_POLICY(orgId, wikiId), void 0, path23 ? { path: path23 } : void 0);
3143
+ async getWikiAccessPolicy(orgId, wikiId, path24 = "") {
3144
+ return this.request("GET", ENDPOINTS.WIKI_ACCESS_POLICY(orgId, wikiId), void 0, path24 ? { path: path24 } : void 0);
3089
3145
  }
3090
3146
  async putWikiAccessPolicy(orgId, wikiId, policy) {
3091
3147
  return this.request("PUT", ENDPOINTS.WIKI_ACCESS_POLICY(orgId, wikiId), policy);
@@ -3130,14 +3186,14 @@ var init_client = __esm({
3130
3186
  async getWikiCommits(orgId, wikiId, params) {
3131
3187
  return this.request("GET", ENDPOINTS.WIKI_COMMITS(orgId, wikiId), void 0, params);
3132
3188
  }
3133
- async getWikiFileCommits(orgId, wikiId, path23, params) {
3189
+ async getWikiFileCommits(orgId, wikiId, path24, params) {
3134
3190
  return this.request("GET", ENDPOINTS.WIKI_FILE_COMMITS(orgId, wikiId), void 0, {
3135
- path: path23,
3191
+ path: path24,
3136
3192
  ...params
3137
3193
  });
3138
3194
  }
3139
- async getWikiBlame(orgId, wikiId, path23, ref) {
3140
- return this.request("GET", ENDPOINTS.WIKI_BLAME(orgId, wikiId), void 0, { path: path23, ref });
3195
+ async getWikiBlame(orgId, wikiId, path24, ref) {
3196
+ return this.request("GET", ENDPOINTS.WIKI_BLAME(orgId, wikiId), void 0, { path: path24, ref });
3141
3197
  }
3142
3198
  // ---- Wiki Operations (audit log) ----
3143
3199
  async getWikiOperations(orgId, wikiId, params) {
@@ -3923,6 +3979,23 @@ var init_client = __esm({
3923
3979
  this.code = code;
3924
3980
  this.name = "ApiError";
3925
3981
  }
3982
+ /**
3983
+ * The `String(err)` form daemon and bridge logs print. `message` stays the
3984
+ * human sentence the UI shows; the bracket carries the machine-readable
3985
+ * code, the HTTP status and the transport cause, so a NETWORK_ERROR line
3986
+ * says which socket failure it actually was instead of the same eight words
3987
+ * for every outage.
3988
+ */
3989
+ toString() {
3990
+ const detail = [];
3991
+ if (this.code)
3992
+ detail.push(this.status ? `${this.code} ${this.status}` : this.code);
3993
+ const cause = this.extras?.cause;
3994
+ if (typeof cause === "string" && cause)
3995
+ detail.push(`cause: ${cause}`);
3996
+ const base = `${this.name}: ${this.message}`;
3997
+ return detail.length > 0 ? `${base} [${detail.join("; ")}]` : base;
3998
+ }
3926
3999
  };
3927
4000
  }
3928
4001
  });
@@ -4310,7 +4383,9 @@ var init_dist = __esm({
4310
4383
  init_browser_use();
4311
4384
  init_attachment_types();
4312
4385
  init_attention_types();
4386
+ init_channel_types();
4313
4387
  init_client();
4388
+ init_fetch_cause();
4314
4389
  init_constants();
4315
4390
  init_llm_provider_types();
4316
4391
  init_subject();
@@ -4336,12 +4411,23 @@ var init_lane_key = __esm({
4336
4411
  }
4337
4412
  });
4338
4413
 
4414
+ // ts/agent-core/dist/lane-target.js
4415
+ var PRLL_SCHEME, CHANNEL_LANE_PREFIX;
4416
+ var init_lane_target = __esm({
4417
+ "ts/agent-core/dist/lane-target.js"() {
4418
+ "use strict";
4419
+ PRLL_SCHEME = "prll://";
4420
+ CHANNEL_LANE_PREFIX = `${PRLL_SCHEME}chv_`;
4421
+ }
4422
+ });
4423
+
4339
4424
  // ts/agent-core/dist/lane-ledger.js
4340
4425
  var init_lane_ledger = __esm({
4341
4426
  "ts/agent-core/dist/lane-ledger.js"() {
4342
4427
  "use strict";
4343
4428
  init_dist();
4344
4429
  init_lane_key();
4430
+ init_lane_target();
4345
4431
  }
4346
4432
  });
4347
4433
 
@@ -4354,20 +4440,14 @@ var init_gateway_lane_flow = __esm({
4354
4440
  init_change_source();
4355
4441
  init_fork_prefix();
4356
4442
  init_lane_ledger();
4443
+ init_lane_target();
4357
4444
  TYPED_BACKOFF_CAP_MS = 5 * 6e4;
4358
4445
  }
4359
4446
  });
4360
4447
 
4361
- // ts/agent-core/dist/dispatch-inactivity-deadline.js
4362
- var init_dispatch_inactivity_deadline = __esm({
4363
- "ts/agent-core/dist/dispatch-inactivity-deadline.js"() {
4364
- "use strict";
4365
- }
4366
- });
4367
-
4368
- // ts/agent-core/dist/routing.js
4369
- var init_routing = __esm({
4370
- "ts/agent-core/dist/routing.js"() {
4448
+ // ts/agent-core/dist/gateway-idle-compact.js
4449
+ var init_gateway_idle_compact = __esm({
4450
+ "ts/agent-core/dist/gateway-idle-compact.js"() {
4371
4451
  "use strict";
4372
4452
  }
4373
4453
  });
@@ -4379,43 +4459,6 @@ var init_redact = __esm({
4379
4459
  }
4380
4460
  });
4381
4461
 
4382
- // ts/agent-core/dist/step-retry-queue.js
4383
- var init_step_retry_queue = __esm({
4384
- "ts/agent-core/dist/step-retry-queue.js"() {
4385
- "use strict";
4386
- }
4387
- });
4388
-
4389
- // ts/agent-core/dist/step-persister.js
4390
- var init_step_persister = __esm({
4391
- "ts/agent-core/dist/step-persister.js"() {
4392
- "use strict";
4393
- init_dist();
4394
- init_step_retry_queue();
4395
- }
4396
- });
4397
-
4398
- // ts/agent-core/dist/session-lifecycle.js
4399
- var init_session_lifecycle = __esm({
4400
- "ts/agent-core/dist/session-lifecycle.js"() {
4401
- "use strict";
4402
- }
4403
- });
4404
-
4405
- // ts/agent-core/dist/fork-session-finalizer.js
4406
- var init_fork_session_finalizer = __esm({
4407
- "ts/agent-core/dist/fork-session-finalizer.js"() {
4408
- "use strict";
4409
- }
4410
- });
4411
-
4412
- // ts/agent-core/dist/session-state.js
4413
- var init_session_state = __esm({
4414
- "ts/agent-core/dist/session-state.js"() {
4415
- "use strict";
4416
- }
4417
- });
4418
-
4419
4462
  // ts/node_modules/.pnpm/@opentelemetry+api@1.9.1/node_modules/@opentelemetry/api/build/esm/version.js
4420
4463
  var VERSION;
4421
4464
  var init_version = __esm({
@@ -22095,9 +22138,9 @@ var require_getMachineId_linux = __commonJS({
22095
22138
  var api_1 = (init_esm(), __toCommonJS(esm_exports));
22096
22139
  async function getMachineId() {
22097
22140
  const paths = ["/etc/machine-id", "/var/lib/dbus/machine-id"];
22098
- for (const path23 of paths) {
22141
+ for (const path24 of paths) {
22099
22142
  try {
22100
- const result = await fs_1.promises.readFile(path23, { encoding: "utf8" });
22143
+ const result = await fs_1.promises.readFile(path24, { encoding: "utf8" });
22101
22144
  return result.trim();
22102
22145
  } catch (e) {
22103
22146
  api_1.diag.debug(`error reading machine id: ${e}`);
@@ -25500,7 +25543,7 @@ function appendRootPathToUrlIfNeeded(url) {
25500
25543
  return void 0;
25501
25544
  }
25502
25545
  }
25503
- function appendResourcePathToUrl(url, path23) {
25546
+ function appendResourcePathToUrl(url, path24) {
25504
25547
  try {
25505
25548
  new URL(url);
25506
25549
  } catch (_a) {
@@ -25510,11 +25553,11 @@ function appendResourcePathToUrl(url, path23) {
25510
25553
  if (!url.endsWith("/")) {
25511
25554
  url = url + "/";
25512
25555
  }
25513
- url += path23;
25556
+ url += path24;
25514
25557
  try {
25515
25558
  new URL(url);
25516
25559
  } catch (_b) {
25517
- diag2.warn("Configuration: Provided URL appended with '" + path23 + "' is not a valid URL, using 'undefined' instead of '" + url + "'");
25560
+ diag2.warn("Configuration: Provided URL appended with '" + path24 + "' is not a valid URL, using 'undefined' instead of '" + url + "'");
25518
25561
  return void 0;
25519
25562
  }
25520
25563
  return url;
@@ -30819,16 +30862,100 @@ var require_src15 = __commonJS({
30819
30862
 
30820
30863
  // ts/agent-core/dist/telemetry.js
30821
30864
  import { AsyncLocalStorage } from "node:async_hooks";
30822
- async function initAgentTelemetry(serviceName, runtimeType) {
30865
+ import { readFileSync } from "node:fs";
30866
+ import * as path3 from "node:path";
30867
+ import { fileURLToPath } from "node:url";
30868
+ function resolveTelemetryEnvironment(apiUrl, override = process.env.PRLL_SERVER_ENV) {
30869
+ const forced = override?.trim();
30870
+ if (forced)
30871
+ return forced;
30872
+ let host = "";
30873
+ try {
30874
+ host = apiUrl ? new URL(apiUrl).hostname.toLowerCase() : "";
30875
+ } catch {
30876
+ host = "";
30877
+ }
30878
+ if (PRODUCTION_API_HOSTS.has(host))
30879
+ return "production";
30880
+ if (STAGING_API_HOSTS.has(host))
30881
+ return "staging";
30882
+ return "development";
30883
+ }
30884
+ function resolveServiceVersion(importMetaUrl) {
30885
+ const fallback = process.env.npm_package_version || "unknown";
30886
+ let dir;
30887
+ try {
30888
+ dir = path3.dirname(fileURLToPath(importMetaUrl));
30889
+ } catch {
30890
+ return fallback;
30891
+ }
30892
+ for (const candidate of [path3.join(dir, "manifest.json"), path3.join(dir, "..", "package.json")]) {
30893
+ try {
30894
+ const parsed = JSON.parse(readFileSync(candidate, "utf-8"));
30895
+ if (typeof parsed.version === "string" && parsed.version.trim()) {
30896
+ return parsed.version.trim();
30897
+ }
30898
+ } catch {
30899
+ }
30900
+ }
30901
+ return fallback;
30902
+ }
30903
+ function createThrottledDiagLogger(now = Date.now) {
30904
+ const lastAt = /* @__PURE__ */ new Map();
30905
+ const describe = (a) => {
30906
+ if (a instanceof Error)
30907
+ return a.message;
30908
+ if (a && typeof a === "object" && typeof a.message === "string") {
30909
+ return a.message;
30910
+ }
30911
+ if (typeof a === "string" && a.startsWith("{")) {
30912
+ try {
30913
+ const parsed = JSON.parse(a);
30914
+ if (typeof parsed.message === "string")
30915
+ return parsed.message;
30916
+ } catch {
30917
+ }
30918
+ }
30919
+ return String(a);
30920
+ };
30921
+ const emit = (level, args) => {
30922
+ const msg = args.map(describe).join(" ");
30923
+ const key = `${level}:${msg.slice(0, 160)}`;
30924
+ const at = now();
30925
+ const prev = lastAt.get(key);
30926
+ if (prev !== void 0 && at - prev < DIAG_THROTTLE_MS)
30927
+ return;
30928
+ if (lastAt.size >= DIAG_THROTTLE_KEYS)
30929
+ lastAt.clear();
30930
+ lastAt.set(key, at);
30931
+ console.warn(`${new Date(at).toISOString()} [telemetry] otel ${level}: ${msg}`);
30932
+ };
30933
+ return {
30934
+ verbose: () => {
30935
+ },
30936
+ debug: () => {
30937
+ },
30938
+ info: () => {
30939
+ },
30940
+ warn: (...args) => emit("warn", args),
30941
+ error: (...args) => emit("error", args)
30942
+ };
30943
+ }
30944
+ async function initAgentTelemetry(serviceName, runtimeType, opts = {}) {
30823
30945
  const noopHandle = { shutdown: async () => {
30824
30946
  } };
30825
- const apiUrl = process.env.PRLL_API_URL;
30826
- const apiKey = process.env.PRLL_API_KEY;
30947
+ const apiUrl = opts.apiUrl ?? process.env.PRLL_API_URL;
30948
+ const apiKey = opts.apiKey ?? process.env.PRLL_API_KEY;
30827
30949
  if (!apiUrl || !apiKey) {
30950
+ console.warn(`${(/* @__PURE__ */ new Date()).toISOString()} [telemetry] disabled: no API url/key resolved for ${serviceName} \u2014 nothing will reach SigNoz`);
30828
30951
  return noopHandle;
30829
30952
  }
30953
+ const environment = opts.environment ?? resolveTelemetryEnvironment(apiUrl);
30954
+ const serviceVersion = opts.serviceVersion ?? process.env.npm_package_version ?? "unknown";
30830
30955
  try {
30831
30956
  const otelEndpoint = apiUrl.replace(/\/$/, "") + "/otel";
30957
+ if (!initialized)
30958
+ diag2.setLogger(createThrottledDiagLogger(), DiagLogLevel.WARN);
30832
30959
  const { OTLPTraceExporter } = await Promise.resolve().then(() => __toESM(require_src6(), 1));
30833
30960
  const { OTLPMetricExporter } = await Promise.resolve().then(() => __toESM(require_src8(), 1));
30834
30961
  const { OTLPLogExporter } = await Promise.resolve().then(() => __toESM(require_src9(), 1));
@@ -30838,8 +30965,8 @@ async function initAgentTelemetry(serviceName, runtimeType) {
30838
30965
  const { Resource } = await Promise.resolve().then(() => __toESM(require_src3(), 1));
30839
30966
  const resource = new Resource({
30840
30967
  "service.name": serviceName,
30841
- "service.version": process.env.npm_package_version || "unknown",
30842
- "deployment.environment.name": process.env.PRLL_SERVER_ENV || process.env.NODE_ENV || "development",
30968
+ "service.version": serviceVersion,
30969
+ "deployment.environment.name": environment,
30843
30970
  "parall.runtime_type": runtimeType,
30844
30971
  "parall.agent_id": process.env.PRLL_AGENT_ID || "",
30845
30972
  "parall.machine_id": process.env.PRLL_MACHINE_ID || "",
@@ -30890,6 +31017,7 @@ async function initAgentTelemetry(serviceName, runtimeType) {
30890
31017
  description: "LLM cost per turn in USD (when the runtime reports it)"
30891
31018
  });
30892
31019
  initialized = true;
31020
+ console.log(`${(/* @__PURE__ */ new Date()).toISOString()} [telemetry] exporting ${serviceName} v${serviceVersion} env=${environment} to ${otelEndpoint}`);
30893
31021
  shutdownFn = async () => {
30894
31022
  await tracerProvider.forceFlush();
30895
31023
  await meterProvider.forceFlush();
@@ -30904,7 +31032,8 @@ async function initAgentTelemetry(serviceName, runtimeType) {
30904
31032
  await shutdownFn();
30905
31033
  }
30906
31034
  };
30907
- } catch {
31035
+ } catch (err) {
31036
+ console.warn(`${(/* @__PURE__ */ new Date()).toISOString()} [telemetry] init failed for ${serviceName}, running without export: ${String(err)}`);
30908
31037
  return noopHandle;
30909
31038
  }
30910
31039
  }
@@ -30941,7 +31070,7 @@ function createOtelLogger(layer, prefix) {
30941
31070
  child: (sub) => createOtelLogger(layer, `${prefix}:${sub}`)
30942
31071
  };
30943
31072
  }
30944
- var import_api_logs, initialized, shutdownFn, tracer, dispatchCounter, dispatchDuration, missingReplyCounter, turnTokensCounter, turnCostCounter, otelLogger, sessionKeyStorage;
31073
+ var import_api_logs, initialized, shutdownFn, tracer, dispatchCounter, dispatchDuration, missingReplyCounter, turnTokensCounter, turnCostCounter, otelLogger, PRODUCTION_API_HOSTS, STAGING_API_HOSTS, DIAG_THROTTLE_MS, DIAG_THROTTLE_KEYS, sessionKeyStorage;
30945
31074
  var init_telemetry = __esm({
30946
31075
  "ts/agent-core/dist/telemetry.js"() {
30947
31076
  "use strict";
@@ -30957,10 +31086,89 @@ var init_telemetry = __esm({
30957
31086
  turnTokensCounter = null;
30958
31087
  turnCostCounter = null;
30959
31088
  otelLogger = null;
31089
+ PRODUCTION_API_HOSTS = /* @__PURE__ */ new Set(["api.parall.com"]);
31090
+ STAGING_API_HOSTS = /* @__PURE__ */ new Set(["api.staging.prll.sh"]);
31091
+ DIAG_THROTTLE_MS = 6e4;
31092
+ DIAG_THROTTLE_KEYS = 200;
30960
31093
  sessionKeyStorage = new AsyncLocalStorage();
30961
31094
  }
30962
31095
  });
30963
31096
 
31097
+ // ts/agent-core/dist/gateway-runtime-turns.js
31098
+ var init_gateway_runtime_turns = __esm({
31099
+ "ts/agent-core/dist/gateway-runtime-turns.js"() {
31100
+ "use strict";
31101
+ init_dispatch_adapter();
31102
+ init_redact();
31103
+ init_telemetry();
31104
+ }
31105
+ });
31106
+
31107
+ // ts/agent-core/dist/gateway-drain.js
31108
+ var init_gateway_drain = __esm({
31109
+ "ts/agent-core/dist/gateway-drain.js"() {
31110
+ "use strict";
31111
+ }
31112
+ });
31113
+
31114
+ // ts/agent-core/dist/gateway-session-binding.js
31115
+ var init_gateway_session_binding = __esm({
31116
+ "ts/agent-core/dist/gateway-session-binding.js"() {
31117
+ "use strict";
31118
+ }
31119
+ });
31120
+
31121
+ // ts/agent-core/dist/dispatch-inactivity-deadline.js
31122
+ var init_dispatch_inactivity_deadline = __esm({
31123
+ "ts/agent-core/dist/dispatch-inactivity-deadline.js"() {
31124
+ "use strict";
31125
+ }
31126
+ });
31127
+
31128
+ // ts/agent-core/dist/routing.js
31129
+ var init_routing = __esm({
31130
+ "ts/agent-core/dist/routing.js"() {
31131
+ "use strict";
31132
+ }
31133
+ });
31134
+
31135
+ // ts/agent-core/dist/step-retry-queue.js
31136
+ var init_step_retry_queue = __esm({
31137
+ "ts/agent-core/dist/step-retry-queue.js"() {
31138
+ "use strict";
31139
+ }
31140
+ });
31141
+
31142
+ // ts/agent-core/dist/step-persister.js
31143
+ var init_step_persister = __esm({
31144
+ "ts/agent-core/dist/step-persister.js"() {
31145
+ "use strict";
31146
+ init_dist();
31147
+ init_step_retry_queue();
31148
+ }
31149
+ });
31150
+
31151
+ // ts/agent-core/dist/session-lifecycle.js
31152
+ var init_session_lifecycle = __esm({
31153
+ "ts/agent-core/dist/session-lifecycle.js"() {
31154
+ "use strict";
31155
+ }
31156
+ });
31157
+
31158
+ // ts/agent-core/dist/fork-session-finalizer.js
31159
+ var init_fork_session_finalizer = __esm({
31160
+ "ts/agent-core/dist/fork-session-finalizer.js"() {
31161
+ "use strict";
31162
+ }
31163
+ });
31164
+
31165
+ // ts/agent-core/dist/session-state.js
31166
+ var init_session_state = __esm({
31167
+ "ts/agent-core/dist/session-state.js"() {
31168
+ "use strict";
31169
+ }
31170
+ });
31171
+
30964
31172
  // ts/agent-core/dist/gateway-base.js
30965
31173
  var init_gateway_base = __esm({
30966
31174
  "ts/agent-core/dist/gateway-base.js"() {
@@ -30971,7 +31179,12 @@ var init_gateway_base = __esm({
30971
31179
  init_dispatch_adapter();
30972
31180
  init_fork_state();
30973
31181
  init_gateway_lane_flow();
31182
+ init_gateway_idle_compact();
31183
+ init_gateway_runtime_turns();
31184
+ init_gateway_drain();
31185
+ init_gateway_session_binding();
30974
31186
  init_lane_ledger();
31187
+ init_lane_target();
30975
31188
  init_dispatch_inactivity_deadline();
30976
31189
  init_routing();
30977
31190
  init_redact();
@@ -32092,14 +32305,14 @@ var require_util2 = __commonJS({
32092
32305
  }
32093
32306
  const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
32094
32307
  let origin = url.origin != null ? url.origin : `${url.protocol || ""}//${url.hostname || ""}:${port}`;
32095
- let path23 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
32308
+ let path24 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
32096
32309
  if (origin[origin.length - 1] === "/") {
32097
32310
  origin = origin.slice(0, origin.length - 1);
32098
32311
  }
32099
- if (path23 && path23[0] !== "/") {
32100
- path23 = `/${path23}`;
32312
+ if (path24 && path24[0] !== "/") {
32313
+ path24 = `/${path24}`;
32101
32314
  }
32102
- return new URL(`${origin}${path23}`);
32315
+ return new URL(`${origin}${path24}`);
32103
32316
  }
32104
32317
  if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
32105
32318
  throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
@@ -32920,9 +33133,9 @@ var require_diagnostics = __commonJS({
32920
33133
  "undici:client:sendHeaders",
32921
33134
  (evt) => {
32922
33135
  const {
32923
- request: { method, path: path23, origin }
33136
+ request: { method, path: path24, origin }
32924
33137
  } = evt;
32925
- debugLog("sending request to %s %s%s", method, origin, path23);
33138
+ debugLog("sending request to %s %s%s", method, origin, path24);
32926
33139
  }
32927
33140
  );
32928
33141
  }
@@ -32940,14 +33153,14 @@ var require_diagnostics = __commonJS({
32940
33153
  "undici:request:headers",
32941
33154
  (evt) => {
32942
33155
  const {
32943
- request: { method, path: path23, origin },
33156
+ request: { method, path: path24, origin },
32944
33157
  response: { statusCode }
32945
33158
  } = evt;
32946
33159
  debugLog(
32947
33160
  "received response to %s %s%s - HTTP %d",
32948
33161
  method,
32949
33162
  origin,
32950
- path23,
33163
+ path24,
32951
33164
  statusCode
32952
33165
  );
32953
33166
  }
@@ -32956,23 +33169,23 @@ var require_diagnostics = __commonJS({
32956
33169
  "undici:request:trailers",
32957
33170
  (evt) => {
32958
33171
  const {
32959
- request: { method, path: path23, origin }
33172
+ request: { method, path: path24, origin }
32960
33173
  } = evt;
32961
- debugLog("trailers received from %s %s%s", method, origin, path23);
33174
+ debugLog("trailers received from %s %s%s", method, origin, path24);
32962
33175
  }
32963
33176
  );
32964
33177
  diagnosticsChannel.subscribe(
32965
33178
  "undici:request:error",
32966
33179
  (evt) => {
32967
33180
  const {
32968
- request: { method, path: path23, origin },
33181
+ request: { method, path: path24, origin },
32969
33182
  error
32970
33183
  } = evt;
32971
33184
  debugLog(
32972
33185
  "request to %s %s%s errored - %s",
32973
33186
  method,
32974
33187
  origin,
32975
- path23,
33188
+ path24,
32976
33189
  error.message
32977
33190
  );
32978
33191
  }
@@ -33075,7 +33288,7 @@ var require_request = __commonJS({
33075
33288
  var kHandler = Symbol("handler");
33076
33289
  var Request = class {
33077
33290
  constructor(origin, {
33078
- path: path23,
33291
+ path: path24,
33079
33292
  method,
33080
33293
  body,
33081
33294
  headers,
@@ -33092,11 +33305,11 @@ var require_request = __commonJS({
33092
33305
  maxRedirections,
33093
33306
  typeOfService
33094
33307
  }, handler) {
33095
- if (typeof path23 !== "string") {
33308
+ if (typeof path24 !== "string") {
33096
33309
  throw new InvalidArgumentError("path must be a string");
33097
- } else if (path23[0] !== "/" && !(path23.startsWith("http://") || path23.startsWith("https://")) && method !== "CONNECT") {
33310
+ } else if (path24[0] !== "/" && !(path24.startsWith("http://") || path24.startsWith("https://")) && method !== "CONNECT") {
33098
33311
  throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
33099
- } else if (invalidPathRegex.test(path23)) {
33312
+ } else if (invalidPathRegex.test(path24)) {
33100
33313
  throw new InvalidArgumentError("invalid request path");
33101
33314
  }
33102
33315
  if (typeof method !== "string") {
@@ -33171,7 +33384,7 @@ var require_request = __commonJS({
33171
33384
  this.completed = false;
33172
33385
  this.aborted = false;
33173
33386
  this.upgrade = upgrade || null;
33174
- this.path = query ? serializePathWithQuery(path23, query) : path23;
33387
+ this.path = query ? serializePathWithQuery(path24, query) : path24;
33175
33388
  this.origin = origin;
33176
33389
  this.protocol = getProtocolFromUrlString(origin);
33177
33390
  this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
@@ -38210,7 +38423,7 @@ var require_client_h1 = __commonJS({
38210
38423
  return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
38211
38424
  }
38212
38425
  function writeH1(client, request3) {
38213
- const { method, path: path23, host, upgrade, blocking, reset } = request3;
38426
+ const { method, path: path24, host, upgrade, blocking, reset } = request3;
38214
38427
  let { body, headers, contentLength } = request3;
38215
38428
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
38216
38429
  if (util.isFormDataLike(body)) {
@@ -38279,7 +38492,7 @@ var require_client_h1 = __commonJS({
38279
38492
  if (socket.setTypeOfService) {
38280
38493
  socket.setTypeOfService(request3.typeOfService);
38281
38494
  }
38282
- let header = `${method} ${path23} HTTP/1.1\r
38495
+ let header = `${method} ${path24} HTTP/1.1\r
38283
38496
  `;
38284
38497
  if (typeof host === "string") {
38285
38498
  header += `host: ${host}\r
@@ -38932,7 +39145,7 @@ var require_client_h2 = __commonJS({
38932
39145
  function writeH2(client, request3) {
38933
39146
  const requestTimeout = request3.bodyTimeout ?? client[kBodyTimeout];
38934
39147
  const session = client[kHTTP2Session];
38935
- const { method, path: path23, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request3;
39148
+ const { method, path: path24, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request3;
38936
39149
  let { body } = request3;
38937
39150
  if (upgrade != null && upgrade !== "websocket") {
38938
39151
  util.errorRequest(client, request3, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
@@ -39000,7 +39213,7 @@ var require_client_h2 = __commonJS({
39000
39213
  }
39001
39214
  headers[HTTP2_HEADER_METHOD] = "CONNECT";
39002
39215
  headers[HTTP2_HEADER_PROTOCOL] = "websocket";
39003
- headers[HTTP2_HEADER_PATH] = path23;
39216
+ headers[HTTP2_HEADER_PATH] = path24;
39004
39217
  if (protocol === "ws:" || protocol === "wss:") {
39005
39218
  headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
39006
39219
  } else {
@@ -39041,7 +39254,7 @@ var require_client_h2 = __commonJS({
39041
39254
  stream.setTimeout(requestTimeout);
39042
39255
  return true;
39043
39256
  }
39044
- headers[HTTP2_HEADER_PATH] = path23;
39257
+ headers[HTTP2_HEADER_PATH] = path24;
39045
39258
  headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
39046
39259
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
39047
39260
  if (body && typeof body.read === "function") {
@@ -41343,10 +41556,10 @@ var require_proxy_agent = __commonJS({
41343
41556
  };
41344
41557
  const {
41345
41558
  origin,
41346
- path: path23 = "/",
41559
+ path: path24 = "/",
41347
41560
  headers = {}
41348
41561
  } = opts;
41349
- opts.path = origin + path23;
41562
+ opts.path = origin + path24;
41350
41563
  if (!("host" in headers) && !("Host" in headers)) {
41351
41564
  const { host } = new URL(origin);
41352
41565
  headers.host = host;
@@ -43409,20 +43622,20 @@ var require_mock_utils = __commonJS({
43409
43622
  }
43410
43623
  return normalizedQp;
43411
43624
  }
43412
- function safeUrl(path23) {
43413
- if (typeof path23 !== "string") {
43414
- return path23;
43625
+ function safeUrl(path24) {
43626
+ if (typeof path24 !== "string") {
43627
+ return path24;
43415
43628
  }
43416
- const pathSegments = path23.split("?", 3);
43629
+ const pathSegments = path24.split("?", 3);
43417
43630
  if (pathSegments.length !== 2) {
43418
- return path23;
43631
+ return path24;
43419
43632
  }
43420
43633
  const qp = new URLSearchParams(pathSegments.pop());
43421
43634
  qp.sort();
43422
43635
  return [...pathSegments, qp.toString()].join("?");
43423
43636
  }
43424
- function matchKey(mockDispatch2, { path: path23, method, body, headers }) {
43425
- const pathMatch = matchValue(mockDispatch2.path, path23);
43637
+ function matchKey(mockDispatch2, { path: path24, method, body, headers }) {
43638
+ const pathMatch = matchValue(mockDispatch2.path, path24);
43426
43639
  const methodMatch = matchValue(mockDispatch2.method, method);
43427
43640
  const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
43428
43641
  const headersMatch = matchHeaders(mockDispatch2, headers);
@@ -43447,8 +43660,8 @@ var require_mock_utils = __commonJS({
43447
43660
  const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path;
43448
43661
  const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
43449
43662
  const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
43450
- let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path23, ignoreTrailingSlash }) => {
43451
- return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path23)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path23), resolvedPath);
43663
+ let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path24, ignoreTrailingSlash }) => {
43664
+ return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path24)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path24), resolvedPath);
43452
43665
  });
43453
43666
  if (matchedMockDispatches.length === 0) {
43454
43667
  throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
@@ -43487,19 +43700,19 @@ var require_mock_utils = __commonJS({
43487
43700
  mockDispatches.splice(index, 1);
43488
43701
  }
43489
43702
  }
43490
- function removeTrailingSlash(path23) {
43491
- while (path23.endsWith("/")) {
43492
- path23 = path23.slice(0, -1);
43703
+ function removeTrailingSlash(path24) {
43704
+ while (path24.endsWith("/")) {
43705
+ path24 = path24.slice(0, -1);
43493
43706
  }
43494
- if (path23.length === 0) {
43495
- path23 = "/";
43707
+ if (path24.length === 0) {
43708
+ path24 = "/";
43496
43709
  }
43497
- return path23;
43710
+ return path24;
43498
43711
  }
43499
43712
  function buildKey(opts) {
43500
- const { path: path23, method, body, headers, query } = opts;
43713
+ const { path: path24, method, body, headers, query } = opts;
43501
43714
  return {
43502
- path: path23,
43715
+ path: path24,
43503
43716
  method,
43504
43717
  body,
43505
43718
  headers,
@@ -44189,10 +44402,10 @@ var require_pending_interceptors_formatter = __commonJS({
44189
44402
  }
44190
44403
  format(pendingInterceptors) {
44191
44404
  const withPrettyHeaders = pendingInterceptors.map(
44192
- ({ method, path: path23, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
44405
+ ({ method, path: path24, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
44193
44406
  Method: method,
44194
44407
  Origin: origin,
44195
- Path: path23,
44408
+ Path: path24,
44196
44409
  "Status code": statusCode,
44197
44410
  Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
44198
44411
  Invocations: timesInvoked,
@@ -44274,9 +44487,9 @@ var require_mock_agent = __commonJS({
44274
44487
  const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
44275
44488
  const dispatchOpts = { ...opts };
44276
44489
  if (acceptNonStandardSearchParameters && dispatchOpts.path) {
44277
- const [path23, searchParams] = dispatchOpts.path.split("?");
44490
+ const [path24, searchParams] = dispatchOpts.path.split("?");
44278
44491
  const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
44279
- dispatchOpts.path = `${path23}?${normalizedSearchParams}`;
44492
+ dispatchOpts.path = `${path24}?${normalizedSearchParams}`;
44280
44493
  }
44281
44494
  return this[kAgent].dispatch(dispatchOpts, handler);
44282
44495
  }
@@ -44481,7 +44694,7 @@ var require_snapshot_recorder = __commonJS({
44481
44694
  "ts/node_modules/.pnpm/undici@7.24.8/node_modules/undici/lib/mock/snapshot-recorder.js"(exports2, module2) {
44482
44695
  "use strict";
44483
44696
  var { writeFile, readFile, mkdir } = __require("node:fs/promises");
44484
- var { dirname: dirname13, resolve: resolve9 } = __require("node:path");
44697
+ var { dirname: dirname14, resolve: resolve9 } = __require("node:path");
44485
44698
  var { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = __require("node:timers");
44486
44699
  var { InvalidArgumentError, UndiciError } = require_errors();
44487
44700
  var { hashId, isUrlExcludedFactory, normalizeHeaders, createHeaderFilters } = require_snapshot_utils();
@@ -44677,12 +44890,12 @@ var require_snapshot_recorder = __commonJS({
44677
44890
  * @return {Promise<void>} - Resolves when snapshots are loaded
44678
44891
  */
44679
44892
  async loadSnapshots(filePath) {
44680
- const path23 = filePath || this.#snapshotPath;
44681
- if (!path23) {
44893
+ const path24 = filePath || this.#snapshotPath;
44894
+ if (!path24) {
44682
44895
  throw new InvalidArgumentError("Snapshot path is required");
44683
44896
  }
44684
44897
  try {
44685
- const data = await readFile(resolve9(path23), "utf8");
44898
+ const data = await readFile(resolve9(path24), "utf8");
44686
44899
  const parsed = JSON.parse(data);
44687
44900
  if (Array.isArray(parsed)) {
44688
44901
  this.#snapshots.clear();
@@ -44696,7 +44909,7 @@ var require_snapshot_recorder = __commonJS({
44696
44909
  if (error.code === "ENOENT") {
44697
44910
  this.#snapshots.clear();
44698
44911
  } else {
44699
- throw new UndiciError(`Failed to load snapshots from ${path23}`, { cause: error });
44912
+ throw new UndiciError(`Failed to load snapshots from ${path24}`, { cause: error });
44700
44913
  }
44701
44914
  }
44702
44915
  }
@@ -44707,12 +44920,12 @@ var require_snapshot_recorder = __commonJS({
44707
44920
  * @returns {Promise<void>} - Resolves when snapshots are saved
44708
44921
  */
44709
44922
  async saveSnapshots(filePath) {
44710
- const path23 = filePath || this.#snapshotPath;
44711
- if (!path23) {
44923
+ const path24 = filePath || this.#snapshotPath;
44924
+ if (!path24) {
44712
44925
  throw new InvalidArgumentError("Snapshot path is required");
44713
44926
  }
44714
- const resolvedPath = resolve9(path23);
44715
- await mkdir(dirname13(resolvedPath), { recursive: true });
44927
+ const resolvedPath = resolve9(path24);
44928
+ await mkdir(dirname14(resolvedPath), { recursive: true });
44716
44929
  const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
44717
44930
  hash,
44718
44931
  snapshot
@@ -45336,15 +45549,15 @@ var require_redirect_handler = __commonJS({
45336
45549
  return;
45337
45550
  }
45338
45551
  const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
45339
- const path23 = search ? `${pathname}${search}` : pathname;
45340
- const redirectUrlString = `${origin}${path23}`;
45552
+ const path24 = search ? `${pathname}${search}` : pathname;
45553
+ const redirectUrlString = `${origin}${path24}`;
45341
45554
  for (const historyUrl of this.history) {
45342
45555
  if (historyUrl.toString() === redirectUrlString) {
45343
45556
  throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`);
45344
45557
  }
45345
45558
  }
45346
45559
  this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
45347
- this.opts.path = path23;
45560
+ this.opts.path = path24;
45348
45561
  this.opts.origin = origin;
45349
45562
  this.opts.query = null;
45350
45563
  }
@@ -51551,11 +51764,11 @@ var require_fetch = __commonJS({
51551
51764
  function dispatch({ body }) {
51552
51765
  const url = requestCurrentURL(request3);
51553
51766
  const agent = fetchParams.controller.dispatcher;
51554
- const path23 = url.pathname + url.search;
51767
+ const path24 = url.pathname + url.search;
51555
51768
  const hasTrailingQuestionMark = url.search.length === 0 && url.href[url.href.length - url.hash.length - 1] === "?";
51556
51769
  return new Promise((resolve9, reject) => agent.dispatch(
51557
51770
  {
51558
- path: hasTrailingQuestionMark ? `${path23}?` : path23,
51771
+ path: hasTrailingQuestionMark ? `${path24}?` : path24,
51559
51772
  origin: url.origin,
51560
51773
  method: request3.method,
51561
51774
  body: agent.isMockActive ? request3.body && (request3.body.source || request3.body.stream) : body,
@@ -52502,9 +52715,9 @@ var require_util5 = __commonJS({
52502
52715
  }
52503
52716
  }
52504
52717
  }
52505
- function validateCookiePath(path23) {
52506
- for (let i = 0; i < path23.length; ++i) {
52507
- const code = path23.charCodeAt(i);
52718
+ function validateCookiePath(path24) {
52719
+ for (let i = 0; i < path24.length; ++i) {
52720
+ const code = path24.charCodeAt(i);
52508
52721
  if (code < 32 || // exclude CTLs (0-31)
52509
52722
  code === 127 || // DEL
52510
52723
  code === 59) {
@@ -55674,11 +55887,11 @@ var require_undici = __commonJS({
55674
55887
  if (typeof opts.path !== "string") {
55675
55888
  throw new InvalidArgumentError("invalid opts.path");
55676
55889
  }
55677
- let path23 = opts.path;
55890
+ let path24 = opts.path;
55678
55891
  if (!opts.path.startsWith("/")) {
55679
- path23 = `/${path23}`;
55892
+ path24 = `/${path24}`;
55680
55893
  }
55681
- url = new URL(util.parseOrigin(url).origin + path23);
55894
+ url = new URL(util.parseOrigin(url).origin + path24);
55682
55895
  } else {
55683
55896
  if (!opts) {
55684
55897
  opts = typeof url === "object" ? url : {};
@@ -55953,6 +56166,21 @@ var init_provider_config = __esm({
55953
56166
  }
55954
56167
  });
55955
56168
 
56169
+ // ts/agent-core/dist/runtime-activity-port.js
56170
+ var init_runtime_activity_port = __esm({
56171
+ "ts/agent-core/dist/runtime-activity-port.js"() {
56172
+ "use strict";
56173
+ init_dispatch_adapter();
56174
+ }
56175
+ });
56176
+
56177
+ // ts/agent-core/dist/runtime-turn-base.js
56178
+ var init_runtime_turn_base = __esm({
56179
+ "ts/agent-core/dist/runtime-turn-base.js"() {
56180
+ "use strict";
56181
+ }
56182
+ });
56183
+
55956
56184
  // ts/agent-core/dist/types.js
55957
56185
  var init_types4 = __esm({
55958
56186
  "ts/agent-core/dist/types.js"() {
@@ -55970,6 +56198,7 @@ var init_dist2 = __esm({
55970
56198
  init_dispatch_adapter();
55971
56199
  init_fork_prefix();
55972
56200
  init_gateway_base();
56201
+ init_gateway_idle_compact();
55973
56202
  init_gateway_lane_flow();
55974
56203
  init_http_keepalive();
55975
56204
  init_lane_key();
@@ -55981,6 +56210,8 @@ var init_dist2 = __esm({
55981
56210
  init_provider_config();
55982
56211
  init_redact();
55983
56212
  init_routing();
56213
+ init_runtime_activity_port();
56214
+ init_runtime_turn_base();
55984
56215
  init_session_state();
55985
56216
  init_skills();
55986
56217
  init_telemetry();
@@ -56006,7 +56237,7 @@ __export(config_exports, {
56006
56237
  });
56007
56238
  import * as fs from "node:fs";
56008
56239
  import * as os2 from "node:os";
56009
- import * as path3 from "node:path";
56240
+ import * as path4 from "node:path";
56010
56241
  function parseMs(value, fallback) {
56011
56242
  if (!value)
56012
56243
  return fallback;
@@ -56020,7 +56251,7 @@ function parseMsAllowZero(value, fallback) {
56020
56251
  return Number.isFinite(n) && n >= 0 ? n : fallback;
56021
56252
  }
56022
56253
  function daemonConfigPath(env = process.env) {
56023
- return path3.join(daemonConfigDir(env), "config.json");
56254
+ return path4.join(daemonConfigDir(env), "config.json");
56024
56255
  }
56025
56256
  function tryLoadConfigFile(env) {
56026
56257
  const cfgPath = daemonConfigPath(env);
@@ -56060,7 +56291,7 @@ function resolveClaudeDaemonConfig(env = process.env) {
56060
56291
  throw new Error(`PRLL_API_KEY does not look like a Machine bearer (expected prefix "mck_"). Daemon mode requires a machine-scoped key issued via POST /machines/{id}/keys.`);
56061
56292
  }
56062
56293
  const rootClaudeHome = resolvePath(env.PRLL_CLAUDE_HOME?.trim() || env.HOME || os2.homedir());
56063
- const rootStateDir = resolvePath(env.PRLL_CLAUDE_STATE_DIR?.trim() || path3.join(rootClaudeHome, ".parall-agent"));
56294
+ const rootStateDir = resolvePath(env.PRLL_CLAUDE_STATE_DIR?.trim() || path4.join(rootClaudeHome, ".parall-agent"));
56064
56295
  return {
56065
56296
  apiUrl,
56066
56297
  apiKey,
@@ -56091,22 +56322,22 @@ function assertSafeAgentId(agentId) {
56091
56322
  return agentId;
56092
56323
  }
56093
56324
  function agentStateDirFor(rootStateDir, agentId) {
56094
- return path3.join(rootStateDir, "agents", assertSafeAgentId(agentId));
56325
+ return path4.join(rootStateDir, "agents", assertSafeAgentId(agentId));
56095
56326
  }
56096
56327
  function agentClaudeHomeFor(rootClaudeHome, agentId) {
56097
- return path3.join(rootClaudeHome, "agents", assertSafeAgentId(agentId));
56328
+ return path4.join(rootClaudeHome, "agents", assertSafeAgentId(agentId));
56098
56329
  }
56099
56330
  function sharedClaudeCredentialsFileFor(rootClaudeHome) {
56100
- return path3.join(rootClaudeHome, ".claude", ".credentials.json");
56331
+ return path4.join(rootClaudeHome, ".claude", ".credentials.json");
56101
56332
  }
56102
56333
  function agentClaudeCredentialsFileFor(agentClaudeHome) {
56103
- return path3.join(agentClaudeHome, ".claude", ".credentials.json");
56334
+ return path4.join(agentClaudeHome, ".claude", ".credentials.json");
56104
56335
  }
56105
56336
  function agentWorkspaceDirFor(rootStateDir, agentId) {
56106
- return path3.join(rootStateDir, "agents", assertSafeAgentId(agentId), "workspace");
56337
+ return path4.join(rootStateDir, "agents", assertSafeAgentId(agentId), "workspace");
56107
56338
  }
56108
56339
  function agentHomeDirFor(rootStateDir, agentId) {
56109
- return path3.join(rootStateDir, "agents", assertSafeAgentId(agentId), "home");
56340
+ return path4.join(rootStateDir, "agents", assertSafeAgentId(agentId), "home");
56110
56341
  }
56111
56342
  function resolveUpdateSigningEnabled(env = process.env) {
56112
56343
  return env.PRLL_DAEMON_SIGNING_DISABLED !== "1";
@@ -56127,22 +56358,22 @@ var init_config = __esm({
56127
56358
  });
56128
56359
 
56129
56360
  // ts/daemon/dist/win-service.js
56130
- import * as path4 from "node:path";
56361
+ import * as path5 from "node:path";
56131
56362
  function winServicePaths(home) {
56132
- const root = path4.join(home, ".parall-daemon");
56133
- const serviceDir = path4.join(root, "service");
56134
- const logDir = path4.join(root, "logs");
56363
+ const root = path5.join(home, ".parall-daemon");
56364
+ const serviceDir = path5.join(root, "service");
56365
+ const logDir = path5.join(root, "logs");
56135
56366
  return {
56136
56367
  serviceDir,
56137
- launcherCjs: path4.join(serviceDir, "parall-daemon-launcher.cjs"),
56138
- legacyLauncherJs: path4.join(serviceDir, "parall-daemon-launcher.js"),
56139
- launcherVbs: path4.join(serviceDir, "parall-daemon-launcher.vbs"),
56140
- taskXml: path4.join(serviceDir, "task.xml"),
56141
- pidFile: path4.join(root, "daemon.pid"),
56368
+ launcherCjs: path5.join(serviceDir, "parall-daemon-launcher.cjs"),
56369
+ legacyLauncherJs: path5.join(serviceDir, "parall-daemon-launcher.js"),
56370
+ launcherVbs: path5.join(serviceDir, "parall-daemon-launcher.vbs"),
56371
+ taskXml: path5.join(serviceDir, "task.xml"),
56372
+ pidFile: path5.join(root, "daemon.pid"),
56142
56373
  logDir,
56143
- logFile: path4.join(logDir, "parall-daemon.log"),
56144
- overlayEntry: path4.join(root, "bundle", "current", "parall-daemon.js"),
56145
- runningMarker: path4.join(root, "bundle", "daemon-running")
56374
+ logFile: path5.join(logDir, "parall-daemon.log"),
56375
+ overlayEntry: path5.join(root, "bundle", "current", "parall-daemon.js"),
56376
+ runningMarker: path5.join(root, "bundle", "daemon-running")
56146
56377
  };
56147
56378
  }
56148
56379
  function vbsQuote(value) {
@@ -56283,7 +56514,7 @@ var init_win_service = __esm({
56283
56514
  });
56284
56515
 
56285
56516
  // ts/daemon/dist/win-lifecycle.js
56286
- import * as path5 from "node:path";
56517
+ import * as path6 from "node:path";
56287
56518
  function probePidIdentity(deps, pid) {
56288
56519
  const script = `$p = Get-CimInstance Win32_Process -Filter 'ProcessId=${pid}'; if ($null -eq $p) { 'ABSENT' } else { 'PRESENT' + [char]9 + $p.Name + [char]9 + "$($p.CommandLine)" }`;
56289
56520
  const r = deps.run("powershell.exe", ["-NoProfile", "-Command", script]);
@@ -56301,7 +56532,7 @@ function probePidIdentity(deps, pid) {
56301
56532
  if (!commandLine) {
56302
56533
  return "indeterminate";
56303
56534
  }
56304
- const launcherNeedle = path5.join(deps.paths.serviceDir, "parall-daemon-launcher").toLowerCase();
56535
+ const launcherNeedle = path6.join(deps.paths.serviceDir, "parall-daemon-launcher").toLowerCase();
56305
56536
  return commandLine.toLowerCase().includes(launcherNeedle) ? "daemon" : "not-daemon";
56306
56537
  }
56307
56538
  function readTrackedPid(deps) {
@@ -56549,7 +56780,7 @@ __export(updater_exports, {
56549
56780
  DaemonUpdater: () => DaemonUpdater
56550
56781
  });
56551
56782
  import * as fs2 from "node:fs";
56552
- import * as path6 from "node:path";
56783
+ import * as path7 from "node:path";
56553
56784
  import * as https2 from "node:https";
56554
56785
  import * as http2 from "node:http";
56555
56786
  import { createHash } from "node:crypto";
@@ -56645,20 +56876,20 @@ MCowBQYDK2VwAyEAQHQAZThNX7+deJNyHl/5DgiAa1OHx7UQoJotam0JhUk=
56645
56876
  return false;
56646
56877
  if (!state.previous_version)
56647
56878
  return false;
56648
- const previousDir = path6.join(this.bundleDir, "versions", state.previous_version);
56879
+ const previousDir = path7.join(this.bundleDir, "versions", state.previous_version);
56649
56880
  if (!fs2.existsSync(previousDir))
56650
56881
  return false;
56651
56882
  this.log.warn(`rollback: ${current.version} failed ${state.boot_count} boots, reverting to ${state.previous_version}`);
56652
56883
  if (process.platform === "win32") {
56653
- const currentDir = path6.join(this.bundleDir, "current");
56884
+ const currentDir = path7.join(this.bundleDir, "current");
56654
56885
  if (fs2.existsSync(currentDir)) {
56655
56886
  for (const file of fs2.readdirSync(currentDir)) {
56656
- fs2.unlinkSync(path6.join(currentDir, file));
56887
+ fs2.unlinkSync(path7.join(currentDir, file));
56657
56888
  }
56658
56889
  }
56659
56890
  fs2.mkdirSync(currentDir, { recursive: true });
56660
56891
  for (const file of fs2.readdirSync(previousDir)) {
56661
- fs2.copyFileSync(path6.join(previousDir, file), path6.join(currentDir, file));
56892
+ fs2.copyFileSync(path7.join(previousDir, file), path7.join(currentDir, file));
56662
56893
  }
56663
56894
  } else {
56664
56895
  this.swapSymlink(state.previous_version);
@@ -56780,11 +57011,11 @@ MCowBQYDK2VwAyEAQHQAZThNX7+deJNyHl/5DgiAa1OHx7UQoJotam0JhUk=
56780
57011
  return false;
56781
57012
  }
56782
57013
  }
56783
- const stagingDir = path6.join(this.bundleDir, "staging");
57014
+ const stagingDir = path7.join(this.bundleDir, "staging");
56784
57015
  this.cleanDir(stagingDir);
56785
57016
  fs2.mkdirSync(stagingDir, { recursive: true });
56786
57017
  for (const [filename, meta] of Object.entries(remote.files)) {
56787
- const filePath = path6.join(stagingDir, filename);
57018
+ const filePath = path7.join(stagingDir, filename);
56788
57019
  const fileUrl = `${this.cdnBaseUrl}/${remote.version}/${filename}`;
56789
57020
  try {
56790
57021
  await this.downloadFile(fileUrl, filePath);
@@ -56806,7 +57037,7 @@ MCowBQYDK2VwAyEAQHQAZThNX7+deJNyHl/5DgiAa1OHx7UQoJotam0JhUk=
56806
57037
  return false;
56807
57038
  }
56808
57039
  }
56809
- fs2.writeFileSync(path6.join(stagingDir, "manifest.json"), JSON.stringify(remote, null, 2));
57040
+ fs2.writeFileSync(path7.join(stagingDir, "manifest.json"), JSON.stringify(remote, null, 2));
56810
57041
  const rollbackVersion = state?.confirmed_version ?? local?.version;
56811
57042
  const newState = {
56812
57043
  confirmed_version: rollbackVersion,
@@ -56821,9 +57052,9 @@ MCowBQYDK2VwAyEAQHQAZThNX7+deJNyHl/5DgiAa1OHx7UQoJotam0JhUk=
56821
57052
  return true;
56822
57053
  }
56823
57054
  atomicSwap(stagingDir, newVersion) {
56824
- const versionsDir = path6.join(this.bundleDir, "versions");
56825
- const targetDir = path6.join(versionsDir, newVersion);
56826
- const currentLink = path6.join(this.bundleDir, "current");
57055
+ const versionsDir = path7.join(this.bundleDir, "versions");
57056
+ const targetDir = path7.join(versionsDir, newVersion);
57057
+ const currentLink = path7.join(this.bundleDir, "current");
56827
57058
  fs2.mkdirSync(versionsDir, { recursive: true });
56828
57059
  if (fs2.existsSync(targetDir)) {
56829
57060
  fs2.rmSync(targetDir, { recursive: true });
@@ -56833,12 +57064,12 @@ MCowBQYDK2VwAyEAQHQAZThNX7+deJNyHl/5DgiAa1OHx7UQoJotam0JhUk=
56833
57064
  const currentDir = currentLink;
56834
57065
  if (fs2.existsSync(currentDir)) {
56835
57066
  for (const file of fs2.readdirSync(currentDir)) {
56836
- fs2.unlinkSync(path6.join(currentDir, file));
57067
+ fs2.unlinkSync(path7.join(currentDir, file));
56837
57068
  }
56838
57069
  }
56839
57070
  fs2.mkdirSync(currentDir, { recursive: true });
56840
57071
  for (const file of fs2.readdirSync(targetDir)) {
56841
- fs2.copyFileSync(path6.join(targetDir, file), path6.join(currentDir, file));
57072
+ fs2.copyFileSync(path7.join(targetDir, file), path7.join(currentDir, file));
56842
57073
  }
56843
57074
  } else {
56844
57075
  this.swapSymlink(newVersion);
@@ -56846,7 +57077,7 @@ MCowBQYDK2VwAyEAQHQAZThNX7+deJNyHl/5DgiAa1OHx7UQoJotam0JhUk=
56846
57077
  this.pruneOldVersions(versionsDir, newVersion);
56847
57078
  }
56848
57079
  swapSymlink(version) {
56849
- const currentLink = path6.join(this.bundleDir, "current");
57080
+ const currentLink = path7.join(this.bundleDir, "current");
56850
57081
  const tmpLink = `${currentLink}.new`;
56851
57082
  try {
56852
57083
  fs2.unlinkSync(tmpLink);
@@ -56865,7 +57096,7 @@ MCowBQYDK2VwAyEAQHQAZThNX7+deJNyHl/5DgiAa1OHx7UQoJotam0JhUk=
56865
57096
  try {
56866
57097
  for (const entry of fs2.readdirSync(versionsDir)) {
56867
57098
  if (!keep.has(entry)) {
56868
- fs2.rmSync(path6.join(versionsDir, entry), { recursive: true });
57099
+ fs2.rmSync(path7.join(versionsDir, entry), { recursive: true });
56869
57100
  }
56870
57101
  }
56871
57102
  } catch {
@@ -56873,8 +57104,8 @@ MCowBQYDK2VwAyEAQHQAZThNX7+deJNyHl/5DgiAa1OHx7UQoJotam0JhUk=
56873
57104
  }
56874
57105
  // --- Manifest & State I/O ---
56875
57106
  loadLocalManifest() {
56876
- const currentDir = path6.join(this.bundleDir, "current");
56877
- const manifestPath = path6.join(currentDir, "manifest.json");
57107
+ const currentDir = path7.join(this.bundleDir, "current");
57108
+ const manifestPath = path7.join(currentDir, "manifest.json");
56878
57109
  try {
56879
57110
  return JSON.parse(fs2.readFileSync(manifestPath, "utf-8"));
56880
57111
  } catch {
@@ -56882,7 +57113,7 @@ MCowBQYDK2VwAyEAQHQAZThNX7+deJNyHl/5DgiAa1OHx7UQoJotam0JhUk=
56882
57113
  }
56883
57114
  }
56884
57115
  loadUpdateState() {
56885
- const statePath = path6.join(this.bundleDir, "update-state.json");
57116
+ const statePath = path7.join(this.bundleDir, "update-state.json");
56886
57117
  try {
56887
57118
  return JSON.parse(fs2.readFileSync(statePath, "utf-8"));
56888
57119
  } catch {
@@ -56890,8 +57121,8 @@ MCowBQYDK2VwAyEAQHQAZThNX7+deJNyHl/5DgiAa1OHx7UQoJotam0JhUk=
56890
57121
  }
56891
57122
  }
56892
57123
  saveUpdateState(state) {
56893
- const statePath = path6.join(this.bundleDir, "update-state.json");
56894
- const stateDir = path6.dirname(statePath);
57124
+ const statePath = path7.join(this.bundleDir, "update-state.json");
57125
+ const stateDir = path7.dirname(statePath);
56895
57126
  fs2.mkdirSync(stateDir, { recursive: true });
56896
57127
  const tmpPath = `${statePath}.tmp-${process.pid}-${Date.now()}`;
56897
57128
  let fd;
@@ -57030,7 +57261,7 @@ MCowBQYDK2VwAyEAQHQAZThNX7+deJNyHl/5DgiAa1OHx7UQoJotam0JhUk=
57030
57261
  import { execFileSync, execSync, spawn } from "node:child_process";
57031
57262
  import * as fs3 from "node:fs";
57032
57263
  import * as os3 from "node:os";
57033
- import * as path7 from "node:path";
57264
+ import * as path8 from "node:path";
57034
57265
  import * as readline from "node:readline";
57035
57266
  function readConfig() {
57036
57267
  try {
@@ -57139,7 +57370,7 @@ function installServiceWindows() {
57139
57370
  fs3.unlinkSync(p.legacyLauncherJs);
57140
57371
  } catch {
57141
57372
  }
57142
- const wscriptExe = path7.join(process.env.SystemRoot || "C:\\Windows", "System32", "wscript.exe");
57373
+ const wscriptExe = path8.join(process.env.SystemRoot || "C:\\Windows", "System32", "wscript.exe");
57143
57374
  fs3.writeFileSync(p.launcherVbs, encodeUtf16LeBom(buildLauncherVbs({ nodeExe: process.execPath, launcherCjs: p.launcherCjs })));
57144
57375
  fs3.writeFileSync(p.taskXml, encodeUtf16LeBom(buildTaskXml({ wscriptExe, launcherVbs: p.launcherVbs })));
57145
57376
  const create = runWinCmd("schtasks", ["/Create", "/TN", WIN_TASK_NAME, "/XML", p.taskXml, "/F"]);
@@ -57205,10 +57436,10 @@ function serviceUninstallWindows() {
57205
57436
  console.log("Task Scheduler task uninstalled (logs kept).");
57206
57437
  }
57207
57438
  function plistPath() {
57208
- return path7.join(os3.homedir(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
57439
+ return path8.join(os3.homedir(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
57209
57440
  }
57210
57441
  function systemdUnitPath() {
57211
- return path7.join(os3.homedir(), ".config", "systemd", "user", "parall-daemon.service");
57442
+ return path8.join(os3.homedir(), ".config", "systemd", "user", "parall-daemon.service");
57212
57443
  }
57213
57444
  function getDaemonBin() {
57214
57445
  try {
@@ -57218,7 +57449,7 @@ function getDaemonBin() {
57218
57449
  }
57219
57450
  }
57220
57451
  function generatePlist(daemonBin) {
57221
- const logPath = path7.join(os3.homedir(), "Library", "Logs", "parall-daemon.log");
57452
+ const logPath = path8.join(os3.homedir(), "Library", "Logs", "parall-daemon.log");
57222
57453
  return `<?xml version="1.0" encoding="UTF-8"?>
57223
57454
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
57224
57455
  <plist version="1.0">
@@ -57277,14 +57508,14 @@ function installService() {
57277
57508
  }
57278
57509
  const bin = getDaemonBin();
57279
57510
  if (isMacOS()) {
57280
- const dir = path7.dirname(plistPath());
57511
+ const dir = path8.dirname(plistPath());
57281
57512
  fs3.mkdirSync(dir, { recursive: true });
57282
57513
  fs3.writeFileSync(plistPath(), generatePlist(bin));
57283
57514
  execSync(`launchctl bootout gui/$(id -u) ${plistPath()} 2>/dev/null || true`);
57284
57515
  execSync(`launchctl bootstrap gui/$(id -u) ${plistPath()}`);
57285
57516
  console.log(`launchd agent installed: ${plistPath()}`);
57286
57517
  } else if (isLinux()) {
57287
- const dir = path7.dirname(systemdUnitPath());
57518
+ const dir = path8.dirname(systemdUnitPath());
57288
57519
  fs3.mkdirSync(dir, { recursive: true });
57289
57520
  fs3.writeFileSync(systemdUnitPath(), generateSystemdUnit(bin));
57290
57521
  execSync("systemctl --user daemon-reload");
@@ -57377,7 +57608,7 @@ function cmdLogs(lines) {
57377
57608
  child2.on("exit", (code) => process.exit(code ?? 0));
57378
57609
  return;
57379
57610
  }
57380
- const logPath = path7.join(os3.homedir(), "Library", "Logs", "parall-daemon.log");
57611
+ const logPath = path8.join(os3.homedir(), "Library", "Logs", "parall-daemon.log");
57381
57612
  if (!fs3.existsSync(logPath)) {
57382
57613
  console.log("No log file found at", logPath);
57383
57614
  return;
@@ -61485,8 +61716,8 @@ var init_browser_cdp = __esm({
61485
61716
 
61486
61717
  // ts/daemon/dist/clip-runtime/browser-proxy-state.js
61487
61718
  import { createHash as createHash2 } from "node:crypto";
61488
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "node:fs";
61489
- import * as path8 from "node:path";
61719
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync5, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "node:fs";
61720
+ import * as path9 from "node:path";
61490
61721
  function normalizeProxyConfig(proxy) {
61491
61722
  if (!proxy || !proxy.server?.trim()) {
61492
61723
  if (proxy && (proxy.username || proxy.password)) {
@@ -61520,7 +61751,7 @@ function proxyFingerprint(proxy) {
61520
61751
  }
61521
61752
  function readSidecarObject(homeDir, file) {
61522
61753
  try {
61523
- const parsed = JSON.parse(readFileSync4(path8.join(homeDir, file), "utf8"));
61754
+ const parsed = JSON.parse(readFileSync5(path9.join(homeDir, file), "utf8"));
61524
61755
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
61525
61756
  } catch {
61526
61757
  return {};
@@ -61533,7 +61764,7 @@ function appliedProxyFingerprint(homeDir, account) {
61533
61764
  function writeAppliedProxyFingerprint(homeDir, account, fingerprint) {
61534
61765
  const state = readSidecarObject(homeDir, PROXY_STATE_FILE);
61535
61766
  state.applied = { ...state.applied, [account]: fingerprint };
61536
- atomicWriteJson(path8.join(homeDir, PROXY_STATE_FILE), state);
61767
+ atomicWriteJson(path9.join(homeDir, PROXY_STATE_FILE), state);
61537
61768
  }
61538
61769
  function readCookieBackup(homeDir, account) {
61539
61770
  const cookies = readSidecarObject(homeDir, COOKIE_BACKUP_FILE).backups?.[account];
@@ -61553,10 +61784,10 @@ function clearCookieBackup(homeDir, account) {
61553
61784
  function updateCookieBackupFile(homeDir, mutate) {
61554
61785
  const file = readSidecarObject(homeDir, COOKIE_BACKUP_FILE);
61555
61786
  mutate(file);
61556
- atomicWriteJson(path8.join(homeDir, COOKIE_BACKUP_FILE), file);
61787
+ atomicWriteJson(path9.join(homeDir, COOKIE_BACKUP_FILE), file);
61557
61788
  }
61558
61789
  function atomicWriteJson(filePath, value) {
61559
- mkdirSync3(path8.dirname(filePath), { recursive: true });
61790
+ mkdirSync3(path9.dirname(filePath), { recursive: true });
61560
61791
  const tmp = `${filePath}.tmp-${process.pid}`;
61561
61792
  writeFileSync3(tmp, JSON.stringify(value));
61562
61793
  renameSync2(tmp, filePath);
@@ -61860,17 +62091,17 @@ var init_browser_readiness = __esm({
61860
62091
 
61861
62092
  // ts/daemon/dist/clip-runtime/bun-resolver.js
61862
62093
  import * as fs4 from "node:fs";
61863
- import * as path9 from "node:path";
62094
+ import * as path10 from "node:path";
61864
62095
  import { execFileSync as execFileSync2 } from "node:child_process";
61865
62096
  function findBunBinary() {
61866
62097
  const isWindows2 = process.platform === "win32";
61867
62098
  const binName = isWindows2 ? "bun.exe" : "bun";
61868
- const embedded = path9.join(path9.dirname(process.execPath), binName);
62099
+ const embedded = path10.join(path10.dirname(process.execPath), binName);
61869
62100
  if (fs4.existsSync(embedded))
61870
62101
  return embedded;
61871
62102
  if (!isWindows2) {
61872
62103
  const candidates = [
61873
- path9.join(process.env.HOME || "", ".bun", "bin", "bun"),
62104
+ path10.join(process.env.HOME || "", ".bun", "bin", "bun"),
61874
62105
  "/usr/local/bin/bun",
61875
62106
  "/opt/homebrew/bin/bun"
61876
62107
  ];
@@ -61898,7 +62129,7 @@ var init_bun_resolver = __esm({
61898
62129
 
61899
62130
  // ts/daemon/dist/clip-runtime/clip-installer.js
61900
62131
  import * as fs5 from "node:fs";
61901
- import * as path10 from "node:path";
62132
+ import * as path11 from "node:path";
61902
62133
  import * as crypto from "node:crypto";
61903
62134
  import { execFileSync as execFileSync3 } from "node:child_process";
61904
62135
  import { pipeline } from "node:stream/promises";
@@ -62112,7 +62343,7 @@ function verifyChecksum(filePath, algo, expectedHex) {
62112
62343
  hash.update(content);
62113
62344
  const actual = hash.digest("hex");
62114
62345
  if (actual !== expectedHex) {
62115
- throw new Error(`checksum mismatch for ${path10.basename(filePath)}: expected ${algo}:${expectedHex}, got ${algo}:${actual}`);
62346
+ throw new Error(`checksum mismatch for ${path11.basename(filePath)}: expected ${algo}:${expectedHex}, got ${algo}:${actual}`);
62116
62347
  }
62117
62348
  }
62118
62349
  function validateTarEntries(tarballPath) {
@@ -62129,11 +62360,11 @@ function validateTarEntries(tarballPath) {
62129
62360
  const trimmed = entry.trim();
62130
62361
  if (!trimmed)
62131
62362
  continue;
62132
- if (path10.isAbsolute(trimmed)) {
62363
+ if (path11.isAbsolute(trimmed)) {
62133
62364
  throw new Error(`tarball contains absolute path: "${trimmed}"`);
62134
62365
  }
62135
- const normalized = path10.normalize(trimmed);
62136
- if (normalized.startsWith("..") || normalized.includes(`${path10.sep}..${path10.sep}`)) {
62366
+ const normalized = path11.normalize(trimmed);
62367
+ if (normalized.startsWith("..") || normalized.includes(`${path11.sep}..${path11.sep}`)) {
62137
62368
  throw new Error(`tarball contains path traversal: "${trimmed}"`);
62138
62369
  }
62139
62370
  }
@@ -62181,7 +62412,7 @@ function detectStripComponents(tarballPath) {
62181
62412
  return commonPrefix ? 1 : 0;
62182
62413
  }
62183
62414
  function installDeps(clipDir) {
62184
- const pkgJsonPath = path10.join(clipDir, "package.json");
62415
+ const pkgJsonPath = path11.join(clipDir, "package.json");
62185
62416
  if (!fs5.existsSync(pkgJsonPath))
62186
62417
  return;
62187
62418
  let hasDeps = false;
@@ -62200,7 +62431,7 @@ function installDeps(clipDir) {
62200
62431
  if (bunPath) {
62201
62432
  const bunEnv = {
62202
62433
  ...process.env,
62203
- PATH: `${path10.dirname(bunPath)}${path10.delimiter}${process.env.PATH ?? ""}`
62434
+ PATH: `${path11.dirname(bunPath)}${path11.delimiter}${process.env.PATH ?? ""}`
62204
62435
  };
62205
62436
  for (const args of [["install", "--frozen-lockfile"], ["install"]]) {
62206
62437
  try {
@@ -62236,19 +62467,19 @@ async function installClip(opts) {
62236
62467
  const registryUrl = (opts.registryUrl ?? DEFAULT_REGISTRY_URL).replace(/\/+$/, "");
62237
62468
  const parsed = parseSource(opts.source);
62238
62469
  const alias = opts.alias ?? deriveAlias(parsed);
62239
- const destDir = path10.join(opts.clipsDir, alias);
62470
+ const destDir = path11.join(opts.clipsDir, alias);
62240
62471
  const versionMeta = await resolveVersionMeta(registryUrl, parsed);
62241
- const tmpDir = path10.join(opts.clipsDir, `.tmp-${alias}-${Date.now()}`);
62472
+ const tmpDir = path11.join(opts.clipsDir, `.tmp-${alias}-${Date.now()}`);
62242
62473
  fs5.mkdirSync(tmpDir, { recursive: true });
62243
- const tarballPath = path10.join(tmpDir, `${alias}-${versionMeta.version}.tgz`);
62244
- const stageDir = path10.join(tmpDir, "stage");
62474
+ const tarballPath = path11.join(tmpDir, `${alias}-${versionMeta.version}.tgz`);
62475
+ const stageDir = path11.join(tmpDir, "stage");
62245
62476
  try {
62246
62477
  await httpDownload(versionMeta.tarball, tarballPath);
62247
62478
  verifyChecksum(tarballPath, versionMeta.checksumAlgo, versionMeta.checksumHex);
62248
62479
  validateTarEntries(tarballPath);
62249
62480
  extractTarball(tarballPath, stageDir);
62250
62481
  installDeps(stageDir);
62251
- const backupDir = path10.join(opts.clipsDir, `.backup-${alias}-${Date.now()}`);
62482
+ const backupDir = path11.join(opts.clipsDir, `.backup-${alias}-${Date.now()}`);
62252
62483
  let backedUp = false;
62253
62484
  try {
62254
62485
  if (fs5.existsSync(destDir)) {
@@ -62289,9 +62520,9 @@ var init_clip_installer = __esm({
62289
62520
 
62290
62521
  // ts/daemon/dist/clip-runtime/manifest.js
62291
62522
  import * as fs6 from "node:fs";
62292
- import * as path11 from "node:path";
62523
+ import * as path12 from "node:path";
62293
62524
  function loadClipJson(dir) {
62294
- const filePath = path11.join(dir, "clip.json");
62525
+ const filePath = path12.join(dir, "clip.json");
62295
62526
  try {
62296
62527
  const content = fs6.readFileSync(filePath, "utf-8");
62297
62528
  return JSON.parse(content);
@@ -62300,7 +62531,7 @@ function loadClipJson(dir) {
62300
62531
  }
62301
62532
  }
62302
62533
  function loadPackageJson(dir) {
62303
- const filePath = path11.join(dir, "package.json");
62534
+ const filePath = path12.join(dir, "package.json");
62304
62535
  try {
62305
62536
  const content = fs6.readFileSync(filePath, "utf-8");
62306
62537
  return JSON.parse(content);
@@ -62415,19 +62646,19 @@ function manifestFromIpc(ipcManifest) {
62415
62646
  function resolveEntrypoint(clip) {
62416
62647
  const clipJson = loadClipJson(clip.path);
62417
62648
  if (clipJson?.main)
62418
- return path11.join(clip.path, clipJson.main);
62649
+ return path12.join(clip.path, clipJson.main);
62419
62650
  const pkgJson = loadPackageJson(clip.path);
62420
62651
  if (pkgJson?.main)
62421
- return path11.join(clip.path, pkgJson.main);
62652
+ return path12.join(clip.path, pkgJson.main);
62422
62653
  if (pkgJson?.bin) {
62423
62654
  const binPath = typeof pkgJson.bin === "string" ? pkgJson.bin : Object.values(pkgJson.bin)[0];
62424
62655
  if (binPath)
62425
- return path11.join(clip.path, binPath);
62656
+ return path12.join(clip.path, binPath);
62426
62657
  }
62427
- const defaultEntry = path11.join(clip.path, "index.ts");
62658
+ const defaultEntry = path12.join(clip.path, "index.ts");
62428
62659
  if (fs6.existsSync(defaultEntry))
62429
62660
  return defaultEntry;
62430
- return path11.join(clip.path, "index.js");
62661
+ return path12.join(clip.path, "index.js");
62431
62662
  }
62432
62663
  function finalizeManifest(manifest) {
62433
62664
  const m = { ...manifest };
@@ -62457,8 +62688,8 @@ var init_manifest = __esm({
62457
62688
  // ts/daemon/dist/runtimes.js
62458
62689
  import * as fs7 from "node:fs";
62459
62690
  import * as os4 from "node:os";
62460
- import * as path12 from "node:path";
62461
- import { fileURLToPath } from "node:url";
62691
+ import * as path13 from "node:path";
62692
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
62462
62693
  function buildStandardEnv(baseEnv, agentId, orgId, apiKey, dirs, pc) {
62463
62694
  const env = { ...baseEnv };
62464
62695
  clearAllProviderCreds(env);
@@ -62472,7 +62703,7 @@ function buildStandardEnv(baseEnv, agentId, orgId, apiKey, dirs, pc) {
62472
62703
  env.PRLL_PROVIDER_CONFIG = JSON.stringify(pc);
62473
62704
  if (dirs.homeDir)
62474
62705
  env.HOME = dirs.homeDir;
62475
- delete env.PRLL_DAEMON_MODE;
62706
+ env.PRLL_DAEMON_MODE = "1";
62476
62707
  return env;
62477
62708
  }
62478
62709
  function bundledSiblingBin(overlayName, entryPath) {
@@ -62480,17 +62711,17 @@ function bundledSiblingBin(overlayName, entryPath) {
62480
62711
  const entry = entryPath ?? process.argv[1];
62481
62712
  if (entry) {
62482
62713
  try {
62483
- candidateDirs.push(path12.dirname(fs7.realpathSync(entry)));
62714
+ candidateDirs.push(path13.dirname(fs7.realpathSync(entry)));
62484
62715
  } catch {
62485
- candidateDirs.push(path12.dirname(path12.resolve(entry)));
62716
+ candidateDirs.push(path13.dirname(path13.resolve(entry)));
62486
62717
  }
62487
62718
  }
62488
62719
  try {
62489
- candidateDirs.push(path12.dirname(fileURLToPath(import.meta.url)));
62720
+ candidateDirs.push(path13.dirname(fileURLToPath2(import.meta.url)));
62490
62721
  } catch {
62491
62722
  }
62492
62723
  for (const dir of candidateDirs) {
62493
- const bin = path12.join(dir, overlayName);
62724
+ const bin = path13.join(dir, overlayName);
62494
62725
  try {
62495
62726
  if (fs7.existsSync(bin))
62496
62727
  return bin;
@@ -62506,7 +62737,7 @@ function getRuntimeAdapter(runtimeType, opts) {
62506
62737
  return base;
62507
62738
  try {
62508
62739
  const bundleDir = resolveBundleDir(opts?.env);
62509
- const overlayBin = path12.join(bundleDir, "current", overlayName);
62740
+ const overlayBin = path13.join(bundleDir, "current", overlayName);
62510
62741
  if (fs7.existsSync(overlayBin)) {
62511
62742
  return { ...base, bin: process.execPath, args: [overlayBin] };
62512
62743
  }
@@ -62544,9 +62775,9 @@ var init_runtimes = __esm({
62544
62775
  buildEnv(baseEnv, agentId, orgId, apiKey, dirs, pc) {
62545
62776
  const env = buildStandardEnv(baseEnv, agentId, orgId, apiKey, dirs, pc);
62546
62777
  if (baseEnv.KUBERNETES_SERVICE_HOST || llmSource(pc) !== "runtime_auth") {
62547
- env.PRLL_CODEX_HOME = path12.join(dirs.stateDir, ".codex");
62778
+ env.PRLL_CODEX_HOME = path13.join(dirs.stateDir, ".codex");
62548
62779
  } else if (dirs.homeDir && !env.CODEX_HOME) {
62549
- env.CODEX_HOME = path12.join(baseEnv.HOME || os4.homedir(), ".codex");
62780
+ env.CODEX_HOME = path13.join(baseEnv.HOME || os4.homedir(), ".codex");
62550
62781
  }
62551
62782
  return env;
62552
62783
  }
@@ -63392,7 +63623,7 @@ var init_hub_client = __esm({
63392
63623
 
63393
63624
  // ts/daemon/dist/clip-runtime/process-manager.js
63394
63625
  import * as fs8 from "node:fs";
63395
- import * as path13 from "node:path";
63626
+ import * as path14 from "node:path";
63396
63627
  function browserCapabilityConfig() {
63397
63628
  return {
63398
63629
  name: BROWSER_CAPABILITY_NAME,
@@ -63651,7 +63882,7 @@ var init_process_manager = __esm({
63651
63882
  * Reads clip-config.json if present, or scans subdirectories for clip.json files.
63652
63883
  */
63653
63884
  async loadInstalledClips() {
63654
- const configFile = path13.join(path13.dirname(this.clipsDir), "clip-config.json");
63885
+ const configFile = path14.join(path14.dirname(this.clipsDir), "clip-config.json");
63655
63886
  if (fs8.existsSync(configFile)) {
63656
63887
  try {
63657
63888
  const content = fs8.readFileSync(configFile, "utf-8");
@@ -63670,9 +63901,9 @@ var init_process_manager = __esm({
63670
63901
  for (const entry of entries) {
63671
63902
  if (!entry.isDirectory())
63672
63903
  continue;
63673
- const clipDir = path13.join(this.clipsDir, entry.name);
63674
- const clipJsonPath = path13.join(clipDir, "clip.json");
63675
- const pkgJsonPath = path13.join(clipDir, "package.json");
63904
+ const clipDir = path14.join(this.clipsDir, entry.name);
63905
+ const clipJsonPath = path14.join(clipDir, "clip.json");
63906
+ const pkgJsonPath = path14.join(clipDir, "package.json");
63676
63907
  if (fs8.existsSync(clipJsonPath)) {
63677
63908
  try {
63678
63909
  const clipJson = JSON.parse(fs8.readFileSync(clipJsonPath, "utf-8"));
@@ -63742,7 +63973,7 @@ var init_process_manager = __esm({
63742
63973
  // shells out to `bun` by name resolves it — the daemon's launchd PATH
63743
63974
  // does not include Frameworks/. Symmetric with installDeps(); relies on
63744
63975
  // the embedded binary being named `bun` (Frameworks/bun).
63745
- PATH: `${path13.dirname(bunPath)}${path13.delimiter}${process.env.PATH ?? ""}`
63976
+ PATH: `${path14.dirname(bunPath)}${path14.delimiter}${process.env.PATH ?? ""}`
63746
63977
  });
63747
63978
  this.setStatus(config.name, "running", "starting");
63748
63979
  try {
@@ -63771,7 +64002,7 @@ var init_process_manager = __esm({
63771
64002
  return proc;
63772
64003
  }
63773
64004
  ensureClipDataDir(config, context2 = {}) {
63774
- const dir = path13.join(this.dataDir, config.name, context2.clipId ?? "default");
64005
+ const dir = path14.join(this.dataDir, config.name, context2.clipId ?? "default");
63775
64006
  fs8.mkdirSync(dir, { recursive: true });
63776
64007
  return dir;
63777
64008
  }
@@ -65278,10 +65509,10 @@ var init_browser_viewer_streamer = __esm({
65278
65509
  // ts/daemon/dist/clip-runtime/browser-profile-manager.js
65279
65510
  import { spawn as spawn4 } from "node:child_process";
65280
65511
  import { randomBytes } from "node:crypto";
65281
- import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync8 } from "node:fs";
65512
+ import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync9 } from "node:fs";
65282
65513
  import { createRequire } from "node:module";
65283
- import * as path14 from "node:path";
65284
- import { fileURLToPath as fileURLToPath2 } from "node:url";
65514
+ import * as path15 from "node:path";
65515
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
65285
65516
  function normalizeStartUrl(value) {
65286
65517
  const trimmed = value?.trim();
65287
65518
  if (!trimmed)
@@ -65316,14 +65547,14 @@ function isRecoverableBrowserDaemonError(err) {
65316
65547
  return lower.includes("chrome not connected") || lower.includes("cdp at 127.0.0.1") || lower.includes("no page target found") || lower.includes("bb-browser /command returned 503") && (lower.includes("chrome") || lower.includes("cdp"));
65317
65548
  }
65318
65549
  function resolveBbBrowserDaemonPath() {
65319
- const sibling = path14.join(path14.dirname(fileURLToPath2(import.meta.url)), "bb-browser-daemon.js");
65550
+ const sibling = path15.join(path15.dirname(fileURLToPath3(import.meta.url)), "bb-browser-daemon.js");
65320
65551
  if (existsSync8(sibling))
65321
65552
  return sibling;
65322
65553
  const require2 = createRequire(import.meta.url);
65323
65554
  const pkgPath = require2.resolve("@pinixai/bb-browser-pro/package.json");
65324
- const pkg = JSON.parse(readFileSync8(pkgPath, "utf8"));
65555
+ const pkg = JSON.parse(readFileSync9(pkgPath, "utf8"));
65325
65556
  const rel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.["bb-browser-daemon"] ?? "./dist/daemon.js";
65326
- const full = path14.resolve(path14.dirname(pkgPath), rel);
65557
+ const full = path15.resolve(path15.dirname(pkgPath), rel);
65327
65558
  if (!existsSync8(full)) {
65328
65559
  throw new Error(`bb-browser-daemon entrypoint not found at ${full}`);
65329
65560
  }
@@ -65998,8 +66229,8 @@ var init_browser_profile_manager = __esm({
65998
66229
  });
65999
66230
 
66000
66231
  // ts/daemon/dist/clip-runtime/browser-profile-pool.js
66001
- import { existsSync as existsSync9, mkdirSync as mkdirSync7, readdirSync as readdirSync3, readFileSync as readFileSync9, renameSync as renameSync4, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "node:fs";
66002
- import * as path15 from "node:path";
66232
+ import { existsSync as existsSync9, mkdirSync as mkdirSync7, readdirSync as readdirSync3, readFileSync as readFileSync10, renameSync as renameSync4, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "node:fs";
66233
+ import * as path16 from "node:path";
66003
66234
  function isSafeProfileId(id) {
66004
66235
  return /^brp_[A-Za-z0-9_-]+$/.test(id);
66005
66236
  }
@@ -66370,11 +66601,11 @@ var init_browser_profile_pool = __esm({
66370
66601
  }
66371
66602
  }
66372
66603
  profileHome(profileId) {
66373
- return path15.join(this.opts.baseHomeDir, sanitizeProfileId(profileId));
66604
+ return path16.join(this.opts.baseHomeDir, sanitizeProfileId(profileId));
66374
66605
  }
66375
66606
  /** Legacy shared-layout cookie file for a profile (pre per-profile homes). */
66376
66607
  legacyAccountFile(profileId) {
66377
- return path15.join(this.opts.baseHomeDir, "accounts", `${sanitizeProfileId(profileId)}.json`);
66608
+ return path16.join(this.opts.baseHomeDir, "accounts", `${sanitizeProfileId(profileId)}.json`);
66378
66609
  }
66379
66610
  /**
66380
66611
  * Remove every on-disk trace of a profile: its per-profile home AND any
@@ -66402,12 +66633,12 @@ var init_browser_profile_pool = __esm({
66402
66633
  // reset_generation to this value: a newer server value means a reset was missed
66403
66634
  // while offline → wipe. Missing/corrupt reads as 0 (so any server reset wins).
66404
66635
  metaFile(profileId) {
66405
- return path15.join(this.profileHome(profileId), ".parall-profile-meta.json");
66636
+ return path16.join(this.profileHome(profileId), ".parall-profile-meta.json");
66406
66637
  }
66407
66638
  /** The reset_generation this daemon has applied for the profile (0 if unknown). */
66408
66639
  appliedResetGeneration(profileId) {
66409
66640
  try {
66410
- const parsed = JSON.parse(readFileSync9(this.metaFile(profileId), "utf8"));
66641
+ const parsed = JSON.parse(readFileSync10(this.metaFile(profileId), "utf8"));
66411
66642
  const gen = parsed.reset_generation;
66412
66643
  return typeof gen === "number" && Number.isFinite(gen) ? gen : 0;
66413
66644
  } catch {
@@ -66420,7 +66651,7 @@ var init_browser_profile_pool = __esm({
66420
66651
  writeResetGeneration(profileId, generation) {
66421
66652
  const home = this.profileHome(profileId);
66422
66653
  mkdirSync7(home, { recursive: true });
66423
- const tmp = path15.join(home, `.parall-profile-meta.json.tmp-${process.pid}`);
66654
+ const tmp = path16.join(home, `.parall-profile-meta.json.tmp-${process.pid}`);
66424
66655
  writeFileSync4(tmp, JSON.stringify({ reset_generation: generation }));
66425
66656
  renameSync4(tmp, this.metaFile(profileId));
66426
66657
  }
@@ -66446,7 +66677,7 @@ var init_browser_profile_pool = __esm({
66446
66677
  } catch {
66447
66678
  }
66448
66679
  try {
66449
- const accountsDir = path15.join(this.opts.baseHomeDir, "accounts");
66680
+ const accountsDir = path16.join(this.opts.baseHomeDir, "accounts");
66450
66681
  for (const e of readdirSync3(accountsDir, { withFileTypes: true })) {
66451
66682
  if (!e.isFile() || !e.name.endsWith(".json"))
66452
66683
  continue;
@@ -66472,8 +66703,8 @@ var init_browser_profile_pool = __esm({
66472
66703
  const legacy = this.legacyAccountFile(profileId);
66473
66704
  if (!existsSync9(legacy))
66474
66705
  return;
66475
- const destDir = path15.join(this.profileHome(profileId), "accounts");
66476
- const dest = path15.join(destDir, path15.basename(legacy));
66706
+ const destDir = path16.join(this.profileHome(profileId), "accounts");
66707
+ const dest = path16.join(destDir, path16.basename(legacy));
66477
66708
  if (existsSync9(dest))
66478
66709
  return;
66479
66710
  try {
@@ -66506,10 +66737,10 @@ var init_clip_runtime = __esm({
66506
66737
 
66507
66738
  // ts/daemon/dist/filesystem.js
66508
66739
  import * as fs9 from "fs";
66509
- import * as path16 from "path";
66740
+ import * as path17 from "path";
66510
66741
  import * as os5 from "os";
66511
66742
  function browseDenyReason(value) {
66512
- const normalized = path16.resolve(value).split(path16.sep).join("/");
66743
+ const normalized = path17.resolve(value).split(path17.sep).join("/");
66513
66744
  if (normalized === "/")
66514
66745
  return "";
66515
66746
  for (const prefix of SYSTEM_DIR_PREFIXES) {
@@ -66539,8 +66770,8 @@ function syntheticRoots() {
66539
66770
  return roots;
66540
66771
  }
66541
66772
  async function listDirectory(dirPath) {
66542
- const resolved = path16.resolve(dirPath);
66543
- const normalized = resolved.split(path16.sep).join("/");
66773
+ const resolved = path17.resolve(dirPath);
66774
+ const normalized = resolved.split(path17.sep).join("/");
66544
66775
  if (normalized === "/") {
66545
66776
  return { entries: syntheticRoots() };
66546
66777
  }
@@ -66557,7 +66788,7 @@ async function listDirectory(dirPath) {
66557
66788
  return { entries: [], error: "Directory not found" };
66558
66789
  return { entries: [], error: "Permission denied" };
66559
66790
  }
66560
- const realDeny = browseDenyReason(realPath.split(path16.sep).join("/"));
66791
+ const realDeny = browseDenyReason(realPath.split(path17.sep).join("/"));
66561
66792
  if (realDeny) {
66562
66793
  return { entries: [], error: `Access denied: ${realDeny}` };
66563
66794
  }
@@ -66627,9 +66858,9 @@ var init_filesystem = __esm({
66627
66858
  // ts/daemon/dist/local-control.js
66628
66859
  import { chmodSync as chmodSync2, existsSync as existsSync10, mkdirSync as mkdirSync8, rmSync as rmSync4, statSync } from "node:fs";
66629
66860
  import * as net2 from "node:net";
66630
- import * as path17 from "node:path";
66861
+ import * as path18 from "node:path";
66631
66862
  function localControlSocketPath(env = process.env) {
66632
- return path17.join(daemonConfigDir(env), "run", "control.sock");
66863
+ return path18.join(daemonConfigDir(env), "run", "control.sock");
66633
66864
  }
66634
66865
  function isSocketLive(sockPath) {
66635
66866
  return new Promise((resolve9) => {
@@ -66672,7 +66903,7 @@ var init_local_control = __esm({
66672
66903
  if (this.server)
66673
66904
  throw new Error("local control server already started");
66674
66905
  const sockPath = this.opts.socketPath;
66675
- const dir = path17.dirname(sockPath);
66906
+ const dir = path18.dirname(sockPath);
66676
66907
  mkdirSync8(dir, { recursive: true, mode: 448 });
66677
66908
  try {
66678
66909
  chmodSync2(dir, 448);
@@ -66897,7 +67128,7 @@ var init_local_profile_control = __esm({
66897
67128
 
66898
67129
  // ts/daemon/dist/home-isolation.js
66899
67130
  import * as fs10 from "node:fs";
66900
- import * as path18 from "node:path";
67131
+ import * as path19 from "node:path";
66901
67132
  function ensureIsolatedHome(spec, agentId, log2, platform2 = process.platform) {
66902
67133
  fs10.mkdirSync(spec.homeDir, { recursive: true });
66903
67134
  const failures = [];
@@ -66909,18 +67140,18 @@ function ensureIsolatedHome(spec, agentId, log2, platform2 = process.platform) {
66909
67140
  }
66910
67141
  };
66911
67142
  attempt(".claude link", () => {
66912
- fs10.mkdirSync(path18.join(spec.claudeStateRoot, ".claude"), { recursive: true });
66913
- ensureLink(path18.join(spec.homeDir, ".claude"), path18.join(spec.claudeStateRoot, ".claude"), agentId, log2);
67143
+ fs10.mkdirSync(path19.join(spec.claudeStateRoot, ".claude"), { recursive: true });
67144
+ ensureLink(path19.join(spec.homeDir, ".claude"), path19.join(spec.claudeStateRoot, ".claude"), agentId, log2);
66914
67145
  });
66915
- attempt(".claude.json link", () => ensureLink(path18.join(spec.homeDir, ".claude.json"), path18.join(spec.claudeStateRoot, ".claude.json"), agentId, log2));
67146
+ attempt(".claude.json link", () => ensureLink(path19.join(spec.homeDir, ".claude.json"), path19.join(spec.claudeStateRoot, ".claude.json"), agentId, log2));
66916
67147
  if (platform2 === "darwin") {
66917
67148
  attempt("Library/Keychains link", () => {
66918
- fs10.mkdirSync(path18.join(spec.homeDir, "Library"), { recursive: true });
66919
- ensureLink(path18.join(spec.homeDir, "Library", "Keychains"), path18.join(spec.systemHome, "Library", "Keychains"), agentId, log2);
67149
+ fs10.mkdirSync(path19.join(spec.homeDir, "Library"), { recursive: true });
67150
+ ensureLink(path19.join(spec.homeDir, "Library", "Keychains"), path19.join(spec.systemHome, "Library", "Keychains"), agentId, log2);
66920
67151
  });
66921
67152
  }
66922
67153
  attempt(".gitconfig", () => {
66923
- const gitconfig = path18.join(spec.homeDir, ".gitconfig");
67154
+ const gitconfig = path19.join(spec.homeDir, ".gitconfig");
66924
67155
  if (!fs10.existsSync(gitconfig)) {
66925
67156
  fs10.writeFileSync(gitconfig, `[user]
66926
67157
  name = ${gitConfigValue(spec.gitUserName)}
@@ -66946,7 +67177,7 @@ function ensureLink(linkPath, target, agentId, log2) {
66946
67177
  if (existing) {
66947
67178
  if (existing.isSymbolicLink()) {
66948
67179
  const current = fs10.readlinkSync(linkPath);
66949
- if (path18.resolve(path18.dirname(linkPath), current) === path18.resolve(target))
67180
+ if (path19.resolve(path19.dirname(linkPath), current) === path19.resolve(target))
66950
67181
  return;
66951
67182
  fs10.unlinkSync(linkPath);
66952
67183
  log2.info(`agent ${agentId}: relinking ${linkPath} \u2192 ${target}`);
@@ -66959,16 +67190,16 @@ function ensureLink(linkPath, target, agentId, log2) {
66959
67190
  fs10.symlinkSync(target, linkPath);
66960
67191
  }
66961
67192
  function ensureSharedCredentialLink(rootClaudeHome, agentClaudeHome, agentId, log2) {
66962
- const sharedCredentials = path18.resolve(sharedClaudeCredentialsFileFor(rootClaudeHome));
67193
+ const sharedCredentials = path19.resolve(sharedClaudeCredentialsFileFor(rootClaudeHome));
66963
67194
  const agentCredentials = agentClaudeCredentialsFileFor(agentClaudeHome);
66964
- const agentCredentialsDir = path18.dirname(agentCredentials);
66965
- fs10.mkdirSync(path18.dirname(sharedCredentials), { recursive: true });
67195
+ const agentCredentialsDir = path19.dirname(agentCredentials);
67196
+ fs10.mkdirSync(path19.dirname(sharedCredentials), { recursive: true });
66966
67197
  fs10.mkdirSync(agentCredentialsDir, { recursive: true });
66967
67198
  try {
66968
67199
  const existing = fs10.lstatSync(agentCredentials);
66969
67200
  if (existing.isSymbolicLink()) {
66970
67201
  const currentTarget = fs10.readlinkSync(agentCredentials);
66971
- if (path18.resolve(agentCredentialsDir, currentTarget) === sharedCredentials) {
67202
+ if (path19.resolve(agentCredentialsDir, currentTarget) === sharedCredentials) {
66972
67203
  return;
66973
67204
  }
66974
67205
  fs10.unlinkSync(agentCredentials);
@@ -66996,7 +67227,7 @@ var init_home_isolation = __esm({
66996
67227
  import { execFileSync as execFileSync4 } from "node:child_process";
66997
67228
  import * as fs11 from "node:fs";
66998
67229
  import * as os6 from "node:os";
66999
- import * as path19 from "node:path";
67230
+ import * as path20 from "node:path";
67000
67231
  function runtimeBinaryEnvVar(runtimeType) {
67001
67232
  return RUNTIME_BINARIES[runtimeType]?.envVar;
67002
67233
  }
@@ -67073,16 +67304,16 @@ function resolveRuntimeCommand(command, env, inheritedPath, primaryPath, fallbac
67073
67304
  function resolveDirectPath(command) {
67074
67305
  if (!command.includes("/") && !command.includes("\\"))
67075
67306
  return null;
67076
- const abs = path19.isAbsolute(command) ? command : path19.resolve(process.cwd(), command);
67307
+ const abs = path20.isAbsolute(command) ? command : path20.resolve(process.cwd(), command);
67077
67308
  return isExecutable(abs) ? abs : null;
67078
67309
  }
67079
67310
  function resolveFromPath(command, pathValue, env, platform2) {
67080
67311
  if (!pathValue || command.includes("/") || command.includes("\\"))
67081
67312
  return null;
67082
- const dirs = pathValue.split(path19.delimiter).filter(Boolean);
67313
+ const dirs = pathValue.split(path20.delimiter).filter(Boolean);
67083
67314
  for (const dir of dirs) {
67084
67315
  for (const file of commandCandidates(command, env, platform2)) {
67085
- const candidate = path19.join(dir, file);
67316
+ const candidate = path20.join(dir, file);
67086
67317
  if (isExecutable(candidate))
67087
67318
  return { binaryPath: candidate, pathValue };
67088
67319
  }
@@ -67123,7 +67354,7 @@ __PRLL_PATH__%s
67123
67354
  if (line.startsWith("__PRLL_PATH__"))
67124
67355
  pathValue = line.slice("__PRLL_PATH__".length);
67125
67356
  }
67126
- if (path19.isAbsolute(binaryPath) && isExecutable(binaryPath)) {
67357
+ if (path20.isAbsolute(binaryPath) && isExecutable(binaryPath)) {
67127
67358
  return { binaryPath, pathValue: pathValue || void 0 };
67128
67359
  }
67129
67360
  } catch {
@@ -67143,18 +67374,18 @@ function cachedCandidatePathPlan(env, platform2) {
67143
67374
  function candidatePathPlan(env, platform2 = process.platform) {
67144
67375
  const home = env.HOME || os6.homedir();
67145
67376
  if (platform2 === "win32") {
67146
- const appData = env.APPDATA || path19.join(home, "AppData", "Roaming");
67147
- const localAppData = env.LOCALAPPDATA || path19.join(home, "AppData", "Local");
67377
+ const appData = env.APPDATA || path20.join(home, "AppData", "Roaming");
67378
+ const localAppData = env.LOCALAPPDATA || path20.join(home, "AppData", "Local");
67148
67379
  const winPrimaryDirs = [
67149
67380
  ...splitPath(env.PRLL_DAEMON_RUNTIME_PATH),
67150
67381
  ...splitPath(env.PRLL_DAEMON_EXTRA_PATH),
67151
- path19.dirname(process.execPath),
67382
+ path20.dirname(process.execPath),
67152
67383
  env.PNPM_HOME,
67153
- path19.join(appData, "npm"),
67154
- path19.join(localAppData, "pnpm"),
67155
- path19.join(localAppData, "Volta", "bin"),
67156
- path19.join(home, ".volta", "bin"),
67157
- path19.join(home, ".bun", "bin")
67384
+ path20.join(appData, "npm"),
67385
+ path20.join(localAppData, "pnpm"),
67386
+ path20.join(localAppData, "Volta", "bin"),
67387
+ path20.join(home, ".volta", "bin"),
67388
+ path20.join(home, ".bun", "bin")
67158
67389
  ];
67159
67390
  return {
67160
67391
  primaryDirs: unique(winPrimaryDirs).filter((dir) => !!dir && isDirectory(dir)),
@@ -67164,21 +67395,21 @@ function candidatePathPlan(env, platform2 = process.platform) {
67164
67395
  const primaryDirs = [
67165
67396
  ...splitPath(env.PRLL_DAEMON_RUNTIME_PATH),
67166
67397
  ...splitPath(env.PRLL_DAEMON_EXTRA_PATH),
67167
- path19.dirname(process.execPath),
67168
- path19.join(path19.dirname(process.execPath), "bin"),
67169
- path19.resolve(path19.dirname(process.execPath), "..", "Resources", "bin"),
67170
- path19.join(home, ".local", "bin"),
67171
- path19.join(home, "bin"),
67172
- path19.join(home, ".npm-global", "bin"),
67173
- path19.join(home, "Library", "pnpm"),
67174
- path19.join(home, ".local", "share", "pnpm"),
67175
- path19.join(home, ".volta", "bin"),
67176
- path19.join(home, ".bun", "bin"),
67177
- path19.join(home, ".asdf", "shims"),
67178
- path19.join(home, ".local", "share", "mise", "shims"),
67179
- path19.join(home, ".mise", "shims"),
67180
- path19.join(home, ".fnm", "aliases", "default", "bin"),
67181
- path19.join(home, "Library", "Application Support", "fnm", "aliases", "default", "bin"),
67398
+ path20.dirname(process.execPath),
67399
+ path20.join(path20.dirname(process.execPath), "bin"),
67400
+ path20.resolve(path20.dirname(process.execPath), "..", "Resources", "bin"),
67401
+ path20.join(home, ".local", "bin"),
67402
+ path20.join(home, "bin"),
67403
+ path20.join(home, ".npm-global", "bin"),
67404
+ path20.join(home, "Library", "pnpm"),
67405
+ path20.join(home, ".local", "share", "pnpm"),
67406
+ path20.join(home, ".volta", "bin"),
67407
+ path20.join(home, ".bun", "bin"),
67408
+ path20.join(home, ".asdf", "shims"),
67409
+ path20.join(home, ".local", "share", "mise", "shims"),
67410
+ path20.join(home, ".mise", "shims"),
67411
+ path20.join(home, ".fnm", "aliases", "default", "bin"),
67412
+ path20.join(home, "Library", "Application Support", "fnm", "aliases", "default", "bin"),
67182
67413
  "/opt/homebrew/bin",
67183
67414
  "/usr/local/bin",
67184
67415
  "/usr/bin",
@@ -67197,19 +67428,19 @@ function candidatePathPlan(env, platform2 = process.platform) {
67197
67428
  };
67198
67429
  }
67199
67430
  function nvmVersionBinDirs(home) {
67200
- const root = path19.join(home, ".nvm", "versions", "node");
67431
+ const root = path20.join(home, ".nvm", "versions", "node");
67201
67432
  let versions;
67202
67433
  try {
67203
67434
  versions = fs11.readdirSync(root);
67204
67435
  } catch {
67205
67436
  return [];
67206
67437
  }
67207
- return sortVersionNamesDesc(versions).map((version) => path19.join(root, version, "bin"));
67438
+ return sortVersionNamesDesc(versions).map((version) => path20.join(root, version, "bin"));
67208
67439
  }
67209
67440
  function fnmVersionBinDirs(home) {
67210
67441
  const roots = [
67211
- path19.join(home, ".fnm", "node-versions"),
67212
- path19.join(home, "Library", "Application Support", "fnm", "node-versions")
67442
+ path20.join(home, ".fnm", "node-versions"),
67443
+ path20.join(home, "Library", "Application Support", "fnm", "node-versions")
67213
67444
  ];
67214
67445
  const dirs = [];
67215
67446
  for (const root of roots) {
@@ -67219,7 +67450,7 @@ function fnmVersionBinDirs(home) {
67219
67450
  } catch {
67220
67451
  continue;
67221
67452
  }
67222
- dirs.push(...sortVersionNamesDesc(versions).map((version) => path19.join(root, version, "installation", "bin")));
67453
+ dirs.push(...sortVersionNamesDesc(versions).map((version) => path20.join(root, version, "installation", "bin")));
67223
67454
  }
67224
67455
  return dirs;
67225
67456
  }
@@ -67241,13 +67472,13 @@ function parseVersionName(value) {
67241
67472
  return value.replace(/^v/i, "").split(".").map((part) => Number.parseInt(part, 10)).filter((part) => Number.isFinite(part));
67242
67473
  }
67243
67474
  function splitPath(value) {
67244
- return value?.split(path19.delimiter).filter(Boolean) ?? [];
67475
+ return value?.split(path20.delimiter).filter(Boolean) ?? [];
67245
67476
  }
67246
67477
  function mergePath(prependDirs, existing) {
67247
- return unique([...prependDirs, ...splitPath(existing)]).join(path19.delimiter);
67478
+ return unique([...prependDirs, ...splitPath(existing)]).join(path20.delimiter);
67248
67479
  }
67249
67480
  function anchorResolvedPath(pathValue, resolution) {
67250
- return mergePath([path19.dirname(resolution.binaryPath), ...splitPath(resolution.pathValue)], pathValue);
67481
+ return mergePath([path20.dirname(resolution.binaryPath), ...splitPath(resolution.pathValue)], pathValue);
67251
67482
  }
67252
67483
  function commandCandidates(command, env, platform2 = process.platform) {
67253
67484
  if (platform2 !== "win32")
@@ -67402,7 +67633,7 @@ var init_runtime_detector = __esm({
67402
67633
  import { spawn as spawn5 } from "node:child_process";
67403
67634
  import { createHash as createHash4 } from "node:crypto";
67404
67635
  import * as fs12 from "node:fs";
67405
- import * as path20 from "node:path";
67636
+ import * as path21 from "node:path";
67406
67637
  async function prepareWorkspace(opts) {
67407
67638
  const prior = opts.attached.workspace_state;
67408
67639
  const plan = buildWorkspacePlan(opts.attached.daemon_config, opts.defaultWorkspaceDir, prior?.config_hash);
@@ -67547,8 +67778,8 @@ async function ensureWorkspace(plan, log2) {
67547
67778
  assertSafeCustomWorkspacePath(plan);
67548
67779
  }
67549
67780
  if (!fs12.existsSync(plan.workspaceDir)) {
67550
- fs12.mkdirSync(path20.dirname(plan.workspaceDir), { recursive: true });
67551
- assertWritableWorkspaceDir(path20.dirname(plan.workspaceDir));
67781
+ fs12.mkdirSync(path21.dirname(plan.workspaceDir), { recursive: true });
67782
+ assertWritableWorkspaceDir(path21.dirname(plan.workspaceDir));
67552
67783
  await runCommand("git", ["clone", remote, plan.workspaceDir], process.cwd());
67553
67784
  } else {
67554
67785
  const st = fs12.statSync(plan.workspaceDir);
@@ -67730,10 +67961,10 @@ ${tail}`)));
67730
67961
  });
67731
67962
  }
67732
67963
  function requireAbsolute(value, field) {
67733
- if (!value || !path20.isAbsolute(value)) {
67964
+ if (!value || !path21.isAbsolute(value)) {
67734
67965
  throw new Error(`${field} must be an absolute path`);
67735
67966
  }
67736
- return path20.resolve(value);
67967
+ return path21.resolve(value);
67737
67968
  }
67738
67969
  function assertSafeCustomWorkspacePath(plan, candidate = plan.workspaceDir) {
67739
67970
  if (!plan.customWorkspaceField)
@@ -67743,14 +67974,14 @@ function assertSafeCustomWorkspacePath(plan, candidate = plan.workspaceDir) {
67743
67974
  if (reason) {
67744
67975
  throw new Error(`${plan.customWorkspaceField} must point to a project folder, not ${reason}: ${normalized}`);
67745
67976
  }
67746
- const defaultWorkspace = path20.resolve(plan.defaultWorkspaceDir);
67977
+ const defaultWorkspace = path21.resolve(plan.defaultWorkspaceDir);
67747
67978
  if (isAncestorPath(normalized, defaultWorkspace) || normalized === defaultWorkspace) {
67748
67979
  throw new Error(`${plan.customWorkspaceField} must not point at daemon state directories: ${normalized}`);
67749
67980
  }
67750
67981
  }
67751
67982
  function assertWritableWorkspaceDir(dir) {
67752
67983
  fs12.accessSync(dir, fs12.constants.R_OK | fs12.constants.W_OK | fs12.constants.X_OK);
67753
- const probe = path20.join(dir, `.parall-workspace-check-${process.pid}-${Date.now()}`);
67984
+ const probe = path21.join(dir, `.parall-workspace-check-${process.pid}-${Date.now()}`);
67754
67985
  const fd = fs12.openSync(probe, "wx", 384);
67755
67986
  fs12.closeSync(fd);
67756
67987
  fs12.unlinkSync(probe);
@@ -67814,11 +68045,11 @@ function workspacePathDenyReason(value) {
67814
68045
  return "";
67815
68046
  }
67816
68047
  function isAncestorPath(parent, child) {
67817
- const relative2 = path20.relative(parent, child);
67818
- return relative2 !== "" && !relative2.startsWith("..") && !path20.isAbsolute(relative2);
68048
+ const relative2 = path21.relative(parent, child);
68049
+ return relative2 !== "" && !relative2.startsWith("..") && !path21.isAbsolute(relative2);
67819
68050
  }
67820
68051
  function toPolicyPath(value) {
67821
- return path20.resolve(value).split(path20.sep).join("/");
68052
+ return path21.resolve(value).split(path21.sep).join("/");
67822
68053
  }
67823
68054
  function isNodeError(err) {
67824
68055
  return err instanceof Error && "code" in err;
@@ -67837,7 +68068,7 @@ var init_workspace = __esm({
67837
68068
  import { spawn as spawn6 } from "node:child_process";
67838
68069
  import * as fs13 from "node:fs";
67839
68070
  import * as os7 from "node:os";
67840
- import * as path21 from "node:path";
68071
+ import * as path22 from "node:path";
67841
68072
  function sleepCancellable(ms, signal) {
67842
68073
  if (signal.aborted)
67843
68074
  return Promise.resolve(false);
@@ -67998,7 +68229,7 @@ var init_supervisor = __esm({
67998
68229
  this.migrateFlatLayout();
67999
68230
  if (process.env.PRLL_CLIP_RUNTIME_ENABLED === "true") {
68000
68231
  this.browserProfilePool = new BrowserProfilePool({
68001
- baseHomeDir: path21.join(this.config.rootStateDir, "bb-browser"),
68232
+ baseHomeDir: path22.join(this.config.rootStateDir, "bb-browser"),
68002
68233
  log: this.log,
68003
68234
  reportStatus: (profileId, status, errorMsg, generation) => {
68004
68235
  this.client.reportBrowserProfileStatus(profileId, status, errorMsg, generation).catch((err) => this.log.warn(`browser profile status report failed: ${String(err)}`));
@@ -68007,8 +68238,8 @@ var init_supervisor = __esm({
68007
68238
  proxyProbeUrl: this.resolveBrowserProxyProbeUrl()
68008
68239
  });
68009
68240
  this.clipManager = new ClipProcessManager({
68010
- clipsDir: path21.join(this.config.rootStateDir, "clips"),
68011
- dataDir: path21.join(this.config.rootStateDir, "clip-data"),
68241
+ clipsDir: path22.join(this.config.rootStateDir, "clips"),
68242
+ dataDir: path22.join(this.config.rootStateDir, "clip-data"),
68012
68243
  browserProfileManager: this.browserProfilePool,
68013
68244
  // Execution side: nested browser dependency invokes resolve their
68014
68245
  // binding and route through the hub (no local shortcut).
@@ -68360,12 +68591,12 @@ var init_supervisor = __esm({
68360
68591
  */
68361
68592
  migrateFlatLayout() {
68362
68593
  const root = this.config.rootStateDir;
68363
- const agentsDir = path21.join(root, "agents");
68364
- const flatWorkspace = path21.join(root, "workspace");
68594
+ const agentsDir = path22.join(root, "agents");
68595
+ const flatWorkspace = path22.join(root, "workspace");
68365
68596
  if (!fs13.existsSync(flatWorkspace) || fs13.existsSync(agentsDir))
68366
68597
  return;
68367
68598
  let ownerAgentId;
68368
- const sessionsDir = path21.join(root, "sessions");
68599
+ const sessionsDir = path22.join(root, "sessions");
68369
68600
  if (fs13.existsSync(sessionsDir)) {
68370
68601
  try {
68371
68602
  for (const file of fs13.readdirSync(sessionsDir)) {
@@ -68382,13 +68613,13 @@ var init_supervisor = __esm({
68382
68613
  }
68383
68614
  }
68384
68615
  const targetId = ownerAgentId ?? "_orphan";
68385
- const targetDir = path21.join(agentsDir, targetId);
68616
+ const targetDir = path22.join(agentsDir, targetId);
68386
68617
  try {
68387
68618
  fs13.mkdirSync(targetDir, { recursive: true });
68388
68619
  for (const sub of ["workspace", "sessions", "dispatch-context"]) {
68389
- const src = path21.join(root, sub);
68620
+ const src = path22.join(root, sub);
68390
68621
  if (fs13.existsSync(src)) {
68391
- fs13.renameSync(src, path21.join(targetDir, sub));
68622
+ fs13.renameSync(src, path22.join(targetDir, sub));
68392
68623
  }
68393
68624
  }
68394
68625
  this.log.info(`migrated legacy flat state \u2192 agents/${targetId}/`);
@@ -68681,7 +68912,7 @@ var init_supervisor = __esm({
68681
68912
  return this.runtimeDetectInFlight;
68682
68913
  }
68683
68914
  machineClipToConfig(clip) {
68684
- const clipPath = path21.join(this.config.rootStateDir, "clips", clip.alias);
68915
+ const clipPath = path22.join(this.config.rootStateDir, "clips", clip.alias);
68685
68916
  return {
68686
68917
  clipId: clip.clip_id,
68687
68918
  name: clip.alias,
@@ -68747,7 +68978,7 @@ var init_supervisor = __esm({
68747
68978
  if (!sourceRef) {
68748
68979
  throw new Error(`registry clip "${config.name}" is missing source_ref`);
68749
68980
  }
68750
- const expectedPath = path21.join(this.config.rootStateDir, "clips", config.name);
68981
+ const expectedPath = path22.join(this.config.rootStateDir, "clips", config.name);
68751
68982
  const localVersion = this.readInstalledClipVersion(expectedPath);
68752
68983
  if (localVersion && (!config.version || localVersion === config.version)) {
68753
68984
  return { ...config, path: expectedPath, source: expectedPath };
@@ -68765,7 +68996,7 @@ var init_supervisor = __esm({
68765
68996
  const result = await installClip({
68766
68997
  source,
68767
68998
  alias: config.name,
68768
- clipsDir: path21.join(this.config.rootStateDir, "clips"),
68999
+ clipsDir: path22.join(this.config.rootStateDir, "clips"),
68769
69000
  registryUrl: process.env.PRLL_PINIX_REGISTRY_URL?.trim() || void 0
68770
69001
  });
68771
69002
  this.log.info(`clip ensured: ${result.alias} v${result.version} at ${result.path}`);
@@ -68780,7 +69011,7 @@ var init_supervisor = __esm({
68780
69011
  readInstalledClipVersion(dir) {
68781
69012
  for (const file of ["clip.json", "package.json"]) {
68782
69013
  try {
68783
- const raw = fs13.readFileSync(path21.join(dir, file), "utf-8");
69014
+ const raw = fs13.readFileSync(path22.join(dir, file), "utf-8");
68784
69015
  const parsed = JSON.parse(raw);
68785
69016
  if (typeof parsed.version === "string" && parsed.version.trim()) {
68786
69017
  return parsed.version.trim();
@@ -69415,7 +69646,11 @@ async function runForever(config, client, log2, signal, updater, gate) {
69415
69646
  async function main(bootstrap2) {
69416
69647
  configureHttpKeepAlive();
69417
69648
  const config = resolveClaudeDaemonConfig(process.env);
69418
- const telemetry = await initAgentTelemetry("parall-daemon", "daemon");
69649
+ const telemetry = await initAgentTelemetry("parall-daemon", "daemon", {
69650
+ apiUrl: config.apiUrl,
69651
+ apiKey: config.apiKey,
69652
+ serviceVersion: resolveServiceVersion(import.meta.url)
69653
+ });
69419
69654
  log = createOtelLogger("daemon", "daemon");
69420
69655
  log.info(`boot: api=${config.apiUrl} pollMs=${config.pollIntervalMs} heartbeatMs=${config.heartbeatIntervalMs} agentBin=${config.agentBin}`);
69421
69656
  log.info(`keepalive: bootstrapBackoffMs=${config.bootstrapBackoffMs} supervisorRestartBackoffMs=${config.supervisorRestartBackoffMs}`);
@@ -69504,7 +69739,7 @@ var init_daemon_main = __esm({
69504
69739
  init_daemon_paths();
69505
69740
  init_daemon_update_mode();
69506
69741
  import * as fs14 from "node:fs";
69507
- import * as path22 from "node:path";
69742
+ import * as path23 from "node:path";
69508
69743
  var UPDATE_EXIT_CODE2 = 42;
69509
69744
  function formatError2(reason) {
69510
69745
  if (reason instanceof Error) {
@@ -69529,7 +69764,7 @@ function clearRunningMarker(markerPath) {
69529
69764
  }
69530
69765
  function prepareDaemonBootstrap(env = process.env, args = process.argv.slice(2)) {
69531
69766
  const bundleDir = resolveBundleDir(env);
69532
- const runningMarker = path22.join(bundleDir, "daemon-running");
69767
+ const runningMarker = path23.join(bundleDir, "daemon-running");
69533
69768
  const lifecycleMarkerEnabled = args.length === 0 && !isSelfUpdateDisabledByEnv(env) && isSelfUpdateManaged(bundleDir, env);
69534
69769
  if (!lifecycleMarkerEnabled) {
69535
69770
  return { lifecycleMarkerEnabled: false, runningMarker, uncleanPrevExit: false };