@vsuryav/agent-sim 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/bin/agent-sim.js +25 -0
- package/package.json +72 -0
- package/src/app-paths.ts +29 -0
- package/src/app-sync.test.ts +75 -0
- package/src/app-sync.ts +110 -0
- package/src/cli.ts +129 -0
- package/src/collector/claude-code.test.ts +102 -0
- package/src/collector/claude-code.ts +133 -0
- package/src/collector/codex-cli.test.ts +116 -0
- package/src/collector/codex-cli.ts +149 -0
- package/src/collector/db.test.ts +59 -0
- package/src/collector/db.ts +125 -0
- package/src/collector/names.test.ts +21 -0
- package/src/collector/names.ts +28 -0
- package/src/collector/personality.test.ts +40 -0
- package/src/collector/personality.ts +46 -0
- package/src/collector/remote-sync.test.ts +31 -0
- package/src/collector/remote-sync.ts +171 -0
- package/src/collector/sync.test.ts +67 -0
- package/src/collector/sync.ts +148 -0
- package/src/collector/types.ts +1 -0
- package/src/engine/bootstrap/state.ts +3 -0
- package/src/engine/buddy/CompanionSprite.tsx +371 -0
- package/src/engine/buddy/companion.ts +133 -0
- package/src/engine/buddy/prompt.ts +36 -0
- package/src/engine/buddy/sprites.ts +514 -0
- package/src/engine/buddy/types.ts +148 -0
- package/src/engine/buddy/useBuddyNotification.tsx +98 -0
- package/src/engine/ink/Ansi.tsx +292 -0
- package/src/engine/ink/bidi.ts +139 -0
- package/src/engine/ink/clearTerminal.ts +74 -0
- package/src/engine/ink/colorize.ts +231 -0
- package/src/engine/ink/components/AlternateScreen.tsx +80 -0
- package/src/engine/ink/components/App.tsx +658 -0
- package/src/engine/ink/components/AppContext.ts +21 -0
- package/src/engine/ink/components/Box.tsx +214 -0
- package/src/engine/ink/components/Button.tsx +192 -0
- package/src/engine/ink/components/ClockContext.tsx +112 -0
- package/src/engine/ink/components/CursorDeclarationContext.ts +32 -0
- package/src/engine/ink/components/ErrorOverview.tsx +109 -0
- package/src/engine/ink/components/Link.tsx +42 -0
- package/src/engine/ink/components/Newline.tsx +39 -0
- package/src/engine/ink/components/NoSelect.tsx +68 -0
- package/src/engine/ink/components/RawAnsi.tsx +57 -0
- package/src/engine/ink/components/ScrollBox.tsx +237 -0
- package/src/engine/ink/components/Spacer.tsx +20 -0
- package/src/engine/ink/components/StdinContext.ts +49 -0
- package/src/engine/ink/components/TerminalFocusContext.tsx +52 -0
- package/src/engine/ink/components/TerminalSizeContext.tsx +7 -0
- package/src/engine/ink/components/Text.tsx +254 -0
- package/src/engine/ink/constants.ts +2 -0
- package/src/engine/ink/dom.ts +484 -0
- package/src/engine/ink/events/click-event.ts +38 -0
- package/src/engine/ink/events/dispatcher.ts +233 -0
- package/src/engine/ink/events/emitter.ts +39 -0
- package/src/engine/ink/events/event-handlers.ts +73 -0
- package/src/engine/ink/events/event.ts +11 -0
- package/src/engine/ink/events/focus-event.ts +21 -0
- package/src/engine/ink/events/input-event.ts +205 -0
- package/src/engine/ink/events/keyboard-event.ts +51 -0
- package/src/engine/ink/events/terminal-event.ts +107 -0
- package/src/engine/ink/events/terminal-focus-event.ts +19 -0
- package/src/engine/ink/focus.ts +181 -0
- package/src/engine/ink/frame.ts +124 -0
- package/src/engine/ink/get-max-width.ts +27 -0
- package/src/engine/ink/global.d.ts +18 -0
- package/src/engine/ink/hit-test.ts +130 -0
- package/src/engine/ink/hooks/use-animation-frame.ts +57 -0
- package/src/engine/ink/hooks/use-app.ts +8 -0
- package/src/engine/ink/hooks/use-declared-cursor.ts +73 -0
- package/src/engine/ink/hooks/use-input.ts +92 -0
- package/src/engine/ink/hooks/use-interval.ts +67 -0
- package/src/engine/ink/hooks/use-search-highlight.ts +53 -0
- package/src/engine/ink/hooks/use-selection.ts +104 -0
- package/src/engine/ink/hooks/use-stdin.ts +8 -0
- package/src/engine/ink/hooks/use-tab-status.ts +72 -0
- package/src/engine/ink/hooks/use-terminal-focus.ts +16 -0
- package/src/engine/ink/hooks/use-terminal-title.ts +31 -0
- package/src/engine/ink/hooks/use-terminal-viewport.ts +96 -0
- package/src/engine/ink/ink.tsx +1723 -0
- package/src/engine/ink/instances.ts +10 -0
- package/src/engine/ink/layout/engine.ts +6 -0
- package/src/engine/ink/layout/geometry.ts +97 -0
- package/src/engine/ink/layout/node.ts +152 -0
- package/src/engine/ink/layout/yoga.ts +308 -0
- package/src/engine/ink/line-width-cache.ts +24 -0
- package/src/engine/ink/log-update.ts +773 -0
- package/src/engine/ink/measure-element.ts +23 -0
- package/src/engine/ink/measure-text.ts +47 -0
- package/src/engine/ink/node-cache.ts +54 -0
- package/src/engine/ink/optimizer.ts +93 -0
- package/src/engine/ink/output.ts +797 -0
- package/src/engine/ink/parse-keypress.ts +801 -0
- package/src/engine/ink/reconciler.ts +512 -0
- package/src/engine/ink/render-border.ts +231 -0
- package/src/engine/ink/render-node-to-output.ts +1462 -0
- package/src/engine/ink/render-to-screen.ts +231 -0
- package/src/engine/ink/renderer.ts +178 -0
- package/src/engine/ink/root.ts +184 -0
- package/src/engine/ink/screen.ts +1486 -0
- package/src/engine/ink/searchHighlight.ts +93 -0
- package/src/engine/ink/selection.ts +917 -0
- package/src/engine/ink/squash-text-nodes.ts +92 -0
- package/src/engine/ink/stringWidth.ts +222 -0
- package/src/engine/ink/styles.ts +771 -0
- package/src/engine/ink/supports-hyperlinks.ts +57 -0
- package/src/engine/ink/tabstops.ts +46 -0
- package/src/engine/ink/terminal-focus-state.ts +47 -0
- package/src/engine/ink/terminal-querier.ts +212 -0
- package/src/engine/ink/terminal.ts +248 -0
- package/src/engine/ink/termio/ansi.ts +75 -0
- package/src/engine/ink/termio/csi.ts +319 -0
- package/src/engine/ink/termio/dec.ts +60 -0
- package/src/engine/ink/termio/esc.ts +67 -0
- package/src/engine/ink/termio/osc.ts +493 -0
- package/src/engine/ink/termio/parser.ts +394 -0
- package/src/engine/ink/termio/sgr.ts +308 -0
- package/src/engine/ink/termio/tokenize.ts +319 -0
- package/src/engine/ink/termio/types.ts +236 -0
- package/src/engine/ink/useTerminalNotification.ts +126 -0
- package/src/engine/ink/warn.ts +9 -0
- package/src/engine/ink/widest-line.ts +19 -0
- package/src/engine/ink/wrap-text.ts +74 -0
- package/src/engine/ink/wrapAnsi.ts +20 -0
- package/src/engine/native-ts/yoga-layout/enums.ts +134 -0
- package/src/engine/native-ts/yoga-layout/index.ts +2578 -0
- package/src/engine/stubs/bootstrap-state.ts +4 -0
- package/src/engine/stubs/debug.ts +6 -0
- package/src/engine/stubs/log.ts +4 -0
- package/src/engine/utils/debug.ts +5 -0
- package/src/engine/utils/earlyInput.ts +4 -0
- package/src/engine/utils/env.ts +15 -0
- package/src/engine/utils/envUtils.ts +4 -0
- package/src/engine/utils/execFileNoThrow.ts +24 -0
- package/src/engine/utils/fullscreen.ts +4 -0
- package/src/engine/utils/intl.ts +9 -0
- package/src/engine/utils/log.ts +3 -0
- package/src/engine/utils/semver.ts +13 -0
- package/src/engine/utils/sliceAnsi.ts +10 -0
- package/src/engine/utils/theme.ts +17 -0
- package/src/game/App.tsx +141 -0
- package/src/game/agents/behavior.ts +249 -0
- package/src/game/agents/speech.ts +57 -0
- package/src/game/canvas.ts +98 -0
- package/src/game/launch.ts +36 -0
- package/src/game/ship/ShipView.tsx +145 -0
- package/src/game/ship/ship-map.ts +172 -0
- package/src/game/ui/AgentBio.tsx +72 -0
- package/src/game/ui/HUD.tsx +63 -0
- package/src/game/ui/StatusBar.tsx +49 -0
- package/src/game/useKeyboard.ts +62 -0
- package/src/main.tsx +22 -0
- package/src/run-interactive.ts +74 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DOMElement } from './dom.js'
|
|
2
|
+
|
|
3
|
+
type Output = {
|
|
4
|
+
/**
|
|
5
|
+
* Element width.
|
|
6
|
+
*/
|
|
7
|
+
width: number
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Element height.
|
|
11
|
+
*/
|
|
12
|
+
height: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Measure the dimensions of a particular `<Box>` element.
|
|
17
|
+
*/
|
|
18
|
+
const measureElement = (node: DOMElement): Output => ({
|
|
19
|
+
width: node.yogaNode?.getComputedWidth() ?? 0,
|
|
20
|
+
height: node.yogaNode?.getComputedHeight() ?? 0,
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
export default measureElement
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { lineWidth } from './line-width-cache.js'
|
|
2
|
+
|
|
3
|
+
type Output = {
|
|
4
|
+
width: number
|
|
5
|
+
height: number
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// Single-pass measurement: computes both width and height in one
|
|
9
|
+
// iteration instead of two (widestLine + countVisualLines).
|
|
10
|
+
// Uses indexOf to avoid array allocation from split('\n').
|
|
11
|
+
function measureText(text: string, maxWidth: number): Output {
|
|
12
|
+
if (text.length === 0) {
|
|
13
|
+
return {
|
|
14
|
+
width: 0,
|
|
15
|
+
height: 0,
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Infinite or non-positive width means no wrapping — each line is one visual line.
|
|
20
|
+
// Must check before the loop since Math.ceil(w / Infinity) = 0.
|
|
21
|
+
const noWrap = maxWidth <= 0 || !Number.isFinite(maxWidth)
|
|
22
|
+
|
|
23
|
+
let height = 0
|
|
24
|
+
let width = 0
|
|
25
|
+
let start = 0
|
|
26
|
+
|
|
27
|
+
while (start <= text.length) {
|
|
28
|
+
const end = text.indexOf('\n', start)
|
|
29
|
+
const line = end === -1 ? text.substring(start) : text.substring(start, end)
|
|
30
|
+
|
|
31
|
+
const w = lineWidth(line)
|
|
32
|
+
width = Math.max(width, w)
|
|
33
|
+
|
|
34
|
+
if (noWrap) {
|
|
35
|
+
height++
|
|
36
|
+
} else {
|
|
37
|
+
height += w === 0 ? 1 : Math.ceil(w / maxWidth)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (end === -1) break
|
|
41
|
+
start = end + 1
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return { width, height }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default measureText
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { DOMElement } from './dom.js'
|
|
2
|
+
import type { Rectangle } from './layout/geometry.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Cached layout bounds for each rendered node (used for blit + clearing).
|
|
6
|
+
* `top` is the yoga-local getComputedTop() — stored so ScrollBox viewport
|
|
7
|
+
* culling can skip yoga reads for clean children whose position hasn't
|
|
8
|
+
* shifted (O(dirty) instead of O(mounted) first-pass).
|
|
9
|
+
*/
|
|
10
|
+
export type CachedLayout = {
|
|
11
|
+
x: number
|
|
12
|
+
y: number
|
|
13
|
+
width: number
|
|
14
|
+
height: number
|
|
15
|
+
top?: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const nodeCache = new WeakMap<DOMElement, CachedLayout>()
|
|
19
|
+
|
|
20
|
+
/** Rects of removed children that need clearing on next render */
|
|
21
|
+
export const pendingClears = new WeakMap<DOMElement, Rectangle[]>()
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Set when a pendingClear is added for an absolute-positioned node.
|
|
25
|
+
* Signals renderer to disable blit for the next frame: the removed node
|
|
26
|
+
* may have painted over non-siblings (e.g. an overlay over a ScrollBox
|
|
27
|
+
* earlier in tree order), so their blits from prevScreen would restore
|
|
28
|
+
* the overlay's pixels. Normal-flow removals are already handled by
|
|
29
|
+
* hasRemovedChild at the parent level; only absolute positioning paints
|
|
30
|
+
* cross-subtree. Reset at the start of each render.
|
|
31
|
+
*/
|
|
32
|
+
let absoluteNodeRemoved = false
|
|
33
|
+
|
|
34
|
+
export function addPendingClear(
|
|
35
|
+
parent: DOMElement,
|
|
36
|
+
rect: Rectangle,
|
|
37
|
+
isAbsolute: boolean,
|
|
38
|
+
): void {
|
|
39
|
+
const existing = pendingClears.get(parent)
|
|
40
|
+
if (existing) {
|
|
41
|
+
existing.push(rect)
|
|
42
|
+
} else {
|
|
43
|
+
pendingClears.set(parent, [rect])
|
|
44
|
+
}
|
|
45
|
+
if (isAbsolute) {
|
|
46
|
+
absoluteNodeRemoved = true
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function consumeAbsoluteRemovedFlag(): boolean {
|
|
51
|
+
const had = absoluteNodeRemoved
|
|
52
|
+
absoluteNodeRemoved = false
|
|
53
|
+
return had
|
|
54
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { Diff } from './frame.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Optimize a diff by applying all optimization rules in a single pass.
|
|
5
|
+
* This reduces the number of patches that need to be written to the terminal.
|
|
6
|
+
*
|
|
7
|
+
* Rules applied:
|
|
8
|
+
* - Remove empty stdout patches
|
|
9
|
+
* - Merge consecutive cursorMove patches
|
|
10
|
+
* - Remove no-op cursorMove (0,0) patches
|
|
11
|
+
* - Concat adjacent style patches (transition diffs — can't drop either)
|
|
12
|
+
* - Dedupe consecutive hyperlinks with same URI
|
|
13
|
+
* - Cancel cursor hide/show pairs
|
|
14
|
+
* - Remove clear patches with count 0
|
|
15
|
+
*/
|
|
16
|
+
export function optimize(diff: Diff): Diff {
|
|
17
|
+
if (diff.length <= 1) {
|
|
18
|
+
return diff
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const result: Diff = []
|
|
22
|
+
let len = 0
|
|
23
|
+
|
|
24
|
+
for (const patch of diff) {
|
|
25
|
+
const type = patch.type
|
|
26
|
+
|
|
27
|
+
// Skip no-ops
|
|
28
|
+
if (type === 'stdout') {
|
|
29
|
+
if (patch.content === '') continue
|
|
30
|
+
} else if (type === 'cursorMove') {
|
|
31
|
+
if (patch.x === 0 && patch.y === 0) continue
|
|
32
|
+
} else if (type === 'clear') {
|
|
33
|
+
if (patch.count === 0) continue
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Try to merge with previous patch
|
|
37
|
+
if (len > 0) {
|
|
38
|
+
const lastIdx = len - 1
|
|
39
|
+
const last = result[lastIdx]!
|
|
40
|
+
const lastType = last.type
|
|
41
|
+
|
|
42
|
+
// Merge consecutive cursorMove
|
|
43
|
+
if (type === 'cursorMove' && lastType === 'cursorMove') {
|
|
44
|
+
result[lastIdx] = {
|
|
45
|
+
type: 'cursorMove',
|
|
46
|
+
x: last.x + patch.x,
|
|
47
|
+
y: last.y + patch.y,
|
|
48
|
+
}
|
|
49
|
+
continue
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Collapse consecutive cursorTo (only the last one matters)
|
|
53
|
+
if (type === 'cursorTo' && lastType === 'cursorTo') {
|
|
54
|
+
result[lastIdx] = patch
|
|
55
|
+
continue
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Concat adjacent style patches. styleStr is a transition diff
|
|
59
|
+
// (computed by diffAnsiCodes(from, to)), not a setter — dropping
|
|
60
|
+
// the first is only sound if its undo-codes are a subset of the
|
|
61
|
+
// second's, which is NOT guaranteed. e.g. [\e[49m, \e[2m]: dropping
|
|
62
|
+
// the bg reset leaks it into the next \e[2J/\e[2K via BCE.
|
|
63
|
+
if (type === 'styleStr' && lastType === 'styleStr') {
|
|
64
|
+
result[lastIdx] = { type: 'styleStr', str: last.str + patch.str }
|
|
65
|
+
continue
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Dedupe hyperlinks
|
|
69
|
+
if (
|
|
70
|
+
type === 'hyperlink' &&
|
|
71
|
+
lastType === 'hyperlink' &&
|
|
72
|
+
patch.uri === last.uri
|
|
73
|
+
) {
|
|
74
|
+
continue
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Cancel cursor hide/show pairs
|
|
78
|
+
if (
|
|
79
|
+
(type === 'cursorShow' && lastType === 'cursorHide') ||
|
|
80
|
+
(type === 'cursorHide' && lastType === 'cursorShow')
|
|
81
|
+
) {
|
|
82
|
+
result.pop()
|
|
83
|
+
len--
|
|
84
|
+
continue
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
result.push(patch)
|
|
89
|
+
len++
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return result
|
|
93
|
+
}
|