@easonwumac/computer-linker 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.
Files changed (82) hide show
  1. package/CHANGELOG.md +230 -0
  2. package/LICENSE +21 -0
  3. package/README.md +539 -0
  4. package/SECURITY.md +48 -0
  5. package/dist/api.d.ts +2 -0
  6. package/dist/api.js +360 -0
  7. package/dist/audit.d.ts +70 -0
  8. package/dist/audit.js +102 -0
  9. package/dist/capabilities.d.ts +98 -0
  10. package/dist/capabilities.js +718 -0
  11. package/dist/capability-policy.d.ts +22 -0
  12. package/dist/capability-policy.js +103 -0
  13. package/dist/chatgpt.d.ts +167 -0
  14. package/dist/chatgpt.js +561 -0
  15. package/dist/cli.d.ts +2 -0
  16. package/dist/cli.js +4621 -0
  17. package/dist/client-smoke.d.ts +44 -0
  18. package/dist/client-smoke.js +639 -0
  19. package/dist/client.d.ts +217 -0
  20. package/dist/client.js +357 -0
  21. package/dist/codex-runs.d.ts +35 -0
  22. package/dist/codex-runs.js +66 -0
  23. package/dist/computer-contract.d.ts +33 -0
  24. package/dist/computer-contract.js +384 -0
  25. package/dist/computer-operation-registry.d.ts +45 -0
  26. package/dist/computer-operation-registry.js +179 -0
  27. package/dist/config-diagnostics.d.ts +11 -0
  28. package/dist/config-diagnostics.js +185 -0
  29. package/dist/config.d.ts +10 -0
  30. package/dist/config.js +69 -0
  31. package/dist/history-insights.d.ts +132 -0
  32. package/dist/history-insights.js +457 -0
  33. package/dist/http-auth.d.ts +3 -0
  34. package/dist/http-auth.js +15 -0
  35. package/dist/mcp-surface.d.ts +5 -0
  36. package/dist/mcp-surface.js +25 -0
  37. package/dist/oauth-provider.d.ts +52 -0
  38. package/dist/oauth-provider.js +325 -0
  39. package/dist/package-metadata.d.ts +7 -0
  40. package/dist/package-metadata.js +24 -0
  41. package/dist/permissions.d.ts +43 -0
  42. package/dist/permissions.js +150 -0
  43. package/dist/platform-shell.d.ts +28 -0
  44. package/dist/platform-shell.js +124 -0
  45. package/dist/processes.d.ts +50 -0
  46. package/dist/processes.js +178 -0
  47. package/dist/profile.d.ts +159 -0
  48. package/dist/profile.js +416 -0
  49. package/dist/screenshot.d.ts +47 -0
  50. package/dist/screenshot.js +302 -0
  51. package/dist/search.d.ts +34 -0
  52. package/dist/search.js +340 -0
  53. package/dist/security.d.ts +10 -0
  54. package/dist/security.js +108 -0
  55. package/dist/sensitive-files.d.ts +4 -0
  56. package/dist/sensitive-files.js +96 -0
  57. package/dist/server.d.ts +9 -0
  58. package/dist/server.js +713 -0
  59. package/dist/service.d.ts +125 -0
  60. package/dist/service.js +486 -0
  61. package/dist/sessions.d.ts +26 -0
  62. package/dist/sessions.js +34 -0
  63. package/dist/tunnels.d.ts +161 -0
  64. package/dist/tunnels.js +1243 -0
  65. package/dist/workspace-operations.d.ts +170 -0
  66. package/dist/workspace-operations.js +3219 -0
  67. package/dist/workspaces.d.ts +61 -0
  68. package/dist/workspaces.js +353 -0
  69. package/docs/agent-instructions.md +65 -0
  70. package/docs/alpha-evidence.example.json +54 -0
  71. package/docs/api-compatibility.md +56 -0
  72. package/docs/architecture.md +561 -0
  73. package/docs/chatgpt-setup.md +397 -0
  74. package/docs/client-recipes.md +98 -0
  75. package/docs/client-sdk.md +163 -0
  76. package/docs/computer-operation-v1.schema.json +143 -0
  77. package/docs/manual-test-plan.md +322 -0
  78. package/docs/product-spec.md +911 -0
  79. package/docs/release-checklist.md +285 -0
  80. package/docs/service-mode.md +99 -0
  81. package/examples/minimal-mcp-client.mjs +114 -0
  82. package/package.json +87 -0
@@ -0,0 +1,285 @@
1
+ # Release Checklist
2
+
3
+ Computer Linker's first productized target is an alpha release for trusted
4
+ local development machines. Do not treat alpha as an unattended public service.
5
+
6
+ ## Alpha Gate
7
+
8
+ Run the same gate locally and in CI:
9
+
10
+ ```bash
11
+ npm run release:validate
12
+ npm run product:check
13
+ ```
14
+
15
+ This performs:
16
+
17
+ - Release metadata validation.
18
+ - TypeScript typecheck.
19
+ - Full test suite.
20
+ - Runtime build.
21
+ - Package smoke check with `npm pack --dry-run`, real `.tgz` creation,
22
+ temporary consumer install, installed CLI execution, isolated installed
23
+ `self-test`, `setup` / `status` config smoke, and installed SDK import.
24
+
25
+ Before publishing a public npm/package artifact, run:
26
+
27
+ ```bash
28
+ npm run public:check
29
+ ```
30
+
31
+ ## Local npm Release Automation
32
+
33
+ Use the local wrapper when you are ready to publish from the current repository:
34
+
35
+ ```bash
36
+ npm run release:check
37
+ npm run release:dry-run
38
+ npm run release:publish -- --create-tag --otp <code>
39
+ git push origin main --follow-tags
40
+ ```
41
+
42
+ `release:check` runs the local product and public package gates without
43
+ publishing. It does not require a clean worktree, so it is useful before the
44
+ final release commit.
45
+
46
+ `release:dry-run` requires the release commit to be clean and on main/master.
47
+ It runs `npm publish --dry-run`; if `v<package.version>` is missing, it creates
48
+ a temporary local tag for the dry-run and removes it afterward. If that tag
49
+ already exists on another commit, bump the package version before releasing.
50
+
51
+ `release:publish` performs the real npm publish. It requires a clean
52
+ main/master worktree, a dated `CHANGELOG.md` heading for the package version,
53
+ npm login, and a release tag on `HEAD`. Pass `--create-tag` to create the
54
+ release tag automatically before publishing, `--otp <code>` for npm 2FA, and
55
+ `--push` only when the script should push `HEAD` and tags to `origin` after a
56
+ successful publish.
57
+
58
+ For the one-command local alpha readiness gate, run:
59
+
60
+ ```bash
61
+ npm run alpha:check
62
+ ```
63
+
64
+ This runs `product:check`, `public:audit`, a preserved-history public repo
65
+ audit, and a public snapshot dry-run, then prints a readiness report. It is
66
+ intentionally local-only and does not trigger GitHub Actions or tunnel
67
+ providers. If the report is `needs_attention` only because
68
+ `preserved-history-audit` found private dogfooding fingerprints, do not change
69
+ the existing GitHub repository to public visibility; publish a fresh
70
+ `public:mirror` instead.
71
+
72
+ For that fresh public mirror release path, run:
73
+
74
+ ```bash
75
+ npm run public:mirror -- --remote <github-owner>/<public-repo>
76
+ ```
77
+
78
+ This accepts the preserved-history warning only for a detached snapshot release;
79
+ it does not mean the private repository can be made public with existing
80
+ history. `public:ready` and `alpha:snapshot-check` remain lower-level aliases
81
+ for checking readiness without writing the mirror.
82
+
83
+ Before announcing a public alpha, capture one external MCP client/tunnel pass as
84
+ machine-readable evidence:
85
+
86
+ ```bash
87
+ npm run alpha:evidence -- preflight
88
+ npm run alpha:evidence -- smoke --redaction-confirmed
89
+ npm run alpha:check -- --require-evidence
90
+ ```
91
+
92
+ The generated evidence file is gitignored and should remain local. It records
93
+ which client, exposure path, generic MCP tool flow, MCP-only public surface, and
94
+ history review were tested. It must not contain owner tokens, API keys, bearer
95
+ headers, screenshots, or private file contents. The check rejects placeholder
96
+ client names, placeholder tunnel targets, non-HTTPS public URLs, non-`/mcp` MCP
97
+ paths, and stale evidence. Use `alpha:evidence smoke` to create or refresh the
98
+ evidence file and mark the full external smoke pass without hand-editing JSON;
99
+ it auto-detects exposure, tunnel target, and scope from local preflight state
100
+ when possible. Pass explicit `--client`, `--exposure`, `--tunnel-or-url`, or
101
+ `--scope` only when auto-detection cannot infer the tested target. `smoke` can
102
+ refresh an existing Computer Linker alpha evidence file, but still requires
103
+ `--force` before replacing unrelated files. Use `alpha:evidence init`,
104
+ `record-smoke`, or `record` only when you want to split the steps or keep
105
+ separate notes per check. `smoke`, `init`, `record-smoke`, and `record` refuse
106
+ common secret-shaped values before writing the evidence file. Use
107
+ `alpha:evidence preflight` before recording evidence to inspect local
108
+ config, audit history, and tunnel runtime state for missing external smoke
109
+ signals and print a read-only prompt to paste into the external MCP client.
110
+ When a previous attempt already completed some calls, `nextExternalClientPrompt`
111
+ narrows the prompt to the missing operation. It is a preflight only; it does not
112
+ replace manual redaction and client-instruction confirmation. `recordCommand`
113
+ shows the short evidence command to run when the preflight no longer fails. Use
114
+ [alpha-evidence.example.json](alpha-evidence.example.json) for the schema.
115
+ The public release audit blocks `.computer-linker-alpha-evidence.json` if it
116
+ is ever tracked or packed; only the example schema belongs in the public repo.
117
+
118
+ Before publishing the detached public mirror, run the final local release
119
+ preflight:
120
+
121
+ ```bash
122
+ npm run public:release-ready
123
+ ```
124
+
125
+ This is the release-oriented alpha readiness gate. It requires fresh external
126
+ MCP evidence and a dated `CHANGELOG.md` heading for the current package version,
127
+ so it reports both final blockers in one place before `public:mirror`.
128
+
129
+ This adds the public-release audit: packed-file inspection, tracked and
130
+ non-ignored untracked file secret-shape scanning, production `npm audit`,
131
+ dependency license allowlist checks, and a high-risk Git history secret scan.
132
+
133
+ Before changing the current GitHub repository to public visibility while
134
+ preserving its Git history, run the stricter one-command gate:
135
+
136
+ ```bash
137
+ npm run public:repo-ready
138
+ ```
139
+
140
+ If strict history fails because private dogfooding commits contain local
141
+ fingerprints, do not rewrite `main` unless every collaborator agrees. Publish a
142
+ fresh public mirror instead:
143
+
144
+ ```bash
145
+ npm run public:mirror -- --remote <github-owner>/<public-repo>
146
+ cd ../computer-linker-public
147
+ git push -u origin main --follow-tags
148
+ ```
149
+
150
+ `public:mirror` runs the public readiness gate once, then calls the lower-level
151
+ `public:snapshot` path with the already-checked commit. `public:snapshot`
152
+ refuses a dirty worktree, copies the committed `HEAD` tree only, and creates a
153
+ new single-commit repository using your configured Git author identity. The
154
+ generated commit bypasses local Git hooks because the script performs its own
155
+ snapshot verification. It verifies that the generated repository has exactly
156
+ one clean commit, a `v<package.version>` tag pointing at that commit, and no
157
+ strict-history local fingerprints before printing push instructions. Use
158
+ `--remote <github-owner>/<public-repo>` for publishable mirrors; the shorthand is
159
+ normalized to `https://github.com/<github-owner>/<public-repo>.git`, and full
160
+ GitHub URLs also work. The remote is added during snapshot creation, and when
161
+ that remote is a GitHub repository, the snapshot's `package.json` repository,
162
+ issue, and homepage links are rewritten to the public repository. Public-facing
163
+ GitHub links in files such as issue-template config and schema ids are also
164
+ rewritten. Real publishable mirrors require the matching changelog heading to
165
+ be dated instead of `Unreleased`; remote dry-runs print whether the real run
166
+ would be blocked. The default output directory is `../computer-linker-public`; pass
167
+ `--output <path>` only when you need a different disposable mirror directory.
168
+ When the default directory already contains a clean one-commit snapshot created
169
+ by Computer Linker, `public:snapshot` replaces it automatically so the short
170
+ publish command is repeatable.
171
+ Without `--remote`, the output is a local verification snapshot and the package
172
+ metadata remains unchanged; do not push that verification-only mirror. Use
173
+ `--force` only when replacing a non-default disposable output directory or a
174
+ manually changed generated mirror. `--allow-dirty` is accepted only with `--dry-run`; committed `HEAD`
175
+ must be clean before creating a real public snapshot. Snapshot commits omit the
176
+ private source commit reference by default; use `--include-source-ref` only when
177
+ release traceability is more important than keeping the public mirror detached
178
+ from the private dogfooding history.
179
+
180
+ Use `npm run public:ready` and `npm run public:snapshot` directly only when
181
+ debugging a failed release gate.
182
+
183
+ `computer-linker doctor` and `/api/v1/control` with `action: "doctor"` also
184
+ return `releaseReadiness`. The release is blocked when that object has
185
+ `status: "blocked"` or non-empty `blockingReasons`.
186
+ `computer-linker config validate` exposes the same config, security, and
187
+ release-readiness subset for release scripts and exits non-zero when the status
188
+ is blocked.
189
+
190
+ ## Required Before Tagging
191
+
192
+ - `npm run product:check` passes locally, and the manual Windows/Node 22 CI gate
193
+ passes when Actions budget is available.
194
+ - `npm run alpha:check` passes locally before sharing an alpha build or public
195
+ snapshot; a `preserved-history-audit` warning is acceptable only when the
196
+ release will use `public:mirror` instead of preserving private repo history.
197
+ - `npm run public:mirror -- --dry-run --remote <github-owner>/<public-repo>`
198
+ passes before publishing from a fresh public mirror.
199
+ - `npm run alpha:check -- --require-evidence` passes before announcing a public
200
+ alpha outside private dogfooding.
201
+ - Broader OS or Node coverage is run manually before a wider release when the
202
+ Actions budget allows it.
203
+ - `npm run public:check` passes before publishing a package artifact.
204
+ - `npm run public:repo-ready` passes before changing the existing GitHub
205
+ repository to public visibility with preserved history. If it fails only on
206
+ local history fingerprints, publish from `public:mirror` instead.
207
+ - `computer-linker doctor --json` reports no `releaseReadiness.blockingReasons`
208
+ on the target machine.
209
+ - `computer-linker config validate` exits successfully on the target machine.
210
+ - At least one workspace scope is configured and its path exists.
211
+ - HTTP exposure has an owner token before any tunnel is started.
212
+ - Shell or Codex scopes have an explicit command allowlist when used outside
213
+ local dogfooding.
214
+ - README, product spec, architecture docs, changelog, security policy, and
215
+ `computer_operation` schema match the shipped contract.
216
+ - Tagged releases use `v<package.version>` and replace the current changelog
217
+ heading's `Unreleased` suffix with a release date before pushing the tag.
218
+ Fresh public mirrors create this tag automatically; push it with
219
+ `--follow-tags`.
220
+ - Manual `npm publish` is guarded by `prepublishOnly`, which requires a clean
221
+ worktree, `v<package.version>` on `HEAD`, a dated changelog heading,
222
+ `npm run public:check`, and strict public-history audit before npm prepares
223
+ the package.
224
+
225
+ ## Security Review
226
+
227
+ For each shell or Codex-enabled scope, verify:
228
+
229
+ - The scope points at a trusted project directory.
230
+ - `allowedCommands` is narrow enough for expected workflows.
231
+ - `deniedCommands` blocks known destructive local patterns for that team.
232
+ - `maxRuntimeSeconds` and `maxOutputBytes` are finite.
233
+ - The user understands that shell and Codex are cwd-bound execution, not an OS
234
+ filesystem sandbox.
235
+
236
+ ## Smoke Commands
237
+
238
+ ```bash
239
+ computer-linker init
240
+ computer-linker self-test
241
+ computer-linker status
242
+ computer-linker status --details
243
+ computer-linker status --json
244
+ computer-linker doctor
245
+ computer-linker doctor --json
246
+ computer-linker config validate
247
+ computer-linker config policy app --json
248
+ computer-linker client setup
249
+ computer-linker client setup --details
250
+ computer-linker client setup --show-token
251
+ computer-linker client setup --json
252
+ computer-linker client smoke --url http://127.0.0.1:3939/mcp --allow-http
253
+ computer-linker client chatgpt verify --mode coding
254
+ npm run alpha:evidence -- check
255
+ ```
256
+
257
+ For package validation from a checkout:
258
+
259
+ ```bash
260
+ npm ci
261
+ npm run release:validate
262
+ npm run product:check
263
+ npm run public:audit
264
+ ```
265
+
266
+ For preserved-history GitHub repository publication, replace the last two
267
+ commands with:
268
+
269
+ ```bash
270
+ npm run public:repo-ready
271
+ ```
272
+
273
+ The manual GitHub Actions `Release Package` workflow runs `public:repo-ready`
274
+ and uploads the resulting `computer-linker-*.tgz` artifact for final
275
+ inspection. It must be launched manually from the `v<package.version>` tag in a
276
+ repo whose preserved history is safe for public packaging, such as the
277
+ `--remote` public snapshot. The workflow also rejects an `Unreleased` changelog
278
+ heading before spending time on the full public gate.
279
+ The default CI workflow is also manual and cost-capped: run it from
280
+ `workflow_dispatch` only when Actions budget is available. It should stay on
281
+ `windows-latest` with Node 22 and run `npm run product:check`; run broader OS or
282
+ Node coverage manually only for a wider release. `npm run release:validate`
283
+ rejects automatic triggers, matrix jobs, non-Windows runners, and extra Node
284
+ versions in the default workflows.
285
+ Use [manual-test-plan.md](manual-test-plan.md) for the local dogfooding pass.
@@ -0,0 +1,99 @@
1
+ # Service Mode
2
+
3
+ Computer Linker can run as a background service on Linux, macOS, and Windows.
4
+ The default service flow is conservative: preview with `--dry-run`, then apply
5
+ install/uninstall with `--yes`.
6
+
7
+ Generate a profile for the current platform:
8
+
9
+ ```bash
10
+ computer-linker service profile
11
+ ```
12
+
13
+ Generate a specific platform manifest:
14
+
15
+ ```bash
16
+ computer-linker service profile --platform linux --format manifest
17
+ computer-linker service profile --platform macos --format manifest
18
+ computer-linker service profile --platform windows --format manifest
19
+ ```
20
+
21
+ Write a complete service bundle:
22
+
23
+ ```bash
24
+ computer-linker service profile --platform linux --output-dir ./service-profile
25
+ ```
26
+
27
+ The bundle contains:
28
+
29
+ - `service-profile.json`
30
+ - the native service manifest (`.service`, `.plist`, or `.ps1`)
31
+ - `install-service.sh` or `install-service.ps1`
32
+ - `uninstall-service.sh` or `uninstall-service.ps1`
33
+
34
+ Check what Computer Linker expects on this machine:
35
+
36
+ ```bash
37
+ computer-linker service status
38
+ computer-linker service status --json
39
+ ```
40
+
41
+ Preview install or uninstall commands without changing the OS:
42
+
43
+ ```bash
44
+ computer-linker service install --dry-run
45
+ computer-linker service install --dry-run --json
46
+ computer-linker service uninstall --dry-run
47
+ ```
48
+
49
+ Install or remove the service on the current platform:
50
+
51
+ ```bash
52
+ computer-linker service install --yes
53
+ computer-linker service start
54
+ computer-linker service status
55
+ computer-linker service logs
56
+ computer-linker service stop
57
+ computer-linker service uninstall --yes
58
+ ```
59
+
60
+ `install --yes` writes the service bundle under the Computer Linker config
61
+ directory by default, then runs the generated install script. Pass
62
+ `--output-dir ./service-profile` when you want the bundle somewhere else.
63
+ `service start` and `service stop` control the already-installed service on the
64
+ current platform. Use `--dry-run` for cross-platform plans such as
65
+ `--platform linux` while working on Windows.
66
+
67
+ Before installing:
68
+
69
+ ```bash
70
+ computer-linker init
71
+ computer-linker doctor
72
+ ```
73
+
74
+ `doctor` includes a machine-readable `startup` block with foreground start,
75
+ HTTP, stdio, and persistent service startup modes. It also includes the current
76
+ platform service status commands, profile command, bundle command, and install
77
+ dry-run command, so a setup script or MCP client can discover the right service
78
+ workflow without parsing this document.
79
+
80
+ The generated service runs:
81
+
82
+ ```bash
83
+ computer-linker serve --transport http
84
+ ```
85
+
86
+ It uses `COMPUTER_LINKER_CONFIG_DIR` so the service reads the same bounded
87
+ workspace config as the interactive CLI. Host, port, owner token, public URL,
88
+ and workspace permissions stay in `config.json`.
89
+
90
+ Platform notes:
91
+
92
+ - Linux uses `systemd`.
93
+ - macOS uses a per-user `launchd` agent in `~/Library/LaunchAgents`.
94
+ - Windows uses `sc.exe`; install/uninstall require an elevated PowerShell
95
+ prompt. Generated Windows services write `service.out.log` and
96
+ `service.err.log` under the Computer Linker config directory.
97
+
98
+ Keep the HTTP service loopback-only unless it is protected by Tailscale,
99
+ Cloudflare Access, or equivalent network controls.
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env node
2
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
3
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
4
+
5
+ const url = new URL(
6
+ process.env.COMPUTER_LINKER_MCP_URL ??
7
+ process.env.WORKSPACE_LINKER_MCP_URL ??
8
+ process.argv[2] ??
9
+ "http://127.0.0.1:3939/mcp",
10
+ );
11
+ const token =
12
+ process.env.COMPUTER_LINKER_TOKEN ??
13
+ process.env.COMPUTER_LINKER_OWNER_TOKEN ??
14
+ process.env.WORKSPACE_LINKER_TOKEN ??
15
+ process.env.WORKSPACE_LINKER_OWNER_TOKEN ??
16
+ process.argv[3];
17
+
18
+ const client = new Client({
19
+ name: "computer-linker-minimal-client",
20
+ version: "0.1.0",
21
+ });
22
+ const transport = new StreamableHTTPClientTransport(url, {
23
+ requestInit: {
24
+ headers: token ? { authorization: `Bearer ${token}` } : undefined,
25
+ },
26
+ });
27
+
28
+ try {
29
+ await client.connect(transport);
30
+
31
+ const tools = await client.listTools();
32
+ const toolNames = tools.tools.map((tool) => tool.name);
33
+ console.log(`tools: ${toolNames.join(", ")}`);
34
+
35
+ for (const requiredTool of ["get_computer_info", "computer_operation", "get_operation_history"]) {
36
+ if (!toolNames.includes(requiredTool)) {
37
+ throw new Error(`Missing required tool: ${requiredTool}`);
38
+ }
39
+ }
40
+
41
+ const computerInfo = toolData(await client.callTool({
42
+ name: "get_computer_info",
43
+ arguments: {},
44
+ }));
45
+ const scope = readableScope(computerInfo);
46
+ if (!scope) {
47
+ throw new Error("No readable scope returned by get_computer_info.");
48
+ }
49
+ console.log(`scope: ${scope}`);
50
+
51
+ const operation = toolData(await client.callTool({
52
+ name: "computer_operation",
53
+ arguments: {
54
+ scope,
55
+ op: "file.list",
56
+ target: ".",
57
+ input: {},
58
+ options: { maxEntries: 5 },
59
+ },
60
+ }));
61
+ if (operation?.ok !== true) {
62
+ throw new Error(`computer_operation file.list failed: ${operation?.error?.message ?? "unknown error"}`);
63
+ }
64
+ console.log("file.list: ok");
65
+
66
+ const history = toolData(await client.callTool({
67
+ name: "get_operation_history",
68
+ arguments: {
69
+ view: "last",
70
+ limit: 5,
71
+ },
72
+ }));
73
+ console.log(`history: ${history?.view ?? "unknown"}`);
74
+ } finally {
75
+ await closeClient();
76
+ }
77
+
78
+ function toolData(result) {
79
+ if (result?.structuredContent && typeof result.structuredContent === "object") {
80
+ return result.structuredContent;
81
+ }
82
+ const text = result?.content?.find((item) => item.type === "text" && typeof item.text === "string")?.text;
83
+ if (!text) return undefined;
84
+ try {
85
+ return JSON.parse(text);
86
+ } catch {
87
+ return undefined;
88
+ }
89
+ }
90
+
91
+ function readableScope(computerInfo) {
92
+ return computerInfo?.scopes?.find((scope) => (
93
+ typeof scope.id === "string" &&
94
+ (
95
+ scope.permissions?.read === true ||
96
+ scope.allowedOperations?.includes("file.list") ||
97
+ scope.allowedOperations?.includes("read") ||
98
+ scope.allowedOperations?.includes("search_text")
99
+ )
100
+ ))?.id;
101
+ }
102
+
103
+ async function closeClient() {
104
+ try {
105
+ if (transport.sessionId) await transport.terminateSession();
106
+ } catch {
107
+ // Best effort.
108
+ }
109
+ try {
110
+ await client.close();
111
+ } catch {
112
+ // Best effort.
113
+ }
114
+ }
package/package.json ADDED
@@ -0,0 +1,87 @@
1
+ {
2
+ "name": "@easonwumac/computer-linker",
3
+ "version": "0.1.2",
4
+ "description": "One computer, one permissioned MCP linker for local workspaces.",
5
+ "type": "module",
6
+ "main": "dist/client.js",
7
+ "types": "dist/client.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "docs",
11
+ "examples",
12
+ "README.md",
13
+ "CHANGELOG.md",
14
+ "LICENSE",
15
+ "SECURITY.md"
16
+ ],
17
+ "keywords": [
18
+ "mcp",
19
+ "mcp-server",
20
+ "workspace",
21
+ "codex",
22
+ "local-first",
23
+ "automation"
24
+ ],
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/easonwumac/computer-linker.git"
28
+ },
29
+ "bugs": {
30
+ "url": "https://github.com/easonwumac/computer-linker/issues"
31
+ },
32
+ "homepage": "https://github.com/easonwumac/computer-linker#readme",
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/client.d.ts",
36
+ "import": "./dist/client.js"
37
+ },
38
+ "./client": {
39
+ "types": "./dist/client.d.ts",
40
+ "import": "./dist/client.js"
41
+ }
42
+ },
43
+ "bin": {
44
+ "computer-linker": "dist/cli.js"
45
+ },
46
+ "scripts": {
47
+ "build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json",
48
+ "alpha:check": "node scripts/alpha-readiness-report.mjs",
49
+ "alpha:evidence": "node scripts/alpha-evidence.mjs",
50
+ "alpha:snapshot-check": "node scripts/alpha-readiness-report.mjs --accept-public-snapshot",
51
+ "dev": "tsx src/cli.ts",
52
+ "pack:check": "npm run build && npm run pack:smoke",
53
+ "pack:smoke": "node scripts/package-smoke.mjs",
54
+ "prepublishOnly": "npm run publish:guard",
55
+ "product:check": "npm run release:validate && npm run typecheck && npm test && npm run build && npm run pack:smoke",
56
+ "publish:guard": "node scripts/publish-guard.mjs",
57
+ "public:audit": "node scripts/public-release-audit.mjs",
58
+ "public:check": "npm run product:check && npm run public:audit",
59
+ "public:mirror": "node scripts/create-public-mirror.mjs",
60
+ "public:ready": "node scripts/alpha-readiness-report.mjs --accept-public-snapshot",
61
+ "public:release-ready": "node scripts/alpha-readiness-report.mjs --accept-public-snapshot --require-evidence --require-dated-changelog",
62
+ "public:repo-ready": "npm run product:check && npm run public:audit -- --strict-history",
63
+ "public:snapshot": "node scripts/create-public-snapshot.mjs",
64
+ "release:check": "node scripts/release-npm.mjs --check",
65
+ "release:dry-run": "node scripts/release-npm.mjs --dry-run",
66
+ "release:publish": "node scripts/release-npm.mjs --publish",
67
+ "release:validate": "node scripts/release-validate.mjs",
68
+ "start": "node dist/cli.js start",
69
+ "test": "node scripts/run-tests.mjs",
70
+ "typecheck": "tsc -p tsconfig.json --noEmit"
71
+ },
72
+ "engines": {
73
+ "node": ">=20.12"
74
+ },
75
+ "dependencies": {
76
+ "@modelcontextprotocol/sdk": "^1.29.0",
77
+ "express": "^5.2.1",
78
+ "zod": "^4.4.3"
79
+ },
80
+ "devDependencies": {
81
+ "@types/express": "^5.0.6",
82
+ "@types/node": "^25.9.1",
83
+ "tsx": "^4.22.3",
84
+ "typescript": "^6.0.3"
85
+ },
86
+ "license": "MIT"
87
+ }