patchwork-os 0.2.0-beta.0 → 0.2.0-beta.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.
Files changed (92) hide show
  1. package/README.md +4 -1
  2. package/dist/analyticsAggregator.d.ts +5 -1
  3. package/dist/analyticsAggregator.js +15 -4
  4. package/dist/analyticsAggregator.js.map +1 -1
  5. package/dist/analyticsPrefs.d.ts +11 -0
  6. package/dist/analyticsPrefs.js +33 -0
  7. package/dist/analyticsPrefs.js.map +1 -1
  8. package/dist/bridge.js +36 -26
  9. package/dist/bridge.js.map +1 -1
  10. package/dist/claudeDriver.d.ts +0 -16
  11. package/dist/claudeDriver.js +19 -20
  12. package/dist/claudeDriver.js.map +1 -1
  13. package/dist/claudeMdPatch.d.ts +9 -3
  14. package/dist/claudeMdPatch.js +79 -13
  15. package/dist/claudeMdPatch.js.map +1 -1
  16. package/dist/claudeOrchestrator.d.ts +12 -0
  17. package/dist/claudeOrchestrator.js +2 -0
  18. package/dist/claudeOrchestrator.js.map +1 -1
  19. package/dist/commands/marketplace.d.ts +15 -10
  20. package/dist/commands/marketplace.js +27 -115
  21. package/dist/commands/marketplace.js.map +1 -1
  22. package/dist/commitIssueLinkLog.d.ts +8 -0
  23. package/dist/commitIssueLinkLog.js +53 -1
  24. package/dist/commitIssueLinkLog.js.map +1 -1
  25. package/dist/config.d.ts +3 -3
  26. package/dist/config.js +13 -2
  27. package/dist/config.js.map +1 -1
  28. package/dist/connectorRoutes.js +63 -372
  29. package/dist/connectorRoutes.js.map +1 -1
  30. package/dist/connectors/jira.js +18 -1
  31. package/dist/connectors/jira.js.map +1 -1
  32. package/dist/drivers/claude/subprocess.d.ts +12 -2
  33. package/dist/drivers/claude/subprocess.js +79 -6
  34. package/dist/drivers/claude/subprocess.js.map +1 -1
  35. package/dist/drivers/gemini/api.d.ts +18 -0
  36. package/dist/drivers/gemini/api.js +29 -0
  37. package/dist/drivers/gemini/api.js.map +1 -0
  38. package/dist/drivers/index.d.ts +3 -1
  39. package/dist/drivers/index.js +9 -1
  40. package/dist/drivers/index.js.map +1 -1
  41. package/dist/drivers/local/index.d.ts +26 -0
  42. package/dist/drivers/local/index.js +41 -0
  43. package/dist/drivers/local/index.js.map +1 -0
  44. package/dist/httpErrorResponse.d.ts +36 -0
  45. package/dist/httpErrorResponse.js +46 -0
  46. package/dist/httpErrorResponse.js.map +1 -0
  47. package/dist/inboxRoutes.js +90 -11
  48. package/dist/inboxRoutes.js.map +1 -1
  49. package/dist/index.d.ts +1 -1
  50. package/dist/index.js +3 -2
  51. package/dist/index.js.map +1 -1
  52. package/dist/oauth.d.ts +13 -0
  53. package/dist/oauth.js +13 -0
  54. package/dist/oauth.js.map +1 -1
  55. package/dist/oauthRoutes.js +3 -8
  56. package/dist/oauthRoutes.js.map +1 -1
  57. package/dist/patchworkConfig.d.ts +14 -1
  58. package/dist/patchworkConfig.js +99 -4
  59. package/dist/patchworkConfig.js.map +1 -1
  60. package/dist/preToolUseHook.js +7 -1
  61. package/dist/preToolUseHook.js.map +1 -1
  62. package/dist/prompts.js +4 -0
  63. package/dist/prompts.js.map +1 -1
  64. package/dist/recipeOrchestration.js +13 -3
  65. package/dist/recipeOrchestration.js.map +1 -1
  66. package/dist/recipeRoutes.d.ts +5 -0
  67. package/dist/recipeRoutes.js +57 -33
  68. package/dist/recipeRoutes.js.map +1 -1
  69. package/dist/recipes/agentExecutor.d.ts +10 -1
  70. package/dist/recipes/agentExecutor.js +5 -4
  71. package/dist/recipes/agentExecutor.js.map +1 -1
  72. package/dist/recipes/tools/gmail.js +18 -1
  73. package/dist/recipes/tools/gmail.js.map +1 -1
  74. package/dist/recipes/yamlRunner.d.ts +15 -2
  75. package/dist/recipes/yamlRunner.js +11 -3
  76. package/dist/recipes/yamlRunner.js.map +1 -1
  77. package/dist/recipesHttp.d.ts +14 -0
  78. package/dist/recipesHttp.js +59 -1
  79. package/dist/recipesHttp.js.map +1 -1
  80. package/dist/server.d.ts +6 -0
  81. package/dist/server.js +249 -245
  82. package/dist/server.js.map +1 -1
  83. package/dist/tools/runCommand.js +5 -0
  84. package/dist/tools/runCommand.js.map +1 -1
  85. package/dist/tools/terminal.js +4 -0
  86. package/dist/tools/terminal.js.map +1 -1
  87. package/dist/tools/utils.d.ts +4 -0
  88. package/dist/tools/utils.js +59 -0
  89. package/dist/tools/utils.js.map +1 -1
  90. package/package.json +1 -1
  91. package/scripts/start-all.sh +4 -2
  92. package/templates/recipes/approval-queue-ui-test.yaml +205 -0
@@ -1,7 +1,9 @@
1
1
  import { ApiDriver } from "./claude/api.js";
2
2
  import { SubprocessDriver } from "./claude/subprocess.js";
3
+ import { GeminiApiDriver } from "./gemini/api.js";
3
4
  import { GeminiSubprocessDriver } from "./gemini/index.js";
4
5
  import { GrokApiDriver } from "./grok/index.js";
6
+ import { LocalApiDriver } from "./local/index.js";
5
7
  import { OpenAIApiDriver } from "./openai/index.js";
6
8
  /**
7
9
  * Create the appropriate driver from a mode string.
@@ -11,7 +13,7 @@ export function createDriver(mode, opts, log) {
11
13
  if (mode === "none")
12
14
  return null;
13
15
  if (mode === "subprocess")
14
- return new SubprocessDriver(opts.binary, opts.antBinary, log);
16
+ return new SubprocessDriver(opts.binary, opts.antBinary, log, opts.bridgeMcp);
15
17
  if (mode === "api")
16
18
  return new ApiDriver(log);
17
19
  if (mode === "openai")
@@ -20,12 +22,18 @@ export function createDriver(mode, opts, log) {
20
22
  return new GrokApiDriver(log);
21
23
  if (mode === "gemini")
22
24
  return new GeminiSubprocessDriver(opts.binary === "claude" ? "gemini" : opts.binary, log, opts.bridgeMcp);
25
+ if (mode === "gemini-api")
26
+ return new GeminiApiDriver(log);
27
+ if (mode === "local")
28
+ return new LocalApiDriver(log);
23
29
  throw new Error(`Unknown driver mode: ${mode}`);
24
30
  }
25
31
  export { ApiDriver } from "./claude/api.js";
26
32
  export { SubprocessDriver } from "./claude/subprocess.js";
33
+ export { GeminiApiDriver } from "./gemini/api.js";
27
34
  export { GeminiSubprocessDriver } from "./gemini/index.js";
28
35
  export { GrokApiDriver } from "./grok/index.js";
36
+ export { LocalApiDriver } from "./local/index.js";
29
37
  export { OpenAIApiDriver } from "./openai/index.js";
30
38
  export { toProviderTaskOutcome } from "./types.js";
31
39
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/drivers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAkBpD;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAgB,EAChB,IAAuB,EACvB,GAA0B;IAE1B,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,IAAI,KAAK,YAAY;QACvB,OAAO,IAAI,gBAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAChE,IAAI,IAAI,KAAK,KAAK;QAAE,OAAO,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC;IAC9C,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC;IACvD,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC;IACnD,IAAI,IAAI,KAAK,QAAQ;QACnB,OAAO,IAAI,sBAAsB,CAC/B,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EACjD,GAAG,EACH,IAAI,CAAC,SAAS,CACf,CAAC;IACJ,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC;AAClD,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAOpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/drivers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAoBpD;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAgB,EAChB,IAAuB,EACvB,GAA0B;IAE1B,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,IAAI,KAAK,YAAY;QACvB,OAAO,IAAI,gBAAgB,CACzB,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,SAAS,EACd,GAAG,EACH,IAAI,CAAC,SAAS,CACf,CAAC;IACJ,IAAI,IAAI,KAAK,KAAK;QAAE,OAAO,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC;IAC9C,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC;IACvD,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC;IACnD,IAAI,IAAI,KAAK,QAAQ;QACnB,OAAO,IAAI,sBAAsB,CAC/B,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EACjD,GAAG,EACH,IAAI,CAAC,SAAS,CACf,CAAC;IACJ,IAAI,IAAI,KAAK,YAAY;QAAE,OAAO,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC;IAC3D,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC;IACrD,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC;AAClD,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAOpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { OpenAIApiDriver } from "../openai/index.js";
2
+ /**
3
+ * Local LLM driver — Ollama, LM Studio, vLLM, llama.cpp server, and most
4
+ * other self-hosted runtimes expose an OpenAI-compatible chat-completions
5
+ * endpoint at /v1/chat/completions. Same trick as Grok / Gemini API:
6
+ * subclass OpenAIApiDriver with a different baseURL + default model.
7
+ *
8
+ * Auth: most local runtimes don't validate the API key, but the OpenAI SDK
9
+ * requires *something* in the apiKey field — we send a constant placeholder.
10
+ *
11
+ * Configuration: LOCAL_ENDPOINT and LOCAL_MODEL environment variables.
12
+ * The bridge auto-injects `patchwork.localEndpoint` / `patchwork.localModel`
13
+ * into these env vars at startup (see config.ts), so saving via the
14
+ * dashboard's Local LLM card flows straight through to the driver.
15
+ *
16
+ * Examples:
17
+ * Ollama → http://localhost:11434/v1
18
+ * LM Studio → http://localhost:1234/v1
19
+ * vLLM → http://localhost:8000/v1
20
+ * llama.cpp → http://localhost:8080/v1
21
+ */
22
+ export declare class LocalApiDriver extends OpenAIApiDriver {
23
+ readonly name = "local";
24
+ constructor(log: (msg: string) => void);
25
+ protected apiKey(): string | undefined;
26
+ }
@@ -0,0 +1,41 @@
1
+ import { OpenAIApiDriver } from "../openai/index.js";
2
+ /**
3
+ * Local LLM driver — Ollama, LM Studio, vLLM, llama.cpp server, and most
4
+ * other self-hosted runtimes expose an OpenAI-compatible chat-completions
5
+ * endpoint at /v1/chat/completions. Same trick as Grok / Gemini API:
6
+ * subclass OpenAIApiDriver with a different baseURL + default model.
7
+ *
8
+ * Auth: most local runtimes don't validate the API key, but the OpenAI SDK
9
+ * requires *something* in the apiKey field — we send a constant placeholder.
10
+ *
11
+ * Configuration: LOCAL_ENDPOINT and LOCAL_MODEL environment variables.
12
+ * The bridge auto-injects `patchwork.localEndpoint` / `patchwork.localModel`
13
+ * into these env vars at startup (see config.ts), so saving via the
14
+ * dashboard's Local LLM card flows straight through to the driver.
15
+ *
16
+ * Examples:
17
+ * Ollama → http://localhost:11434/v1
18
+ * LM Studio → http://localhost:1234/v1
19
+ * vLLM → http://localhost:8000/v1
20
+ * llama.cpp → http://localhost:8080/v1
21
+ */
22
+ export class LocalApiDriver extends OpenAIApiDriver {
23
+ name = "local";
24
+ constructor(log) {
25
+ const baseURL = process.env.LOCAL_ENDPOINT;
26
+ if (!baseURL) {
27
+ throw new Error("LocalApiDriver requires LOCAL_ENDPOINT environment variable (e.g. http://localhost:11434/v1)");
28
+ }
29
+ super(log, {
30
+ baseURL,
31
+ // Per-install default — caller can still override via input.model.
32
+ defaultModel: process.env.LOCAL_MODEL ?? "llama3.2",
33
+ });
34
+ }
35
+ apiKey() {
36
+ // Most local runtimes ignore the key but the OpenAI SDK requires a
37
+ // non-empty value. "ollama" is the conventional placeholder.
38
+ return process.env.LOCAL_API_KEY ?? "ollama";
39
+ }
40
+ }
41
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/drivers/local/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,OAAO,cAAe,SAAQ,eAAe;IAC/B,IAAI,GAAG,OAAO,CAAC;IAEjC,YAAY,GAA0B;QACpC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;QAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,8FAA8F,CAC/F,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,GAAG,EAAE;YACT,OAAO;YACP,mEAAmE;YACnE,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,UAAU;SACpD,CAAC,CAAC;IACL,CAAC;IAEkB,MAAM;QACvB,mEAAmE;QACnE,6DAA6D;QAC7D,OAAO,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,QAAQ,CAAC;IAC/C,CAAC;CACF"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Centralized HTTP error responder for the bridge's plain-`http` route
3
+ * handlers.
4
+ *
5
+ * Replaces the ~96 inline `res.end(JSON.stringify({error: err.message}))`
6
+ * blocks scattered across `server.ts`, `connectorRoutes.ts`,
7
+ * `recipeRoutes.ts`, `inboxRoutes.ts`, and `oauthRoutes.ts` — every one of
8
+ * which leaked the underlying error message (and sometimes a stack frame
9
+ * via `Error.toString`) to the network. CodeQL flagged each as
10
+ * `js/stack-trace-exposure` (89 open alerts at the time of writing).
11
+ *
12
+ * Contract:
13
+ * - Always returns a generic `{error: "Internal server error"}` body, never
14
+ * the underlying error.message — even for non-Error throws.
15
+ * - Logs the full detail (stack preferred, message fallback, String(err)
16
+ * last) to stderr with an optional context label so post-incident
17
+ * debugging is unaffected.
18
+ * - Idempotent on `headersSent` / `writableEnded` so callers nested inside
19
+ * other try/catch blocks can safely call this without re-throwing.
20
+ *
21
+ * Note: the dashboard's Next.js route handlers (`dashboard/src/app/api/**`)
22
+ * are a separate runtime — they use `NextResponse.json(...)` and have their
23
+ * own (smaller) leak surface; this helper is bridge-side only.
24
+ */
25
+ import type { ServerResponse } from "node:http";
26
+ /**
27
+ * Write a generic 500 response and log the underlying error detail
28
+ * server-side.
29
+ *
30
+ * @param res The Node http response to write to.
31
+ * @param err The thrown value caught by the route handler.
32
+ * @param context Optional short tag identifying the route ("recipes/lint",
33
+ * "connectors/jira/connect", etc.). Surfaces in the server
34
+ * log only — never sent to the client.
35
+ */
36
+ export declare function respond500(res: ServerResponse, err: unknown, context?: string): void;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Centralized HTTP error responder for the bridge's plain-`http` route
3
+ * handlers.
4
+ *
5
+ * Replaces the ~96 inline `res.end(JSON.stringify({error: err.message}))`
6
+ * blocks scattered across `server.ts`, `connectorRoutes.ts`,
7
+ * `recipeRoutes.ts`, `inboxRoutes.ts`, and `oauthRoutes.ts` — every one of
8
+ * which leaked the underlying error message (and sometimes a stack frame
9
+ * via `Error.toString`) to the network. CodeQL flagged each as
10
+ * `js/stack-trace-exposure` (89 open alerts at the time of writing).
11
+ *
12
+ * Contract:
13
+ * - Always returns a generic `{error: "Internal server error"}` body, never
14
+ * the underlying error.message — even for non-Error throws.
15
+ * - Logs the full detail (stack preferred, message fallback, String(err)
16
+ * last) to stderr with an optional context label so post-incident
17
+ * debugging is unaffected.
18
+ * - Idempotent on `headersSent` / `writableEnded` so callers nested inside
19
+ * other try/catch blocks can safely call this without re-throwing.
20
+ *
21
+ * Note: the dashboard's Next.js route handlers (`dashboard/src/app/api/**`)
22
+ * are a separate runtime — they use `NextResponse.json(...)` and have their
23
+ * own (smaller) leak surface; this helper is bridge-side only.
24
+ */
25
+ const GENERIC_BODY = JSON.stringify({ error: "Internal server error" });
26
+ /**
27
+ * Write a generic 500 response and log the underlying error detail
28
+ * server-side.
29
+ *
30
+ * @param res The Node http response to write to.
31
+ * @param err The thrown value caught by the route handler.
32
+ * @param context Optional short tag identifying the route ("recipes/lint",
33
+ * "connectors/jira/connect", etc.). Surfaces in the server
34
+ * log only — never sent to the client.
35
+ */
36
+ export function respond500(res, err, context) {
37
+ const detail = err instanceof Error ? (err.stack ?? err.message) : String(err);
38
+ console.error(`[http-500]${context ? ` ${context}` : ""}: ${detail}`);
39
+ if (!res.headersSent) {
40
+ res.writeHead(500, { "Content-Type": "application/json" });
41
+ }
42
+ if (!res.writableEnded) {
43
+ res.end(GENERIC_BODY);
44
+ }
45
+ }
46
+ //# sourceMappingURL=httpErrorResponse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpErrorResponse.js","sourceRoot":"","sources":["../src/httpErrorResponse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;AAExE;;;;;;;;;GASG;AACH,MAAM,UAAU,UAAU,CACxB,GAAmB,EACnB,GAAY,EACZ,OAAgB;IAEhB,MAAM,MAAM,GACV,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAClE,OAAO,CAAC,KAAK,CAAC,aAAa,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC,CAAC;IACtE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;QACrB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QACvB,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACxB,CAAC;AACH,CAAC"}
@@ -16,6 +16,24 @@
16
16
  import { existsSync } from "node:fs";
17
17
  import os from "node:os";
18
18
  import path from "node:path";
19
+ import { respond500 } from "./httpErrorResponse.js";
20
+ /**
21
+ * Filename guard shared by every inbox sub-route. Rejects directory
22
+ * separators and `..` segments so the request can never escape the inbox
23
+ * directory. Returns the joined absolute path on success, or null with the
24
+ * caller responsible for emitting a 400.
25
+ */
26
+ function safeInboxPath(filename) {
27
+ if (!filename)
28
+ return null;
29
+ if (filename.includes("/") || filename.includes("\\"))
30
+ return null;
31
+ if (filename === "." || filename === "..")
32
+ return null;
33
+ if (filename.startsWith("."))
34
+ return null; // no dotfiles, reserves `.archive/` namespace
35
+ return path.join(os.homedir(), ".patchwork", "inbox", filename);
36
+ }
19
37
  /**
20
38
  * Try to handle an `/inbox` or `/inbox/<filename>.md` route. Returns true
21
39
  * if the route was dispatched (caller should `return` from the request
@@ -61,10 +79,7 @@ export function tryHandleInboxRoute(req, res, parsedUrl) {
61
79
  res.end(JSON.stringify({ items }));
62
80
  }
63
81
  catch (err) {
64
- res.writeHead(500, { "Content-Type": "application/json" });
65
- res.end(JSON.stringify({
66
- error: err instanceof Error ? err.message : String(err),
67
- }));
82
+ respond500(res, err);
68
83
  }
69
84
  })();
70
85
  return true;
@@ -75,13 +90,12 @@ export function tryHandleInboxRoute(req, res, parsedUrl) {
75
90
  try {
76
91
  const { readFile, stat } = await import("node:fs/promises");
77
92
  const filename = decodeURIComponent(inboxFileMatch[1] ?? "");
78
- // Prevent path traversal — filename must not contain directory separators
79
- if (filename.includes("/") || filename.includes("\\")) {
93
+ const filePath = safeInboxPath(filename);
94
+ if (!filePath) {
80
95
  res.writeHead(400, { "Content-Type": "application/json" });
81
96
  res.end(JSON.stringify({ error: "Invalid filename" }));
82
97
  return;
83
98
  }
84
- const filePath = path.join(os.homedir(), ".patchwork", "inbox", filename);
85
99
  const [content, stats] = await Promise.all([
86
100
  readFile(filePath, "utf8"),
87
101
  stat(filePath),
@@ -100,10 +114,75 @@ export function tryHandleInboxRoute(req, res, parsedUrl) {
100
114
  res.end(JSON.stringify({ error: "Not found" }));
101
115
  }
102
116
  else {
103
- res.writeHead(500, { "Content-Type": "application/json" });
104
- res.end(JSON.stringify({
105
- error: err instanceof Error ? err.message : String(err),
106
- }));
117
+ respond500(res, err);
118
+ }
119
+ }
120
+ })();
121
+ return true;
122
+ }
123
+ if (inboxFileMatch && req.method === "DELETE") {
124
+ void (async () => {
125
+ try {
126
+ const { unlink } = await import("node:fs/promises");
127
+ const filename = decodeURIComponent(inboxFileMatch[1] ?? "");
128
+ const filePath = safeInboxPath(filename);
129
+ if (!filePath) {
130
+ res.writeHead(400, { "Content-Type": "application/json" });
131
+ res.end(JSON.stringify({ ok: false, error: "Invalid filename" }));
132
+ return;
133
+ }
134
+ await unlink(filePath);
135
+ res.writeHead(200, { "Content-Type": "application/json" });
136
+ res.end(JSON.stringify({ ok: true, path: filePath }));
137
+ }
138
+ catch (err) {
139
+ const code = err.code;
140
+ if (code === "ENOENT") {
141
+ res.writeHead(404, { "Content-Type": "application/json" });
142
+ res.end(JSON.stringify({ ok: false, error: "Not found" }));
143
+ }
144
+ else {
145
+ respond500(res, err);
146
+ }
147
+ }
148
+ })();
149
+ return true;
150
+ }
151
+ // POST /inbox/<filename>.md/archive — move to ~/.patchwork/inbox/.archive/
152
+ const inboxArchiveMatch = parsedUrl.pathname?.match(/^\/inbox\/([^/]+\.md)\/archive$/);
153
+ if (inboxArchiveMatch && req.method === "POST") {
154
+ void (async () => {
155
+ try {
156
+ const { mkdir, rename } = await import("node:fs/promises");
157
+ const filename = decodeURIComponent(inboxArchiveMatch[1] ?? "");
158
+ const filePath = safeInboxPath(filename);
159
+ if (!filePath) {
160
+ res.writeHead(400, { "Content-Type": "application/json" });
161
+ res.end(JSON.stringify({ ok: false, error: "Invalid filename" }));
162
+ return;
163
+ }
164
+ const archiveDir = path.join(os.homedir(), ".patchwork", "inbox", ".archive");
165
+ await mkdir(archiveDir, { recursive: true });
166
+ let dest = path.join(archiveDir, filename);
167
+ // Suffix with timestamp on collision so historical archives survive.
168
+ if (existsSync(dest)) {
169
+ const ext = path.extname(filename);
170
+ const stem = filename.slice(0, filename.length - ext.length);
171
+ const stamp = new Date().toISOString().replace(/[:.]/g, "-");
172
+ dest = path.join(archiveDir, `${stem}.${stamp}${ext}`);
173
+ }
174
+ await rename(filePath, dest);
175
+ res.writeHead(200, { "Content-Type": "application/json" });
176
+ res.end(JSON.stringify({ ok: true, path: dest }));
177
+ }
178
+ catch (err) {
179
+ const code = err.code;
180
+ if (code === "ENOENT") {
181
+ res.writeHead(404, { "Content-Type": "application/json" });
182
+ res.end(JSON.stringify({ ok: false, error: "Not found" }));
183
+ }
184
+ else {
185
+ respond500(res, err);
107
186
  }
108
187
  }
109
188
  })();
@@ -1 +1 @@
1
- {"version":3,"file":"inboxRoutes.js","sourceRoot":"","sources":["../src/inboxRoutes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"inboxRoutes.js","sourceRoot":"","sources":["../src/inboxRoutes.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- export { BRIDGE_BLOCK_END, BRIDGE_BLOCK_RE, bridgeBlockStartMarker, extractClaudeMdBlockVersion, patchClaudeMdImport, } from "./claudeMdPatch.js";
2
+ export { BRIDGE_BLOCK_END, bridgeBlockStartMarker, extractClaudeMdBlockVersion, patchClaudeMdImport, replaceAllBridgeBlocks, } from "./claudeMdPatch.js";
package/dist/index.js CHANGED
@@ -63,7 +63,7 @@ const OPEN_VSX_NAME = "claude-ide-bridge-extension";
63
63
  // CLAUDE.md versioned-block patching moved to ./claudeMdPatch.ts so tests
64
64
  // can import the helpers without triggering the top-level CLI side effects
65
65
  // at the bottom of this file. Re-exported here for back-compat.
66
- export { BRIDGE_BLOCK_END, BRIDGE_BLOCK_RE, bridgeBlockStartMarker, extractClaudeMdBlockVersion, patchClaudeMdImport, } from "./claudeMdPatch.js";
66
+ export { BRIDGE_BLOCK_END, bridgeBlockStartMarker, extractClaudeMdBlockVersion, patchClaudeMdImport, replaceAllBridgeBlocks, } from "./claudeMdPatch.js";
67
67
  import { extractClaudeMdBlockVersion, patchClaudeMdImport, } from "./claudeMdPatch.js";
68
68
  /**
69
69
  * Downloads the latest VSIX from Open VSX Registry to a temp file.
@@ -368,7 +368,8 @@ if (process.argv[2] === "install") {
368
368
  await runInstall(process.argv.slice(3));
369
369
  process.exit(0);
370
370
  }
371
- // Handle marketplace subcommand — browse and install community skills
371
+ // Handle marketplace subcommand — DEPRECATED, prints migration message.
372
+ // See issue #279 and src/commands/marketplace.ts for the rationale.
372
373
  if (process.argv[2] === "marketplace") {
373
374
  const { runMarketplace } = await import("./commands/marketplace.js");
374
375
  await runMarketplace(process.argv.slice(3));