@rose42/t3-feedback 0.1.0 → 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.
- package/README.md +65 -50
- package/dist/bridge/http.d.ts +7 -2
- package/dist/bridge/http.js +41 -1
- package/dist/bridge/index.d.ts +5 -3
- package/dist/bridge/index.js +4 -2
- package/dist/bridge/launchEditor.d.ts +21 -0
- package/dist/bridge/launchEditor.js +139 -0
- package/dist/bridge/paths.d.ts +2 -0
- package/dist/bridge/paths.js +2 -0
- package/dist/bridge/readSource.js +2 -0
- package/dist/bridge/sendFeedback.d.ts +17 -1
- package/dist/bridge/sendFeedback.js +23 -6
- package/dist/cli/bin.js +0 -0
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/mount.js +50 -12
- package/dist/client/ui/backdropAway.d.ts +2 -0
- package/dist/client/ui/backdropAway.js +12 -0
- package/dist/client/ui/elementTargetChip.d.ts +13 -4
- package/dist/client/ui/elementTargetChip.js +21 -7
- package/dist/client/ui/elementTargetPanelSession.js +6 -4
- package/dist/client/ui/screenshotPanelSession.js +36 -28
- package/dist/client/ui/sourcePathPrefix.d.ts +12 -0
- package/dist/client/ui/sourcePathPrefix.js +39 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/plugin.d.ts +6 -1
- package/dist/plugin.js +71 -4
- package/dist/types.d.ts +49 -3
- package/dist/types.js +47 -0
- package/docs/devcontainer.md +2 -0
- package/docs/release.md +47 -0
- package/package.json +22 -21
package/dist/types.d.ts
CHANGED
|
@@ -227,14 +227,23 @@ export type T3FeedbackPickOptions = {
|
|
|
227
227
|
* When a picked element resolves to a component file, make the path in the
|
|
228
228
|
* ELEMENT chip clickable to open it in the IDE.
|
|
229
229
|
*
|
|
230
|
-
* - omit / `true` — GET
|
|
231
|
-
*
|
|
230
|
+
* - omit / `true` — GET `{api}/open-editor?file=path:line:column` (bridge;
|
|
231
|
+
* launches Cursor/VS Code remote CLI). Falls back from Vite’s
|
|
232
|
+
* `/__open-in-editor` so preview proxies share the feedback origin.
|
|
232
233
|
* - `false` — plain text path, no open action
|
|
233
|
-
* - `{ endpoint }` —
|
|
234
|
+
* - `{ endpoint }` — custom GET path (still `?file=`)
|
|
234
235
|
* - `{ urlTemplate }` — navigate to a URL with `{file}`, `{line}`, `{column}`
|
|
235
236
|
* (e.g. `vscode://file/{file}:{line}:{column}`); wins over `endpoint`
|
|
236
237
|
*/
|
|
237
238
|
openInEditor?: boolean | T3FeedbackOpenInEditorOptions;
|
|
239
|
+
/**
|
|
240
|
+
* Prefix resolved component paths so they are workspace-relative
|
|
241
|
+
* (e.g. `examples/vite-react` → `examples/vite-react/src/App.tsx`).
|
|
242
|
+
* Use when the Vite/Next app cwd is a subfolder of the T3 / IDE workspace.
|
|
243
|
+
* The Vite plugin also derives this automatically when `workspaceRootHints`
|
|
244
|
+
* points at an ancestor of the Vite root.
|
|
245
|
+
*/
|
|
246
|
+
sourcePathPrefix?: string;
|
|
238
247
|
};
|
|
239
248
|
/** Custom open-in-editor behavior when not using the Vite default endpoint alone. */
|
|
240
249
|
export type T3FeedbackOpenInEditorOptions = {
|
|
@@ -297,9 +306,20 @@ export type T3FeedbackPickConfig = {
|
|
|
297
306
|
sourceFramework: "react" | "next" | "vue" | "svelte" | "qwik" | "locator" | "auto" | "none";
|
|
298
307
|
/** `null` when open-in-editor is disabled. */
|
|
299
308
|
openInEditor: T3FeedbackOpenInEditorConfig | null;
|
|
309
|
+
/**
|
|
310
|
+
* Workspace-relative prefix for resolved source paths (`undefined` when unset).
|
|
311
|
+
* See {@link T3FeedbackPickOptions.sourcePathPrefix}.
|
|
312
|
+
*/
|
|
313
|
+
sourcePathPrefix?: string;
|
|
300
314
|
};
|
|
301
315
|
/** Default Vite DEV endpoint for opening a file in the editor. */
|
|
302
316
|
export declare const DEFAULT_OPEN_IN_EDITOR_ENDPOINT = "/__open-in-editor";
|
|
317
|
+
/**
|
|
318
|
+
* Prefer the bridge `/open-editor` route (same origin as feedback posts) over
|
|
319
|
+
* Vite's `/__open-in-editor` so preview proxies and Cursor remote CLIs work.
|
|
320
|
+
* Explicit custom endpoints / urlTemplates are left alone.
|
|
321
|
+
*/
|
|
322
|
+
export declare function resolveOpenInEditorEndpointForApi(openInEditor: T3FeedbackOpenInEditorConfig | null, apiEndpoint: string): T3FeedbackOpenInEditorConfig | null;
|
|
303
323
|
/** Resolved screenshot options embedded in the client config. */
|
|
304
324
|
export type T3FeedbackScreenshotConfig = {
|
|
305
325
|
/** `null` when capture shortcut is disabled. */
|
|
@@ -315,6 +335,8 @@ export type T3FeedbackRecordConfig = {
|
|
|
315
335
|
};
|
|
316
336
|
export declare function resolveOpenInEditorConfig(value?: boolean | T3FeedbackOpenInEditorOptions): T3FeedbackOpenInEditorConfig | null;
|
|
317
337
|
export declare function resolvePickConfig(pick?: T3FeedbackPickOptions): T3FeedbackPickConfig;
|
|
338
|
+
/** Trim / slash-normalize a pick `sourcePathPrefix` (empty → undefined). */
|
|
339
|
+
export declare function normalizePickSourcePathPrefix(prefix?: string | null): string | undefined;
|
|
318
340
|
export declare function resolveScreenshotConfig(screenshot?: T3FeedbackScreenshotOptions, pickCropPaddingPx?: number): T3FeedbackScreenshotConfig;
|
|
319
341
|
export declare function resolveRecordConfig(record?: T3FeedbackRecordOptions): T3FeedbackRecordConfig;
|
|
320
342
|
/**
|
|
@@ -366,6 +388,21 @@ export type T3FeedbackBuiltinPluginOptions = {
|
|
|
366
388
|
export declare function resolveActivePlugins(active?: readonly T3BuiltinPluginId[], includeConsoleLogs?: boolean): Set<T3BuiltinPluginId>;
|
|
367
389
|
/** Stable ordered list of active built-in ids (for JSON client config). */
|
|
368
390
|
export declare function resolveActivePluginList(active?: readonly T3BuiltinPluginId[], includeConsoleLogs?: boolean): T3BuiltinPluginId[];
|
|
391
|
+
/**
|
|
392
|
+
* Provider + model for newly created T3 threads (`thread.create` `modelSelection`).
|
|
393
|
+
* `instanceId` is the T3 provider instance (e.g. `"cursor"`, `"codex"`).
|
|
394
|
+
*/
|
|
395
|
+
export type T3FeedbackModelSelection = {
|
|
396
|
+
instanceId: string;
|
|
397
|
+
model: string;
|
|
398
|
+
};
|
|
399
|
+
/** Default provider/model when creating threads (Cursor Auto-style default). */
|
|
400
|
+
export declare const DEFAULT_MODEL_SELECTION: T3FeedbackModelSelection;
|
|
401
|
+
/**
|
|
402
|
+
* Normalize a configured / env / inherited model selection.
|
|
403
|
+
* Returns `undefined` when both fields are empty after trim.
|
|
404
|
+
*/
|
|
405
|
+
export declare function normalizeModelSelection(value: Partial<T3FeedbackModelSelection> | null | undefined): T3FeedbackModelSelection | undefined;
|
|
369
406
|
/** Options for `t3FeedbackPlugin` (Node / Vite config). */
|
|
370
407
|
export type T3FeedbackPluginOptions = {
|
|
371
408
|
/** T3 HTTP origin. Default: http://localhost:3773 (override via T3_FEEDBACK_ORIGIN). */
|
|
@@ -377,6 +414,15 @@ export type T3FeedbackPluginOptions = {
|
|
|
377
414
|
* an in-container hostname). Do **not** point this at another container's T3.
|
|
378
415
|
*/
|
|
379
416
|
openOrigin?: string;
|
|
417
|
+
/**
|
|
418
|
+
* Provider/model for **new** feedback threads.
|
|
419
|
+
* Default: `{ instanceId: "cursor", model: "default" }`.
|
|
420
|
+
* When omitted, the bridge prefers an existing project thread that already
|
|
421
|
+
* uses the same `instanceId` (so Cursor Auto settings are reused) instead of
|
|
422
|
+
* copying the first thread (which may be a disabled provider like Codex).
|
|
423
|
+
* Overridable via `T3_FEEDBACK_INSTANCE_ID` / `T3_FEEDBACK_MODEL`.
|
|
424
|
+
*/
|
|
425
|
+
modelSelection?: T3FeedbackModelSelection;
|
|
380
426
|
/**
|
|
381
427
|
* Optional prefix for newly created thread titles
|
|
382
428
|
* (e.g. `"Checkout"` → `"Checkout: /pay · broken CTA"`).
|
package/dist/types.js
CHANGED
|
@@ -73,6 +73,23 @@ export const DEFAULT_RECORD_SHORTCUT = {
|
|
|
73
73
|
};
|
|
74
74
|
/** Default Vite DEV endpoint for opening a file in the editor. */
|
|
75
75
|
export const DEFAULT_OPEN_IN_EDITOR_ENDPOINT = "/__open-in-editor";
|
|
76
|
+
/**
|
|
77
|
+
* Prefer the bridge `/open-editor` route (same origin as feedback posts) over
|
|
78
|
+
* Vite's `/__open-in-editor` so preview proxies and Cursor remote CLIs work.
|
|
79
|
+
* Explicit custom endpoints / urlTemplates are left alone.
|
|
80
|
+
*/
|
|
81
|
+
export function resolveOpenInEditorEndpointForApi(openInEditor, apiEndpoint) {
|
|
82
|
+
if (!openInEditor)
|
|
83
|
+
return null;
|
|
84
|
+
if (openInEditor.urlTemplate)
|
|
85
|
+
return openInEditor;
|
|
86
|
+
const pathOnly = openInEditor.endpoint.split("?")[0] ?? openInEditor.endpoint;
|
|
87
|
+
if (pathOnly !== DEFAULT_OPEN_IN_EDITOR_ENDPOINT && !pathOnly.endsWith("/__open-in-editor")) {
|
|
88
|
+
return openInEditor;
|
|
89
|
+
}
|
|
90
|
+
const base = apiEndpoint.replace(/\/$/, "") || "/__t3-feedback";
|
|
91
|
+
return { endpoint: `${base}/open-editor` };
|
|
92
|
+
}
|
|
76
93
|
export function resolveOpenInEditorConfig(value) {
|
|
77
94
|
if (value === false)
|
|
78
95
|
return null;
|
|
@@ -103,6 +120,7 @@ export function resolvePickConfig(pick) {
|
|
|
103
120
|
pick?.sourceFramework === "auto"
|
|
104
121
|
? pick.sourceFramework
|
|
105
122
|
: "auto";
|
|
123
|
+
const sourcePathPrefix = normalizePickSourcePathPrefix(pick?.sourcePathPrefix);
|
|
106
124
|
return {
|
|
107
125
|
shortcut,
|
|
108
126
|
afterPick: pick?.afterPick ?? "crop",
|
|
@@ -112,8 +130,16 @@ export function resolvePickConfig(pick) {
|
|
|
112
130
|
styles: pick?.styles ?? "none",
|
|
113
131
|
sourceFramework,
|
|
114
132
|
openInEditor: resolveOpenInEditorConfig(pick?.openInEditor),
|
|
133
|
+
...(sourcePathPrefix ? { sourcePathPrefix } : {}),
|
|
115
134
|
};
|
|
116
135
|
}
|
|
136
|
+
/** Trim / slash-normalize a pick `sourcePathPrefix` (empty → undefined). */
|
|
137
|
+
export function normalizePickSourcePathPrefix(prefix) {
|
|
138
|
+
if (typeof prefix !== "string")
|
|
139
|
+
return undefined;
|
|
140
|
+
const cleaned = prefix.trim().replace(/\\/g, "/").replace(/^\/+/, "").replace(/\/+$/, "");
|
|
141
|
+
return cleaned || undefined;
|
|
142
|
+
}
|
|
117
143
|
export function resolveScreenshotConfig(screenshot, pickCropPaddingPx = 12) {
|
|
118
144
|
const shortcut = screenshot?.shortcut === false
|
|
119
145
|
? null
|
|
@@ -281,3 +307,24 @@ export function resolveActivePluginList(active, includeConsoleLogs) {
|
|
|
281
307
|
const set = resolveActivePlugins(active, includeConsoleLogs);
|
|
282
308
|
return T3_BUILTIN_PLUGIN_IDS.filter((id) => set.has(id));
|
|
283
309
|
}
|
|
310
|
+
/** Default provider/model when creating threads (Cursor Auto-style default). */
|
|
311
|
+
export const DEFAULT_MODEL_SELECTION = {
|
|
312
|
+
instanceId: "cursor",
|
|
313
|
+
model: "default",
|
|
314
|
+
};
|
|
315
|
+
/**
|
|
316
|
+
* Normalize a configured / env / inherited model selection.
|
|
317
|
+
* Returns `undefined` when both fields are empty after trim.
|
|
318
|
+
*/
|
|
319
|
+
export function normalizeModelSelection(value) {
|
|
320
|
+
if (!value)
|
|
321
|
+
return undefined;
|
|
322
|
+
const instanceId = typeof value.instanceId === "string" ? value.instanceId.trim() : "";
|
|
323
|
+
const model = typeof value.model === "string" ? value.model.trim() : "";
|
|
324
|
+
if (!instanceId && !model)
|
|
325
|
+
return undefined;
|
|
326
|
+
return {
|
|
327
|
+
instanceId: instanceId || DEFAULT_MODEL_SELECTION.instanceId,
|
|
328
|
+
model: model || DEFAULT_MODEL_SELECTION.model,
|
|
329
|
+
};
|
|
330
|
+
}
|
package/docs/devcontainer.md
CHANGED
|
@@ -77,6 +77,8 @@ t3 --no-browser --port "${T3CODE_PORT:-3775}"
|
|
|
77
77
|
|
|
78
78
|
Keep this project’s port unique vs other concurrent containers (`3773`, `3774`, …). Same host port ⇒ same browser origin ⇒ sessions kick each other off (`Invalid session token signature`).
|
|
79
79
|
|
|
80
|
+
Demo app ports are also forwarded from this same container (`5173`–`5176`, `3000`, `8787`) — see [examples/README.md](../examples/README.md).
|
|
81
|
+
|
|
80
82
|
`T3_FEEDBACK_ORIGIN` / `T3_FEEDBACK_OPEN_ORIGIN` follow the same `T3CODE_PORT` default so the plugin bridges to this instance. Consumer projects must set both to **their** T3 port — not this plugin container's — or Open links will embed this environment's id/label.
|
|
81
83
|
|
|
82
84
|
### Override on conflict
|
package/docs/release.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Release
|
|
2
|
+
|
|
3
|
+
Releases are driven by **version tags** (`vX.Y.Z`). Pushing a tag runs CI:
|
|
4
|
+
|
|
5
|
+
**verify** → **GitLab Release** (dist tarball in the package registry) → **npm publish** via OIDC trusted publishing.
|
|
6
|
+
|
|
7
|
+
CI uses the `node:24` image (npm ≥ 11.5.1). Publish must run on **GitLab.com shared runners** — self-hosted runners are not supported for npm OIDC.
|
|
8
|
+
|
|
9
|
+
## One-time npm trusted publisher setup
|
|
10
|
+
|
|
11
|
+
1. Create or join the **`rose42`** org on [npmjs.com](https://www.npmjs.com) with permission to publish `@rose42/*`.
|
|
12
|
+
2. On the package page for [`@rose42/t3-feedback`](https://www.npmjs.com/package/@rose42/t3-feedback): **Settings → Trusted Publishing → GitLab CI/CD**. Configure (values are case-sensitive):
|
|
13
|
+
- **Namespace**: `rose42`
|
|
14
|
+
- **Project name**: `t3-feedback`
|
|
15
|
+
- **Top-level CI file path**: `.gitlab-ci.yml`
|
|
16
|
+
- **Environment name**: leave empty (this pipeline does not use GitLab environments)
|
|
17
|
+
- **Allowed actions**: at least `npm publish`
|
|
18
|
+
3. Do **not** add an `NPM_TOKEN` CI variable or write `_authToken` into `.npmrc` for publish. The `publish` job requests `NPM_ID_TOKEN` (audience `npm:registry.npmjs.org`); the npm CLI exchanges that OIDC token for a short-lived publish credential. A fallback token overrides OIDC and breaks the flow.
|
|
19
|
+
4. Optional local check: `pnpm login` then `pnpm publish --dry-run --access public`.
|
|
20
|
+
|
|
21
|
+
### After the first successful tag publish
|
|
22
|
+
|
|
23
|
+
1. In GitLab: **Settings → CI/CD → Variables** — remove `NPM_TOKEN` if it still exists (or stop using it).
|
|
24
|
+
2. Optionally on npm → package **Settings → Publishing access**: require 2FA and disallow tokens.
|
|
25
|
+
|
|
26
|
+
## Cut a release
|
|
27
|
+
|
|
28
|
+
Requires a clean git worktree. Bumps `package.json`, commits, tags `vX.Y.Z`, and pushes (with `--follow-tags`) so the tag pipeline runs.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pnpm release -- 0.1.0 # first release (exact version)
|
|
32
|
+
# later:
|
|
33
|
+
pnpm release -- patch # or: minor | major
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
After the pipeline succeeds:
|
|
37
|
+
|
|
38
|
+
- npm: [`@rose42/t3-feedback`](https://www.npmjs.com/package/@rose42/t3-feedback)
|
|
39
|
+
- GitLab: **Deploy → Releases** (asset links to the generic package tarball)
|
|
40
|
+
|
|
41
|
+
## CI publish job (OIDC)
|
|
42
|
+
|
|
43
|
+
The `publish` job in [`.gitlab-ci.yml`](../.gitlab-ci.yml):
|
|
44
|
+
|
|
45
|
+
- Requests `NPM_ID_TOKEN` with `aud: "npm:registry.npmjs.org"`
|
|
46
|
+
- Optionally requests `SIGSTORE_ID_TOKEN` with `aud: sigstore` for provenance
|
|
47
|
+
- Runs `pnpm publish --access public --no-git-checks` with **no** `~/.npmrc` `_authToken`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rose42/t3-feedback",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "DEV-only: capture app feedback and send it to a T3 Code thread (unofficial community tool)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -58,29 +58,11 @@
|
|
|
58
58
|
"docs",
|
|
59
59
|
"!dist/**/*.map"
|
|
60
60
|
],
|
|
61
|
-
"scripts": {
|
|
62
|
-
"dev": "tsc -p tsconfig.build.json --watch",
|
|
63
|
-
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
64
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
65
|
-
"lint": "eslint .",
|
|
66
|
-
"format": "prettier --write .",
|
|
67
|
-
"format:check": "prettier --check .",
|
|
68
|
-
"test": "vitest run",
|
|
69
|
-
"test:watch": "vitest",
|
|
70
|
-
"release": "bash scripts/release.sh",
|
|
71
|
-
"prepublishOnly": "pnpm typecheck && pnpm lint && pnpm test && pnpm build"
|
|
72
|
-
},
|
|
73
61
|
"engines": {
|
|
74
62
|
"node": ">=24"
|
|
75
63
|
},
|
|
76
|
-
"packageManager": "pnpm@10.21.0",
|
|
77
|
-
"pnpm": {
|
|
78
|
-
"onlyBuiltDependencies": [
|
|
79
|
-
"esbuild"
|
|
80
|
-
]
|
|
81
|
-
},
|
|
82
64
|
"dependencies": {
|
|
83
|
-
"@rose42/feedback-capture": "0.1.
|
|
65
|
+
"@rose42/feedback-capture": "~0.1.1",
|
|
84
66
|
"ws": "^8.18.3"
|
|
85
67
|
},
|
|
86
68
|
"peerDependencies": {
|
|
@@ -103,5 +85,24 @@
|
|
|
103
85
|
"typescript-eslint": "^8.46.4",
|
|
104
86
|
"vite": "^7.0.0",
|
|
105
87
|
"vitest": "^3.2.7"
|
|
88
|
+
},
|
|
89
|
+
"scripts": {
|
|
90
|
+
"dev": "tsc -p tsconfig.build.json --watch",
|
|
91
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
92
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
93
|
+
"lint": "eslint .",
|
|
94
|
+
"format": "prettier --write .",
|
|
95
|
+
"format:check": "prettier --check .",
|
|
96
|
+
"test": "vitest run",
|
|
97
|
+
"test:watch": "vitest",
|
|
98
|
+
"release": "bash scripts/release.sh",
|
|
99
|
+
"examples:install": "bash scripts/examples-install.sh",
|
|
100
|
+
"examples:all": "bash scripts/examples-all.sh",
|
|
101
|
+
"examples:vite-react": "pnpm --dir examples/vite-react dev",
|
|
102
|
+
"examples:vite-vue": "pnpm --dir examples/vite-vue dev",
|
|
103
|
+
"examples:vite-svelte": "pnpm --dir examples/vite-svelte dev",
|
|
104
|
+
"examples:vite-qwik": "pnpm --dir examples/vite-qwik dev",
|
|
105
|
+
"examples:next": "pnpm --dir examples/next-app dev",
|
|
106
|
+
"examples:node": "pnpm --dir examples/node-bridge dev"
|
|
106
107
|
}
|
|
107
|
-
}
|
|
108
|
+
}
|