@parall/agent-core 1.35.0 → 1.36.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/event-format.d.ts.map +1 -1
- package/dist/event-format.js +25 -0
- package/dist/gateway-base.d.ts +2 -0
- package/dist/gateway-base.d.ts.map +1 -1
- package/dist/gateway-base.js +94 -6
- package/dist/skills/index.d.ts +1 -0
- package/dist/skills/index.d.ts.map +1 -1
- package/dist/skills/index.js +7 -0
- package/dist/skills/parall-external-triggers.d.ts +2 -0
- package/dist/skills/parall-external-triggers.d.ts.map +1 -0
- package/dist/skills/parall-external-triggers.js +88 -0
- package/dist/skills/parall-platform.d.ts +1 -1
- package/dist/skills/parall-platform.d.ts.map +1 -1
- package/dist/skills/parall-platform.js +56 -0
- package/dist/skills/parall-tasks.d.ts +1 -1
- package/dist/skills/parall-tasks.d.ts.map +1 -1
- package/dist/skills/parall-tasks.js +32 -3
- package/dist/skills/parall-wiki.d.ts +1 -1
- package/dist/skills/parall-wiki.d.ts.map +1 -1
- package/dist/skills/parall-wiki.js +49 -2
- package/dist/types.d.ts +8 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/event-format.ts +24 -0
- package/src/gateway-base.ts +97 -6
- package/src/skills/index.ts +8 -0
- package/src/skills/parall-external-triggers.ts +88 -0
- package/src/skills/parall-platform.ts +56 -0
- package/src/skills/parall-tasks.ts +32 -3
- package/src/skills/parall-wiki.ts +49 -2
- package/src/types.ts +15 -2
|
@@ -16,8 +16,11 @@ Key facts the commands won't tell you:
|
|
|
16
16
|
the absolute workspace path (\`synced → /path/to/<slug>\` / \`Mount: ...\`).
|
|
17
17
|
Always address wiki files by that absolute path — your shell cwd is usually
|
|
18
18
|
NOT inside the workspace.
|
|
19
|
-
- **Text
|
|
20
|
-
|
|
19
|
+
- **Text and binary are two paths.** The workspace + changeset flow is for
|
|
20
|
+
text (markdown, code, config). Binary assets (images, PDFs, archives) are
|
|
21
|
+
diff-less — they don't go in the workspace; use \`parall wiki file\` (see
|
|
22
|
+
**Binary files** below). Dropping a binary into the workspace just gets it
|
|
23
|
+
rejected on propose.
|
|
21
24
|
- **\`cat\`, \`search\`, \`query\`, \`outline\`, and \`section\` read your local
|
|
22
25
|
workspace copy when it exists** — including your own unproposed edits. Add
|
|
23
26
|
\`--remote\` to \`cat\` to read the server version instead.
|
|
@@ -98,6 +101,50 @@ Re-propose REPLACES the changeset's previous contents with your current
|
|
|
98
101
|
workspace diff — to withdraw a file from the proposal, revert it locally
|
|
99
102
|
(restore the synced content) and re-propose; it drops out of the changeset.
|
|
100
103
|
|
|
104
|
+
## Binary files
|
|
105
|
+
|
|
106
|
+
Images, PDFs, archives — anything that can't be diffed — bypass the workspace
|
|
107
|
+
and changeset-text flow entirely. They never belong in the synced workspace
|
|
108
|
+
(propose rejects them); use \`parall wiki file\` instead. \`cat\` is text-only —
|
|
109
|
+
to read a binary's real bytes use \`file get\` (a plain \`sync\` only leaves a
|
|
110
|
+
few-line Git-LFS pointer on disk, since the runtime has no git-lfs).
|
|
111
|
+
|
|
112
|
+
\`\`\`bash
|
|
113
|
+
# Maintainer: direct-commit a binary to the default branch (no review)
|
|
114
|
+
parall wiki file upload ./diagram.png docs/assets/diagram.png
|
|
115
|
+
|
|
116
|
+
# Read a binary's real bytes (LFS pointers resolved server-side) to a file.
|
|
117
|
+
# Always use --output for binaries — without it the bytes stream to stdout and
|
|
118
|
+
# would flood your context.
|
|
119
|
+
parall wiki file get docs/assets/diagram.png --output ./diagram.png
|
|
120
|
+
parall wiki file get docs/assets/diagram.png --ref <commit-or-branch> --output ./diagram.png # a specific revision
|
|
121
|
+
|
|
122
|
+
# Remove a binary from the default branch (git history still has it)
|
|
123
|
+
parall wiki file delete docs/assets/diagram.png
|
|
124
|
+
\`\`\`
|
|
125
|
+
|
|
126
|
+
\`upload\` needs **maintain**; it routes by size automatically (≤1 MiB inline,
|
|
127
|
+
larger → LFS). A text file sent to \`upload\` is rejected — that's the changeset
|
|
128
|
+
flow's job.
|
|
129
|
+
|
|
130
|
+
### Reader: propose markdown that embeds an image
|
|
131
|
+
|
|
132
|
+
Without maintain you can still propose a doc with images — upload the binary
|
|
133
|
+
into your **changeset's** branch (read + author), not the default branch:
|
|
134
|
+
|
|
135
|
+
\`\`\`bash
|
|
136
|
+
parall wiki sync
|
|
137
|
+
# edit a .md in the workspace to add 
|
|
138
|
+
parall wiki changeset create <wiki> --title "Add foo diagram" # creates the changeset (note its id)
|
|
139
|
+
parall wiki file upload ./foo.png assets/foo.png <wiki> --changeset <changesetId>
|
|
140
|
+
# leave it for a maintainer to merge — both the markdown and the image squash in together
|
|
141
|
+
\`\`\`
|
|
142
|
+
|
|
143
|
+
Do the markdown \`changeset create\` first so the changeset exists, then attach
|
|
144
|
+
the image to it. Don't re-propose (\`--update\`) after attaching a binary —
|
|
145
|
+
re-propose replays only the text workspace and the server rejects dropping the
|
|
146
|
+
attached binary (422 \`REPLACE_HAS_BINARY\`).
|
|
147
|
+
|
|
101
148
|
## Discovery & history
|
|
102
149
|
|
|
103
150
|
\`\`\`bash
|
package/dist/types.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export type DispatchState = {
|
|
|
26
26
|
};
|
|
27
27
|
/** Normalized inbound event from Parall. */
|
|
28
28
|
export type ParallEvent = {
|
|
29
|
-
type: 'message' | 'task' | 'task_comment' | 'wiki_comment' | 'schedule' | 'approval';
|
|
29
|
+
type: 'message' | 'task' | 'task_comment' | 'wiki_comment' | 'schedule' | 'external_trigger' | 'approval';
|
|
30
30
|
targetId: string;
|
|
31
31
|
targetName?: string;
|
|
32
32
|
targetType?: string;
|
|
@@ -54,10 +54,16 @@ export type ParallEvent = {
|
|
|
54
54
|
scheduledFireAt?: string;
|
|
55
55
|
/** Fire-time attached_to_uri snapshot, used for schedule events. */
|
|
56
56
|
attachedUri?: string;
|
|
57
|
+
/** External trigger metadata, used for external_trigger events. */
|
|
58
|
+
externalConnectionId?: string;
|
|
59
|
+
externalConnectionSourceType?: string;
|
|
60
|
+
externalConnectionDisplayName?: string;
|
|
61
|
+
externalIngressEventId?: string;
|
|
62
|
+
externalIngressEventType?: string;
|
|
57
63
|
/** Original event timestamp (e.g., message.created_at). When present,
|
|
58
64
|
* input steps use this instead of server insertion time for ordering. */
|
|
59
65
|
sentAt?: string;
|
|
60
|
-
ackSourceType?: 'message' | 'task_activity' | 'comment' | 'schedule_run';
|
|
66
|
+
ackSourceType?: 'message' | 'task_activity' | 'comment' | 'schedule_run' | 'external_trigger_run';
|
|
61
67
|
ackSourceId?: string;
|
|
62
68
|
/** Unread message count in the target chat since agent's last interaction. */
|
|
63
69
|
unreadCount?: number;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,MAAM,MAAM,UAAU,GAAG;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACjE,mFAAmF;IACnF,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,sFAAsF;IACtF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qFAAqF;IACrF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,2DAA2D;AAC3D,MAAM,MAAM,aAAa,GAAG;IAC1B,eAAe,EAAE,OAAO,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,kBAAkB,EAAE,UAAU,EAAE,CAAC;IACjC,UAAU,EAAE,WAAW,EAAE,CAAC;IAC1B,oFAAoF;IACpF,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC,CAAC;AAEF,4CAA4C;AAC5C,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,MAAM,MAAM,UAAU,GAAG;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACjE,mFAAmF;IACnF,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,sFAAsF;IACtF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qFAAqF;IACrF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,2DAA2D;AAC3D,MAAM,MAAM,aAAa,GAAG;IAC1B,eAAe,EAAE,OAAO,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,kBAAkB,EAAE,UAAU,EAAE,CAAC;IACjC,UAAU,EAAE,WAAW,EAAE,CAAC;IAC1B,oFAAoF;IACpF,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC,CAAC;AAEF,4CAA4C;AAC5C,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EACA,SAAS,GACT,MAAM,GACN,cAAc,GACd,cAAc,GACd,UAAU,GACV,kBAAkB,GAClB,UAAU,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,KAAK,CAAC;QAClB,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;IACH,8DAA8D;IAC9D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mEAAmE;IACnE,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,4BAA4B,CAAC,EAAE,MAAM,CAAC;IACtC,6BAA6B,CAAC,EAAE,MAAM,CAAC;IACvC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC;8EAC0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,SAAS,GAAG,eAAe,GAAG,SAAS,GAAG,cAAc,GAAG,sBAAsB,CAAC;IAClG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,sEAAsE;IACtE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parall/agent-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.36.1",
|
|
4
4
|
"description": "Shared agent runtime orchestration helpers for Parall",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"@opentelemetry/sdk-logs": "^0.57.0",
|
|
36
36
|
"@opentelemetry/sdk-metrics": "^1.30.0",
|
|
37
37
|
"@opentelemetry/sdk-trace-node": "^1.30.0",
|
|
38
|
-
"@parall/sdk": "1.
|
|
38
|
+
"@parall/sdk": "1.36.1"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/node": "^22.0.0",
|
package/src/event-format.ts
CHANGED
|
@@ -89,6 +89,26 @@ export function buildEventBody(event: ParallEvent): string {
|
|
|
89
89
|
if (event.scheduledFireAt) lines.push(`[Scheduled at: ${sanitizeMeta(event.scheduledFireAt)}]`);
|
|
90
90
|
if (event.attachedUri) lines.push(`[Attached: ${sanitizeMeta(event.attachedUri)}]`);
|
|
91
91
|
lines.push('', event.body);
|
|
92
|
+
} else if (event.type === 'external_trigger') {
|
|
93
|
+
lines.push(`[Event: external.trigger]`);
|
|
94
|
+
lines.push(`[Trigger: prll://${event.targetId}]`);
|
|
95
|
+
lines.push(`[Run: prll://${event.messageId}]`);
|
|
96
|
+
if (event.externalConnectionId) {
|
|
97
|
+
const label = event.externalConnectionDisplayName
|
|
98
|
+
? `${sanitizeMeta(event.externalConnectionDisplayName)} (prll://${event.externalConnectionId})`
|
|
99
|
+
: `prll://${event.externalConnectionId}`;
|
|
100
|
+
lines.push(`[Connection: ${label}]`);
|
|
101
|
+
}
|
|
102
|
+
if (event.externalIngressEventId)
|
|
103
|
+
lines.push(`[Ingress: prll://${event.externalIngressEventId}]`);
|
|
104
|
+
if (event.attachedUri) lines.push(`[Attached: ${sanitizeMeta(event.attachedUri)}]`);
|
|
105
|
+
if (event.externalConnectionSourceType) {
|
|
106
|
+
lines.push(`[Source: ${sanitizeMeta(event.externalConnectionSourceType)}]`);
|
|
107
|
+
}
|
|
108
|
+
if (event.externalIngressEventType) {
|
|
109
|
+
lines.push(`[External event: ${sanitizeMeta(event.externalIngressEventType)}]`);
|
|
110
|
+
}
|
|
111
|
+
lines.push('', event.body);
|
|
92
112
|
} else {
|
|
93
113
|
lines.push(`[Event: task.assigned]`);
|
|
94
114
|
const taskLabel = event.targetName
|
|
@@ -125,6 +145,10 @@ function buildSendMessageHint(event: ParallEvent): string {
|
|
|
125
145
|
return `\n<system-reminder>To communicate, use the CLI: \`parall messages send\` / \`parall dm\`. Your plain text output is not delivered.</system-reminder>`;
|
|
126
146
|
}
|
|
127
147
|
|
|
148
|
+
if (event.type === 'external_trigger' || event.targetId.startsWith('xtr_')) {
|
|
149
|
+
return `\n<system-reminder>This external trigger is incoming-only. Your plain text output is not sent back to the external provider. To communicate in Parall, use \`parall messages send\` / \`parall dm\`; provider-specific outbound actions require a separate capability.</system-reminder>`;
|
|
150
|
+
}
|
|
151
|
+
|
|
128
152
|
return '';
|
|
129
153
|
}
|
|
130
154
|
|
package/src/gateway-base.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
Comment,
|
|
13
13
|
DispatchDeliveryReason,
|
|
14
14
|
DispatchNewData,
|
|
15
|
+
ExternalTriggerRun,
|
|
15
16
|
HelloData,
|
|
16
17
|
MessageNewData,
|
|
17
18
|
ScheduleRun,
|
|
@@ -194,6 +195,9 @@ function resolveStepTarget(event: ParallEvent): { target_type: string; target_id
|
|
|
194
195
|
if (event.type === 'schedule' || event.targetId.startsWith('sch_')) {
|
|
195
196
|
return { target_type: 'schedule', target_id: event.targetId };
|
|
196
197
|
}
|
|
198
|
+
if (event.type === 'external_trigger' || event.targetId.startsWith('xtr_')) {
|
|
199
|
+
return { target_type: 'external_trigger', target_id: event.targetId };
|
|
200
|
+
}
|
|
197
201
|
if (event.type === 'wiki_comment') {
|
|
198
202
|
// target_id is the full wiki target_uri (scheme-stripped routing key). The
|
|
199
203
|
// server stores target_type freely and only publishes step WS events /
|
|
@@ -457,6 +461,18 @@ export class ParallAgentGateway {
|
|
|
457
461
|
`schedule fire dispatch failed for ${data.source_id}: ${String(err)}`,
|
|
458
462
|
);
|
|
459
463
|
}
|
|
464
|
+
} else if (data.event_type === 'external_trigger') {
|
|
465
|
+
if (!data.source_id) return;
|
|
466
|
+
try {
|
|
467
|
+
const dispatched = await this.fetchAndHandleExternalTriggerRun(data.source_id);
|
|
468
|
+
if (dispatched) {
|
|
469
|
+
this.opts.client.ackDispatchByID(this.opts.config.org_id, data.id).catch(() => {});
|
|
470
|
+
}
|
|
471
|
+
} catch (err) {
|
|
472
|
+
this.opts.log?.error(
|
|
473
|
+
`external trigger dispatch failed for ${data.source_id}: ${String(err)}`,
|
|
474
|
+
);
|
|
475
|
+
}
|
|
460
476
|
} else if (data.event_type === 'approval_decided') {
|
|
461
477
|
if (!data.source_id) return;
|
|
462
478
|
try {
|
|
@@ -570,9 +586,11 @@ export class ParallAgentGateway {
|
|
|
570
586
|
? 'wiki_comment'
|
|
571
587
|
: event.type === 'schedule'
|
|
572
588
|
? 'schedule_fire'
|
|
573
|
-
: event.type === '
|
|
574
|
-
? '
|
|
575
|
-
: '
|
|
589
|
+
: event.type === 'external_trigger'
|
|
590
|
+
? 'external_trigger'
|
|
591
|
+
: event.type === 'approval'
|
|
592
|
+
? 'approval_decided'
|
|
593
|
+
: 'mention',
|
|
576
594
|
trigger_ref:
|
|
577
595
|
event.type === 'task'
|
|
578
596
|
? { task_id: event.targetId }
|
|
@@ -582,9 +600,16 @@ export class ParallAgentGateway {
|
|
|
582
600
|
? { comment_id: event.messageId, target_uri: event.replyTargetUri }
|
|
583
601
|
: event.type === 'schedule'
|
|
584
602
|
? { schedule_id: event.targetId, run_id: event.messageId }
|
|
585
|
-
: event.type === '
|
|
586
|
-
? {
|
|
587
|
-
|
|
603
|
+
: event.type === 'external_trigger'
|
|
604
|
+
? {
|
|
605
|
+
trigger_id: event.targetId,
|
|
606
|
+
run_id: event.messageId,
|
|
607
|
+
connection_id: event.externalConnectionId,
|
|
608
|
+
ingress_event_id: event.externalIngressEventId,
|
|
609
|
+
}
|
|
610
|
+
: event.type === 'approval'
|
|
611
|
+
? { approval_id: event.messageId }
|
|
612
|
+
: { message_id: event.messageId },
|
|
588
613
|
sender_id: event.senderId,
|
|
589
614
|
sender_name: event.senderName,
|
|
590
615
|
summary: event.body.substring(0, 200),
|
|
@@ -1930,6 +1955,70 @@ export class ParallAgentGateway {
|
|
|
1930
1955
|
return dispatched;
|
|
1931
1956
|
}
|
|
1932
1957
|
|
|
1958
|
+
private async fetchAndHandleExternalTriggerRun(runId: string): Promise<boolean> {
|
|
1959
|
+
let run: ExternalTriggerRun | null = null;
|
|
1960
|
+
try {
|
|
1961
|
+
run = await this.opts.client.getExternalTriggerRun(this.opts.config.org_id, runId);
|
|
1962
|
+
} catch (err: unknown) {
|
|
1963
|
+
const status = (err as { status?: number })?.status;
|
|
1964
|
+
if (status === 404) {
|
|
1965
|
+
this.opts.log?.warn(
|
|
1966
|
+
`external trigger run ${runId} not accessible (404), acking stale dispatch`,
|
|
1967
|
+
);
|
|
1968
|
+
return true;
|
|
1969
|
+
}
|
|
1970
|
+
this.opts.log?.warn(
|
|
1971
|
+
`external trigger run fetch failed for ${runId}, leaving pending: ${String(err)}`,
|
|
1972
|
+
);
|
|
1973
|
+
return false;
|
|
1974
|
+
}
|
|
1975
|
+
if (!run) return true;
|
|
1976
|
+
return this.handleExternalTriggerRun(run);
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
private async handleExternalTriggerRun(run: ExternalTriggerRun): Promise<boolean> {
|
|
1980
|
+
if (this.shuttingDown) return false;
|
|
1981
|
+
const dedupeKey = `external_trigger_run:${run.id}`;
|
|
1982
|
+
if (this.dispatchedTasks.has(dedupeKey)) return false;
|
|
1983
|
+
this.dispatchedTasks.add(dedupeKey);
|
|
1984
|
+
this.opts.log?.info(`external trigger fired: ${run.id} (trigger ${run.trigger_id})`);
|
|
1985
|
+
const attachedUri =
|
|
1986
|
+
typeof run.trigger_snapshot?.attached_to_uri === 'string'
|
|
1987
|
+
? run.trigger_snapshot.attached_to_uri
|
|
1988
|
+
: undefined;
|
|
1989
|
+
|
|
1990
|
+
const event: ParallEvent = {
|
|
1991
|
+
type: 'external_trigger',
|
|
1992
|
+
targetId: run.trigger_id,
|
|
1993
|
+
targetName: run.trigger_name || undefined,
|
|
1994
|
+
targetType: 'external_trigger',
|
|
1995
|
+
senderId: 'system',
|
|
1996
|
+
senderName: 'external',
|
|
1997
|
+
messageId: run.id,
|
|
1998
|
+
body: run.agent_input_body ?? '',
|
|
1999
|
+
externalConnectionId: run.connection_id,
|
|
2000
|
+
externalConnectionSourceType: run.connection_source_type || undefined,
|
|
2001
|
+
externalConnectionDisplayName: run.connection_display_name || undefined,
|
|
2002
|
+
externalIngressEventId: run.ingress_event_id,
|
|
2003
|
+
externalIngressEventType: run.ingress_event_type || undefined,
|
|
2004
|
+
attachedUri,
|
|
2005
|
+
ackSourceType: 'external_trigger_run',
|
|
2006
|
+
ackSourceId: run.id,
|
|
2007
|
+
};
|
|
2008
|
+
|
|
2009
|
+
let dispatched: boolean;
|
|
2010
|
+
try {
|
|
2011
|
+
dispatched = await this.handleInboundEvent(event);
|
|
2012
|
+
} catch (err) {
|
|
2013
|
+
this.dispatchedTasks.delete(dedupeKey);
|
|
2014
|
+
throw err;
|
|
2015
|
+
}
|
|
2016
|
+
if (!dispatched) {
|
|
2017
|
+
this.dispatchedTasks.delete(dedupeKey);
|
|
2018
|
+
}
|
|
2019
|
+
return dispatched;
|
|
2020
|
+
}
|
|
2021
|
+
|
|
1933
2022
|
private async fetchAndHandleApprovalDecided(
|
|
1934
2023
|
approvalId: string,
|
|
1935
2024
|
actorId: string | null,
|
|
@@ -2081,6 +2170,8 @@ export class ParallAgentGateway {
|
|
|
2081
2170
|
);
|
|
2082
2171
|
} else if (item.event_type === 'schedule.fire' && item.source_id) {
|
|
2083
2172
|
dispatched = await this.fetchAndHandleScheduleFire(item.source_id, item.actor_id);
|
|
2173
|
+
} else if (item.event_type === 'external_trigger' && item.source_id) {
|
|
2174
|
+
dispatched = await this.fetchAndHandleExternalTriggerRun(item.source_id);
|
|
2084
2175
|
} else if (item.event_type === 'approval_decided' && item.source_id) {
|
|
2085
2176
|
dispatched = await this.fetchAndHandleApprovalDecided(
|
|
2086
2177
|
item.source_id,
|
package/src/skills/index.ts
CHANGED
|
@@ -5,12 +5,14 @@ export { PARALL_PLATFORM_SKILL } from './parall-platform.js';
|
|
|
5
5
|
export { PARALL_TASKS_SKILL } from './parall-tasks.js';
|
|
6
6
|
export { PARALL_WIKI_SKILL } from './parall-wiki.js';
|
|
7
7
|
export { PARALL_SCHEDULES_SKILL } from './parall-schedules.js';
|
|
8
|
+
export { PARALL_EXTERNAL_TRIGGERS_SKILL } from './parall-external-triggers.js';
|
|
8
9
|
export { PARALL_CLIPS_SKILL } from './parall-clips.js';
|
|
9
10
|
|
|
10
11
|
import { PARALL_PLATFORM_SKILL } from './parall-platform.js';
|
|
11
12
|
import { PARALL_TASKS_SKILL } from './parall-tasks.js';
|
|
12
13
|
import { PARALL_WIKI_SKILL } from './parall-wiki.js';
|
|
13
14
|
import { PARALL_SCHEDULES_SKILL } from './parall-schedules.js';
|
|
15
|
+
import { PARALL_EXTERNAL_TRIGGERS_SKILL } from './parall-external-triggers.js';
|
|
14
16
|
import { PARALL_CLIPS_SKILL } from './parall-clips.js';
|
|
15
17
|
|
|
16
18
|
export type SkillMeta = { name: string; description: string; content: string };
|
|
@@ -40,6 +42,12 @@ export const SKILLS: SkillMeta[] = [
|
|
|
40
42
|
'Parall schedule operations: create / pause / resume / cancel recurring or one-shot time triggers; respond to schedule fire events. Use when: user asks to set up a recurring reminder, schedule a delayed prompt, run cron-like work, or when the agent receives an `[Event: schedule.fired]` dispatch.',
|
|
41
43
|
content: PARALL_SCHEDULES_SKILL,
|
|
42
44
|
},
|
|
45
|
+
{
|
|
46
|
+
name: 'parall-external-triggers',
|
|
47
|
+
description:
|
|
48
|
+
'Parall External Trigger operations: create incoming connections, configure CEL/Liquid triggers, inspect incoming events and runs, and respond to `[Event: external.trigger]` dispatches. Use when: user asks to connect an external system to an agent, set up incoming callbacks/notifications, or when the agent receives an external trigger event.',
|
|
49
|
+
content: PARALL_EXTERNAL_TRIGGERS_SKILL,
|
|
50
|
+
},
|
|
43
51
|
{
|
|
44
52
|
name: 'parall-clips',
|
|
45
53
|
description:
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
export const PARALL_EXTERNAL_TRIGGERS_SKILL = `# Parall External Triggers
|
|
2
|
+
|
|
3
|
+
An **External Trigger** is an incoming platform trigger. External systems send events to an External Trigger Connection, Parall matches active triggers with CEL, renders a Liquid template into an agent input body, and dispatches that input to the configured target agents.
|
|
4
|
+
|
|
5
|
+
Use External Triggers for incoming events such as GitHub callbacks, Slack/Feishu notifications, generic webhooks, or emails once the platform has a connection for them. The runtime behavior is incoming-only: receiving a trigger does not imply that you can call the external system back unless another explicit Parall capability is available.
|
|
6
|
+
|
|
7
|
+
## Prerequisite
|
|
8
|
+
|
|
9
|
+
External Trigger CLI commands are gated by the org-level \`external-triggers\` feature flag. If a command reports that the feature is unavailable, ask a human org admin to enable the flag before trying again. Public ingress delivery may still be live even when the management CLI is hidden behind the rollout flag.
|
|
10
|
+
|
|
11
|
+
## Creating a trigger
|
|
12
|
+
|
|
13
|
+
\`\`\`bash
|
|
14
|
+
# 1. Create a connection. The ingress token is shown once; prefer writing it
|
|
15
|
+
# to a local file so it does not land in shell history or logs.
|
|
16
|
+
parall external-triggers create-connection --name "GitHub CI" --token-file ./github-ci-webhook-token.txt
|
|
17
|
+
|
|
18
|
+
# 2. Create a trigger that targets one or more agents.
|
|
19
|
+
parall external-triggers create \\
|
|
20
|
+
--connection prll://xcn_xxx \\
|
|
21
|
+
--name "Failed checks" \\
|
|
22
|
+
--target-ids prll://usr_agent_xxx \\
|
|
23
|
+
--filter "body.json.check_run.conclusion == 'failure'" \\
|
|
24
|
+
--template-file ./github-check-failed.md \\
|
|
25
|
+
--attached-to-uri prll://tsk_xxx
|
|
26
|
+
\`\`\`
|
|
27
|
+
|
|
28
|
+
\`--filter\` is CEL. Omit it to match all incoming events (\`true\`). Keep filters small and deterministic; do not model provider-specific branching in agent code when the CEL expression can select the relevant events first.
|
|
29
|
+
|
|
30
|
+
\`--template\` / \`--template-file\` is Liquid with the safe Parall profile. It can read event data, body data, safe request metadata, trigger fields, run fields, and connection fields. It cannot call HTTP, read databases, evaluate arbitrary code, access platform secrets, or read arbitrary request headers/query parameters.
|
|
31
|
+
|
|
32
|
+
Example template:
|
|
33
|
+
|
|
34
|
+
\`\`\`liquid
|
|
35
|
+
GitHub check failed.
|
|
36
|
+
|
|
37
|
+
Event: {{ request.headers.x_github_event | default: "unknown" }}
|
|
38
|
+
Repo: {{ body.json.repository.full_name }}
|
|
39
|
+
PR: {{ body.json.pull_request.number }} {{ body.json.pull_request.title }}
|
|
40
|
+
Check: {{ body.json.check_run.name }}
|
|
41
|
+
Conclusion: {{ body.json.check_run.conclusion }}
|
|
42
|
+
|
|
43
|
+
Run: {{ body.json.check_run.html_url }}
|
|
44
|
+
\`\`\`
|
|
45
|
+
|
|
46
|
+
Do not render access tokens, signing secrets, cookies, or private credentials into agent input. Request snapshots and bodies may contain third-party data; treat them as user-provided input.
|
|
47
|
+
|
|
48
|
+
## Inspecting and lifecycle
|
|
49
|
+
|
|
50
|
+
\`\`\`bash
|
|
51
|
+
parall external-triggers connections
|
|
52
|
+
parall external-triggers connection prll://xcn_xxx
|
|
53
|
+
parall external-triggers schema prll://xcn_xxx
|
|
54
|
+
|
|
55
|
+
parall external-triggers list
|
|
56
|
+
parall external-triggers list --connection prll://xcn_xxx
|
|
57
|
+
parall external-triggers get prll://xtr_xxx
|
|
58
|
+
parall external-triggers update prll://xtr_xxx --filter "event.type == 'check_run'"
|
|
59
|
+
parall external-triggers pause prll://xtr_xxx
|
|
60
|
+
parall external-triggers resume prll://xtr_xxx
|
|
61
|
+
parall external-triggers delete prll://xtr_xxx
|
|
62
|
+
|
|
63
|
+
parall external-triggers runs prll://xtr_xxx
|
|
64
|
+
parall external-triggers run prll://xrn_xxx
|
|
65
|
+
parall external-triggers events --connection prll://xcn_xxx
|
|
66
|
+
parall external-triggers event prll://xin_xxx
|
|
67
|
+
\`\`\`
|
|
68
|
+
|
|
69
|
+
## Responding to external trigger dispatches
|
|
70
|
+
|
|
71
|
+
When you receive \`[Event: external.trigger]\`, Parall has already matched a trigger and rendered its template. The prompt includes headers such as:
|
|
72
|
+
|
|
73
|
+
- \`[Trigger: prll://xtr_xxx]\`
|
|
74
|
+
- \`[Run: prll://xrn_xxx]\`
|
|
75
|
+
- \`[Connection: ... (prll://xcn_xxx)]\`
|
|
76
|
+
- \`[Ingress: prll://xin_xxx]\`
|
|
77
|
+
- Optional \`[Attached: prll://...]\`
|
|
78
|
+
|
|
79
|
+
The rendered agent input body follows those headers. You usually do not need to fetch the run before acting. Fetch the run only for audit/debugging:
|
|
80
|
+
|
|
81
|
+
\`\`\`bash
|
|
82
|
+
parall external-triggers run prll://xrn_xxx
|
|
83
|
+
\`\`\`
|
|
84
|
+
|
|
85
|
+
Act on the rendered input the same way you would act on a user message: send a message, create or update tasks, edit wiki pages, or use available clips. If no visible response is needed, use \`parall no-reply --reason "handled external trigger"\` before sending any message.
|
|
86
|
+
|
|
87
|
+
CLI command results are JSON on stdout; mutation commands may emit auxiliary hints on stderr, for example \`Created: prll://xtr_xxx\`.
|
|
88
|
+
`;
|
|
@@ -64,8 +64,36 @@ parall machines logs prll://mch_xxx --lines 100
|
|
|
64
64
|
\`\`\`bash
|
|
65
65
|
parall chats list # List all chats
|
|
66
66
|
parall messages list prll://cht_xxx # Read chat message history
|
|
67
|
+
parall messages list prll://cht_xxx --since 2026-01-01 # Only messages at/after a date (RFC3339 or YYYY-MM-DD)
|
|
67
68
|
\`\`\`
|
|
68
69
|
|
|
70
|
+
## Org-Context Search
|
|
71
|
+
|
|
72
|
+
Before deciding or starting non-trivial work, search the org's real history —
|
|
73
|
+
past discussions, decisions, tasks, and wiki notes — so you don't re-litigate
|
|
74
|
+
settled questions or repeat known mistakes. This searches live org data
|
|
75
|
+
(semantic + keyword), not a local copy, and is permission-filtered to what you
|
|
76
|
+
can see.
|
|
77
|
+
|
|
78
|
+
\`\`\`bash
|
|
79
|
+
# Semantic + keyword search across messages, tasks, and wiki
|
|
80
|
+
parall search "auth v5 upgrade"
|
|
81
|
+
|
|
82
|
+
# Restrict entity types (m=message, t=task, w=wiki). --channel narrows the
|
|
83
|
+
# MESSAGE hits to one chat (tasks/wiki are unaffected by it).
|
|
84
|
+
parall search "auth v5 upgrade" --types m,w --channel prll://cht_eng
|
|
85
|
+
|
|
86
|
+
# Time-box to recent activity (RFC3339 or YYYY-MM-DD). Narrows messages + tasks;
|
|
87
|
+
# wiki is always matched by relevance (the index has no authored timestamp).
|
|
88
|
+
parall search "auth v5 upgrade" --since 2026-01-01
|
|
89
|
+
|
|
90
|
+
# Narrow wiki hits to a frontmatter document type
|
|
91
|
+
parall search "deploy steps" --types w --wiki-type Runbook
|
|
92
|
+
\`\`\`
|
|
93
|
+
|
|
94
|
+
Even with zero curated notes, the raw message + task history is searchable — the
|
|
95
|
+
original discussion and its approval/rejection IS the precedent.
|
|
96
|
+
|
|
69
97
|
## Sending Messages
|
|
70
98
|
|
|
71
99
|
Each \`[Event: message.new]\` includes \`[Chat: ... (prll://cht_xxx)]\` — use that chat URI to reply.
|
|
@@ -156,10 +184,38 @@ Every entity is addressable with a \`prll://\` URI. Common prefixes you'll see i
|
|
|
156
184
|
| \`prll://prj_\` | Project | parall-tasks |
|
|
157
185
|
| \`prll://sch_\` | Schedule (time trigger) | parall-schedules |
|
|
158
186
|
| \`prll://srn_\` | Schedule run (single fire audit record; carries fire-time snapshot) | parall-schedules |
|
|
187
|
+
| \`prll://xcn_\` | External Trigger Connection (incoming endpoint) | parall-external-triggers |
|
|
188
|
+
| \`prll://xin_\` | External Trigger Event (single incoming event audit record) | parall-external-triggers |
|
|
189
|
+
| \`prll://xtr_\` | External Trigger (incoming trigger configuration) | parall-external-triggers |
|
|
190
|
+
| \`prll://xrn_\` | External Trigger run (single matched dispatch audit record) | parall-external-triggers |
|
|
159
191
|
| \`prll://wik_\` | Wiki | parall-wiki |
|
|
160
192
|
| \`prll://att_\` | Attachment | parall-platform (files) |
|
|
161
193
|
|
|
162
194
|
When a message or event references \`prll://sch_xxx\` or \`prll://srn_xxx\`, or when you receive \`[Event: schedule.fired]\`, switch to the **parall-schedules** skill for the CLI commands (create / list / pause / resume / cancel / runs).
|
|
163
195
|
|
|
196
|
+
When a message or event references \`prll://xcn_xxx\`, \`prll://xin_xxx\`, \`prll://xtr_xxx\`, or \`prll://xrn_xxx\`, or when you receive \`[Event: external.trigger]\`, switch to the **parall-external-triggers** skill for the CLI commands (connections / triggers / events / runs).
|
|
197
|
+
|
|
198
|
+
## References (relationship graph)
|
|
199
|
+
|
|
200
|
+
\`prll://\` references between entities form a graph — a message cites a task, a
|
|
201
|
+
task cites a wiki page, and so on. Walk it to answer "what is this decision /
|
|
202
|
+
entity connected to". All results are permission-filtered to what you can see.
|
|
203
|
+
|
|
204
|
+
\`\`\`bash
|
|
205
|
+
# Resolve URIs to entity metadata (titles, status, previews)
|
|
206
|
+
parall refs resolve prll://tsk_xxx prll://wik_xxx
|
|
207
|
+
|
|
208
|
+
# Single hop — who references X
|
|
209
|
+
parall refs backlinks prll://tsk_xxx
|
|
210
|
+
|
|
211
|
+
# Multi-hop — the connected sub-graph around X (entity-level URI only — no
|
|
212
|
+
# path/anchor; depth 1–4, default 2)
|
|
213
|
+
parall refs graph prll://tsk_xxx --depth 2
|
|
214
|
+
\`\`\`
|
|
215
|
+
|
|
216
|
+
\`refs graph\` traverses both directions (inbound + outbound) and returns \`nodes\`
|
|
217
|
+
and \`edges\` with each node's hop \`depth\`. \`truncated: true\` means a size cap clipped
|
|
218
|
+
the result — narrow it with a smaller \`--depth\`.
|
|
219
|
+
|
|
164
220
|
CLI success output is JSON. Errors print a JSON line (\`{"error","status","code",...}\`) and, on a \`PERMISSION_DENIED\`, may add a plain-text \`Request approval:\` line — read both.
|
|
165
221
|
`;
|
|
@@ -2,16 +2,39 @@ export const PARALL_TASKS_SKILL = `# Parall Tasks
|
|
|
2
2
|
|
|
3
3
|
Manage tasks and projects via the Parall CLI. Auth and runtime context are pre-configured.
|
|
4
4
|
|
|
5
|
+
## Finding What's on Someone's Plate (incl. subtasks)
|
|
6
|
+
|
|
7
|
+
To answer "what do I still have to do", "what's <person> working on", or any
|
|
8
|
+
"open work assigned to X" question, use \`tasks assigned\`:
|
|
9
|
+
|
|
10
|
+
\`\`\`bash
|
|
11
|
+
# Pending tasks (todo + in_progress) assigned to a member — INCLUDES subtasks.
|
|
12
|
+
parall tasks assigned prll://usr_xxx # a specific person (e.g. the human who asked)
|
|
13
|
+
parall tasks assigned # yourself (defaults to the authenticated user)
|
|
14
|
+
\`\`\`
|
|
15
|
+
|
|
16
|
+
This is the authoritative "open work for a person" query. It returns every
|
|
17
|
+
pending task assigned to that member **including subtasks** — even when the
|
|
18
|
+
subtask's parent task belongs to someone else. Decomposed work usually lives in
|
|
19
|
+
subtasks, so do NOT answer this kind of question from \`tasks list\` alone:
|
|
20
|
+
that is org-wide, page-capped, and not scoped to a person, so a person's
|
|
21
|
+
subtasks are easily missed.
|
|
22
|
+
|
|
23
|
+
Resolve a person's \`prll://usr_\` id from the message context, the members
|
|
24
|
+
list, or ref search; your own id comes from \`parall whoami\`.
|
|
25
|
+
|
|
5
26
|
## Task Commands
|
|
6
27
|
|
|
7
28
|
\`\`\`bash
|
|
8
|
-
# List tasks (
|
|
29
|
+
# List tasks (org-wide; filter by status, assignee, or parent)
|
|
9
30
|
parall tasks list
|
|
10
31
|
parall tasks list --status todo
|
|
11
32
|
parall tasks list --status in_progress
|
|
33
|
+
parall tasks list --assignee-id prll://usr_xxx # first page only (default 20) — for a person's FULL backlog use 'tasks assigned' above
|
|
34
|
+
parall tasks subtasks prll://tsk_xxx # children of a single parent task
|
|
12
35
|
|
|
13
|
-
# Create a task
|
|
14
|
-
parall tasks create --title "Task title" [--assignee-id prll://usr_xxx] [--project-id prll://prj_xxx]
|
|
36
|
+
# Create a task (add --parent-id to make it a SUBTASK of another task)
|
|
37
|
+
parall tasks create --title "Task title" [--assignee-id prll://usr_xxx] [--parent-id prll://tsk_xxx] [--project-id prll://prj_xxx]
|
|
15
38
|
|
|
16
39
|
# Update task status
|
|
17
40
|
parall tasks update prll://tsk_xxx --status in_progress
|
|
@@ -21,6 +44,12 @@ parall tasks update prll://tsk_xxx --status done
|
|
|
21
44
|
parall tasks comments add prll://tsk_xxx --body "Progress update..."
|
|
22
45
|
\`\`\`
|
|
23
46
|
|
|
47
|
+
Subtasks are just tasks with a parent: create one with \`tasks create --parent-id\`,
|
|
48
|
+
re-parent with \`tasks update --parent-id\`, list a parent's children with
|
|
49
|
+
\`tasks subtasks\`. \`tasks list\` without \`--parent-id\` already returns both
|
|
50
|
+
top-level tasks and subtasks; per-person open work is best fetched with
|
|
51
|
+
\`tasks assigned\` (above).
|
|
52
|
+
|
|
24
53
|
## Project Commands
|
|
25
54
|
|
|
26
55
|
\`\`\`bash
|
|
@@ -16,8 +16,11 @@ Key facts the commands won't tell you:
|
|
|
16
16
|
the absolute workspace path (\`synced → /path/to/<slug>\` / \`Mount: ...\`).
|
|
17
17
|
Always address wiki files by that absolute path — your shell cwd is usually
|
|
18
18
|
NOT inside the workspace.
|
|
19
|
-
- **Text
|
|
20
|
-
|
|
19
|
+
- **Text and binary are two paths.** The workspace + changeset flow is for
|
|
20
|
+
text (markdown, code, config). Binary assets (images, PDFs, archives) are
|
|
21
|
+
diff-less — they don't go in the workspace; use \`parall wiki file\` (see
|
|
22
|
+
**Binary files** below). Dropping a binary into the workspace just gets it
|
|
23
|
+
rejected on propose.
|
|
21
24
|
- **\`cat\`, \`search\`, \`query\`, \`outline\`, and \`section\` read your local
|
|
22
25
|
workspace copy when it exists** — including your own unproposed edits. Add
|
|
23
26
|
\`--remote\` to \`cat\` to read the server version instead.
|
|
@@ -98,6 +101,50 @@ Re-propose REPLACES the changeset's previous contents with your current
|
|
|
98
101
|
workspace diff — to withdraw a file from the proposal, revert it locally
|
|
99
102
|
(restore the synced content) and re-propose; it drops out of the changeset.
|
|
100
103
|
|
|
104
|
+
## Binary files
|
|
105
|
+
|
|
106
|
+
Images, PDFs, archives — anything that can't be diffed — bypass the workspace
|
|
107
|
+
and changeset-text flow entirely. They never belong in the synced workspace
|
|
108
|
+
(propose rejects them); use \`parall wiki file\` instead. \`cat\` is text-only —
|
|
109
|
+
to read a binary's real bytes use \`file get\` (a plain \`sync\` only leaves a
|
|
110
|
+
few-line Git-LFS pointer on disk, since the runtime has no git-lfs).
|
|
111
|
+
|
|
112
|
+
\`\`\`bash
|
|
113
|
+
# Maintainer: direct-commit a binary to the default branch (no review)
|
|
114
|
+
parall wiki file upload ./diagram.png docs/assets/diagram.png
|
|
115
|
+
|
|
116
|
+
# Read a binary's real bytes (LFS pointers resolved server-side) to a file.
|
|
117
|
+
# Always use --output for binaries — without it the bytes stream to stdout and
|
|
118
|
+
# would flood your context.
|
|
119
|
+
parall wiki file get docs/assets/diagram.png --output ./diagram.png
|
|
120
|
+
parall wiki file get docs/assets/diagram.png --ref <commit-or-branch> --output ./diagram.png # a specific revision
|
|
121
|
+
|
|
122
|
+
# Remove a binary from the default branch (git history still has it)
|
|
123
|
+
parall wiki file delete docs/assets/diagram.png
|
|
124
|
+
\`\`\`
|
|
125
|
+
|
|
126
|
+
\`upload\` needs **maintain**; it routes by size automatically (≤1 MiB inline,
|
|
127
|
+
larger → LFS). A text file sent to \`upload\` is rejected — that's the changeset
|
|
128
|
+
flow's job.
|
|
129
|
+
|
|
130
|
+
### Reader: propose markdown that embeds an image
|
|
131
|
+
|
|
132
|
+
Without maintain you can still propose a doc with images — upload the binary
|
|
133
|
+
into your **changeset's** branch (read + author), not the default branch:
|
|
134
|
+
|
|
135
|
+
\`\`\`bash
|
|
136
|
+
parall wiki sync
|
|
137
|
+
# edit a .md in the workspace to add 
|
|
138
|
+
parall wiki changeset create <wiki> --title "Add foo diagram" # creates the changeset (note its id)
|
|
139
|
+
parall wiki file upload ./foo.png assets/foo.png <wiki> --changeset <changesetId>
|
|
140
|
+
# leave it for a maintainer to merge — both the markdown and the image squash in together
|
|
141
|
+
\`\`\`
|
|
142
|
+
|
|
143
|
+
Do the markdown \`changeset create\` first so the changeset exists, then attach
|
|
144
|
+
the image to it. Don't re-propose (\`--update\`) after attaching a binary —
|
|
145
|
+
re-propose replays only the text workspace and the server rejects dropping the
|
|
146
|
+
attached binary (422 \`REPLACE_HAS_BINARY\`).
|
|
147
|
+
|
|
101
148
|
## Discovery & history
|
|
102
149
|
|
|
103
150
|
\`\`\`bash
|
package/src/types.ts
CHANGED
|
@@ -24,7 +24,14 @@ export type DispatchState = {
|
|
|
24
24
|
|
|
25
25
|
/** Normalized inbound event from Parall. */
|
|
26
26
|
export type ParallEvent = {
|
|
27
|
-
type:
|
|
27
|
+
type:
|
|
28
|
+
| 'message'
|
|
29
|
+
| 'task'
|
|
30
|
+
| 'task_comment'
|
|
31
|
+
| 'wiki_comment'
|
|
32
|
+
| 'schedule'
|
|
33
|
+
| 'external_trigger'
|
|
34
|
+
| 'approval';
|
|
28
35
|
targetId: string;
|
|
29
36
|
targetName?: string;
|
|
30
37
|
targetType?: string;
|
|
@@ -52,10 +59,16 @@ export type ParallEvent = {
|
|
|
52
59
|
scheduledFireAt?: string;
|
|
53
60
|
/** Fire-time attached_to_uri snapshot, used for schedule events. */
|
|
54
61
|
attachedUri?: string;
|
|
62
|
+
/** External trigger metadata, used for external_trigger events. */
|
|
63
|
+
externalConnectionId?: string;
|
|
64
|
+
externalConnectionSourceType?: string;
|
|
65
|
+
externalConnectionDisplayName?: string;
|
|
66
|
+
externalIngressEventId?: string;
|
|
67
|
+
externalIngressEventType?: string;
|
|
55
68
|
/** Original event timestamp (e.g., message.created_at). When present,
|
|
56
69
|
* input steps use this instead of server insertion time for ordering. */
|
|
57
70
|
sentAt?: string;
|
|
58
|
-
ackSourceType?: 'message' | 'task_activity' | 'comment' | 'schedule_run';
|
|
71
|
+
ackSourceType?: 'message' | 'task_activity' | 'comment' | 'schedule_run' | 'external_trigger_run';
|
|
59
72
|
ackSourceId?: string;
|
|
60
73
|
/** Unread message count in the target chat since agent's last interaction. */
|
|
61
74
|
unreadCount?: number;
|