@parall/agent-core 1.52.1 → 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.
@@ -2,6 +2,7 @@ import type { GatewayLogger } from './dispatch-adapter.js';
2
2
  import type { AgentCapability } from './platform-config.js';
3
3
  export declare const CAPABILITY_FEISHU_CLI = "feishu-cli";
4
4
  export declare const CAPABILITY_SLACK_SEND = "slack-send";
5
+ export declare const CAPABILITY_WECHAT_SEND = "wechat-send";
5
6
  export declare function channelCapabilityKeyFor(provider: string): string;
6
7
  export declare const CHANNEL_POINTER_MAGIC = "parall channel capability pointer";
7
8
  export declare function capabilityBinDir(stateDir: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"channel-capability.d.ts","sourceRoot":"","sources":["../src/channel-capability.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAoB5D,eAAO,MAAM,qBAAqB,eAAe,CAAC;AAOlD,eAAO,MAAM,qBAAqB,eAAe,CAAC;AAMlD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGhE;AAMD,eAAO,MAAM,qBAAqB,sCAAsC,CAAC;AAMzE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEzD;AAcD,wBAAgB,oBAAoB,IAAI,MAAM,CAK7C;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,eAAe,EAAE,EAC/B,GAAG,CAAC,EAAE,aAAa,GAClB,IAAI,CAMN;AAuED,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,MAAM,CAkBR;AAED,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,MAAM,CAUR"}
1
+ {"version":3,"file":"channel-capability.d.ts","sourceRoot":"","sources":["../src/channel-capability.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAoB5D,eAAO,MAAM,qBAAqB,eAAe,CAAC;AAOlD,eAAO,MAAM,qBAAqB,eAAe,CAAC;AAMlD,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AAMpD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIhE;AAMD,eAAO,MAAM,qBAAqB,sCAAsC,CAAC;AAMzE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEzD;AAcD,wBAAgB,oBAAoB,IAAI,MAAM,CAK7C;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,eAAe,EAAE,EAC/B,GAAG,CAAC,EAAE,aAAa,GAClB,IAAI,CAMN;AAuED,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,MAAM,CAkBR;AAED,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,MAAM,CAUR"}
@@ -25,6 +25,11 @@ export const CAPABILITY_FEISHU_CLI = 'feishu-cli';
25
25
  // (gateway-base) can map provider → capability without pattern-matching on
26
26
  // a `-cli` suffix slack will never have.
27
27
  export const CAPABILITY_SLACK_SEND = 'slack-send';
28
+ // WeChat's channel capability key (tier B, research preview): the
29
+ // affordance is the platform verb `parall wechat send` — same shape as
30
+ // slack; the key exists so event-hint routing can map provider →
31
+ // capability without the `-cli` suffix convention wechat will never have.
32
+ export const CAPABILITY_WECHAT_SEND = 'wechat-send';
28
33
  // channelCapabilityKeyFor maps a channel provider to the capability key the
29
34
  // server declares for it in agents.capabilities[] — the SSOT for the
30
35
  // per-provider reply-affordance lookup. Unknown providers fall back to the
@@ -32,6 +37,8 @@ export const CAPABILITY_SLACK_SEND = 'slack-send';
32
37
  export function channelCapabilityKeyFor(provider) {
33
38
  if (provider === 'slack')
34
39
  return CAPABILITY_SLACK_SEND;
40
+ if (provider === 'wechat')
41
+ return CAPABILITY_WECHAT_SEND;
35
42
  return `${provider}-cli`;
36
43
  }
37
44
  // Marker embedded in every generated pointer. channel-exec skips any PATH
@@ -1 +1 @@
1
- {"version":3,"file":"event-format.d.ts","sourceRoot":"","sources":["../src/event-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAS1D,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAkIzD;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAEtE;AAoFD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAK/D;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,CAkBnE"}
1
+ {"version":3,"file":"event-format.d.ts","sourceRoot":"","sources":["../src/event-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAS1D,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAkIzD;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAEtE;AAsGD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAK/D;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,CAkBnE"}
@@ -192,13 +192,30 @@ function buildSendMessageHint(event) {
192
192
  : '';
193
193
  return `\n<system-reminder>To reply, use the platform verb: \`parall slack send${channelArg}${replyTo} --text <your reply>\`. In channels --reply-to is REQUIRED (the reply lands in that message's thread); in DMs it is optional (DMs are linear). \`parall slack send\` is the ONLY outbound path — your plain text output is NOT delivered to the external conversation.</system-reminder>`;
194
194
  }
195
+ if (event.channelProvider === 'wechat') {
196
+ // WeChat (tier B, research preview): no threads, no message ids —
197
+ // the reply goes to the conversation named in this event (a friend
198
+ // wxid, or a room id ending in @chatroom). In group chats --at
199
+ // carries the actual speaker wxid from this event (senderId is the
200
+ // extracted group speaker) so the @-mention closes the loop; only
201
+ // fall back to a placeholder when the id is missing.
202
+ const toArg = event.channelExternalConversationId
203
+ ? ` --to "${event.channelExternalConversationId}"`
204
+ : ' --to <wxid from this event>';
205
+ const atArg = event.channelConversationType === 'group'
206
+ ? event.senderId && event.senderId !== 'external'
207
+ ? ` --at "${event.senderId}"`
208
+ : ' --at <wxid of the person you are answering>'
209
+ : '';
210
+ return `\n<system-reminder>To reply, use the platform verb: \`parall wechat send${toArg}${atArg} --text <your reply>\`. In group chats, --at @-mentions the person you are answering. \`parall wechat send\` is the ONLY outbound path — your plain text output is NOT delivered to the external conversation.</system-reminder>`;
211
+ }
195
212
  if (!event.channelProvider) {
196
213
  // Cosmetic provider-label miss (the connection lookup transiently
197
214
  // failed): a live grant means outbound IS available, but naming one
198
215
  // vendor's command here could point a Slack conversation at
199
216
  // lark-cli (or vice versa). Stay vendor-neutral and defer to the
200
217
  // capability declaration already in the system prompt.
201
- return `\n<system-reminder>To reply, use the channel capability granted in your system prompt — for Feishu conversations that is \`lark-cli im\`, for Slack it is \`parall slack send\` (pass the message id from this event as --reply-to). That capability is the ONLY outbound path — your plain text output is NOT delivered to the external conversation.</system-reminder>`;
218
+ return `\n<system-reminder>To reply, use the channel capability granted in your system prompt — for Feishu conversations that is \`lark-cli im\`, for Slack it is \`parall slack send\` (pass the message id from this event as --reply-to), for WeChat it is \`parall wechat send\`. That capability is the ONLY outbound path — your plain text output is NOT delivered to the external conversation.</system-reminder>`;
202
219
  }
203
220
  // Known non-slack provider → the tier-A vendor-CLI shape (feishu is
204
221
  // the only tier-A channel today).
@@ -119,6 +119,7 @@ export declare class ParallAgentGateway {
119
119
  private readonly dispatchedTasks;
120
120
  private readonly channelConnectionProviders;
121
121
  private readonly dispatchedMessages;
122
+ private readonly injectedMainBufferEvents;
122
123
  readonly typedRedriveBackoff: Map<string, {
123
124
  failures: number;
124
125
  until: number;
@@ -1 +1 @@
1
- {"version":3,"file":"gateway-base.d.ts","sourceRoot":"","sources":["../src/gateway-base.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gateway-base.d.ts","sourceRoot":"","sources":["../src/gateway-base.ts"],"names":[],"mappings":"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"}
@@ -4,9 +4,9 @@ import * as path from 'node:path';
4
4
  import { randomUUID } from 'node:crypto';
5
5
  import { ApiError, mentionTargetsUser } from '@parall/sdk';
6
6
  import { buildEventBody, buildEventBodyForForkResult, buildForkResultPrefix, buildForkScopePrefix, } from './event-format.js';
7
- import { CAPABILITY_SLACK_SEND, channelCapabilityKeyFor } from './channel-capability.js';
7
+ import { CAPABILITY_SLACK_SEND, CAPABILITY_WECHAT_SEND, channelCapabilityKeyFor, } from './channel-capability.js';
8
8
  import { buildErrorStepContent, } from './dispatch-adapter.js';
9
- import { clearTypedDedupeForEvent, consumeMessageWorkItem, consumeTypedDispatch, dispatchLaneGroup, resolveDispatchByID, settleDrainedTypedGroup, steerLaneMessage, typedLedgerEventIds, } from './gateway-lane-flow.js';
9
+ import { clearTypedDedupeForEvent, consumeMessageWorkItem, consumeTypedDispatch, dispatchLaneGroup, resolveDispatchByID, settleDrainedTypedGroup, shiftMainBufferGroup, steerLaneMessage, typedLedgerEventIds, } from './gateway-lane-flow.js';
10
10
  import { LaneLedger, bindLaneSession, releaseLocalMessageClaims } from './lane-ledger.js';
11
11
  import { routeTrigger } from './routing.js';
12
12
  import { redactTurnOutcome } from './redact.js';
@@ -159,6 +159,7 @@ export class ParallAgentGateway {
159
159
  // (stable mapping; avoids one connection fetch per inbound message).
160
160
  channelConnectionProviders = new Map();
161
161
  dispatchedMessages = new Set();
162
+ injectedMainBufferEvents = new WeakSet();
162
163
  // Per-WorkItem failure backoff for typed dispatch consumption — see
163
164
  // LaneFlowHost.typedRedriveBackoff in gateway-lane-flow.ts.
164
165
  typedRedriveBackoff = new Map();
@@ -1620,14 +1621,10 @@ export class ParallAgentGateway {
1620
1621
  break;
1621
1622
  }
1622
1623
  const groupKey = this.dispatchGroupKey(this.dispatchState.mainBuffer[0]);
1623
- const events = [];
1624
- while (this.dispatchState.mainBuffer[0] &&
1625
- this.dispatchGroupKey(this.dispatchState.mainBuffer[0]) === groupKey) {
1626
- events.push(this.dispatchState.mainBuffer.shift());
1627
- }
1624
+ const hasPendingInjections = this.opts.dispatchAdapter.hasPendingInjections?.(this.opts.runtimeKey) ?? false;
1625
+ const events = shiftMainBufferGroup(this.laneFlowHost(), groupKey, hasPendingInjections && this.opts.dispatchAdapter.inputLifecycleMode === 'explicit');
1628
1626
  const event = events[events.length - 1];
1629
1627
  const earlier = events.slice(0, -1);
1630
- const hasPendingInjections = this.opts.dispatchAdapter.hasPendingInjections?.(this.opts.runtimeKey) ?? false;
1631
1628
  const pendingFork = hasPendingInjections
1632
1629
  ? []
1633
1630
  : this.dispatchState.pendingForkResults.splice(0);
@@ -2534,7 +2531,7 @@ export class ParallAgentGateway {
2534
2531
  const keys = this.opts.getCapabilityKeys?.() ?? [];
2535
2532
  const cliCapable = provider
2536
2533
  ? keys.includes(channelCapabilityKeyFor(provider))
2537
- : keys.some((k) => k.endsWith('-cli') || k === CAPABILITY_SLACK_SEND);
2534
+ : keys.some((k) => k.endsWith('-cli') || k === CAPABILITY_SLACK_SEND || k === CAPABILITY_WECHAT_SEND);
2538
2535
  const event = {
2539
2536
  type: 'channel_message',
2540
2537
  targetId: conv.id,
@@ -25,6 +25,8 @@ export interface LaneFlowHost {
25
25
  dispatchState: {
26
26
  mainBuffer: ParallEvent[];
27
27
  };
28
+ injectedMainBufferEvents: WeakSet<ParallEvent>;
29
+ dispatchGroupKey(event: ParallEvent): string;
28
30
  /**
29
31
  * Per-WorkItem failure backoff for typed dispatch consumption. A consume
30
32
  * that ends without an ack re-arms the entry; the next attempt for the
@@ -58,6 +60,12 @@ export interface LaneFlowHost {
58
60
  buildMessageDispatchDecision(chatId: string, message: DispatchableMessage): Promise<MessageDispatchDecision>;
59
61
  handleInboundEvent(event: ParallEvent): Promise<boolean>;
60
62
  }
63
+ /**
64
+ * Shift one same-lane group from the main buffer. Explicit soft-steer
65
+ * bookkeeping keeps the original one-event stdin frame boundaries; ordinary
66
+ * backlog and non-explicit adapters retain historical batching.
67
+ */
68
+ export declare function shiftMainBufferGroup(host: LaneFlowHost, groupKey: string, preserveInjectedFrameBoundary: boolean): ParallEvent[];
61
69
  export declare function steerLaneMessage(host: LaneFlowHost, event: ParallEvent): Promise<void>;
62
70
  /**
63
71
  * Dispatch one group of same-lane message events under the ledger contract:
@@ -1 +1 @@
1
- {"version":3,"file":"gateway-lane-flow.d.ts","sourceRoot":"","sources":["../src/gateway-lane-flow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gateway-lane-flow.d.ts","sourceRoot":"","sources":["../src/gateway-lane-flow.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,46 @@
1
1
  import { ApiError } from '@parall/sdk';
2
2
  import { buildEventBody } from './event-format.js';
3
3
  import { LedgerUnsupportedError } from './lane-ledger.js';
4
+ /**
5
+ * Shift one same-lane group from the main buffer. Explicit soft-steer
6
+ * bookkeeping keeps the original one-event stdin frame boundaries; ordinary
7
+ * backlog and non-explicit adapters retain historical batching.
8
+ */
9
+ export function shiftMainBufferGroup(host, groupKey, preserveInjectedFrameBoundary) {
10
+ const events = [];
11
+ while (host.dispatchState.mainBuffer[0] &&
12
+ host.dispatchGroupKey(host.dispatchState.mainBuffer[0]) === groupKey &&
13
+ (!preserveInjectedFrameBoundary || events.length === 0)) {
14
+ events.push(host.dispatchState.mainBuffer.shift());
15
+ }
16
+ return events;
17
+ }
18
+ function hasUninjectedSameLaneEventAhead(host, event) {
19
+ const eventIndex = host.dispatchState.mainBuffer.lastIndexOf(event);
20
+ if (eventIndex <= 0)
21
+ return false;
22
+ const groupKey = host.dispatchGroupKey(event);
23
+ return host.dispatchState.mainBuffer
24
+ .slice(0, eventIndex)
25
+ .some((buffered) => host.dispatchGroupKey(buffered) === groupKey &&
26
+ !host.injectedMainBufferEvents.has(buffered));
27
+ }
4
28
  export async function steerLaneMessage(host, event) {
5
29
  const { laneLedger: ledger, opts } = host;
6
30
  const adapter = opts.dispatchAdapter;
7
31
  if (!ledger || !adapter.enqueueDuringDispatch)
8
32
  return;
33
+ // Push-before-await preserves arrival order in mainBuffer. Keep stdin in
34
+ // that same order: while an earlier same-lane event is still un-injected
35
+ // (including an injection attempt in flight), later events stay buffered.
36
+ if (hasUninjectedSameLaneEventAhead(host, event))
37
+ return;
9
38
  const folded = await ledger.steerLive(event);
10
- if (folded &&
11
- (await adapter.enqueueDuringDispatch(opts.runtimeKey, buildEventBody(event), folded.inputLifecycle))) {
39
+ if (!folded)
40
+ return;
41
+ const injected = await adapter.enqueueDuringDispatch(opts.runtimeKey, buildEventBody(event), folded.inputLifecycle);
42
+ if (injected) {
43
+ host.injectedMainBufferEvents.add(event);
12
44
  opts.log?.info(`steer folded+injected for ${event.messageId} (will drain for bookkeeping)`);
13
45
  }
14
46
  }
@@ -4,6 +4,7 @@ export { PARALL_WIKI_SKILL } from './parall-wiki.js';
4
4
  export { PARALL_SCHEDULES_SKILL } from './parall-schedules.js';
5
5
  export { PARALL_EXTERNAL_TRIGGERS_SKILL } from './parall-external-triggers.js';
6
6
  export { PARALL_CLIPS_SKILL } from './parall-clips.js';
7
+ export { PARALL_CLIP_AUTHORING_SKILL } from './parall-clip-authoring.js';
7
8
  export type SkillMeta = {
8
9
  name: string;
9
10
  description: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/skills/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,8BAA8B,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AASvD,MAAM,MAAM,SAAS,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/E,eAAO,MAAM,MAAM,EAAE,SAAS,EAqC7B,CAAC;AAEF,yEAAyE;AACzE,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAKvD;AAED,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAIjE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/skills/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,8BAA8B,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAUzE,MAAM,MAAM,SAAS,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/E,eAAO,MAAM,MAAM,EAAE,SAAS,EA2C7B,CAAC;AAEF,yEAAyE;AACzE,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAKvD;AAED,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAIjE"}
@@ -6,12 +6,14 @@ export { PARALL_WIKI_SKILL } from './parall-wiki.js';
6
6
  export { PARALL_SCHEDULES_SKILL } from './parall-schedules.js';
7
7
  export { PARALL_EXTERNAL_TRIGGERS_SKILL } from './parall-external-triggers.js';
8
8
  export { PARALL_CLIPS_SKILL } from './parall-clips.js';
9
+ export { PARALL_CLIP_AUTHORING_SKILL } from './parall-clip-authoring.js';
9
10
  import { PARALL_PLATFORM_SKILL } from './parall-platform.js';
10
11
  import { PARALL_TASKS_SKILL } from './parall-tasks.js';
11
12
  import { PARALL_WIKI_SKILL } from './parall-wiki.js';
12
13
  import { PARALL_SCHEDULES_SKILL } from './parall-schedules.js';
13
14
  import { PARALL_EXTERNAL_TRIGGERS_SKILL } from './parall-external-triggers.js';
14
15
  import { PARALL_CLIPS_SKILL } from './parall-clips.js';
16
+ import { PARALL_CLIP_AUTHORING_SKILL } from './parall-clip-authoring.js';
15
17
  export const SKILLS = [
16
18
  {
17
19
  name: 'parall-platform',
@@ -40,9 +42,14 @@ export const SKILLS = [
40
42
  },
41
43
  {
42
44
  name: 'parall-clips',
43
- description: 'Parall clip operations: list installed clips, invoke clip commands, inspect clip details. 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.',
45
+ 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.',
44
46
  content: PARALL_CLIPS_SKILL,
45
47
  },
48
+ {
49
+ name: 'parall-clip-authoring',
50
+ 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` — 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.',
51
+ content: PARALL_CLIP_AUTHORING_SKILL,
52
+ },
46
53
  ];
47
54
  /** Write plain skill markdown files to a target directory (CC/Codex). */
48
55
  export function writeSkillFiles(targetDir) {
@@ -0,0 +1,2 @@
1
+ export declare const PARALL_CLIP_AUTHORING_SKILL = "# Authoring a Parall Clip (v3)\n\nWrite a **registry (v3) clip**. This skill is for CREATING clips; to DISCOVER\nand CALL clips that are already installed, use the Parall Clips skill instead.\n\nTwo kinds of clip exist, and this document covers authoring both:\n\n- A **browser clip** \u2014 the main subject here \u2014 is a folder of named commands\n that run on an Edge (a member's desktop or an org-shared cloud profile) and\n drive a real browser session: one manifest (`manifest.json` or `site.json`,\n either name works) + one `.js` file per command + optional `_`-prefixed\n helpers. The Edge runs each command's JS in a sandbox with a browser handle\n bound to the target profile.\n- An **MCP clip** is a manifest-ONLY declaration pointing at a remote MCP tool\n server \u2014 no `.js` files; its tools come live from that server's own\n `tools/list`, never from the manifest. See \"MCP clips\" below.\n\n## Project layout\n\n```\nmy-clip/\n\u251C\u2500\u2500 manifest.json # name, description, version, command params\n\u251C\u2500\u2500 _helpers.js # OPTIONAL \u2014 any _-prefixed file is auto-injected into every command\n\u251C\u2500\u2500 search.js # one command = one file; filename (minus .js) IS the command name\n\u2514\u2500\u2500 profile.js # another command\n```\n\n## manifest.json\n\n```json\n{\n \"name\": \"twitter\",\n \"description\": \"Twitter / X\",\n \"version\": \"1.0.0\",\n \"commands\": {\n \"search\": {\n \"description\": \"Search tweets\",\n \"params\": {\n \"query\": { \"type\": \"string\", \"required\": true },\n \"count\": { \"type\": \"number\", \"required\": false }\n }\n },\n \"profile\": {\n \"description\": \"Fetch a user profile\",\n \"params\": { \"handle\": { \"type\": \"string\", \"required\": true } }\n }\n }\n}\n```\n\n- `commands` keys MUST match the `.js` filenames (`search` \u2194 `search.js`).\n- `params` is the input contract the caller sees in `clip info`; validate them in code too.\n- **No top-level `\"type\"` needed for a browser clip** \u2014 omitting it means\n browser. The only accepted values are `\"browser\"` and `\"mcp\"` (for the\n latter, see \"MCP clips\" below). **`\"type\": \"clip\"` is the legacy Pinix v2\n package value and is refused at publish** \u2014 don't copy it in from an older\n clip.\n\n## A command file\n\n```js\n// search.js \u2014 a command is a single async function of (args).\n// The code does NOT know or pick the profile; the Edge binds it per invocation.\n//\n// SHAPE, not a runnable Twitter client: the \"...\" parts (the GraphQL path,\n// parseTweets' body) are what you fill in per target site. Deliberately not\n// pinned to a real X endpoint \u2014 a site's internal API paths rotate, and a\n// stale one baked into this skill would teach a URL that 404s.\nmodule.exports = async function (args) {\n if (!args.query) return { error: \"Missing argument: query\" };\n\n const tab = await browser.open(\"https://x.com\");\n // Everything after open() goes in try/finally: an early return or a thrown\n // fetch would otherwise leak the tab, and the Edge is long-lived.\n try {\n const ct0 = await tab.cookie(\"ct0\");\n if (!ct0) return { error: \"Not logged in\" };\n\n const data = await tab.fetch(\"/i/api/graphql/.../SearchTimeline?...\", {\n headers: twitterHeaders(ct0), // from _helpers.js, auto-injected\n });\n return { query: args.query, tweets: parseTweets(data) };\n } finally {\n await tab.close();\n }\n};\n```\n\nReturn a plain JSON-serializable object. A thrown error surfaces to the caller as\n`SCRIPT_ERROR`; a returned `{ error: \"...\" }` is your own typed failure \u2014 prefer it\nfor expected cases (not logged in, missing arg).\n\n## Helpers (`_`-prefixed)\n\nAny file whose name starts with `_` is NOT a command. Its top-level functions are\ninjected into every command's scope \u2014 no import/require needed:\n\n```js\n// _helpers.js\nfunction twitterHeaders(ct0) {\n return { \"X-Csrf-Token\": ct0, \"X-Twitter-Auth-Type\": \"OAuth2Session\" };\n}\nfunction parseTweets(data) { /* ... */ }\n```\n\n## Runtime API (globals available in every command)\n\n- `browser.open(url)` \u2192 tab handle \u00B7 `browser.tabs()` \u2192 open tabs\n- `tab.cookie(name)` \u00B7 `tab.fetch(url, opts)` (in-browser fetch, carries the session)\n- `tab.eval(expr)` (escape hatch) \u00B7 `tab.click(sel)` \u00B7 `tab.fill(sel, text)` \u00B7 `tab.navigate(url)`\n- `tab.waitForSelector(sel)` \u00B7 `tab.getTitle()` \u00B7 `tab.getURL()` \u00B7 `tab.screenshot()` \u00B7 `tab.close()`\n- `fetch` \u2014 runtime-side HTTP, does NOT go through the browser (no session)\n- `console` \u2014 logs \u00B7 `args` \u2014 the invocation input\n\n**Prefer `tab.fetch` over `tab.eval`**: fetch reuses the logged-in session and\nreturns structured data; eval is the last resort. Always `tab.close()` what you\nopen, and do it in a `finally` \u2014 an early return or a thrown fetch is exactly\nwhen the tab leaks.\n\n## Develop \u2192 publish \u2192 iterate\n\nUse the platform `parall clip` subcommands \u2014 they reuse the credentials you\nalready have (`PRLL_API_KEY` / `PRLL_ORG_ID`), so there is nothing to install\nor configure.\n\n> A separate **standalone `parall-clip`** binary also exists (the Edge-side\n> authoring tool). It takes the SAME operations but a DIFFERENT argument shape \u2014\n> `parall-clip exec <clip> <cmd> --query \"AI\" --count 10` passes one flag per\n> param, while `parall clip exec` takes a single JSON blob. Do not mix the two\n> forms; everything below is the platform CLI.\n\n1. **Publish** the clip directory to the org registry. Publishing is not a\n release step here \u2014 it is the edit loop's SAVE button, because exec only\n ever sees published files:\n\n ```sh\n parall clip publish ./my-clip/\n ```\n\n It packages the directory (the manifest plus the directory's top-level\n `.js` files; an MCP clip is manifest-only) and POSTs it for you (5 MB cap).\n `name` is the org-wide upsert key \u2014 manifest fields win, else the directory\n name / `0.0.1` / `private` fill the gaps. Re-publishing an existing name is\n **author-only** and REPLACES the file set. Publishing into YOUR org makes it\n usable there immediately (same-org self-reference, no review);\n `\"visibility\": \"public\"` additionally submits the version for platform\n review before it can spread cross-org.\n\n Programmatic equivalent (what `publish` calls under the hood \u2014 use only if\n you can't run the CLI). Send it verbatim-shaped: `visibility` is exactly\n one of `\"private\"` / `\"public\"`, and `files` maps each filename to its\n source as a string:\n\n ```\n POST /api/v1/orgs/{orgId}/clip-registry/publish\n {\n \"name\": \"twitter\",\n \"description\": \"Twitter / X\",\n \"version\": \"1.0.0\",\n \"visibility\": \"private\",\n \"manifest\": {\n \"name\": \"twitter\",\n \"version\": \"1.0.0\",\n \"commands\": { \"search\": { \"description\": \"Search tweets\" } }\n },\n \"files\": { \"search.js\": \"module.exports = async function (args) { return {}; };\" }\n }\n ```\n\n2. **Exec** a command against a real target. Args are ONE argument \u2014 a JSON\n string (or plain text for a single-value command), not per-param flags:\n\n ```sh\n parall clip exec <clip> <command> '{\"query\":\"AI\",\"count\":10}' --connection <ccn_id|alias>\n # or route to a desktop (BYOC) device you own: --edge <edge-id>\n # --connection and --edge are mutually exclusive; --timeout <ms> defaults to 30000\n ```\n\n A **cloud (hosted) profile is reachable ONLY via `--connection`** \u2014 the\n binding its maintainer created IS the authorization. With neither flag the\n server resolves only your own online desktop device, never a cloud profile.\n Discover the bindings with `parall clip connections <clip>`.\n\n3. **Iterate**: edit locally \u2192 `parall clip publish` again \u2192 re-exec. Exec\n resolves the file set from the REGISTRY, server-side \u2014 your own org always\n runs the live working copy, i.e. the latest publish. It NEVER reads your\n local directory: an edit you did not re-publish silently runs the previous\n version.\n\n## Install model & self-development (v3)\n\n- Installing a clip is a **reference**, not a copy \u2014 the JS lives once in the Market DB.\n- **Your own org** always executes its **live working copy** (latest published files),\n so re-publishing is your edit loop.\n- **Other orgs** installing your `public` clip execute only the **approved snapshot**\n (`approved_version_id`); unreviewed public edits are invisible/unexecutable cross-org.\n- To customize someone else's public clip: install \u2192 **fetch its effective\n file set** \u2192 modify \u2192 **publish into your OWN org** (a derived private\n entry). You cannot edit a published clip in place. The CLI has no files\n subcommand (`clip info` returns only the manifest) \u2014 read the source via\n the API:\n\n ```\n GET /api/v1/orgs/{orgId}/clip-registry/{clipId}/files\n ```\n\n It returns exactly what you may read and execute: your own clip \u2192 the live\n working copy; an installed public clip \u2192 the approved snapshot.\n\n## MCP clips (manifest-only)\n\nAn MCP clip declares a remote MCP tool server. There is nothing to code: no\n`.js` files (the no-scripts refusal at publish applies to browser clips only),\nand the folder is just a manifest:\n\n```json\n{\n \"name\": \"linear\",\n \"description\": \"Linear (MCP)\",\n \"version\": \"1.0.0\",\n \"type\": \"mcp\",\n \"mcp\": { \"server_url\": \"https://mcp.linear.app/mcp\", \"auth\": \"oauth\" }\n}\n```\n\n- The `mcp` block takes ONLY `server_url` and `auth` (`\"none\" | \"bearer\" |\n \"api_key\" | \"oauth\"`). Any other key is refused at publish \u2014 a credential\n belongs to the installing org's own configuration, NEVER to the clip\n definition.\n- `server_url` must be an absolute **https** URL with no embedded credentials,\n query, or fragment. It is review material, frozen with the approved version.\n- Do NOT put the server in the top-level `server` / `auth` manifest keys \u2014\n those are legacy Edge-manifest fields nothing reads. Only the `mcp` block\n declares the server.\n- Both fields are optional, but what you declare is LOCKED: the installing\n org's config must match it, and changing the URL or auth mode means\n republishing.\n- Entering the credential / completing OAuth is a HUMAN step in the Clip\n Console (the config-write endpoints are session-only \u2014 an API key cannot\n call them). Once configured, discover the live tool schemas with\n `parall clip tools <clip>` and exec like any other clip.\n- Publish is the same command: `parall clip publish ./my-clip/`.\n\n## Cloud (hosted) vs desktop (BYOC) Edge\n\nThe same command JS runs on either. Hosted profiles are org-shared cloud browsers\nreachable ONLY via an explicit `--connection`; cloud state lives in S3 and is\nhydrated per pod. Your code never touches this \u2014 it just gets a `browser`/`tab`\nbound to whatever profile the connection selected.\n\n## Constraints\n\n- Browser clips: one command = one file; keep a command's work self-contained\n (open what you need, close it, return). The Edge is stateless about your code\n between calls.\n- Never embed credentials in the clip source \u2014 rely on the profile's logged-in\n session (`tab.cookie` / `tab.fetch`). Published source is visible to installers.\n- Exec has a timeout (default 30s, caller-set up to 120s). Long scrapes should page,\n not block.\n";
2
+ //# sourceMappingURL=parall-clip-authoring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parall-clip-authoring.d.ts","sourceRoot":"","sources":["../../src/skills/parall-clip-authoring.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,2BAA2B,06WAmQvC,CAAC"}
@@ -0,0 +1,260 @@
1
+ export const PARALL_CLIP_AUTHORING_SKILL = `# Authoring a Parall Clip (v3)
2
+
3
+ Write a **registry (v3) clip**. This skill is for CREATING clips; to DISCOVER
4
+ and CALL clips that are already installed, use the Parall Clips skill instead.
5
+
6
+ Two kinds of clip exist, and this document covers authoring both:
7
+
8
+ - A **browser clip** — the main subject here — is a folder of named commands
9
+ that run on an Edge (a member's desktop or an org-shared cloud profile) and
10
+ drive a real browser session: one manifest (\`manifest.json\` or \`site.json\`,
11
+ either name works) + one \`.js\` file per command + optional \`_\`-prefixed
12
+ helpers. The Edge runs each command's JS in a sandbox with a browser handle
13
+ bound to the target profile.
14
+ - An **MCP clip** is a manifest-ONLY declaration pointing at a remote MCP tool
15
+ server — no \`.js\` files; its tools come live from that server's own
16
+ \`tools/list\`, never from the manifest. See "MCP clips" below.
17
+
18
+ ## Project layout
19
+
20
+ \`\`\`
21
+ my-clip/
22
+ ├── manifest.json # name, description, version, command params
23
+ ├── _helpers.js # OPTIONAL — any _-prefixed file is auto-injected into every command
24
+ ├── search.js # one command = one file; filename (minus .js) IS the command name
25
+ └── profile.js # another command
26
+ \`\`\`
27
+
28
+ ## manifest.json
29
+
30
+ \`\`\`json
31
+ {
32
+ "name": "twitter",
33
+ "description": "Twitter / X",
34
+ "version": "1.0.0",
35
+ "commands": {
36
+ "search": {
37
+ "description": "Search tweets",
38
+ "params": {
39
+ "query": { "type": "string", "required": true },
40
+ "count": { "type": "number", "required": false }
41
+ }
42
+ },
43
+ "profile": {
44
+ "description": "Fetch a user profile",
45
+ "params": { "handle": { "type": "string", "required": true } }
46
+ }
47
+ }
48
+ }
49
+ \`\`\`
50
+
51
+ - \`commands\` keys MUST match the \`.js\` filenames (\`search\` ↔ \`search.js\`).
52
+ - \`params\` is the input contract the caller sees in \`clip info\`; validate them in code too.
53
+ - **No top-level \`"type"\` needed for a browser clip** — omitting it means
54
+ browser. The only accepted values are \`"browser"\` and \`"mcp"\` (for the
55
+ latter, see "MCP clips" below). **\`"type": "clip"\` is the legacy Pinix v2
56
+ package value and is refused at publish** — don't copy it in from an older
57
+ clip.
58
+
59
+ ## A command file
60
+
61
+ \`\`\`js
62
+ // search.js — a command is a single async function of (args).
63
+ // The code does NOT know or pick the profile; the Edge binds it per invocation.
64
+ //
65
+ // SHAPE, not a runnable Twitter client: the "..." parts (the GraphQL path,
66
+ // parseTweets' body) are what you fill in per target site. Deliberately not
67
+ // pinned to a real X endpoint — a site's internal API paths rotate, and a
68
+ // stale one baked into this skill would teach a URL that 404s.
69
+ module.exports = async function (args) {
70
+ if (!args.query) return { error: "Missing argument: query" };
71
+
72
+ const tab = await browser.open("https://x.com");
73
+ // Everything after open() goes in try/finally: an early return or a thrown
74
+ // fetch would otherwise leak the tab, and the Edge is long-lived.
75
+ try {
76
+ const ct0 = await tab.cookie("ct0");
77
+ if (!ct0) return { error: "Not logged in" };
78
+
79
+ const data = await tab.fetch("/i/api/graphql/.../SearchTimeline?...", {
80
+ headers: twitterHeaders(ct0), // from _helpers.js, auto-injected
81
+ });
82
+ return { query: args.query, tweets: parseTweets(data) };
83
+ } finally {
84
+ await tab.close();
85
+ }
86
+ };
87
+ \`\`\`
88
+
89
+ Return a plain JSON-serializable object. A thrown error surfaces to the caller as
90
+ \`SCRIPT_ERROR\`; a returned \`{ error: "..." }\` is your own typed failure — prefer it
91
+ for expected cases (not logged in, missing arg).
92
+
93
+ ## Helpers (\`_\`-prefixed)
94
+
95
+ Any file whose name starts with \`_\` is NOT a command. Its top-level functions are
96
+ injected into every command's scope — no import/require needed:
97
+
98
+ \`\`\`js
99
+ // _helpers.js
100
+ function twitterHeaders(ct0) {
101
+ return { "X-Csrf-Token": ct0, "X-Twitter-Auth-Type": "OAuth2Session" };
102
+ }
103
+ function parseTweets(data) { /* ... */ }
104
+ \`\`\`
105
+
106
+ ## Runtime API (globals available in every command)
107
+
108
+ - \`browser.open(url)\` → tab handle · \`browser.tabs()\` → open tabs
109
+ - \`tab.cookie(name)\` · \`tab.fetch(url, opts)\` (in-browser fetch, carries the session)
110
+ - \`tab.eval(expr)\` (escape hatch) · \`tab.click(sel)\` · \`tab.fill(sel, text)\` · \`tab.navigate(url)\`
111
+ - \`tab.waitForSelector(sel)\` · \`tab.getTitle()\` · \`tab.getURL()\` · \`tab.screenshot()\` · \`tab.close()\`
112
+ - \`fetch\` — runtime-side HTTP, does NOT go through the browser (no session)
113
+ - \`console\` — logs · \`args\` — the invocation input
114
+
115
+ **Prefer \`tab.fetch\` over \`tab.eval\`**: fetch reuses the logged-in session and
116
+ returns structured data; eval is the last resort. Always \`tab.close()\` what you
117
+ open, and do it in a \`finally\` — an early return or a thrown fetch is exactly
118
+ when the tab leaks.
119
+
120
+ ## Develop → publish → iterate
121
+
122
+ Use the platform \`parall clip\` subcommands — they reuse the credentials you
123
+ already have (\`PRLL_API_KEY\` / \`PRLL_ORG_ID\`), so there is nothing to install
124
+ or configure.
125
+
126
+ > A separate **standalone \`parall-clip\`** binary also exists (the Edge-side
127
+ > authoring tool). It takes the SAME operations but a DIFFERENT argument shape —
128
+ > \`parall-clip exec <clip> <cmd> --query "AI" --count 10\` passes one flag per
129
+ > param, while \`parall clip exec\` takes a single JSON blob. Do not mix the two
130
+ > forms; everything below is the platform CLI.
131
+
132
+ 1. **Publish** the clip directory to the org registry. Publishing is not a
133
+ release step here — it is the edit loop's SAVE button, because exec only
134
+ ever sees published files:
135
+
136
+ \`\`\`sh
137
+ parall clip publish ./my-clip/
138
+ \`\`\`
139
+
140
+ It packages the directory (the manifest plus the directory's top-level
141
+ \`.js\` files; an MCP clip is manifest-only) and POSTs it for you (5 MB cap).
142
+ \`name\` is the org-wide upsert key — manifest fields win, else the directory
143
+ name / \`0.0.1\` / \`private\` fill the gaps. Re-publishing an existing name is
144
+ **author-only** and REPLACES the file set. Publishing into YOUR org makes it
145
+ usable there immediately (same-org self-reference, no review);
146
+ \`"visibility": "public"\` additionally submits the version for platform
147
+ review before it can spread cross-org.
148
+
149
+ Programmatic equivalent (what \`publish\` calls under the hood — use only if
150
+ you can't run the CLI). Send it verbatim-shaped: \`visibility\` is exactly
151
+ one of \`"private"\` / \`"public"\`, and \`files\` maps each filename to its
152
+ source as a string:
153
+
154
+ \`\`\`
155
+ POST /api/v1/orgs/{orgId}/clip-registry/publish
156
+ {
157
+ "name": "twitter",
158
+ "description": "Twitter / X",
159
+ "version": "1.0.0",
160
+ "visibility": "private",
161
+ "manifest": {
162
+ "name": "twitter",
163
+ "version": "1.0.0",
164
+ "commands": { "search": { "description": "Search tweets" } }
165
+ },
166
+ "files": { "search.js": "module.exports = async function (args) { return {}; };" }
167
+ }
168
+ \`\`\`
169
+
170
+ 2. **Exec** a command against a real target. Args are ONE argument — a JSON
171
+ string (or plain text for a single-value command), not per-param flags:
172
+
173
+ \`\`\`sh
174
+ parall clip exec <clip> <command> '{"query":"AI","count":10}' --connection <ccn_id|alias>
175
+ # or route to a desktop (BYOC) device you own: --edge <edge-id>
176
+ # --connection and --edge are mutually exclusive; --timeout <ms> defaults to 30000
177
+ \`\`\`
178
+
179
+ A **cloud (hosted) profile is reachable ONLY via \`--connection\`** — the
180
+ binding its maintainer created IS the authorization. With neither flag the
181
+ server resolves only your own online desktop device, never a cloud profile.
182
+ Discover the bindings with \`parall clip connections <clip>\`.
183
+
184
+ 3. **Iterate**: edit locally → \`parall clip publish\` again → re-exec. Exec
185
+ resolves the file set from the REGISTRY, server-side — your own org always
186
+ runs the live working copy, i.e. the latest publish. It NEVER reads your
187
+ local directory: an edit you did not re-publish silently runs the previous
188
+ version.
189
+
190
+ ## Install model & self-development (v3)
191
+
192
+ - Installing a clip is a **reference**, not a copy — the JS lives once in the Market DB.
193
+ - **Your own org** always executes its **live working copy** (latest published files),
194
+ so re-publishing is your edit loop.
195
+ - **Other orgs** installing your \`public\` clip execute only the **approved snapshot**
196
+ (\`approved_version_id\`); unreviewed public edits are invisible/unexecutable cross-org.
197
+ - To customize someone else's public clip: install → **fetch its effective
198
+ file set** → modify → **publish into your OWN org** (a derived private
199
+ entry). You cannot edit a published clip in place. The CLI has no files
200
+ subcommand (\`clip info\` returns only the manifest) — read the source via
201
+ the API:
202
+
203
+ \`\`\`
204
+ GET /api/v1/orgs/{orgId}/clip-registry/{clipId}/files
205
+ \`\`\`
206
+
207
+ It returns exactly what you may read and execute: your own clip → the live
208
+ working copy; an installed public clip → the approved snapshot.
209
+
210
+ ## MCP clips (manifest-only)
211
+
212
+ An MCP clip declares a remote MCP tool server. There is nothing to code: no
213
+ \`.js\` files (the no-scripts refusal at publish applies to browser clips only),
214
+ and the folder is just a manifest:
215
+
216
+ \`\`\`json
217
+ {
218
+ "name": "linear",
219
+ "description": "Linear (MCP)",
220
+ "version": "1.0.0",
221
+ "type": "mcp",
222
+ "mcp": { "server_url": "https://mcp.linear.app/mcp", "auth": "oauth" }
223
+ }
224
+ \`\`\`
225
+
226
+ - The \`mcp\` block takes ONLY \`server_url\` and \`auth\` (\`"none" | "bearer" |
227
+ "api_key" | "oauth"\`). Any other key is refused at publish — a credential
228
+ belongs to the installing org's own configuration, NEVER to the clip
229
+ definition.
230
+ - \`server_url\` must be an absolute **https** URL with no embedded credentials,
231
+ query, or fragment. It is review material, frozen with the approved version.
232
+ - Do NOT put the server in the top-level \`server\` / \`auth\` manifest keys —
233
+ those are legacy Edge-manifest fields nothing reads. Only the \`mcp\` block
234
+ declares the server.
235
+ - Both fields are optional, but what you declare is LOCKED: the installing
236
+ org's config must match it, and changing the URL or auth mode means
237
+ republishing.
238
+ - Entering the credential / completing OAuth is a HUMAN step in the Clip
239
+ Console (the config-write endpoints are session-only — an API key cannot
240
+ call them). Once configured, discover the live tool schemas with
241
+ \`parall clip tools <clip>\` and exec like any other clip.
242
+ - Publish is the same command: \`parall clip publish ./my-clip/\`.
243
+
244
+ ## Cloud (hosted) vs desktop (BYOC) Edge
245
+
246
+ The same command JS runs on either. Hosted profiles are org-shared cloud browsers
247
+ reachable ONLY via an explicit \`--connection\`; cloud state lives in S3 and is
248
+ hydrated per pod. Your code never touches this — it just gets a \`browser\`/\`tab\`
249
+ bound to whatever profile the connection selected.
250
+
251
+ ## Constraints
252
+
253
+ - Browser clips: one command = one file; keep a command's work self-contained
254
+ (open what you need, close it, return). The Edge is stateless about your code
255
+ between calls.
256
+ - Never embed credentials in the clip source — rely on the profile's logged-in
257
+ session (\`tab.cookie\` / \`tab.fetch\`). Published source is visible to installers.
258
+ - Exec has a timeout (default 30s, caller-set up to 120s). Long scrapes should page,
259
+ not block.
260
+ `;