@fabiofiorita/porcelain 0.66.0 → 0.67.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 (48) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/server/src/cli/main.mjs +72 -12
  4. package/web/dist/assets/_paired-Cf9W7w-r.js +1 -0
  5. package/web/dist/assets/_paired-DV6Uu96D.js +1 -0
  6. package/web/dist/assets/_paired-DdiJtBi7.js +1 -0
  7. package/web/dist/assets/_paired-DtZr8WeA.js +1 -0
  8. package/web/dist/assets/_section-BhA0KAGA.js +1 -0
  9. package/web/dist/assets/_worktreeId-Bn1qBq2T.js +1 -0
  10. package/web/dist/assets/_worktreeId-Cf9W7w-r.js +1 -0
  11. package/web/dist/assets/_worktreeId-D0bWoqgW.js +1 -0
  12. package/web/dist/assets/_worktreeId-DtZr8WeA.js +1 -0
  13. package/web/dist/assets/{access-PfkNUy8X.js → access-DKodjctH.js} +1 -1
  14. package/web/dist/assets/connected-workspace-B0v2QBMa.js +1 -0
  15. package/web/dist/assets/desktop-actions-xMY_-vix.js +11 -0
  16. package/web/dist/assets/{edit-file-DCY33r0N.js → edit-file-DpmO9xHx.js} +1 -1
  17. package/web/dist/assets/{file-editor-DqwC15Bu.js → file-editor-CSiOZ6Sd.js} +1 -1
  18. package/web/dist/assets/{files-DSu00eSD.js → files-De0CgA0d.js} +1 -1
  19. package/web/dist/assets/index-CTp3Y5lC.css +2 -0
  20. package/web/dist/assets/index-DL7Akkem.js +10 -0
  21. package/web/dist/assets/{lazyRouteComponent-BN1KZ2m_.js → lazyRouteComponent-D-Ru9boN.js} +1 -1
  22. package/web/dist/assets/{link-CHPttD8L.js → link-BtPdbBer.js} +1 -1
  23. package/web/dist/assets/pair-Datv-jBb.js +1 -0
  24. package/web/dist/assets/pair-DtZr8WeA.js +1 -0
  25. package/web/dist/assets/{search-BRNsqnzM.js → search-BYxM2Eui.js} +1 -1
  26. package/web/dist/assets/settings-page-BdwyGbHc.js +1345 -0
  27. package/web/dist/assets/useRouterState-B1-fsbiG.js +1 -0
  28. package/web/dist/assets/{workspace-error-6xgfcxxo.js → workspace-error-DZaV6KWv.js} +1 -1
  29. package/web/dist/assets/workspace-pending-BUZzjlSx.js +1 -0
  30. package/web/dist/index.html +10 -10
  31. package/web/dist/assets/_paired-BJ24myQ-.js +0 -1
  32. package/web/dist/assets/_paired-BOEAypIu.js +0 -1
  33. package/web/dist/assets/_paired-DWS716EI.js +0 -1
  34. package/web/dist/assets/_paired-kBv2c0H3.js +0 -1
  35. package/web/dist/assets/_section-C-I81Snm.js +0 -1
  36. package/web/dist/assets/_worktreeId-BJ24myQ-.js +0 -1
  37. package/web/dist/assets/_worktreeId-BOEAypIu.js +0 -1
  38. package/web/dist/assets/_worktreeId-CBPxjFcc.js +0 -1
  39. package/web/dist/assets/_worktreeId-D0zP3o0a.js +0 -1
  40. package/web/dist/assets/connected-workspace-ilTkoEvG.js +0 -1
  41. package/web/dist/assets/desktop-actions-yCl9eHIG.js +0 -11
  42. package/web/dist/assets/git-actions-CzAWomWn.js +0 -1345
  43. package/web/dist/assets/index-BLk_t8u4.css +0 -2
  44. package/web/dist/assets/index-BkIFSmjE.js +0 -10
  45. package/web/dist/assets/pair-BJ24myQ-.js +0 -1
  46. package/web/dist/assets/pair-D18DAPBg.js +0 -1
  47. package/web/dist/assets/useRouterState-CMqkVuYp.js +0 -1
  48. package/web/dist/assets/workspace-pending-BgHnZ1Rw.js +0 -1
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # @fabiofiorita/porcelain (0.66.0)
1
+ # @fabiofiorita/porcelain (0.67.0)
2
2
 
3
3
  The Porcelain review server and bundled web app for a plain Node installation.
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fabiofiorita/porcelain",
3
- "version": "0.66.0",
3
+ "version": "0.67.0",
4
4
  "description": "Review coding agents’ changes from a browser, Mac or phone",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -2986,7 +2986,7 @@ import { NodeRuntime } from "@effect/platform-node";
2986
2986
  import {
2987
2987
  Cause as Cause3,
2988
2988
  ConfigProvider,
2989
- Console,
2989
+ Console as Console2,
2990
2990
  Context as Context75,
2991
2991
  Effect as Effect58,
2992
2992
  Exit as Exit3,
@@ -7525,7 +7525,7 @@ var readCliVersion = Effect26.fn("Cli.readVersion")(function* (packageRoot) {
7525
7525
  });
7526
7526
 
7527
7527
  // apps/server/src/cli/cli-program.ts
7528
- import { Effect as Effect57, Ref as Ref3, Result as Result6 } from "effect";
7528
+ import { Console, Effect as Effect57, Ref as Ref3, Result as Result6 } from "effect";
7529
7529
  import { CliError, Command as Command2 } from "effect/cli";
7530
7530
 
7531
7531
  // apps/server/src/cli/command-tree.ts
@@ -9385,6 +9385,9 @@ var openServiceUpdateRunner = Effect44.fn("openServiceUpdateRunner")(
9385
9385
  return answer2 === "active" || answer2 === "activating";
9386
9386
  }
9387
9387
  );
9388
+ const updateRunning = Effect44.fn("ServiceUpdate.updateRunning")(function* (managed) {
9389
+ return preparing || managed && ((yield* directoryLockIsHeld(`${paths.updater}.lock`)) || (yield* updaterActive()));
9390
+ });
9388
9391
  const latestVersion = Effect44.fn("ServiceUpdate.latestVersion")(function* (input, running) {
9389
9392
  const known = latest;
9390
9393
  if (known !== void 0 && (running || known.checkedAt >= input.staleBefore))
@@ -9432,18 +9435,17 @@ var openServiceUpdateRunner = Effect44.fn("openServiceUpdateRunner")(
9432
9435
  function* (input) {
9433
9436
  const version = yield* runningVersion();
9434
9437
  const managed = version !== void 0 && options.packageRoot === pathApi.join(paths.runtime, "node_modules", PACKAGE_NAME) && (yield* exists(paths.installed));
9435
- const running = preparing || managed && ((yield* directoryLockIsHeld(`${paths.updater}.lock`)) || (yield* updaterActive()));
9436
- const published = managed ? yield* latestVersion(input, running) : void 0;
9438
+ const initiallyRunning = yield* updateRunning(managed);
9439
+ const published = managed ? yield* latestVersion(input, initiallyRunning) : void 0;
9440
+ const record = yield* readUpdateRecord(paths.updateRecord);
9441
+ const running = initiallyRunning || record !== void 0 && (yield* updateRunning(managed));
9437
9442
  return {
9438
9443
  managed,
9439
9444
  version,
9440
9445
  latest: published,
9441
9446
  available: published !== void 0 && version !== void 0 && (yield* compareVersions(published, version)) > 0,
9442
9447
  running,
9443
- last: presentedUpdate(
9444
- yield* readUpdateRecord(paths.updateRecord),
9445
- running
9446
- )
9448
+ last: presentedUpdate(record, running)
9447
9449
  };
9448
9450
  },
9449
9451
  provideFiles,
@@ -10874,6 +10876,19 @@ var mcp = Command.make(
10874
10876
  ).pipe(
10875
10877
  Command.withDescription("Serve MCP over the local owner socket for an agent")
10876
10878
  );
10879
+ var desktopMcpCommand = Command.make(
10880
+ "porcelain-mcp",
10881
+ {
10882
+ dataDirectory: Flag.String("data-directory").pipe(
10883
+ Flag.withSchema(absolutePathSchema2),
10884
+ Flag.withDescription("Server data directory of the running desktop app")
10885
+ )
10886
+ },
10887
+ Effect56.fn("Cli.desktopMcpCommand")(function* (input) {
10888
+ const operations2 = yield* CliOperations;
10889
+ yield* operations2.mcp(input);
10890
+ })
10891
+ ).pipe(Command.withDescription("Connect an agent to the running desktop app"));
10877
10892
  var shareHandler = Effect56.fn("Cli.shareCommand")(function* (action) {
10878
10893
  const operations2 = yield* CliOperations;
10879
10894
  yield* finish(
@@ -11011,9 +11026,20 @@ var porcelainCommand = rootConfiguration.pipe(
11011
11026
  );
11012
11027
 
11013
11028
  // apps/server/src/cli/cli-program.ts
11014
- var cliProgram = Effect57.fn("Cli.run")(function* (args, version) {
11029
+ var cliProgram = Effect57.fn("Cli.run")(function* (args, version, mode = "server") {
11015
11030
  const exitCode = yield* Ref3.make(0);
11016
- yield* Command2.runWith(porcelainCommand, { version })(args).pipe(
11031
+ const program = mode === "desktop-mcp" ? Command2.runWith(desktopMcpCommand, { version })(args) : Command2.runWith(porcelainCommand, { version })(args);
11032
+ const console2 = yield* Console.Console;
11033
+ const presentation = new Proxy(console2, {
11034
+ get(target, property, receiver) {
11035
+ if (mode === "desktop-mcp" && property === "log")
11036
+ return (...values) => target.error(...values);
11037
+ const value2 = Reflect.get(target, property, receiver);
11038
+ return value2;
11039
+ }
11040
+ });
11041
+ yield* program.pipe(
11042
+ Effect57.provideService(Console.Console, presentation),
11017
11043
  Effect57.provideService(CliExit, exitCode),
11018
11044
  Effect57.provideService(CliVersion, version),
11019
11045
  Effect57.catchFilter(
@@ -11088,11 +11114,17 @@ function createCliRunner(runtime, platform) {
11088
11114
  const program = Effect58.gen(function* () {
11089
11115
  const configured = yield* CliRuntime;
11090
11116
  return yield* Effect58.gen(function* () {
11117
+ if (options.desktopMcpVersion !== void 0)
11118
+ return yield* cliProgram(
11119
+ args,
11120
+ options.desktopMcpVersion,
11121
+ "desktop-mcp"
11122
+ );
11091
11123
  const packageRoot = yield* cliPackageRoot();
11092
11124
  const version = yield* readCliVersion(packageRoot).pipe(Effect58.orDie);
11093
11125
  return yield* cliProgram(args, version);
11094
11126
  }).pipe(
11095
- Effect58.provideService(Console.Console, output2),
11127
+ Effect58.provideService(Console2.Console, output2),
11096
11128
  Effect58.provide(services),
11097
11129
  Effect58.catchCause(
11098
11130
  (cause) => Cause3.hasInterruptsOnly(cause) ? Effect58.interrupt : Effect58.sync(() => {
@@ -15853,6 +15885,20 @@ var events = channel("porcelain.http");
15853
15885
  function httpEvent(event) {
15854
15886
  events.publish(event);
15855
15887
  }
15888
+ function toolAudit(tool) {
15889
+ return Effect152.flatMap(
15890
+ Effect152.serviceOption(RequestContext),
15891
+ (context) => Effect152.sync(() => {
15892
+ if (context._tag === "Some" && context.value.principal?.kind === "owner")
15893
+ httpEvent({
15894
+ event: "tool-handled",
15895
+ owner: true,
15896
+ id: context.value.requestId,
15897
+ tool
15898
+ });
15899
+ })
15900
+ );
15901
+ }
15856
15902
  var handlerAudit = HttpRouter3.middleware(
15857
15903
  (app) => Effect152.flatMap(Effect152.serviceOption(RequestContext), (context) => {
15858
15904
  if (context._tag === "Some")
@@ -20863,7 +20909,7 @@ var agent = { kind: "agent" };
20863
20909
  var summaryWarnings = {
20864
20910
  "missing-style": "No authored CSS was detected in the summary HTML. The review was published. Add CSS and republish, matching the reviewed application\u2019s colors, background, typography and components where possible. Style the layer links and content hierarchy, then visually verify the result. If styles are generated at runtime, verify that they load correctly."
20865
20911
  };
20866
- function invocation(operation) {
20912
+ function invocation(tool, operation) {
20867
20913
  return Effect228.gen(function* () {
20868
20914
  const request2 = yield* Effect228.serviceOption(
20869
20915
  HttpServerRequest2.HttpServerRequest
@@ -20876,6 +20922,7 @@ function invocation(operation) {
20876
20922
  message: "The x-porcelain-cwd header is required"
20877
20923
  })
20878
20924
  );
20925
+ yield* toolAudit(tool);
20879
20926
  return yield* operation(cwd);
20880
20927
  }).pipe(
20881
20928
  Effect228.mapError(
@@ -20890,9 +20937,16 @@ function invocation(operation) {
20890
20937
  function reviewMcpHandlers(useCases) {
20891
20938
  return Layer152.mergeAll(
20892
20939
  McpServer.toolkit(ReviewToolkit).pipe(
20940
+ Layer152.tap(
20941
+ () => Effect228.sync(() => {
20942
+ for (const tool of Object.keys(ReviewToolkit.tools))
20943
+ httpEvent({ event: "tool-registered", owner: true, tool });
20944
+ })
20945
+ ),
20893
20946
  Layer152.provide(
20894
20947
  ReviewToolkit.toLayer({
20895
20948
  publish_review: ({ cwd, ...review }) => invocation(
20949
+ "publish_review",
20896
20950
  (defaultCwd) => Effect228.gen(function* () {
20897
20951
  const published = yield* useCases.reviewTools.atWorktreePath.execute({
20898
20952
  operation: useCases.reviewTools.publishReview,
@@ -20908,6 +20962,7 @@ function reviewMcpHandlers(useCases) {
20908
20962
  })
20909
20963
  ),
20910
20964
  delete_review: ({ cwd }) => invocation(
20965
+ "delete_review",
20911
20966
  (defaultCwd) => useCases.reviewTools.atWorktreePath.execute({
20912
20967
  operation: useCases.reviewTools.deleteReview,
20913
20968
  cwd: cwd ?? defaultCwd,
@@ -20915,6 +20970,7 @@ function reviewMcpHandlers(useCases) {
20915
20970
  })
20916
20971
  ),
20917
20972
  read_review: ({ cwd }) => invocation(
20973
+ "read_review",
20918
20974
  (defaultCwd) => useCases.reviewTools.atWorktreePath.execute({
20919
20975
  operation: useCases.reviewTools.readPublishedReview,
20920
20976
  cwd: cwd ?? defaultCwd,
@@ -20922,6 +20978,7 @@ function reviewMcpHandlers(useCases) {
20922
20978
  })
20923
20979
  ),
20924
20980
  list_comments: ({ cwd, scope }) => invocation(
20981
+ "list_comments",
20925
20982
  (defaultCwd) => Effect228.map(
20926
20983
  useCases.reviewTools.atWorktreePath.execute({
20927
20984
  operation: useCases.reviewTools.listCommentThreads,
@@ -20932,6 +20989,7 @@ function reviewMcpHandlers(useCases) {
20932
20989
  )
20933
20990
  ),
20934
20991
  create_comment: ({ cwd, ...input }) => invocation(
20992
+ "create_comment",
20935
20993
  (defaultCwd) => useCases.reviewTools.atWorktreePath.execute({
20936
20994
  operation: useCases.reviewTools.createCommentThread,
20937
20995
  cwd: cwd ?? defaultCwd,
@@ -20939,6 +20997,7 @@ function reviewMcpHandlers(useCases) {
20939
20997
  })
20940
20998
  ),
20941
20999
  reply_to_comment: ({ cwd, ...input }) => invocation(
21000
+ "reply_to_comment",
20942
21001
  (defaultCwd) => useCases.reviewTools.atWorktreePath.execute({
20943
21002
  operation: useCases.reviewTools.replyToComment,
20944
21003
  cwd: cwd ?? defaultCwd,
@@ -20946,6 +21005,7 @@ function reviewMcpHandlers(useCases) {
20946
21005
  })
20947
21006
  ),
20948
21007
  resolve_comment: ({ cwd, ...input }) => invocation(
21008
+ "resolve_comment",
20949
21009
  (defaultCwd) => useCases.reviewTools.atWorktreePath.execute({
20950
21010
  operation: useCases.reviewTools.updateCommentThread,
20951
21011
  cwd: cwd ?? defaultCwd,
@@ -0,0 +1 @@
1
+ import{t as e}from"./workspace-error-DZaV6KWv.js";var t=e;export{t as errorComponent};
@@ -0,0 +1 @@
1
+ import{r as e}from"./rolldown-runtime-hePW80VL.js";import{hi as t,li as n,mi as r}from"./files-De0CgA0d.js";import{Ct as i}from"./access-DKodjctH.js";import{r as a}from"./link-BtPdbBer.js";import{t as o}from"./useRouterState-B1-fsbiG.js";import{B as s,I as c,V as l,ln as u}from"./settings-page-BdwyGbHc.js";import{a as d,t as f}from"./desktop-actions-xMY_-vix.js";import{o as p}from"./index-DL7Akkem.js";var m=e(t(),1),h=n(),g=r();function _(e){let t=(0,h.c)(3),{children:n}=e,r;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,g.jsx)(u,{}),t[0]=r):r=t[0];let i;return t[1]===n?i=t[2]:(i=(0,g.jsxs)(g.Fragment,{children:[r,(0,g.jsx)(d,{children:n})]}),t[1]=n,t[2]=i),i}function v(e){let t=(0,h.c)(6),{children:n}=e,[r,a]=(0,m.useState)(!0),o=i(),u;t[0]===o?u=t[1]:(u=o&&(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(s,{connection:o}),(0,g.jsx)(l,{connection:o})]}),t[0]=o,t[1]=u);let d;return t[2]!==n||t[3]!==r||t[4]!==u?(d=(0,g.jsx)(_,{children:(0,g.jsxs)(c,{open:r,onOpenChange:a,children:[n,u]})}),t[2]=n,t[3]=r,t[4]=u,t[5]=d):d=t[5],d}function y(){let e=(0,h.c)(4),t=i(),n;e[0]===Symbol.for(`react.memo_cache_sentinel`)?(n={select:b},e[0]=n):n=e[0];let r=o(n),s;return e[1]!==t||e[2]!==r?(s=t?(0,g.jsxs)(v,{children:[(0,g.jsx)(p,{}),(0,g.jsx)(f,{connection:t,empty:r})]}):(0,g.jsx)(a,{to:`/pair`,replace:!0}),e[1]=t,e[2]=r,e[3]=s):s=e[3],s}function b(e){return e.location.pathname===`/`}export{y as component};
@@ -0,0 +1 @@
1
+ import{li as e,mi as t}from"./files-De0CgA0d.js";import{St as n}from"./access-DKodjctH.js";import{r}from"./link-BtPdbBer.js";import{t as i}from"./useRouterState-B1-fsbiG.js";import{Et as a,Tt as o,xt as s}from"./settings-page-BdwyGbHc.js";import{i as c}from"./index-DL7Akkem.js";import{t as l}from"./connected-workspace-B0v2QBMa.js";var u=e(),d=t();function f(){let e=(0,u.c)(18),t=c.useSearch(),f,m;e[0]===t?(f=e[1],m=e[2]):({worktree:m,...f}=t,e[0]=t,e[1]=f,e[2]=m);let h;e[3]===Symbol.for(`react.memo_cache_sentinel`)?(h={select:p},e[3]=h):h=e[3];let g=i(h),{connection:_}=n(),v=s(_),y;e[4]!==v||e[5]!==m?(y=m===void 0?a(v,o(v)?.id):a(v,m),e[4]=v,e[5]=m,e[6]=y):y=e[6];let b=y;if(b&&g){let t;e[7]!==b.projectId||e[8]!==b.worktree.id?(t={projectId:b.projectId,worktreeId:b.worktree.id},e[7]=b.projectId,e[8]=b.worktree.id,e[9]=t):t=e[9];let n;e[10]!==f||e[11]!==m?(n=m===void 0?{}:f,e[10]=f,e[11]=m,e[12]=n):n=e[12];let i;return e[13]!==t||e[14]!==n?(i=(0,d.jsx)(r,{to:`/$projectId/$worktreeId`,params:t,search:n,replace:!0}),e[13]=t,e[14]=n,e[15]=i):i=e[15],i}let x=m!==void 0&&g,S;return e[16]===x?S=e[17]:(S=(0,d.jsx)(l,{missing:x}),e[16]=x,e[17]=S),S}function p(e){return e.status===`idle`&&e.location.pathname===`/`}export{f as component};
@@ -0,0 +1 @@
1
+ import{t as e}from"./workspace-error-DZaV6KWv.js";var t=e;export{t as errorComponent};
@@ -0,0 +1 @@
1
+ import{li as e,mi as t}from"./files-De0CgA0d.js";import{t as n}from"./settings-page-BdwyGbHc.js";import{n as r}from"./index-DL7Akkem.js";var i=e(),a=t();function o(){let e=(0,i.c)(2),{section:t}=r.useParams(),o;return e[0]===t?o=e[1]:(o=(0,a.jsx)(n,{section:t}),e[0]=t,e[1]=o),o}export{o as component};
@@ -0,0 +1 @@
1
+ import{li as e,mi as t}from"./files-De0CgA0d.js";import{wt as n}from"./access-DKodjctH.js";import{r}from"./link-BtPdbBer.js";import"./settings-page-BdwyGbHc.js";import"./workspace-pending-BUZzjlSx.js";import{t as i}from"./index-DL7Akkem.js";import"./connected-workspace-B0v2QBMa.js";var a=e(),o=t();function s(){let e=(0,a.c)(9),{environmentId:t,projectId:s,worktreeId:c}=i.useParams(),l=i.useSearch();n(t);{let t;return e[0]!==l||e[1]!==c?(t=(0,o.jsx)(r,{to:`/`,search:{...l,worktree:c},replace:!0}),e[0]=l,e[1]=c,e[2]=t):t=e[2],t}}export{s as component};
@@ -0,0 +1 @@
1
+ import{t as e}from"./workspace-error-DZaV6KWv.js";var t=e;export{t as errorComponent};
@@ -0,0 +1 @@
1
+ import{li as e,mi as t}from"./files-De0CgA0d.js";import{St as n}from"./access-DKodjctH.js";import{r}from"./link-BtPdbBer.js";import{Et as i,xt as a}from"./settings-page-BdwyGbHc.js";import{r as o}from"./index-DL7Akkem.js";import{t as s}from"./connected-workspace-B0v2QBMa.js";var c=e(),l=t();function u(){let e=(0,c.c)(10),{projectId:t,worktreeId:u}=o.useParams(),d=o.useSearch(),{connection:f}=n(),p=a(f),m;e[0]!==p||e[1]!==u?(m=i(p,u),e[0]=p,e[1]=u,e[2]=m):m=e[2];let h=m;if(h?.projectId!==t){let t;return e[3]!==d||e[4]!==u?(t=(0,l.jsx)(r,{to:`/`,search:{...d,worktree:u},replace:!0}),e[3]=d,e[4]=u,e[5]=t):t=e[5],t}let g;return e[6]!==p||e[7]!==d||e[8]!==h?(g=(0,l.jsx)(s,{review:{selection:h,search:d,inventory:p}}),e[6]=p,e[7]=d,e[8]=h,e[9]=g):g=e[9],g}export{u as component};
@@ -0,0 +1 @@
1
+ import{t as e}from"./workspace-error-DZaV6KWv.js";var t=e;export{t as errorComponent};