pinpatch 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.
- package/LICENSE +21 -0
- package/README.md +70 -0
- package/bin/pinpatch.mjs +2 -0
- package/dist/index.cjs +379 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +363 -0
- package/dist/index.js.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pinpatch
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# pinpatch
|
|
2
|
+
|
|
3
|
+
Pinpatch lets you place pins on a running local app, generate implementation tasks, and execute them through supported providers (`codex` or `claude`).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
Global install:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g pinpatch
|
|
11
|
+
pinpatch --help
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Run without global install:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx pinpatch@latest --help
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Prerequisites
|
|
21
|
+
|
|
22
|
+
- Node.js `>=18`
|
|
23
|
+
- A local web app running on `localhost` (default target port `3000`)
|
|
24
|
+
- For Codex execution: `codex` CLI installed and authenticated
|
|
25
|
+
- For Claude execution: `claude` CLI installed and authenticated
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
1. Start your local app (example on `3000`).
|
|
30
|
+
2. Start Pinpatch:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pinpatch dev --target 3000
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
3. Open the proxied app at `http://localhost:3030`.
|
|
37
|
+
4. Press `c` to enter pin mode, click an element, and submit a request.
|
|
38
|
+
|
|
39
|
+
## Commands
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pinpatch --help
|
|
43
|
+
pinpatch dev --target 3000
|
|
44
|
+
pinpatch implement <taskId>
|
|
45
|
+
pinpatch tasks
|
|
46
|
+
pinpatch tasks --prune
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Runtime Artifacts
|
|
50
|
+
|
|
51
|
+
Pinpatch writes runtime files to:
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
.pinpatch/
|
|
55
|
+
config.json
|
|
56
|
+
tasks/
|
|
57
|
+
sessions/
|
|
58
|
+
screenshots/
|
|
59
|
+
runtime/logs/
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Troubleshooting
|
|
63
|
+
|
|
64
|
+
- `Target localhost:<port> is unreachable`: start your app first.
|
|
65
|
+
- `Bridge port ... is already in use` / `Proxy port ... is already in use`: choose different ports.
|
|
66
|
+
- Provider process errors: verify `codex`/`claude` CLI authentication and PATH setup.
|
|
67
|
+
|
|
68
|
+
## Monorepo Source
|
|
69
|
+
|
|
70
|
+
For contributor workflows and e2e testing, see the repository root docs in `README.md` and `CONTRIBUTING.md`.
|
package/bin/pinpatch.mjs
ADDED
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
|
|
25
|
+
// src/index.ts
|
|
26
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
27
|
+
var import_node_fs = require("fs");
|
|
28
|
+
var import_node_http = __toESM(require("http"), 1);
|
|
29
|
+
var import_node_child_process = require("child_process");
|
|
30
|
+
var import_commander = require("commander");
|
|
31
|
+
var import_core = require("@pinpatch/core");
|
|
32
|
+
var import_providers = require("@pinpatch/providers");
|
|
33
|
+
var import_proxy = require("@pinpatch/proxy");
|
|
34
|
+
var cliEntrypointDir = process.argv[1] ? import_node_path.default.dirname(import_node_path.default.resolve(process.argv[1])) : process.cwd();
|
|
35
|
+
var packageRootFromCli = ["bin", "dist", "src"].includes(
|
|
36
|
+
import_node_path.default.basename(cliEntrypointDir)
|
|
37
|
+
) ? import_node_path.default.resolve(cliEntrypointDir, "..") : cliEntrypointDir;
|
|
38
|
+
var workspaceRootFromCli = import_node_path.default.resolve(packageRootFromCli, "../..");
|
|
39
|
+
var resolveRuntimeCwd = () => {
|
|
40
|
+
const initCwd = process.env.INIT_CWD?.trim();
|
|
41
|
+
if (initCwd) {
|
|
42
|
+
const resolved = import_node_path.default.resolve(initCwd);
|
|
43
|
+
if ((0, import_node_fs.existsSync)(resolved)) {
|
|
44
|
+
return resolved;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const cwd = process.cwd();
|
|
48
|
+
const workspaceRootFromCwd = import_node_path.default.resolve(cwd, "../..");
|
|
49
|
+
const workspaceMarkerFromCwd = import_node_path.default.join(
|
|
50
|
+
workspaceRootFromCwd,
|
|
51
|
+
"pnpm-workspace.yaml"
|
|
52
|
+
);
|
|
53
|
+
const appearsToBeCliPackage = import_node_path.default.basename(cwd) === "cli" && import_node_path.default.basename(import_node_path.default.dirname(cwd)) === "packages";
|
|
54
|
+
if (appearsToBeCliPackage && (0, import_node_fs.existsSync)(workspaceMarkerFromCwd)) {
|
|
55
|
+
return workspaceRootFromCwd;
|
|
56
|
+
}
|
|
57
|
+
const workspaceMarker = import_node_path.default.join(
|
|
58
|
+
workspaceRootFromCli,
|
|
59
|
+
"pnpm-workspace.yaml"
|
|
60
|
+
);
|
|
61
|
+
if (cwd === packageRootFromCli && (0, import_node_fs.existsSync)(workspaceMarker)) {
|
|
62
|
+
return workspaceRootFromCli;
|
|
63
|
+
}
|
|
64
|
+
return cwd;
|
|
65
|
+
};
|
|
66
|
+
var keyboardShortcutsHelp = [
|
|
67
|
+
"Keyboard shortcuts (when using `pinpatch dev` in the proxied app):",
|
|
68
|
+
" c Toggle pin mode",
|
|
69
|
+
" Escape Exit pin mode and close the composer",
|
|
70
|
+
" Cmd+Delete/Backspace Clear all pins (macOS)",
|
|
71
|
+
" Ctrl+Delete/Backspace Clear all pins (Windows/Linux)",
|
|
72
|
+
" Enter Submit from composer/follow-up textarea",
|
|
73
|
+
" Shift+Enter Insert a newline in composer/follow-up textarea"
|
|
74
|
+
].join("\n");
|
|
75
|
+
var waitForSignal = async () => {
|
|
76
|
+
await new Promise((resolve) => {
|
|
77
|
+
const onSignal = () => {
|
|
78
|
+
process.off("SIGINT", onSignal);
|
|
79
|
+
process.off("SIGTERM", onSignal);
|
|
80
|
+
resolve();
|
|
81
|
+
};
|
|
82
|
+
process.on("SIGINT", onSignal);
|
|
83
|
+
process.on("SIGTERM", onSignal);
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
var targetReachable = async (port) => {
|
|
87
|
+
return await new Promise((resolve) => {
|
|
88
|
+
const request = import_node_http.default.get(
|
|
89
|
+
{
|
|
90
|
+
host: "localhost",
|
|
91
|
+
port,
|
|
92
|
+
path: "/",
|
|
93
|
+
timeout: 1500
|
|
94
|
+
},
|
|
95
|
+
() => {
|
|
96
|
+
request.destroy();
|
|
97
|
+
resolve(true);
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
request.on("error", () => resolve(false));
|
|
101
|
+
request.on("timeout", () => {
|
|
102
|
+
request.destroy();
|
|
103
|
+
resolve(false);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
var resolveOverlayBundlePath = (cwd) => {
|
|
108
|
+
const candidates = [
|
|
109
|
+
process.env.PINPATCH_OVERLAY_SCRIPT_PATH,
|
|
110
|
+
import_node_path.default.join(cwd, "apps", "overlay", "dist", "pinpatch-overlay.iife.js"),
|
|
111
|
+
import_node_path.default.join(
|
|
112
|
+
cwd,
|
|
113
|
+
"node_modules",
|
|
114
|
+
"@pinpatch",
|
|
115
|
+
"overlay",
|
|
116
|
+
"dist",
|
|
117
|
+
"pinpatch-overlay.iife.js"
|
|
118
|
+
),
|
|
119
|
+
import_node_path.default.join(
|
|
120
|
+
packageRootFromCli,
|
|
121
|
+
"node_modules",
|
|
122
|
+
"@pinpatch",
|
|
123
|
+
"overlay",
|
|
124
|
+
"dist",
|
|
125
|
+
"pinpatch-overlay.iife.js"
|
|
126
|
+
),
|
|
127
|
+
import_node_path.default.join(
|
|
128
|
+
workspaceRootFromCli,
|
|
129
|
+
"apps",
|
|
130
|
+
"overlay",
|
|
131
|
+
"dist",
|
|
132
|
+
"pinpatch-overlay.iife.js"
|
|
133
|
+
),
|
|
134
|
+
import_node_path.default.join(
|
|
135
|
+
resolveRuntimeCwd(),
|
|
136
|
+
"apps",
|
|
137
|
+
"overlay",
|
|
138
|
+
"dist",
|
|
139
|
+
"pinpatch-overlay.iife.js"
|
|
140
|
+
)
|
|
141
|
+
].filter((value) => Boolean(value));
|
|
142
|
+
for (const candidate of candidates) {
|
|
143
|
+
if ((0, import_node_fs.existsSync)(candidate)) {
|
|
144
|
+
return candidate;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const maybeBuildOverlay = (workspaceRoot) => {
|
|
148
|
+
const overlayWorkspace = import_node_path.default.join(
|
|
149
|
+
workspaceRoot,
|
|
150
|
+
"apps",
|
|
151
|
+
"overlay",
|
|
152
|
+
"package.json"
|
|
153
|
+
);
|
|
154
|
+
if (!(0, import_node_fs.existsSync)(overlayWorkspace)) {
|
|
155
|
+
return void 0;
|
|
156
|
+
}
|
|
157
|
+
const output = (0, import_node_child_process.spawnSync)(
|
|
158
|
+
"pnpm",
|
|
159
|
+
["--filter", "@pinpatch/overlay", "build"],
|
|
160
|
+
{
|
|
161
|
+
cwd: workspaceRoot,
|
|
162
|
+
stdio: "inherit"
|
|
163
|
+
}
|
|
164
|
+
);
|
|
165
|
+
if (output.status === 0) {
|
|
166
|
+
const builtPath = import_node_path.default.join(
|
|
167
|
+
workspaceRoot,
|
|
168
|
+
"apps",
|
|
169
|
+
"overlay",
|
|
170
|
+
"dist",
|
|
171
|
+
"pinpatch-overlay.iife.js"
|
|
172
|
+
);
|
|
173
|
+
if ((0, import_node_fs.existsSync)(builtPath)) {
|
|
174
|
+
return builtPath;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return void 0;
|
|
178
|
+
};
|
|
179
|
+
const buildRoots = Array.from(/* @__PURE__ */ new Set([cwd, workspaceRootFromCli]));
|
|
180
|
+
for (const buildRoot of buildRoots) {
|
|
181
|
+
const built = maybeBuildOverlay(buildRoot);
|
|
182
|
+
if (built) {
|
|
183
|
+
return built;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return void 0;
|
|
187
|
+
};
|
|
188
|
+
var runDev = async (options) => {
|
|
189
|
+
const cwd = resolveRuntimeCwd();
|
|
190
|
+
const store = new import_core.ArtifactStore(cwd);
|
|
191
|
+
await store.ensureStructure();
|
|
192
|
+
await store.ensureGitignoreEntry();
|
|
193
|
+
const config = await (0, import_core.resolveConfig)(cwd, {
|
|
194
|
+
provider: options.provider,
|
|
195
|
+
model: options.model,
|
|
196
|
+
target: options.target,
|
|
197
|
+
debug: options.debug,
|
|
198
|
+
bridgePort: options.bridgePort,
|
|
199
|
+
proxyPort: options.proxyPort
|
|
200
|
+
});
|
|
201
|
+
const logger = (0, import_core.createLogger)({
|
|
202
|
+
store,
|
|
203
|
+
component: "cli",
|
|
204
|
+
debugEnabled: config.debug
|
|
205
|
+
});
|
|
206
|
+
const reachable = await targetReachable(config.target);
|
|
207
|
+
if (!reachable) {
|
|
208
|
+
throw new Error(
|
|
209
|
+
`Target localhost:${config.target} is unreachable. Start your app first and retry. Hint: lsof -i :${config.target}`
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
const overlayScriptPath = resolveOverlayBundlePath(cwd);
|
|
213
|
+
const providerRegistry = (0, import_providers.createProviderRegistry)(["codex", "claude"]);
|
|
214
|
+
const bridge = (0, import_core.createBridgeServer)({
|
|
215
|
+
cwd,
|
|
216
|
+
port: config.bridgePort,
|
|
217
|
+
store,
|
|
218
|
+
logger,
|
|
219
|
+
overlayScriptPath,
|
|
220
|
+
getProviderAdapter: (provider) => providerRegistry.getAdapter(provider)
|
|
221
|
+
});
|
|
222
|
+
const proxy = (0, import_proxy.createReverseProxy)({
|
|
223
|
+
targetPort: config.target,
|
|
224
|
+
proxyPort: config.proxyPort,
|
|
225
|
+
bridgePort: config.bridgePort,
|
|
226
|
+
provider: config.provider,
|
|
227
|
+
model: config.model,
|
|
228
|
+
logger
|
|
229
|
+
});
|
|
230
|
+
try {
|
|
231
|
+
await bridge.start();
|
|
232
|
+
} catch (error) {
|
|
233
|
+
const code = error.code;
|
|
234
|
+
if (code === "EADDRINUSE") {
|
|
235
|
+
throw new Error(
|
|
236
|
+
`Bridge port ${config.bridgePort} is already in use. Hint: lsof -i :${config.bridgePort}`
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
241
|
+
try {
|
|
242
|
+
await proxy.start();
|
|
243
|
+
} catch (error) {
|
|
244
|
+
const code = error.code;
|
|
245
|
+
if (code === "EADDRINUSE") {
|
|
246
|
+
await bridge.stop();
|
|
247
|
+
throw new Error(
|
|
248
|
+
`Proxy port ${config.proxyPort} is already in use. Hint: lsof -i :${config.proxyPort}`
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
await bridge.stop();
|
|
252
|
+
throw error;
|
|
253
|
+
}
|
|
254
|
+
console.log(`Pinpatch dev ready`);
|
|
255
|
+
console.log(`Target app: http://localhost:${config.target}`);
|
|
256
|
+
console.log(`Proxied app: http://localhost:${config.proxyPort}`);
|
|
257
|
+
console.log(`Bridge API: http://localhost:${config.bridgePort}`);
|
|
258
|
+
await waitForSignal();
|
|
259
|
+
await proxy.stop();
|
|
260
|
+
await bridge.stop();
|
|
261
|
+
};
|
|
262
|
+
var runImplement = async (taskId, options) => {
|
|
263
|
+
const cwd = resolveRuntimeCwd();
|
|
264
|
+
const store = new import_core.ArtifactStore(cwd);
|
|
265
|
+
await store.ensureStructure();
|
|
266
|
+
await store.ensureGitignoreEntry();
|
|
267
|
+
const config = await (0, import_core.resolveConfig)(cwd, {
|
|
268
|
+
provider: options.provider,
|
|
269
|
+
model: options.model,
|
|
270
|
+
debug: options.debug
|
|
271
|
+
});
|
|
272
|
+
const logger = (0, import_core.createLogger)({
|
|
273
|
+
store,
|
|
274
|
+
component: "cli",
|
|
275
|
+
debugEnabled: config.debug
|
|
276
|
+
});
|
|
277
|
+
const task = await store.getTask(taskId);
|
|
278
|
+
if (!task) {
|
|
279
|
+
throw new Error(`Task ${taskId} was not found under .pinpatch/tasks`);
|
|
280
|
+
}
|
|
281
|
+
const providerRegistry = (0, import_providers.createProviderRegistry)(["codex", "claude"]);
|
|
282
|
+
const eventBus = new import_core.TaskEventBus();
|
|
283
|
+
const runner = new import_core.TaskRunner({
|
|
284
|
+
cwd,
|
|
285
|
+
store,
|
|
286
|
+
logger,
|
|
287
|
+
eventBus,
|
|
288
|
+
getProviderAdapter: (provider) => providerRegistry.getAdapter(provider)
|
|
289
|
+
});
|
|
290
|
+
const sessionId = (0, import_core.generateSessionId)();
|
|
291
|
+
const result = await runner.runTask({
|
|
292
|
+
taskId,
|
|
293
|
+
sessionId,
|
|
294
|
+
provider: config.provider,
|
|
295
|
+
model: config.model,
|
|
296
|
+
dryRun: Boolean(options.dryRun),
|
|
297
|
+
debug: config.debug
|
|
298
|
+
});
|
|
299
|
+
console.log(`Task ${taskId} -> ${result.status}`);
|
|
300
|
+
console.log(result.summary);
|
|
301
|
+
if (result.changedFiles.length > 0) {
|
|
302
|
+
console.log("Changed files:");
|
|
303
|
+
for (const changedFile of result.changedFiles) {
|
|
304
|
+
console.log(` - ${changedFile}`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (result.status !== "completed") {
|
|
308
|
+
process.exitCode = 1;
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
var runTasks = async (options) => {
|
|
312
|
+
const cwd = resolveRuntimeCwd();
|
|
313
|
+
const store = new import_core.ArtifactStore(cwd);
|
|
314
|
+
await store.ensureStructure();
|
|
315
|
+
if (options.prune) {
|
|
316
|
+
const result = await store.prune();
|
|
317
|
+
console.log(`Pruned logs: ${result.removedLogs}`);
|
|
318
|
+
console.log(`Pruned orphan sessions: ${result.removedSessions}`);
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const tasks = await store.listTasks();
|
|
322
|
+
tasks.sort(
|
|
323
|
+
(left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt)
|
|
324
|
+
);
|
|
325
|
+
if (tasks.length === 0) {
|
|
326
|
+
console.log("No tasks found in .pinpatch/tasks");
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
console.table(
|
|
330
|
+
tasks.map((task) => ({
|
|
331
|
+
taskId: task.taskId,
|
|
332
|
+
status: task.status,
|
|
333
|
+
updatedAt: task.updatedAt,
|
|
334
|
+
provider: task.provider ?? "-",
|
|
335
|
+
model: task.model ?? "-",
|
|
336
|
+
latestSessionId: task.latestSessionId ?? "-"
|
|
337
|
+
}))
|
|
338
|
+
);
|
|
339
|
+
};
|
|
340
|
+
var program = new import_commander.Command();
|
|
341
|
+
program.name("pinpatch").description("Pinpatch CLI").version("0.1.0");
|
|
342
|
+
program.addHelpText(
|
|
343
|
+
"after",
|
|
344
|
+
`
|
|
345
|
+
Quick reference:
|
|
346
|
+
pinpatch dev --target <port>
|
|
347
|
+
pinpatch implement <taskId>
|
|
348
|
+
pinpatch tasks
|
|
349
|
+
pinpatch tasks --prune
|
|
350
|
+
|
|
351
|
+
${keyboardShortcutsHelp}
|
|
352
|
+
`
|
|
353
|
+
);
|
|
354
|
+
program.command("dev").description("Start Pinpatch bridge + proxy runtime").option(
|
|
355
|
+
"--target <port>",
|
|
356
|
+
"Target app localhost port",
|
|
357
|
+
(value) => Number.parseInt(value, 10)
|
|
358
|
+
).option("--provider <name>", "Provider name (codex|claude)").option("--model <model>", "Provider model").option(
|
|
359
|
+
"--bridge-port <port>",
|
|
360
|
+
"Bridge server port",
|
|
361
|
+
(value) => Number.parseInt(value, 10)
|
|
362
|
+
).option(
|
|
363
|
+
"--proxy-port <port>",
|
|
364
|
+
"Proxy server port",
|
|
365
|
+
(value) => Number.parseInt(value, 10)
|
|
366
|
+
).option("--debug", "Enable debug logs", false).action(async (options) => {
|
|
367
|
+
await runDev(options);
|
|
368
|
+
});
|
|
369
|
+
program.command("implement").description("Execute a saved task through provider adapter").argument("<taskId>", "Task id").option("--provider <name>", "Provider name").option("--model <model>", "Provider model").option("--dry-run", "Do not apply provider edits", false).option("--debug", "Enable debug logs", false).action(async (taskId, options) => {
|
|
370
|
+
await runImplement(taskId, options);
|
|
371
|
+
});
|
|
372
|
+
program.command("tasks").description("List or prune task/session artifacts").option("--prune", "Prune expired logs and orphan sessions", false).option("--debug", "Enable debug logs", false).action(async (options) => {
|
|
373
|
+
await runTasks(options);
|
|
374
|
+
});
|
|
375
|
+
program.parseAsync(process.argv).catch((error) => {
|
|
376
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
377
|
+
process.exitCode = 1;
|
|
378
|
+
});
|
|
379
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import path from \"node:path\";\nimport { existsSync } from \"node:fs\";\nimport http from \"node:http\";\nimport { spawnSync } from \"node:child_process\";\nimport { Command } from \"commander\";\nimport {\n ArtifactStore,\n createBridgeServer,\n createLogger,\n generateSessionId,\n resolveConfig,\n TaskEventBus,\n TaskRunner,\n type ProviderName,\n} from \"@pinpatch/core\";\nimport { createProviderRegistry } from \"@pinpatch/providers\";\nimport { createReverseProxy } from \"@pinpatch/proxy\";\n\nconst cliEntrypointDir = process.argv[1]\n ? path.dirname(path.resolve(process.argv[1]))\n : process.cwd();\nconst packageRootFromCli = [\"bin\", \"dist\", \"src\"].includes(\n path.basename(cliEntrypointDir),\n)\n ? path.resolve(cliEntrypointDir, \"..\")\n : cliEntrypointDir;\nconst workspaceRootFromCli = path.resolve(packageRootFromCli, \"../..\");\n\nconst resolveRuntimeCwd = (): string => {\n const initCwd = process.env.INIT_CWD?.trim();\n if (initCwd) {\n const resolved = path.resolve(initCwd);\n if (existsSync(resolved)) {\n return resolved;\n }\n }\n\n const cwd = process.cwd();\n\n const workspaceRootFromCwd = path.resolve(cwd, \"../..\");\n const workspaceMarkerFromCwd = path.join(\n workspaceRootFromCwd,\n \"pnpm-workspace.yaml\",\n );\n const appearsToBeCliPackage =\n path.basename(cwd) === \"cli\" &&\n path.basename(path.dirname(cwd)) === \"packages\";\n if (appearsToBeCliPackage && existsSync(workspaceMarkerFromCwd)) {\n return workspaceRootFromCwd;\n }\n\n const workspaceMarker = path.join(\n workspaceRootFromCli,\n \"pnpm-workspace.yaml\",\n );\n if (cwd === packageRootFromCli && existsSync(workspaceMarker)) {\n return workspaceRootFromCli;\n }\n\n return cwd;\n};\n\ntype DevCommandOptions = {\n target?: number;\n provider?: ProviderName;\n model?: string;\n debug?: boolean;\n bridgePort?: number;\n proxyPort?: number;\n};\n\ntype ImplementCommandOptions = {\n provider?: ProviderName;\n model?: string;\n dryRun?: boolean;\n debug?: boolean;\n};\n\ntype TasksCommandOptions = {\n prune?: boolean;\n debug?: boolean;\n};\n\nconst keyboardShortcutsHelp = [\n \"Keyboard shortcuts (when using `pinpatch dev` in the proxied app):\",\n \" c Toggle pin mode\",\n \" Escape Exit pin mode and close the composer\",\n \" Cmd+Delete/Backspace Clear all pins (macOS)\",\n \" Ctrl+Delete/Backspace Clear all pins (Windows/Linux)\",\n \" Enter Submit from composer/follow-up textarea\",\n \" Shift+Enter Insert a newline in composer/follow-up textarea\",\n].join(\"\\n\");\n\nconst waitForSignal = async (): Promise<void> => {\n await new Promise<void>((resolve) => {\n const onSignal = () => {\n process.off(\"SIGINT\", onSignal);\n process.off(\"SIGTERM\", onSignal);\n resolve();\n };\n\n process.on(\"SIGINT\", onSignal);\n process.on(\"SIGTERM\", onSignal);\n });\n};\n\nconst targetReachable = async (port: number): Promise<boolean> => {\n return await new Promise<boolean>((resolve) => {\n const request = http.get(\n {\n host: \"localhost\",\n port,\n path: \"/\",\n timeout: 1500,\n },\n () => {\n request.destroy();\n resolve(true);\n },\n );\n\n request.on(\"error\", () => resolve(false));\n request.on(\"timeout\", () => {\n request.destroy();\n resolve(false);\n });\n });\n};\n\nconst resolveOverlayBundlePath = (cwd: string): string | undefined => {\n const candidates = [\n process.env.PINPATCH_OVERLAY_SCRIPT_PATH,\n path.join(cwd, \"apps\", \"overlay\", \"dist\", \"pinpatch-overlay.iife.js\"),\n path.join(\n cwd,\n \"node_modules\",\n \"@pinpatch\",\n \"overlay\",\n \"dist\",\n \"pinpatch-overlay.iife.js\",\n ),\n path.join(\n packageRootFromCli,\n \"node_modules\",\n \"@pinpatch\",\n \"overlay\",\n \"dist\",\n \"pinpatch-overlay.iife.js\",\n ),\n path.join(\n workspaceRootFromCli,\n \"apps\",\n \"overlay\",\n \"dist\",\n \"pinpatch-overlay.iife.js\",\n ),\n path.join(\n resolveRuntimeCwd(),\n \"apps\",\n \"overlay\",\n \"dist\",\n \"pinpatch-overlay.iife.js\",\n ),\n ].filter((value): value is string => Boolean(value));\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n const maybeBuildOverlay = (workspaceRoot: string): string | undefined => {\n const overlayWorkspace = path.join(\n workspaceRoot,\n \"apps\",\n \"overlay\",\n \"package.json\",\n );\n if (!existsSync(overlayWorkspace)) {\n return undefined;\n }\n\n const output = spawnSync(\n \"pnpm\",\n [\"--filter\", \"@pinpatch/overlay\", \"build\"],\n {\n cwd: workspaceRoot,\n stdio: \"inherit\",\n },\n );\n\n if (output.status === 0) {\n const builtPath = path.join(\n workspaceRoot,\n \"apps\",\n \"overlay\",\n \"dist\",\n \"pinpatch-overlay.iife.js\",\n );\n if (existsSync(builtPath)) {\n return builtPath;\n }\n }\n\n return undefined;\n };\n\n const buildRoots = Array.from(new Set([cwd, workspaceRootFromCli]));\n for (const buildRoot of buildRoots) {\n const built = maybeBuildOverlay(buildRoot);\n if (built) {\n return built;\n }\n }\n\n return undefined;\n};\n\nconst runDev = async (options: DevCommandOptions): Promise<void> => {\n const cwd = resolveRuntimeCwd();\n const store = new ArtifactStore(cwd);\n await store.ensureStructure();\n await store.ensureGitignoreEntry();\n\n const config = await resolveConfig(cwd, {\n provider: options.provider,\n model: options.model,\n target: options.target,\n debug: options.debug,\n bridgePort: options.bridgePort,\n proxyPort: options.proxyPort,\n });\n\n const logger = createLogger({\n store,\n component: \"cli\",\n debugEnabled: config.debug,\n });\n\n const reachable = await targetReachable(config.target);\n if (!reachable) {\n throw new Error(\n `Target localhost:${config.target} is unreachable. Start your app first and retry. Hint: lsof -i :${config.target}`,\n );\n }\n\n const overlayScriptPath = resolveOverlayBundlePath(cwd);\n\n const providerRegistry = createProviderRegistry([\"codex\", \"claude\"]);\n const bridge = createBridgeServer({\n cwd,\n port: config.bridgePort,\n store,\n logger,\n overlayScriptPath,\n getProviderAdapter: (provider) => providerRegistry.getAdapter(provider),\n });\n\n const proxy = createReverseProxy({\n targetPort: config.target,\n proxyPort: config.proxyPort,\n bridgePort: config.bridgePort,\n provider: config.provider,\n model: config.model,\n logger,\n });\n\n try {\n await bridge.start();\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code === \"EADDRINUSE\") {\n throw new Error(\n `Bridge port ${config.bridgePort} is already in use. Hint: lsof -i :${config.bridgePort}`,\n );\n }\n\n throw error;\n }\n\n try {\n await proxy.start();\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code === \"EADDRINUSE\") {\n await bridge.stop();\n throw new Error(\n `Proxy port ${config.proxyPort} is already in use. Hint: lsof -i :${config.proxyPort}`,\n );\n }\n\n await bridge.stop();\n throw error;\n }\n\n console.log(`Pinpatch dev ready`);\n console.log(`Target app: http://localhost:${config.target}`);\n console.log(`Proxied app: http://localhost:${config.proxyPort}`);\n console.log(`Bridge API: http://localhost:${config.bridgePort}`);\n\n await waitForSignal();\n\n await proxy.stop();\n await bridge.stop();\n};\n\nconst runImplement = async (\n taskId: string,\n options: ImplementCommandOptions,\n): Promise<void> => {\n const cwd = resolveRuntimeCwd();\n const store = new ArtifactStore(cwd);\n await store.ensureStructure();\n await store.ensureGitignoreEntry();\n\n const config = await resolveConfig(cwd, {\n provider: options.provider,\n model: options.model,\n debug: options.debug,\n });\n\n const logger = createLogger({\n store,\n component: \"cli\",\n debugEnabled: config.debug,\n });\n\n const task = await store.getTask(taskId);\n if (!task) {\n throw new Error(`Task ${taskId} was not found under .pinpatch/tasks`);\n }\n\n const providerRegistry = createProviderRegistry([\"codex\", \"claude\"]);\n const eventBus = new TaskEventBus();\n const runner = new TaskRunner({\n cwd,\n store,\n logger,\n eventBus,\n getProviderAdapter: (provider) => providerRegistry.getAdapter(provider),\n });\n\n const sessionId = generateSessionId();\n const result = await runner.runTask({\n taskId,\n sessionId,\n provider: config.provider,\n model: config.model,\n dryRun: Boolean(options.dryRun),\n debug: config.debug,\n });\n\n console.log(`Task ${taskId} -> ${result.status}`);\n console.log(result.summary);\n if (result.changedFiles.length > 0) {\n console.log(\"Changed files:\");\n for (const changedFile of result.changedFiles) {\n console.log(` - ${changedFile}`);\n }\n }\n\n if (result.status !== \"completed\") {\n process.exitCode = 1;\n }\n};\n\nconst runTasks = async (options: TasksCommandOptions): Promise<void> => {\n const cwd = resolveRuntimeCwd();\n const store = new ArtifactStore(cwd);\n await store.ensureStructure();\n\n if (options.prune) {\n const result = await store.prune();\n console.log(`Pruned logs: ${result.removedLogs}`);\n console.log(`Pruned orphan sessions: ${result.removedSessions}`);\n return;\n }\n\n const tasks = await store.listTasks();\n tasks.sort(\n (left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt),\n );\n\n if (tasks.length === 0) {\n console.log(\"No tasks found in .pinpatch/tasks\");\n return;\n }\n\n console.table(\n tasks.map((task) => ({\n taskId: task.taskId,\n status: task.status,\n updatedAt: task.updatedAt,\n provider: task.provider ?? \"-\",\n model: task.model ?? \"-\",\n latestSessionId: task.latestSessionId ?? \"-\",\n })),\n );\n};\n\nconst program = new Command();\nprogram.name(\"pinpatch\").description(\"Pinpatch CLI\").version(\"0.1.0\");\nprogram.addHelpText(\n \"after\",\n `\\nQuick reference:\\n pinpatch dev --target <port>\\n pinpatch implement <taskId>\\n pinpatch tasks\\n pinpatch tasks --prune\\n\\n${keyboardShortcutsHelp}\\n`,\n);\n\nprogram\n .command(\"dev\")\n .description(\"Start Pinpatch bridge + proxy runtime\")\n .option(\"--target <port>\", \"Target app localhost port\", (value) =>\n Number.parseInt(value, 10),\n )\n .option(\"--provider <name>\", \"Provider name (codex|claude)\")\n .option(\"--model <model>\", \"Provider model\")\n .option(\"--bridge-port <port>\", \"Bridge server port\", (value) =>\n Number.parseInt(value, 10),\n )\n .option(\"--proxy-port <port>\", \"Proxy server port\", (value) =>\n Number.parseInt(value, 10),\n )\n .option(\"--debug\", \"Enable debug logs\", false)\n .action(async (options: DevCommandOptions) => {\n await runDev(options);\n });\n\nprogram\n .command(\"implement\")\n .description(\"Execute a saved task through provider adapter\")\n .argument(\"<taskId>\", \"Task id\")\n .option(\"--provider <name>\", \"Provider name\")\n .option(\"--model <model>\", \"Provider model\")\n .option(\"--dry-run\", \"Do not apply provider edits\", false)\n .option(\"--debug\", \"Enable debug logs\", false)\n .action(async (taskId: string, options: ImplementCommandOptions) => {\n await runImplement(taskId, options);\n });\n\nprogram\n .command(\"tasks\")\n .description(\"List or prune task/session artifacts\")\n .option(\"--prune\", \"Prune expired logs and orphan sessions\", false)\n .option(\"--debug\", \"Enable debug logs\", false)\n .action(async (options: TasksCommandOptions) => {\n await runTasks(options);\n });\n\nprogram.parseAsync(process.argv).catch((error: unknown) => {\n console.error(error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n});\n"],"mappings":"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","names":["path","http"]}
|
package/dist/index.d.cts
ADDED
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { existsSync } from "fs";
|
|
4
|
+
import http from "http";
|
|
5
|
+
import { spawnSync } from "child_process";
|
|
6
|
+
import { Command } from "commander";
|
|
7
|
+
import {
|
|
8
|
+
ArtifactStore,
|
|
9
|
+
createBridgeServer,
|
|
10
|
+
createLogger,
|
|
11
|
+
generateSessionId,
|
|
12
|
+
resolveConfig,
|
|
13
|
+
TaskEventBus,
|
|
14
|
+
TaskRunner
|
|
15
|
+
} from "@pinpatch/core";
|
|
16
|
+
import { createProviderRegistry } from "@pinpatch/providers";
|
|
17
|
+
import { createReverseProxy } from "@pinpatch/proxy";
|
|
18
|
+
var cliEntrypointDir = process.argv[1] ? path.dirname(path.resolve(process.argv[1])) : process.cwd();
|
|
19
|
+
var packageRootFromCli = ["bin", "dist", "src"].includes(
|
|
20
|
+
path.basename(cliEntrypointDir)
|
|
21
|
+
) ? path.resolve(cliEntrypointDir, "..") : cliEntrypointDir;
|
|
22
|
+
var workspaceRootFromCli = path.resolve(packageRootFromCli, "../..");
|
|
23
|
+
var resolveRuntimeCwd = () => {
|
|
24
|
+
const initCwd = process.env.INIT_CWD?.trim();
|
|
25
|
+
if (initCwd) {
|
|
26
|
+
const resolved = path.resolve(initCwd);
|
|
27
|
+
if (existsSync(resolved)) {
|
|
28
|
+
return resolved;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const cwd = process.cwd();
|
|
32
|
+
const workspaceRootFromCwd = path.resolve(cwd, "../..");
|
|
33
|
+
const workspaceMarkerFromCwd = path.join(
|
|
34
|
+
workspaceRootFromCwd,
|
|
35
|
+
"pnpm-workspace.yaml"
|
|
36
|
+
);
|
|
37
|
+
const appearsToBeCliPackage = path.basename(cwd) === "cli" && path.basename(path.dirname(cwd)) === "packages";
|
|
38
|
+
if (appearsToBeCliPackage && existsSync(workspaceMarkerFromCwd)) {
|
|
39
|
+
return workspaceRootFromCwd;
|
|
40
|
+
}
|
|
41
|
+
const workspaceMarker = path.join(
|
|
42
|
+
workspaceRootFromCli,
|
|
43
|
+
"pnpm-workspace.yaml"
|
|
44
|
+
);
|
|
45
|
+
if (cwd === packageRootFromCli && existsSync(workspaceMarker)) {
|
|
46
|
+
return workspaceRootFromCli;
|
|
47
|
+
}
|
|
48
|
+
return cwd;
|
|
49
|
+
};
|
|
50
|
+
var keyboardShortcutsHelp = [
|
|
51
|
+
"Keyboard shortcuts (when using `pinpatch dev` in the proxied app):",
|
|
52
|
+
" c Toggle pin mode",
|
|
53
|
+
" Escape Exit pin mode and close the composer",
|
|
54
|
+
" Cmd+Delete/Backspace Clear all pins (macOS)",
|
|
55
|
+
" Ctrl+Delete/Backspace Clear all pins (Windows/Linux)",
|
|
56
|
+
" Enter Submit from composer/follow-up textarea",
|
|
57
|
+
" Shift+Enter Insert a newline in composer/follow-up textarea"
|
|
58
|
+
].join("\n");
|
|
59
|
+
var waitForSignal = async () => {
|
|
60
|
+
await new Promise((resolve) => {
|
|
61
|
+
const onSignal = () => {
|
|
62
|
+
process.off("SIGINT", onSignal);
|
|
63
|
+
process.off("SIGTERM", onSignal);
|
|
64
|
+
resolve();
|
|
65
|
+
};
|
|
66
|
+
process.on("SIGINT", onSignal);
|
|
67
|
+
process.on("SIGTERM", onSignal);
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
var targetReachable = async (port) => {
|
|
71
|
+
return await new Promise((resolve) => {
|
|
72
|
+
const request = http.get(
|
|
73
|
+
{
|
|
74
|
+
host: "localhost",
|
|
75
|
+
port,
|
|
76
|
+
path: "/",
|
|
77
|
+
timeout: 1500
|
|
78
|
+
},
|
|
79
|
+
() => {
|
|
80
|
+
request.destroy();
|
|
81
|
+
resolve(true);
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
request.on("error", () => resolve(false));
|
|
85
|
+
request.on("timeout", () => {
|
|
86
|
+
request.destroy();
|
|
87
|
+
resolve(false);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
var resolveOverlayBundlePath = (cwd) => {
|
|
92
|
+
const candidates = [
|
|
93
|
+
process.env.PINPATCH_OVERLAY_SCRIPT_PATH,
|
|
94
|
+
path.join(cwd, "apps", "overlay", "dist", "pinpatch-overlay.iife.js"),
|
|
95
|
+
path.join(
|
|
96
|
+
cwd,
|
|
97
|
+
"node_modules",
|
|
98
|
+
"@pinpatch",
|
|
99
|
+
"overlay",
|
|
100
|
+
"dist",
|
|
101
|
+
"pinpatch-overlay.iife.js"
|
|
102
|
+
),
|
|
103
|
+
path.join(
|
|
104
|
+
packageRootFromCli,
|
|
105
|
+
"node_modules",
|
|
106
|
+
"@pinpatch",
|
|
107
|
+
"overlay",
|
|
108
|
+
"dist",
|
|
109
|
+
"pinpatch-overlay.iife.js"
|
|
110
|
+
),
|
|
111
|
+
path.join(
|
|
112
|
+
workspaceRootFromCli,
|
|
113
|
+
"apps",
|
|
114
|
+
"overlay",
|
|
115
|
+
"dist",
|
|
116
|
+
"pinpatch-overlay.iife.js"
|
|
117
|
+
),
|
|
118
|
+
path.join(
|
|
119
|
+
resolveRuntimeCwd(),
|
|
120
|
+
"apps",
|
|
121
|
+
"overlay",
|
|
122
|
+
"dist",
|
|
123
|
+
"pinpatch-overlay.iife.js"
|
|
124
|
+
)
|
|
125
|
+
].filter((value) => Boolean(value));
|
|
126
|
+
for (const candidate of candidates) {
|
|
127
|
+
if (existsSync(candidate)) {
|
|
128
|
+
return candidate;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const maybeBuildOverlay = (workspaceRoot) => {
|
|
132
|
+
const overlayWorkspace = path.join(
|
|
133
|
+
workspaceRoot,
|
|
134
|
+
"apps",
|
|
135
|
+
"overlay",
|
|
136
|
+
"package.json"
|
|
137
|
+
);
|
|
138
|
+
if (!existsSync(overlayWorkspace)) {
|
|
139
|
+
return void 0;
|
|
140
|
+
}
|
|
141
|
+
const output = spawnSync(
|
|
142
|
+
"pnpm",
|
|
143
|
+
["--filter", "@pinpatch/overlay", "build"],
|
|
144
|
+
{
|
|
145
|
+
cwd: workspaceRoot,
|
|
146
|
+
stdio: "inherit"
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
if (output.status === 0) {
|
|
150
|
+
const builtPath = path.join(
|
|
151
|
+
workspaceRoot,
|
|
152
|
+
"apps",
|
|
153
|
+
"overlay",
|
|
154
|
+
"dist",
|
|
155
|
+
"pinpatch-overlay.iife.js"
|
|
156
|
+
);
|
|
157
|
+
if (existsSync(builtPath)) {
|
|
158
|
+
return builtPath;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return void 0;
|
|
162
|
+
};
|
|
163
|
+
const buildRoots = Array.from(/* @__PURE__ */ new Set([cwd, workspaceRootFromCli]));
|
|
164
|
+
for (const buildRoot of buildRoots) {
|
|
165
|
+
const built = maybeBuildOverlay(buildRoot);
|
|
166
|
+
if (built) {
|
|
167
|
+
return built;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return void 0;
|
|
171
|
+
};
|
|
172
|
+
var runDev = async (options) => {
|
|
173
|
+
const cwd = resolveRuntimeCwd();
|
|
174
|
+
const store = new ArtifactStore(cwd);
|
|
175
|
+
await store.ensureStructure();
|
|
176
|
+
await store.ensureGitignoreEntry();
|
|
177
|
+
const config = await resolveConfig(cwd, {
|
|
178
|
+
provider: options.provider,
|
|
179
|
+
model: options.model,
|
|
180
|
+
target: options.target,
|
|
181
|
+
debug: options.debug,
|
|
182
|
+
bridgePort: options.bridgePort,
|
|
183
|
+
proxyPort: options.proxyPort
|
|
184
|
+
});
|
|
185
|
+
const logger = createLogger({
|
|
186
|
+
store,
|
|
187
|
+
component: "cli",
|
|
188
|
+
debugEnabled: config.debug
|
|
189
|
+
});
|
|
190
|
+
const reachable = await targetReachable(config.target);
|
|
191
|
+
if (!reachable) {
|
|
192
|
+
throw new Error(
|
|
193
|
+
`Target localhost:${config.target} is unreachable. Start your app first and retry. Hint: lsof -i :${config.target}`
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
const overlayScriptPath = resolveOverlayBundlePath(cwd);
|
|
197
|
+
const providerRegistry = createProviderRegistry(["codex", "claude"]);
|
|
198
|
+
const bridge = createBridgeServer({
|
|
199
|
+
cwd,
|
|
200
|
+
port: config.bridgePort,
|
|
201
|
+
store,
|
|
202
|
+
logger,
|
|
203
|
+
overlayScriptPath,
|
|
204
|
+
getProviderAdapter: (provider) => providerRegistry.getAdapter(provider)
|
|
205
|
+
});
|
|
206
|
+
const proxy = createReverseProxy({
|
|
207
|
+
targetPort: config.target,
|
|
208
|
+
proxyPort: config.proxyPort,
|
|
209
|
+
bridgePort: config.bridgePort,
|
|
210
|
+
provider: config.provider,
|
|
211
|
+
model: config.model,
|
|
212
|
+
logger
|
|
213
|
+
});
|
|
214
|
+
try {
|
|
215
|
+
await bridge.start();
|
|
216
|
+
} catch (error) {
|
|
217
|
+
const code = error.code;
|
|
218
|
+
if (code === "EADDRINUSE") {
|
|
219
|
+
throw new Error(
|
|
220
|
+
`Bridge port ${config.bridgePort} is already in use. Hint: lsof -i :${config.bridgePort}`
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
throw error;
|
|
224
|
+
}
|
|
225
|
+
try {
|
|
226
|
+
await proxy.start();
|
|
227
|
+
} catch (error) {
|
|
228
|
+
const code = error.code;
|
|
229
|
+
if (code === "EADDRINUSE") {
|
|
230
|
+
await bridge.stop();
|
|
231
|
+
throw new Error(
|
|
232
|
+
`Proxy port ${config.proxyPort} is already in use. Hint: lsof -i :${config.proxyPort}`
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
await bridge.stop();
|
|
236
|
+
throw error;
|
|
237
|
+
}
|
|
238
|
+
console.log(`Pinpatch dev ready`);
|
|
239
|
+
console.log(`Target app: http://localhost:${config.target}`);
|
|
240
|
+
console.log(`Proxied app: http://localhost:${config.proxyPort}`);
|
|
241
|
+
console.log(`Bridge API: http://localhost:${config.bridgePort}`);
|
|
242
|
+
await waitForSignal();
|
|
243
|
+
await proxy.stop();
|
|
244
|
+
await bridge.stop();
|
|
245
|
+
};
|
|
246
|
+
var runImplement = async (taskId, options) => {
|
|
247
|
+
const cwd = resolveRuntimeCwd();
|
|
248
|
+
const store = new ArtifactStore(cwd);
|
|
249
|
+
await store.ensureStructure();
|
|
250
|
+
await store.ensureGitignoreEntry();
|
|
251
|
+
const config = await resolveConfig(cwd, {
|
|
252
|
+
provider: options.provider,
|
|
253
|
+
model: options.model,
|
|
254
|
+
debug: options.debug
|
|
255
|
+
});
|
|
256
|
+
const logger = createLogger({
|
|
257
|
+
store,
|
|
258
|
+
component: "cli",
|
|
259
|
+
debugEnabled: config.debug
|
|
260
|
+
});
|
|
261
|
+
const task = await store.getTask(taskId);
|
|
262
|
+
if (!task) {
|
|
263
|
+
throw new Error(`Task ${taskId} was not found under .pinpatch/tasks`);
|
|
264
|
+
}
|
|
265
|
+
const providerRegistry = createProviderRegistry(["codex", "claude"]);
|
|
266
|
+
const eventBus = new TaskEventBus();
|
|
267
|
+
const runner = new TaskRunner({
|
|
268
|
+
cwd,
|
|
269
|
+
store,
|
|
270
|
+
logger,
|
|
271
|
+
eventBus,
|
|
272
|
+
getProviderAdapter: (provider) => providerRegistry.getAdapter(provider)
|
|
273
|
+
});
|
|
274
|
+
const sessionId = generateSessionId();
|
|
275
|
+
const result = await runner.runTask({
|
|
276
|
+
taskId,
|
|
277
|
+
sessionId,
|
|
278
|
+
provider: config.provider,
|
|
279
|
+
model: config.model,
|
|
280
|
+
dryRun: Boolean(options.dryRun),
|
|
281
|
+
debug: config.debug
|
|
282
|
+
});
|
|
283
|
+
console.log(`Task ${taskId} -> ${result.status}`);
|
|
284
|
+
console.log(result.summary);
|
|
285
|
+
if (result.changedFiles.length > 0) {
|
|
286
|
+
console.log("Changed files:");
|
|
287
|
+
for (const changedFile of result.changedFiles) {
|
|
288
|
+
console.log(` - ${changedFile}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (result.status !== "completed") {
|
|
292
|
+
process.exitCode = 1;
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
var runTasks = async (options) => {
|
|
296
|
+
const cwd = resolveRuntimeCwd();
|
|
297
|
+
const store = new ArtifactStore(cwd);
|
|
298
|
+
await store.ensureStructure();
|
|
299
|
+
if (options.prune) {
|
|
300
|
+
const result = await store.prune();
|
|
301
|
+
console.log(`Pruned logs: ${result.removedLogs}`);
|
|
302
|
+
console.log(`Pruned orphan sessions: ${result.removedSessions}`);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const tasks = await store.listTasks();
|
|
306
|
+
tasks.sort(
|
|
307
|
+
(left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt)
|
|
308
|
+
);
|
|
309
|
+
if (tasks.length === 0) {
|
|
310
|
+
console.log("No tasks found in .pinpatch/tasks");
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
console.table(
|
|
314
|
+
tasks.map((task) => ({
|
|
315
|
+
taskId: task.taskId,
|
|
316
|
+
status: task.status,
|
|
317
|
+
updatedAt: task.updatedAt,
|
|
318
|
+
provider: task.provider ?? "-",
|
|
319
|
+
model: task.model ?? "-",
|
|
320
|
+
latestSessionId: task.latestSessionId ?? "-"
|
|
321
|
+
}))
|
|
322
|
+
);
|
|
323
|
+
};
|
|
324
|
+
var program = new Command();
|
|
325
|
+
program.name("pinpatch").description("Pinpatch CLI").version("0.1.0");
|
|
326
|
+
program.addHelpText(
|
|
327
|
+
"after",
|
|
328
|
+
`
|
|
329
|
+
Quick reference:
|
|
330
|
+
pinpatch dev --target <port>
|
|
331
|
+
pinpatch implement <taskId>
|
|
332
|
+
pinpatch tasks
|
|
333
|
+
pinpatch tasks --prune
|
|
334
|
+
|
|
335
|
+
${keyboardShortcutsHelp}
|
|
336
|
+
`
|
|
337
|
+
);
|
|
338
|
+
program.command("dev").description("Start Pinpatch bridge + proxy runtime").option(
|
|
339
|
+
"--target <port>",
|
|
340
|
+
"Target app localhost port",
|
|
341
|
+
(value) => Number.parseInt(value, 10)
|
|
342
|
+
).option("--provider <name>", "Provider name (codex|claude)").option("--model <model>", "Provider model").option(
|
|
343
|
+
"--bridge-port <port>",
|
|
344
|
+
"Bridge server port",
|
|
345
|
+
(value) => Number.parseInt(value, 10)
|
|
346
|
+
).option(
|
|
347
|
+
"--proxy-port <port>",
|
|
348
|
+
"Proxy server port",
|
|
349
|
+
(value) => Number.parseInt(value, 10)
|
|
350
|
+
).option("--debug", "Enable debug logs", false).action(async (options) => {
|
|
351
|
+
await runDev(options);
|
|
352
|
+
});
|
|
353
|
+
program.command("implement").description("Execute a saved task through provider adapter").argument("<taskId>", "Task id").option("--provider <name>", "Provider name").option("--model <model>", "Provider model").option("--dry-run", "Do not apply provider edits", false).option("--debug", "Enable debug logs", false).action(async (taskId, options) => {
|
|
354
|
+
await runImplement(taskId, options);
|
|
355
|
+
});
|
|
356
|
+
program.command("tasks").description("List or prune task/session artifacts").option("--prune", "Prune expired logs and orphan sessions", false).option("--debug", "Enable debug logs", false).action(async (options) => {
|
|
357
|
+
await runTasks(options);
|
|
358
|
+
});
|
|
359
|
+
program.parseAsync(process.argv).catch((error) => {
|
|
360
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
361
|
+
process.exitCode = 1;
|
|
362
|
+
});
|
|
363
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import path from \"node:path\";\nimport { existsSync } from \"node:fs\";\nimport http from \"node:http\";\nimport { spawnSync } from \"node:child_process\";\nimport { Command } from \"commander\";\nimport {\n ArtifactStore,\n createBridgeServer,\n createLogger,\n generateSessionId,\n resolveConfig,\n TaskEventBus,\n TaskRunner,\n type ProviderName,\n} from \"@pinpatch/core\";\nimport { createProviderRegistry } from \"@pinpatch/providers\";\nimport { createReverseProxy } from \"@pinpatch/proxy\";\n\nconst cliEntrypointDir = process.argv[1]\n ? path.dirname(path.resolve(process.argv[1]))\n : process.cwd();\nconst packageRootFromCli = [\"bin\", \"dist\", \"src\"].includes(\n path.basename(cliEntrypointDir),\n)\n ? path.resolve(cliEntrypointDir, \"..\")\n : cliEntrypointDir;\nconst workspaceRootFromCli = path.resolve(packageRootFromCli, \"../..\");\n\nconst resolveRuntimeCwd = (): string => {\n const initCwd = process.env.INIT_CWD?.trim();\n if (initCwd) {\n const resolved = path.resolve(initCwd);\n if (existsSync(resolved)) {\n return resolved;\n }\n }\n\n const cwd = process.cwd();\n\n const workspaceRootFromCwd = path.resolve(cwd, \"../..\");\n const workspaceMarkerFromCwd = path.join(\n workspaceRootFromCwd,\n \"pnpm-workspace.yaml\",\n );\n const appearsToBeCliPackage =\n path.basename(cwd) === \"cli\" &&\n path.basename(path.dirname(cwd)) === \"packages\";\n if (appearsToBeCliPackage && existsSync(workspaceMarkerFromCwd)) {\n return workspaceRootFromCwd;\n }\n\n const workspaceMarker = path.join(\n workspaceRootFromCli,\n \"pnpm-workspace.yaml\",\n );\n if (cwd === packageRootFromCli && existsSync(workspaceMarker)) {\n return workspaceRootFromCli;\n }\n\n return cwd;\n};\n\ntype DevCommandOptions = {\n target?: number;\n provider?: ProviderName;\n model?: string;\n debug?: boolean;\n bridgePort?: number;\n proxyPort?: number;\n};\n\ntype ImplementCommandOptions = {\n provider?: ProviderName;\n model?: string;\n dryRun?: boolean;\n debug?: boolean;\n};\n\ntype TasksCommandOptions = {\n prune?: boolean;\n debug?: boolean;\n};\n\nconst keyboardShortcutsHelp = [\n \"Keyboard shortcuts (when using `pinpatch dev` in the proxied app):\",\n \" c Toggle pin mode\",\n \" Escape Exit pin mode and close the composer\",\n \" Cmd+Delete/Backspace Clear all pins (macOS)\",\n \" Ctrl+Delete/Backspace Clear all pins (Windows/Linux)\",\n \" Enter Submit from composer/follow-up textarea\",\n \" Shift+Enter Insert a newline in composer/follow-up textarea\",\n].join(\"\\n\");\n\nconst waitForSignal = async (): Promise<void> => {\n await new Promise<void>((resolve) => {\n const onSignal = () => {\n process.off(\"SIGINT\", onSignal);\n process.off(\"SIGTERM\", onSignal);\n resolve();\n };\n\n process.on(\"SIGINT\", onSignal);\n process.on(\"SIGTERM\", onSignal);\n });\n};\n\nconst targetReachable = async (port: number): Promise<boolean> => {\n return await new Promise<boolean>((resolve) => {\n const request = http.get(\n {\n host: \"localhost\",\n port,\n path: \"/\",\n timeout: 1500,\n },\n () => {\n request.destroy();\n resolve(true);\n },\n );\n\n request.on(\"error\", () => resolve(false));\n request.on(\"timeout\", () => {\n request.destroy();\n resolve(false);\n });\n });\n};\n\nconst resolveOverlayBundlePath = (cwd: string): string | undefined => {\n const candidates = [\n process.env.PINPATCH_OVERLAY_SCRIPT_PATH,\n path.join(cwd, \"apps\", \"overlay\", \"dist\", \"pinpatch-overlay.iife.js\"),\n path.join(\n cwd,\n \"node_modules\",\n \"@pinpatch\",\n \"overlay\",\n \"dist\",\n \"pinpatch-overlay.iife.js\",\n ),\n path.join(\n packageRootFromCli,\n \"node_modules\",\n \"@pinpatch\",\n \"overlay\",\n \"dist\",\n \"pinpatch-overlay.iife.js\",\n ),\n path.join(\n workspaceRootFromCli,\n \"apps\",\n \"overlay\",\n \"dist\",\n \"pinpatch-overlay.iife.js\",\n ),\n path.join(\n resolveRuntimeCwd(),\n \"apps\",\n \"overlay\",\n \"dist\",\n \"pinpatch-overlay.iife.js\",\n ),\n ].filter((value): value is string => Boolean(value));\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n const maybeBuildOverlay = (workspaceRoot: string): string | undefined => {\n const overlayWorkspace = path.join(\n workspaceRoot,\n \"apps\",\n \"overlay\",\n \"package.json\",\n );\n if (!existsSync(overlayWorkspace)) {\n return undefined;\n }\n\n const output = spawnSync(\n \"pnpm\",\n [\"--filter\", \"@pinpatch/overlay\", \"build\"],\n {\n cwd: workspaceRoot,\n stdio: \"inherit\",\n },\n );\n\n if (output.status === 0) {\n const builtPath = path.join(\n workspaceRoot,\n \"apps\",\n \"overlay\",\n \"dist\",\n \"pinpatch-overlay.iife.js\",\n );\n if (existsSync(builtPath)) {\n return builtPath;\n }\n }\n\n return undefined;\n };\n\n const buildRoots = Array.from(new Set([cwd, workspaceRootFromCli]));\n for (const buildRoot of buildRoots) {\n const built = maybeBuildOverlay(buildRoot);\n if (built) {\n return built;\n }\n }\n\n return undefined;\n};\n\nconst runDev = async (options: DevCommandOptions): Promise<void> => {\n const cwd = resolveRuntimeCwd();\n const store = new ArtifactStore(cwd);\n await store.ensureStructure();\n await store.ensureGitignoreEntry();\n\n const config = await resolveConfig(cwd, {\n provider: options.provider,\n model: options.model,\n target: options.target,\n debug: options.debug,\n bridgePort: options.bridgePort,\n proxyPort: options.proxyPort,\n });\n\n const logger = createLogger({\n store,\n component: \"cli\",\n debugEnabled: config.debug,\n });\n\n const reachable = await targetReachable(config.target);\n if (!reachable) {\n throw new Error(\n `Target localhost:${config.target} is unreachable. Start your app first and retry. Hint: lsof -i :${config.target}`,\n );\n }\n\n const overlayScriptPath = resolveOverlayBundlePath(cwd);\n\n const providerRegistry = createProviderRegistry([\"codex\", \"claude\"]);\n const bridge = createBridgeServer({\n cwd,\n port: config.bridgePort,\n store,\n logger,\n overlayScriptPath,\n getProviderAdapter: (provider) => providerRegistry.getAdapter(provider),\n });\n\n const proxy = createReverseProxy({\n targetPort: config.target,\n proxyPort: config.proxyPort,\n bridgePort: config.bridgePort,\n provider: config.provider,\n model: config.model,\n logger,\n });\n\n try {\n await bridge.start();\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code === \"EADDRINUSE\") {\n throw new Error(\n `Bridge port ${config.bridgePort} is already in use. Hint: lsof -i :${config.bridgePort}`,\n );\n }\n\n throw error;\n }\n\n try {\n await proxy.start();\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code === \"EADDRINUSE\") {\n await bridge.stop();\n throw new Error(\n `Proxy port ${config.proxyPort} is already in use. Hint: lsof -i :${config.proxyPort}`,\n );\n }\n\n await bridge.stop();\n throw error;\n }\n\n console.log(`Pinpatch dev ready`);\n console.log(`Target app: http://localhost:${config.target}`);\n console.log(`Proxied app: http://localhost:${config.proxyPort}`);\n console.log(`Bridge API: http://localhost:${config.bridgePort}`);\n\n await waitForSignal();\n\n await proxy.stop();\n await bridge.stop();\n};\n\nconst runImplement = async (\n taskId: string,\n options: ImplementCommandOptions,\n): Promise<void> => {\n const cwd = resolveRuntimeCwd();\n const store = new ArtifactStore(cwd);\n await store.ensureStructure();\n await store.ensureGitignoreEntry();\n\n const config = await resolveConfig(cwd, {\n provider: options.provider,\n model: options.model,\n debug: options.debug,\n });\n\n const logger = createLogger({\n store,\n component: \"cli\",\n debugEnabled: config.debug,\n });\n\n const task = await store.getTask(taskId);\n if (!task) {\n throw new Error(`Task ${taskId} was not found under .pinpatch/tasks`);\n }\n\n const providerRegistry = createProviderRegistry([\"codex\", \"claude\"]);\n const eventBus = new TaskEventBus();\n const runner = new TaskRunner({\n cwd,\n store,\n logger,\n eventBus,\n getProviderAdapter: (provider) => providerRegistry.getAdapter(provider),\n });\n\n const sessionId = generateSessionId();\n const result = await runner.runTask({\n taskId,\n sessionId,\n provider: config.provider,\n model: config.model,\n dryRun: Boolean(options.dryRun),\n debug: config.debug,\n });\n\n console.log(`Task ${taskId} -> ${result.status}`);\n console.log(result.summary);\n if (result.changedFiles.length > 0) {\n console.log(\"Changed files:\");\n for (const changedFile of result.changedFiles) {\n console.log(` - ${changedFile}`);\n }\n }\n\n if (result.status !== \"completed\") {\n process.exitCode = 1;\n }\n};\n\nconst runTasks = async (options: TasksCommandOptions): Promise<void> => {\n const cwd = resolveRuntimeCwd();\n const store = new ArtifactStore(cwd);\n await store.ensureStructure();\n\n if (options.prune) {\n const result = await store.prune();\n console.log(`Pruned logs: ${result.removedLogs}`);\n console.log(`Pruned orphan sessions: ${result.removedSessions}`);\n return;\n }\n\n const tasks = await store.listTasks();\n tasks.sort(\n (left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt),\n );\n\n if (tasks.length === 0) {\n console.log(\"No tasks found in .pinpatch/tasks\");\n return;\n }\n\n console.table(\n tasks.map((task) => ({\n taskId: task.taskId,\n status: task.status,\n updatedAt: task.updatedAt,\n provider: task.provider ?? \"-\",\n model: task.model ?? \"-\",\n latestSessionId: task.latestSessionId ?? \"-\",\n })),\n );\n};\n\nconst program = new Command();\nprogram.name(\"pinpatch\").description(\"Pinpatch CLI\").version(\"0.1.0\");\nprogram.addHelpText(\n \"after\",\n `\\nQuick reference:\\n pinpatch dev --target <port>\\n pinpatch implement <taskId>\\n pinpatch tasks\\n pinpatch tasks --prune\\n\\n${keyboardShortcutsHelp}\\n`,\n);\n\nprogram\n .command(\"dev\")\n .description(\"Start Pinpatch bridge + proxy runtime\")\n .option(\"--target <port>\", \"Target app localhost port\", (value) =>\n Number.parseInt(value, 10),\n )\n .option(\"--provider <name>\", \"Provider name (codex|claude)\")\n .option(\"--model <model>\", \"Provider model\")\n .option(\"--bridge-port <port>\", \"Bridge server port\", (value) =>\n Number.parseInt(value, 10),\n )\n .option(\"--proxy-port <port>\", \"Proxy server port\", (value) =>\n Number.parseInt(value, 10),\n )\n .option(\"--debug\", \"Enable debug logs\", false)\n .action(async (options: DevCommandOptions) => {\n await runDev(options);\n });\n\nprogram\n .command(\"implement\")\n .description(\"Execute a saved task through provider adapter\")\n .argument(\"<taskId>\", \"Task id\")\n .option(\"--provider <name>\", \"Provider name\")\n .option(\"--model <model>\", \"Provider model\")\n .option(\"--dry-run\", \"Do not apply provider edits\", false)\n .option(\"--debug\", \"Enable debug logs\", false)\n .action(async (taskId: string, options: ImplementCommandOptions) => {\n await runImplement(taskId, options);\n });\n\nprogram\n .command(\"tasks\")\n .description(\"List or prune task/session artifacts\")\n .option(\"--prune\", \"Prune expired logs and orphan sessions\", false)\n .option(\"--debug\", \"Enable debug logs\", false)\n .action(async (options: TasksCommandOptions) => {\n await runTasks(options);\n });\n\nprogram.parseAsync(process.argv).catch((error: unknown) => {\n console.error(error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n});\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pinpatch",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI for Pinpatch pin-to-code workflow with local proxy and overlay runtime.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/alex1craig/pinpatch.git"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"pinpatch",
|
|
12
|
+
"cli",
|
|
13
|
+
"developer-tools",
|
|
14
|
+
"proxy",
|
|
15
|
+
"overlay"
|
|
16
|
+
],
|
|
17
|
+
"type": "module",
|
|
18
|
+
"main": "dist/index.cjs",
|
|
19
|
+
"module": "dist/index.js",
|
|
20
|
+
"types": "dist/index.d.ts",
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"bin"
|
|
24
|
+
],
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18"
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"bin": {
|
|
32
|
+
"pinpatch": "bin/pinpatch.mjs"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"commander": "^13.1.0",
|
|
36
|
+
"@pinpatch/core": "0.1.0",
|
|
37
|
+
"@pinpatch/proxy": "0.1.0",
|
|
38
|
+
"@pinpatch/providers": "0.1.0",
|
|
39
|
+
"@pinpatch/overlay": "0.1.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"tsup": "^8.3.5",
|
|
43
|
+
"tsx": "^4.19.2",
|
|
44
|
+
"vitest": "^3.0.6"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsup",
|
|
48
|
+
"dev": "tsx src/index.ts",
|
|
49
|
+
"test": "vitest run --passWithNoTests",
|
|
50
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
51
|
+
"lint": "echo 'lint not configured'",
|
|
52
|
+
"clean": "rm -rf dist coverage"
|
|
53
|
+
}
|
|
54
|
+
}
|