opencode-lookout 0.0.0-stage → 0.1.2

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.
@@ -0,0 +1,67 @@
1
+ # Release assurance implementation plan
2
+
3
+ ## Goal and boundaries
4
+
5
+ Add fail-closed release validation without publishing a release, installing a
6
+ self-hosted runner or spending on hosted services. Apply the approved naming break
7
+ below. Preserve the installed checkout; work on `feat/release-gates`.
8
+
9
+ ## Authorized naming migration
10
+
11
+ The maintainer approved a clean naming break, superseding the compatibility
12
+ requirement. New identifiers are `opencode-lookout`, `/lookout`,
13
+ `bin/lookout.mjs`, and `lookout:` markers. No legacy aliases or preference
14
+ migration are required. Do not touch the installed copy, personal configuration,
15
+ or private host storage. Reinstallation is deferred until after remote release.
16
+
17
+ Tests must cover damaged markers, idempotent load/unload, retained restrictions,
18
+ rejected self-disables, and offline recovery. Public GitHub already uses
19
+ `opencode-lookout`; verify hosted state before delivery. Old restrictions must be
20
+ restored with the old checkout before reinstalling; never silently remove them.
21
+
22
+ ## Execution checkpoints
23
+
24
+ The maintainer chose the current policy API rather than an adapter for OpenCode
25
+ 2.2.1/2.2.2, then approved a support-aware test policy after the first realistic
26
+ matrix test exposed the API change. Controls require V2 2.2.3+. All five versions
27
+ remain mandatory: 2.2.1/2.2.2 must prove read-only inventory, rejected mutations,
28
+ offline lifecycle/recovery, and both terminal browsing flows. Other versions
29
+ must pass full controls and both terminal flows. Unknown versions do not become
30
+ read-only skips. Evidence records and validates each target's profile.
31
+
32
+ - [x] Quality, dependency remediation, and naming migration: `src/`, `bin/`,
33
+ existing tests and docs; run `make check` and both isolated terminal cases.
34
+ - [x] Scanner/evidence validation: `scripts/`, failure fixtures in `test/`;
35
+ reject every finding, error, missing report, and source mismatch.
36
+ - [ ] Docker matrix and hosted gates: discover and exercise five stable versions
37
+ and the next RC, then validate workflows and repository protection.
38
+ - [ ] Portable editor/agent guidance and final delivery evidence.
39
+
40
+ ## Work units
41
+
42
+ 1. **Quality and documentation:** enable checked JavaScript alongside strict
43
+ TypeScript, add lint/JSDoc checks, document module contracts, and run `make check`.
44
+ 2. **Release evidence:** add tested parsers that reject any scanner finding/error,
45
+ missing/stale evidence, nonzero test results, and incomplete compatibility sets.
46
+ Audit all dependency classes and full Git history; never use severity waivers.
47
+ 3. **Containers:** discover the newest five stable `@opencode/cli` versions plus
48
+ the newest RC for the next release when present. Run actual server/TUI flows in
49
+ isolated local Docker containers, bound to immutable source and CLI artifacts.
50
+ 4. **Hosted gates:** run quality, OSS security, dependency/supply-chain, and container
51
+ compatibility checks on public standard Ubuntu runners. Avoid artifact uploads,
52
+ caches, paid scanners, and privileged PR jobs. Manual release assessment also
53
+ requires matching local evidence and human review; it does not publish.
54
+ 5. **Governance:** configure single-maintainer protections (zero required external
55
+ approvals), security settings, release documentation, and explicit support limits.
56
+
57
+ ## Acceptance and failure paths
58
+
59
+ Test low/unknown-severity findings, scanner errors and empty/malformed reports;
60
+ stale/mismatched source evidence; fewer than five stable versions; a newly
61
+ available RC; failed/missing matrix entries; and container cleanup. A blocked
62
+ upstream dependency is a release blocker, not permission to weaken the policy.
63
+
64
+ All code needs typed public contracts or checked JSDoc, with side effects and
65
+ failure/recovery behavior explained. A clean result means only no findings in the
66
+ configured checks at that time. It is not a guarantee that vulnerabilities do not
67
+ exist. No new platform or CLI support claim is made until its test passes.
@@ -0,0 +1,171 @@
1
+ # Repository metadata and releases
2
+
3
+ The GitHub repository description should explain what Lookout does without
4
+ claiming official OpenCode affiliation or verified security. Use topic tags for
5
+ discovery: `opencode`, `opencode-plugin`, `tui`, `terminal`, `sidebar`, `typescript`,
6
+ and `developer-tools`. Topics are not Git release tags.
7
+
8
+ ## Version and tag policy
9
+
10
+ Use [Semantic Versioning](https://semver.org/) and annotated Git tags named
11
+ `vMAJOR.MINOR.PATCH`. During 0.x development, describe compatibility changes
12
+ explicitly in the changelog; do not treat a minor bump as a migration plan.
13
+ Prereleases use suffixes such as `v0.2.0-rc.1`. Never move or replace a published
14
+ tag. Create a new version if a release needs correction.
15
+
16
+ Tags identify reviewed source revisions. They do not publish an npm package,
17
+ certify provider readiness, or install an update for users. There is
18
+ no automatic publishing workflow. v0.1.2 introduces a separate, manually
19
+ dispatched npm workflow; the older source-release tags remain unchanged.
20
+
21
+ ## Release checklist
22
+
23
+ 1. Review the exact commit, including security, compatibility, recovery, dependency,
24
+ and license impact. Record the maintainer's approval and commit ID in the PR
25
+ or release notes. Automated review does not satisfy this step.
26
+ 2. Update package and lockfile versions together. Move the relevant changelog
27
+ entries from **Unreleased** to a dated version section.
28
+ 3. On the clean candidate, run `make check`, `npm run security`,
29
+ `npm run test:compatibility`, and `npm run release:check`. Require all hosted
30
+ CI jobs, including **Release gate**, to pass on that same revision. Record the
31
+ source digest, CLI versions/artifacts, container architecture, and Node versions.
32
+ The required **Analyze** checks must come from full `push` or
33
+ `workflow_dispatch` runs on the candidate, not the separate **PR Analyze**
34
+ checks. After merging, verify the full checks on `main` too and confirm its
35
+ source tree is identical to the approved candidate before publishing.
36
+ 4. Inspect tracked files and full history for private data. Every configured
37
+ finding at any severity, scanner error, missing result, stale receipt, or
38
+ incomplete compatibility result blocks. Do not waive or suppress findings to
39
+ make a release pass. Fix the root cause or leave the release blocked.
40
+ 5. Create a signed annotated tag if signing is available, or an annotated tag
41
+ otherwise. Confirm the tag targets the approved commit before pushing it.
42
+ Push only that named tag; do not use a blanket tag push.
43
+ 6. Create a GitHub release deliberately, with behavior changes, compatibility,
44
+ validation, recovery, and known limitations. Do not attach personal config,
45
+ logs, credentials, or retained test fixtures.
46
+
47
+ Public repository creation is not an initial release. Leave changes under
48
+ **Unreleased** and omit a release tag until this checklist is satisfied.
49
+
50
+ ## Scanner prerequisites and evidence
51
+
52
+ Install Semgrep 1.182.0, Trivy 0.76.1, Gitleaks 8.30.1, Docker, and Node 26.4.0+.
53
+ CI installs checksum-verified binaries and uses a digest-pinned
54
+ Semgrep image; see `scripts/install-ci-scanners.sh`. Semgrep rules are downloaded
55
+ from commit `16b9e6d45f10649f6a531ec4838ed9924372c3bc` with a pinned checksum.
56
+ Only JavaScript/TypeScript language security and GitHub Actions security packs
57
+ are selected. React-specific style/i18n rules are not applicable to this Solid TUI;
58
+ registry packs requiring the paid Pro engine are not silently counted as passing.
59
+ The rules retain the upstream Semgrep Rules License and are not vendored as MIT.
60
+
61
+ All receipts live in ignored `release-evidence/`. Release assessment requires
62
+ receipts no older than 24 hours and re-discovers CLI targets; a new RC invalidates
63
+ an older matrix. Missing tools, registry outages, scanner database failures, and
64
+ nonzero test statuses block instead of falling back to previous success. Re-run
65
+ after correcting the cause. Failed runs must never be presented as passes.
66
+
67
+ The matrix tests supported behavior, not identical features on every CLI. The
68
+ maintainer-approved profiles are **read-only** for 2.2.1/2.2.2 and **controls**
69
+ for the remaining targets. Read-only cases must prove rejected mutations, safe
70
+ inventory, lifecycle, and both terminal browsing flows. Control cases must prove
71
+ effective skill/MCP/plugin restrictions and recovery as well. Every case must
72
+ pass its explicit profile; any new unsupported CLI blocks until reviewed.
73
+
74
+ ## Single-maintainer hosted protection
75
+
76
+ Require a pull request, resolved conversations, and successful **Runtime (Node 22)**,
77
+ **Runtime (Node 24)**, **Quality (Node 26)**, **Security**, **Compatibility**, and
78
+ **Release gate** checks, plus CodeQL's **Analyze (actions)** and
79
+ **Analyze (javascript-typescript)**. The CI aggregate does not replace those
80
+ separate hosted CodeQL checks. Each CodeQL job validates SARIF for every finding
81
+ and analysis error after the analyze action succeeds.
82
+ Full scans run on every repository branch push. PR scans remain available as
83
+ **PR Analyze (actions)** and **PR Analyze (javascript-typescript)**, but their
84
+ change-focused results cannot substitute for full-candidate assurance. For a fork
85
+ PR, the maintainer must bring the reviewed candidate onto a repository branch
86
+ and obtain the required full checks; do not bypass protection to merge it.
87
+ Use zero required external approvals: the sole maintainer reviews the exact
88
+ revision. Disable force pushes/deletions and apply the checks to administrators.
89
+ Remote protection must be verified live; this document alone does not enable it.
90
+
91
+ Only standard public GitHub runners are used. No self-hosted runners, artifact
92
+ uploads, or cache actions are configured. Runner logs still have normal GitHub
93
+ retention. Do not add paid runners or external service requirements implicitly.
94
+ Never reuse a token from conversation history.
95
+
96
+ ## Manual npm publication (v0.1.2 onward)
97
+
98
+ Preparation does not authorize publication. Obtain exact-revision maintainer
99
+ approval after reviewing packaging, generated TUI, consumer audits and installed
100
+ server/TUI evidence. Complete the GitHub release checklist first, including full
101
+ candidate and post-merge CodeQL. The approved tag and main must have identical
102
+ source trees. Re-run stale hosted checks: every required job must have completed
103
+ successfully within 24 hours. A newer failed or incomplete workflow blocks; the
104
+ validator does not fall back to an older success.
105
+
106
+ Configure an npm trusted publisher for GitHub owner `sodejm`, repository
107
+ `opencode-lookout`, workflow filename `npm-publish.yml`, environment `npm`.
108
+ Use GitHub-hosted standard runners. Configure the GitHub `npm` environment to
109
+ allow reviewed release tags and require the sole maintainer's approval; do not
110
+ require a second reviewer. Verify these settings live. Give the publisher only
111
+ the required publish permission, not dist-tag administration. No npm token is
112
+ stored in the repository or workflow. See the current
113
+ [npm trusted publishing guide](https://docs.npmjs.com/trusted-publishers/).
114
+
115
+ **First-package bootstrap remains an account-setup decision.** npm's
116
+ [trust prerequisites](https://docs.npmjs.com/cli/v11/commands/npm-trust) require the
117
+ package to already exist on the registry. A registry
118
+ 404 does not establish ownership, and local `npm whoami` is not an OIDC permission
119
+ check. If package settings are not available for this new name, stop and agree a
120
+ bootstrap procedure with the maintainer. Do not publish a placeholder, use the
121
+ revoked token, silently switch to token publishing, or claim OIDC provenance for
122
+ a local publish. Login/2FA must happen in the maintainer's own terminal or npm UI,
123
+ never by sharing credentials in chat.
124
+
125
+ ### Approved one-time v0.1.2 bootstrap
126
+
127
+ The maintainer approved publishing the real first `opencode-lookout@0.1.2`
128
+ artifact using the existing authenticated npm login, with 2FA completed privately.
129
+ This is a one-time exception to OIDC publication, not permission to publish a
130
+ placeholder or use the revoked token. It does not waive any quality, security,
131
+ compatibility, signed-tag, GitHub-release, exact-revision approval, or post-merge
132
+ gate above. Record the approved SHA and tested tarball integrity in the release.
133
+
134
+ Before publishing, verify the registry still has no package, verify account
135
+ identity, and run `node scripts/check-package-evidence.mjs PATH_TO_TESTED_TARBALL`
136
+ on the clean approved checkout with fresh evidence. Publish those exact tarball
137
+ bytes with `npm publish PATH_TO_TESTED_TARBALL --access public --ignore-scripts`
138
+ from the maintainer's terminal. Never send credentials or 2FA codes through chat.
139
+ If publication is interrupted, query the registry before retrying; do not attempt
140
+ to replace an existing version.
141
+
142
+ This version has **no GitHub OIDC provenance**. Verify its registry integrity
143
+ against the approved artifact and test a fresh registry installation, including
144
+ offline recovery and both isolated terminal modes. After the package exists,
145
+ configure the trusted publisher described above for future versions. Do not
146
+ dispatch the OIDC workflow for the already-published v0.1.2: npm versions are
147
+ immutable. This exception expires after the first successful v0.1.2 publication.
148
+
149
+ ### Subsequent trusted publications
150
+
151
+ After account setup and exact approval, manually dispatch **Publish npm (manual)**
152
+ on the published tag (not `main`) with `approved_sha` set to its full commit ID:
153
+
154
+ ```sh
155
+ gh workflow run npm-publish.yml --ref vX.Y.Z -f approved_sha=FULL_APPROVED_COMMIT
156
+ ```
157
+
158
+ The workflow verifies the signed annotated tag through GitHub, the non-draft
159
+ GitHub release, the approved SHA and fresh hosted CI/full-CodeQL runs. It installs
160
+ with scripts disabled, reruns security, Docker and release assessment, packs and
161
+ tests the actual tarball, and checks its integrity against Docker evidence. It
162
+ rechecks hosted state immediately before `npm publish --provenance` using OIDC.
163
+ The job has `id-token: write` only for this manual operation; PR CI cannot publish.
164
+ Provenance binds the workflow's tag revision to the artifact, not to human review.
165
+
166
+ After publication, verify the registry's version, tarball integrity and provenance
167
+ against the workflow output and approved tag. Install the registry artifact in a
168
+ fresh isolated prefix and rerun packed recovery/server/TUI validation before
169
+ claiming npm delivery complete. If the job is interrupted after publication,
170
+ inspect registry state first: published versions are immutable, and the workflow
171
+ rejects an already-present version rather than attempting to replace it.
@@ -0,0 +1,176 @@
1
+ # Threat model
2
+
3
+ ## npm publication and consumer boundary
4
+
5
+ The npm artifact uses a files allowlist and has no install hooks. Its committed
6
+ generated TUI is byte-checked against source and included in security coverage.
7
+ An isolated consumer install must pass the same all-severity audit parser, without
8
+ assuming dependency overrides propagate from this repository. They do not:
9
+ installing `@opencode/plugin` as a consumer dependency reproduced vulnerable
10
+ glob/minimatch transitive resolutions. OpenCode supplies the SDK/UI runtime;
11
+ optional peers document that boundary without installing a second copy. The
12
+ offline CLI needs only jsonc-parser. Host-runtime security remains an OpenCode
13
+ responsibility, not a claim made by a clean Lookout consumer audit.
14
+
15
+ npm bin symlinks must execute the CLI rather than silently returning success.
16
+ Tests cover missing, malformed and ambiguous configs, edited ownership markers,
17
+ confirmation refusal and recovery while preserving unrelated denies. Only stable
18
+ package paths are owned; direct registry entries and other config layers can
19
+ override a global disable and require separate inspection.
20
+
21
+ The manual publication job has short-lived OIDC authority in the `npm` environment,
22
+ not a stored npm token. It requires a verified annotated tag at the approved SHA,
23
+ a non-draft stable GitHub release, matching main tree and fresh complete candidate
24
+ and post-merge CI/full CodeQL runs. It reruns local gates and verifies that the
25
+ published tarball hash is the one exercised by Docker. Missing, malformed, stale,
26
+ failed or mismatched evidence blocks publication. Release evidence endpoints
27
+ are queried using validated public GitHub dispatch identifiers; local manifest
28
+ data is compared locally and is not used to construct outbound request URLs.
29
+ Environment/package settings are external controls and must be checked by the
30
+ maintainer before first use.
31
+ Repository write access and compromised dependencies/runners remain trusted risks.
32
+
33
+ The maintainer-approved first-package v0.1.2 bootstrap uses an existing npm login
34
+ and private 2FA instead of OIDC, because npm requires an existing package before
35
+ trusted-publisher setup. The maintainer's terminal and npm session are additional
36
+ trusted components for this one publication. All release gates and exact-artifact
37
+ checks still apply, but this version cannot claim GitHub OIDC provenance. No
38
+ credential enters repository files, CI secrets, or chat. The exception expires
39
+ after v0.1.2; future versions use the manual trusted-publishing workflow.
40
+
41
+ PR CodeQL results can omit findings outside the reported changes. Required
42
+ **Analyze** checks therefore come from full branch-push/dispatch scans; PR scans
43
+ use distinct names. A clean PR analysis alone cannot authorize release, and the
44
+ post-merge full scan must pass before publishing. The integration harness keeps
45
+ fixture session responses in memory instead of writing an unused response dump.
46
+
47
+ The release-preparation dependency update changes only development declarations
48
+ (`@types/node` and `undici-types`), not production dependencies or runtime authority.
49
+ Install scripts remain disabled. Node 22/24 production-only tests still guard the
50
+ offline CLI contract; Node 26 type declarations alone do not prove that contract.
51
+
52
+ Configuration reads validate the opened descriptor rather than checking a path
53
+ before opening it. No-follow and nonblocking flags reject final symlinks and
54
+ avoid FIFO hangs. Reads are bounded even if a file grows after validation; link
55
+ count, size, mode, and timestamps are rechecked before parsing. This does not
56
+ protect against a hostile owner of the parent directory or remove the documented
57
+ final-check/rename race with an uncooperative external editor.
58
+
59
+ ## Release assurance boundary
60
+
61
+ Release checks reject every configured finding, regardless of severity, as well
62
+ as scanner errors, missing output, stale receipts, source mismatches, and missing
63
+ compatibility cases. npm audit covers development, optional, and peer dependencies;
64
+ npm signatures checks registry signatures; Trivy checks the lockfile and repository
65
+ misconfiguration; Semgrep uses pinned OSS language/Actions security rules; Gitleaks
66
+ checks full Git history and current nonignored source. No scan is proof of absence
67
+ of vulnerabilities. This does not certify the host OS or an upstream CLI binary.
68
+
69
+ The repository's `.semgrepignore` overrides default test exclusions: source,
70
+ test harnesses, and fixtures are scanned. Required entrypoint coverage is checked
71
+ explicitly. Only generated output and separately audited dependency code are
72
+ excluded. Downloaded rule fixtures are not project source and must not be scanned
73
+ as if they were part of Lookout.
74
+
75
+ Rule downloads are SHA-256 checked in memory before tar receives the same bytes
76
+ on stdin. The archive is not saved to disk. Each run extracts into a fresh private
77
+ directory, preventing stale rule files from changing the configured scan. A
78
+ checksum mismatch or extraction failure aborts before any success receipt.
79
+
80
+ Actions are SHA-pinned and use standard public runners. Repository access is
81
+ read-only except CodeQL security-result uploads (`security-events: write`);
82
+ CodeQL database uploads are disabled. Its Actions and JavaScript/TypeScript
83
+ analyses reject every SARIF result and warning/error, not just scanner failures.
84
+ Explicit `none`/`note` invocation diagnostics (such as successfully extracted
85
+ files) are informational, not findings. Missing or unknown diagnostic levels and
86
+ recorded exceptions still block, as do findings with any level, even `none`.
87
+ Downloads of
88
+ standalone scanner binaries, the Semgrep image, rule archive, and Node base image
89
+ are digest-pinned. CLI versions are discovered dynamically, and npm integrity binds
90
+ each tested binary. A malicious registry, compromised upstream release, or scanner
91
+ blind spot remains a risk. Dependency overrides cross major versions and require
92
+ behavioral tests, not just a clean audit.
93
+
94
+ Docker test builds need network access to fetch dependencies. Test execution has
95
+ no network, host mounts, Docker socket, elevated capabilities, or personal secrets.
96
+ Fixture provider/tool denials remain mandatory even inside the container. The
97
+ repository and Docker daemon are trusted inputs, not a sandbox for arbitrary
98
+ malicious code. Local receipts are not signed attestations: a user with filesystem
99
+ access can forge them. Exact-revision maintainer review and matching hosted checks
100
+ remain required. No workflow automatically publishes or treats AI review as human
101
+ approval. The approved breaking rename does not claim old ownership blocks;
102
+ restore/unload the previous installation with its own CLI before reinstalling.
103
+
104
+ ## Assets and authority
105
+
106
+ Protect global OpenCode configuration, existing access restrictions, credentials,
107
+ and unrelated plugins. The server process already runs with the user's filesystem
108
+ authority. Its authenticated clients can call plugin RPCs. Confirmation protects
109
+ against accidental UI use; it is not a sandbox against a malicious authenticated
110
+ client or another plugin running as the same user.
111
+
112
+ The TUI is not an authority for configuration paths, resource IDs, or management
113
+ eligibility. The server fixes the target path and rechecks the catalog. RPCs are
114
+ not exposed as model tools. No credential APIs are used.
115
+
116
+ ## Threats and implemented controls
117
+
118
+ | Threat | Control | Evidence |
119
+ | --- | --- | --- |
120
+ | Wildcard disables or arbitrary file writes | Exact ID validation, fixed config path, fixed resource kinds | Config and controller tests |
121
+ | Erasing external policy | Remove only owned blocks; never add allow rules | Config tests |
122
+ | Replay or stale preview | One-use token, 60-second expiry, configuration hash | Controller tests |
123
+ | Two extension writers | Exclusive file lock and atomic replacement | Controller tests |
124
+ | Partial write or stale lock | Temp-file cleanup; preserve original on pre-rename failure; offline recovery | Controller tests and README |
125
+ | Credential disclosure | Display-field allowlist; no raw API errors or configuration in the catalog | Catalog tests |
126
+ | Terminal control sequences in metadata | Strip control characters and bound display strings | Catalog tests |
127
+ | Loss of re-enable path after filtering | Reconstruct disabled rows from owned entries | Catalog tests |
128
+ | Disabling policy enforcement | Built-in plugins and Lookout are read-only in the UI | Config and catalog tests |
129
+ | Broken UI prevents recovery | External load/unload/status/restore commands; no automatic discovery | Lifecycle tests |
130
+
131
+ The live fixture validates filtering and recovery for all three controllable
132
+ resource kinds. It runs with temporary HOME/XDG directories and denies provider
133
+ and tool use to keep keyboard-test mistakes from starting inference or shell work.
134
+ Terminal logs can contain local paths and session metadata; retained fixtures are
135
+ local debugging artifacts, not shareable evidence. See [Validation](VALIDATION.md)
136
+ for the tested runtime and remaining coverage limits.
137
+
138
+ Plugin descriptions add read-only access to the exact local plugin source from
139
+ the server catalog, or its direct package manifest. File reads are bounded and
140
+ reject non-regular files and final-component symlinks. Plugin source is never
141
+ executed for metadata extraction. Only an explicit description field/tag is
142
+ returned, sanitized for terminal control characters; errors do not expose paths.
143
+ The catalog, not an RPC caller, selects the source path. An installed malicious
144
+ plugin already has the server user's authority; these checks are not a sandbox
145
+ against that user or plugin. Description metadata is display text, not instructions.
146
+
147
+ ## Limits and review
148
+
149
+ Public contribution and CI are additional trust boundaries. GitHub Actions run
150
+ untrusted pull-request code without repository write permissions or project
151
+ secrets. Checkout credentials are not persisted, action revisions are pinned, and
152
+ dependency install scripts are disabled. Dependabot proposes updates; it does not
153
+ merge or publish them. Human review must check runtime dependency compatibility.
154
+ Dependency licenses and notices must be reviewed before redistributing bundled
155
+ artifacts; this repository does not publish bundles.
156
+
157
+ The status-dot and MCP-display change affects presentation only. It adds no RPC,
158
+ configuration write, credential access, or trust boundary. Existing MCP
159
+ restrictions remain intact and can still be removed by offline restore. Green
160
+ dots indicate catalog availability, not successful authentication or execution.
161
+
162
+ - Global changes can affect active work in other sessions. The preview warns about
163
+ this; it does not forcibly stop or migrate those sessions.
164
+ - Higher-priority policy can override a local denial. A saved entry is not proof
165
+ that a resource is blocked. The catalog reports when it remains listed.
166
+ - An uncooperative external writer can race the final hash check. Keep manual
167
+ config edits separate from Lookout changes.
168
+ - Loaded skill text cannot be removed from an existing conversation.
169
+ - Server-side plugin status does not certify its terminal component is healthy.
170
+ - Managed provenance is not available for every catalog field. Unrecognized
171
+ sources are read-only instead of being assumed local.
172
+ - Denials are operational configuration, not a sandbox for arbitrary plugin code.
173
+
174
+ The owner of this local installation owns these residual risks. Human review is
175
+ pending; test results are not human approval. Recheck this model when adding
176
+ resource kinds, file targets, credential access, or remote management.
@@ -0,0 +1,99 @@
1
+ # Validation
2
+
3
+ ## Packed consumer validation
4
+
5
+ `make check` includes `build:check` and `test:package`. The latter packs the actual
6
+ artifact, installs it outside the checkout with `--omit=dev --ignore-scripts`,
7
+ audits its dependency graph at every severity, and exercises the npm bin and
8
+ offline failure/recovery paths with isolated HOME/XDG directories. It rejects
9
+ accidentally installed SDK/build dependencies. Node 22/24 CI runs this too.
10
+
11
+ The Docker matrix now loads a production-installed tarball from `/consumer`, not
12
+ the harness checkout. The runner packs once into `.build/npm-artifact/` and copies
13
+ those exact bytes into every image; it does not repack with another platform's
14
+ gzip implementation. Each image's tarball must match the local pack's SHA-512
15
+ integrity. The source and package digests are both recorded in compatibility and
16
+ release receipts. Fixture provider/tool denials and both terminal modes remain.
17
+ For a local packed server/TUI case, use:
18
+
19
+ ```sh
20
+ LOOKOUT_PACKED_INTEGRATION=1 LOOKOUT_TUI=1 npm run test:package
21
+ LOOKOUT_PACKED_INTEGRATION=1 LOOKOUT_TUI=1 LOOKOUT_NARROW=1 LOOKOUT_THEME=tokyonight npm run test:package
22
+ ```
23
+
24
+ These tests prove stable-prefix/path loading. They do not prove direct registry
25
+ entry recovery, npm ownership, OIDC authentication or registry publication.
26
+
27
+ ## Repository checks
28
+
29
+ `make check` runs Prettier, local documentation-link checks, blocking ESLint/JSDoc,
30
+ strict TypeScript with checked JavaScript, and Node's test runner. Unit tests
31
+ cover catalog filtering, literal search, description metadata, ownership,
32
+ reversible controls, malformed config, duplicate keys, protected IDs, expired
33
+ and replayed previews, external edits, symlinks, locks, and offline recovery.
34
+ Release tests reject low/unknown findings, scanner errors, incomplete reports,
35
+ stale/source-mismatched evidence, incomplete matrices, and failed commands.
36
+ Workflow tests keep required full CodeQL checks distinct from PR-only checks.
37
+ The terminal fixture asserts that session responses are not saved to disk.
38
+
39
+ ## Runtime checks
40
+
41
+ ```sh
42
+ LOOKOUT_TUI=1 node test/integration.mjs
43
+ LOOKOUT_TUI=1 LOOKOUT_NARROW=1 LOOKOUT_THEME=tokyonight node test/integration.mjs
44
+ npm run test:compatibility
45
+ ```
46
+
47
+ The first two commands use the installed CLI with fresh HOME/XDG fixtures. They
48
+ deny every provider/tool action and never submit a model request. They exercise:
49
+
50
+ - Skill, MCP, and local plugin disable/reload/re-enable and filtered-row recovery.
51
+ - Rejection of protected controls; offline unload/load and RPC disappearance.
52
+ - Carbonfox at 150×52 and Tokyonight at 80×36, search, category/state selection,
53
+ details, cancellation, confirmation, and offline restore; zero inference cost.
54
+ - Native MCP status without duplicate inventory; file-sourced plugin descriptions.
55
+
56
+ After cancelling a preview, the terminal harness checks the reopened catalog's
57
+ full heading rather than requiring a contiguous search placeholder. A retained
58
+ failure showed the renderer updating only changed placeholder cells. A synthetic
59
+ regression covers that output and rejects unrelated dialogs; cancellation must
60
+ still leave zero owned restrictions, and confirmation and offline restore must
61
+ still change and restore the fixture. This test-only correction does not change
62
+ runtime behavior, permissions, or the threat model's trust boundaries.
63
+
64
+ The Docker runner discovers the newest five stable V2+ CLI versions plus the
65
+ highest RC of the nearest unreleased version. It fails if discovery or any test
66
+ fails. Each image installs a CLI artifact with verified npm integrity and locked
67
+ dependencies. Tests run as non-root, without network, capabilities, host mounts,
68
+ credentials, or a Docker socket. Only temporary container storage is writable.
69
+ Both terminal modes run for each target; server/recovery checks run in each mode.
70
+ The approved read-only profile for 2.2.1/2.2.2 requires visible inventory, rejected
71
+ enable/disable/apply RPCs, browsing/details, no changed restrictions, and offline
72
+ load/unload. All other targets require full effective controls. These are distinct
73
+ support claims, not silently skipped test steps.
74
+ Reports bind results to source bytes, CLI integrity, and Docker image IDs.
75
+
76
+ ## Evidence and limits
77
+
78
+ Machine-readable evidence is generated under ignored `release-evidence/`; do not
79
+ commit raw scanner logs or terminal fixtures. See [Release policy](RELEASING.md).
80
+ Read the source digest, target, profile, mode, and exit status together. A passing
81
+ probe or an earlier commit's run is not a passing current release matrix.
82
+
83
+ The initial five-version run reproduced an ineffective skill restriction on
84
+ 2.2.1. Upstream source confirms 2.2.1/2.2.2 use a different policy action; the
85
+ current `skill.use`/`mcp.use` API starts in 2.2.3. The maintainer chose not to add
86
+ an older-policy adapter and approved testing those hosts against a read-only
87
+ support profile. The original failed control test is not counted as passing;
88
+ fresh profile-specific evidence is required.
89
+
90
+ The old installation is deliberately untouched. Reinstallation is deferred until
91
+ after remote release. Historical pre-rename tests do not establish this revision's
92
+ compatibility. No broader platform/version support is claimed before its matrix
93
+ passes. Linux amd64 hosted results are distinct from local Linux arm64 results.
94
+
95
+ PTY tests are not pixel-level or accessibility audits. Mouse interactions,
96
+ preference persistence, remote-server behavior, and other terminal sizes still
97
+ need human review. Catalog filtering does not revoke instructions already loaded
98
+ in conversations. Catalog availability proves neither provider authentication nor
99
+ quota. A clean scan means only no findings in the configured checks at that time.
package/package.json CHANGED
@@ -1,6 +1,105 @@
1
1
  {
2
2
  "name": "opencode-lookout",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.2",
4
+ "description": "A native-style resource sidebar for OpenCode, with reversible local controls.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/sodejm/opencode-lookout.git"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/sodejm/opencode-lookout/issues"
12
+ },
13
+ "homepage": "https://github.com/sodejm/opencode-lookout#readme",
14
+ "engines": {
15
+ "node": ">=22"
16
+ },
17
+ "publishConfig": {
18
+ "access": "public",
19
+ "registry": "https://registry.npmjs.org/"
20
+ },
21
+ "files": [
22
+ "src/",
23
+ "bin/lookout.mjs",
24
+ "dist/tui.js",
25
+ "docs/*.md",
26
+ "CHANGELOG.md",
27
+ "SECURITY.md",
28
+ "SUPPORT.md",
29
+ "CONTRIBUTING.md",
30
+ "GOVERNANCE.md",
31
+ "CODE_OF_CONDUCT.md"
32
+ ],
33
+ "bin": {
34
+ "lookout": "bin/lookout.mjs"
35
+ },
36
+ "type": "module",
37
+ "exports": {
38
+ ".": "./src/server.ts",
39
+ "./tui": "./dist/tui.js",
40
+ "./rpc": "./src/rpc.ts"
41
+ },
42
+ "scripts": {
43
+ "build": "node scripts/build-tui.mjs --write",
44
+ "build:check": "node scripts/build-tui.mjs",
45
+ "test": "node --test test/*.test.mjs",
46
+ "test:package": "node test/packed.mjs",
47
+ "typecheck": "tsc --noEmit",
48
+ "lint": "eslint . --max-warnings 0",
49
+ "test:compatibility": "node scripts/compatibility.mjs",
50
+ "security": "node scripts/security.mjs",
51
+ "release:check": "node scripts/release-check.mjs",
52
+ "format:check": "prettier --check 'src/**/*.{mjs,ts,tsx}' 'test/**/*.mjs' 'bin/*.mjs' 'scripts/*.mjs' '*.json' '.github/**/*.yml' '.vscode/*.json' 'eslint.config.mjs' 'opencode-lookout.code-workspace'",
53
+ "test:integration": "node test/integration.mjs",
54
+ "test:tui": "LOOKOUT_TUI=1 node test/integration.mjs",
55
+ "docs:check": "node scripts/check-docs.mjs",
56
+ "check": "npm run format:check && npm run docs:check && npm run lint && npm run typecheck && npm run build:check && npm test && npm run test:package"
57
+ },
58
+ "dependencies": {
59
+ "jsonc-parser": "3.3.1"
60
+ },
61
+ "peerDependencies": {
62
+ "@opencode/plugin": ">=2.2.1 <=2.2.6",
63
+ "@opentui/core": "^0.8.0",
64
+ "@opentui/solid": "^0.8.0",
65
+ "solid-js": "^1.9.0"
66
+ },
67
+ "peerDependenciesMeta": {
68
+ "@opencode/plugin": {
69
+ "optional": true
70
+ },
71
+ "@opentui/core": {
72
+ "optional": true
73
+ },
74
+ "@opentui/solid": {
75
+ "optional": true
76
+ },
77
+ "solid-js": {
78
+ "optional": true
79
+ }
80
+ },
81
+ "overrides": {
82
+ "glob@>=9 <=14.0.1": "14.0.3",
83
+ "minimatch@>=7 <11.0.1": "11.0.4"
84
+ },
85
+ "devDependencies": {
86
+ "@babel/core": "7.29.7",
87
+ "@babel/preset-typescript": "7.27.1",
88
+ "@types/babel__core": "7.20.5",
89
+ "babel-preset-solid": "1.9.16",
90
+ "@eslint/js": "10.0.1",
91
+ "@opencode/client": "2.2.5",
92
+ "@opencode/plugin": "2.2.5",
93
+ "@opencode/theme": "2.2.5",
94
+ "@opentui/core": "0.8.0",
95
+ "@opentui/solid": "0.8.0",
96
+ "@types/node": "26.6.6",
97
+ "eslint": "10.14.0",
98
+ "eslint-plugin-jsdoc": "65.4.3",
99
+ "globals": "17.14.0",
100
+ "prettier": "3.9.10",
101
+ "solid-js": "1.9.16",
102
+ "typescript": "5.9.3",
103
+ "typescript-eslint": "8.72.1"
104
+ }
105
+ }