@sealant/mend 0.11.1 → 0.12.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.
package/dist/dashboard.js CHANGED
@@ -157,7 +157,7 @@ const SessionDetail = ({ item }) => {
157
157
  const { session, annotation, services } = item;
158
158
  const color = STATUS_COLOR[session.status] ?? MUTED;
159
159
  const summary = session.summary?.split("\n")[0] ?? null;
160
- return (_jsxs(_Fragment, { children: [_jsxs("text", { height: 1, bg: "transparent", children: [_jsx("span", { children: " " }), _jsx("span", { fg: color, children: session.status }), _jsx("span", { fg: FAINT, children: " \u00B7 " }), _jsx("span", { fg: MUTED, children: session.branch }), _jsxs("span", { fg: FAINT, children: [session.baseSha === "" ? "" : ` vs ${session.baseSha.slice(0, 12)}`, " \u00B7 started", " ", timeAgo(session.createdAt)] })] }), _jsxs("text", { height: 1, bg: "transparent", children: [_jsx("span", { children: " " }), services.length === 0 ? (_jsx("span", { fg: FAINT, children: "no services running" })) : (services.slice(0, 3).map((service, index) => (_jsxs("span", { children: [index > 0 ? _jsx("span", { fg: FAINT, children: " \u00B7 " }) : null, _jsx("span", { fg: service.status === "reachable" ? INK_2 : MUTED, children: `${service.label ?? service.id.slice(0, 6)} :${service.workspacePort ?? "?"}${service.protocol === "udp" ? "u" : ""}→${service.hostPort ?? "?"} ${service.status}` })] }, service.id)))), services.length > 3 ? _jsx("span", { fg: FAINT, children: ` · +${services.length - 3} more` }) : null] }), _jsxs("text", { height: 1, bg: "transparent", children: [_jsx("span", { children: " " }), annotation === undefined || annotation.openComments === 0 ? (_jsx("span", { fg: FAINT, children: "no open review comments" })) : (_jsxs("span", { fg: INK_2, children: [annotation.openComments, " open comment", annotation.openComments === 1 ? "" : "s"] })), annotation?.pendingFollowUp === true ? (_jsxs(_Fragment, { children: [_jsx("span", { fg: FAINT, children: " \u00B7 " }), _jsx("span", { fg: INK_2, children: "follow-up pending" })] })) : null, annotation?.changeId != null ? (_jsxs(_Fragment, { children: [_jsx("span", { fg: FAINT, children: " \u00B7 " }), _jsx("span", { fg: MUTED, children: "v reviews the change" })] })) : null] }), _jsx("text", { height: 1, bg: "transparent", fg: summary === null ? FAINT : MUTED, children: ` ${summary ?? "no summary yet"}` })] }));
160
+ return (_jsxs(_Fragment, { children: [_jsxs("text", { height: 1, bg: "transparent", children: [_jsx("span", { children: " " }), _jsx("span", { fg: color, children: session.status }), _jsx("span", { fg: FAINT, children: " \u00B7 " }), _jsx("span", { fg: MUTED, children: session.branch }), _jsxs("span", { fg: FAINT, children: [session.baseSha === "" ? "" : ` vs ${session.baseRef ?? session.baseSha.slice(0, 12)}`, " \u00B7 started ", timeAgo(session.createdAt)] })] }), _jsxs("text", { height: 1, bg: "transparent", children: [_jsx("span", { children: " " }), services.length === 0 ? (_jsx("span", { fg: FAINT, children: "no services running" })) : (services.slice(0, 3).map((service, index) => (_jsxs("span", { children: [index > 0 ? _jsx("span", { fg: FAINT, children: " \u00B7 " }) : null, _jsx("span", { fg: service.status === "reachable" ? INK_2 : MUTED, children: `${service.label ?? service.id.slice(0, 6)} :${service.workspacePort ?? "?"}${service.protocol === "udp" ? "u" : ""}→${service.hostPort ?? "?"} ${service.status}` })] }, service.id)))), services.length > 3 ? _jsx("span", { fg: FAINT, children: ` · +${services.length - 3} more` }) : null] }), _jsxs("text", { height: 1, bg: "transparent", children: [_jsx("span", { children: " " }), annotation === undefined || annotation.openComments === 0 ? (_jsx("span", { fg: FAINT, children: "no open review comments" })) : (_jsxs("span", { fg: INK_2, children: [annotation.openComments, " open comment", annotation.openComments === 1 ? "" : "s"] })), annotation?.pendingFollowUp === true ? (_jsxs(_Fragment, { children: [_jsx("span", { fg: FAINT, children: " \u00B7 " }), _jsx("span", { fg: INK_2, children: "follow-up pending" })] })) : null, annotation?.changeId != null ? (_jsxs(_Fragment, { children: [_jsx("span", { fg: FAINT, children: " \u00B7 " }), _jsx("span", { fg: MUTED, children: "v reviews the change" })] })) : null] }), _jsx("text", { height: 1, bg: "transparent", fg: summary === null ? FAINT : MUTED, children: ` ${summary ?? "no summary yet"}` })] }));
161
161
  };
162
162
  const StatusLine = ({ busy, busyStarted, status, }) => {
163
163
  const [now, setNow] = useState(() => Date.now());
@@ -324,6 +324,7 @@ const App = ({ ctx, onQuit }) => {
324
324
  label: null,
325
325
  branch: "provisioning…",
326
326
  baseSha: "",
327
+ baseRef: null,
327
328
  status: "starting",
328
329
  summary: null,
329
330
  createdAt: new Date().toISOString(),
package/dist/main.js CHANGED
@@ -253,7 +253,8 @@ const launch = async (config, harness, args) => {
253
253
  base: parsed.base,
254
254
  });
255
255
  say(`${green("✓")} worktree ${session.worktree} ${dim(`· branch ${session.branch}`)}`);
256
- say(`${green("✓")} base ${dim(session.baseSha.slice(0, 12))} · session ${dim(session.id.slice(0, 8))}`);
256
+ const baseWord = session.baseRef === null ? "" : `${session.baseRef} `;
257
+ say(`${green("✓")} base ${baseWord}${dim(session.baseSha.slice(0, 12))} · session ${dim(session.id.slice(0, 8))}`);
257
258
  say(`${cobalt(" watch")} · ${config.url}/sessions/${session.id}`);
258
259
  // Everything runs SUPERVISED (SDK 0.7.0): a workspace mounts the worktree,
259
260
  // a platform PTY runs argv, the record begins. Commands tail the record;
@@ -1578,7 +1579,7 @@ _mend() {
1578
1579
  'connect:send this machine'"'"'s claude/codex/github credential to the platform'
1579
1580
  'continue:resume with the pending follow-up' 'resume:rejoin a settled session'
1580
1581
  'rejoin:attach if live, otherwise resume'
1581
- 'projects:adopted projects' 'sessions:sessions with review facts' 'status:active sessions'
1582
+ 'refresh:fetch origin branches into the store' 'projects:adopted projects' 'sessions:sessions with review facts' 'status:active sessions'
1582
1583
  'ui:the dashboard' 'help:help'
1583
1584
  )
1584
1585
  if (( CURRENT == 2 )); then
@@ -1598,7 +1599,7 @@ _mend "$@"
1598
1599
  const BASH_COMPLETIONS = `_mend() {
1599
1600
  local cur=\${COMP_WORDS[COMP_CWORD]}
1600
1601
  if [ "$COMP_CWORD" -eq 1 ]; then
1601
- COMPREPLY=( $(compgen -W "adopt codex claude opencode run attach shell service keys pair doctor continue resume rejoin projects sessions status ui help" -- "$cur") )
1602
+ COMPREPLY=( $(compgen -W "adopt codex claude opencode run attach shell service keys pair doctor continue resume rejoin refresh projects sessions status ui help" -- "$cur") )
1602
1603
  return
1603
1604
  fi
1604
1605
  case \${COMP_WORDS[1]} in
@@ -1884,6 +1885,23 @@ const projectsCommand = async (config) => {
1884
1885
  if (here !== undefined)
1885
1886
  say(dim(` ▸ ${here.name} is the cwd's project`));
1886
1887
  };
1888
+ /**
1889
+ * `mend refresh [project]`: fetch every origin branch into the project's
1890
+ * store (new sessions base on current tips), then show what it holds. The
1891
+ * project resolves like the launch commands: named, or the cwd's.
1892
+ */
1893
+ const refreshCommand = async (config, args) => {
1894
+ const explicit = args.find((a) => !a.startsWith("--")) ?? takeFlagValue(args, "--project");
1895
+ const project = await findProject(config, explicit ?? null);
1896
+ const branches = await api(config, "POST", `/projects/${project.id}/refresh`);
1897
+ say(`${green("✓")} refreshed ${project.name} ${dim(`· ${branches.length} branches`)}`);
1898
+ for (const branch of branches.slice(0, 12)) {
1899
+ const marker = branch.isDefault ? cobalt("▸ ") : " ";
1900
+ say(`${marker}${branch.name} ${dim(branch.sha.slice(0, 12))} ${dim(branch.committedAt.slice(0, 10))}`);
1901
+ }
1902
+ if (branches.length > 12)
1903
+ say(dim(` … ${branches.length - 12} more`));
1904
+ };
1887
1905
  const printSessionRow = (row) => {
1888
1906
  const { session, annotation } = row;
1889
1907
  const live = ACTIVE_STATUSES.has(session.status);
@@ -1896,7 +1914,8 @@ const printSessionRow = (row) => {
1896
1914
  }
1897
1915
  if (annotation !== undefined && annotation.pendingFollowUp)
1898
1916
  facts.push(amber("follow-up pending"));
1899
- say(`${session.harness.padEnd(8)} ${dim(session.id.slice(0, 8))} ${live ? green(status) : dim(status)} ${row.projectName} ${dim(session.branch)}${facts.length > 0 ? ` ${facts.join(dim(" · "))}` : ""}`);
1917
+ const base = session.baseRef === null ? session.baseSha.slice(0, 12) : session.baseRef;
1918
+ say(`${session.harness.padEnd(8)} ${dim(session.id.slice(0, 8))} ${live ? green(status) : dim(status)} ${row.projectName} ${dim(`${session.branch} · base ${base}`)}${facts.length > 0 ? ` ${facts.join(dim(" · "))}` : ""}`);
1900
1919
  };
1901
1920
  /**
1902
1921
  * Active sessions by default; --all sweeps every project's detail so settled
@@ -1959,6 +1978,7 @@ const sessionsCommand = async (config, args) => {
1959
1978
  worktree: session.worktree,
1960
1979
  branch: session.branch,
1961
1980
  baseSha: session.baseSha,
1981
+ baseRef: session.baseRef,
1962
1982
  status: session.status,
1963
1983
  summary: session.summary,
1964
1984
  createdAt: session.createdAt,
@@ -2075,6 +2095,8 @@ everything else
2075
2095
  mend continue [session-id] resume a session with its pending review follow-up
2076
2096
  mend resume [session-id] [--with h] rejoin a settled session (state restored; --with switches harness)
2077
2097
  mend rejoin [session-id] [--harness h] attach if live, otherwise resume; newest live wins
2098
+ mend refresh [project] fetch origin's branches into the store — new sessions
2099
+ base on current tips (default: the cwd's project)
2078
2100
  mend projects adopted projects and their live sessions
2079
2101
  mend sessions [--all] [--project p] [--json]
2080
2102
  sessions with review facts; JSON is stable for integrations
@@ -2140,6 +2162,8 @@ const main = async () => {
2140
2162
  return rejoinCommand(config, rest);
2141
2163
  case "projects":
2142
2164
  return projectsCommand(config);
2165
+ case "refresh":
2166
+ return refreshCommand(config, rest);
2143
2167
  case "sessions":
2144
2168
  case "status":
2145
2169
  return sessionsCommand(config, rest);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sealant/mend",
3
- "version": "0.11.1",
3
+ "version": "0.12.1",
4
4
  "description": "The mend CLI: adopt a repository into Mend's store, launch your coding agent in a recorded session worktree, detach and reattach from any terminal",
5
5
  "keywords": [
6
6
  "claude-code",