crewly 1.20.307 → 1.20.309

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 (93) hide show
  1. package/config/hooks/agent-status/report.sh +5 -5
  2. package/dist/backend/backend/src/constants.d.ts +80 -0
  3. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  4. package/dist/backend/backend/src/constants.js +80 -0
  5. package/dist/backend/backend/src/constants.js.map +1 -1
  6. package/dist/backend/backend/src/index.d.ts +9 -0
  7. package/dist/backend/backend/src/index.d.ts.map +1 -1
  8. package/dist/backend/backend/src/index.js +161 -2
  9. package/dist/backend/backend/src/index.js.map +1 -1
  10. package/dist/backend/backend/src/services/board/board-activity.normalizer.d.ts +17 -0
  11. package/dist/backend/backend/src/services/board/board-activity.normalizer.d.ts.map +1 -1
  12. package/dist/backend/backend/src/services/board/board-activity.normalizer.js +8 -5
  13. package/dist/backend/backend/src/services/board/board-activity.normalizer.js.map +1 -1
  14. package/dist/backend/backend/src/services/board/board-activity.tracker.d.ts +5 -0
  15. package/dist/backend/backend/src/services/board/board-activity.tracker.d.ts.map +1 -1
  16. package/dist/backend/backend/src/services/board/board-activity.tracker.js +25 -1
  17. package/dist/backend/backend/src/services/board/board-activity.tracker.js.map +1 -1
  18. package/dist/backend/backend/src/services/board/board-interaction-hooks.d.ts +34 -0
  19. package/dist/backend/backend/src/services/board/board-interaction-hooks.d.ts.map +1 -0
  20. package/dist/backend/backend/src/services/board/board-interaction-hooks.js +60 -0
  21. package/dist/backend/backend/src/services/board/board-interaction-hooks.js.map +1 -0
  22. package/dist/backend/backend/src/services/board/board-interactions.d.ts +54 -0
  23. package/dist/backend/backend/src/services/board/board-interactions.d.ts.map +1 -0
  24. package/dist/backend/backend/src/services/board/board-interactions.js +92 -0
  25. package/dist/backend/backend/src/services/board/board-interactions.js.map +1 -0
  26. package/dist/backend/backend/src/services/board/board-links.d.ts +51 -0
  27. package/dist/backend/backend/src/services/board/board-links.d.ts.map +1 -0
  28. package/dist/backend/backend/src/services/board/board-links.js +168 -0
  29. package/dist/backend/backend/src/services/board/board-links.js.map +1 -0
  30. package/dist/backend/backend/src/services/board/board-push.service.d.ts +28 -3
  31. package/dist/backend/backend/src/services/board/board-push.service.d.ts.map +1 -1
  32. package/dist/backend/backend/src/services/board/board-push.service.js +108 -9
  33. package/dist/backend/backend/src/services/board/board-push.service.js.map +1 -1
  34. package/dist/backend/backend/src/services/board/board-snapshot.builder.d.ts +39 -2
  35. package/dist/backend/backend/src/services/board/board-snapshot.builder.d.ts.map +1 -1
  36. package/dist/backend/backend/src/services/board/board-snapshot.builder.js +85 -8
  37. package/dist/backend/backend/src/services/board/board-snapshot.builder.js.map +1 -1
  38. package/dist/backend/backend/src/services/board/board.sources.d.ts.map +1 -1
  39. package/dist/backend/backend/src/services/board/board.sources.js +27 -1
  40. package/dist/backend/backend/src/services/board/board.sources.js.map +1 -1
  41. package/dist/backend/backend/src/services/board/board.types.d.ts +48 -0
  42. package/dist/backend/backend/src/services/board/board.types.d.ts.map +1 -1
  43. package/dist/backend/backend/src/services/board/board.types.js +9 -1
  44. package/dist/backend/backend/src/services/board/board.types.js.map +1 -1
  45. package/dist/backend/backend/src/services/board/canvas/canvas-inbound.service.d.ts +122 -0
  46. package/dist/backend/backend/src/services/board/canvas/canvas-inbound.service.d.ts.map +1 -0
  47. package/dist/backend/backend/src/services/board/canvas/canvas-inbound.service.js +339 -0
  48. package/dist/backend/backend/src/services/board/canvas/canvas-inbound.service.js.map +1 -0
  49. package/dist/backend/backend/src/services/board/canvas/canvas-redact.d.ts +44 -0
  50. package/dist/backend/backend/src/services/board/canvas/canvas-redact.d.ts.map +1 -0
  51. package/dist/backend/backend/src/services/board/canvas/canvas-redact.js +161 -0
  52. package/dist/backend/backend/src/services/board/canvas/canvas-redact.js.map +1 -0
  53. package/dist/backend/backend/src/services/board/canvas/canvas-step.normalizer.d.ts +57 -0
  54. package/dist/backend/backend/src/services/board/canvas/canvas-step.normalizer.d.ts.map +1 -0
  55. package/dist/backend/backend/src/services/board/canvas/canvas-step.normalizer.js +164 -0
  56. package/dist/backend/backend/src/services/board/canvas/canvas-step.normalizer.js.map +1 -0
  57. package/dist/backend/backend/src/services/board/canvas/canvas-step.stream.d.ts +140 -0
  58. package/dist/backend/backend/src/services/board/canvas/canvas-step.stream.d.ts.map +1 -0
  59. package/dist/backend/backend/src/services/board/canvas/canvas-step.stream.js +300 -0
  60. package/dist/backend/backend/src/services/board/canvas/canvas-step.stream.js.map +1 -0
  61. package/dist/backend/backend/src/services/board/canvas/canvas-terminal.service.d.ts +99 -0
  62. package/dist/backend/backend/src/services/board/canvas/canvas-terminal.service.d.ts.map +1 -0
  63. package/dist/backend/backend/src/services/board/canvas/canvas-terminal.service.js +223 -0
  64. package/dist/backend/backend/src/services/board/canvas/canvas-terminal.service.js.map +1 -0
  65. package/dist/backend/backend/src/services/board/canvas/canvas-transcript.tail.d.ts +126 -0
  66. package/dist/backend/backend/src/services/board/canvas/canvas-transcript.tail.d.ts.map +1 -0
  67. package/dist/backend/backend/src/services/board/canvas/canvas-transcript.tail.js +385 -0
  68. package/dist/backend/backend/src/services/board/canvas/canvas-transcript.tail.js.map +1 -0
  69. package/dist/backend/backend/src/services/board/canvas/canvas-wiring.d.ts +103 -0
  70. package/dist/backend/backend/src/services/board/canvas/canvas-wiring.d.ts.map +1 -0
  71. package/dist/backend/backend/src/services/board/canvas/canvas-wiring.js +124 -0
  72. package/dist/backend/backend/src/services/board/canvas/canvas-wiring.js.map +1 -0
  73. package/dist/backend/backend/src/services/board/canvas/canvas.types.d.ts +88 -0
  74. package/dist/backend/backend/src/services/board/canvas/canvas.types.d.ts.map +1 -0
  75. package/dist/backend/backend/src/services/board/canvas/canvas.types.js +8 -0
  76. package/dist/backend/backend/src/services/board/canvas/canvas.types.js.map +1 -0
  77. package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts +1 -1
  78. package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts.map +1 -1
  79. package/dist/backend/backend/src/services/cloud/cloud-sync.types.js +1 -0
  80. package/dist/backend/backend/src/services/cloud/cloud-sync.types.js.map +1 -1
  81. package/dist/backend/backend/src/services/slack/slack-initializer.d.ts.map +1 -1
  82. package/dist/backend/backend/src/services/slack/slack-initializer.js +2 -1
  83. package/dist/backend/backend/src/services/slack/slack-initializer.js.map +1 -1
  84. package/dist/backend/build-info.json +2 -2
  85. package/dist/cli/backend/src/constants.d.ts +80 -0
  86. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  87. package/dist/cli/backend/src/constants.js +80 -0
  88. package/dist/cli/backend/src/constants.js.map +1 -1
  89. package/dist/cli/backend/src/services/cloud/cloud-sync.types.d.ts +1 -1
  90. package/dist/cli/backend/src/services/cloud/cloud-sync.types.d.ts.map +1 -1
  91. package/dist/cli/backend/src/services/cloud/cloud-sync.types.js +1 -0
  92. package/dist/cli/backend/src/services/cloud/cloud-sync.types.js.map +1 -1
  93. package/package.json +1 -1
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Redaction for what the canvas shows (crewly#1247 v2), on the machine, before
3
+ * anything leaves it:
4
+ *
5
+ * - {@link shortAgentLine}: the agent's own words from a transcript, reduced
6
+ * to one short line (at most 280 characters), no code blocks, no secrets;
7
+ * - {@link maskTerminalText}: a terminal tail with every secret, token, email
8
+ * and URL query masked.
9
+ *
10
+ * Both reuse the board's {@link scrubText} and the secret redactor that guards
11
+ * the session logs; this file only adds what those do not cover (zero-width
12
+ * characters, base64 blobs, spaced `key = value` secrets, ANSI).
13
+ *
14
+ * Pure (no I/O).
15
+ *
16
+ * @module services/board/canvas/canvas-redact
17
+ */
18
+ import { CANVAS_CONSTANTS } from '../../../constants.js';
19
+ import { redactSecrets } from '../../../utils/secret-redactor.js';
20
+ import { clip, looksLikeToken, REDACTED, scrubText } from '../board-redact.js';
21
+ const C = CANVAS_CONSTANTS;
22
+ /** A terminal capture is cut to this many characters from the end before any pattern runs. */
23
+ const MAX_RAW_CHARS = 400_000;
24
+ /** A raw line is cut to this many characters (an escape-heavy line shrinks after ANSI removal). */
25
+ const MAX_RAW_LINE = 6_000;
26
+ /** A line is masked over its first this many characters (the displayed 400 plus room for a secret that straddles the cut; the cost is quadratic in it). */
27
+ const MASK_LINE_CHARS = 600;
28
+ // eslint-disable-next-line no-control-regex
29
+ const ANSI = /\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[PX^_][^\x1b]*\x1b\\|\x1b[@-Z\\^_=>]|\x9b[0-9;?]*[ -/]*[@-~]/g;
30
+ /** Characters that hide text or reorder it. */
31
+ const INVISIBLE = /[\u200b-\u200f\u202a-\u202e\u2060-\u2069\ufeff]/g;
32
+ /** A long run of base64 / base64url, or a data: URI payload. */
33
+ const BASE64_BLOB = /data:[\w/+.-]+;base64,[A-Za-z0-9+/_=-]+|[A-Za-z0-9+_]{40,}={0,2}/g;
34
+ /** `secret_key = value` with spaces around the separator (the shared redactor wants `NAME=value`). */
35
+ const SPACED_SECRET = /((?:api[_ -]?key|secret|token|passw(?:or)?d|passphrase|private[_ -]?key|credential|auth)[\w-]*\s*(?:[:=]|is)\s+)["']?[^\s"',;]{4,}/gi;
36
+ const PROMPT_SECRET = /((?:password|passphrase|pin|otp|verification code|2fa code)(?:\s+for\s+\S+)?\s*(?:\([^)]*\))?\s*[:?]\s*)\S.*$/gim;
37
+ /** `[REDACTED NAME]` from the shared redactor, without the name (which env var it was is not Cloud's business). */
38
+ const REDACTED_MASK = /\[REDACTED[^\]]*\]/g;
39
+ const EMAIL = /[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}/g;
40
+ const URL_QUERY = /(\bhttps?:\/\/[^\s?#"'<>]+)\?[^\s"'<>]*/gi;
41
+ const URL_CREDENTIALS = /(\b[a-z][a-z0-9+.-]*:\/\/)[^\s/@:]+:[^\s/@]+@/gi;
42
+ const BEARER = /\b(?:bearer|basic)\s+[A-Za-z0-9._~+/=-]{6,}/gi;
43
+ const HEX_LONG = /\b[0-9a-fA-F]{32,}\b/g;
44
+ /** A phone number: international (`+...`) or three-three-four groups. Dates, versions and model ids are not. */
45
+ const PHONE = /(?<![\w.-])(?:\+\d[\d\s().-]{8,}\d|\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4})(?![\w-])/g;
46
+ /**
47
+ * Whether a word of a terminal line looks like a credential. Slugs such as
48
+ * `claude-opus-4-5-20251101` (lowercase words joined by dashes) are not.
49
+ *
50
+ * @param word - Word without surrounding punctuation
51
+ * @returns True when it should be masked
52
+ */
53
+ function looksSecretWord(word) {
54
+ if (word.length < 24 || !/^[A-Za-z0-9_+=/-]+$/.test(word))
55
+ return false;
56
+ if (!/\d/.test(word) || !/[A-Za-z]/.test(word))
57
+ return false;
58
+ if (/^[a-z0-9]+(?:-[a-z0-9.]+)+$/.test(word))
59
+ return false;
60
+ if (word.includes('/'))
61
+ return false; // a path
62
+ return looksLikeToken(word) || (/[A-Z]/.test(word) && /[a-z]/.test(word));
63
+ }
64
+ /**
65
+ * Mask what must not be shown in either surface.
66
+ *
67
+ * @param text - One line or a whole text
68
+ * @returns Text with emails, URL queries / credentials, bearer tokens, long hex, blobs and spaced secrets masked
69
+ */
70
+ function maskCommon(text) {
71
+ let s = text;
72
+ s = s.replace(URL_CREDENTIALS, `$1${REDACTED}@`);
73
+ s = s.replace(URL_QUERY, '$1?[query]');
74
+ s = s.replace(EMAIL, '[email]');
75
+ s = s.replace(BEARER, REDACTED);
76
+ s = s.replace(SPACED_SECRET, `$1${REDACTED}`);
77
+ s = s.replace(HEX_LONG, REDACTED);
78
+ s = s.replace(BASE64_BLOB, (m) => (m.startsWith('data:') || m.endsWith('=') || (/\d/.test(m) && /[A-Z]/.test(m) && /[a-z]/.test(m)) ? REDACTED : m));
79
+ return s;
80
+ }
81
+ /**
82
+ * Reduce an assistant message block to one short, safe line.
83
+ *
84
+ * Takes the first paragraph outside code fences (a list item or heading loses
85
+ * its marker), removes markdown emphasis, masks secrets / emails / URL
86
+ * queries / phone numbers, and cuts at 280 characters. Anything that is
87
+ * markup (`<system-reminder>`), an interrupt notice, or empty after masking
88
+ * gives null.
89
+ *
90
+ * @param raw - Text of a `text` block
91
+ * @param secrets - Exact secret values to mask (backend env)
92
+ * @returns The line, or null when nothing worth showing is left
93
+ */
94
+ export function shortAgentLine(raw, secrets = []) {
95
+ if (typeof raw !== 'string')
96
+ return null;
97
+ let s = raw.length > 6000 ? raw.slice(0, 6000) : raw;
98
+ s = s.replace(INVISIBLE, '').replace(ANSI, '');
99
+ // Code is never a "short line": drop fenced blocks (an unclosed fence runs to the end)
100
+ s = s.replace(/```[\s\S]*?(?:```|$)/g, '\n\n').replace(/~~~[\s\S]*?(?:~~~|$)/g, '\n\n');
101
+ const paragraphs = s
102
+ .split(/\n\s*\n/)
103
+ .map((p) => p.trim())
104
+ .filter(Boolean);
105
+ let first = paragraphs.find((p) => !/^(?:\||<|\[Request interrupted|No response requested|API Error)/i.test(p)) ?? '';
106
+ // Soft-wrapped lines are one sentence; a list shows its first item
107
+ const lines = first.split('\n').map((l) => l.trim()).filter(Boolean);
108
+ first = /^(?:[-*+]|\d+[.)])\s/.test(lines[0] ?? '') ? (lines[0] ?? '') : lines.join(' ');
109
+ first = first
110
+ .replace(/^(?:#{1,6}|[-*+]|\d+[.)]|>)\s+/, '')
111
+ .replace(/\[([^\]]{1,120})\]\(([^)\s]*)\)/g, '$1')
112
+ .replace(/(\*\*|__|\*|_|`)/g, '');
113
+ if (first.length < 2 || /^<[a-z/!]/i.test(first))
114
+ return null;
115
+ const out = scrubText(maskCommon(redactSecrets(first, secrets).replace(REDACTED_MASK, REDACTED)).replace(PHONE, '[number]'), C.TEXT_MAX);
116
+ if (!/[\p{L}\p{N}]/u.test(out.replace(/\[(?:redacted|email|number|query)\]/gi, '')))
117
+ return null;
118
+ return out;
119
+ }
120
+ /**
121
+ * Mask a terminal tail for the canvas: ANSI and control characters removed,
122
+ * then secrets (by value, by `NAME=value`, by shape), emails, URL queries and
123
+ * credentials, bearer tokens, password prompts and long token-like words.
124
+ *
125
+ * @param text - Raw tail (the PTY capture)
126
+ * @param secrets - Exact secret values to mask (backend env)
127
+ * @param maxLines - Keep this many lines from the end
128
+ * @returns Lines, oldest first, each at most {@link CANVAS_CONSTANTS.TERMINAL_MAX_LINE_CHARS} characters
129
+ */
130
+ export function maskTerminalText(text, secrets = [], maxLines = C.TERMINAL_TAIL_LINES) {
131
+ // Bound the work first: the patterns below are linear per line, but a single
132
+ // megabyte-long line of letters would still cost seconds in the email pattern
133
+ const bounded = (text.length > MAX_RAW_CHARS ? text.slice(-MAX_RAW_CHARS) : text)
134
+ .split('\n')
135
+ .slice(-(maxLines + 20))
136
+ .map((l) => (l.length > MAX_RAW_LINE ? l.slice(0, MAX_RAW_LINE) : l));
137
+ let s = bounded.join('\n').replace(/\r\n/g, '\n').replace(ANSI, '').replace(INVISIBLE, '');
138
+ // A carriage return redraws the line: keep what was drawn last
139
+ s = s
140
+ .split('\n')
141
+ .map((l) => {
142
+ const drawn = l.includes('\r') ? (l.split('\r').filter(Boolean).pop() ?? '') : l;
143
+ return drawn.length > MASK_LINE_CHARS ? drawn.slice(0, MASK_LINE_CHARS) : drawn;
144
+ })
145
+ .join('\n');
146
+ // eslint-disable-next-line no-control-regex
147
+ s = s.replace(/[\u0000-\u0008\u000b-\u001f\u007f]/g, '');
148
+ // Whole-text passes first: a private key block spans lines
149
+ s = redactSecrets(s, secrets).replace(REDACTED_MASK, REDACTED);
150
+ s = s.replace(PROMPT_SECRET, `$1${REDACTED}`);
151
+ const lines = s.split('\n').map((line) => {
152
+ let l = maskCommon(line);
153
+ l = l.replace(PHONE, '[number]');
154
+ l = l.replace(/[A-Za-z0-9_+=/-]{24,}/g, (w) => (looksSecretWord(w) ? REDACTED : w));
155
+ return clip(l.replace(/\s+$/, ''), C.TERMINAL_MAX_LINE_CHARS);
156
+ });
157
+ while (lines.length > 0 && lines[lines.length - 1] === '')
158
+ lines.pop();
159
+ return lines.slice(-maxLines);
160
+ }
161
+ //# sourceMappingURL=canvas-redact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-redact.js","sourceRoot":"","sources":["../../../../../../../backend/src/services/board/canvas/canvas-redact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Step normalizer (crewly#1247 v2): maps a runtime tool call, a browser action,
3
+ * a chat reply or a wait on the owner to one canvas step: a kind, a verb
4
+ * (`label`) and a redacted `target`. Same redaction rules as the board
5
+ * ({@link scrubText}, repo-relative paths, host + path, executable +
6
+ * subcommand); the raw tool input is read here and dropped.
7
+ *
8
+ * Pure (no I/O).
9
+ *
10
+ * @module services/board/canvas/canvas-step.normalizer
11
+ */
12
+ import { type NormalizeContext, type ToolInput } from '../board-activity.normalizer.js';
13
+ import type { StepKind } from './canvas.types.js';
14
+ /** What a step says before it gets an id and a time. */
15
+ export interface StepShape {
16
+ kind: StepKind;
17
+ label: string;
18
+ target?: string;
19
+ }
20
+ /**
21
+ * One tool call as a step.
22
+ *
23
+ * @param toolName - Runtime tool name (`Edit`, `Bash`, `mcp__x__y`, ...)
24
+ * @param input - Validated input slice (see {@link parseToolInput})
25
+ * @param ctx - Project roots for relative paths
26
+ * @returns Kind, verb and redacted target
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * stepOfTool('Bash', { command: 'cd app && npm test -- --ci' }); // { kind: 'command', label: 'Ran', target: 'npm test' }
31
+ * stepOfTool('WebSearch', { query: 'open swarm rivals' }); // { kind: 'search', label: 'Searched', target: '"open swarm rivals"' }
32
+ * ```
33
+ */
34
+ export declare function stepOfTool(toolName: string, input?: ToolInput, ctx?: NormalizeContext): StepShape;
35
+ /**
36
+ * A browser action by an agent (the Chrome extension path).
37
+ *
38
+ * @param tool - Extension tool name (`navigate`, `click`, ...)
39
+ * @param url - The page the agent is on, if known
40
+ * @returns Step shape
41
+ */
42
+ export declare function stepOfBrowserAction(tool: string, url?: string): StepShape;
43
+ /**
44
+ * An agent message to the owner or a channel.
45
+ *
46
+ * @param channel - Channel or chat name (`#general`, `owner chat`, `Slack`)
47
+ * @returns Step shape
48
+ */
49
+ export declare function stepOfMessage(channel: string): StepShape;
50
+ /**
51
+ * The agent waits for the owner.
52
+ *
53
+ * @param what - Short plain-words description
54
+ * @returns Step shape
55
+ */
56
+ export declare function stepOfOwnerWait(what: string): StepShape;
57
+ //# sourceMappingURL=canvas-step.normalizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-step.normalizer.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/board/canvas/canvas-step.normalizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAMN,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,MAAM,iCAAiC,CAAC;AAEzC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,wDAAwD;AACxD,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAoDD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,GAAE,SAAc,EAAE,GAAG,GAAE,gBAAqB,GAAG,SAAS,CAyCzG;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAYzE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAGxD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAEvD"}
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Step normalizer (crewly#1247 v2): maps a runtime tool call, a browser action,
3
+ * a chat reply or a wait on the owner to one canvas step: a kind, a verb
4
+ * (`label`) and a redacted `target`. Same redaction rules as the board
5
+ * ({@link scrubText}, repo-relative paths, host + path, executable +
6
+ * subcommand); the raw tool input is read here and dropped.
7
+ *
8
+ * Pure (no I/O).
9
+ *
10
+ * @module services/board/canvas/canvas-step.normalizer
11
+ */
12
+ import { BROWSING_SKILLS, CHANNEL_NAME, flagValue, MESSAGING_SKILLS, WRITING_SKILLS, } from '../board-activity.normalizer.js';
13
+ import { clip, looksLikeToken, redactUrl, reduceCommand, relativePath, scrubText } from '../board-redact.js';
14
+ const shape = (kind, label, target) => {
15
+ const t = target ? clip(scrubText(target, 120)) : '';
16
+ return { kind, label, ...(t ? { target: t } : {}) };
17
+ };
18
+ const channelName = (raw, fallback) => {
19
+ // A readable name only: a chat-v2 channel id (a UUID) or a Slack id says nothing to the owner
20
+ if (!raw || !CHANNEL_NAME.test(raw) || looksLikeToken(raw.replace(/^#/, '')) || /^[0-9a-f]{8}-/i.test(raw) || /^[CDG][A-Z0-9]{8,}$/.test(raw))
21
+ return fallback;
22
+ return raw.startsWith('#') ? raw : `#${raw}`;
23
+ };
24
+ function fromCommand(command) {
25
+ const reduced = reduceCommand(command);
26
+ if (!reduced)
27
+ return shape('command', 'Ran', 'a shell command');
28
+ if (reduced.skill) {
29
+ const skill = reduced.skill;
30
+ if (MESSAGING_SKILLS.has(skill)) {
31
+ const fallback = skill.includes('slack') ? 'Slack' : skill === 'reply-channel' ? 'a channel' : 'owner chat';
32
+ return shape('message', 'Sent message', channelName(flagValue(reduced.args, ['--channel', '--to']), fallback));
33
+ }
34
+ if (BROWSING_SKILLS.has(skill)) {
35
+ const url = reduced.args.find((w) => /^https?:\/\//i.test(w));
36
+ if (skill === 'web-search')
37
+ return shape('search', 'Searched', 'the web');
38
+ return shape('browse', url ? 'Opened' : 'Browsed', url ? redactUrl(url) : 'the browser');
39
+ }
40
+ const place = WRITING_SKILLS[skill];
41
+ if (place)
42
+ return shape('write', 'Wrote in', place);
43
+ return shape('command', 'Ran', reduced.label);
44
+ }
45
+ if ((reduced.executable === 'curl' || reduced.executable === 'wget') && reduced.args.length > 0) {
46
+ const url = reduced.args.find((w) => /^https?:\/\//i.test(w));
47
+ if (url)
48
+ return shape('browse', 'Fetched', redactUrl(url));
49
+ }
50
+ return shape('command', 'Ran', reduced.label);
51
+ }
52
+ function fromMcp(name, input) {
53
+ const parts = name.split('__');
54
+ const server = parts[1] ?? 'mcp';
55
+ const tool = parts.slice(2).join('_') || server;
56
+ const hay = `${server} ${tool}`.toLowerCase();
57
+ if (/browser|chrome|playwright|puppeteer|navigate|screenshot/.test(hay)) {
58
+ return shape('browse', /navigate/.test(hay) ? 'Opened' : 'Browsed', input.url ? redactUrl(input.url) : 'the browser');
59
+ }
60
+ if (/slack|chat|message|mail|email|telegram|whatsapp|discord/.test(hay))
61
+ return shape('message', 'Sent message', server);
62
+ if (/search/.test(hay))
63
+ return shape('search', 'Searched', server);
64
+ if (/docs?|drive|sheets?|slides?|notion|zoho|canva|wiki|write|publish/.test(hay))
65
+ return shape('write', 'Wrote in', server);
66
+ return shape('tool', 'Used', `${server} ${tool}`);
67
+ }
68
+ /**
69
+ * One tool call as a step.
70
+ *
71
+ * @param toolName - Runtime tool name (`Edit`, `Bash`, `mcp__x__y`, ...)
72
+ * @param input - Validated input slice (see {@link parseToolInput})
73
+ * @param ctx - Project roots for relative paths
74
+ * @returns Kind, verb and redacted target
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * stepOfTool('Bash', { command: 'cd app && npm test -- --ci' }); // { kind: 'command', label: 'Ran', target: 'npm test' }
79
+ * stepOfTool('WebSearch', { query: 'open swarm rivals' }); // { kind: 'search', label: 'Searched', target: '"open swarm rivals"' }
80
+ * ```
81
+ */
82
+ export function stepOfTool(toolName, input = {}, ctx = {}) {
83
+ const name = toolName || 'tool';
84
+ const rel = input.filePath ? relativePath(input.filePath, ctx.roots ?? []) : '';
85
+ switch (name) {
86
+ case 'Read':
87
+ return shape('read', 'Read', rel || 'a file');
88
+ case 'Edit':
89
+ case 'MultiEdit':
90
+ return shape('edit', 'Edited', rel || 'a file');
91
+ case 'NotebookEdit':
92
+ return shape('edit', 'Edited', rel || 'a notebook');
93
+ case 'Write':
94
+ return shape('write', 'Wrote', rel || 'a file');
95
+ case 'Grep':
96
+ case 'Glob':
97
+ case 'LS':
98
+ return shape('search', 'Searched', rel || 'the code');
99
+ case 'Bash':
100
+ case 'BashOutput':
101
+ case 'KillShell':
102
+ return input.command ? fromCommand(input.command) : shape('command', 'Ran', 'a shell command');
103
+ case 'WebFetch':
104
+ return shape('browse', 'Opened', input.url ? redactUrl(input.url) : 'a web page');
105
+ case 'WebSearch': {
106
+ const q = input.query ? scrubText(input.query, 100) : '';
107
+ return shape('search', 'Searched', q ? `"${q}"` : 'the web');
108
+ }
109
+ case 'Task':
110
+ case 'Agent':
111
+ return shape('tool', 'Asked', 'a helper agent');
112
+ case 'TodoWrite':
113
+ return shape('tool', 'Planned', 'the next steps');
114
+ case 'AskUserQuestion':
115
+ return shape('wait', 'Asked', 'the owner a question');
116
+ case 'ExitPlanMode':
117
+ return shape('wait', 'Waiting for', 'plan approval');
118
+ default:
119
+ break;
120
+ }
121
+ if (name.startsWith('mcp__'))
122
+ return fromMcp(name, input);
123
+ return shape('tool', 'Used', /^[A-Za-z0-9_-]{1,64}$/.test(name) ? name : 'a tool');
124
+ }
125
+ /**
126
+ * A browser action by an agent (the Chrome extension path).
127
+ *
128
+ * @param tool - Extension tool name (`navigate`, `click`, ...)
129
+ * @param url - The page the agent is on, if known
130
+ * @returns Step shape
131
+ */
132
+ export function stepOfBrowserAction(tool, url) {
133
+ const where = url ? redactUrl(url) : 'the browser';
134
+ const verbs = {
135
+ navigate: 'Opened',
136
+ click: 'Clicked on',
137
+ type: 'Typed on',
138
+ scroll: 'Scrolled',
139
+ screenshot: 'Looked at',
140
+ read: 'Read',
141
+ extract: 'Read',
142
+ };
143
+ return shape('browse', verbs[tool] ?? 'Browsed', where);
144
+ }
145
+ /**
146
+ * An agent message to the owner or a channel.
147
+ *
148
+ * @param channel - Channel or chat name (`#general`, `owner chat`, `Slack`)
149
+ * @returns Step shape
150
+ */
151
+ export function stepOfMessage(channel) {
152
+ const name = CHANNEL_NAME.test(channel) && !channel.startsWith('#') && channel !== 'owner chat' && channel !== 'Slack' ? `#${channel}` : channel;
153
+ return shape('message', 'Sent message', name);
154
+ }
155
+ /**
156
+ * The agent waits for the owner.
157
+ *
158
+ * @param what - Short plain-words description
159
+ * @returns Step shape
160
+ */
161
+ export function stepOfOwnerWait(what) {
162
+ return shape('wait', 'Waiting for', what || 'the owner');
163
+ }
164
+ //# sourceMappingURL=canvas-step.normalizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-step.normalizer.js","sourceRoot":"","sources":["../../../../../../../backend/src/services/board/canvas/canvas-step.normalizer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * The live step stream per agent (crewly#1247 v2).
3
+ *
4
+ * Pairs a tool start with its end (hook PreToolUse / PostToolUse) into one
5
+ * {@link StepEvent} with a duration and a status, takes instant steps (a chat
6
+ * reply, a browser action) and the agent's own short text lines (from the
7
+ * transcript tail), and keeps the last 300 per agent in memory.
8
+ *
9
+ * A step is sent again, with the same id, when it changes (`running` ->
10
+ * `done` / `error`): `unsent` holds the newest version of every step Cloud has
11
+ * not taken yet, so a failed push loses nothing (capped per agent).
12
+ *
13
+ * In memory only; nothing here reads files or the network. Everything that
14
+ * goes in has been through the redaction in {@link ./canvas-step.normalizer}
15
+ * and {@link ./canvas-redact}.
16
+ *
17
+ * @module services/board/canvas/canvas-step.stream
18
+ */
19
+ import type { StepShape } from './canvas-step.normalizer.js';
20
+ import type { StepEvent, StepStatus } from './canvas.types.js';
21
+ /** Called when a session's steps changed. */
22
+ export type StepChangeListener = (session: string) => void;
23
+ /**
24
+ * Steps per agent.
25
+ */
26
+ export declare class StepStream {
27
+ private readonly sessions;
28
+ private readonly listeners;
29
+ /**
30
+ * Subscribe to changes.
31
+ *
32
+ * @param listener - Called with the session whose steps changed
33
+ * @returns Unsubscribe
34
+ */
35
+ onChange(listener: StepChangeListener): () => void;
36
+ private emit;
37
+ private get;
38
+ private touch;
39
+ private insert;
40
+ /** A running step older than the limit lost its end: close it without a duration. */
41
+ private sweep;
42
+ /**
43
+ * A step began (a tool call started).
44
+ *
45
+ * @param session - Agent session
46
+ * @param shape - Kind, verb and target
47
+ * @param opts.id - The runtime's tool-call id; a derived one when absent
48
+ * @param now - Clock (tests)
49
+ * @returns The step id
50
+ */
51
+ start(session: string, shape: StepShape, opts?: {
52
+ id?: string;
53
+ }, now?: number): string;
54
+ /**
55
+ * A step ended. Without an id the oldest running step ends (a hook that
56
+ * did not name its tool call).
57
+ *
58
+ * @param session - Agent session
59
+ * @param id - Step id, if known
60
+ * @param status - How it ended
61
+ * @param now - Clock (tests)
62
+ */
63
+ finish(session: string, id?: string, status?: StepStatus, now?: number): void;
64
+ /**
65
+ * A step turned out to have failed (the transcript's `is_error` flag), after
66
+ * its end was already seen.
67
+ *
68
+ * @param session - Agent session
69
+ * @param id - Step id
70
+ * @param now - Clock (tests)
71
+ */
72
+ markError(session: string, id: string, now?: number): void;
73
+ /**
74
+ * A step that has no duration (a message sent, a page opened by the
75
+ * extension). Dropped when a tool call of the same kind is running, or the
76
+ * previous step is the same thing within 5 s (a skill's own tool call and
77
+ * the controller that served it).
78
+ *
79
+ * @param session - Agent session
80
+ * @param shape - Kind, verb and target
81
+ * @param now - Clock (tests)
82
+ * @returns The step id, or null when it repeated the previous step
83
+ */
84
+ instant(session: string, shape: StepShape, now?: number): string | null;
85
+ /**
86
+ * One line of the agent's own words.
87
+ *
88
+ * @param session - Agent session
89
+ * @param id - Stable id (the transcript entry's uuid)
90
+ * @param atMs - When it was written
91
+ * @param text - Already reduced and redacted (see shortAgentLine)
92
+ * @returns True when it is new
93
+ */
94
+ text(session: string, id: string, atMs: number, text: string): boolean;
95
+ /**
96
+ * The turn ended: whatever still runs ended with it.
97
+ *
98
+ * @param session - Agent session
99
+ * @param now - Clock (tests)
100
+ */
101
+ closeAll(session: string, now?: number): void;
102
+ /**
103
+ * A session's recent steps (oldest first).
104
+ *
105
+ * @param session - Agent session
106
+ * @param limit - Newest this many
107
+ * @param now - Clock (tests)
108
+ * @returns Copies
109
+ */
110
+ recent(session: string, limit?: number, now?: number): StepEvent[];
111
+ /** Whether the session has a step that is still running. */
112
+ hasRunning(session: string): boolean;
113
+ /**
114
+ * Steps (new or changed) Cloud has not taken. Call {@link ackUnsent} once
115
+ * it did.
116
+ *
117
+ * @param sessions - Only these sessions (all when omitted)
118
+ * @param max - Most steps in all
119
+ * @param perSession - Most steps per session (the oldest go first; the rest wait for the next delta)
120
+ * @returns Steps, oldest first
121
+ */
122
+ peekUnsent(sessions?: Iterable<string>, max?: number, perSession?: number): StepEvent[];
123
+ /**
124
+ * Mark steps as taken. A step that changed since it was peeked stays
125
+ * unsent (and goes out again); steps left over by the per-delta limit stay
126
+ * too, for the next delta.
127
+ *
128
+ * @param steps - What {@link peekUnsent} returned and Cloud accepted
129
+ */
130
+ ackUnsent(steps: readonly StepEvent[]): void;
131
+ /** Sessions with steps not yet sent. */
132
+ sessionsWithUnsent(): string[];
133
+ /**
134
+ * Forget a session (it was deleted).
135
+ *
136
+ * @param session - Agent session
137
+ */
138
+ forget(session: string): void;
139
+ }
140
+ //# sourceMappingURL=canvas-step.stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-step.stream.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/board/canvas/canvas-step.stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAe/D,6CAA6C;AAC7C,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAI3D;;GAEG;AACH,qBAAa,UAAU;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmC;IAC5D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiC;IAE3D;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,IAAI;IAKlD,OAAO,CAAC,IAAI;IAUZ,OAAO,CAAC,GAAG;IASX,OAAO,CAAC,KAAK;IAQb,OAAO,CAAC,MAAM;IAad,qFAAqF;IACrF,OAAO,CAAC,KAAK;IAiBb;;;;;;;;OAQG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,GAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAO,EAAE,GAAG,GAAE,MAAmB,GAAG,MAAM;IAetG;;;;;;;;OAQG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,GAAE,UAAmB,EAAE,GAAG,GAAE,MAAmB,GAAG,IAAI;IAejG;;;;;;;OAOG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,IAAI;IAItE;;;;;;;;;;OAUG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,GAAE,MAAmB,GAAG,MAAM,GAAG,IAAI;IAmBnF;;;;;;;;OAQG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO;IAmBtE;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,IAAI;IAOzD;;;;;;;OAOG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,EAAE,GAAG,GAAE,MAAmB,GAAG,SAAS,EAAE;IAOlF,4DAA4D;IAC5D,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIpC;;;;;;;;OAQG;IACH,UAAU,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,GAAG,GAAE,MAA0B,EAAE,UAAU,GAAE,MAAoC,GAAG,SAAS,EAAE;IAavI;;;;;;OAMG;IACH,SAAS,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,GAAG,IAAI;IAS5C,wCAAwC;IACxC,kBAAkB,IAAI,MAAM,EAAE;IAI9B;;;;OAIG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;CAG7B"}