rvlib-shipkit 2.2.0 → 2.3.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 (107) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/package.json +1 -1
  3. package/src/agent-time/mask.ts +43 -0
  4. package/src/agent-time/render.ts +187 -0
  5. package/src/agent-time/report.ts +335 -0
  6. package/src/agent-time/shape.ts +271 -0
  7. package/src/agent-time/signals.ts +84 -0
  8. package/src/agent-time/store.ts +379 -0
  9. package/src/agent-time/timeline.ts +218 -0
  10. package/src/agent-time/turns.ts +135 -0
  11. package/src/cli/cmd_Commands.ts +5 -0
  12. package/src/cli/cmd_Review.ts +948 -0
  13. package/src/cli/cmd_Time.ts +112 -0
  14. package/src/cli/cmd_Trailer.ts +259 -6
  15. package/src/cli/kit/verb.ts +14 -4
  16. package/src/cli.ts +6 -4
  17. package/src/collections/collection-types.ts +6 -1
  18. package/src/collections/providers.ts +3 -0
  19. package/src/collections/review.ts +70 -0
  20. package/src/core/layout.ts +2 -0
  21. package/src/reflect/prompt-corpus.ts +15 -119
  22. package/src/reflect/transcript.ts +254 -0
  23. package/src/review/anim.ts +228 -0
  24. package/src/review/auto.ts +141 -0
  25. package/src/review/format.ts +150 -0
  26. package/src/review/http.ts +23 -0
  27. package/src/review/marks.ts +43 -0
  28. package/src/review/media.ts +45 -0
  29. package/src/review/model.ts +854 -0
  30. package/src/review/project.ts +110 -0
  31. package/src/review/role.ts +48 -0
  32. package/src/review/routes.ts +228 -0
  33. package/src/review/store.ts +1002 -0
  34. package/src/review/threads.ts +237 -0
  35. package/src/review/trailer-desk.ts +385 -0
  36. package/src/review/trailer-model.ts +183 -0
  37. package/src/review/trailer-routes.ts +136 -0
  38. package/src/review/unit.ts +165 -0
  39. package/src/review/watchers.ts +54 -0
  40. package/src/serve/embed.ts +35 -0
  41. package/src/serve/hub-app/activity-view.tsx +1 -1
  42. package/src/serve/hub-app/activity.css +0 -4
  43. package/src/serve/hub-app/dock-view.tsx +5 -4
  44. package/src/serve/hub-app/hash-route.ts +28 -1
  45. package/src/serve/hub-app/header-bar.tsx +3 -1
  46. package/src/serve/hub-app/home-st.ts +10 -2
  47. package/src/serve/hub-app/home-strip.tsx +3 -2
  48. package/src/serve/hub-app/home.html +1 -0
  49. package/src/serve/hub-app/hub-app.tsx +80 -11
  50. package/src/serve/hub-app/hub.css +45 -13
  51. package/src/serve/hub-app/icons.tsx +9 -0
  52. package/src/serve/hub-app/index.html +1 -0
  53. package/src/serve/hub-app/insights-view.tsx +4 -3
  54. package/src/serve/hub-app/keys.ts +14 -10
  55. package/src/serve/hub-app/layout-st.ts +63 -2
  56. package/src/serve/hub-app/planned-view.tsx +3 -2
  57. package/src/serve/hub-app/planned.css +0 -1
  58. package/src/serve/hub-app/project-list.css +22 -4
  59. package/src/serve/hub-app/project-list.tsx +41 -8
  60. package/src/serve/hub-app/projects-svc.ts +4 -0
  61. package/src/serve/hub-app/repo-sections.ts +15 -3
  62. package/src/serve/hub-app/repo-st.ts +45 -3
  63. package/src/serve/hub-app/review/clip-st.ts +208 -0
  64. package/src/serve/hub-app/review/kind-view.tsx +171 -0
  65. package/src/serve/hub-app/review/kit.tsx +113 -0
  66. package/src/serve/hub-app/review/review-answer.tsx +239 -0
  67. package/src/serve/hub-app/review/review-board.tsx +46 -0
  68. package/src/serve/hub-app/review/review-list.tsx +156 -0
  69. package/src/serve/hub-app/review/review-page.tsx +101 -0
  70. package/src/serve/hub-app/review/review-st.ts +779 -0
  71. package/src/serve/hub-app/review/review-views.tsx +503 -0
  72. package/src/serve/hub-app/review/trailer-page.tsx +416 -0
  73. package/src/serve/hub-app/review/trailer-st.ts +602 -0
  74. package/src/serve/hub-app/review/trailer-timeline.tsx +207 -0
  75. package/src/serve/hub-app/review.css +329 -0
  76. package/src/serve/hub-app/theme-st.ts +56 -0
  77. package/src/serve/hub-app/tree-build.ts +4 -0
  78. package/src/serve/hub-app/tree-row.tsx +1 -1
  79. package/src/serve/hub-app/tree-svc.ts +4 -0
  80. package/src/serve/hub-runtime.ts +5 -3
  81. package/src/serve/same-origin.ts +5 -1
  82. package/src/serve/serve-hub.ts +8 -0
  83. package/src/shipkit-files.ts +9 -5
  84. package/src/trailer/adapter.ts +58 -3
  85. package/src/trailer/build.ts +300 -41
  86. package/src/trailer/ffmpeg.ts +22 -0
  87. package/src/trailer/footage.ts +109 -40
  88. package/src/trailer/grammar.ts +444 -69
  89. package/src/trailer/graph.ts +199 -14
  90. package/src/trailer/holes.ts +72 -0
  91. package/src/trailer/load-unit.ts +20 -3
  92. package/src/trailer/look.ts +17 -3
  93. package/src/trailer/passage.ts +129 -0
  94. package/src/trailer/plan.ts +80 -21
  95. package/src/trailer/prune.ts +193 -0
  96. package/src/trailer/score/compose.ts +240 -0
  97. package/src/trailer/score/dsp.ts +272 -0
  98. package/src/trailer/score/palette.ts +188 -0
  99. package/src/trailer/score/pattern.ts +91 -0
  100. package/src/trailer/score/score.ts +214 -0
  101. package/src/trailer/score/sound.ts +112 -0
  102. package/src/trailer/score/synth.ts +361 -0
  103. package/src/trailer/states.ts +76 -0
  104. package/src/trailer/stitch.ts +92 -9
  105. package/src/trailer/titles.ts +123 -18
  106. package/src/trailer/vocab.ts +23 -4
  107. package/src/trailer/words.ts +254 -0
@@ -0,0 +1,135 @@
1
+ // Turn count: what makes an agent slow when no command is. Every tool call
2
+ // costs a model turn before it, so an agent that reads one file per turn
3
+ // spends its wall on the model, not on the reads. The two questions this
4
+ // module answers on pure data: was a call a single read, and did it go out in
5
+ // parallel with the one before it.
6
+ //
7
+ // The constraint a reader breaks first: a read is judged on the WHOLE command,
8
+ // never on its shape alone. `grep -l x | xargs sed -i` shapes as `grep`, and
9
+ // it writes.
10
+ import { stripHeredocs } from './shape.ts'
11
+ import type { Closed } from './timeline.ts'
12
+
13
+ /** bumped with any read rule below: the index judges every stored call again */
14
+ export const READ_VERSION = 1
15
+
16
+ /** tools that only read */
17
+ export const READ_TOOLS: ReadonlySet<string> = new Set(['Read', 'Grep', 'Glob'])
18
+
19
+ /** Bash shapes that only read (shape.ts names them). `sed` without `-i` prints;
20
+ * `sed -i` is shaped `sed -i (edit)` and `cat > f` is `cat > (write)`, so
21
+ * neither is here */
22
+ export const READ_SHAPES: ReadonlySet<string> = new Set(['grep', 'rg', 'git grep', 'sed', 'cat', 'ls', 'head', 'tail', 'wc', 'find', 'git status', 'git log', 'git diff', 'git show'])
23
+
24
+ /** words a read command may carry beside its read: scene setting, loop and
25
+ * test words, a filter it pipes into, a print */
26
+ const BESIDE = new Set([
27
+ 'cd', 'pushd', 'popd', 'export', 'set', 'true', ':', 'time', 'for', 'do', 'done', 'while', 'if', 'then', 'else', 'fi', '[', '[[', 'test',
28
+ 'echo', 'printf', 'pwd', 'uptime', 'date', 'which', 'basename', 'dirname', 'realpath', 'stat', 'file', 'du', 'tree', 'diff',
29
+ 'sort', 'uniq', 'cut', 'tr', 'nl', 'column', 'jq', 'awk', 'xargs', 'grep', 'egrep', 'rg', 'head', 'tail', 'wc', 'cat', 'sed', 'ls', 'find', 'git',
30
+ ])
31
+
32
+ /** a find action that writes or runs something */
33
+ const FIND_ACTS = /\s-(?:delete|exec|execdir|ok|okdir|fprint0?|fprintf|fls)\b/
34
+
35
+ /** git subcommands that only read */
36
+ const GIT_READS = new Set(['status', 'log', 'diff', 'show', 'grep', 'ls-files', 'ls-tree', 'rev-parse', 'rev-list', 'merge-base', 'cat-file', 'describe', 'shortlog', 'branch', 'blame'])
37
+
38
+ /** the parts of a command line: statements and every pipeline part, quoted
39
+ * text blanked (a pattern is never a separator nor a redirect) */
40
+ const parts = (command: string): string[] =>
41
+ (command.includes('<<') ? stripHeredocs(command) : command)
42
+ .replace(/\\\n/g, ' ')
43
+ .replace(/'[^']*'|"(?:[^"\\]|\\.)*"/g, '""')
44
+ .split(/&&|\|\||[;\n|]|(?<![>&])&(?![>&])/)
45
+
46
+ /** an output redirect to a file: `> f`, `>> f`, `&> f`; `2>&1` and
47
+ * `> /dev/null` write nothing */
48
+ const writesFile = (part: string): boolean => {
49
+ for (const m of part.matchAll(/>{1,2}\s*([^\s>]*)/g)) {
50
+ const target = m[1] ?? ''
51
+ if (target === '' || target.startsWith('&') || target === '/dev/null' || target.startsWith('/dev/std')) continue
52
+ return true
53
+ }
54
+ return false
55
+ }
56
+
57
+ /** the words of a part after env assignments and a leading `X=$(` */
58
+ const HEAD = /^[\s(]*(?:[A-Za-z_][A-Za-z0-9_]*=(?:\$\(|\S*\s+))*(\S+)\s*(.*)$/s
59
+
60
+ /** one part of the line reads only */
61
+ function partReads(part: string, whole: string): boolean {
62
+ if (writesFile(part)) return false
63
+ if (/^\s*[A-Za-z_][A-Za-z0-9_]*=\S*\s*$/.test(part)) return true
64
+ const m = HEAD.exec(part)
65
+ if (m == null) return true
66
+ const head = (m[1] as string).replace(/^.*\//, '').replace(/\)+$/, '')
67
+ const rest = ` ${m[2] ?? ''}`
68
+ if (!BESIDE.has(head)) return false
69
+ if (head === 'sed') return !/\s-[a-zA-Z]*i|\s--in-place/.test(rest)
70
+ if (head === 'find') return !FIND_ACTS.test(rest)
71
+ if (head === 'awk') return !/system\(|print[^;'"]*>/.test(whole)
72
+ if (head === 'xargs') return partReads(rest.replace(/^(?:\s+-\S+(?:\s+\d+)?)*/, ''), whole)
73
+ if (head === 'git') return GIT_READS.has(/^(?:\s+-[Cc]\s+\S+|\s+-\S+)*\s+(\S+)/.exec(rest)?.[1] ?? '')
74
+ if (head === 'do' || head === 'then' || head === 'else') return rest.trim() === '' || partReads(rest, whole)
75
+ return true
76
+ }
77
+
78
+ /** the call only read: a read tool, or a Bash command of a read shape (a for
79
+ * loop over one included) whose every part reads */
80
+ export function isReadOnly(c: { tool: string; shape: string; cmd: string }): boolean {
81
+ if (READ_TOOLS.has(c.tool)) return true
82
+ if (c.tool !== 'Bash' || !READ_SHAPES.has(c.shape.replace(/^\(for\) /, ''))) return false
83
+ return parts(c.cmd).every((p) => p.trim() === '' || partReads(p, c.cmd))
84
+ }
85
+
86
+ /** a call issued this soon after the one before, while that one still ran,
87
+ * went out in the same turn */
88
+ export const PARALLEL_MS = 2000
89
+
90
+ /** one flag per call (sorted by start, closeCalls): it started before the
91
+ * previous call ended, within PARALLEL_MS of its start */
92
+ export function parallelFlags(calls: readonly Closed[]): boolean[] {
93
+ return calls.map((c, i) => {
94
+ const prev = calls[i - 1]
95
+ return prev != null && c.start < prev.stop && c.start - prev.start <= PARALLEL_MS
96
+ })
97
+ }
98
+
99
+ /** the turn metrics of a set of streams */
100
+ export type TurnStats = { calls: number; reads: number; parallel: number; model: number }
101
+
102
+ export const emptyTurns = (): TurnStats => ({ calls: 0, reads: 0, parallel: 0, model: 0 })
103
+
104
+ export const addTurns = (into: TurnStats, t: TurnStats): TurnStats => {
105
+ into.calls += t.calls
106
+ into.reads += t.reads
107
+ into.parallel += t.parallel
108
+ into.model += t.model
109
+ return into
110
+ }
111
+
112
+ /** what a read shape costs in model turns: its calls, and the model time of
113
+ * the turns that issued them */
114
+ export type ReadCost = { shape: string; calls: number; model: number }
115
+
116
+ /** a read call's name in the cost table: its tool, or its Bash shape */
117
+ export const readName = (c: { tool: string; shape: string }): string => (c.tool === 'Bash' ? c.shape : c.tool)
118
+
119
+ /** the turns of one stream: `model` is its model bucket, `turnModel` the
120
+ * per call share wallBreakdown filled; read calls add to `costs` */
121
+ export function turnsOf(calls: readonly Closed[], model: number, turnModel: Float64Array, costs: Map<string, ReadCost>): TurnStats {
122
+ const par = parallelFlags(calls)
123
+ const t: TurnStats = { calls: calls.length, reads: 0, parallel: 0, model }
124
+ calls.forEach((c, i) => {
125
+ if (par[i]) t.parallel++
126
+ if (!c.read) return
127
+ t.reads++
128
+ const name = readName(c)
129
+ const row = costs.get(name) ?? { shape: name, calls: 0, model: 0 }
130
+ row.calls++
131
+ row.model += turnModel[i] ?? 0
132
+ costs.set(name, row)
133
+ })
134
+ return t
135
+ }
@@ -17,6 +17,9 @@ export type CommandRow = {
17
17
  examples: [string, string][]
18
18
  /** a filmable command (cli/kit/verb.ts): takes --out, a clip also --seconds */
19
19
  film?: Film
20
+ /** a filmable command's take version and length (build/trailer.md, Film lines) */
21
+ version?: number | string
22
+ length?: 'own'
20
23
  /** listed on the essentials page */
21
24
  essential?: Essential
22
25
  /** what a kit row runs */
@@ -76,6 +79,8 @@ export function commandRows(plain: Definition[], detailed: Definition[] = [], bi
76
79
  if (c != null) {
77
80
  const m = marksOf(c)
78
81
  if (m.film != null) row.film = m.film
82
+ if (m.version != null) row.version = m.version
83
+ if (m.length != null) row.length = m.length
79
84
  if (m.essential != null) row.essential = m.essential
80
85
  const v = ROW_OF.get(c)
81
86
  if (v != null) row.runs = runText(v.run)