@parall/daemon 1.52.2 → 1.53.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.
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "1.52.2",
3
- "built_at": "2026-08-05T06:13:33.099Z",
2
+ "version": "1.53.0",
3
+ "built_at": "2026-08-05T09:24:55.164Z",
4
4
  "min_node_version": "20.0.0",
5
5
  "files": {
6
6
  "bb-browser-daemon.js": {
@@ -24,21 +24,21 @@
24
24
  "size": 7220
25
25
  },
26
26
  "parall-claude-agent.js": {
27
- "sha256": "2b780cc9718945476c05ae4f173426c5f064150ce7af499dba339ed293b4afff",
28
- "size": 2779447
27
+ "sha256": "03212787f04c48979089dcc72db0f34bcfe517e36a0d0702fe17e216cf46f69b",
28
+ "size": 2791626
29
29
  },
30
30
  "parall-codex-agent.js": {
31
- "sha256": "40ec7af38394abf1a926e4b982a08a110f3902cd609bdb1d9c5453f1e3d43434",
32
- "size": 2810151
31
+ "sha256": "d76c1a2329560bb3c7b8badfe20fff84464e844469b2514dcaee1b0595968ba7",
32
+ "size": 2822330
33
33
  },
34
34
  "parall-daemon.js": {
35
- "sha256": "b2e754ab09cf56e435b5947275968401721b3f194193701a6447e4d0ef2d61a9",
36
- "size": 2977953
35
+ "sha256": "a30282759eea26d092cbfd62f47bc6a8096db5ec054872dfe444c1bac56b49e0",
36
+ "size": 2978202
37
37
  },
38
38
  "parall-openclaw-agent.js": {
39
39
  "sha256": "856a1c3a9ae0ffef8efe2481fa1171dbeb1d67cccb88616aa9bf16da96a69355",
40
40
  "size": 9923
41
41
  }
42
42
  },
43
- "signature": "d11VXm3N6e4KIaGx7lp08AdQA9IE3RNCbcj673a+Wd7u2ibl/5VgBCXAMlOaO9HS3PoCGF1IMh3lsFciaHQ7Ag=="
43
+ "signature": "w30RAe4Nw8xT06MeL6hZBorrsxsoaZt0snApyNs8ICBk2XB/7cWyZKUZ+G1XC81r3fHkztJNIC4Qc0wBFJeMBQ=="
44
44
  }
@@ -60565,6 +60565,268 @@ parall clip exec <clip> <tool> [json-args] --connection <ccn_|alias>
60565
60565
  built-in tools.
60566
60566
  `;
60567
60567
 
60568
+ // ts/agent-core/dist/skills/parall-clip-authoring.js
60569
+ var PARALL_CLIP_AUTHORING_SKILL = `# Authoring a Parall Clip (v3)
60570
+
60571
+ Write a **registry (v3) clip**. This skill is for CREATING clips; to DISCOVER
60572
+ and CALL clips that are already installed, use the Parall Clips skill instead.
60573
+
60574
+ Two kinds of clip exist, and this document covers authoring both:
60575
+
60576
+ - A **browser clip** \u2014 the main subject here \u2014 is a folder of named commands
60577
+ that run on an Edge (a member's desktop or an org-shared cloud profile) and
60578
+ drive a real browser session: one manifest (\`manifest.json\` or \`site.json\`,
60579
+ either name works) + one \`.js\` file per command + optional \`_\`-prefixed
60580
+ helpers. The Edge runs each command's JS in a sandbox with a browser handle
60581
+ bound to the target profile.
60582
+ - An **MCP clip** is a manifest-ONLY declaration pointing at a remote MCP tool
60583
+ server \u2014 no \`.js\` files; its tools come live from that server's own
60584
+ \`tools/list\`, never from the manifest. See "MCP clips" below.
60585
+
60586
+ ## Project layout
60587
+
60588
+ \`\`\`
60589
+ my-clip/
60590
+ \u251C\u2500\u2500 manifest.json # name, description, version, command params
60591
+ \u251C\u2500\u2500 _helpers.js # OPTIONAL \u2014 any _-prefixed file is auto-injected into every command
60592
+ \u251C\u2500\u2500 search.js # one command = one file; filename (minus .js) IS the command name
60593
+ \u2514\u2500\u2500 profile.js # another command
60594
+ \`\`\`
60595
+
60596
+ ## manifest.json
60597
+
60598
+ \`\`\`json
60599
+ {
60600
+ "name": "twitter",
60601
+ "description": "Twitter / X",
60602
+ "version": "1.0.0",
60603
+ "commands": {
60604
+ "search": {
60605
+ "description": "Search tweets",
60606
+ "params": {
60607
+ "query": { "type": "string", "required": true },
60608
+ "count": { "type": "number", "required": false }
60609
+ }
60610
+ },
60611
+ "profile": {
60612
+ "description": "Fetch a user profile",
60613
+ "params": { "handle": { "type": "string", "required": true } }
60614
+ }
60615
+ }
60616
+ }
60617
+ \`\`\`
60618
+
60619
+ - \`commands\` keys MUST match the \`.js\` filenames (\`search\` \u2194 \`search.js\`).
60620
+ - \`params\` is the input contract the caller sees in \`clip info\`; validate them in code too.
60621
+ - **No top-level \`"type"\` needed for a browser clip** \u2014 omitting it means
60622
+ browser. The only accepted values are \`"browser"\` and \`"mcp"\` (for the
60623
+ latter, see "MCP clips" below). **\`"type": "clip"\` is the legacy Pinix v2
60624
+ package value and is refused at publish** \u2014 don't copy it in from an older
60625
+ clip.
60626
+
60627
+ ## A command file
60628
+
60629
+ \`\`\`js
60630
+ // search.js \u2014 a command is a single async function of (args).
60631
+ // The code does NOT know or pick the profile; the Edge binds it per invocation.
60632
+ //
60633
+ // SHAPE, not a runnable Twitter client: the "..." parts (the GraphQL path,
60634
+ // parseTweets' body) are what you fill in per target site. Deliberately not
60635
+ // pinned to a real X endpoint \u2014 a site's internal API paths rotate, and a
60636
+ // stale one baked into this skill would teach a URL that 404s.
60637
+ module.exports = async function (args) {
60638
+ if (!args.query) return { error: "Missing argument: query" };
60639
+
60640
+ const tab = await browser.open("https://x.com");
60641
+ // Everything after open() goes in try/finally: an early return or a thrown
60642
+ // fetch would otherwise leak the tab, and the Edge is long-lived.
60643
+ try {
60644
+ const ct0 = await tab.cookie("ct0");
60645
+ if (!ct0) return { error: "Not logged in" };
60646
+
60647
+ const data = await tab.fetch("/i/api/graphql/.../SearchTimeline?...", {
60648
+ headers: twitterHeaders(ct0), // from _helpers.js, auto-injected
60649
+ });
60650
+ return { query: args.query, tweets: parseTweets(data) };
60651
+ } finally {
60652
+ await tab.close();
60653
+ }
60654
+ };
60655
+ \`\`\`
60656
+
60657
+ Return a plain JSON-serializable object. A thrown error surfaces to the caller as
60658
+ \`SCRIPT_ERROR\`; a returned \`{ error: "..." }\` is your own typed failure \u2014 prefer it
60659
+ for expected cases (not logged in, missing arg).
60660
+
60661
+ ## Helpers (\`_\`-prefixed)
60662
+
60663
+ Any file whose name starts with \`_\` is NOT a command. Its top-level functions are
60664
+ injected into every command's scope \u2014 no import/require needed:
60665
+
60666
+ \`\`\`js
60667
+ // _helpers.js
60668
+ function twitterHeaders(ct0) {
60669
+ return { "X-Csrf-Token": ct0, "X-Twitter-Auth-Type": "OAuth2Session" };
60670
+ }
60671
+ function parseTweets(data) { /* ... */ }
60672
+ \`\`\`
60673
+
60674
+ ## Runtime API (globals available in every command)
60675
+
60676
+ - \`browser.open(url)\` \u2192 tab handle \xB7 \`browser.tabs()\` \u2192 open tabs
60677
+ - \`tab.cookie(name)\` \xB7 \`tab.fetch(url, opts)\` (in-browser fetch, carries the session)
60678
+ - \`tab.eval(expr)\` (escape hatch) \xB7 \`tab.click(sel)\` \xB7 \`tab.fill(sel, text)\` \xB7 \`tab.navigate(url)\`
60679
+ - \`tab.waitForSelector(sel)\` \xB7 \`tab.getTitle()\` \xB7 \`tab.getURL()\` \xB7 \`tab.screenshot()\` \xB7 \`tab.close()\`
60680
+ - \`fetch\` \u2014 runtime-side HTTP, does NOT go through the browser (no session)
60681
+ - \`console\` \u2014 logs \xB7 \`args\` \u2014 the invocation input
60682
+
60683
+ **Prefer \`tab.fetch\` over \`tab.eval\`**: fetch reuses the logged-in session and
60684
+ returns structured data; eval is the last resort. Always \`tab.close()\` what you
60685
+ open, and do it in a \`finally\` \u2014 an early return or a thrown fetch is exactly
60686
+ when the tab leaks.
60687
+
60688
+ ## Develop \u2192 publish \u2192 iterate
60689
+
60690
+ Use the platform \`parall clip\` subcommands \u2014 they reuse the credentials you
60691
+ already have (\`PRLL_API_KEY\` / \`PRLL_ORG_ID\`), so there is nothing to install
60692
+ or configure.
60693
+
60694
+ > A separate **standalone \`parall-clip\`** binary also exists (the Edge-side
60695
+ > authoring tool). It takes the SAME operations but a DIFFERENT argument shape \u2014
60696
+ > \`parall-clip exec <clip> <cmd> --query "AI" --count 10\` passes one flag per
60697
+ > param, while \`parall clip exec\` takes a single JSON blob. Do not mix the two
60698
+ > forms; everything below is the platform CLI.
60699
+
60700
+ 1. **Publish** the clip directory to the org registry. Publishing is not a
60701
+ release step here \u2014 it is the edit loop's SAVE button, because exec only
60702
+ ever sees published files:
60703
+
60704
+ \`\`\`sh
60705
+ parall clip publish ./my-clip/
60706
+ \`\`\`
60707
+
60708
+ It packages the directory (the manifest plus the directory's top-level
60709
+ \`.js\` files; an MCP clip is manifest-only) and POSTs it for you (5 MB cap).
60710
+ \`name\` is the org-wide upsert key \u2014 manifest fields win, else the directory
60711
+ name / \`0.0.1\` / \`private\` fill the gaps. Re-publishing an existing name is
60712
+ **author-only** and REPLACES the file set. Publishing into YOUR org makes it
60713
+ usable there immediately (same-org self-reference, no review);
60714
+ \`"visibility": "public"\` additionally submits the version for platform
60715
+ review before it can spread cross-org.
60716
+
60717
+ Programmatic equivalent (what \`publish\` calls under the hood \u2014 use only if
60718
+ you can't run the CLI). Send it verbatim-shaped: \`visibility\` is exactly
60719
+ one of \`"private"\` / \`"public"\`, and \`files\` maps each filename to its
60720
+ source as a string:
60721
+
60722
+ \`\`\`
60723
+ POST /api/v1/orgs/{orgId}/clip-registry/publish
60724
+ {
60725
+ "name": "twitter",
60726
+ "description": "Twitter / X",
60727
+ "version": "1.0.0",
60728
+ "visibility": "private",
60729
+ "manifest": {
60730
+ "name": "twitter",
60731
+ "version": "1.0.0",
60732
+ "commands": { "search": { "description": "Search tweets" } }
60733
+ },
60734
+ "files": { "search.js": "module.exports = async function (args) { return {}; };" }
60735
+ }
60736
+ \`\`\`
60737
+
60738
+ 2. **Exec** a command against a real target. Args are ONE argument \u2014 a JSON
60739
+ string (or plain text for a single-value command), not per-param flags:
60740
+
60741
+ \`\`\`sh
60742
+ parall clip exec <clip> <command> '{"query":"AI","count":10}' --connection <ccn_id|alias>
60743
+ # or route to a desktop (BYOC) device you own: --edge <edge-id>
60744
+ # --connection and --edge are mutually exclusive; --timeout <ms> defaults to 30000
60745
+ \`\`\`
60746
+
60747
+ A **cloud (hosted) profile is reachable ONLY via \`--connection\`** \u2014 the
60748
+ binding its maintainer created IS the authorization. With neither flag the
60749
+ server resolves only your own online desktop device, never a cloud profile.
60750
+ Discover the bindings with \`parall clip connections <clip>\`.
60751
+
60752
+ 3. **Iterate**: edit locally \u2192 \`parall clip publish\` again \u2192 re-exec. Exec
60753
+ resolves the file set from the REGISTRY, server-side \u2014 your own org always
60754
+ runs the live working copy, i.e. the latest publish. It NEVER reads your
60755
+ local directory: an edit you did not re-publish silently runs the previous
60756
+ version.
60757
+
60758
+ ## Install model & self-development (v3)
60759
+
60760
+ - Installing a clip is a **reference**, not a copy \u2014 the JS lives once in the Market DB.
60761
+ - **Your own org** always executes its **live working copy** (latest published files),
60762
+ so re-publishing is your edit loop.
60763
+ - **Other orgs** installing your \`public\` clip execute only the **approved snapshot**
60764
+ (\`approved_version_id\`); unreviewed public edits are invisible/unexecutable cross-org.
60765
+ - To customize someone else's public clip: install \u2192 **fetch its effective
60766
+ file set** \u2192 modify \u2192 **publish into your OWN org** (a derived private
60767
+ entry). You cannot edit a published clip in place. The CLI has no files
60768
+ subcommand (\`clip info\` returns only the manifest) \u2014 read the source via
60769
+ the API:
60770
+
60771
+ \`\`\`
60772
+ GET /api/v1/orgs/{orgId}/clip-registry/{clipId}/files
60773
+ \`\`\`
60774
+
60775
+ It returns exactly what you may read and execute: your own clip \u2192 the live
60776
+ working copy; an installed public clip \u2192 the approved snapshot.
60777
+
60778
+ ## MCP clips (manifest-only)
60779
+
60780
+ An MCP clip declares a remote MCP tool server. There is nothing to code: no
60781
+ \`.js\` files (the no-scripts refusal at publish applies to browser clips only),
60782
+ and the folder is just a manifest:
60783
+
60784
+ \`\`\`json
60785
+ {
60786
+ "name": "linear",
60787
+ "description": "Linear (MCP)",
60788
+ "version": "1.0.0",
60789
+ "type": "mcp",
60790
+ "mcp": { "server_url": "https://mcp.linear.app/mcp", "auth": "oauth" }
60791
+ }
60792
+ \`\`\`
60793
+
60794
+ - The \`mcp\` block takes ONLY \`server_url\` and \`auth\` (\`"none" | "bearer" |
60795
+ "api_key" | "oauth"\`). Any other key is refused at publish \u2014 a credential
60796
+ belongs to the installing org's own configuration, NEVER to the clip
60797
+ definition.
60798
+ - \`server_url\` must be an absolute **https** URL with no embedded credentials,
60799
+ query, or fragment. It is review material, frozen with the approved version.
60800
+ - Do NOT put the server in the top-level \`server\` / \`auth\` manifest keys \u2014
60801
+ those are legacy Edge-manifest fields nothing reads. Only the \`mcp\` block
60802
+ declares the server.
60803
+ - Both fields are optional, but what you declare is LOCKED: the installing
60804
+ org's config must match it, and changing the URL or auth mode means
60805
+ republishing.
60806
+ - Entering the credential / completing OAuth is a HUMAN step in the Clip
60807
+ Console (the config-write endpoints are session-only \u2014 an API key cannot
60808
+ call them). Once configured, discover the live tool schemas with
60809
+ \`parall clip tools <clip>\` and exec like any other clip.
60810
+ - Publish is the same command: \`parall clip publish ./my-clip/\`.
60811
+
60812
+ ## Cloud (hosted) vs desktop (BYOC) Edge
60813
+
60814
+ The same command JS runs on either. Hosted profiles are org-shared cloud browsers
60815
+ reachable ONLY via an explicit \`--connection\`; cloud state lives in S3 and is
60816
+ hydrated per pod. Your code never touches this \u2014 it just gets a \`browser\`/\`tab\`
60817
+ bound to whatever profile the connection selected.
60818
+
60819
+ ## Constraints
60820
+
60821
+ - Browser clips: one command = one file; keep a command's work self-contained
60822
+ (open what you need, close it, return). The Edge is stateless about your code
60823
+ between calls.
60824
+ - Never embed credentials in the clip source \u2014 rely on the profile's logged-in
60825
+ session (\`tab.cookie\` / \`tab.fetch\`). Published source is visible to installers.
60826
+ - Exec has a timeout (default 30s, caller-set up to 120s). Long scrapes should page,
60827
+ not block.
60828
+ `;
60829
+
60568
60830
  // ts/agent-core/dist/skills/index.js
60569
60831
  var SKILLS = [
60570
60832
  {
@@ -60594,8 +60856,13 @@ var SKILLS = [
60594
60856
  },
60595
60857
  {
60596
60858
  name: "parall-clips",
60597
- description: "Parall clip operations: list installed clips and their connections, inspect clip commands/tools, execute clip commands on an explicit connection. Use when: the task requires external capabilities (GitHub, web search, etc.), user asks about available tools/clips, or you need to call a clip command.",
60859
+ description: "Parall clip operations: list installed clips and their connections, inspect clip commands/tools, execute clip commands on an explicit connection. Use when: the task requires external capabilities (GitHub, web search, etc.), user asks about available tools/clips, or you need to call a clip command. For WRITING a new clip, use parall-clip-authoring instead.",
60598
60860
  content: PARALL_CLIPS_SKILL
60861
+ },
60862
+ {
60863
+ name: "parall-clip-authoring",
60864
+ description: "Authoring a v3 registry clip: write manifest.json + command .js files + _helpers, drive the browser/tab runtime API, publish the directory to the org registry with `parall clip publish` \u2014 or declare a manifest-only MCP clip pointing at a remote tool server. Use when: user asks to write/create/build a new clip, author a clip command, package a browser automation as a clip, declare an MCP clip, or publish a clip. For CALLING clips that already exist, use parall-clips instead.",
60865
+ content: PARALL_CLIP_AUTHORING_SKILL
60599
60866
  }
60600
60867
  ];
60601
60868
  function writeSkillFiles(targetDir) {
@@ -60565,6 +60565,268 @@ parall clip exec <clip> <tool> [json-args] --connection <ccn_|alias>
60565
60565
  built-in tools.
60566
60566
  `;
60567
60567
 
60568
+ // ts/agent-core/dist/skills/parall-clip-authoring.js
60569
+ var PARALL_CLIP_AUTHORING_SKILL = `# Authoring a Parall Clip (v3)
60570
+
60571
+ Write a **registry (v3) clip**. This skill is for CREATING clips; to DISCOVER
60572
+ and CALL clips that are already installed, use the Parall Clips skill instead.
60573
+
60574
+ Two kinds of clip exist, and this document covers authoring both:
60575
+
60576
+ - A **browser clip** \u2014 the main subject here \u2014 is a folder of named commands
60577
+ that run on an Edge (a member's desktop or an org-shared cloud profile) and
60578
+ drive a real browser session: one manifest (\`manifest.json\` or \`site.json\`,
60579
+ either name works) + one \`.js\` file per command + optional \`_\`-prefixed
60580
+ helpers. The Edge runs each command's JS in a sandbox with a browser handle
60581
+ bound to the target profile.
60582
+ - An **MCP clip** is a manifest-ONLY declaration pointing at a remote MCP tool
60583
+ server \u2014 no \`.js\` files; its tools come live from that server's own
60584
+ \`tools/list\`, never from the manifest. See "MCP clips" below.
60585
+
60586
+ ## Project layout
60587
+
60588
+ \`\`\`
60589
+ my-clip/
60590
+ \u251C\u2500\u2500 manifest.json # name, description, version, command params
60591
+ \u251C\u2500\u2500 _helpers.js # OPTIONAL \u2014 any _-prefixed file is auto-injected into every command
60592
+ \u251C\u2500\u2500 search.js # one command = one file; filename (minus .js) IS the command name
60593
+ \u2514\u2500\u2500 profile.js # another command
60594
+ \`\`\`
60595
+
60596
+ ## manifest.json
60597
+
60598
+ \`\`\`json
60599
+ {
60600
+ "name": "twitter",
60601
+ "description": "Twitter / X",
60602
+ "version": "1.0.0",
60603
+ "commands": {
60604
+ "search": {
60605
+ "description": "Search tweets",
60606
+ "params": {
60607
+ "query": { "type": "string", "required": true },
60608
+ "count": { "type": "number", "required": false }
60609
+ }
60610
+ },
60611
+ "profile": {
60612
+ "description": "Fetch a user profile",
60613
+ "params": { "handle": { "type": "string", "required": true } }
60614
+ }
60615
+ }
60616
+ }
60617
+ \`\`\`
60618
+
60619
+ - \`commands\` keys MUST match the \`.js\` filenames (\`search\` \u2194 \`search.js\`).
60620
+ - \`params\` is the input contract the caller sees in \`clip info\`; validate them in code too.
60621
+ - **No top-level \`"type"\` needed for a browser clip** \u2014 omitting it means
60622
+ browser. The only accepted values are \`"browser"\` and \`"mcp"\` (for the
60623
+ latter, see "MCP clips" below). **\`"type": "clip"\` is the legacy Pinix v2
60624
+ package value and is refused at publish** \u2014 don't copy it in from an older
60625
+ clip.
60626
+
60627
+ ## A command file
60628
+
60629
+ \`\`\`js
60630
+ // search.js \u2014 a command is a single async function of (args).
60631
+ // The code does NOT know or pick the profile; the Edge binds it per invocation.
60632
+ //
60633
+ // SHAPE, not a runnable Twitter client: the "..." parts (the GraphQL path,
60634
+ // parseTweets' body) are what you fill in per target site. Deliberately not
60635
+ // pinned to a real X endpoint \u2014 a site's internal API paths rotate, and a
60636
+ // stale one baked into this skill would teach a URL that 404s.
60637
+ module.exports = async function (args) {
60638
+ if (!args.query) return { error: "Missing argument: query" };
60639
+
60640
+ const tab = await browser.open("https://x.com");
60641
+ // Everything after open() goes in try/finally: an early return or a thrown
60642
+ // fetch would otherwise leak the tab, and the Edge is long-lived.
60643
+ try {
60644
+ const ct0 = await tab.cookie("ct0");
60645
+ if (!ct0) return { error: "Not logged in" };
60646
+
60647
+ const data = await tab.fetch("/i/api/graphql/.../SearchTimeline?...", {
60648
+ headers: twitterHeaders(ct0), // from _helpers.js, auto-injected
60649
+ });
60650
+ return { query: args.query, tweets: parseTweets(data) };
60651
+ } finally {
60652
+ await tab.close();
60653
+ }
60654
+ };
60655
+ \`\`\`
60656
+
60657
+ Return a plain JSON-serializable object. A thrown error surfaces to the caller as
60658
+ \`SCRIPT_ERROR\`; a returned \`{ error: "..." }\` is your own typed failure \u2014 prefer it
60659
+ for expected cases (not logged in, missing arg).
60660
+
60661
+ ## Helpers (\`_\`-prefixed)
60662
+
60663
+ Any file whose name starts with \`_\` is NOT a command. Its top-level functions are
60664
+ injected into every command's scope \u2014 no import/require needed:
60665
+
60666
+ \`\`\`js
60667
+ // _helpers.js
60668
+ function twitterHeaders(ct0) {
60669
+ return { "X-Csrf-Token": ct0, "X-Twitter-Auth-Type": "OAuth2Session" };
60670
+ }
60671
+ function parseTweets(data) { /* ... */ }
60672
+ \`\`\`
60673
+
60674
+ ## Runtime API (globals available in every command)
60675
+
60676
+ - \`browser.open(url)\` \u2192 tab handle \xB7 \`browser.tabs()\` \u2192 open tabs
60677
+ - \`tab.cookie(name)\` \xB7 \`tab.fetch(url, opts)\` (in-browser fetch, carries the session)
60678
+ - \`tab.eval(expr)\` (escape hatch) \xB7 \`tab.click(sel)\` \xB7 \`tab.fill(sel, text)\` \xB7 \`tab.navigate(url)\`
60679
+ - \`tab.waitForSelector(sel)\` \xB7 \`tab.getTitle()\` \xB7 \`tab.getURL()\` \xB7 \`tab.screenshot()\` \xB7 \`tab.close()\`
60680
+ - \`fetch\` \u2014 runtime-side HTTP, does NOT go through the browser (no session)
60681
+ - \`console\` \u2014 logs \xB7 \`args\` \u2014 the invocation input
60682
+
60683
+ **Prefer \`tab.fetch\` over \`tab.eval\`**: fetch reuses the logged-in session and
60684
+ returns structured data; eval is the last resort. Always \`tab.close()\` what you
60685
+ open, and do it in a \`finally\` \u2014 an early return or a thrown fetch is exactly
60686
+ when the tab leaks.
60687
+
60688
+ ## Develop \u2192 publish \u2192 iterate
60689
+
60690
+ Use the platform \`parall clip\` subcommands \u2014 they reuse the credentials you
60691
+ already have (\`PRLL_API_KEY\` / \`PRLL_ORG_ID\`), so there is nothing to install
60692
+ or configure.
60693
+
60694
+ > A separate **standalone \`parall-clip\`** binary also exists (the Edge-side
60695
+ > authoring tool). It takes the SAME operations but a DIFFERENT argument shape \u2014
60696
+ > \`parall-clip exec <clip> <cmd> --query "AI" --count 10\` passes one flag per
60697
+ > param, while \`parall clip exec\` takes a single JSON blob. Do not mix the two
60698
+ > forms; everything below is the platform CLI.
60699
+
60700
+ 1. **Publish** the clip directory to the org registry. Publishing is not a
60701
+ release step here \u2014 it is the edit loop's SAVE button, because exec only
60702
+ ever sees published files:
60703
+
60704
+ \`\`\`sh
60705
+ parall clip publish ./my-clip/
60706
+ \`\`\`
60707
+
60708
+ It packages the directory (the manifest plus the directory's top-level
60709
+ \`.js\` files; an MCP clip is manifest-only) and POSTs it for you (5 MB cap).
60710
+ \`name\` is the org-wide upsert key \u2014 manifest fields win, else the directory
60711
+ name / \`0.0.1\` / \`private\` fill the gaps. Re-publishing an existing name is
60712
+ **author-only** and REPLACES the file set. Publishing into YOUR org makes it
60713
+ usable there immediately (same-org self-reference, no review);
60714
+ \`"visibility": "public"\` additionally submits the version for platform
60715
+ review before it can spread cross-org.
60716
+
60717
+ Programmatic equivalent (what \`publish\` calls under the hood \u2014 use only if
60718
+ you can't run the CLI). Send it verbatim-shaped: \`visibility\` is exactly
60719
+ one of \`"private"\` / \`"public"\`, and \`files\` maps each filename to its
60720
+ source as a string:
60721
+
60722
+ \`\`\`
60723
+ POST /api/v1/orgs/{orgId}/clip-registry/publish
60724
+ {
60725
+ "name": "twitter",
60726
+ "description": "Twitter / X",
60727
+ "version": "1.0.0",
60728
+ "visibility": "private",
60729
+ "manifest": {
60730
+ "name": "twitter",
60731
+ "version": "1.0.0",
60732
+ "commands": { "search": { "description": "Search tweets" } }
60733
+ },
60734
+ "files": { "search.js": "module.exports = async function (args) { return {}; };" }
60735
+ }
60736
+ \`\`\`
60737
+
60738
+ 2. **Exec** a command against a real target. Args are ONE argument \u2014 a JSON
60739
+ string (or plain text for a single-value command), not per-param flags:
60740
+
60741
+ \`\`\`sh
60742
+ parall clip exec <clip> <command> '{"query":"AI","count":10}' --connection <ccn_id|alias>
60743
+ # or route to a desktop (BYOC) device you own: --edge <edge-id>
60744
+ # --connection and --edge are mutually exclusive; --timeout <ms> defaults to 30000
60745
+ \`\`\`
60746
+
60747
+ A **cloud (hosted) profile is reachable ONLY via \`--connection\`** \u2014 the
60748
+ binding its maintainer created IS the authorization. With neither flag the
60749
+ server resolves only your own online desktop device, never a cloud profile.
60750
+ Discover the bindings with \`parall clip connections <clip>\`.
60751
+
60752
+ 3. **Iterate**: edit locally \u2192 \`parall clip publish\` again \u2192 re-exec. Exec
60753
+ resolves the file set from the REGISTRY, server-side \u2014 your own org always
60754
+ runs the live working copy, i.e. the latest publish. It NEVER reads your
60755
+ local directory: an edit you did not re-publish silently runs the previous
60756
+ version.
60757
+
60758
+ ## Install model & self-development (v3)
60759
+
60760
+ - Installing a clip is a **reference**, not a copy \u2014 the JS lives once in the Market DB.
60761
+ - **Your own org** always executes its **live working copy** (latest published files),
60762
+ so re-publishing is your edit loop.
60763
+ - **Other orgs** installing your \`public\` clip execute only the **approved snapshot**
60764
+ (\`approved_version_id\`); unreviewed public edits are invisible/unexecutable cross-org.
60765
+ - To customize someone else's public clip: install \u2192 **fetch its effective
60766
+ file set** \u2192 modify \u2192 **publish into your OWN org** (a derived private
60767
+ entry). You cannot edit a published clip in place. The CLI has no files
60768
+ subcommand (\`clip info\` returns only the manifest) \u2014 read the source via
60769
+ the API:
60770
+
60771
+ \`\`\`
60772
+ GET /api/v1/orgs/{orgId}/clip-registry/{clipId}/files
60773
+ \`\`\`
60774
+
60775
+ It returns exactly what you may read and execute: your own clip \u2192 the live
60776
+ working copy; an installed public clip \u2192 the approved snapshot.
60777
+
60778
+ ## MCP clips (manifest-only)
60779
+
60780
+ An MCP clip declares a remote MCP tool server. There is nothing to code: no
60781
+ \`.js\` files (the no-scripts refusal at publish applies to browser clips only),
60782
+ and the folder is just a manifest:
60783
+
60784
+ \`\`\`json
60785
+ {
60786
+ "name": "linear",
60787
+ "description": "Linear (MCP)",
60788
+ "version": "1.0.0",
60789
+ "type": "mcp",
60790
+ "mcp": { "server_url": "https://mcp.linear.app/mcp", "auth": "oauth" }
60791
+ }
60792
+ \`\`\`
60793
+
60794
+ - The \`mcp\` block takes ONLY \`server_url\` and \`auth\` (\`"none" | "bearer" |
60795
+ "api_key" | "oauth"\`). Any other key is refused at publish \u2014 a credential
60796
+ belongs to the installing org's own configuration, NEVER to the clip
60797
+ definition.
60798
+ - \`server_url\` must be an absolute **https** URL with no embedded credentials,
60799
+ query, or fragment. It is review material, frozen with the approved version.
60800
+ - Do NOT put the server in the top-level \`server\` / \`auth\` manifest keys \u2014
60801
+ those are legacy Edge-manifest fields nothing reads. Only the \`mcp\` block
60802
+ declares the server.
60803
+ - Both fields are optional, but what you declare is LOCKED: the installing
60804
+ org's config must match it, and changing the URL or auth mode means
60805
+ republishing.
60806
+ - Entering the credential / completing OAuth is a HUMAN step in the Clip
60807
+ Console (the config-write endpoints are session-only \u2014 an API key cannot
60808
+ call them). Once configured, discover the live tool schemas with
60809
+ \`parall clip tools <clip>\` and exec like any other clip.
60810
+ - Publish is the same command: \`parall clip publish ./my-clip/\`.
60811
+
60812
+ ## Cloud (hosted) vs desktop (BYOC) Edge
60813
+
60814
+ The same command JS runs on either. Hosted profiles are org-shared cloud browsers
60815
+ reachable ONLY via an explicit \`--connection\`; cloud state lives in S3 and is
60816
+ hydrated per pod. Your code never touches this \u2014 it just gets a \`browser\`/\`tab\`
60817
+ bound to whatever profile the connection selected.
60818
+
60819
+ ## Constraints
60820
+
60821
+ - Browser clips: one command = one file; keep a command's work self-contained
60822
+ (open what you need, close it, return). The Edge is stateless about your code
60823
+ between calls.
60824
+ - Never embed credentials in the clip source \u2014 rely on the profile's logged-in
60825
+ session (\`tab.cookie\` / \`tab.fetch\`). Published source is visible to installers.
60826
+ - Exec has a timeout (default 30s, caller-set up to 120s). Long scrapes should page,
60827
+ not block.
60828
+ `;
60829
+
60568
60830
  // ts/agent-core/dist/skills/index.js
60569
60831
  var SKILLS = [
60570
60832
  {
@@ -60594,8 +60856,13 @@ var SKILLS = [
60594
60856
  },
60595
60857
  {
60596
60858
  name: "parall-clips",
60597
- description: "Parall clip operations: list installed clips and their connections, inspect clip commands/tools, execute clip commands on an explicit connection. Use when: the task requires external capabilities (GitHub, web search, etc.), user asks about available tools/clips, or you need to call a clip command.",
60859
+ description: "Parall clip operations: list installed clips and their connections, inspect clip commands/tools, execute clip commands on an explicit connection. Use when: the task requires external capabilities (GitHub, web search, etc.), user asks about available tools/clips, or you need to call a clip command. For WRITING a new clip, use parall-clip-authoring instead.",
60598
60860
  content: PARALL_CLIPS_SKILL
60861
+ },
60862
+ {
60863
+ name: "parall-clip-authoring",
60864
+ description: "Authoring a v3 registry clip: write manifest.json + command .js files + _helpers, drive the browser/tab runtime API, publish the directory to the org registry with `parall clip publish` \u2014 or declare a manifest-only MCP clip pointing at a remote tool server. Use when: user asks to write/create/build a new clip, author a clip command, package a browser automation as a clip, declare an MCP clip, or publish a clip. For CALLING clips that already exist, use parall-clips instead.",
60865
+ content: PARALL_CLIP_AUTHORING_SKILL
60599
60866
  }
60600
60867
  ];
60601
60868
  function writeSkillFiles(targetDir) {
@@ -54849,6 +54849,13 @@ var init_parall_clips = __esm({
54849
54849
  }
54850
54850
  });
54851
54851
 
54852
+ // ts/agent-core/dist/skills/parall-clip-authoring.js
54853
+ var init_parall_clip_authoring = __esm({
54854
+ "ts/agent-core/dist/skills/parall-clip-authoring.js"() {
54855
+ "use strict";
54856
+ }
54857
+ });
54858
+
54852
54859
  // ts/agent-core/dist/skills/index.js
54853
54860
  var init_skills = __esm({
54854
54861
  "ts/agent-core/dist/skills/index.js"() {
@@ -54859,12 +54866,14 @@ var init_skills = __esm({
54859
54866
  init_parall_schedules();
54860
54867
  init_parall_external_triggers();
54861
54868
  init_parall_clips();
54869
+ init_parall_clip_authoring();
54862
54870
  init_parall_platform();
54863
54871
  init_parall_tasks();
54864
54872
  init_parall_wiki();
54865
54873
  init_parall_schedules();
54866
54874
  init_parall_external_triggers();
54867
54875
  init_parall_clips();
54876
+ init_parall_clip_authoring();
54868
54877
  }
54869
54878
  });
54870
54879
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parall/daemon",
3
- "version": "1.52.2",
3
+ "version": "1.53.0",
4
4
  "description": "Parall local agent runtime — daemon supervisor + bridge runtimes, bundled as standalone JS files",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -33,11 +33,11 @@
33
33
  "@aws-sdk/client-s3": "3.984.0",
34
34
  "@pinixai/bb-browser-pro": "0.15.0",
35
35
  "ws": "^8.18.0",
36
- "@parall/agent-core": "1.52.2",
37
- "@parall/sdk": "1.52.2",
38
- "@parall/claude-agent": "1.52.2",
39
- "@parall/codex-agent": "1.52.2",
40
- "@parall/openclaw-agent": "1.52.2"
36
+ "@parall/agent-core": "1.53.0",
37
+ "@parall/claude-agent": "1.53.0",
38
+ "@parall/codex-agent": "1.53.0",
39
+ "@parall/openclaw-agent": "1.53.0",
40
+ "@parall/sdk": "1.53.0"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "^22.0.0",