@causyne/agent 1.10.21 → 1.11.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.
Files changed (55) hide show
  1. package/native-skills/media/professional-document-publishing/SKILL.md +44 -0
  2. package/native-skills/media/screenplay-and-shotlist-forge/SKILL.md +42 -0
  3. package/package.json +1 -1
  4. package/src/acp/client.js +235 -0
  5. package/src/acp/client.ts +282 -0
  6. package/src/acp/peerProfiles.js +122 -0
  7. package/src/acp/peerProfiles.ts +128 -0
  8. package/src/acp/protocol.js +54 -0
  9. package/src/acp/protocol.ts +434 -0
  10. package/src/acp/server.js +609 -0
  11. package/src/acp/server.ts +676 -0
  12. package/src/agentLoop.d.ts +43 -0
  13. package/src/agentLoop.js +142 -8
  14. package/src/commands.js +203 -0
  15. package/src/compiledSkills.js +10 -0
  16. package/src/documentEngine/antiSlopAuditor.js +156 -0
  17. package/src/documentEngine/antiSlopAuditor.ts +221 -0
  18. package/src/documentEngine/documentForge.js +443 -0
  19. package/src/documentEngine/documentForge.ts +519 -0
  20. package/src/documentEngine/screenplayFormatter.js +336 -0
  21. package/src/documentEngine/screenplayFormatter.ts +407 -0
  22. package/src/entrypoint.js +13 -0
  23. package/src/execSafe.js +10 -13
  24. package/src/execSafe.ts +25 -0
  25. package/src/modelRouter.js +56 -123
  26. package/src/modelRouter.ts +134 -0
  27. package/src/observer/advisory.js +164 -0
  28. package/src/observer/advisory.ts +171 -0
  29. package/src/observer/coldObserver.js +462 -0
  30. package/src/observer/coldObserver.ts +540 -0
  31. package/src/observer/evidence.js +435 -0
  32. package/src/observer/evidence.ts +499 -0
  33. package/src/perception.js +303 -118
  34. package/src/perception.ts +387 -0
  35. package/src/procSignal.js +15 -16
  36. package/src/procSignal.ts +31 -0
  37. package/src/promptMentions.js +170 -0
  38. package/src/promptMentions.ts +212 -0
  39. package/src/sandbox.js +1 -1
  40. package/src/textDiff.js +117 -109
  41. package/src/textDiff.ts +169 -0
  42. package/src/toolPacks.js +5 -2
  43. package/src/tools/documentForge.js +215 -0
  44. package/src/tools/documentForge.ts +265 -0
  45. package/src/tools/peerAgent.js +102 -0
  46. package/src/tools/peerAgent.ts +116 -0
  47. package/src/tools/registry.js +3 -1
  48. package/src/tui/completion.js +97 -41
  49. package/src/tui/prompt.js +17 -17
  50. package/src/uncertainty.js +93 -205
  51. package/src/uncertainty.ts +255 -0
  52. package/src/utils/paths.js +15 -18
  53. package/src/utils/paths.ts +36 -0
  54. package/src/vfeTracker.js +122 -181
  55. package/src/vfeTracker.ts +242 -0
@@ -0,0 +1,336 @@
1
+ /*
2
+ * Copyright (c) 2026 Causyne.
3
+ * SPDX-License-Identifier: BUSL-1.1
4
+ *
5
+ * Hollywood Standard Screenplay & Production Shot List Formatter.
6
+ * Enforces industry Courier 12pt specifications, 1-page-per-minute timing,
7
+ * director's shot list grids, and voice-over (VO) timing synchronization.
8
+ */
9
+ /**
10
+ * Generate industry-standard Hollywood Screenplay HTML + CSS.
11
+ * Courier 12pt, 1.5in left margin, centered character cues, constrained dialogue width.
12
+ */
13
+ export function formatScreenplayHtml(spec) {
14
+ const css = `
15
+ /* Hollywood Industry Standard Screenplay Layout */
16
+ @page {
17
+ size: letter portrait;
18
+ margin: 1.0in 1.0in 1.0in 1.5in;
19
+ @top-right {
20
+ content: counter(page) ".";
21
+ font-family: "Courier Prime", "Courier Final Draft", Courier, monospace;
22
+ font-size: 10pt;
23
+ }
24
+ }
25
+ @page :first {
26
+ @top-right { content: normal; }
27
+ }
28
+
29
+ html {
30
+ -webkit-print-color-adjust: exact;
31
+ print-color-adjust: exact;
32
+ }
33
+
34
+ body {
35
+ margin: 0;
36
+ padding: 0;
37
+ font-family: "Courier Prime", "Courier Final Draft", Courier, monospace;
38
+ font-size: 12pt;
39
+ line-height: 1.0;
40
+ color: #000000;
41
+ background: #ffffff;
42
+ }
43
+
44
+ .script-title-page {
45
+ page-break-after: always;
46
+ height: 9.0in;
47
+ display: flex;
48
+ flex-direction: column;
49
+ justify-content: center;
50
+ align-items: center;
51
+ text-align: center;
52
+ }
53
+ .script-title {
54
+ font-size: 18pt;
55
+ font-weight: bold;
56
+ letter-spacing: 0.1em;
57
+ text-transform: uppercase;
58
+ margin-bottom: 24pt;
59
+ }
60
+ .script-by {
61
+ font-size: 12pt;
62
+ margin-bottom: 12pt;
63
+ }
64
+ .script-author {
65
+ font-size: 12pt;
66
+ text-transform: uppercase;
67
+ margin-bottom: 48pt;
68
+ }
69
+
70
+ .element-scene_heading {
71
+ font-weight: bold;
72
+ text-transform: uppercase;
73
+ margin-top: 18pt;
74
+ margin-bottom: 10pt;
75
+ page-break-after: avoid;
76
+ }
77
+
78
+ .element-action {
79
+ margin-bottom: 12pt;
80
+ line-height: 1.25;
81
+ text-align: left;
82
+ }
83
+
84
+ .element-character {
85
+ text-transform: uppercase;
86
+ margin-left: 2.2in;
87
+ margin-top: 14pt;
88
+ margin-bottom: 0;
89
+ page-break-after: avoid;
90
+ }
91
+
92
+ .element-parenthetical {
93
+ margin-left: 1.6in;
94
+ width: 2.5in;
95
+ margin-top: 0;
96
+ margin-bottom: 0;
97
+ page-break-after: avoid;
98
+ }
99
+
100
+ .element-dialogue {
101
+ margin-left: 1.0in;
102
+ width: 3.5in;
103
+ line-height: 1.2;
104
+ margin-top: 2pt;
105
+ margin-bottom: 12pt;
106
+ }
107
+
108
+ .element-transition {
109
+ text-transform: uppercase;
110
+ text-align: right;
111
+ margin-top: 14pt;
112
+ margin-bottom: 14pt;
113
+ page-break-after: avoid;
114
+ }
115
+ `.trim();
116
+ let bodyContent = '';
117
+ if (spec.title) {
118
+ bodyContent += `
119
+ <div class="script-title-page">
120
+ <div class="script-title">${escapeHtml(spec.title)}</div>
121
+ <div class="script-by">written by</div>
122
+ <div class="script-author">${escapeHtml(spec.author || 'Anonymous')}</div>
123
+ ${spec.contact ? `<div style="margin-top: auto; font-size: 10pt;">${escapeHtml(spec.contact)}</div>` : ''}
124
+ </div>`;
125
+ }
126
+ bodyContent += '<div class="script-body">';
127
+ for (const el of spec.elements) {
128
+ const escaped = escapeHtml(el.text);
129
+ switch (el.type) {
130
+ case 'scene_heading':
131
+ bodyContent += `\n<div class="element-scene_heading">${escaped}</div>`;
132
+ break;
133
+ case 'action':
134
+ bodyContent += `\n<div class="element-action">${escaped}</div>`;
135
+ break;
136
+ case 'character':
137
+ bodyContent += `\n<div class="element-character">${escaped}</div>`;
138
+ break;
139
+ case 'parenthetical':
140
+ bodyContent += `\n<div class="element-parenthetical">(${escaped.replace(/^\(|\)$/g, '')})</div>`;
141
+ break;
142
+ case 'dialogue':
143
+ bodyContent += `\n<div class="element-dialogue">${escaped}</div>`;
144
+ break;
145
+ case 'transition':
146
+ bodyContent += `\n<div class="element-transition">${escaped}</div>`;
147
+ break;
148
+ }
149
+ }
150
+ bodyContent += '\n</div>';
151
+ const html = `<!DOCTYPE html>
152
+ <html lang="en">
153
+ <head>
154
+ <meta charset="UTF-8">
155
+ <title>${escapeHtml(spec.title)}</title>
156
+ <style>
157
+ ${css}
158
+ </style>
159
+ </head>
160
+ <body>
161
+ ${bodyContent}
162
+ </body>
163
+ </html>`;
164
+ return { html, css };
165
+ }
166
+ /**
167
+ * Format Production Shot List as print-ready HTML table.
168
+ */
169
+ export function formatShotListHtml(title, shots) {
170
+ const css = `
171
+ @page {
172
+ size: A4 landscape;
173
+ margin: 15mm;
174
+ @bottom-right {
175
+ content: "Page " counter(page) " of " counter(pages);
176
+ font-size: 9pt;
177
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
178
+ }
179
+ }
180
+ body {
181
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
182
+ font-size: 9.5pt;
183
+ color: #111827;
184
+ margin: 0;
185
+ padding: 0;
186
+ }
187
+ .header {
188
+ margin-bottom: 16px;
189
+ border-bottom: 2px solid #0f172a;
190
+ padding-bottom: 8px;
191
+ display: flex;
192
+ justify-content: space-between;
193
+ align-items: baseline;
194
+ }
195
+ .title {
196
+ font-size: 16pt;
197
+ font-weight: 700;
198
+ letter-spacing: -0.02em;
199
+ }
200
+ .subtitle {
201
+ font-size: 10pt;
202
+ color: #4b5563;
203
+ }
204
+ table {
205
+ width: 100%;
206
+ border-collapse: collapse;
207
+ margin-top: 8px;
208
+ }
209
+ th {
210
+ background: #0f172a;
211
+ color: #ffffff;
212
+ font-weight: 600;
213
+ text-align: left;
214
+ padding: 8px 10px;
215
+ font-size: 8.5pt;
216
+ text-transform: uppercase;
217
+ letter-spacing: 0.05em;
218
+ }
219
+ td {
220
+ padding: 8px 10px;
221
+ border-bottom: 1px solid #e2e8f0;
222
+ vertical-align: top;
223
+ line-height: 1.4;
224
+ }
225
+ tr:nth-child(even) td {
226
+ background: #f8fafc;
227
+ }
228
+ tr {
229
+ page-break-inside: avoid;
230
+ }
231
+ .badge {
232
+ display: inline-block;
233
+ padding: 2px 6px;
234
+ border-radius: 4px;
235
+ font-size: 7.5pt;
236
+ font-weight: 600;
237
+ background: #e0e7ff;
238
+ color: #3730a3;
239
+ }
240
+ `.trim();
241
+ let totalDuration = 0;
242
+ const rows = shots
243
+ .map((s) => {
244
+ totalDuration += s.durationSeconds;
245
+ return `
246
+ <tr>
247
+ <td style="font-weight: bold; width: 40px;">${escapeHtml(String(s.shotNumber))}</td>
248
+ <td style="width: 70px;">${escapeHtml(s.scene || '-')}</td>
249
+ <td style="width: 70px;"><span class="badge">${escapeHtml(s.framing)}</span></td>
250
+ <td style="width: 90px;">${escapeHtml(s.angle || 'Eye-level')}</td>
251
+ <td style="width: 90px;">${escapeHtml(s.movement || 'Static')}</td>
252
+ <td style="width: 60px;">${escapeHtml(s.lens || '-')}</td>
253
+ <td><strong>${escapeHtml(s.subject)}</strong> — ${escapeHtml(s.action)}</td>
254
+ <td style="width: 160px; font-size: 8.5pt; color: #475569;">${escapeHtml(s.audioOrSfx || '-')}</td>
255
+ <td style="text-align: right; font-weight: 600; width: 50px;">${s.durationSeconds}s</td>
256
+ </tr>`;
257
+ })
258
+ .join('');
259
+ const html = `<!DOCTYPE html>
260
+ <html lang="en">
261
+ <head>
262
+ <meta charset="UTF-8">
263
+ <title>${escapeHtml(title)} - Shot List</title>
264
+ <style>${css}</style>
265
+ </head>
266
+ <body>
267
+ <div class="header">
268
+ <div class="title">${escapeHtml(title)} — Production Shot List</div>
269
+ <div class="subtitle">Total Shots: ${shots.length} | Est. Duration: ${totalDuration}s (${(totalDuration / 60).toFixed(1)} min)</div>
270
+ </div>
271
+ <table>
272
+ <thead>
273
+ <tr>
274
+ <th>Shot</th>
275
+ <th>Scene</th>
276
+ <th>Framing</th>
277
+ <th>Angle</th>
278
+ <th>Movement</th>
279
+ <th>Lens</th>
280
+ <th>Subject & Action Description</th>
281
+ <th>Audio / SFX Cue</th>
282
+ <th style="text-align: right;">Dur</th>
283
+ </tr>
284
+ </thead>
285
+ <tbody>
286
+ ${rows}
287
+ </tbody>
288
+ </table>
289
+ </body>
290
+ </html>`;
291
+ return { html, css };
292
+ }
293
+ /**
294
+ * Analyze Voice-Over / Dubbing blocks for Word-Per-Minute (WPM) cadence.
295
+ * Target: 130-155 WPM for natural documentary/commercial narration.
296
+ */
297
+ export function analyzeVoiceOverTiming(blocks) {
298
+ let totalWords = 0;
299
+ let totalDuration = 0;
300
+ const analyzed = blocks.map((b) => {
301
+ const words = b.text.trim().split(/\s+/).filter(Boolean).length;
302
+ totalWords += words;
303
+ totalDuration += b.targetDurationSeconds;
304
+ const minutes = b.targetDurationSeconds / 60;
305
+ const wpm = minutes > 0 ? Math.round(words / minutes) : 0;
306
+ let status = 'optimal';
307
+ if (wpm > 165)
308
+ status = 'too_fast';
309
+ else if (wpm < 115)
310
+ status = 'too_slow';
311
+ return {
312
+ id: b.id,
313
+ timecode: b.timecode,
314
+ text: b.text,
315
+ wordCount: words,
316
+ targetDurationSeconds: b.targetDurationSeconds,
317
+ wpm,
318
+ status
319
+ };
320
+ });
321
+ const avgMinutes = totalDuration / 60;
322
+ const averageWpm = avgMinutes > 0 ? Math.round(totalWords / avgMinutes) : 0;
323
+ return {
324
+ blocks: analyzed,
325
+ totalWords,
326
+ totalDurationSeconds: totalDuration,
327
+ averageWpm
328
+ };
329
+ }
330
+ function escapeHtml(str) {
331
+ return String(str || '')
332
+ .replace(/&/g, '&amp;')
333
+ .replace(/</g, '&lt;')
334
+ .replace(/>/g, '&gt;')
335
+ .replace(/"/g, '&quot;');
336
+ }