opencode-session-port 0.0.0-stage → 0.1.1
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/LICENSE +21 -0
- package/README.md +84 -2
- package/dist/tui.js +10276 -0
- package/package.json +48 -4
- package/src/core/contracts/crypto.ts +66 -0
- package/src/core/contracts/index.ts +13 -0
- package/src/core/contracts/json.ts +142 -0
- package/src/core/contracts/session.ts +12 -0
- package/src/core/crypto/container.ts +686 -0
- package/src/core/crypto/envelope.ts +232 -0
- package/src/core/crypto/errors.ts +52 -0
- package/src/core/crypto/gzip-stream.ts +388 -0
- package/src/core/crypto/index.ts +13 -0
- package/src/core/crypto/kdf.ts +101 -0
- package/src/core/crypto/policy.ts +202 -0
- package/src/core/crypto/zero.ts +33 -0
- package/src/core/restore/identity.ts +202 -0
- package/src/core/restore/index.ts +24 -0
- package/src/core/restore/planner.ts +1122 -0
- package/src/core/sessions/collector.ts +323 -0
- package/src/core/sessions/errors.ts +37 -0
- package/src/core/sessions/guards.ts +11 -0
- package/src/core/sessions/index.ts +29 -0
- package/src/core/sessions/policy.ts +80 -0
- package/src/core/sessions/port.ts +88 -0
- package/src/core/sessions/serialize.ts +15 -0
- package/src/core/sessions/unsettled.ts +35 -0
- package/src/integrations/omo/index.ts +28 -0
- package/src/tui/adapters/host-client.ts +254 -0
- package/src/tui/adapters/index.ts +72 -0
- package/src/tui/adapters/location-resolver.ts +281 -0
- package/src/tui/adapters/project-destinations.ts +271 -0
- package/src/tui/adapters/session-id-inventory.ts +378 -0
- package/src/tui/adapters/session-import.ts +189 -0
- package/src/tui/adapters/session-read.ts +115 -0
- package/src/tui/artifacts/files.ts +285 -0
- package/src/tui/orchestration/checkpoint.ts +160 -0
- package/src/tui/orchestration/index.ts +55 -0
- package/src/tui/orchestration/restore-auth.ts +94 -0
- package/src/tui/orchestration/restore-execution.ts +381 -0
- package/src/tui/orchestration/restore-preflight.ts +223 -0
- package/src/tui/orchestration/shared.ts +75 -0
- package/src/tui/ui/password-dialog.tsx +251 -0
- package/src/tui/ui/password-flow.ts +288 -0
- package/src/tui/ui/restore-project-selector.ts +62 -0
- package/src/tui/ui/restore-report-dialog.tsx +251 -0
- package/src/tui/ui/restore-report-flow.ts +94 -0
- package/src/tui/ui/sessionport-commands.tsx +65 -0
- package/src/tui/wiring/composition.ts +354 -0
- package/src/tui/wiring/experimental-profile.ts +86 -0
- package/src/tui/wiring/index.ts +51 -0
- package/src/tui/wiring/install.ts +108 -0
- package/src/tui/wiring/reports.ts +340 -0
- package/src/tui.ts +34 -0
- package/tsconfig.json +18 -0
- package/tui.ts +17 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitized SessionPort command reports (Phase 2 wiring; O-15/OQ-15).
|
|
3
|
+
*
|
|
4
|
+
* Every function here returns a fixed, generic notification object; raw host
|
|
5
|
+
* or exception text is NEVER interpolated. Classification uses stable error
|
|
6
|
+
* classes/codes only, never message text, so a failure report cannot leak
|
|
7
|
+
* session IDs, paths, host internals, or password material. Exact user-facing
|
|
8
|
+
* copy remains OPEN (OQ-15); these strings are the wiring lane's generic
|
|
9
|
+
* sanitized categories.
|
|
10
|
+
*
|
|
11
|
+
* Truthful-outcome rules:
|
|
12
|
+
* - Checkpoint success is reported only for a `written` outcome with the
|
|
13
|
+
* artifact path, encrypted byte count, and session count.
|
|
14
|
+
* - Restore success is reported only for a non-empty execution result with at
|
|
15
|
+
* least one imported session and no failed/blocked/not-attempted entries; an
|
|
16
|
+
* empty artifact, cancel, capability absence, authentication failure, and
|
|
17
|
+
* every error are reported as non-success.
|
|
18
|
+
* - A completed non-empty restore execution is presented through the
|
|
19
|
+
* designer-owned keyboard-navigable report dialog using
|
|
20
|
+
* `mapRestoreExecutionToReportPresentation` (aggregate counts plus one
|
|
21
|
+
* navigable entry per session: source ID, planner classification, skip
|
|
22
|
+
* reason when present, and execution status). `reportRestoreExecution`
|
|
23
|
+
* remains the truthful empty-result notification, and
|
|
24
|
+
* `reportRestoreExecutionFallback` is the bounded aggregate-only notification
|
|
25
|
+
* used when that dialog cannot be displayed; partial progress states
|
|
26
|
+
* explicitly that there is no atomic rollback.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import { ArtifactFileError } from "../artifacts/files.ts";
|
|
30
|
+
import { HostAdapterError, ProjectDestinationError } from "../adapters/index.ts";
|
|
31
|
+
import { LocationResolutionError } from "../adapters/location-resolver.ts";
|
|
32
|
+
import { CryptoContainerError } from "../../core/crypto/errors.ts";
|
|
33
|
+
import { RestorePlanError } from "../../core/restore/planner.ts";
|
|
34
|
+
import { SessionCollectionError } from "../../core/sessions/index.ts";
|
|
35
|
+
import { RESTORE_PASSWORD_ATTEMPT_LIMIT } from "../orchestration/index.ts";
|
|
36
|
+
import type { CheckpointOutcome, RestoreExecutionResult } from "../orchestration/index.ts";
|
|
37
|
+
import type {
|
|
38
|
+
RestoreReportPresentationModel,
|
|
39
|
+
RestoreReportSession,
|
|
40
|
+
} from "../ui/restore-report-flow.ts";
|
|
41
|
+
|
|
42
|
+
/* ------------------------------------------------------------------------- */
|
|
43
|
+
/* Notification shape */
|
|
44
|
+
/* ------------------------------------------------------------------------- */
|
|
45
|
+
|
|
46
|
+
/** Host toast variants (mirrors `Plugin.Context["ui"]["toast"]`). */
|
|
47
|
+
export type SessionPortNotificationVariant = "info" | "success" | "warning" | "error";
|
|
48
|
+
|
|
49
|
+
/** One sanitized user-facing notification; `message` never contains raw error text. */
|
|
50
|
+
export interface SessionPortNotification {
|
|
51
|
+
readonly title: string;
|
|
52
|
+
readonly message: string;
|
|
53
|
+
readonly variant: SessionPortNotificationVariant;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* ------------------------------------------------------------------------- */
|
|
57
|
+
/* Checkpoint reports */
|
|
58
|
+
/* ------------------------------------------------------------------------- */
|
|
59
|
+
|
|
60
|
+
/** Reports one completed checkpoint outcome with its raw path/size/count facts. */
|
|
61
|
+
export function reportCheckpointOutcome(outcome: CheckpointOutcome): SessionPortNotification {
|
|
62
|
+
switch (outcome.status) {
|
|
63
|
+
case "no-sessions":
|
|
64
|
+
return {
|
|
65
|
+
title: "Checkpoint not created",
|
|
66
|
+
message: "No sessions were found for this project, so no checkpoint was created.",
|
|
67
|
+
variant: "warning",
|
|
68
|
+
};
|
|
69
|
+
case "canceled":
|
|
70
|
+
return {
|
|
71
|
+
title: "Checkpoint canceled",
|
|
72
|
+
message: "The password prompt was canceled; no artifact was written.",
|
|
73
|
+
variant: "info",
|
|
74
|
+
};
|
|
75
|
+
case "written":
|
|
76
|
+
return {
|
|
77
|
+
title: "Checkpoint created",
|
|
78
|
+
message: `Wrote ${outcome.artifactPath} (${outcome.encryptedBytes} bytes, ${outcome.sessionCount} sessions).`,
|
|
79
|
+
variant: "success",
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Reports one checkpoint failure as a fixed, sanitized category. */
|
|
85
|
+
export function reportCheckpointFailure(error: unknown): SessionPortNotification {
|
|
86
|
+
const category = classifyFailure(error);
|
|
87
|
+
switch (category) {
|
|
88
|
+
case "location":
|
|
89
|
+
return checkpointFailure("The active project could not be verified with the host; no artifact was written.");
|
|
90
|
+
case "location-capability":
|
|
91
|
+
return checkpointFailure(
|
|
92
|
+
"This OpenCode host does not expose the project-location capability required to create a checkpoint; no artifact was written.",
|
|
93
|
+
);
|
|
94
|
+
case "capability":
|
|
95
|
+
return checkpointFailure("This OpenCode host does not expose the required session-listing capability; no artifact was written.");
|
|
96
|
+
case "collection":
|
|
97
|
+
return checkpointFailure("Collecting the project's sessions failed; no artifact was written.");
|
|
98
|
+
case "path-exists":
|
|
99
|
+
return checkpointFailure("An artifact already exists at that path; nothing was overwritten.");
|
|
100
|
+
case "artifact-path":
|
|
101
|
+
return checkpointFailure("The artifact output path is not usable; no artifact was written.");
|
|
102
|
+
case "crypto":
|
|
103
|
+
return checkpointFailure("The checkpoint could not be encrypted; no artifact was written.");
|
|
104
|
+
case "destinations":
|
|
105
|
+
case "plan":
|
|
106
|
+
case "authentication":
|
|
107
|
+
// Not reachable on the checkpoint path; fall through to the generic case.
|
|
108
|
+
break;
|
|
109
|
+
case "unknown":
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
return checkpointFailure("Checkpoint failed; no artifact was written.");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function checkpointFailure(message: string): SessionPortNotification {
|
|
116
|
+
return { title: "Checkpoint failed", message, variant: "error" };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* ------------------------------------------------------------------------- */
|
|
120
|
+
/* Restore reports */
|
|
121
|
+
/* ------------------------------------------------------------------------- */
|
|
122
|
+
|
|
123
|
+
/** The artifact path argument is required; nothing was read or changed. */
|
|
124
|
+
export function reportRestoreUsage(): SessionPortNotification {
|
|
125
|
+
return {
|
|
126
|
+
title: "Restore needs an artifact path",
|
|
127
|
+
message: "Usage: /restore <path-to-checkpoint>. No sessions were changed.",
|
|
128
|
+
variant: "warning",
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** O-12 capability absence: reported before any artifact read, decrypt, or import. */
|
|
133
|
+
export function reportRestoreCapabilityUnavailable(): SessionPortNotification {
|
|
134
|
+
return {
|
|
135
|
+
title: "Restore unavailable",
|
|
136
|
+
message:
|
|
137
|
+
"This OpenCode host does not expose the session-import capability required to restore; no sessions were changed.",
|
|
138
|
+
variant: "warning",
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** The user canceled project selection or the password prompt; nothing was changed. */
|
|
143
|
+
export function reportRestoreCanceled(): SessionPortNotification {
|
|
144
|
+
return {
|
|
145
|
+
title: "Restore canceled",
|
|
146
|
+
message: "Restore was canceled; no sessions were changed.",
|
|
147
|
+
variant: "info",
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Terminal three-attempt authentication failure; deliberately does not distinguish password vs. damage. */
|
|
152
|
+
export function reportRestoreAuthenticationFailed(): SessionPortNotification {
|
|
153
|
+
return {
|
|
154
|
+
title: "Restore stopped",
|
|
155
|
+
message: `The checkpoint could not be opened after ${RESTORE_PASSWORD_ATTEMPT_LIMIT} password attempts; no sessions were changed.`,
|
|
156
|
+
variant: "error",
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Reports one restore failure as a fixed, sanitized category. `executionStarted`
|
|
162
|
+
* is true only once the import executor was invoked; the copy never claims
|
|
163
|
+
* "no sessions were changed" after that point.
|
|
164
|
+
*/
|
|
165
|
+
export function reportRestoreFailure(error: unknown, executionStarted: boolean): SessionPortNotification {
|
|
166
|
+
if (executionStarted) {
|
|
167
|
+
return {
|
|
168
|
+
title: "Restore stopped",
|
|
169
|
+
message:
|
|
170
|
+
"Restore stopped unexpectedly during execution. Review the session list for partial results; there is no atomic rollback.",
|
|
171
|
+
variant: "error",
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const category = classifyFailure(error);
|
|
175
|
+
switch (category) {
|
|
176
|
+
case "capability":
|
|
177
|
+
return restoreFailure("This OpenCode host does not expose a capability required to restore; no sessions were changed.");
|
|
178
|
+
case "location-capability":
|
|
179
|
+
return restoreFailure(
|
|
180
|
+
"This OpenCode host does not expose the project-location capability required to restore; no sessions were changed.",
|
|
181
|
+
);
|
|
182
|
+
case "location":
|
|
183
|
+
return restoreFailure("The selected project could not be verified with the host; no sessions were changed.");
|
|
184
|
+
case "destinations":
|
|
185
|
+
return restoreFailure("The host project list could not be read; no sessions were changed.");
|
|
186
|
+
case "collection":
|
|
187
|
+
return restoreFailure("The destination project's sessions could not be read; no sessions were changed.");
|
|
188
|
+
case "plan":
|
|
189
|
+
return restoreFailure("The checkpoint does not match this destination safely; no sessions were changed.");
|
|
190
|
+
case "artifact-path":
|
|
191
|
+
return restoreFailure("The artifact path is not usable; no sessions were changed.");
|
|
192
|
+
case "path-exists":
|
|
193
|
+
return restoreFailure("The artifact path is not usable for reading; no sessions were changed.");
|
|
194
|
+
case "authentication":
|
|
195
|
+
return restoreFailure("The checkpoint could not be authenticated; no sessions were changed.");
|
|
196
|
+
case "crypto":
|
|
197
|
+
return restoreFailure("The file could not be opened as a SessionPort checkpoint; no sessions were changed.");
|
|
198
|
+
case "unknown":
|
|
199
|
+
return restoreFailure("Restore failed; no sessions were changed.");
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function restoreFailure(message: string): SessionPortNotification {
|
|
204
|
+
return { title: "Restore failed", message, variant: "error" };
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Reports one completed restore execution: aggregate counts plus per-session
|
|
209
|
+
* facts. Zero sessions never report success; all-skipped results report as
|
|
210
|
+
* informational, not success. Partial progress states the no-rollback policy.
|
|
211
|
+
*
|
|
212
|
+
* Non-empty executions are presented through the designer report dialog
|
|
213
|
+
* instead; this helper remains the truthful empty-result notification (and the
|
|
214
|
+
* defensive empty-result branch of `reportRestoreExecutionFallback`).
|
|
215
|
+
*/
|
|
216
|
+
export function reportRestoreExecution(result: RestoreExecutionResult): SessionPortNotification {
|
|
217
|
+
const { summary } = result;
|
|
218
|
+
if (summary.total === 0) {
|
|
219
|
+
return {
|
|
220
|
+
title: "Nothing to restore",
|
|
221
|
+
message: "The checkpoint contains no sessions; no sessions were imported.",
|
|
222
|
+
variant: "warning",
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
const lines: string[] = [
|
|
226
|
+
`Restore finished: ${summary.imported} imported, ${summary.skipped} skipped, ${summary.failed} failed, ` +
|
|
227
|
+
`${summary.blocked} blocked, ${summary.notAttempted} not attempted (${summary.total} total).`,
|
|
228
|
+
];
|
|
229
|
+
for (const outcome of result.outcomes) {
|
|
230
|
+
const fields = [outcome.sourceSessionID, outcome.classification, outcome.status];
|
|
231
|
+
if (outcome.skipReason !== undefined) fields.push(outcome.skipReason);
|
|
232
|
+
lines.push(fields.join(" · "));
|
|
233
|
+
}
|
|
234
|
+
if (summary.failed > 0 || summary.blocked > 0 || summary.notAttempted > 0) {
|
|
235
|
+
lines.push("Partial progress: no atomic rollback; imported sessions remain.");
|
|
236
|
+
}
|
|
237
|
+
const clean = summary.failed === 0 && summary.blocked === 0 && summary.notAttempted === 0;
|
|
238
|
+
const variant = !clean ? "warning" : summary.imported > 0 ? "success" : "info";
|
|
239
|
+
return {
|
|
240
|
+
title: "Restore finished",
|
|
241
|
+
message: lines.join("\n"),
|
|
242
|
+
variant,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/* ------------------------------------------------------------------------- */
|
|
247
|
+
/* Restore report dialog integration */
|
|
248
|
+
/* ------------------------------------------------------------------------- */
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Maps one completed, already-sanitized execution result into the designer's
|
|
252
|
+
* `RestoreReportPresentationModel`. Only aggregate counts and display-safe
|
|
253
|
+
* per-session facts (source session ID, planner classification, execution
|
|
254
|
+
* status, and planner skip reason) cross into the model; the derived target
|
|
255
|
+
* session ID, host data, and exception objects are never included.
|
|
256
|
+
*/
|
|
257
|
+
export function mapRestoreExecutionToReportPresentation(result: RestoreExecutionResult): RestoreReportPresentationModel {
|
|
258
|
+
const sessions: RestoreReportSession[] = result.outcomes.map((outcome) => ({
|
|
259
|
+
sessionID: outcome.sourceSessionID,
|
|
260
|
+
classification: outcome.classification,
|
|
261
|
+
status: outcome.status,
|
|
262
|
+
...(outcome.skipReason !== undefined ? { skipReason: outcome.skipReason } : {}),
|
|
263
|
+
}));
|
|
264
|
+
return {
|
|
265
|
+
summary: {
|
|
266
|
+
total: result.summary.total,
|
|
267
|
+
imported: result.summary.imported,
|
|
268
|
+
skipped: result.summary.skipped,
|
|
269
|
+
failed: result.summary.failed,
|
|
270
|
+
blocked: result.summary.blocked,
|
|
271
|
+
notAttempted: result.summary.notAttempted,
|
|
272
|
+
},
|
|
273
|
+
sessions,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Bounded aggregate-only fallback for a completed non-empty execution whose
|
|
279
|
+
* interactive report dialog could not be displayed. The execution already
|
|
280
|
+
* finished, so this copy never reports an execution failure; it contains only
|
|
281
|
+
* aggregate counts, a fixed display-failure note, and the partial-progress
|
|
282
|
+
* no-rollback notice when the result is partial. No per-session lines, raw
|
|
283
|
+
* exception text, or dialog error text are ever included.
|
|
284
|
+
*/
|
|
285
|
+
export function reportRestoreExecutionFallback(result: RestoreExecutionResult): SessionPortNotification {
|
|
286
|
+
const { summary } = result;
|
|
287
|
+
if (summary.total === 0) {
|
|
288
|
+
// Defensive: an empty result keeps the truthful non-success copy.
|
|
289
|
+
return reportRestoreExecution(result);
|
|
290
|
+
}
|
|
291
|
+
const clean = summary.failed === 0 && summary.blocked === 0 && summary.notAttempted === 0;
|
|
292
|
+
const variant = !clean ? "warning" : summary.imported > 0 ? "success" : "info";
|
|
293
|
+
const lines = [
|
|
294
|
+
`Restore finished: ${summary.imported} imported, ${summary.skipped} skipped, ${summary.failed} failed, ` +
|
|
295
|
+
`${summary.blocked} blocked, ${summary.notAttempted} not attempted (${summary.total} total). ` +
|
|
296
|
+
"The per-session report could not be displayed.",
|
|
297
|
+
];
|
|
298
|
+
if (!clean) {
|
|
299
|
+
lines.push("Partial progress: no atomic rollback; imported sessions remain.");
|
|
300
|
+
}
|
|
301
|
+
return {
|
|
302
|
+
title: "Restore finished",
|
|
303
|
+
message: lines.join("\n"),
|
|
304
|
+
variant,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/* ------------------------------------------------------------------------- */
|
|
309
|
+
/* Error classification (classes/codes only; never message text) */
|
|
310
|
+
/* ------------------------------------------------------------------------- */
|
|
311
|
+
|
|
312
|
+
type FailureCategory =
|
|
313
|
+
| "capability"
|
|
314
|
+
| "location"
|
|
315
|
+
| "location-capability"
|
|
316
|
+
| "destinations"
|
|
317
|
+
| "collection"
|
|
318
|
+
| "plan"
|
|
319
|
+
| "artifact-path"
|
|
320
|
+
| "path-exists"
|
|
321
|
+
| "authentication"
|
|
322
|
+
| "crypto"
|
|
323
|
+
| "unknown";
|
|
324
|
+
|
|
325
|
+
function classifyFailure(error: unknown): FailureCategory {
|
|
326
|
+
if (error instanceof HostAdapterError) {
|
|
327
|
+
return error.code === "capability-unavailable" ? "capability" : "unknown";
|
|
328
|
+
}
|
|
329
|
+
if (error instanceof LocationResolutionError) {
|
|
330
|
+
return error.code === "capability-unavailable" ? "location-capability" : "location";
|
|
331
|
+
}
|
|
332
|
+
if (error instanceof ProjectDestinationError) return "destinations";
|
|
333
|
+
if (error instanceof SessionCollectionError) return "collection";
|
|
334
|
+
if (error instanceof RestorePlanError) return "plan";
|
|
335
|
+
if (error instanceof ArtifactFileError) return error.code === "path-exists" ? "path-exists" : "artifact-path";
|
|
336
|
+
if (error instanceof CryptoContainerError) {
|
|
337
|
+
return error.code === "authentication-failed" ? "authentication" : "crypto";
|
|
338
|
+
}
|
|
339
|
+
return "unknown";
|
|
340
|
+
}
|
package/src/tui.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Plugin } from "@opencode/plugin/tui"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SessionPort TUI plugin entrypoint (Phase 2 experimental Windows wiring).
|
|
5
|
+
*
|
|
6
|
+
* Setup checks `process.platform` first and only on Windows dynamically imports
|
|
7
|
+
* `installSessionPortWiring`, which:
|
|
8
|
+
* - registers `/checkpoint` and `/restore` only on Windows (`process.platform
|
|
9
|
+
* === "win32"`); every other platform gets no registration and no
|
|
10
|
+
* platform-support claim;
|
|
11
|
+
* - initializes the pinned `libsodium-wrappers-sumo@0.8.4` runtime first and
|
|
12
|
+
* fails closed if it is unavailable (setup rejects; nothing is registered);
|
|
13
|
+
* - registers commands inside the existing app-slot/keymap component scope
|
|
14
|
+
* (E39) and returns the slot disposer to the host.
|
|
15
|
+
*
|
|
16
|
+
* The platform gate deliberately runs before the dynamic import: the wiring
|
|
17
|
+
* module statically imports the designer-owned UI modules, which import the
|
|
18
|
+
* optional UI peers (`@opentui/solid`, `solid-js`). Non-Windows plugin setup
|
|
19
|
+
* therefore never evaluates them, and no OpenTUI dependency is added to the
|
|
20
|
+
* package surface.
|
|
21
|
+
*
|
|
22
|
+
* Command handlers own their errors and report sanitized copy; no raw host
|
|
23
|
+
* error crosses to the host. The active Windows experimental defaults are
|
|
24
|
+
* recorded in `docs/v1/decision-log.md`; this is not a production approval or
|
|
25
|
+
* format freeze.
|
|
26
|
+
*/
|
|
27
|
+
export default Plugin.define({
|
|
28
|
+
id: "sessionport",
|
|
29
|
+
async setup(context) {
|
|
30
|
+
if (process.platform !== "win32") return undefined
|
|
31
|
+
const { installSessionPortWiring } = await import("./tui/wiring/index.ts")
|
|
32
|
+
return installSessionPortWiring(context)
|
|
33
|
+
},
|
|
34
|
+
})
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"module": "Preserve",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ESNext", "DOM"],
|
|
7
|
+
"jsx": "preserve",
|
|
8
|
+
"jsxImportSource": "@opentui/solid",
|
|
9
|
+
"types": [],
|
|
10
|
+
"strict": true,
|
|
11
|
+
"noEmit": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"verbatimModuleSyntax": true,
|
|
15
|
+
"allowImportingTsExtensions": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src"]
|
|
18
|
+
}
|
package/tui.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionPort TUI entrypoint shim for the host's directory-based plugin
|
|
3
|
+
* resolution (`Host.resolve` probes `<directory>/tui` by path, before any
|
|
4
|
+
* package `exports` lookup). It re-exports the product entrypoint unchanged;
|
|
5
|
+
* all behavior (Windows platform gate, pinned-sodium initialization, deferred
|
|
6
|
+
* `./tui/wiring/index.ts` import) stays in `src/tui.ts`.
|
|
7
|
+
*
|
|
8
|
+
* This file is part of the packaged `files` allowlist so an installed copy of
|
|
9
|
+
* the package resolves under the pinned Host.resolve convention. It adds no
|
|
10
|
+
* registration, host access, or activation of its own.
|
|
11
|
+
*
|
|
12
|
+
* The re-export targets the compiled bundle `dist/tui.js`, not the TSX source:
|
|
13
|
+
* the directory loader probes `<directory>/tui` by path and would otherwise
|
|
14
|
+
* bypass the `exports["./tui"]` bundle entirely. `dist/tui.js` is produced by
|
|
15
|
+
* `build:tui` (wired as `prepack`) from `src/tui.ts`.
|
|
16
|
+
*/
|
|
17
|
+
export { default } from "./dist/tui.js"
|