agentix-cli 0.22.0 → 0.25.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.
- package/LICENSE +21 -0
- package/README.md +102 -103
- package/agentx.example.json +9 -3
- package/dist/App-6Y7B3YQH.js +8 -0
- package/dist/App-6Y7B3YQH.js.map +1 -0
- package/dist/ChatApp-KIEUJ2DS.js +7 -0
- package/dist/ChatApp-KIEUJ2DS.js.map +1 -0
- package/dist/{agent-Y4U4R3ZZ.js → agent-QGZIAZMY.js} +2 -2
- package/dist/architect-SEPWMWS4.js +2 -0
- package/dist/{board-dashboard-2CPBWFOB.js → board-dashboard-CQ5F4GPD.js} +3756 -1010
- package/dist/board-dashboard-CQ5F4GPD.js.map +1 -0
- package/dist/builtin-FRKAQMFS.js +2 -0
- package/dist/chunk-2WVX3LEC.js +2 -0
- package/dist/chunk-2WVX3LEC.js.map +1 -0
- package/dist/chunk-3WQFCIB6.js +24 -0
- package/dist/chunk-3WQFCIB6.js.map +1 -0
- package/dist/chunk-53GCFZPR.js +116 -0
- package/dist/chunk-53GCFZPR.js.map +1 -0
- package/dist/{chunk-IKBHHTIT.js → chunk-5U35WAZF.js} +2 -2
- package/dist/chunk-67Q4DCPS.js +54 -0
- package/dist/chunk-67Q4DCPS.js.map +1 -0
- package/dist/chunk-76Z4VHDX.js +8 -0
- package/dist/chunk-76Z4VHDX.js.map +1 -0
- package/dist/{chunk-7P5QRX5W.js → chunk-BFXONUUN.js} +2 -2
- package/dist/{chunk-P3TJHGO5.js → chunk-FDMWOPEL.js} +2 -2
- package/dist/chunk-FDWOECJY.js +54 -0
- package/dist/chunk-FDWOECJY.js.map +1 -0
- package/dist/chunk-G57RZCXM.js +5 -0
- package/dist/chunk-G57RZCXM.js.map +1 -0
- package/dist/{chunk-NOF4HSGK.js → chunk-H5D7ATXS.js} +2 -2
- package/dist/chunk-HA3XI7Z2.js +155 -0
- package/dist/chunk-HA3XI7Z2.js.map +1 -0
- package/dist/chunk-HR4JSRZS.js +3 -0
- package/dist/{chunk-A6BKSZQA.js.map → chunk-HR4JSRZS.js.map} +1 -1
- package/dist/chunk-I3SIXTJO.js +44 -0
- package/dist/chunk-I3SIXTJO.js.map +1 -0
- package/dist/chunk-ISEBLHWX.js +118 -0
- package/dist/chunk-ISEBLHWX.js.map +1 -0
- package/dist/{chunk-4ITQP3XL.js → chunk-JP5IEXR7.js} +2 -2
- package/dist/chunk-JXWAGMI2.js +13 -0
- package/dist/chunk-JXWAGMI2.js.map +1 -0
- package/dist/chunk-KUCCW2VG.js +431 -0
- package/dist/chunk-KUCCW2VG.js.map +1 -0
- package/dist/chunk-LDHPMJ7M.js +257 -0
- package/dist/chunk-LDHPMJ7M.js.map +1 -0
- package/dist/{chunk-WHP4I44J.js → chunk-LNXCJWOU.js} +29 -30
- package/dist/chunk-LNXCJWOU.js.map +1 -0
- package/dist/chunk-M4AMWP3H.js +178 -0
- package/dist/chunk-M4AMWP3H.js.map +1 -0
- package/dist/chunk-NGSIRE4X.js +126 -0
- package/dist/chunk-NGSIRE4X.js.map +1 -0
- package/dist/{chunk-CNNLREHD.js → chunk-P4VWIVKN.js} +268 -410
- package/dist/chunk-P4VWIVKN.js.map +1 -0
- package/dist/chunk-Q6YO7LYE.js +47 -0
- package/dist/chunk-Q6YO7LYE.js.map +1 -0
- package/dist/chunk-TMKLHTCG.js +971 -0
- package/dist/chunk-TMKLHTCG.js.map +1 -0
- package/dist/chunk-TRJTTBE2.js +7 -0
- package/dist/chunk-TRJTTBE2.js.map +1 -0
- package/dist/chunk-U2CKL755.js +4 -0
- package/dist/chunk-U2CKL755.js.map +1 -0
- package/dist/chunk-UCQ2N3KO.js +9 -0
- package/dist/chunk-UCQ2N3KO.js.map +1 -0
- package/dist/chunk-W4YR2RO2.js +2 -0
- package/dist/chunk-W4YR2RO2.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/client-GGVVLOOF.js +2 -0
- package/dist/{compaction-BTUJJ3LJ.js → compaction-NWEMOSHA.js} +3 -3
- package/dist/config-7FSZFRTQ.js +2 -0
- package/dist/config-mutator-POCOYYJ4.js +2 -0
- package/dist/{context-planner-I7ID7XF3.js → context-planner-45GEWKGL.js} +2 -2
- package/dist/doctor-DHLBEKA4.js +2 -0
- package/dist/heal-HZ3EQD52.js +2 -0
- package/dist/index.d.ts +1244 -225
- package/dist/index.js +12 -12
- package/dist/index.js.map +1 -1
- package/dist/memory-extract-AENFVVO5.js +2 -0
- package/dist/processes-UIC4XXA6.js +2 -0
- package/dist/program-WVAVJFND.js +2 -0
- package/dist/projects-api-KRME2YKZ.js +2 -0
- package/dist/projects-api-KRME2YKZ.js.map +1 -0
- package/dist/projects-mutate-3NHVG437.js +7 -0
- package/dist/projects-mutate-3NHVG437.js.map +1 -0
- package/dist/providers-L27BJ5A6.js +2 -0
- package/dist/registry-T36ZIAWV.js +2 -0
- package/dist/rotation-memo-B3EXXSEH.js +13 -0
- package/dist/rotation-memo-B3EXXSEH.js.map +1 -0
- package/dist/scheduler-GH7TIKYS.js +2 -0
- package/dist/surface-usage-PRL6Z4U3.js +2 -0
- package/dist/wiki-M6YNRFC4.js +2 -0
- package/dist/workflows/templates/branching.yaml +75 -0
- package/dist/workflows/templates/extract.yaml +59 -0
- package/dist/workflows/templates/linear.yaml +37 -0
- package/dist/workflows/templates/retry.yaml +61 -0
- package/dist/workspace-setup-TBQAHYHJ.js +2 -0
- package/package.json +11 -3
- package/dist/board-dashboard-2CPBWFOB.js.map +0 -1
- package/dist/chunk-2HXSJYAJ.js +0 -15
- package/dist/chunk-2HXSJYAJ.js.map +0 -1
- package/dist/chunk-5F3J55LG.js +0 -2
- package/dist/chunk-5F3J55LG.js.map +0 -1
- package/dist/chunk-A6BKSZQA.js +0 -3
- package/dist/chunk-ABVZHJUO.js +0 -7
- package/dist/chunk-ABVZHJUO.js.map +0 -1
- package/dist/chunk-BHSPAP4U.js +0 -44
- package/dist/chunk-BHSPAP4U.js.map +0 -1
- package/dist/chunk-CDNWCYF7.js +0 -2
- package/dist/chunk-CDNWCYF7.js.map +0 -1
- package/dist/chunk-CNNLREHD.js.map +0 -1
- package/dist/chunk-CO4YCIIA.js +0 -13
- package/dist/chunk-CO4YCIIA.js.map +0 -1
- package/dist/chunk-EW27SCCC.js +0 -2
- package/dist/chunk-EW27SCCC.js.map +0 -1
- package/dist/chunk-GOLZ6NEL.js +0 -111
- package/dist/chunk-GOLZ6NEL.js.map +0 -1
- package/dist/chunk-JGXE2YNV.js +0 -46
- package/dist/chunk-JGXE2YNV.js.map +0 -1
- package/dist/chunk-KX626FN4.js +0 -6
- package/dist/chunk-KX626FN4.js.map +0 -1
- package/dist/chunk-MTRWXRFF.js +0 -380
- package/dist/chunk-MTRWXRFF.js.map +0 -1
- package/dist/chunk-N67JZAXU.js +0 -2
- package/dist/chunk-N67JZAXU.js.map +0 -1
- package/dist/chunk-OPKQNLGX.js +0 -450
- package/dist/chunk-OPKQNLGX.js.map +0 -1
- package/dist/chunk-OZOQKPJV.js +0 -102
- package/dist/chunk-OZOQKPJV.js.map +0 -1
- package/dist/chunk-VYLZ7UYM.js +0 -118
- package/dist/chunk-VYLZ7UYM.js.map +0 -1
- package/dist/chunk-WHP4I44J.js.map +0 -1
- package/dist/chunk-WJXU5F4Z.js +0 -53
- package/dist/chunk-WJXU5F4Z.js.map +0 -1
- package/dist/chunk-X5D5AV5N.js +0 -833
- package/dist/chunk-X5D5AV5N.js.map +0 -1
- package/dist/config-BLOKGMER.js +0 -2
- package/dist/config-mutator-RG7QY2EL.js +0 -2
- package/dist/doctor-ZTECTUHX.js +0 -2
- package/dist/editor-chat-RVLCKKB7.js +0 -137
- package/dist/editor-chat-RVLCKKB7.js.map +0 -1
- package/dist/heal-YEQYWX2L.js +0 -2
- package/dist/inbox-BIN2S5XN.js +0 -2
- package/dist/memory-extract-KRCHD3OP.js +0 -2
- package/dist/processes-RJ6RDP32.js +0 -2
- package/dist/program-GZOJIWTB.js +0 -2
- package/dist/providers-WVCMIW67.js +0 -2
- package/dist/registry-QZIUSQ5J.js +0 -2
- package/dist/rotation-memo-GMTZPMNE.js +0 -13
- package/dist/rotation-memo-GMTZPMNE.js.map +0 -1
- package/dist/scheduler-B2BQPV4M.js +0 -2
- package/dist/slack-6P7ZJ32Y.js +0 -3
- package/dist/slack-6P7ZJ32Y.js.map +0 -1
- package/dist/store-BAPDZHXE.js +0 -2
- package/dist/task-store-RHISEU6V.js +0 -2
- package/dist/telegram-PIYDRM46.js +0 -3
- package/dist/telegram-PIYDRM46.js.map +0 -1
- package/dist/types-ZRLHHCGB.js +0 -2
- package/dist/web/workflow-editor.global.js +0 -1452
- package/dist/web/workflow-editor.global.js.map +0 -1
- package/dist/whatsapp-PFRDMUMT.js +0 -3
- package/dist/whatsapp-PFRDMUMT.js.map +0 -1
- package/dist/wiki-53W5NLZV.js +0 -2
- package/dist/workspace-setup-DQCZX2NE.js +0 -2
- /package/dist/{agent-Y4U4R3ZZ.js.map → agent-QGZIAZMY.js.map} +0 -0
- /package/dist/{config-BLOKGMER.js.map → architect-SEPWMWS4.js.map} +0 -0
- /package/dist/{config-mutator-RG7QY2EL.js.map → builtin-FRKAQMFS.js.map} +0 -0
- /package/dist/{chunk-IKBHHTIT.js.map → chunk-5U35WAZF.js.map} +0 -0
- /package/dist/{chunk-7P5QRX5W.js.map → chunk-BFXONUUN.js.map} +0 -0
- /package/dist/{chunk-P3TJHGO5.js.map → chunk-FDMWOPEL.js.map} +0 -0
- /package/dist/{chunk-NOF4HSGK.js.map → chunk-H5D7ATXS.js.map} +0 -0
- /package/dist/{chunk-4ITQP3XL.js.map → chunk-JP5IEXR7.js.map} +0 -0
- /package/dist/{doctor-ZTECTUHX.js.map → client-GGVVLOOF.js.map} +0 -0
- /package/dist/{compaction-BTUJJ3LJ.js.map → compaction-NWEMOSHA.js.map} +0 -0
- /package/dist/{heal-YEQYWX2L.js.map → config-7FSZFRTQ.js.map} +0 -0
- /package/dist/{inbox-BIN2S5XN.js.map → config-mutator-POCOYYJ4.js.map} +0 -0
- /package/dist/{context-planner-I7ID7XF3.js.map → context-planner-45GEWKGL.js.map} +0 -0
- /package/dist/{memory-extract-KRCHD3OP.js.map → doctor-DHLBEKA4.js.map} +0 -0
- /package/dist/{processes-RJ6RDP32.js.map → heal-HZ3EQD52.js.map} +0 -0
- /package/dist/{program-GZOJIWTB.js.map → memory-extract-AENFVVO5.js.map} +0 -0
- /package/dist/{providers-WVCMIW67.js.map → processes-UIC4XXA6.js.map} +0 -0
- /package/dist/{registry-QZIUSQ5J.js.map → program-WVAVJFND.js.map} +0 -0
- /package/dist/{scheduler-B2BQPV4M.js.map → providers-L27BJ5A6.js.map} +0 -0
- /package/dist/{store-BAPDZHXE.js.map → registry-T36ZIAWV.js.map} +0 -0
- /package/dist/{task-store-RHISEU6V.js.map → scheduler-GH7TIKYS.js.map} +0 -0
- /package/dist/{types-ZRLHHCGB.js.map → surface-usage-PRL6Z4U3.js.map} +0 -0
- /package/dist/{wiki-53W5NLZV.js.map → wiki-M6YNRFC4.js.map} +0 -0
- /package/dist/{workspace-setup-DQCZX2NE.js.map → workspace-setup-TBQAHYHJ.js.map} +0 -0
package/dist/config-BLOKGMER.js
DELETED
package/dist/doctor-ZTECTUHX.js
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import"./chunk-4YCH6IZV.js";function u(o){let r=o.store.list().map(t=>({id:t.id,title:t.title})),s=o.actors.listActors().map(t=>t.id),n=o.actors.listRoles().map(t=>t.id),e=[];if(e.push(i),e.push(""),e.push(l),e.push(""),e.push("# Environment \u2014 only reference values that exist"),e.push(""),e.push("## Available agents (for `agent` nodes)"),o.availableAgents.length===0)e.push(" (none registered \u2014 the user must add an agent first for `agent` nodes to work)");else for(let t of o.availableAgents)e.push(` - \`${t.id}\`${t.description?` \u2014 ${t.description}`:""}`);if(e.push(""),e.push("## Available actors (for `userTask.assignTo`)"),s.length===0)e.push(" (none \u2014 user must register actors with `agentx actor add <id> \u2026` before workflows can use `userTask`)");else for(let t of s)e.push(` - \`${t}\``);if(e.push(""),e.push("## Available roles (for `userTask.assignTo`)"),n.length===0)e.push(" (none)");else for(let t of n)e.push(` - \`${t}\``);if(e.push(""),e.push("## Available channels (for `action.*` and `trigger.channel`)"),e.push(` ${o.availableChannels.length?o.availableChannels.map(t=>`\`${t}\``).join(", "):"(none live on this node)"}`),e.push(""),e.push("## Existing workflows (for `subProcess.workflowId`)"),r.length===0)e.push(" (no other workflows defined)");else for(let t of r)e.push(` - \`${t.id}\` \u2014 ${t.title}`);e.push(""),o.currentWorkflow&&(e.push("# Current workflow on canvas"),e.push(""),e.push("The user is editing this workflow. Build on it \u2014 do NOT replace it unless they explicitly ask."),e.push(""),e.push("```json"),e.push(JSON.stringify(o.currentWorkflow,null,2)),e.push("```"),e.push("")),e.push("# Conversation"),e.push("");for(let t of o.messages){let a=t.role==="user"?"USER":"ASSISTANT";e.push(`${a}: ${t.content}`),e.push("")}return e.push(c),e.join(`
|
|
2
|
-
`)}function d(o){let r=/```(?:json)?\s*\n([\s\S]*?)```/.exec(o),s=[];r&&s.push(r[1]);let n=o.match(/\{[\s\S]*\}/);n&&s.push(n[0]);for(let e of s)try{let t=JSON.parse(e);if(t&&typeof t=="object"&&"id"in t&&"nodes"in t)return t}catch{}return null}var i=`You are AgentX's workflow author. The user describes a business process in
|
|
3
|
-
plain language; you return a valid V2 workflow JSON that implements it.
|
|
4
|
-
|
|
5
|
-
Read the node catalog below. Prefer the BPM primitives (userTask,
|
|
6
|
-
subProcess, signal.emit/wait, timer.boundary, gateway.parallel, rule)
|
|
7
|
-
when modelling processes with humans, deadlines, parallel streams, or
|
|
8
|
-
nested activities. Prefer the bot primitives (agent, branch, action.*)
|
|
9
|
-
for simple message-in \u2192 reply-out automations.`,l=`# V2 Node catalog
|
|
10
|
-
|
|
11
|
-
## Triggers (exactly one per workflow)
|
|
12
|
-
- \`trigger.channel\` \u2014 inbound channel event.
|
|
13
|
-
config: { "source": "whatsapp-message" | "telegram-message" | "slack-message" | "discord-message" | "gitlab-issue" | "gitlab-pipeline", "filter": { "chat"?: "*", "project"?: "noqta/web", "labels"?: ["x"] } }
|
|
14
|
-
- \`trigger.cron\` \u2014 scheduled. config: { "spec": "0 9 * * *", "timezone": "Africa/Tunis" }
|
|
15
|
-
- \`trigger.hook\` \u2014 subscribes to any on:* hook event. config: { "event": "on:gitlab-issue" }
|
|
16
|
-
- \`trigger.manual\` \u2014 kicked off by CLI or API. config: {}
|
|
17
|
-
- \`trigger.form\` \u2014 human fills a form to start. config: { "form": FormSchema, "startableBy": "role:public" }
|
|
18
|
-
|
|
19
|
-
## Compute
|
|
20
|
-
- \`agent\` \u2014 run an agent with a templated prompt. Output: { reply, result (parsed RESULT: token), json?, durationMs }.
|
|
21
|
-
config: { "agentId": "<id>", "prompt": "Classify {{trigger.text}} \u2014 reply on one line: RESULT: a|b|c", "resultParser": "noqta-result-token" | "json", "timeoutMinutes": 2 }
|
|
22
|
-
- \`transform\` \u2014 reshape upstream context.
|
|
23
|
-
config: { "path": "trigger.contact.phone" } OR { "template": { "key": "{{trigger.text}}" } }
|
|
24
|
-
|
|
25
|
-
## Control flow
|
|
26
|
-
- \`branch\` \u2014 N-way switch (first match wins).
|
|
27
|
-
config: { "cases": [{ "when": { "kind": "equals"|"contains"|"matches"|"exists", "params": { "path": "classify.result", "value": "ok" } }, "to": "port1" }], "default": "fallbackPort" }
|
|
28
|
-
Wire with edges: { "from": "branchId", "fromPort": "port1", "to": "nextNode" }
|
|
29
|
-
- \`gateway.parallel\` \u2014 fan-out (one \u2192 many) or join (many \u2192 one).
|
|
30
|
-
config: { "mode": "fanOut" } \u2014 splits to every outgoing edge
|
|
31
|
-
config: { "mode": "join" } \u2014 waits until every incoming edge arrives, then fires once
|
|
32
|
-
- \`rule\` \u2014 DMN decision table, first matching row wins.
|
|
33
|
-
config: {
|
|
34
|
-
"inputs": ["{{trigger.tier}}", "{{trigger.amount}}"],
|
|
35
|
-
"rules": [
|
|
36
|
-
{ "when": ["gold", ">100"], "to": "vip", "output": { "route": "vip" } },
|
|
37
|
-
{ "when": ["*", ">50"], "to": "high", "output": { "route": "high" } }
|
|
38
|
-
],
|
|
39
|
-
"default": { "to": "low", "output": { "route": "low" } }
|
|
40
|
-
}
|
|
41
|
-
Cell syntax: "*" wildcard, exact "value", ">N" "<N" ">=N" "<=N", "!=x", "/regex/".
|
|
42
|
-
- \`checkpoint\` \u2014 pause until a matching event.
|
|
43
|
-
config: { "name": "await-x", "waitFor": { "source": "manual" }, "resumeMatch": {} }
|
|
44
|
-
|
|
45
|
-
## BPM
|
|
46
|
-
- \`userTask\` \u2014 assign a form to an actor or role; pauses until submission.
|
|
47
|
-
config: {
|
|
48
|
-
"assignTo": "actor:alice" | "role:reviewers",
|
|
49
|
-
"title": "Review expense {{trigger.values.amount}}",
|
|
50
|
-
"description": "\u2026",
|
|
51
|
-
"dueIn": "P2D" | "PT2H" | { "minutes": 60 },
|
|
52
|
-
"form": FormSchema
|
|
53
|
-
}
|
|
54
|
-
Output: { submittedBy, submittedAt, values: { fieldKey: value }, action: "primary" | "secondary" }
|
|
55
|
-
- \`subProcess\` \u2014 spawn a child workflow; parent pauses until child reaches end.
|
|
56
|
-
config: {
|
|
57
|
-
"workflowId": "<other workflow id>",
|
|
58
|
-
"inputMap": { "trigger": { "grantee": "{{trigger.values.name}}" } } (or "*" for full inherit),
|
|
59
|
-
"awaitCompletion": true
|
|
60
|
-
}
|
|
61
|
-
Output: { childRunId, status, output: <child's last bundle> }
|
|
62
|
-
- \`signal.emit\` \u2014 publish an event. config: { "name": "approved", "scope": "workflow"|"global", "payload": {} }
|
|
63
|
-
- \`signal.wait\` \u2014 pause until matching signal arrives. config: { "name": "approved", "scope": "workflow", "match": { "grantId": "{{trigger.id}}" } }
|
|
64
|
-
- \`timer.boundary\` \u2014 pause for a duration. config: { "after": "PT2H" | "P1D" | 60 (minutes) }
|
|
65
|
-
|
|
66
|
-
## Actions \u2014 side-effect sinks
|
|
67
|
-
- \`action.send\` \u2014 post a message to any channel. config: { "channel": "telegram"|"whatsapp"|\u2026, "chatId": "{{trigger.chatId}}", "text": "Hi {{classify.reply}}", "accountId"?: "\u2026" }
|
|
68
|
-
- \`action.createIssue\` \u2014 open a GitLab issue. config: { "channel": "gitlab", "project": "noqta/web", "title": "\u2026", "description": "\u2026", "labels": ["x"], "assignees": ["user"] }
|
|
69
|
-
- \`action.setLabel\` / \`action.readLabel\` / \`action.react\` / \`action.editMessage\` / \`action.logTime\` \u2014 self-explanatory; each maps 1:1 to a channel adapter method.
|
|
70
|
-
- \`action.callHTTP\` \u2014 outbound HTTP. config: { "method": "POST"|"GET"|\u2026, "url": "https://\u2026", "headers": {}, "body": {}, "timeoutMs": 30000 }
|
|
71
|
-
|
|
72
|
-
## Terminal
|
|
73
|
-
- \`end\` \u2014 completes the run. config: { "status": "completed" | "failed" | "canceled" }
|
|
74
|
-
|
|
75
|
-
## FormSchema (used by userTask + trigger.form)
|
|
76
|
-
{
|
|
77
|
-
"title": "Review application",
|
|
78
|
-
"description": "\u2026",
|
|
79
|
-
"fields": [
|
|
80
|
-
{ "key": "score", "label": "Score", "type": "number", "required": true, "validate": { "min": 1, "max": 10 } },
|
|
81
|
-
{ "key": "verdict", "label": "Verdict", "type": "select", "required": true, "options": ["approve", "reject"] },
|
|
82
|
-
{ "key": "notes", "label": "Notes", "type": "long-text" }
|
|
83
|
-
],
|
|
84
|
-
"submitLabel": "Approve",
|
|
85
|
-
"secondaryAction": { "key": "reject", "label": "Reject" }
|
|
86
|
-
}
|
|
87
|
-
Field types: text, long-text, number, boolean, date, select, multi-select, file.
|
|
88
|
-
A form with a \`secondaryAction\` and no required-unfilled fields renders as one-tap Approve/Reject buttons in chat.
|
|
89
|
-
|
|
90
|
-
## Templates
|
|
91
|
-
Every prompt + config value can reference \`{{nodeId.path}}\` against the run context. Examples:
|
|
92
|
-
{{trigger.values.amount}} \u2014 field from the start form
|
|
93
|
-
{{classify.result}} \u2014 parsed RESULT: token from an agent node
|
|
94
|
-
{{review.values.score}} \u2014 submitted userTask field
|
|
95
|
-
{{env.GITLAB_TOKEN}} \u2014 env var (must be listed in workflow.envAllow)
|
|
96
|
-
|
|
97
|
-
## Edges
|
|
98
|
-
[{ "from": "nodeId", "to": "nodeId" }, { "from": "branchId", "fromPort": "case-label", "to": "nodeId" }]
|
|
99
|
-
Every edge's from/to must reference an existing node. Branch + rule nodes MUST have outgoing edges whose fromPort matches a declared case/rule/default.
|
|
100
|
-
|
|
101
|
-
## Workflow shell
|
|
102
|
-
{
|
|
103
|
-
"id": "lower-kebab-id",
|
|
104
|
-
"version": 2,
|
|
105
|
-
"title": "Human readable",
|
|
106
|
-
"description": "optional",
|
|
107
|
-
"priority": 0,
|
|
108
|
-
"fanOut": false,
|
|
109
|
-
"envAllow": [],
|
|
110
|
-
"maxChildDepth": 5,
|
|
111
|
-
"retention": { "maxRuns": 500, "maxDays": 90 },
|
|
112
|
-
"nodes": [...],
|
|
113
|
-
"edges": [...]
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
## Lint rules (all enforced on save)
|
|
117
|
-
- exactly one trigger.* node
|
|
118
|
-
- every edge references an existing node
|
|
119
|
-
- every node is reachable from the trigger
|
|
120
|
-
- at least one end/checkpoint/userTask/subProcess/signal.wait/timer.boundary is reachable
|
|
121
|
-
- branch + rule outgoing fromPort values match declared cases (or default)
|
|
122
|
-
- cycles are only allowed when the cycle crosses an agent/checkpoint/userTask/subProcess/signal.wait/timer.boundary`,c=`# Your reply
|
|
123
|
-
|
|
124
|
-
Respond in ONE of two ways:
|
|
125
|
-
|
|
126
|
-
1. **Clarification**: if the user's request is ambiguous, ask exactly ONE short follow-up question. No JSON.
|
|
127
|
-
|
|
128
|
-
2. **Workflow**: if you have enough to produce a workflow, reply with:
|
|
129
|
-
- 1\u20133 short lines explaining what you built
|
|
130
|
-
- a \`\`\`json code block containing the complete, valid V2 workflow
|
|
131
|
-
- (no prose after the JSON block)
|
|
132
|
-
|
|
133
|
-
Only reference agent ids, actor ids, role ids, and channel names that
|
|
134
|
-
appear in the Environment section above. If the user asks for an agent
|
|
135
|
-
that doesn't exist, tell them which agent to register first. Never
|
|
136
|
-
invent workflowIds for subProcess that aren't in the existing list.`;export{u as buildWorkflowAuthorPrompt,d as extractWorkflowJson};
|
|
137
|
-
//# sourceMappingURL=editor-chat-RVLCKKB7.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/workflows/editor-chat.ts"],"sourcesContent":["import type { Workflow } from \"./types\"\nimport type { WorkflowStore } from \"./store\"\nimport type { ActorStore } from \"../actors/store\"\n\n// --- Workflow-builder chat context ---\n//\n// Produces the plain-text prompt the authoring agent reads. Packs\n// *everything* the agent needs to generate a valid V2 workflow JSON on\n// its first try: node catalog with config examples, available agent\n// ids, actor + role ids, channel adapter names, the user's existing\n// workflow list (for subProcess targets), and — when the author is\n// editing — the current workflow JSON as a starting point.\n//\n// The output is deliberately text, not JSON. Agents (LLMs) produce\n// better structured output when the schema is described as prose +\n// examples rather than as raw JSON Schema. The explicit \"reply with a\n// ```json block```\" instruction at the tail is what the API endpoint\n// parses back.\n\nexport interface ChatMessage {\n role: \"user\" | \"assistant\"\n content: string\n}\n\nexport interface BuildContextArgs {\n messages: ChatMessage[]\n store: WorkflowStore\n actors: ActorStore\n /** Full list of agent ids + optional descriptions. */\n availableAgents: Array<{ id: string; description?: string; tags?: string[] }>\n /** Adapter names the daemon has live (telegram, whatsapp, gitlab, ...). */\n availableChannels: string[]\n /** The workflow the user is currently editing (if any). */\n currentWorkflow?: Workflow\n}\n\n/** Build the single-string prompt the agent executes. */\nexport function buildWorkflowAuthorPrompt(args: BuildContextArgs): string {\n const workflows = args.store.list().map((w) => ({ id: w.id, title: w.title }))\n const actorIds = args.actors.listActors().map((a) => a.id)\n const roleIds = args.actors.listRoles().map((r) => r.id)\n\n const parts: string[] = []\n\n parts.push(SYSTEM_HEADER)\n parts.push(\"\")\n parts.push(NODE_CATALOG)\n parts.push(\"\")\n parts.push(\"# Environment — only reference values that exist\")\n parts.push(\"\")\n parts.push(`## Available agents (for \\`agent\\` nodes)`)\n if (args.availableAgents.length === 0) {\n parts.push(\" (none registered — the user must add an agent first for `agent` nodes to work)\")\n } else {\n for (const a of args.availableAgents) {\n parts.push(` - \\`${a.id}\\`${a.description ? ` — ${a.description}` : \"\"}`)\n }\n }\n parts.push(\"\")\n parts.push(\"## Available actors (for `userTask.assignTo`)\")\n if (actorIds.length === 0) {\n parts.push(\" (none — user must register actors with `agentx actor add <id> …` before workflows can use `userTask`)\")\n } else for (const id of actorIds) parts.push(` - \\`${id}\\``)\n parts.push(\"\")\n parts.push(\"## Available roles (for `userTask.assignTo`)\")\n if (roleIds.length === 0) parts.push(\" (none)\")\n else for (const id of roleIds) parts.push(` - \\`${id}\\``)\n parts.push(\"\")\n parts.push(\"## Available channels (for `action.*` and `trigger.channel`)\")\n parts.push(` ${args.availableChannels.length ? args.availableChannels.map((c) => `\\`${c}\\``).join(\", \") : \"(none live on this node)\"}`)\n parts.push(\"\")\n parts.push(\"## Existing workflows (for `subProcess.workflowId`)\")\n if (workflows.length === 0) parts.push(\" (no other workflows defined)\")\n else for (const w of workflows) parts.push(` - \\`${w.id}\\` — ${w.title}`)\n parts.push(\"\")\n\n if (args.currentWorkflow) {\n parts.push(\"# Current workflow on canvas\")\n parts.push(\"\")\n parts.push(\"The user is editing this workflow. Build on it — do NOT replace it unless they explicitly ask.\")\n parts.push(\"\")\n parts.push(\"```json\")\n parts.push(JSON.stringify(args.currentWorkflow, null, 2))\n parts.push(\"```\")\n parts.push(\"\")\n }\n\n parts.push(\"# Conversation\")\n parts.push(\"\")\n for (const m of args.messages) {\n const tag = m.role === \"user\" ? \"USER\" : \"ASSISTANT\"\n parts.push(`${tag}: ${m.content}`)\n parts.push(\"\")\n }\n\n parts.push(RESPONSE_RULES)\n return parts.join(\"\\n\")\n}\n\n/** Try to extract a workflow-shaped JSON block from an agent reply. Returns\n * null if no JSON block is present OR the JSON doesn't have the minimum\n * workflow fields (id, nodes). The caller still runs full zod validation\n * before writing. */\nexport function extractWorkflowJson(reply: string): Record<string, unknown> | null {\n // Prefer fenced ```json blocks; fall back to the largest {...} block.\n const fenced = /```(?:json)?\\s*\\n([\\s\\S]*?)```/.exec(reply)\n const candidates: string[] = []\n if (fenced) candidates.push(fenced[1])\n const braceMatch = reply.match(/\\{[\\s\\S]*\\}/)\n if (braceMatch) candidates.push(braceMatch[0])\n\n for (const raw of candidates) {\n try {\n const parsed = JSON.parse(raw)\n if (parsed && typeof parsed === \"object\" && \"id\" in parsed && \"nodes\" in parsed) {\n return parsed as Record<string, unknown>\n }\n } catch { /* try next */ }\n }\n return null\n}\n\nconst SYSTEM_HEADER = `You are AgentX's workflow author. The user describes a business process in\nplain language; you return a valid V2 workflow JSON that implements it.\n\nRead the node catalog below. Prefer the BPM primitives (userTask,\nsubProcess, signal.emit/wait, timer.boundary, gateway.parallel, rule)\nwhen modelling processes with humans, deadlines, parallel streams, or\nnested activities. Prefer the bot primitives (agent, branch, action.*)\nfor simple message-in → reply-out automations.`\n\nconst NODE_CATALOG = `# V2 Node catalog\n\n## Triggers (exactly one per workflow)\n- \\`trigger.channel\\` — inbound channel event.\n config: { \"source\": \"whatsapp-message\" | \"telegram-message\" | \"slack-message\" | \"discord-message\" | \"gitlab-issue\" | \"gitlab-pipeline\", \"filter\": { \"chat\"?: \"*\", \"project\"?: \"noqta/web\", \"labels\"?: [\"x\"] } }\n- \\`trigger.cron\\` — scheduled. config: { \"spec\": \"0 9 * * *\", \"timezone\": \"Africa/Tunis\" }\n- \\`trigger.hook\\` — subscribes to any on:* hook event. config: { \"event\": \"on:gitlab-issue\" }\n- \\`trigger.manual\\` — kicked off by CLI or API. config: {}\n- \\`trigger.form\\` — human fills a form to start. config: { \"form\": FormSchema, \"startableBy\": \"role:public\" }\n\n## Compute\n- \\`agent\\` — run an agent with a templated prompt. Output: { reply, result (parsed RESULT: token), json?, durationMs }.\n config: { \"agentId\": \"<id>\", \"prompt\": \"Classify {{trigger.text}} — reply on one line: RESULT: a|b|c\", \"resultParser\": \"noqta-result-token\" | \"json\", \"timeoutMinutes\": 2 }\n- \\`transform\\` — reshape upstream context.\n config: { \"path\": \"trigger.contact.phone\" } OR { \"template\": { \"key\": \"{{trigger.text}}\" } }\n\n## Control flow\n- \\`branch\\` — N-way switch (first match wins).\n config: { \"cases\": [{ \"when\": { \"kind\": \"equals\"|\"contains\"|\"matches\"|\"exists\", \"params\": { \"path\": \"classify.result\", \"value\": \"ok\" } }, \"to\": \"port1\" }], \"default\": \"fallbackPort\" }\n Wire with edges: { \"from\": \"branchId\", \"fromPort\": \"port1\", \"to\": \"nextNode\" }\n- \\`gateway.parallel\\` — fan-out (one → many) or join (many → one).\n config: { \"mode\": \"fanOut\" } — splits to every outgoing edge\n config: { \"mode\": \"join\" } — waits until every incoming edge arrives, then fires once\n- \\`rule\\` — DMN decision table, first matching row wins.\n config: {\n \"inputs\": [\"{{trigger.tier}}\", \"{{trigger.amount}}\"],\n \"rules\": [\n { \"when\": [\"gold\", \">100\"], \"to\": \"vip\", \"output\": { \"route\": \"vip\" } },\n { \"when\": [\"*\", \">50\"], \"to\": \"high\", \"output\": { \"route\": \"high\" } }\n ],\n \"default\": { \"to\": \"low\", \"output\": { \"route\": \"low\" } }\n }\n Cell syntax: \"*\" wildcard, exact \"value\", \">N\" \"<N\" \">=N\" \"<=N\", \"!=x\", \"/regex/\".\n- \\`checkpoint\\` — pause until a matching event.\n config: { \"name\": \"await-x\", \"waitFor\": { \"source\": \"manual\" }, \"resumeMatch\": {} }\n\n## BPM\n- \\`userTask\\` — assign a form to an actor or role; pauses until submission.\n config: {\n \"assignTo\": \"actor:alice\" | \"role:reviewers\",\n \"title\": \"Review expense {{trigger.values.amount}}\",\n \"description\": \"…\",\n \"dueIn\": \"P2D\" | \"PT2H\" | { \"minutes\": 60 },\n \"form\": FormSchema\n }\n Output: { submittedBy, submittedAt, values: { fieldKey: value }, action: \"primary\" | \"secondary\" }\n- \\`subProcess\\` — spawn a child workflow; parent pauses until child reaches end.\n config: {\n \"workflowId\": \"<other workflow id>\",\n \"inputMap\": { \"trigger\": { \"grantee\": \"{{trigger.values.name}}\" } } (or \"*\" for full inherit),\n \"awaitCompletion\": true\n }\n Output: { childRunId, status, output: <child's last bundle> }\n- \\`signal.emit\\` — publish an event. config: { \"name\": \"approved\", \"scope\": \"workflow\"|\"global\", \"payload\": {} }\n- \\`signal.wait\\` — pause until matching signal arrives. config: { \"name\": \"approved\", \"scope\": \"workflow\", \"match\": { \"grantId\": \"{{trigger.id}}\" } }\n- \\`timer.boundary\\` — pause for a duration. config: { \"after\": \"PT2H\" | \"P1D\" | 60 (minutes) }\n\n## Actions — side-effect sinks\n- \\`action.send\\` — post a message to any channel. config: { \"channel\": \"telegram\"|\"whatsapp\"|…, \"chatId\": \"{{trigger.chatId}}\", \"text\": \"Hi {{classify.reply}}\", \"accountId\"?: \"…\" }\n- \\`action.createIssue\\` — open a GitLab issue. config: { \"channel\": \"gitlab\", \"project\": \"noqta/web\", \"title\": \"…\", \"description\": \"…\", \"labels\": [\"x\"], \"assignees\": [\"user\"] }\n- \\`action.setLabel\\` / \\`action.readLabel\\` / \\`action.react\\` / \\`action.editMessage\\` / \\`action.logTime\\` — self-explanatory; each maps 1:1 to a channel adapter method.\n- \\`action.callHTTP\\` — outbound HTTP. config: { \"method\": \"POST\"|\"GET\"|…, \"url\": \"https://…\", \"headers\": {}, \"body\": {}, \"timeoutMs\": 30000 }\n\n## Terminal\n- \\`end\\` — completes the run. config: { \"status\": \"completed\" | \"failed\" | \"canceled\" }\n\n## FormSchema (used by userTask + trigger.form)\n{\n \"title\": \"Review application\",\n \"description\": \"…\",\n \"fields\": [\n { \"key\": \"score\", \"label\": \"Score\", \"type\": \"number\", \"required\": true, \"validate\": { \"min\": 1, \"max\": 10 } },\n { \"key\": \"verdict\", \"label\": \"Verdict\", \"type\": \"select\", \"required\": true, \"options\": [\"approve\", \"reject\"] },\n { \"key\": \"notes\", \"label\": \"Notes\", \"type\": \"long-text\" }\n ],\n \"submitLabel\": \"Approve\",\n \"secondaryAction\": { \"key\": \"reject\", \"label\": \"Reject\" }\n}\nField types: text, long-text, number, boolean, date, select, multi-select, file.\nA form with a \\`secondaryAction\\` and no required-unfilled fields renders as one-tap Approve/Reject buttons in chat.\n\n## Templates\nEvery prompt + config value can reference \\`{{nodeId.path}}\\` against the run context. Examples:\n {{trigger.values.amount}} — field from the start form\n {{classify.result}} — parsed RESULT: token from an agent node\n {{review.values.score}} — submitted userTask field\n {{env.GITLAB_TOKEN}} — env var (must be listed in workflow.envAllow)\n\n## Edges\n[{ \"from\": \"nodeId\", \"to\": \"nodeId\" }, { \"from\": \"branchId\", \"fromPort\": \"case-label\", \"to\": \"nodeId\" }]\nEvery edge's from/to must reference an existing node. Branch + rule nodes MUST have outgoing edges whose fromPort matches a declared case/rule/default.\n\n## Workflow shell\n{\n \"id\": \"lower-kebab-id\",\n \"version\": 2,\n \"title\": \"Human readable\",\n \"description\": \"optional\",\n \"priority\": 0,\n \"fanOut\": false,\n \"envAllow\": [],\n \"maxChildDepth\": 5,\n \"retention\": { \"maxRuns\": 500, \"maxDays\": 90 },\n \"nodes\": [...],\n \"edges\": [...]\n}\n\n## Lint rules (all enforced on save)\n- exactly one trigger.* node\n- every edge references an existing node\n- every node is reachable from the trigger\n- at least one end/checkpoint/userTask/subProcess/signal.wait/timer.boundary is reachable\n- branch + rule outgoing fromPort values match declared cases (or default)\n- cycles are only allowed when the cycle crosses an agent/checkpoint/userTask/subProcess/signal.wait/timer.boundary`\n\nconst RESPONSE_RULES = `# Your reply\n\nRespond in ONE of two ways:\n\n1. **Clarification**: if the user's request is ambiguous, ask exactly ONE short follow-up question. No JSON.\n\n2. **Workflow**: if you have enough to produce a workflow, reply with:\n - 1–3 short lines explaining what you built\n - a \\`\\`\\`json code block containing the complete, valid V2 workflow\n - (no prose after the JSON block)\n\nOnly reference agent ids, actor ids, role ids, and channel names that\nappear in the Environment section above. If the user asks for an agent\nthat doesn't exist, tell them which agent to register first. Never\ninvent workflowIds for subProcess that aren't in the existing list.`"],"mappings":"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","names":["buildWorkflowAuthorPrompt","args","workflows","w","actorIds","a","roleIds","r","parts","SYSTEM_HEADER","NODE_CATALOG","id","c","m","tag","RESPONSE_RULES","extractWorkflowJson","reply","fenced","candidates","braceMatch","raw","parsed"]}
|
package/dist/heal-YEQYWX2L.js
DELETED
package/dist/inbox-BIN2S5XN.js
DELETED
package/dist/program-GZOJIWTB.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{a}from"./chunk-OPKQNLGX.js";import"./chunk-WHP4I44J.js";import"./chunk-CNNLREHD.js";import"./chunk-KX626FN4.js";import"./chunk-GV7S5BAX.js";import"./chunk-SZDACK6O.js";import"./chunk-GSX4NK2N.js";import"./chunk-X5D5AV5N.js";import"./chunk-2HXSJYAJ.js";import"./chunk-N67JZAXU.js";import"./chunk-AFRHKA7B.js";import"./chunk-EW27SCCC.js";import"./chunk-VYLZ7UYM.js";import"./chunk-SFQUP3BP.js";import"./chunk-ABVZHJUO.js";import"./chunk-P3TJHGO5.js";import"./chunk-CO4YCIIA.js";import"./chunk-BHSPAP4U.js";import"./chunk-CDNWCYF7.js";import"./chunk-OZOQKPJV.js";import"./chunk-5F3J55LG.js";import"./chunk-GOLZ6NEL.js";import"./chunk-WJXU5F4Z.js";import"./chunk-VWTBHLMX.js";import"./chunk-7P5QRX5W.js";import"./chunk-JTJIPNXY.js";import"./chunk-64P4QHSZ.js";import"./chunk-BFZUG66X.js";import"./chunk-SR3X25TN.js";import"./chunk-53NRX2NA.js";import"./chunk-A6BKSZQA.js";import"./chunk-JGXE2YNV.js";import"./chunk-VJUTQAPJ.js";import"./chunk-DJEZ2HVU.js";import"./chunk-DSYKYZMT.js";import"./chunk-IKBHHTIT.js";import"./chunk-QOYAX2FT.js";import"./chunk-4YCH6IZV.js";export{a as buildProgram};
|
|
2
|
-
//# sourceMappingURL=program-GZOJIWTB.js.map
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{i as a,j as b,k as c,l as d,m as e,n as f}from"./chunk-OZOQKPJV.js";import"./chunk-5F3J55LG.js";import"./chunk-GOLZ6NEL.js";import"./chunk-WJXU5F4Z.js";import"./chunk-VWTBHLMX.js";import"./chunk-7P5QRX5W.js";import"./chunk-JTJIPNXY.js";import"./chunk-64P4QHSZ.js";import"./chunk-BFZUG66X.js";import"./chunk-SR3X25TN.js";import"./chunk-53NRX2NA.js";import"./chunk-A6BKSZQA.js";import"./chunk-JGXE2YNV.js";import"./chunk-VJUTQAPJ.js";import"./chunk-DSYKYZMT.js";import"./chunk-IKBHHTIT.js";import"./chunk-QOYAX2FT.js";import"./chunk-4YCH6IZV.js";export{f as AgentRegistry,c as TRACE_STEP_SUMMARY_BYTES,d as clipForTrace,e as emitTraceStepsFromStreamEvent,b as getGlobalRegistry,a as setGlobalRegistry};
|
|
2
|
-
//# sourceMappingURL=registry-QZIUSQ5J.js.map
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import{a as l}from"./chunk-A6BKSZQA.js";import"./chunk-4YCH6IZV.js";import{execFile as f}from"child_process";var h=3e4,g="haiku",w=`You are about to lose this working session due to context-size rotation. Before that happens, write a compact memo of what you should carry forward to your next session on the same conversation.
|
|
2
|
-
|
|
3
|
-
Include only durable facts a future turn would otherwise have to rediscover:
|
|
4
|
-
- Names, handles, agent ids, telegram/whatsapp/gitlab usernames
|
|
5
|
-
- File paths, URLs, project namespaces, ssh hosts, ports
|
|
6
|
-
- Decisions made and their reasoning
|
|
7
|
-
- Open tasks or commitments to follow up on
|
|
8
|
-
- Identifiers (issue numbers, PR numbers, ticket ids) the user referred to
|
|
9
|
-
|
|
10
|
-
Format: 3-12 short bullet points. Each \u2264120 chars. No prose, no preamble, no header. If the session was uninformative or just casual chat, reply with exactly the literal text "(no memo)".
|
|
11
|
-
|
|
12
|
-
Begin the memo now.`;async function k(n,r){let m=Date.now();if(!r)return{memo:null,reason:"no-resume",durationMs:0};let i=["-p",w,"--output-format","json","--resume",r,"--model",g];n.permissionMode==="bypassPermissions"&&i.push("--dangerously-skip-permissions");let c=l(n.workspace);return new Promise(p=>{let a=!1,e=(t,s)=>{a||(a=!0,p({memo:t,reason:s,durationMs:Date.now()-m}))};f("claude",i,{cwd:n.workspace,env:c,timeout:h,maxBuffer:1024*1024},(t,s,y)=>{if(t)return t.killed?e(null,"timeout"):e(null,`error:${t.message.slice(0,80)}`);try{let u=JSON.parse(s||"{}"),o=typeof u.result=="string"?u.result.trim():"";if(!o||o==="(no memo)")return e(null,"empty");let d=o.length>4096?o.slice(0,4096)+"\u2026":o;return e(d,"ok")}catch{return e(null,"parse-error")}}).on("error",()=>e(null,"spawn-error"))})}export{k as extractRotationMemo};
|
|
13
|
-
//# sourceMappingURL=rotation-memo-GMTZPMNE.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/agents/rotation-memo.ts"],"sourcesContent":["import { execFile } from \"child_process\"\nimport type { AgentDef } from \"@/daemon/config\"\nimport { buildAgentEnv } from \"@/utils/workspace-env\"\n\n// --- Pre-rotation memo extraction ---\n//\n// Just before agentx clears `claudeSessionId` (tier-2 / max-turns / stale\n// rotation), we ask the dying Claude session to dump the facts and\n// decisions it should carry forward. The agent has full working-memory\n// of its tool-use history at this moment — the only chance to capture\n// it before --resume is dropped and the next turn starts with a blank\n// session.\n//\n// The memo persists into MemoryStore, where the existing findRelevant\n// path injects it into future turns naturally. No new wiring on the\n// read side; one-shot LLM call on the write side.\n//\n// Hard rule: never block rotation. Timeout, errors, empty memos all\n// mean \"skip this round of memo capture\". Memory continuity is a\n// best-effort enhancement, not a correctness requirement.\n\nconst MEMO_TIMEOUT_MS = 30_000\nconst MEMO_MODEL = \"haiku\" // cheapest fast model — memo is summarisation, not reasoning\n\nconst MEMO_PROMPT =\n \"You are about to lose this working session due to context-size rotation. \" +\n \"Before that happens, write a compact memo of what you should carry forward \" +\n \"to your next session on the same conversation.\\n\\n\" +\n \"Include only durable facts a future turn would otherwise have to rediscover:\\n\" +\n \"- Names, handles, agent ids, telegram/whatsapp/gitlab usernames\\n\" +\n \"- File paths, URLs, project namespaces, ssh hosts, ports\\n\" +\n \"- Decisions made and their reasoning\\n\" +\n \"- Open tasks or commitments to follow up on\\n\" +\n \"- Identifiers (issue numbers, PR numbers, ticket ids) the user referred to\\n\\n\" +\n \"Format: 3-12 short bullet points. Each ≤120 chars. No prose, no preamble, \" +\n \"no header. If the session was uninformative or just casual chat, reply with \" +\n \"exactly the literal text \\\"(no memo)\\\".\\n\\n\" +\n \"Begin the memo now.\"\n\nexport interface RotationMemoResult {\n /** The extracted memo text, or null when extraction failed/skipped. */\n memo: string | null\n /** Why we skipped or what happened — \"ok\", \"timeout\", \"error\", \"empty\", \"no-resume\". */\n reason: string\n /** Wall-clock time spent in the extractor. */\n durationMs: number\n}\n\n/** Ask the dying Claude session for a carry-forward memo. Spawns one\n * short claude CLI call with --resume on the about-to-be-dropped\n * session id, asks for a compact memo, returns the text. Never throws\n * — every failure mode resolves with `memo=null` so the caller can\n * proceed with the rotation regardless. */\nexport async function extractRotationMemo(\n agent: AgentDef,\n resumeSessionId: string | undefined,\n): Promise<RotationMemoResult> {\n const start = Date.now()\n if (!resumeSessionId) {\n return { memo: null, reason: \"no-resume\", durationMs: 0 }\n }\n\n const args: string[] = [\n \"-p\", MEMO_PROMPT,\n \"--output-format\", \"json\",\n \"--resume\", resumeSessionId,\n \"--model\", MEMO_MODEL,\n ]\n if (agent.permissionMode === \"bypassPermissions\") {\n args.push(\"--dangerously-skip-permissions\")\n }\n\n const env = buildAgentEnv(agent.workspace)\n\n return new Promise<RotationMemoResult>((resolve) => {\n let settled = false\n const finish = (memo: string | null, reason: string) => {\n if (settled) return\n settled = true\n resolve({ memo, reason, durationMs: Date.now() - start })\n }\n\n const child = execFile(\n \"claude\",\n args,\n {\n cwd: agent.workspace,\n env,\n timeout: MEMO_TIMEOUT_MS,\n maxBuffer: 1024 * 1024, // 1 MB; the memo itself is tiny\n },\n (err, stdout, _stderr) => {\n if (err) {\n // execFile signals timeout via signal SIGTERM + err.killed\n if ((err as NodeJS.ErrnoException & { killed?: boolean }).killed) {\n return finish(null, \"timeout\")\n }\n return finish(null, `error:${err.message.slice(0, 80)}`)\n }\n try {\n const data = JSON.parse(stdout || \"{}\")\n // claude -p --output-format json yields { result, ... }\n const text = typeof data.result === \"string\" ? data.result.trim() : \"\"\n if (!text || text === \"(no memo)\") return finish(null, \"empty\")\n // Defensive cap: memos > 4 KB are almost certainly the LLM\n // ignoring instructions and dumping prose. Truncate.\n const capped = text.length > 4096 ? text.slice(0, 4096) + \"…\" : text\n return finish(capped, \"ok\")\n } catch {\n return finish(null, \"parse-error\")\n }\n },\n )\n child.on(\"error\", () => finish(null, \"spawn-error\"))\n })\n}\n"],"mappings":"oEAAA,OAAS,YAAAA,MAAgB,gBAqBzB,IAAMC,EAAkB,IAClBC,EAAa,QAEbC,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBA4BF,eAAsBC,EACpBC,EACAC,EAC6B,CAC7B,IAAMC,EAAQ,KAAK,IAAI,EACvB,GAAI,CAACD,EACH,MAAO,CAAE,KAAM,KAAM,OAAQ,YAAa,WAAY,CAAE,EAG1D,IAAME,EAAiB,CACrB,KAAML,EACN,kBAAmB,OACnB,WAAYG,EACZ,UAAWJ,CACb,EACIG,EAAM,iBAAmB,qBAC3BG,EAAK,KAAK,gCAAgC,EAG5C,IAAMC,EAAMC,EAAcL,EAAM,SAAS,EAEzC,OAAO,IAAI,QAA6BM,GAAY,CAClD,IAAIC,EAAU,GACRC,EAAS,CAACC,EAAqBC,IAAmB,CAClDH,IACJA,EAAU,GACVD,EAAQ,CAAE,KAAAG,EAAM,OAAAC,EAAQ,WAAY,KAAK,IAAI,EAAIR,CAAM,CAAC,EAC1D,EAEcS,EACZ,SACAR,EACA,CACE,IAAKH,EAAM,UACX,IAAAI,EACA,QAASR,EACT,UAAW,KAAO,IACpB,EACA,CAACgB,EAAKC,EAAQC,IAAY,CACxB,GAAIF,EAEF,OAAKA,EAAqD,OACjDJ,EAAO,KAAM,SAAS,EAExBA,EAAO,KAAM,SAASI,EAAI,QAAQ,MAAM,EAAG,EAAE,GAAG,EAEzD,GAAI,CACF,IAAMG,EAAO,KAAK,MAAMF,GAAU,IAAI,EAEhCG,EAAO,OAAOD,EAAK,QAAW,SAAWA,EAAK,OAAO,KAAK,EAAI,GACpE,GAAI,CAACC,GAAQA,IAAS,YAAa,OAAOR,EAAO,KAAM,OAAO,EAG9D,IAAMS,EAASD,EAAK,OAAS,KAAOA,EAAK,MAAM,EAAG,IAAI,EAAI,SAAMA,EAChE,OAAOR,EAAOS,EAAQ,IAAI,CAC5B,MAAE,CACA,OAAOT,EAAO,KAAM,aAAa,CACnC,CACF,CACF,EACM,GAAG,QAAS,IAAMA,EAAO,KAAM,aAAa,CAAC,CACrD,CAAC,CACH","names":["execFile","MEMO_TIMEOUT_MS","MEMO_MODEL","MEMO_PROMPT","extractRotationMemo","agent","resumeSessionId","start","args","env","buildAgentEnv","resolve","settled","finish","memo","reason","execFile","err","stdout","_stderr","data","text","capped"]}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{e as a,f as b}from"./chunk-ABVZHJUO.js";import"./chunk-P3TJHGO5.js";import"./chunk-CO4YCIIA.js";import"./chunk-GOLZ6NEL.js";import"./chunk-VJUTQAPJ.js";import"./chunk-4YCH6IZV.js";export{b as CronScheduler,a as getNextCronDate};
|
|
2
|
-
//# sourceMappingURL=scheduler-B2BQPV4M.js.map
|
package/dist/slack-6P7ZJ32Y.js
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import"./chunk-4YCH6IZV.js";function m(e){let r=e.log??(()=>{});return async function(o){let n=e.inboxBaseUrl??"",s=f(o);for(let d of o.assignedTo){let c=e.actors.channelFor(d,"slack");if(!c)continue;let a=u(o,d,n,s);try{let t=await e.adapter.send({channel:"slack",chatId:c,text:a,parseMode:"markdown"}),l=[...o.delivered??[],{channel:"slack",handle:c,messageId:typeof t=="string"?t:void 0,at:new Date().toISOString()}];e.tasks.save({...o,delivered:l})}catch(t){r(`[task:${o.id}] slack delivery to ${d}@${c} failed: ${t?.message??t}`)}}}}function f(e){if(!e.form.secondaryAction)return!1;for(let r of e.form.fields??[])if(r.required&&r.defaultValue===void 0)return!1;return!0}function u(e,r,i,o){let n=[];if(n.push(`*${e.title}*`),e.description&&n.push("",e.description),!o&&e.form.fields?.length){n.push("","*Fields*:");for(let s of e.form.fields)n.push(`\u2022 ${s.label}${s.required?" (required)":""}`)}return e.dueAt&&n.push("",`:clock3: Due: ${new Date(e.dueAt).toLocaleString()}`),o?(n.push("",`:white_check_mark: <${i}/t/${encodeURIComponent(e.id)}/primary?actor=${encodeURIComponent(r)}|${e.form.submitLabel||"Approve"}>`),e.form.secondaryAction&&n.push(`:x: <${i}/t/${encodeURIComponent(e.id)}/secondary?actor=${encodeURIComponent(r)}|${e.form.secondaryAction.label}>`)):n.push("",`<${i}/inbox?actor=${encodeURIComponent(r)}|Open form>`),n.join(`
|
|
2
|
-
`)}export{m as createSlackTaskRenderer};
|
|
3
|
-
//# sourceMappingURL=slack-6P7ZJ32Y.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/forms/renderers/slack.ts"],"sourcesContent":["import type { UserTaskRecord, TaskStore } from \"../../workflows/task-store\"\nimport type { ActorStore } from \"../../actors/store\"\n\n// --- Slack user-task renderer ---\n//\n// Mirrors the Telegram/WhatsApp Phase 3 renderers. Delivers a plain-text\n// message to the assignee's Slack member id, with one-click approve/\n// reject URLs when the form is shaped that way, or a deep-link to the\n// web inbox for forms with required fields.\n//\n// Block Kit interactive elements (rich buttons with callback handling)\n// would need the adapter to surface Slack's interactive-message webhook.\n// For parity with the other Phase 3 renderers we stick with text + URLs,\n// which works everywhere Slack works and needs no extra plumbing.\n\ninterface SendingAdapter {\n send: (msg: { channel: string; chatId: string; text: string; parseMode?: \"markdown\" | \"html\" | \"plain\" }) => Promise<string | void>\n}\n\nexport interface SlackRendererOptions {\n actors: ActorStore\n tasks: TaskStore\n adapter: SendingAdapter\n inboxBaseUrl?: string\n log?: (msg: string) => void\n}\n\nexport function createSlackTaskRenderer(opts: SlackRendererOptions) {\n const log = opts.log ?? (() => {})\n return async function render(task: UserTaskRecord): Promise<void> {\n const baseUrl = opts.inboxBaseUrl ?? \"\"\n const oneClick = canOneClickSubmit(task)\n for (const actorId of task.assignedTo) {\n const handle = opts.actors.channelFor(actorId, \"slack\")\n if (!handle) continue\n const text = buildText(task, actorId, baseUrl, oneClick)\n try {\n const messageId = await opts.adapter.send({\n channel: \"slack\",\n chatId: handle,\n text,\n parseMode: \"markdown\",\n })\n const delivered = [\n ...(task.delivered ?? []),\n {\n channel: \"slack\",\n handle,\n messageId: typeof messageId === \"string\" ? messageId : undefined,\n at: new Date().toISOString(),\n },\n ]\n opts.tasks.save({ ...task, delivered })\n } catch (e: any) {\n log(`[task:${task.id}] slack delivery to ${actorId}@${handle} failed: ${e?.message ?? e}`)\n }\n }\n }\n}\n\nfunction canOneClickSubmit(task: UserTaskRecord): boolean {\n if (!task.form.secondaryAction) return false\n for (const f of task.form.fields ?? []) {\n if (f.required && f.defaultValue === undefined) return false\n }\n return true\n}\n\nfunction buildText(task: UserTaskRecord, actorId: string, baseUrl: string, oneClick: boolean): string {\n const lines: string[] = []\n lines.push(`*${task.title}*`)\n if (task.description) lines.push(\"\", task.description)\n if (!oneClick && task.form.fields?.length) {\n lines.push(\"\", \"*Fields*:\")\n for (const f of task.form.fields) lines.push(`• ${f.label}${f.required ? \" (required)\" : \"\"}`)\n }\n if (task.dueAt) lines.push(\"\", `:clock3: Due: ${new Date(task.dueAt).toLocaleString()}`)\n if (oneClick) {\n lines.push(\n \"\",\n `:white_check_mark: <${baseUrl}/t/${encodeURIComponent(task.id)}/primary?actor=${encodeURIComponent(actorId)}|${task.form.submitLabel || \"Approve\"}>`,\n )\n if (task.form.secondaryAction) {\n lines.push(\n `:x: <${baseUrl}/t/${encodeURIComponent(task.id)}/secondary?actor=${encodeURIComponent(actorId)}|${task.form.secondaryAction.label}>`,\n )\n }\n } else {\n lines.push(\"\", `<${baseUrl}/inbox?actor=${encodeURIComponent(actorId)}|Open form>`)\n }\n return lines.join(\"\\n\")\n}\n"],"mappings":"4BA2BO,SAASA,EAAwBC,EAA4B,CAClE,IAAMC,EAAMD,EAAK,MAAQ,IAAM,CAAC,GAChC,OAAO,eAAsBE,EAAqC,CAChE,IAAMC,EAAUH,EAAK,cAAgB,GAC/BI,EAAWC,EAAkBH,CAAI,EACvC,QAAWI,KAAWJ,EAAK,WAAY,CACrC,IAAMK,EAASP,EAAK,OAAO,WAAWM,EAAS,OAAO,EACtD,GAAI,CAACC,EAAQ,SACb,IAAMC,EAAOC,EAAUP,EAAMI,EAASH,EAASC,CAAQ,EACvD,GAAI,CACF,IAAMM,EAAY,MAAMV,EAAK,QAAQ,KAAK,CACxC,QAAS,QACT,OAAQO,EACR,KAAAC,EACA,UAAW,UACb,CAAC,EACKG,EAAY,CAChB,GAAIT,EAAK,WAAa,CAAC,EACvB,CACE,QAAS,QACT,OAAAK,EACA,UAAW,OAAOG,GAAc,SAAWA,EAAY,OACvD,GAAI,IAAI,KAAK,EAAE,YAAY,CAC7B,CACF,EACAV,EAAK,MAAM,KAAK,CAAE,GAAGE,EAAM,UAAAS,CAAU,CAAC,CACxC,OAASC,EAAP,CACAX,EAAI,SAASC,EAAK,yBAAyBI,KAAWC,aAAkBK,GAAG,SAAWA,GAAG,CAC3F,EAEJ,CACF,CAEA,SAASP,EAAkBH,EAA+B,CACxD,GAAI,CAACA,EAAK,KAAK,gBAAiB,MAAO,GACvC,QAAWW,KAAKX,EAAK,KAAK,QAAU,CAAC,EACnC,GAAIW,EAAE,UAAYA,EAAE,eAAiB,OAAW,MAAO,GAEzD,MAAO,EACT,CAEA,SAASJ,EAAUP,EAAsBI,EAAiBH,EAAiBC,EAA2B,CACpG,IAAMU,EAAkB,CAAC,EAGzB,GAFAA,EAAM,KAAK,IAAIZ,EAAK,QAAQ,EACxBA,EAAK,aAAaY,EAAM,KAAK,GAAIZ,EAAK,WAAW,EACjD,CAACE,GAAYF,EAAK,KAAK,QAAQ,OAAQ,CACzCY,EAAM,KAAK,GAAI,WAAW,EAC1B,QAAWD,KAAKX,EAAK,KAAK,OAAQY,EAAM,KAAK,UAAKD,EAAE,QAAQA,EAAE,SAAW,cAAgB,IAAI,EAE/F,OAAIX,EAAK,OAAOY,EAAM,KAAK,GAAI,iBAAiB,IAAI,KAAKZ,EAAK,KAAK,EAAE,eAAe,GAAG,EACnFE,GACFU,EAAM,KACJ,GACA,uBAAuBX,OAAa,mBAAmBD,EAAK,EAAE,mBAAmB,mBAAmBI,CAAO,KAAKJ,EAAK,KAAK,aAAe,YAC3I,EACIA,EAAK,KAAK,iBACZY,EAAM,KACJ,QAAQX,OAAa,mBAAmBD,EAAK,EAAE,qBAAqB,mBAAmBI,CAAO,KAAKJ,EAAK,KAAK,gBAAgB,QAC/H,GAGFY,EAAM,KAAK,GAAI,IAAIX,iBAAuB,mBAAmBG,CAAO,cAAc,EAE7EQ,EAAM,KAAK;AAAA,CAAI,CACxB","names":["createSlackTaskRenderer","opts","log","task","baseUrl","oneClick","canOneClickSubmit","actorId","handle","text","buildText","messageId","delivered","e","f","lines"]}
|
package/dist/store-BAPDZHXE.js
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import"./chunk-4YCH6IZV.js";function p(e){let i=e.log??(()=>{});return async function(n){let d=e.inboxBaseUrl??"",r=g(n.form);for(let t of n.assignedTo){let o=e.actors.channelFor(t,"telegram");if(!o)continue;let l=m(n,t,d,r);try{let s;if(r&&e.adapter.sendWithInlineButtons){let a=[{label:n.form.submitLabel||"Approve",url:`${d}/t/${encodeURIComponent(n.id)}/primary?actor=${encodeURIComponent(t)}`},...n.form.secondaryAction?[{label:n.form.secondaryAction.label,url:`${d}/t/${encodeURIComponent(n.id)}/secondary?actor=${encodeURIComponent(t)}`}]:[]],f=await e.adapter.sendWithInlineButtons({chatId:o,text:l,parseMode:"markdown",buttons:a});s=typeof f=="string"?f:void 0}else{let a=await e.adapter.sendMessage({chatId:o,text:l,parseMode:"markdown"});s=typeof a=="string"?a:void 0}let u=[...n.delivered??[],{channel:"telegram",handle:o,messageId:s,at:new Date().toISOString()}];e.tasks.save({...n,delivered:u})}catch(s){i(`[task:${n.id}] telegram delivery to ${t}@${o} failed: ${s?.message??s}`)}}}}function g(e){if(!e.secondaryAction)return!1;for(let i of e.fields??[])if(i.required&&i.defaultValue===void 0)return!1;return!0}function m(e,i,c,n){let d=`${c}/inbox?actor=${encodeURIComponent(i)}`,r=[];if(r.push(`\u{1F4CB} **${e.title}**`),e.description&&r.push("",e.description),!n&&e.form.fields?.length){r.push("","_Fields_:");for(let t of e.form.fields){let o=t.required?" *(required)*":"";r.push(`\u2022 ${t.label}${o}`)}}return e.dueAt&&r.push("",`\u23F0 Due: ${new Date(e.dueAt).toLocaleString()}`),n||r.push("",`[Open form \u2192](${d})`),r.join(`
|
|
2
|
-
`)}export{p as createTelegramTaskRenderer};
|
|
3
|
-
//# sourceMappingURL=telegram-PIYDRM46.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/forms/renderers/telegram.ts"],"sourcesContent":["import type { UserTaskRecord, TaskStore } from \"../../workflows/task-store\"\nimport type { ActorStore } from \"../../actors/store\"\nimport type { FormSchema } from \"../types\"\n\n// --- Telegram user-task renderer ---\n//\n// Delivers a user-task notification to the assignee's Telegram chat.\n//\n// Two delivery shapes:\n// 1. Approve/reject (form has a secondaryAction AND no required fields\n// that lack defaults) — inline-keyboard with two URL buttons that\n// one-tap-submit via `GET /t/:taskId/:action`. No web visit required.\n// 2. Full-form (any form with required fields) — plain message with a\n// deep link to the web inbox where the user fills in values.\n//\n// The one-click URL pattern uses URL buttons (not callback_data) so we\n// don't need to wire callback_query handling into the adapter polling\n// loop for Phase 3 MVP.\n\ninterface SendingAdapter {\n sendMessage: (msg: { chatId: string; text: string; parseMode?: string; accountId?: string }) => Promise<string | undefined | void>\n sendWithInlineButtons?: (args: {\n chatId: string\n text: string\n buttons: Array<{ label: string; url: string }>\n parseMode?: \"markdown\" | \"html\" | \"plain\"\n accountId?: string\n }) => Promise<string | undefined | void>\n}\n\nexport interface TelegramRendererOptions {\n actors: ActorStore\n tasks: TaskStore\n inboxBaseUrl?: string\n adapter: SendingAdapter\n log?: (msg: string) => void\n}\n\nexport function createTelegramTaskRenderer(opts: TelegramRendererOptions) {\n const log = opts.log ?? (() => {})\n return async function render(task: UserTaskRecord): Promise<void> {\n const baseUrl = opts.inboxBaseUrl ?? \"\"\n const oneClick = canOneClickSubmit(task.form)\n\n for (const actorId of task.assignedTo) {\n const handle = opts.actors.channelFor(actorId, \"telegram\")\n if (!handle) continue\n const text = buildTaskText(task, actorId, baseUrl, oneClick)\n\n try {\n let messageId: string | undefined\n if (oneClick && opts.adapter.sendWithInlineButtons) {\n const buttons = [\n { label: task.form.submitLabel || \"Approve\", url: `${baseUrl}/t/${encodeURIComponent(task.id)}/primary?actor=${encodeURIComponent(actorId)}` },\n ...(task.form.secondaryAction ? [{\n label: task.form.secondaryAction.label,\n url: `${baseUrl}/t/${encodeURIComponent(task.id)}/secondary?actor=${encodeURIComponent(actorId)}`,\n }] : []),\n ]\n const r = await opts.adapter.sendWithInlineButtons({\n chatId: handle, text, parseMode: \"markdown\", buttons,\n })\n messageId = typeof r === \"string\" ? r : undefined\n } else {\n const r = await opts.adapter.sendMessage({ chatId: handle, text, parseMode: \"markdown\" })\n messageId = typeof r === \"string\" ? r : undefined\n }\n const delivered = [\n ...(task.delivered ?? []),\n { channel: \"telegram\", handle, messageId, at: new Date().toISOString() },\n ]\n opts.tasks.save({ ...task, delivered })\n } catch (e: any) {\n log(`[task:${task.id}] telegram delivery to ${actorId}@${handle} failed: ${e?.message ?? e}`)\n }\n }\n }\n}\n\n/** A form is one-click-submittable when it has a primary + secondary\n * action AND no required field without a defaultValue. Pure approve/\n * reject forms (no fields at all, or all fields optional with defaults)\n * fit this shape. */\nfunction canOneClickSubmit(form: FormSchema): boolean {\n if (!form.secondaryAction) return false\n for (const f of form.fields ?? []) {\n if (f.required && f.defaultValue === undefined) return false\n }\n return true\n}\n\nfunction buildTaskText(task: UserTaskRecord, actorId: string, baseUrl: string, oneClick: boolean): string {\n const inboxUrl = `${baseUrl}/inbox?actor=${encodeURIComponent(actorId)}`\n const lines: string[] = []\n lines.push(`📋 **${task.title}**`)\n if (task.description) lines.push(\"\", task.description)\n if (!oneClick && task.form.fields?.length) {\n lines.push(\"\", \"_Fields_:\")\n for (const f of task.form.fields) {\n const required = f.required ? \" *(required)*\" : \"\"\n lines.push(`• ${f.label}${required}`)\n }\n }\n if (task.dueAt) lines.push(\"\", `⏰ Due: ${new Date(task.dueAt).toLocaleString()}`)\n if (!oneClick) lines.push(\"\", `[Open form →](${inboxUrl})`)\n return lines.join(\"\\n\")\n}\n"],"mappings":"4BAsCO,SAASA,EAA2BC,EAA+B,CACxE,IAAMC,EAAMD,EAAK,MAAQ,IAAM,CAAC,GAChC,OAAO,eAAsBE,EAAqC,CAChE,IAAMC,EAAUH,EAAK,cAAgB,GAC/BI,EAAWC,EAAkBH,EAAK,IAAI,EAE5C,QAAWI,KAAWJ,EAAK,WAAY,CACrC,IAAMK,EAASP,EAAK,OAAO,WAAWM,EAAS,UAAU,EACzD,GAAI,CAACC,EAAQ,SACb,IAAMC,EAAOC,EAAcP,EAAMI,EAASH,EAASC,CAAQ,EAE3D,GAAI,CACF,IAAIM,EACJ,GAAIN,GAAYJ,EAAK,QAAQ,sBAAuB,CAClD,IAAMW,EAAU,CACd,CAAE,MAAOT,EAAK,KAAK,aAAe,UAAW,IAAK,GAAGC,OAAa,mBAAmBD,EAAK,EAAE,mBAAmB,mBAAmBI,CAAO,GAAI,EAC7I,GAAIJ,EAAK,KAAK,gBAAkB,CAAC,CAC/B,MAAOA,EAAK,KAAK,gBAAgB,MACjC,IAAK,GAAGC,OAAa,mBAAmBD,EAAK,EAAE,qBAAqB,mBAAmBI,CAAO,GAChG,CAAC,EAAI,CAAC,CACR,EACMM,EAAI,MAAMZ,EAAK,QAAQ,sBAAsB,CACjD,OAAQO,EAAQ,KAAAC,EAAM,UAAW,WAAY,QAAAG,CAC/C,CAAC,EACDD,EAAY,OAAOE,GAAM,SAAWA,EAAI,WACnC,CACL,IAAMA,EAAI,MAAMZ,EAAK,QAAQ,YAAY,CAAE,OAAQO,EAAQ,KAAAC,EAAM,UAAW,UAAW,CAAC,EACxFE,EAAY,OAAOE,GAAM,SAAWA,EAAI,OAE1C,IAAMC,EAAY,CAChB,GAAIX,EAAK,WAAa,CAAC,EACvB,CAAE,QAAS,WAAY,OAAAK,EAAQ,UAAAG,EAAW,GAAI,IAAI,KAAK,EAAE,YAAY,CAAE,CACzE,EACAV,EAAK,MAAM,KAAK,CAAE,GAAGE,EAAM,UAAAW,CAAU,CAAC,CACxC,OAASC,EAAP,CACAb,EAAI,SAASC,EAAK,4BAA4BI,KAAWC,aAAkBO,GAAG,SAAWA,GAAG,CAC9F,EAEJ,CACF,CAMA,SAAST,EAAkBU,EAA2B,CACpD,GAAI,CAACA,EAAK,gBAAiB,MAAO,GAClC,QAAWC,KAAKD,EAAK,QAAU,CAAC,EAC9B,GAAIC,EAAE,UAAYA,EAAE,eAAiB,OAAW,MAAO,GAEzD,MAAO,EACT,CAEA,SAASP,EAAcP,EAAsBI,EAAiBH,EAAiBC,EAA2B,CACxG,IAAMa,EAAW,GAAGd,iBAAuB,mBAAmBG,CAAO,IAC/DY,EAAkB,CAAC,EAGzB,GAFAA,EAAM,KAAK,eAAQhB,EAAK,SAAS,EAC7BA,EAAK,aAAagB,EAAM,KAAK,GAAIhB,EAAK,WAAW,EACjD,CAACE,GAAYF,EAAK,KAAK,QAAQ,OAAQ,CACzCgB,EAAM,KAAK,GAAI,WAAW,EAC1B,QAAWF,KAAKd,EAAK,KAAK,OAAQ,CAChC,IAAMiB,EAAWH,EAAE,SAAW,gBAAkB,GAChDE,EAAM,KAAK,UAAKF,EAAE,QAAQG,GAAU,GAGxC,OAAIjB,EAAK,OAAOgB,EAAM,KAAK,GAAI,eAAU,IAAI,KAAKhB,EAAK,KAAK,EAAE,eAAe,GAAG,EAC3EE,GAAUc,EAAM,KAAK,GAAI,sBAAiBD,IAAW,EACnDC,EAAM,KAAK;AAAA,CAAI,CACxB","names":["createTelegramTaskRenderer","opts","log","task","baseUrl","oneClick","canOneClickSubmit","actorId","handle","text","buildTaskText","messageId","buttons","r","delivered","e","form","f","inboxUrl","lines","required"]}
|
package/dist/types-ZRLHHCGB.js
DELETED