openryoko 2026.5.7 → 2026.5.13

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.
Files changed (152) hide show
  1. package/dist/package.json +1 -1
  2. package/dist/src/cli/migrate.d.ts.map +1 -1
  3. package/dist/src/cli/migrate.js +42 -14
  4. package/dist/src/cli/migrate.js.map +1 -1
  5. package/dist/src/cli/setup.d.ts.map +1 -1
  6. package/dist/src/cli/setup.js +4 -27
  7. package/dist/src/cli/setup.js.map +1 -1
  8. package/dist/src/connectors/slack/__tests__/agents-canvas.test.d.ts +2 -0
  9. package/dist/src/connectors/slack/__tests__/agents-canvas.test.d.ts.map +1 -0
  10. package/dist/src/connectors/slack/__tests__/agents-canvas.test.js +191 -0
  11. package/dist/src/connectors/slack/__tests__/agents-canvas.test.js.map +1 -0
  12. package/dist/src/connectors/slack/__tests__/goal-extractor.test.d.ts +2 -0
  13. package/dist/src/connectors/slack/__tests__/goal-extractor.test.d.ts.map +1 -0
  14. package/dist/src/connectors/slack/__tests__/goal-extractor.test.js +129 -0
  15. package/dist/src/connectors/slack/__tests__/goal-extractor.test.js.map +1 -0
  16. package/dist/src/connectors/slack/agents-canvas.d.ts +59 -0
  17. package/dist/src/connectors/slack/agents-canvas.d.ts.map +1 -0
  18. package/dist/src/connectors/slack/agents-canvas.js +372 -0
  19. package/dist/src/connectors/slack/agents-canvas.js.map +1 -0
  20. package/dist/src/connectors/slack/goal-extractor.d.ts +67 -0
  21. package/dist/src/connectors/slack/goal-extractor.d.ts.map +1 -0
  22. package/dist/src/connectors/slack/goal-extractor.js +302 -0
  23. package/dist/src/connectors/slack/goal-extractor.js.map +1 -0
  24. package/dist/src/connectors/slack/index.d.ts +15 -0
  25. package/dist/src/connectors/slack/index.d.ts.map +1 -1
  26. package/dist/src/connectors/slack/index.js +78 -0
  27. package/dist/src/connectors/slack/index.js.map +1 -1
  28. package/dist/src/engines/claude.d.ts +11 -0
  29. package/dist/src/engines/claude.d.ts.map +1 -1
  30. package/dist/src/engines/claude.js +75 -13
  31. package/dist/src/engines/claude.js.map +1 -1
  32. package/dist/src/gateway/api.d.ts.map +1 -1
  33. package/dist/src/gateway/api.js +20 -0
  34. package/dist/src/gateway/api.js.map +1 -1
  35. package/dist/src/gateway/server.d.ts.map +1 -1
  36. package/dist/src/gateway/server.js +61 -2
  37. package/dist/src/gateway/server.js.map +1 -1
  38. package/dist/src/sessions/context.js +20 -2
  39. package/dist/src/sessions/context.js.map +1 -1
  40. package/dist/src/sessions/manager.d.ts.map +1 -1
  41. package/dist/src/sessions/manager.js +15 -1
  42. package/dist/src/sessions/manager.js.map +1 -1
  43. package/dist/src/shared/templateReplacements.d.ts +22 -0
  44. package/dist/src/shared/templateReplacements.d.ts.map +1 -0
  45. package/dist/src/shared/templateReplacements.js +57 -0
  46. package/dist/src/shared/templateReplacements.js.map +1 -0
  47. package/dist/src/shared/types.d.ts +21 -0
  48. package/dist/src/shared/types.d.ts.map +1 -1
  49. package/dist/web/404.html +1 -1
  50. package/dist/web/__next.__PAGE__.txt +2 -2
  51. package/dist/web/__next._full.txt +3 -3
  52. package/dist/web/__next._head.txt +1 -1
  53. package/dist/web/__next._index.txt +2 -2
  54. package/dist/web/__next._tree.txt +2 -2
  55. package/dist/web/_next/static/chunks/{0y3uv64m1qh.k.js → 012aakl34ff5a.js} +2 -2
  56. package/dist/web/_next/static/chunks/{0j4uz-g9x1_~s.js → 0a2uy1kw.~j~c.js} +1 -1
  57. package/dist/web/_next/static/chunks/{0v51a3blij~j6.js → 0agxgztb0b~.7.js} +2 -2
  58. package/dist/web/_next/static/chunks/{1645~4k0qcst0.js → 0g6xt.91k~0bc.js} +2 -2
  59. package/dist/web/_next/static/chunks/{16zc7-yv7supr.js → 0jzw1gpuag8bc.js} +2 -2
  60. package/dist/web/_next/static/chunks/0kceasmxfr3s1.js +1 -0
  61. package/dist/web/_next/static/chunks/{0wv0qjh9tuqx~.js → 0lkp92-ovteta.js} +2 -2
  62. package/dist/web/_next/static/chunks/{1621s_jgljr1_.js → 0msmlzd_~uk0y.js} +2 -2
  63. package/dist/web/_next/static/chunks/{00yn.jp4tr9l6.js → 0z5lzlvft9.4o.js} +2 -2
  64. package/dist/web/_next/static/chunks/103zsy0q9psfj.css +1 -0
  65. package/dist/web/_next/static/chunks/{0ma0h4_2c8y9y.js → 12m97bwrg1tuu.js} +2 -2
  66. package/dist/web/_not-found/__next._full.txt +2 -2
  67. package/dist/web/_not-found/__next._head.txt +1 -1
  68. package/dist/web/_not-found/__next._index.txt +2 -2
  69. package/dist/web/_not-found/__next._not-found.__PAGE__.txt +1 -1
  70. package/dist/web/_not-found/__next._not-found.txt +1 -1
  71. package/dist/web/_not-found/__next._tree.txt +2 -2
  72. package/dist/web/_not-found.html +1 -1
  73. package/dist/web/_not-found.txt +2 -2
  74. package/dist/web/chat/__next._full.txt +3 -3
  75. package/dist/web/chat/__next._head.txt +1 -1
  76. package/dist/web/chat/__next._index.txt +2 -2
  77. package/dist/web/chat/__next._tree.txt +2 -2
  78. package/dist/web/chat/__next.chat.__PAGE__.txt +2 -2
  79. package/dist/web/chat/__next.chat.txt +1 -1
  80. package/dist/web/chat.html +1 -1
  81. package/dist/web/chat.txt +3 -3
  82. package/dist/web/cron/__next._full.txt +3 -3
  83. package/dist/web/cron/__next._head.txt +1 -1
  84. package/dist/web/cron/__next._index.txt +2 -2
  85. package/dist/web/cron/__next._tree.txt +2 -2
  86. package/dist/web/cron/__next.cron.__PAGE__.txt +2 -2
  87. package/dist/web/cron/__next.cron.txt +1 -1
  88. package/dist/web/cron.html +1 -1
  89. package/dist/web/cron.txt +3 -3
  90. package/dist/web/index.html +1 -1
  91. package/dist/web/index.txt +3 -3
  92. package/dist/web/kanban/__next._full.txt +3 -3
  93. package/dist/web/kanban/__next._head.txt +1 -1
  94. package/dist/web/kanban/__next._index.txt +2 -2
  95. package/dist/web/kanban/__next._tree.txt +2 -2
  96. package/dist/web/kanban/__next.kanban.__PAGE__.txt +2 -2
  97. package/dist/web/kanban/__next.kanban.txt +1 -1
  98. package/dist/web/kanban.html +1 -1
  99. package/dist/web/kanban.txt +3 -3
  100. package/dist/web/logs/__next._full.txt +3 -3
  101. package/dist/web/logs/__next._head.txt +1 -1
  102. package/dist/web/logs/__next._index.txt +2 -2
  103. package/dist/web/logs/__next._tree.txt +2 -2
  104. package/dist/web/logs/__next.logs.__PAGE__.txt +2 -2
  105. package/dist/web/logs/__next.logs.txt +1 -1
  106. package/dist/web/logs.html +2 -2
  107. package/dist/web/logs.txt +3 -3
  108. package/dist/web/org/__next._full.txt +3 -3
  109. package/dist/web/org/__next._head.txt +1 -1
  110. package/dist/web/org/__next._index.txt +2 -2
  111. package/dist/web/org/__next._tree.txt +2 -2
  112. package/dist/web/org/__next.org.__PAGE__.txt +2 -2
  113. package/dist/web/org/__next.org.txt +1 -1
  114. package/dist/web/org.html +1 -1
  115. package/dist/web/org.txt +3 -3
  116. package/dist/web/sessions/__next._full.txt +2 -2
  117. package/dist/web/sessions/__next._head.txt +1 -1
  118. package/dist/web/sessions/__next._index.txt +2 -2
  119. package/dist/web/sessions/__next._tree.txt +2 -2
  120. package/dist/web/sessions/__next.sessions.__PAGE__.txt +1 -1
  121. package/dist/web/sessions/__next.sessions.txt +1 -1
  122. package/dist/web/sessions.html +1 -1
  123. package/dist/web/sessions.txt +2 -2
  124. package/dist/web/settings/__next._full.txt +3 -3
  125. package/dist/web/settings/__next._head.txt +1 -1
  126. package/dist/web/settings/__next._index.txt +2 -2
  127. package/dist/web/settings/__next._tree.txt +2 -2
  128. package/dist/web/settings/__next.settings.__PAGE__.txt +2 -2
  129. package/dist/web/settings/__next.settings.txt +1 -1
  130. package/dist/web/settings.html +1 -1
  131. package/dist/web/settings.txt +3 -3
  132. package/dist/web/skills/__next._full.txt +3 -3
  133. package/dist/web/skills/__next._head.txt +1 -1
  134. package/dist/web/skills/__next._index.txt +2 -2
  135. package/dist/web/skills/__next._tree.txt +2 -2
  136. package/dist/web/skills/__next.skills.__PAGE__.txt +2 -2
  137. package/dist/web/skills/__next.skills.txt +1 -1
  138. package/dist/web/skills.html +1 -1
  139. package/dist/web/skills.txt +3 -3
  140. package/package.json +1 -1
  141. package/template/migrations/2026.5.7/files/BOOTSTRAP.md +52 -0
  142. package/template/migrations/2026.5.7/files/IDENTITY.md +25 -0
  143. package/template/migrations/2026.5.7/files/MEMORY.md +33 -0
  144. package/template/migrations/2026.5.7/files/SOUL.md +36 -0
  145. package/template/migrations/2026.5.7/files/TOOLS.md +23 -0
  146. package/template/migrations/2026.5.7/files/memory/.gitkeep +0 -0
  147. package/dist/web/_next/static/chunks/05uy~i7wsbsn3.js +0 -1
  148. package/dist/web/_next/static/chunks/0bj62gv2pext..css +0 -1
  149. package/dist/web/dev/logs/next-development.log +0 -5
  150. /package/dist/web/_next/static/{VBjMXtz9-pIo9izqNT-iu → 2gkySyM5UoStZGUIrVpRy}/_buildManifest.js +0 -0
  151. /package/dist/web/_next/static/{VBjMXtz9-pIo9izqNT-iu → 2gkySyM5UoStZGUIrVpRy}/_clientMiddlewareManifest.js +0 -0
  152. /package/dist/web/_next/static/{VBjMXtz9-pIo9izqNT-iu → 2gkySyM5UoStZGUIrVpRy}/_ssgManifest.js +0 -0
@@ -0,0 +1,129 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { shouldExtractGoal, hasGoalIntent, buildGoalExtractionPrompt, parseGoalExtractionResult, } from "../goal-extractor.js";
3
+ describe("shouldExtractGoal — accepts substantive messages", () => {
4
+ it.each([
5
+ // Substantive task requests (Haiku will decide if they need /goal)
6
+ "OpenRyokoのGithub調査して紹介資料作成まで「最後までやって」",
7
+ "5社のSaaSを比較した表をスレッドに投げて",
8
+ "数字1から3までを別々のターンで出して完了と書いたら止まる",
9
+ "ブログ記事のドラフトを書いて",
10
+ "Just tell me about Tailscale",
11
+ ])("accepts %s", (text) => {
12
+ expect(shouldExtractGoal(text)).toBe(true);
13
+ });
14
+ });
15
+ describe("shouldExtractGoal — skips trivial / pre-prefixed messages", () => {
16
+ it("skips empty", () => {
17
+ expect(shouldExtractGoal("")).toBe(false);
18
+ });
19
+ it("skips whitespace-only", () => {
20
+ expect(shouldExtractGoal(" \n\t ")).toBe(false);
21
+ });
22
+ it("skips very short acknowledgements", () => {
23
+ expect(shouldExtractGoal("ok")).toBe(false);
24
+ expect(shouldExtractGoal("thanks")).toBe(false);
25
+ expect(shouldExtractGoal("はい")).toBe(false);
26
+ expect(shouldExtractGoal("👍")).toBe(false);
27
+ });
28
+ it("skips messages already prefixed with /goal", () => {
29
+ expect(shouldExtractGoal("/goal Posted the comparison\n\nfollow up")).toBe(false);
30
+ });
31
+ });
32
+ describe("hasGoalIntent (deprecated alias)", () => {
33
+ it("forwards to shouldExtractGoal", () => {
34
+ expect(hasGoalIntent("a substantive request")).toBe(true);
35
+ expect(hasGoalIntent("ok")).toBe(false);
36
+ expect(hasGoalIntent("")).toBe(false);
37
+ });
38
+ });
39
+ describe("buildGoalExtractionPrompt", () => {
40
+ it("embeds the user message verbatim", () => {
41
+ const p = buildGoalExtractionPrompt("テスト最後までやってね");
42
+ expect(p).toContain("テスト最後までやってね");
43
+ });
44
+ it("instructs JSON output with condition key", () => {
45
+ const p = buildGoalExtractionPrompt("anything");
46
+ expect(p).toContain('"condition"');
47
+ expect(p).toContain("JSON only");
48
+ });
49
+ it("biases the LLM toward null on ambiguity", () => {
50
+ const p = buildGoalExtractionPrompt("anything");
51
+ expect(p).toContain('{"condition": null}');
52
+ expect(p).toContain("be conservative");
53
+ expect(p).toMatch(/when in doubt[, ]+null/i);
54
+ });
55
+ it("documents the four trigger families (keep-going, notify, embedded stop, pipeline)", () => {
56
+ const p = buildGoalExtractionPrompt("anything");
57
+ expect(p).toContain("完成するまで止まらないで");
58
+ expect(p).toContain("終わったらSlackで教えて");
59
+ expect(p).toContain("完了と書いたら止まる");
60
+ expect(p).toContain("AUTONOMOUSLY ACROSS MANY TURNS");
61
+ });
62
+ it("truncates very long messages", () => {
63
+ const huge = "x".repeat(5000);
64
+ const p = buildGoalExtractionPrompt(huge);
65
+ expect(p).toContain("…(truncated)");
66
+ expect(p.length).toBeLessThan(huge.length + 4000);
67
+ });
68
+ });
69
+ describe("parseGoalExtractionResult — happy path", () => {
70
+ it("parses a plain JSON object", () => {
71
+ const out = parseGoalExtractionResult('{"condition":"Posted a comparison table to the thread"}');
72
+ expect(out).toBe("Posted a comparison table to the thread");
73
+ });
74
+ it("parses inside a fenced ```json``` block", () => {
75
+ const out = parseGoalExtractionResult('```json\n{"condition":"Closed every open Linear issue under project A"}\n```');
76
+ expect(out).toBe("Closed every open Linear issue under project A");
77
+ });
78
+ it("accepts JSON wrapped in surrounding prose", () => {
79
+ const out = parseGoalExtractionResult('Sure, here it is:\n\n{"condition":"All five SaaS rows added"}\n\nDone.');
80
+ expect(out).toBe("All five SaaS rows added");
81
+ });
82
+ it("flattens whitespace and trims", () => {
83
+ const out = parseGoalExtractionResult('{"condition":" Posted the\\n table\\nto the thread. "}');
84
+ expect(out).toBe("Posted the table to the thread.");
85
+ });
86
+ it("strips control characters", () => {
87
+ const out = parseGoalExtractionResult(JSON.stringify({ condition: "Done with task X" }));
88
+ expect(out).toBe("Done with task X");
89
+ });
90
+ it("hard caps at 400 chars", () => {
91
+ const long = "x".repeat(800);
92
+ const out = parseGoalExtractionResult(JSON.stringify({ condition: long }));
93
+ expect(out.length).toBeLessThanOrEqual(400);
94
+ });
95
+ });
96
+ describe("parseGoalExtractionResult — null / refusals", () => {
97
+ it("returns null for explicit null condition", () => {
98
+ expect(parseGoalExtractionResult('{"condition":null}')).toBeNull();
99
+ });
100
+ it("returns null for empty string condition", () => {
101
+ expect(parseGoalExtractionResult('{"condition":""}')).toBeNull();
102
+ });
103
+ it("returns null for whitespace-only condition", () => {
104
+ expect(parseGoalExtractionResult('{"condition":" \\n\\t "}')).toBeNull();
105
+ });
106
+ it("returns null for unparseable output", () => {
107
+ expect(parseGoalExtractionResult("not json")).toBeNull();
108
+ expect(parseGoalExtractionResult("")).toBeNull();
109
+ expect(parseGoalExtractionResult("{}")).toBeNull();
110
+ });
111
+ it("returns null for sentinel placeholders", () => {
112
+ for (const v of ["none", "N/A", "null", "unknown", "tbd"]) {
113
+ expect(parseGoalExtractionResult(JSON.stringify({ condition: v }))).toBeNull();
114
+ }
115
+ });
116
+ it("returns null for human-judgement conditions starting with 'The user is'", () => {
117
+ const out = parseGoalExtractionResult(JSON.stringify({ condition: "The user is satisfied with the result." }));
118
+ expect(out).toBeNull();
119
+ });
120
+ });
121
+ describe("parseGoalExtractionResult — security", () => {
122
+ it("rejects conditions starting with '/' to prevent slash command injection", () => {
123
+ expect(parseGoalExtractionResult('{"condition":"/permission grant write"}')).toBeNull();
124
+ });
125
+ it("does not allow a forged '/goal' nested inside another /goal", () => {
126
+ expect(parseGoalExtractionResult('{"condition":"/goal something else"}')).toBeNull();
127
+ });
128
+ });
129
+ //# sourceMappingURL=goal-extractor.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"goal-extractor.test.js","sourceRoot":"","sources":["../../../../../src/connectors/slack/__tests__/goal-extractor.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Agents View for Slack — a self-updating Canvas that mirrors OpenRyoko's
3
+ * current sessions, inspired by Claude Code v2.1.139's `claude agents`.
4
+ *
5
+ * Data source: OpenRyoko's own session registry (SQLite via `listSessions()`).
6
+ * NOT `~/.claude/daemon/roster.json` — that file is populated only by
7
+ * `claude --bg` background sessions, and OpenRyoko currently spawns one-shot
8
+ * `claude -p` sessions, so its sessions never appear there.
9
+ *
10
+ * Lifecycle: started by SlackConnector when `agentsCanvas.enabled === true`.
11
+ * Polls the session registry every `pollIntervalMs` (default 30s), renders
12
+ * a Markdown summary, and pushes it into a single Slack Canvas. The canvas
13
+ * is created on first run and reused afterwards; its ID is persisted under
14
+ * `${JINN_HOME}/.agents-canvas-state.json`.
15
+ */
16
+ import type { App } from "@slack/bolt";
17
+ import type { Session } from "../../shared/types.js";
18
+ export interface AgentsCanvasConfig {
19
+ enabled?: boolean;
20
+ /** Slack channel to host the canvas. If unset, a standalone canvas is created. */
21
+ channelId?: string;
22
+ /** Display title. Defaults to "Ryoko Agents View". */
23
+ title?: string;
24
+ /** Polling interval in ms. Default 30s. */
25
+ pollIntervalMs?: number;
26
+ /** Max number of sessions shown per state group. Default 10. */
27
+ maxPerGroup?: number;
28
+ }
29
+ /**
30
+ * Pure renderer. Exported so it can be unit-tested without spawning a Slack
31
+ * client. `nowMs` is injectable for deterministic snapshots.
32
+ */
33
+ export declare function renderCanvasMarkdown(sessions: Session[], opts?: {
34
+ title?: string;
35
+ nowMs?: number;
36
+ maxPerGroup?: number;
37
+ }): string;
38
+ /**
39
+ * Manages the lifecycle of the Agents View canvas: periodically polls the
40
+ * session registry, renders Markdown, and pushes it to Slack.
41
+ */
42
+ export declare class AgentsCanvasUpdater {
43
+ private timer;
44
+ private inflight;
45
+ private stopped;
46
+ private canvasId;
47
+ private lastMarkdown;
48
+ private readonly client;
49
+ private readonly config;
50
+ constructor(app: App, config: AgentsCanvasConfig);
51
+ start(): void;
52
+ stop(): void;
53
+ private tick;
54
+ private publish;
55
+ private createCanvas;
56
+ private fetchExistingChannelCanvasId;
57
+ private editCanvas;
58
+ }
59
+ //# sourceMappingURL=agents-canvas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents-canvas.d.ts","sourceRoot":"","sources":["../../../../src/connectors/slack/agents-canvas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAKrD,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kFAAkF;IAClF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAsID;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,OAAO,EAAE,EACnB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAClE,MAAM,CAoCR;AAwBD;;;GAGG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAGrB;gBAEU,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,kBAAkB;IAgBhD,KAAK,IAAI,IAAI;IAiBb,IAAI,IAAI,IAAI;YAQE,IAAI;YAsBJ,OAAO;YAgBP,YAAY;YA8CZ,4BAA4B;YAc5B,UAAU;CAWzB"}
@@ -0,0 +1,372 @@
1
+ /**
2
+ * Agents View for Slack — a self-updating Canvas that mirrors OpenRyoko's
3
+ * current sessions, inspired by Claude Code v2.1.139's `claude agents`.
4
+ *
5
+ * Data source: OpenRyoko's own session registry (SQLite via `listSessions()`).
6
+ * NOT `~/.claude/daemon/roster.json` — that file is populated only by
7
+ * `claude --bg` background sessions, and OpenRyoko currently spawns one-shot
8
+ * `claude -p` sessions, so its sessions never appear there.
9
+ *
10
+ * Lifecycle: started by SlackConnector when `agentsCanvas.enabled === true`.
11
+ * Polls the session registry every `pollIntervalMs` (default 30s), renders
12
+ * a Markdown summary, and pushes it into a single Slack Canvas. The canvas
13
+ * is created on first run and reused afterwards; its ID is persisted under
14
+ * `${JINN_HOME}/.agents-canvas-state.json`.
15
+ */
16
+ import fs from "node:fs";
17
+ import path from "node:path";
18
+ import { listSessions } from "../../sessions/registry.js";
19
+ import { JINN_HOME } from "../../shared/paths.js";
20
+ import { logger } from "../../shared/logger.js";
21
+ const STATE_FILE = path.join(JINN_HOME, ".agents-canvas-state.json");
22
+ const DEFAULT_TITLE = "Ryoko Agents View";
23
+ const DEFAULT_POLL_MS = 30_000;
24
+ const MIN_POLL_MS = 5_000;
25
+ const DEFAULT_MAX_PER_GROUP = 10;
26
+ /** Map a Session.status to its presentation group. */
27
+ function groupOf(s) {
28
+ switch (s.status) {
29
+ case "running":
30
+ return "running";
31
+ case "waiting":
32
+ return "waiting";
33
+ case "interrupted":
34
+ return "interrupted";
35
+ case "error":
36
+ return "error";
37
+ case "idle":
38
+ default:
39
+ return "idle";
40
+ }
41
+ }
42
+ function groupSessions(sessions) {
43
+ const out = {
44
+ running: [],
45
+ waiting: [],
46
+ interrupted: [],
47
+ error: [],
48
+ idle: [],
49
+ };
50
+ for (const s of sessions) {
51
+ out[groupOf(s)].push(s);
52
+ }
53
+ return out;
54
+ }
55
+ /** Round a millisecond duration into "Xm" / "Xh" / "Xd" — never longer than 5 chars. */
56
+ function formatAge(fromIso, nowMs) {
57
+ const t = Date.parse(fromIso);
58
+ if (!Number.isFinite(t))
59
+ return "?";
60
+ const diffMs = Math.max(0, nowMs - t);
61
+ const mins = Math.floor(diffMs / 60_000);
62
+ if (mins < 1)
63
+ return "now";
64
+ if (mins < 60)
65
+ return `${mins}m`;
66
+ const hours = Math.floor(mins / 60);
67
+ if (hours < 24)
68
+ return `${hours}h`;
69
+ const days = Math.floor(hours / 24);
70
+ return `${days}d`;
71
+ }
72
+ /**
73
+ * Make a user-controlled string safe to embed in the Canvas Markdown body.
74
+ * Strips control characters and newlines (which would break list items) and
75
+ * defangs Slack mention / link syntax + Markdown emphasis characters that
76
+ * could otherwise turn a session title into an @channel ping or a heading.
77
+ */
78
+ // Built via new RegExp so the source text is plain ASCII — embedding raw
79
+ // control bytes in a regex literal trips some editor / tool pipelines.
80
+ const CANVAS_CONTROL_CHARS_RE = new RegExp("[\\u0000-\\u001f\\u007f]", "g");
81
+ function escapeForCanvas(input) {
82
+ const stripped = input.replace(CANVAS_CONTROL_CHARS_RE, " ").replace(/\s+/g, " ").trim();
83
+ return (stripped
84
+ // Slack user / channel / group / link mentions: <@U…>, <#C…>, <#C…|name>, <!subteam^…>, <!here>, <!channel>, <!everyone>, <http…>, <mailto:…>.
85
+ // Strip the entire <…> shell so the residue cannot be parsed by
86
+ // Slack's renderer as a mention. We replace with a neutral placeholder
87
+ // for entity-like forms and keep visible link text for the rest.
88
+ .replace(/<!(channel|here|everyone)>/gi, "($1)")
89
+ .replace(/<!subteam\^[^>]*?\|([^>]*)>/g, "$1")
90
+ .replace(/<!subteam\^[^>]*>/g, "(group)")
91
+ .replace(/<@[UW][^>|]*\|([^>]*)>/g, "$1")
92
+ .replace(/<@[UW][^>]*>/g, "(user)")
93
+ .replace(/<#[CDG][^>|]*\|([^>]*)>/g, "#$1")
94
+ .replace(/<#[CDG][^>]*>/g, "(channel)")
95
+ // Generic <url|label> link — keep the human label
96
+ .replace(/<([^<>]*?)\|([^<>]*?)>/g, "$2")
97
+ // Anything else inside <…> — strip the brackets to prevent residual parsing
98
+ .replace(/<([^<>]*)>/g, "$1")
99
+ // Bare @channel / @here / @everyone (no angle brackets) — zero-width space split
100
+ .replace(/(^|[^A-Za-z0-9_])@(channel|here|everyone)\b/gi, "$1@\u200b$2")
101
+ // Markdown emphasis / code / heading / blockquote / table / strikethrough characters — escape so they render literally
102
+ .replace(/([*_`~>#|\\\[\]])/g, "\\$1"));
103
+ }
104
+ function safeTitle(s) {
105
+ const raw = (s.title || s.sessionKey || s.id || "untitled");
106
+ const escaped = escapeForCanvas(raw);
107
+ return escaped.length > 80 ? escaped.slice(0, 77) + "…" : escaped;
108
+ }
109
+ function locationOf(s) {
110
+ const parts = [];
111
+ if (s.connector)
112
+ parts.push(escapeForCanvas(s.connector));
113
+ if (s.source && s.source !== s.connector)
114
+ parts.push(escapeForCanvas(s.source));
115
+ if (s.employee)
116
+ parts.push("@" + escapeForCanvas(s.employee));
117
+ return parts.join(" · ");
118
+ }
119
+ function renderSessionLine(s, nowMs) {
120
+ const title = safeTitle(s);
121
+ const age = formatAge(s.lastActivity, nowMs);
122
+ const loc = locationOf(s);
123
+ const meta = loc ? ` _(${loc})_` : "";
124
+ return `- **${title}**${meta} — ${age}`;
125
+ }
126
+ const GROUP_HEADERS = [
127
+ { key: "running", emoji: "🟢", label: "Running" },
128
+ { key: "waiting", emoji: "🟡", label: "Waiting on you" },
129
+ { key: "error", emoji: "🔴", label: "Errored" },
130
+ { key: "interrupted", emoji: "⏸️", label: "Interrupted (resumable)" },
131
+ { key: "idle", emoji: "✅", label: "Recently idle" },
132
+ ];
133
+ /**
134
+ * Pure renderer. Exported so it can be unit-tested without spawning a Slack
135
+ * client. `nowMs` is injectable for deterministic snapshots.
136
+ */
137
+ export function renderCanvasMarkdown(sessions, opts = {}) {
138
+ const title = opts.title || DEFAULT_TITLE;
139
+ const nowMs = opts.nowMs ?? Date.now();
140
+ const maxPerGroup = Math.max(1, opts.maxPerGroup ?? DEFAULT_MAX_PER_GROUP);
141
+ const grouped = groupSessions(sessions);
142
+ const lines = [];
143
+ lines.push(`# ${title}`);
144
+ lines.push("");
145
+ const total = sessions.length;
146
+ const updated = new Date(nowMs).toISOString().replace("T", " ").slice(0, 16) + " UTC";
147
+ lines.push(`_${total} session${total === 1 ? "" : "s"} · updated ${updated}_`);
148
+ lines.push("");
149
+ let wroteAny = false;
150
+ for (const { key, emoji, label } of GROUP_HEADERS) {
151
+ const bucket = grouped[key];
152
+ if (bucket.length === 0)
153
+ continue;
154
+ wroteAny = true;
155
+ lines.push(`## ${emoji} ${label} (${bucket.length})`);
156
+ const shown = bucket.slice(0, maxPerGroup);
157
+ for (const s of shown) {
158
+ lines.push(renderSessionLine(s, nowMs));
159
+ }
160
+ if (bucket.length > shown.length) {
161
+ lines.push(`- _…and ${bucket.length - shown.length} more_`);
162
+ }
163
+ lines.push("");
164
+ }
165
+ if (!wroteAny) {
166
+ lines.push("_No active sessions._");
167
+ lines.push("");
168
+ }
169
+ return lines.join("\n").trimEnd() + "\n";
170
+ }
171
+ function loadState() {
172
+ try {
173
+ const raw = fs.readFileSync(STATE_FILE, "utf8");
174
+ const parsed = JSON.parse(raw);
175
+ if (parsed && typeof parsed === "object")
176
+ return parsed;
177
+ }
178
+ catch { /* missing or unreadable → fresh state */ }
179
+ return {};
180
+ }
181
+ function saveState(state) {
182
+ try {
183
+ fs.mkdirSync(path.dirname(STATE_FILE), { recursive: true });
184
+ fs.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2), "utf8");
185
+ }
186
+ catch (err) {
187
+ logger.warn(`[agents-canvas] failed to persist state: ${err}`);
188
+ }
189
+ }
190
+ /**
191
+ * Manages the lifecycle of the Agents View canvas: periodically polls the
192
+ * session registry, renders Markdown, and pushes it to Slack.
193
+ */
194
+ export class AgentsCanvasUpdater {
195
+ timer = null;
196
+ inflight = false;
197
+ stopped = false;
198
+ canvasId = null;
199
+ lastMarkdown = null;
200
+ client;
201
+ config;
202
+ constructor(app, config) {
203
+ this.client = app.client;
204
+ this.config = {
205
+ enabled: config.enabled !== false,
206
+ channelId: config.channelId,
207
+ title: config.title || DEFAULT_TITLE,
208
+ pollIntervalMs: Math.max(MIN_POLL_MS, config.pollIntervalMs ?? DEFAULT_POLL_MS),
209
+ maxPerGroup: config.maxPerGroup ?? DEFAULT_MAX_PER_GROUP,
210
+ };
211
+ const persisted = loadState();
212
+ if (persisted.canvasId && persisted.channelId === this.config.channelId) {
213
+ this.canvasId = persisted.canvasId;
214
+ }
215
+ }
216
+ start() {
217
+ if (!this.config.enabled) {
218
+ logger.info("[agents-canvas] disabled by config");
219
+ return;
220
+ }
221
+ if (this.timer)
222
+ return; // already running — make start() idempotent
223
+ this.stopped = false;
224
+ logger.info(`[agents-canvas] starting (interval=${this.config.pollIntervalMs}ms, channel=${this.config.channelId || "standalone"})`);
225
+ // Kick off an immediate update so the canvas reflects current state at boot.
226
+ void this.tick();
227
+ this.timer = setInterval(() => {
228
+ void this.tick();
229
+ }, this.config.pollIntervalMs);
230
+ }
231
+ stop() {
232
+ this.stopped = true;
233
+ if (this.timer) {
234
+ clearInterval(this.timer);
235
+ this.timer = null;
236
+ }
237
+ }
238
+ async tick() {
239
+ if (this.inflight || this.stopped)
240
+ return;
241
+ this.inflight = true;
242
+ try {
243
+ const sessions = listSessions();
244
+ const markdown = renderCanvasMarkdown(sessions, {
245
+ title: this.config.title,
246
+ maxPerGroup: this.config.maxPerGroup,
247
+ });
248
+ // Skip no-op updates to spare Slack API calls + avoid edit churn.
249
+ if (markdown === this.lastMarkdown)
250
+ return;
251
+ // stop() may have fired while we were rendering — bail before any I/O.
252
+ if (this.stopped)
253
+ return;
254
+ await this.publish(markdown);
255
+ this.lastMarkdown = markdown;
256
+ }
257
+ catch (err) {
258
+ logger.warn(`[agents-canvas] tick failed: ${err}`);
259
+ }
260
+ finally {
261
+ this.inflight = false;
262
+ }
263
+ }
264
+ async publish(markdown) {
265
+ if (!this.canvasId) {
266
+ await this.createCanvas(markdown);
267
+ return;
268
+ }
269
+ try {
270
+ await this.editCanvas(this.canvasId, markdown);
271
+ }
272
+ catch (err) {
273
+ logger.warn(`[agents-canvas] edit failed, will try recreating: ${err}`);
274
+ // The persisted canvas may have been deleted by the user; drop the ID
275
+ // and let the next tick re-create it.
276
+ this.canvasId = null;
277
+ saveState({ canvasId: undefined, channelId: this.config.channelId });
278
+ }
279
+ }
280
+ async createCanvas(markdown) {
281
+ const documentContent = { type: "markdown", markdown };
282
+ if (this.config.channelId) {
283
+ try {
284
+ const res = await this.client.apiCall("conversations.canvases.create", {
285
+ channel_id: this.config.channelId,
286
+ document_content: documentContent,
287
+ title: this.config.title,
288
+ });
289
+ const canvasId = extractCanvasId(res);
290
+ if (!canvasId) {
291
+ throw new Error(`conversations.canvases.create returned no canvas_id: ${JSON.stringify(res).slice(0, 200)}`);
292
+ }
293
+ this.canvasId = canvasId;
294
+ }
295
+ catch (err) {
296
+ // If the channel already has a Canvas (created previously by us, by
297
+ // another instance, or manually), Slack returns `channel_canvas_already_exists`.
298
+ // Recover by reading the existing canvas id from conversations.info and
299
+ // editing that one instead of bailing out.
300
+ if (isChannelCanvasAlreadyExistsError(err)) {
301
+ const existingId = await this.fetchExistingChannelCanvasId(this.config.channelId);
302
+ if (!existingId) {
303
+ throw err;
304
+ }
305
+ logger.info(`[agents-canvas] adopting existing channel canvas ${existingId}`);
306
+ this.canvasId = existingId;
307
+ await this.editCanvas(existingId, markdown);
308
+ }
309
+ else {
310
+ throw err;
311
+ }
312
+ }
313
+ }
314
+ else {
315
+ const res = await this.client.apiCall("canvases.create", {
316
+ title: this.config.title,
317
+ document_content: documentContent,
318
+ });
319
+ const canvasId = extractCanvasId(res);
320
+ if (!canvasId) {
321
+ throw new Error(`canvases.create returned no canvas_id: ${JSON.stringify(res).slice(0, 200)}`);
322
+ }
323
+ this.canvasId = canvasId;
324
+ }
325
+ saveState({ canvasId: this.canvasId, channelId: this.config.channelId });
326
+ logger.info(`[agents-canvas] created canvas ${this.canvasId}`);
327
+ }
328
+ async fetchExistingChannelCanvasId(channelId) {
329
+ try {
330
+ const info = await this.client.apiCall("conversations.info", { channel: channelId });
331
+ const channel = info.channel;
332
+ const properties = channel?.properties;
333
+ const canvas = properties?.canvas;
334
+ const id = canvas?.file_id ?? canvas?.id;
335
+ return typeof id === "string" && id ? id : null;
336
+ }
337
+ catch (err) {
338
+ logger.warn(`[agents-canvas] failed to fetch existing channel canvas: ${err}`);
339
+ return null;
340
+ }
341
+ }
342
+ async editCanvas(canvasId, markdown) {
343
+ await this.client.apiCall("canvases.edit", {
344
+ canvas_id: canvasId,
345
+ changes: [
346
+ {
347
+ operation: "replace",
348
+ document_content: { type: "markdown", markdown },
349
+ },
350
+ ],
351
+ });
352
+ }
353
+ }
354
+ function extractCanvasId(res) {
355
+ const direct = res.canvas_id;
356
+ if (typeof direct === "string" && direct)
357
+ return direct;
358
+ const canvas = res.canvas;
359
+ if (canvas && typeof canvas.id === "string")
360
+ return canvas.id;
361
+ return null;
362
+ }
363
+ function isChannelCanvasAlreadyExistsError(err) {
364
+ if (!err || typeof err !== "object")
365
+ return false;
366
+ const data = err.data;
367
+ if (data?.error === "channel_canvas_already_exists")
368
+ return true;
369
+ const msg = err instanceof Error ? err.message : String(err);
370
+ return /channel_canvas_already_exists/.test(msg);
371
+ }
372
+ //# sourceMappingURL=agents-canvas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents-canvas.js","sourceRoot":"","sources":["../../../../src/connectors/slack/agents-canvas.ts"],"names":[],"mappings":"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"}