opencode-context-indicator 1.7.1 → 1.8.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/lib/tui-data.js CHANGED
@@ -1,13 +1,13 @@
1
1
  // lib/tui-data.js
2
2
  //
3
- // Data layer for the TUI entry (tui.tsx): the state.json bridge (readSnapshot /
3
+ // Data layer for the TUI entry (tui.ts): the state.json bridge (readSnapshot /
4
4
  // isEmptyEntry / collectFamily), the shared formatting helpers (fmt / num / fit
5
- // / updatedAt) and the npm-install detection. Plain JS with JSDoc — same shape
6
- // as lib/contributors.js — so tui.tsx stays a thin JSX/setup shell and the node
7
- // tooling (resolve gate, future unit tests) can import it without a transform.
5
+ // / updatedAt) and the family walk. Plain JS with JSDoc — same shape as
6
+ // lib/contributors.js — so tui.ts stays a thin setup shell and the node tooling
7
+ // (resolve gate, unit tests) can import it without a transform.
8
8
  //
9
9
  // These helpers must stay free of solid-js / @opentui imports: the TUI host
10
- // bridges those modules only for the JSX entry, and keeping this file pure
10
+ // bridges those modules only for the plugin bundle, and keeping this file pure
11
11
  // means it also loads anywhere node does.
12
12
  //
13
13
  // state.json shape (written by writeStateFile() in index.js, untrusted input):
@@ -20,7 +20,6 @@
20
20
  import { readFileSync } from "node:fs";
21
21
  import { tmpdir } from "node:os";
22
22
  import { join } from "node:path";
23
- import { fileURLToPath } from "node:url";
24
23
  import { isSafeSessionKey, sumCategories } from "./estimate.js";
25
24
  import { fmt, num } from "./format.js";
26
25
 
@@ -38,21 +37,6 @@ export const STATE_FILE =
38
37
 
39
38
  export const POLL_MS = 1000;
40
39
 
41
- // True when this package was loaded from an npm install, i.e. its own file
42
- // path contains a `node_modules` segment (OpenCode's TUI loader skips the host
43
- // Solid transform for such paths → slots mount once but never live-update; see
44
- // the Graceful mode note in tui.tsx). Normalised to forward slashes for
45
- // Windows paths. ANY file of the package yields the same answer, so checking
46
- // from lib/ is equivalent to checking from the tui.tsx entry.
47
- export function isNodeModulesInstall() {
48
- try {
49
- const selfPath = fileURLToPath(import.meta.url).replace(/\\/g, "/").toLowerCase()
50
- return selfPath.includes("/node_modules/")
51
- } catch {
52
- return false
53
- }
54
- }
55
-
56
40
  // Whole state.json snapshot ({ sessionID: entry }) or {} on any error. The
57
41
  // sidebar resolves one entry from it and the breakdown panel walks the
58
42
  // parentID family over it. Never throws — a missing / empty / corrupt
package/lib/tui-h.ts ADDED
@@ -0,0 +1,73 @@
1
+ // lib/tui-h.ts
2
+ //
3
+ // The two tree builders every TUI surface in this package uses instead of JSX.
4
+ //
5
+ // WHY NO JSX (do not "simplify" this back):
6
+ // OpenCode installs npm plugins inside a `node_modules` tree
7
+ // (~/.cache/opencode/npm/<name>@<version>/<ts>/node_modules/<name>). For such
8
+ // paths the host deliberately skips its Solid/Babel JSX transform (sourceFilter
9
+ // in @opentui/solid/scripts/solid-plugin.js excludes node_modules, upstream
10
+ // anomalyco/opencode#33884). A JSX-compiled file in that position also needs
11
+ // `@opentui/solid` to be installed next to it just to resolve its emitted
12
+ // jsx-runtime import. Files WITHOUT JSX syntax are unaffected: their literal
13
+ // `@opentui/solid/jsx-runtime` import IS rewritten by the host to the
14
+ // in-process OpenTUI module (`nodeModulesRuntimeSpecifiers: true` in
15
+ // DEFAULT_RUNTIME_PLUGIN_REWRITE_OPTIONS of @opentui/core), so the tree stays
16
+ // reactive and the package needs no runtime dependency at all.
17
+ //
18
+ // Therefore: no JSX syntax anywhere in this package's TUI files, and no
19
+ // `@jsxImportSource` pragma. Build the tree with jsx() and mark every DYNAMIC
20
+ // prop as a getter — that is exactly what the Solid compiler emits for
21
+ // `prop={expr}` in JSX, so the runtime semantics are identical:
22
+ //
23
+ // <text fg={base()}>{line}</text>
24
+ // -> h("text", { get fg() { return base() }, get children() { return line } })
25
+ //
26
+ // A plain (non-getter) value is read ONCE, like a literal attribute in JSX.
27
+ // Children follow the same rule: an array of elements is fine (it is diffed by
28
+ // the runtime), a function child is a reactive accessor.
29
+ //
30
+ // RELATIVE IMPORTS OF .ts FILES MUST CARRY THE EXTENSION (`./tui-h.ts`, not
31
+ // `./tui-h`): the host decides which files get the runtime-specifier rewrite by
32
+ // walking the import graph with `import.meta.resolve(specifier, importer)`,
33
+ // which does not probe extensions. An extensionless import is simply not
34
+ // followed, so that file keeps the literal `@opentui/solid/jsx-runtime` import
35
+ // and the npm install dies with `Cannot find package '@opentui/solid'`.
36
+ // test/prepublish.mjs gate (b) enforces this.
37
+ //
38
+ // This module is the only place that imports the jsx runtime, so the allowlist
39
+ // in test/prepublish.mjs stays short.
40
+ //
41
+ // NEVER pass a `key` prop to h()/c(). The jsx runtime's normalizeProps() sees
42
+ // `key`, strips it with `{ ...rest }`, and the spread turns every getter into a
43
+ // plain value read ONCE — the whole subtree freezes with no error. (No list in
44
+ // this package is keyed; if you ever need one, do not add `key` here.)
45
+
46
+ import { jsx } from "@opentui/solid/jsx-runtime"
47
+ import type { JSX } from "@opentui/solid/jsx-runtime"
48
+
49
+ /** An intrinsic OpenTUI element: `h("text", { fg, children })`. */
50
+ export function h<K extends string>(
51
+ tag: K,
52
+ props: K extends keyof JSX.IntrinsicElements ? JSX.IntrinsicElements[K] : never,
53
+ ): JSX.Element {
54
+ return jsx(tag, props as unknown as Record<string, unknown>)
55
+ }
56
+
57
+ /**
58
+ * A component: `c(Show, { get when() {...}, get fallback() {...} })`.
59
+ *
60
+ * The component's own prop type is intentionally not enforced here: host
61
+ * components (Show, and any OpenTUI component) are generic and their unions do
62
+ * not survive inference through a wrapper, while the shapes used in this
63
+ * package are small and covered by the e2e liveness check.
64
+ */
65
+ export function c<C extends (props: any) => unknown, P extends object>(
66
+ component: C,
67
+ props: P,
68
+ ): JSX.Element {
69
+ return jsx(
70
+ component as unknown as (props: Record<string, unknown>) => unknown,
71
+ props as unknown as Record<string, unknown>,
72
+ )
73
+ }