@tmux-web/ext-git-workflow 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/backend/git.js +214 -0
  2. package/dist/backend/pane-ready.js +37 -0
  3. package/dist/backend/routes/commit-push.js +46 -0
  4. package/dist/backend/routes/handoff.js +85 -0
  5. package/dist/backend/routes/send-keys.js +31 -0
  6. package/dist/backend/routes/status.js +10 -0
  7. package/dist/backend/server.js +25 -0
  8. package/dist/backend/status-service.js +110 -0
  9. package/dist/backend/storage.js +32 -0
  10. package/dist/backend/tmux.js +58 -0
  11. package/dist/ui/app.js +425 -0
  12. package/dist/ui/index.html +334 -0
  13. package/node_modules/@tmux-web/ext-gh-workflow/dist/gh-client.d.ts +24 -0
  14. package/node_modules/@tmux-web/ext-gh-workflow/dist/gh-client.js +177 -0
  15. package/node_modules/@tmux-web/ext-gh-workflow/dist/gh-pr.d.ts +20 -0
  16. package/node_modules/@tmux-web/ext-gh-workflow/dist/gh-pr.js +43 -0
  17. package/node_modules/@tmux-web/ext-gh-workflow/dist/gh-repo.d.ts +14 -0
  18. package/node_modules/@tmux-web/ext-gh-workflow/dist/gh-repo.js +58 -0
  19. package/node_modules/@tmux-web/ext-gh-workflow/dist/index.d.ts +3 -0
  20. package/node_modules/@tmux-web/ext-gh-workflow/dist/index.js +3 -0
  21. package/node_modules/@tmux-web/ext-gh-workflow/package.json +38 -0
  22. package/node_modules/@tmux-web/ext-sdk/dist/bridge.d.ts +31 -0
  23. package/node_modules/@tmux-web/ext-sdk/dist/bridge.js +103 -0
  24. package/node_modules/@tmux-web/ext-sdk/dist/index.d.ts +7 -0
  25. package/node_modules/@tmux-web/ext-sdk/dist/index.js +12 -0
  26. package/node_modules/@tmux-web/ext-sdk/dist/types.d.ts +20 -0
  27. package/node_modules/@tmux-web/ext-sdk/dist/types.js +1 -0
  28. package/node_modules/@tmux-web/ext-sdk/package.json +32 -0
  29. package/package.json +43 -0
  30. package/tmux-extension.json +13 -0
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@tmux-web/ext-gh-workflow",
3
+ "version": "0.1.0",
4
+ "description": "Shared GitHub CLI helpers for tmux-web extensions",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/ashutoshpw/tmux-web",
10
+ "directory": "packages/ext-gh-workflow"
11
+ },
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist/"
25
+ ],
26
+ "scripts": {
27
+ "build": "tsc -p tsconfig.json",
28
+ "test": "vitest run"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^25.8.0",
32
+ "typescript": "^5.7.0",
33
+ "vitest": "^2.1.9"
34
+ },
35
+ "overrides": {
36
+ "esbuild": "0.24.2"
37
+ }
38
+ }
@@ -0,0 +1,31 @@
1
+ import type { ExtContext } from './types.js';
2
+ type ContextCallback = (ctx: ExtContext) => void;
3
+ type ConfigCallback = (cfg: unknown) => void | Promise<void>;
4
+ type VoidCallback = () => void | Promise<void>;
5
+ export declare class ExtBridge {
6
+ private readonly extId;
7
+ private contextCb;
8
+ private configCb;
9
+ private openCb;
10
+ private closeCb;
11
+ private _config;
12
+ private pendingContext;
13
+ private pendingConfig;
14
+ private pendingOpen;
15
+ private pendingClose;
16
+ constructor();
17
+ /** Call after all `on*` handlers are registered so early host messages are not lost. */
18
+ ready(): void;
19
+ private _onMessage;
20
+ onContext(cb: ContextCallback): void;
21
+ onConfig(cb: ConfigCallback): void;
22
+ onOpen(cb: VoidCallback): void;
23
+ onClose(cb: VoidCallback): void;
24
+ getConfig(): unknown;
25
+ request<T = unknown>(path: string, options?: {
26
+ method?: string;
27
+ body?: unknown;
28
+ }): Promise<T>;
29
+ resize(height: number): void;
30
+ }
31
+ export {};
@@ -0,0 +1,103 @@
1
+ export class ExtBridge {
2
+ extId;
3
+ contextCb = null;
4
+ configCb = null;
5
+ openCb = null;
6
+ closeCb = null;
7
+ _config = null;
8
+ pendingContext = null;
9
+ pendingConfig = null;
10
+ pendingOpen = false;
11
+ pendingClose = false;
12
+ constructor() {
13
+ const m = window.location.pathname.match(/^\/ext\/([^/]+)\//);
14
+ if (!m)
15
+ throw new Error('[ext-sdk] cannot detect extension id from iframe URL');
16
+ this.extId = m[1];
17
+ window.addEventListener('message', this._onMessage.bind(this));
18
+ }
19
+ /** Call after all `on*` handlers are registered so early host messages are not lost. */
20
+ ready() {
21
+ window.parent.postMessage({ type: 'ext:ready' }, '*');
22
+ }
23
+ _onMessage(event) {
24
+ const msg = event.data;
25
+ if (!msg?.type)
26
+ return;
27
+ if (msg.type === 'ext:context') {
28
+ if (this.contextCb)
29
+ this.contextCb(msg.context);
30
+ else
31
+ this.pendingContext = msg.context;
32
+ }
33
+ else if (msg.type === 'ext:config') {
34
+ this._config = msg.config;
35
+ if (this.configCb)
36
+ this.configCb(msg.config);
37
+ else
38
+ this.pendingConfig = msg.config;
39
+ }
40
+ else if (msg.type === 'ext:open') {
41
+ if (this.openCb)
42
+ void this.openCb();
43
+ else
44
+ this.pendingOpen = true;
45
+ }
46
+ else if (msg.type === 'ext:close') {
47
+ if (this.closeCb)
48
+ void this.closeCb();
49
+ else
50
+ this.pendingClose = true;
51
+ }
52
+ }
53
+ onContext(cb) {
54
+ this.contextCb = cb;
55
+ if (this.pendingContext) {
56
+ cb(this.pendingContext);
57
+ this.pendingContext = null;
58
+ }
59
+ }
60
+ onConfig(cb) {
61
+ this.configCb = cb;
62
+ if (this.pendingConfig !== null) {
63
+ this._config = this.pendingConfig;
64
+ void cb(this.pendingConfig);
65
+ this.pendingConfig = null;
66
+ }
67
+ }
68
+ onOpen(cb) {
69
+ this.openCb = cb;
70
+ if (this.pendingOpen) {
71
+ this.pendingOpen = false;
72
+ void cb();
73
+ }
74
+ }
75
+ onClose(cb) {
76
+ this.closeCb = cb;
77
+ if (this.pendingClose) {
78
+ this.pendingClose = false;
79
+ void cb();
80
+ }
81
+ }
82
+ getConfig() {
83
+ return this._config;
84
+ }
85
+ async request(path, options) {
86
+ const url = `/ext/${this.extId}/api${path}`;
87
+ const init = { method: options?.method ?? 'GET' };
88
+ if (options?.body !== undefined) {
89
+ init.body = JSON.stringify(options.body);
90
+ init.headers = { 'Content-Type': 'application/json' };
91
+ }
92
+ const res = await fetch(url, init);
93
+ if (!res.ok) {
94
+ const text = await res.text().catch(() => res.statusText);
95
+ throw new Error(`[ext-sdk] ${url} → ${res.status}: ${text}`);
96
+ }
97
+ return res.json();
98
+ }
99
+ resize(height) {
100
+ const msg = { type: 'ext:resize', height };
101
+ window.parent.postMessage(msg, '*');
102
+ }
103
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @tmux-web/ext-sdk — extension SDK for tmux-web.
3
+ */
4
+ import { ExtBridge } from './bridge.js';
5
+ export type { ExtContext, ExtMessage } from './types.js';
6
+ export { ExtBridge };
7
+ export declare function createExtension(): ExtBridge;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @tmux-web/ext-sdk — extension SDK for tmux-web.
3
+ */
4
+ import { ExtBridge } from './bridge.js';
5
+ export { ExtBridge };
6
+ let _bridge = null;
7
+ export function createExtension() {
8
+ if (_bridge)
9
+ throw new Error('[ext-sdk] createExtension() called more than once');
10
+ _bridge = new ExtBridge();
11
+ return _bridge;
12
+ }
@@ -0,0 +1,20 @@
1
+ export interface ExtContext {
2
+ session: string;
3
+ host: string;
4
+ }
5
+ export type ExtMessage = {
6
+ type: 'ext:context';
7
+ context: ExtContext;
8
+ } | {
9
+ type: 'ext:config';
10
+ config: unknown;
11
+ } | {
12
+ type: 'ext:ready';
13
+ } | {
14
+ type: 'ext:open';
15
+ } | {
16
+ type: 'ext:close';
17
+ } | {
18
+ type: 'ext:resize';
19
+ height: number;
20
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@tmux-web/ext-sdk",
3
+ "version": "0.1.0",
4
+ "description": "Iframe SDK for tmux-web sidebar extensions",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/ashutoshpw/tmux-web",
10
+ "directory": "packages/ext-sdk"
11
+ },
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist/"
25
+ ],
26
+ "scripts": {
27
+ "build": "tsc -p tsconfig.json"
28
+ },
29
+ "devDependencies": {
30
+ "typescript": "^5.7.0"
31
+ }
32
+ }
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@tmux-web/ext-git-workflow",
3
+ "version": "0.1.0",
4
+ "description": "Git workflow sidebar extension for tmux-web",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/ashutoshpw/tmux-web",
10
+ "directory": "extensions/git-workflow"
11
+ },
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "files": [
16
+ "dist/",
17
+ "tmux-extension.json"
18
+ ],
19
+ "scripts": {
20
+ "build:backend": "tsc -p tsconfig.json",
21
+ "build:ui": "mkdir -p dist/ui && esbuild ui/app.ts --bundle --outfile=dist/ui/app.js --platform=browser --target=es2020 --alias:@tmux-web/ext-sdk=../../packages/ext-sdk/src/index.ts && cp ui/index.html dist/ui/index.html",
22
+ "build": "npm run build:backend && npm run build:ui",
23
+ "start": "node dist/backend/server.js"
24
+ },
25
+ "dependencies": {
26
+ "@hono/node-server": "^1.19.0",
27
+ "@tmux-web/ext-gh-workflow": "file:../../packages/ext-gh-workflow",
28
+ "@tmux-web/ext-sdk": "file:../../packages/ext-sdk",
29
+ "hono": "^4.7.0"
30
+ },
31
+ "bundledDependencies": [
32
+ "@tmux-web/ext-gh-workflow",
33
+ "@tmux-web/ext-sdk"
34
+ ],
35
+ "devDependencies": {
36
+ "@types/node": "^25.8.0",
37
+ "esbuild": "0.24.2",
38
+ "typescript": "^5.7.0"
39
+ },
40
+ "overrides": {
41
+ "esbuild": "0.24.2"
42
+ }
43
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "Git Workflow",
3
+ "icon": "⎇",
4
+ "slot": "sidebar",
5
+ "permissions": [],
6
+ "views": [
7
+ { "entry": "index.html" }
8
+ ],
9
+ "start": "node dist/backend/server.js",
10
+ "config": {
11
+ "pollIntervalMs": 10000
12
+ }
13
+ }