@sealant/mend 0.30.0 → 0.31.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/dist/{chunk-BMFB2UN7.js → chunk-J3TR4UAG.js} +81 -7
- package/dist/{dashboard-OF5UXII2.js → dashboard-3HNFSQZD.js} +60 -7
- package/dist/main.js +157 -11
- package/man/mend-accounts.1 +1 -1
- package/man/mend-adopt.1 +1 -1
- package/man/mend-attach.1 +1 -1
- package/man/mend-codex.1 +1 -1
- package/man/mend-completions.1 +1 -1
- package/man/mend-connect.1 +1 -1
- package/man/mend-continue.1 +1 -1
- package/man/mend-doctor.1 +1 -1
- package/man/mend-dotfiles-repo.1 +1 -1
- package/man/mend-dotfiles-sync.1 +1 -1
- package/man/mend-dotfiles.1 +1 -1
- package/man/mend-env-cluster.1 +1 -1
- package/man/mend-env-load.1 +1 -1
- package/man/mend-env-show.1 +1 -1
- package/man/mend-folder-create.1 +1 -1
- package/man/mend-folder-list.1 +1 -1
- package/man/mend-folder-push.1 +1 -1
- package/man/mend-folder-rm.1 +1 -1
- package/man/mend-git-author.1 +24 -0
- package/man/mend-help.1 +1 -1
- package/man/mend-invite.1 +1 -1
- package/man/mend-keys-init.1 +1 -1
- package/man/mend-keys-mode.1 +1 -1
- package/man/mend-keys-share.1 +1 -1
- package/man/mend-keys-show.1 +1 -1
- package/man/mend-land.1 +9 -2
- package/man/mend-login.1 +1 -1
- package/man/mend-logout.1 +1 -1
- package/man/mend-man.1 +1 -1
- package/man/mend-members.1 +1 -1
- package/man/mend-operator-exposure.1 +1 -1
- package/man/mend-operator-gate.1 +1 -1
- package/man/mend-operator-grant-owner.1 +1 -1
- package/man/mend-operator-org-create.1 +1 -1
- package/man/mend-operator-org-invite-owner.1 +1 -1
- package/man/mend-operator-org-list.1 +1 -1
- package/man/mend-operator-org-rename.1 +1 -1
- package/man/mend-operator-reset-link.1 +1 -1
- package/man/mend-pair.1 +1 -1
- package/man/mend-projects.1 +1 -1
- package/man/mend-pull.1 +1 -1
- package/man/mend-refresh.1 +1 -1
- package/man/mend-rejoin.1 +1 -1
- package/man/mend-resume.1 +1 -1
- package/man/mend-run.1 +1 -1
- package/man/mend-server-logs.1 +1 -1
- package/man/mend-server-restart.1 +1 -1
- package/man/mend-server-setup.1 +1 -1
- package/man/mend-server-start.1 +1 -1
- package/man/mend-server-status.1 +1 -1
- package/man/mend-server-stop.1 +1 -1
- package/man/mend-server-upgrade.1 +1 -1
- package/man/mend-server.1 +1 -1
- package/man/mend-service-add.1 +1 -1
- package/man/mend-service-connect.1 +1 -1
- package/man/mend-service-init.1 +1 -1
- package/man/mend-service-list.1 +1 -1
- package/man/mend-service-logs.1 +1 -1
- package/man/mend-service-restart.1 +1 -1
- package/man/mend-service-run.1 +1 -1
- package/man/mend-service-stop.1 +1 -1
- package/man/mend-session-share.1 +1 -1
- package/man/mend-sessions.1 +1 -1
- package/man/mend-shell.1 +1 -1
- package/man/mend-skills-push.1 +1 -1
- package/man/mend-skills.1 +1 -1
- package/man/mend-snake.1 +1 -1
- package/man/mend-ssh-setup.1 +1 -1
- package/man/mend-ssh.1 +1 -1
- package/man/mend-stop.1 +8 -1
- package/man/mend-ui.1 +2 -2
- package/man/mend-uninstall.1 +1 -1
- package/man/mend-version.1 +1 -1
- package/man/mend-worktrees.1 +1 -1
- package/man/mend.1 +5 -2
- package/package.json +1 -1
|
@@ -26817,7 +26817,9 @@ var AuditAction = Schema_exports.Literals([
|
|
|
26817
26817
|
// `gh` spoke as them.
|
|
26818
26818
|
"change.landed",
|
|
26819
26819
|
"change.pull_request_refreshed",
|
|
26820
|
-
"change.bundle_downloaded"
|
|
26820
|
+
"change.bundle_downloaded",
|
|
26821
|
+
// A pull request opened outside Mend was read with the owner's `gh` and recorded.
|
|
26822
|
+
"change.pull_request_adopted"
|
|
26821
26823
|
]);
|
|
26822
26824
|
var AuditData = Schema_exports.Record(
|
|
26823
26825
|
Schema_exports.String,
|
|
@@ -26841,8 +26843,14 @@ var AuditEvent = class extends Schema_exports.Class("AuditEvent")({
|
|
|
26841
26843
|
};
|
|
26842
26844
|
|
|
26843
26845
|
// ../../packages/domain/src/workbench/landing.ts
|
|
26844
|
-
var LandingTrigger = Schema_exports.Literals(["manual", "automatic"]);
|
|
26845
|
-
var LandingOutcome = Schema_exports.Literals([
|
|
26846
|
+
var LandingTrigger = Schema_exports.Literals(["manual", "automatic", "adopted"]);
|
|
26847
|
+
var LandingOutcome = Schema_exports.Literals([
|
|
26848
|
+
"pushed",
|
|
26849
|
+
"pull-request",
|
|
26850
|
+
"refused",
|
|
26851
|
+
"failed",
|
|
26852
|
+
"adopted"
|
|
26853
|
+
]);
|
|
26846
26854
|
var PullRequestState = Schema_exports.Literals(["open", "closed", "merged"]);
|
|
26847
26855
|
var LandedPullRequest = Schema_exports.Struct({
|
|
26848
26856
|
number: Schema_exports.Int,
|
|
@@ -26868,6 +26876,19 @@ var ChangeLanding = class extends Schema_exports.Class("ChangeLanding")({
|
|
|
26868
26876
|
pushedSha: Schema_exports.NullOr(Sha),
|
|
26869
26877
|
trigger: LandingTrigger,
|
|
26870
26878
|
pullRequest: Schema_exports.NullOr(LandedPullRequest),
|
|
26879
|
+
/**
|
|
26880
|
+
* The pull request's head is in another repository (a fork): Mend pushes to origin only, so it
|
|
26881
|
+
* never updates such a pull request. Older servers omit it.
|
|
26882
|
+
*/
|
|
26883
|
+
pullRequestCrossRepository: Schema_exports.Boolean.pipe(
|
|
26884
|
+
Schema_exports.withDecodingDefaultKey(Effect_exports.succeed(false)),
|
|
26885
|
+
Schema_exports.withConstructorDefault(Effect_exports.succeed(false))
|
|
26886
|
+
),
|
|
26887
|
+
/** Who owns the repository the pull request's head is in, as `gh` reported it; null unknown. */
|
|
26888
|
+
pullRequestHeadOwner: Schema_exports.NullOr(Schema_exports.String).pipe(
|
|
26889
|
+
Schema_exports.withDecodingDefaultKey(Effect_exports.succeed(null)),
|
|
26890
|
+
Schema_exports.withConstructorDefault(Effect_exports.succeed(null))
|
|
26891
|
+
),
|
|
26871
26892
|
outcome: LandingOutcome,
|
|
26872
26893
|
/** The remote's or `gh`'s own words for a refusal or a failure; null otherwise. */
|
|
26873
26894
|
message: Schema_exports.NullOr(Schema_exports.String),
|
|
@@ -26915,7 +26936,11 @@ var LandingFact = Schema_exports.Union([
|
|
|
26915
26936
|
Schema_exports.TaggedStruct("pull-request", {
|
|
26916
26937
|
number: Schema_exports.Int,
|
|
26917
26938
|
state: PullRequestState,
|
|
26918
|
-
observedAt: Timestamp
|
|
26939
|
+
observedAt: Timestamp,
|
|
26940
|
+
/** Opened outside Mend and adopted. Older servers omit it. */
|
|
26941
|
+
outside: Schema_exports.Boolean.pipe(Schema_exports.withDecodingDefaultKey(Effect_exports.succeed(false))),
|
|
26942
|
+
/** The fork's owner when its head is in another repository; null for origin's own. */
|
|
26943
|
+
fork: Schema_exports.NullOr(Schema_exports.String).pipe(Schema_exports.withDecodingDefaultKey(Effect_exports.succeed(null)))
|
|
26919
26944
|
}),
|
|
26920
26945
|
/** A fetch found commits on origin's branch that Mend's branch does not have. */
|
|
26921
26946
|
Schema_exports.TaggedStruct("origin-moved", { branch: Schema_exports.String, commits: Schema_exports.Int }),
|
|
@@ -26956,7 +26981,7 @@ var landingFactLine = (fact, now2) => {
|
|
|
26956
26981
|
case "pushed":
|
|
26957
26982
|
return `pushed \xB7 ${fact.branch} \xB7 ${shortSha(fact.sha)} \xB7 observed`;
|
|
26958
26983
|
case "pull-request":
|
|
26959
|
-
return `pull request #${fact.number} \xB7 ${fact.state} \xB7 observed ${observedAgo(fact.observedAt, now2)}
|
|
26984
|
+
return `pull request #${fact.number} \xB7 ${fact.state} \xB7 observed ${observedAgo(fact.observedAt, now2)}` + (fact.outside ? " \xB7 opened outside Mend" : "") + (fact.fork === null ? "" : ` \xB7 from ${fact.fork === "" ? "a fork" : `${fact.fork}'s fork`}`);
|
|
26960
26985
|
case "origin-moved":
|
|
26961
26986
|
return `origin has moved \xB7 ${fact.branch} has ${plural(fact.commits, "commit", "commits")} Mend has not seen`;
|
|
26962
26987
|
case "changed-since-landing":
|
|
@@ -27258,6 +27283,37 @@ var FolderFile = class extends Schema_exports.Class("FolderFile")({
|
|
|
27258
27283
|
var FOLDER_MAX_FILE_BYTES = 1024 * 1024;
|
|
27259
27284
|
var FOLDER_MAX_REQUEST_BYTES = 4 * 1024 * 1024;
|
|
27260
27285
|
|
|
27286
|
+
// ../../packages/domain/src/workbench/git-author.ts
|
|
27287
|
+
var GitAuthorSource = Schema_exports.Literals(["setting", "account"]);
|
|
27288
|
+
var GitAuthor = class extends Schema_exports.Class("GitAuthor")({
|
|
27289
|
+
name: Schema_exports.String,
|
|
27290
|
+
email: Schema_exports.String
|
|
27291
|
+
}) {
|
|
27292
|
+
};
|
|
27293
|
+
var ResolvedGitAuthor = class extends Schema_exports.Class("ResolvedGitAuthor")({
|
|
27294
|
+
name: Schema_exports.String,
|
|
27295
|
+
email: Schema_exports.String,
|
|
27296
|
+
source: GitAuthorSource
|
|
27297
|
+
}) {
|
|
27298
|
+
};
|
|
27299
|
+
var GIT_AUTHOR_MAX_LENGTH = 200;
|
|
27300
|
+
var normalizeGitAuthor = (author) => new GitAuthor({ name: author.name.trim(), email: author.email.trim() });
|
|
27301
|
+
var gitAuthorIssue = (author) => {
|
|
27302
|
+
const { name, email } = normalizeGitAuthor(author);
|
|
27303
|
+
if (name === "") return "the name is empty";
|
|
27304
|
+
if (email === "") return "the email is empty";
|
|
27305
|
+
if (name.length > GIT_AUTHOR_MAX_LENGTH) {
|
|
27306
|
+
return `the name is longer than ${GIT_AUTHOR_MAX_LENGTH} characters`;
|
|
27307
|
+
}
|
|
27308
|
+
if (email.length > GIT_AUTHOR_MAX_LENGTH) {
|
|
27309
|
+
return `the email is longer than ${GIT_AUTHOR_MAX_LENGTH} characters`;
|
|
27310
|
+
}
|
|
27311
|
+
if (/[<>\r\n]/.test(name)) return "the name contains <, > or a line break";
|
|
27312
|
+
if (!/^[^\s<>@]+@[^\s<>@]+$/.test(email))
|
|
27313
|
+
return "the email is not an address like you@example.com";
|
|
27314
|
+
return null;
|
|
27315
|
+
};
|
|
27316
|
+
|
|
27261
27317
|
// ../../packages/domain/src/workbench/review-slice.ts
|
|
27262
27318
|
var DiffDigest = Schema_exports.String.pipe(
|
|
27263
27319
|
Schema_exports.check(Schema_exports.isPattern(/^[0-9a-f]{64}$/)),
|
|
@@ -27563,13 +27619,14 @@ var ProjectLink = class extends Schema_exports.Class("ProjectLink")({
|
|
|
27563
27619
|
|
|
27564
27620
|
// ../../packages/domain/src/workbench/pass.ts
|
|
27565
27621
|
var PassKind = Schema_exports.Literals(["tour", "read", "suggest"]);
|
|
27566
|
-
var PassStatus = Schema_exports.Literals(["running", "completed", "failed"]);
|
|
27622
|
+
var PassStatus = Schema_exports.Literals(["queued", "running", "completed", "failed"]);
|
|
27567
27623
|
var ChangePass = class extends Schema_exports.Class("ChangePass")({
|
|
27568
27624
|
changeId: ChangeId,
|
|
27569
27625
|
kind: PassKind,
|
|
27570
27626
|
status: PassStatus,
|
|
27571
27627
|
detail: Schema_exports.NullOr(Schema_exports.String),
|
|
27572
27628
|
findings: Schema_exports.NullOr(Schema_exports.Int),
|
|
27629
|
+
/** When it began running; for a `queued` row, when it was queued. */
|
|
27573
27630
|
startedAt: Timestamp,
|
|
27574
27631
|
finishedAt: Schema_exports.NullOr(Timestamp)
|
|
27575
27632
|
}) {
|
|
@@ -27599,7 +27656,7 @@ var ProjectClusterBindingsSnapshot = class extends Schema_exports.Class(
|
|
|
27599
27656
|
}) {
|
|
27600
27657
|
};
|
|
27601
27658
|
|
|
27602
|
-
// ../../node_modules/.pnpm/@sealant+api-contracts@0.37.
|
|
27659
|
+
// ../../node_modules/.pnpm/@sealant+api-contracts@0.37.1_effect@4.0.0-beta.93/node_modules/@sealant/api-contracts/dist/workspace-environment.js
|
|
27603
27660
|
var RESERVED_NAMES = new Map([
|
|
27604
27661
|
// Identity/process roots the daemon and shells own.
|
|
27605
27662
|
...[
|
|
@@ -27934,12 +27991,20 @@ var ServiceView = class extends Schema_exports.Class("ServiceView")({
|
|
|
27934
27991
|
}) {
|
|
27935
27992
|
};
|
|
27936
27993
|
|
|
27994
|
+
// ../../packages/domain/src/workbench/session-fold.ts
|
|
27995
|
+
var servicesHoldLine = (input) => {
|
|
27996
|
+
if (input.agentLive || input.liveServices <= 0) return null;
|
|
27997
|
+
const hold = input.liveServices === 1 ? "1 service keeps the workspace up" : `${input.liveServices} services keep the workspace up`;
|
|
27998
|
+
return input.agentOutcome === null ? hold : `agent ${input.agentOutcome} \xB7 ${hold}`;
|
|
27999
|
+
};
|
|
28000
|
+
|
|
27937
28001
|
// ../../packages/domain/src/workbench/session-control.ts
|
|
27938
28002
|
var SessionControlKind = Schema_exports.Literals([
|
|
27939
28003
|
"interrupt",
|
|
27940
28004
|
"terminal-attach",
|
|
27941
28005
|
"shell-open",
|
|
27942
28006
|
"stop",
|
|
28007
|
+
"services-stop",
|
|
27943
28008
|
"shared-control-on",
|
|
27944
28009
|
"shared-control-off"
|
|
27945
28010
|
]);
|
|
@@ -28315,6 +28380,11 @@ var agentOutcome = (currentAgent) => {
|
|
|
28315
28380
|
if (currentAgent.harness === "shell") return "completed";
|
|
28316
28381
|
return currentAgent.exitCode === null || currentAgent.exitCode === 0 ? "completed" : "failed";
|
|
28317
28382
|
};
|
|
28383
|
+
var servicesHoldOf = (session, currentAgent, liveServices) => servicesHoldLine({
|
|
28384
|
+
agentLive: agentIsLive(session, currentAgent),
|
|
28385
|
+
agentOutcome: agentOutcome(currentAgent),
|
|
28386
|
+
liveServices
|
|
28387
|
+
});
|
|
28318
28388
|
var normalizeRemoteUrl = (raw) => {
|
|
28319
28389
|
if (raw === null) return null;
|
|
28320
28390
|
const trimmed = raw.trim();
|
|
@@ -28454,6 +28524,9 @@ export {
|
|
|
28454
28524
|
narrowCredential,
|
|
28455
28525
|
claudeGrantFacts,
|
|
28456
28526
|
sameGrant,
|
|
28527
|
+
normalizeGitAuthor,
|
|
28528
|
+
gitAuthorIssue,
|
|
28529
|
+
servicesHoldLine,
|
|
28457
28530
|
HARNESS_COMMANDS,
|
|
28458
28531
|
pendingId,
|
|
28459
28532
|
isPendingId,
|
|
@@ -28463,6 +28536,7 @@ export {
|
|
|
28463
28536
|
LIVE_STATUSES,
|
|
28464
28537
|
agentIsLive,
|
|
28465
28538
|
agentOutcome,
|
|
28539
|
+
servicesHoldOf,
|
|
28466
28540
|
normalizeRemoteUrl,
|
|
28467
28541
|
matchProjectByCwd,
|
|
28468
28542
|
cwdFacts,
|
|
@@ -2,6 +2,8 @@ import {
|
|
|
2
2
|
HARNESS_COMMANDS,
|
|
3
3
|
LIVE_STATUSES,
|
|
4
4
|
RepositoryCloneUrl,
|
|
5
|
+
agentIsLive,
|
|
6
|
+
agentOutcome,
|
|
5
7
|
createSseParser,
|
|
6
8
|
cwdFacts,
|
|
7
9
|
eventFamilies,
|
|
@@ -9,8 +11,9 @@ import {
|
|
|
9
11
|
matchProjectByCwd,
|
|
10
12
|
normalizeProjectName,
|
|
11
13
|
pendingId,
|
|
12
|
-
repositoryCloneUrlIssue
|
|
13
|
-
|
|
14
|
+
repositoryCloneUrlIssue,
|
|
15
|
+
servicesHoldLine
|
|
16
|
+
} from "./chunk-J3TR4UAG.js";
|
|
14
17
|
|
|
15
18
|
// src/dashboard.tsx
|
|
16
19
|
import { CliRenderEvents, createCliRenderer } from "@opentui/core";
|
|
@@ -267,17 +270,31 @@ var createLaunchGate = () => {
|
|
|
267
270
|
var markSessionStopped = (data, sessionId) => {
|
|
268
271
|
const processesBySession = new Map(data.processesBySession);
|
|
269
272
|
processesBySession.delete(sessionId);
|
|
270
|
-
const servicesBySession = new Map(data.servicesBySession);
|
|
271
|
-
servicesBySession.delete(sessionId);
|
|
272
273
|
return {
|
|
273
274
|
...mapWorkbenchSessions(
|
|
274
275
|
data,
|
|
275
276
|
(session) => session.id === sessionId ? { ...session, status: "stopped" } : session
|
|
276
277
|
),
|
|
277
|
-
processesBySession
|
|
278
|
-
servicesBySession
|
|
278
|
+
processesBySession
|
|
279
279
|
};
|
|
280
280
|
};
|
|
281
|
+
var markServicesStopped = (data, sessionId) => {
|
|
282
|
+
const servicesBySession = new Map(data.servicesBySession);
|
|
283
|
+
servicesBySession.delete(sessionId);
|
|
284
|
+
return { ...data, servicesBySession };
|
|
285
|
+
};
|
|
286
|
+
var AGENT_WORKING = /* @__PURE__ */ new Set(["starting", "running", "waiting"]);
|
|
287
|
+
var sessionHold = (item) => {
|
|
288
|
+
const agent = item.annotation?.currentAgent ?? null;
|
|
289
|
+
const agentProcessLive = item.processes.some(
|
|
290
|
+
(process2) => process2.kind !== "shell" && process2.exitedAt === null
|
|
291
|
+
);
|
|
292
|
+
return servicesHoldLine({
|
|
293
|
+
agentLive: agent === null ? agentProcessLive || AGENT_WORKING.has(item.session.status) : agentIsLive(item.session, agent),
|
|
294
|
+
agentOutcome: agentOutcome(agent),
|
|
295
|
+
liveServices: Math.max(item.annotation?.liveServices ?? 0, item.services.length)
|
|
296
|
+
});
|
|
297
|
+
};
|
|
281
298
|
var removeWorktreeGroup = (data, projectId, group) => {
|
|
282
299
|
const memberIds = new Set(group.sessions.map((item) => item.session.id));
|
|
283
300
|
const detail = data.details.get(projectId);
|
|
@@ -995,6 +1012,7 @@ var stateColor = (state) => state === "draft" || state === "open" ? INK : state
|
|
|
995
1012
|
var anchorOf = (comment) => comment.file === null ? "change" : `${comment.file}${comment.line === null ? "" : `:${comment.line}${comment.endLine === null || comment.endLine === comment.line ? "" : `-${comment.endLine}`}`}`;
|
|
996
1013
|
var passFact = (pass) => {
|
|
997
1014
|
const label = pass.kind === "suggest" ? "suggestions" : pass.kind;
|
|
1015
|
+
if (pass.status === "queued") return { text: `${label} queued`, color: MUTED };
|
|
998
1016
|
if (pass.status === "running") return { text: `${label} running`, color: INK_2 };
|
|
999
1017
|
if (pass.status === "failed") return { text: `${label} failed`, color: ERROR };
|
|
1000
1018
|
return {
|
|
@@ -2257,13 +2275,15 @@ var SessionRow = ({
|
|
|
2257
2275
|
const shells = processes.filter((process2) => process2.kind === "shell").length;
|
|
2258
2276
|
const nameWidth = Math.max(6, width - 5 - status.length);
|
|
2259
2277
|
const factWidth = Math.max(8, width - 3);
|
|
2278
|
+
const hold = sessionHold(item);
|
|
2260
2279
|
const facts = fitHints(
|
|
2261
2280
|
[
|
|
2281
|
+
...hold === null ? [] : [hold],
|
|
2262
2282
|
session.harness,
|
|
2263
2283
|
shortAge(session.createdAt),
|
|
2264
2284
|
...shells > 0 ? [`${shells} shell`] : [],
|
|
2265
2285
|
...agents > 0 ? [`${agents} agent`] : [],
|
|
2266
|
-
...services.length > 0 ? [`${services.length} service`] : []
|
|
2286
|
+
...hold === null && services.length > 0 ? [`${services.length} service`] : []
|
|
2267
2287
|
],
|
|
2268
2288
|
factWidth
|
|
2269
2289
|
);
|
|
@@ -2315,6 +2335,7 @@ var SessionFacts = ({
|
|
|
2315
2335
|
}) => {
|
|
2316
2336
|
const { session, annotation, services } = item;
|
|
2317
2337
|
const color = STATUS_COLOR[session.status] ?? MUTED;
|
|
2338
|
+
const hold = sessionHold(item);
|
|
2318
2339
|
const summary = session.summary?.split("\n")[0] ?? null;
|
|
2319
2340
|
const change = annotation ?? group?.annotation;
|
|
2320
2341
|
const lines = [
|
|
@@ -2326,6 +2347,10 @@ var SessionFacts = ({
|
|
|
2326
2347
|
/* @__PURE__ */ jsxs3("text", { height: 1, bg: "transparent", children: [
|
|
2327
2348
|
/* @__PURE__ */ jsx3("span", { children: " " }),
|
|
2328
2349
|
/* @__PURE__ */ jsx3("span", { fg: color, children: session.status }),
|
|
2350
|
+
hold === null ? null : /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
2351
|
+
/* @__PURE__ */ jsx3("span", { fg: FAINT, children: " \xB7 " }),
|
|
2352
|
+
/* @__PURE__ */ jsx3("span", { fg: INK_2, children: hold })
|
|
2353
|
+
] }),
|
|
2329
2354
|
/* @__PURE__ */ jsx3("span", { fg: FAINT, children: " \xB7 " }),
|
|
2330
2355
|
/* @__PURE__ */ jsx3("span", { fg: MUTED, children: session.branch }),
|
|
2331
2356
|
/* @__PURE__ */ jsx3("span", { fg: FAINT, children: session.baseSha === "" ? "" : ` vs ${session.baseRef ?? session.baseSha.slice(0, 12)}` })
|
|
@@ -2779,6 +2804,23 @@ ${tunneled}
|
|
|
2779
2804
|
},
|
|
2780
2805
|
onSettled: settleRefetch
|
|
2781
2806
|
});
|
|
2807
|
+
const stopServicesMutation = useMutation2({
|
|
2808
|
+
mutationFn: (session) => ctx.api("POST", `/sessions/${session.id}/services/stop`),
|
|
2809
|
+
onMutate: async (session) => {
|
|
2810
|
+
await queryClient.cancelQueries({ queryKey: WORKBENCH_KEY });
|
|
2811
|
+
patchWorkbench((current) => markServicesStopped(current, session.id));
|
|
2812
|
+
},
|
|
2813
|
+
onSuccess: (result, session) => {
|
|
2814
|
+
say(
|
|
2815
|
+
`stopped ${result.stopped} service${result.stopped === 1 ? "" : "s"} \xB7 ${sessionDisplayName(session)} \u2014 the workspace ends once nothing is live`
|
|
2816
|
+
);
|
|
2817
|
+
},
|
|
2818
|
+
onError: (error) => {
|
|
2819
|
+
say(errorText(error));
|
|
2820
|
+
refetch();
|
|
2821
|
+
},
|
|
2822
|
+
onSettled: settleRefetch
|
|
2823
|
+
});
|
|
2782
2824
|
const stopMutation = useMutation2({
|
|
2783
2825
|
mutationFn: (session) => ctx.api("POST", `/sessions/${session.id}/stop`),
|
|
2784
2826
|
onMutate: async (session) => {
|
|
@@ -2943,6 +2985,17 @@ ${tunneled}
|
|
|
2943
2985
|
}
|
|
2944
2986
|
const session = selectedSession;
|
|
2945
2987
|
if (session === null || isPendingId(session.id)) return;
|
|
2988
|
+
const hold = selectedItem === null ? null : sessionHold(selectedItem);
|
|
2989
|
+
if (hold !== null) {
|
|
2990
|
+
if (stopArmed === `svc:${session.id}` && confirmationVisible("press \u21E7K again")) {
|
|
2991
|
+
setStopArmed(null);
|
|
2992
|
+
stopServicesMutation.mutate(session);
|
|
2993
|
+
return;
|
|
2994
|
+
}
|
|
2995
|
+
setStopArmed(`svc:${session.id}`);
|
|
2996
|
+
say(`press \u21E7K again to stop the services \xB7 ${sessionDisplayName(session)} \u2014 ${hold}`);
|
|
2997
|
+
return;
|
|
2998
|
+
}
|
|
2946
2999
|
if (!LIVE_STATUSES.has(session.status)) {
|
|
2947
3000
|
say("nothing to stop \u2014 the session is settled");
|
|
2948
3001
|
return;
|
package/dist/main.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
claudeGrantFacts,
|
|
8
8
|
createSseParser,
|
|
9
9
|
cwdFacts,
|
|
10
|
+
gitAuthorIssue,
|
|
10
11
|
gitCurrentBranch,
|
|
11
12
|
gitOriginUrl,
|
|
12
13
|
gitTopLevel,
|
|
@@ -16,15 +17,17 @@ import {
|
|
|
16
17
|
landingFactsFromWire,
|
|
17
18
|
matchProjectByCwd,
|
|
18
19
|
narrowCredential,
|
|
20
|
+
normalizeGitAuthor,
|
|
19
21
|
normalizeProjectName,
|
|
20
22
|
normalizeRemoteUrl,
|
|
21
23
|
parseLaunchArgs,
|
|
22
24
|
pasteBytes,
|
|
23
25
|
repositoryCloneUrlIssue,
|
|
24
26
|
sameGrant,
|
|
27
|
+
servicesHoldOf,
|
|
25
28
|
sessionDisplayName,
|
|
26
29
|
trackBracketedPaste
|
|
27
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-J3TR4UAG.js";
|
|
28
31
|
|
|
29
32
|
// src/main.ts
|
|
30
33
|
import { spawn as spawn3, spawnSync as spawnSync4 } from "node:child_process";
|
|
@@ -698,6 +701,21 @@ var formatLoadReport = (report, paint6) => {
|
|
|
698
701
|
return lines;
|
|
699
702
|
};
|
|
700
703
|
|
|
704
|
+
// src/git-author.ts
|
|
705
|
+
var parseGitAuthorArgs = (args) => {
|
|
706
|
+
const clear = args.includes("--clear");
|
|
707
|
+
const words = args.filter((arg) => !arg.startsWith("--"));
|
|
708
|
+
if (clear) return words.length === 0 ? { kind: "clear" } : { kind: "usage" };
|
|
709
|
+
if (words.length === 0) return { kind: "show" };
|
|
710
|
+
const [name, email] = words;
|
|
711
|
+
if (words.length !== 2 || name === void 0 || email === void 0) return { kind: "usage" };
|
|
712
|
+
const issue = gitAuthorIssue({ name, email });
|
|
713
|
+
if (issue !== null) return { kind: "invalid", message: `git author not saved \xB7 ${issue}` };
|
|
714
|
+
const author = normalizeGitAuthor({ name, email });
|
|
715
|
+
return { kind: "set", name: author.name, email: author.email };
|
|
716
|
+
};
|
|
717
|
+
var gitAuthorLine = (author) => `${author.name} <${author.email}> \xB7 ${author.source === "setting" ? "your setting" : "your account's name and email"}`;
|
|
718
|
+
|
|
701
719
|
// src/help.ts
|
|
702
720
|
var SECTIONS = [
|
|
703
721
|
"start",
|
|
@@ -862,7 +880,7 @@ var COMMANDS = [
|
|
|
862
880
|
synopsis: ["[--no-tunnel]"],
|
|
863
881
|
description: [
|
|
864
882
|
"A full-screen view of every project and session, updating live. The session pane takes three quarters of the screen: a read-only detail for the selected session with the conversation record it has written so far. The remaining quarter is a sidebar of three stacked sections, projects then worktrees then sessions, where the section you are in stands open and the other two fold to the line that says what is selected. Bare mend with no command opens the same thing.",
|
|
865
|
-
"Moving the selection only ever navigates: arrows or j/k move inside the open section, enter and the arrows move between the sidebar and the session pane, and nothing takes this terminal until you ask. Reading the record leaves the sidebar as it was. The verbs are a to attach a live session, r to resume a settled one, n for another session in the selected worktree, w for a new worktree, e to rename, v to review the change, o to open it in the browser, Shift+K to stop, Shift+D to remove, and Shift+R to refresh.",
|
|
883
|
+
"Moving the selection only ever navigates: arrows or j/k move inside the open section, enter and the arrows move between the sidebar and the session pane, and nothing takes this terminal until you ask. Reading the record leaves the sidebar as it was. The verbs are a to attach a live session, r to resume a settled one, n for another session in the selected worktree, w for a new worktree, e to rename, v to review the change, o to open it in the browser, Shift+K to stop (on a row whose agent has stopped while its Services keep the workspace up, Shift+K stops those Services), Shift+D to remove, and Shift+R to refresh.",
|
|
866
884
|
"Nothing is ever squeezed. A terminal too narrow for both gives the whole width to the side you are on, a terminal too short for three drawn panes shows the open section alone, and a one-line breadcrumb states whatever did not fit.",
|
|
867
885
|
"On a server that is not this machine, the selected session's live Services declared --http or --https are tunneled to this machine's loopback while it stays selected, and the session pane shows where each one opens, for example web \u2192 http://localhost:5173.",
|
|
868
886
|
"The dashboard needs Node 26 or newer for its terminal. Every other command works on Node 22."
|
|
@@ -899,12 +917,17 @@ var COMMANDS = [
|
|
|
899
917
|
name: "stop",
|
|
900
918
|
section: "sessions",
|
|
901
919
|
summary: "stop the agent; the record and the review remain",
|
|
902
|
-
synopsis: ["[session-id-prefix]", "--all [--project <p>]"],
|
|
920
|
+
synopsis: ["[session-id-prefix]", "--all [--project <p>]", "--services [session-id-prefix]"],
|
|
903
921
|
description: [
|
|
904
922
|
"Ends the agent process. The workspace harvests the harness state and closes. The worktree, the record, and the review stay, and mend resume brings the conversation back.",
|
|
923
|
+
"Services keep running after a stop, and a running Service keeps the workspace up. The stop then prints, for example, agent stopped \xB7 3 services keep the workspace up. --services stops all of them. Once nothing is live, the workspace closes.",
|
|
905
924
|
sessionArg
|
|
906
925
|
],
|
|
907
|
-
options: [
|
|
926
|
+
options: [
|
|
927
|
+
{ flag: "--all", text: "every live session" },
|
|
928
|
+
project("limit --all to one project"),
|
|
929
|
+
{ flag: "--services", text: "stop the session's Services instead of its agent" }
|
|
930
|
+
],
|
|
908
931
|
see: ["resume", "attach"]
|
|
909
932
|
},
|
|
910
933
|
{
|
|
@@ -1017,18 +1040,26 @@ var COMMANDS = [
|
|
|
1017
1040
|
name: "land",
|
|
1018
1041
|
section: "sessions",
|
|
1019
1042
|
summary: "push a session's change to origin and open its pull request",
|
|
1020
|
-
synopsis: [
|
|
1043
|
+
synopsis: [
|
|
1044
|
+
"<session> [--branch <name>] [--no-pr] [--title <text>] [--project <p>]",
|
|
1045
|
+
"<session> --check [--project <p>]"
|
|
1046
|
+
],
|
|
1021
1047
|
description: [
|
|
1022
1048
|
"Only the change's owner lands it: the owner of the worktree's first session, not someone who started a session in it later. Mend takes a checkpoint, commits what the agent left uncommitted on top of the agent's own commits and the last landing, and pushes that to origin with the project's git access. The agent's commits are pushed as they are. The session's branch, and the worktree's files, index and HEAD, are not touched.",
|
|
1023
1049
|
"The push only fast-forwards. When origin's branch has commits Mend has not seen, or origin refuses the push, nothing is pushed and the command prints the remote's own words. Mend never force-pushes.",
|
|
1024
1050
|
"When origin is on GitHub, Mend then opens a pull request into the session's base branch, or updates the one it opened before. That call runs in a workspace with your GitHub account (mend connect github). The description holds Mend's review summary when there is one, the changed files and links back to the session, and an update replaces only Mend's section of it. For any other origin the push happens and the pull request is reported as unavailable, with the reason.",
|
|
1025
1051
|
"Landing again after more work adds commits to the same branch and updates the same pull request. When nothing is new since the last landing, nothing is pushed and the command says so. The branch on origin is never the project's default branch or the pull request's base. The command then prints what Mend observed: the push, the pull request and its state, what changed since, and pushes the agent made itself. It exits 1 when the push was refused or a step failed.",
|
|
1052
|
+
"A pull request someone opened outside Mend, the agent through gh included, is found and recorded as the change's own: Mend looks after the agent pushes a branch and when its turn ends, and --check looks now. It asks GitHub, as you, about the worktree's branch, every branch the agent pushed, and the agent's head commit. A landing then pushes that pull request's branch and updates it. A pull request from a fork is shown and never updated: Mend pushes to origin only, and opens no second pull request beside it.",
|
|
1026
1053
|
"<session> is a prefix of the session id or the worktree's name. Settled sessions count."
|
|
1027
1054
|
],
|
|
1028
1055
|
options: [
|
|
1029
1056
|
{
|
|
1030
1057
|
flag: "--branch <name>",
|
|
1031
|
-
text: "the branch on origin. Default: where the change last pushed to, else mend/<worktree>"
|
|
1058
|
+
text: "the branch on origin. Default: where the change last pushed to, the branch the agent pushed, an adopted pull request's branch, else mend/<worktree>"
|
|
1059
|
+
},
|
|
1060
|
+
{
|
|
1061
|
+
flag: "--check",
|
|
1062
|
+
text: "only look on GitHub for a pull request opened outside Mend, and record it; push nothing"
|
|
1032
1063
|
},
|
|
1033
1064
|
{ flag: "--no-pr", text: "push only; open or update no pull request" },
|
|
1034
1065
|
{
|
|
@@ -1293,6 +1324,22 @@ var COMMANDS = [
|
|
|
1293
1324
|
options: [{ flag: "--all", text: "every known config file" }],
|
|
1294
1325
|
see: ["dotfiles", "dotfiles repo"]
|
|
1295
1326
|
},
|
|
1327
|
+
{
|
|
1328
|
+
name: "git-author",
|
|
1329
|
+
section: "project setup",
|
|
1330
|
+
summary: "the name and email your workspaces commit as",
|
|
1331
|
+
synopsis: ["[<name> <email>]", "--clear"],
|
|
1332
|
+
description: [
|
|
1333
|
+
"Commits the agent makes in your workspaces name this author. Until you set one, it is the name and email you registered with. Without arguments, prints it and where it comes from.",
|
|
1334
|
+
"Each workspace receives it as system git config before the agent starts, so a user section in your dotfiles' .gitconfig or in a repository's own config still decides. Sessions launched after a change commit as the new author."
|
|
1335
|
+
],
|
|
1336
|
+
options: [{ flag: "--clear", text: "go back to your account's name and email" }],
|
|
1337
|
+
examples: [
|
|
1338
|
+
{ command: 'mend git-author "Anna Example" anna@example.com', text: "" },
|
|
1339
|
+
{ command: "mend git-author --clear", text: "" }
|
|
1340
|
+
],
|
|
1341
|
+
see: ["dotfiles", "keys mode"]
|
|
1342
|
+
},
|
|
1296
1343
|
{
|
|
1297
1344
|
name: "keys init",
|
|
1298
1345
|
section: "project setup",
|
|
@@ -2038,17 +2085,22 @@ var parseFlags = (args, valued, switches) => {
|
|
|
2038
2085
|
return { positional, values, on };
|
|
2039
2086
|
};
|
|
2040
2087
|
var parseLandArgs = (args) => {
|
|
2041
|
-
const flags = parseFlags(args, ["--branch", "--title", "--project"], ["--no-pr"]);
|
|
2088
|
+
const flags = parseFlags(args, ["--branch", "--title", "--project"], ["--no-pr", "--check"]);
|
|
2042
2089
|
if ("error" in flags) return flags;
|
|
2043
2090
|
const [session, extra] = flags.positional;
|
|
2044
2091
|
if (session === void 0) return { error: "name the session to land" };
|
|
2045
2092
|
if (extra !== void 0) return { error: `one session only; "${extra}" is extra` };
|
|
2093
|
+
const check = flags.on.has("--check");
|
|
2094
|
+
if (check && (flags.values.has("--branch") || flags.values.has("--title") || flags.on.has("--no-pr"))) {
|
|
2095
|
+
return { error: "--check pushes nothing; it takes no --branch, --title or --no-pr" };
|
|
2096
|
+
}
|
|
2046
2097
|
const branch = flags.values.get("--branch")?.trim() ?? null;
|
|
2047
2098
|
if (branch === "") return { error: "--branch needs a name" };
|
|
2048
2099
|
const title = flags.values.get("--title")?.trim() ?? null;
|
|
2049
2100
|
return {
|
|
2050
2101
|
args: {
|
|
2051
2102
|
session,
|
|
2103
|
+
check,
|
|
2052
2104
|
branch,
|
|
2053
2105
|
pullRequest: !flags.on.has("--no-pr"),
|
|
2054
2106
|
title: title === "" ? null : title,
|
|
@@ -2157,10 +2209,40 @@ var readFacts = (wire) => {
|
|
|
2157
2209
|
return fail("the server's landing facts are in a shape this CLI cannot read \xB7 update mend");
|
|
2158
2210
|
}
|
|
2159
2211
|
};
|
|
2212
|
+
var checkLine = (check) => {
|
|
2213
|
+
const pullRequest = check.landing?.pullRequest ?? null;
|
|
2214
|
+
switch (check.outcome) {
|
|
2215
|
+
case "adopted":
|
|
2216
|
+
return pullRequest === null ? "pull request recorded \xB7 opened outside Mend" : `pull request #${pullRequest.number} recorded \xB7 opened outside Mend \xB7 ${pullRequest.url}`;
|
|
2217
|
+
case "observed":
|
|
2218
|
+
return pullRequest === null ? "pull request already recorded" : `pull request #${pullRequest.number} already recorded \xB7 ${pullRequest.state} \xB7 observed`;
|
|
2219
|
+
case "none":
|
|
2220
|
+
return "no pull request on GitHub for the change's branches or the agent's commit";
|
|
2221
|
+
case "skipped":
|
|
2222
|
+
return `GitHub not checked \xB7 ${check.reason ?? "no reason given"}`;
|
|
2223
|
+
}
|
|
2224
|
+
};
|
|
2160
2225
|
var landCommand = async (api2, args) => {
|
|
2161
2226
|
const parsed = parseLandArgs(args);
|
|
2162
2227
|
if ("error" in parsed) return fail(parsed.error);
|
|
2163
2228
|
const { session, project: project2 } = await findSession(api2, parsed.args.session, parsed.args.project);
|
|
2229
|
+
if (parsed.args.check) {
|
|
2230
|
+
const before = await api2("GET", `/sessions/${session.id}/landings`);
|
|
2231
|
+
if (before.changeId === null) return fail("the session's worktree holds no change yet");
|
|
2232
|
+
const check = await api2(
|
|
2233
|
+
"POST",
|
|
2234
|
+
`/changes/${before.changeId}/pull-request/check`
|
|
2235
|
+
);
|
|
2236
|
+
const mark = check.outcome === "adopted" || check.outcome === "observed" ? green("\u2713") : dim("\xB7");
|
|
2237
|
+
say(`${mark} ${checkLine(check)}`);
|
|
2238
|
+
const after = await api2("GET", `/sessions/${session.id}/landings`);
|
|
2239
|
+
const facts = readFacts(after.facts);
|
|
2240
|
+
if (facts.length > 0) {
|
|
2241
|
+
say(dim(" observed"));
|
|
2242
|
+
for (const fact of facts) say(` ${landingFactLine(fact, /* @__PURE__ */ new Date())}`);
|
|
2243
|
+
}
|
|
2244
|
+
return;
|
|
2245
|
+
}
|
|
2164
2246
|
const steps = parsed.args.pullRequest ? "checkpoint \xB7 commit \xB7 push \xB7 pull request" : "checkpoint \xB7 commit \xB7 push";
|
|
2165
2247
|
say(
|
|
2166
2248
|
dim(
|
|
@@ -6899,6 +6981,12 @@ var attachPicked = async (config, session, tunnels) => {
|
|
|
6899
6981
|
return exitAfterSessionEnd(config, session.id);
|
|
6900
6982
|
};
|
|
6901
6983
|
var stopCommand = async (config, args) => {
|
|
6984
|
+
if (args.includes("--services")) {
|
|
6985
|
+
const prefix2 = args.find((arg) => !arg.startsWith("--"));
|
|
6986
|
+
const session = await resolveLiveSession(config, prefix2, "stop --services");
|
|
6987
|
+
await stopServicesOf(config, session);
|
|
6988
|
+
return;
|
|
6989
|
+
}
|
|
6902
6990
|
const all = args.includes("--all");
|
|
6903
6991
|
const projectFlag = args.indexOf("--project");
|
|
6904
6992
|
const projectName = projectFlag !== -1 && args[projectFlag + 1] !== void 0 ? String(args[projectFlag + 1]) : null;
|
|
@@ -6944,12 +7032,33 @@ var stopSessions = async (config, targets, summarise) => {
|
|
|
6944
7032
|
say6(
|
|
6945
7033
|
`${green6("\u2713")} stopped \xB7 ${session.harness} \xB7 ${dim6(session.id.slice(0, 8))} \xB7 ${session.branch}`
|
|
6946
7034
|
);
|
|
7035
|
+
const after = await api(config, "GET", `/sessions/${session.id}`).catch(
|
|
7036
|
+
() => null
|
|
7037
|
+
);
|
|
7038
|
+
const hold = after === null ? null : servicesHoldOf(after.session, after.currentAgent, after.liveServices ?? 0);
|
|
7039
|
+
if (hold !== null) {
|
|
7040
|
+
say6(`${amber2(" " + hold)} \xB7 mend stop --services ${session.id.slice(0, 8)}`);
|
|
7041
|
+
}
|
|
6947
7042
|
say6(`${cobalt2(" review")} \xB7 ${config.url}/sessions/${session.id}`);
|
|
6948
7043
|
}
|
|
6949
7044
|
if (summarise) {
|
|
6950
7045
|
say6(`${green6("\u2713")} stopped ${targets.length} session${targets.length === 1 ? "" : "s"}`);
|
|
6951
7046
|
}
|
|
6952
7047
|
};
|
|
7048
|
+
var stopServicesOf = async (config, session) => {
|
|
7049
|
+
const result = await api(
|
|
7050
|
+
config,
|
|
7051
|
+
"POST",
|
|
7052
|
+
`/sessions/${session.id}/services/stop`
|
|
7053
|
+
);
|
|
7054
|
+
if (result.stopped === 0) {
|
|
7055
|
+
say6(`no live services \xB7 ${session.harness} \xB7 ${dim6(session.id.slice(0, 8))}`);
|
|
7056
|
+
return;
|
|
7057
|
+
}
|
|
7058
|
+
say6(
|
|
7059
|
+
`${green6("\u2713")} stopped ${result.stopped} service${result.stopped === 1 ? "" : "s"} \xB7 ${session.harness} \xB7 ${dim6(session.id.slice(0, 8))} \xB7 ${session.branch}`
|
|
7060
|
+
);
|
|
7061
|
+
};
|
|
6953
7062
|
var pickSessionInteractively = async (rows) => {
|
|
6954
7063
|
say6(dim6("more than one live session \u2014 pick one:"));
|
|
6955
7064
|
rows.forEach((row, index) => {
|
|
@@ -7845,6 +7954,34 @@ var keysShare = async (config) => {
|
|
|
7845
7954
|
}
|
|
7846
7955
|
});
|
|
7847
7956
|
};
|
|
7957
|
+
var gitAuthorCommand = async (config, args) => {
|
|
7958
|
+
const asked = parseGitAuthorArgs(args);
|
|
7959
|
+
switch (asked.kind) {
|
|
7960
|
+
case "usage":
|
|
7961
|
+
return fail6(usageOf("git-author"));
|
|
7962
|
+
case "invalid":
|
|
7963
|
+
return fail6(asked.message);
|
|
7964
|
+
case "show":
|
|
7965
|
+
say6(gitAuthorLine(await api(config, "GET", "/me/git-author")));
|
|
7966
|
+
return;
|
|
7967
|
+
case "clear": {
|
|
7968
|
+
const author = await api(config, "DELETE", "/me/git-author");
|
|
7969
|
+
say6(`${green6("\u2713")} git author \xB7 ${gitAuthorLine(author)}`);
|
|
7970
|
+
return;
|
|
7971
|
+
}
|
|
7972
|
+
case "set": {
|
|
7973
|
+
const author = await api(config, "PUT", "/me/git-author", {
|
|
7974
|
+
name: asked.name,
|
|
7975
|
+
email: asked.email
|
|
7976
|
+
});
|
|
7977
|
+
say6(`${green6("\u2713")} git author \xB7 ${gitAuthorLine(author)}`);
|
|
7978
|
+
say6(
|
|
7979
|
+
dim6(" sessions launched from now on commit as this, unless their dotfiles say otherwise")
|
|
7980
|
+
);
|
|
7981
|
+
return;
|
|
7982
|
+
}
|
|
7983
|
+
}
|
|
7984
|
+
};
|
|
7848
7985
|
var keysMode = async (config, args) => {
|
|
7849
7986
|
const [value] = args;
|
|
7850
7987
|
if (value !== void 0 && value !== "mend-key" && value !== "bridge") {
|
|
@@ -8248,6 +8385,7 @@ _mend() {
|
|
|
8248
8385
|
'server:local server setup, lifecycle and upgrades'
|
|
8249
8386
|
'uninstall:remove the server, local Mend files, or both'
|
|
8250
8387
|
'keys:the machine Mend deploy key \u2014 init, show, share'
|
|
8388
|
+
'git-author:the name and email your workspaces commit as'
|
|
8251
8389
|
'skills:skill libraries \u2014 list, push'
|
|
8252
8390
|
'accounts:your connected accounts on the platform'
|
|
8253
8391
|
'pair:pair a phone or a second machine' 'doctor:read-only checklist of this setup'
|
|
@@ -8288,7 +8426,7 @@ _mend "$@"
|
|
|
8288
8426
|
var BASH_COMPLETIONS = `_mend() {
|
|
8289
8427
|
local cur=\${COMP_WORDS[COMP_CWORD]}
|
|
8290
8428
|
if [ "$COMP_CWORD" -eq 1 ]; then
|
|
8291
|
-
COMPREPLY=( $(compgen -W "adopt codex claude opencode run attach stop shell service server uninstall keys skills pair doctor continue resume rejoin land pull refresh projects sessions status ui help" -- "$cur") )
|
|
8429
|
+
COMPREPLY=( $(compgen -W "adopt codex claude opencode run attach stop shell service server uninstall keys git-author skills pair doctor continue resume rejoin land pull refresh projects sessions status ui help" -- "$cur") )
|
|
8292
8430
|
return
|
|
8293
8431
|
fi
|
|
8294
8432
|
case \${COMP_WORDS[1]} in
|
|
@@ -8600,11 +8738,14 @@ var refreshCommand = async (config, args) => {
|
|
|
8600
8738
|
}
|
|
8601
8739
|
if (branches.length > 12) say6(dim6(` \u2026 ${branches.length - 12} more`));
|
|
8602
8740
|
};
|
|
8741
|
+
var rowHold = (row) => row.annotation === void 0 ? null : servicesHoldOf(row.session, row.annotation.currentAgent, row.annotation.liveServices ?? 0);
|
|
8603
8742
|
var printSessionRow = (row) => {
|
|
8604
8743
|
const { session, annotation } = row;
|
|
8605
8744
|
const live = ACTIVE_STATUSES.has(session.status);
|
|
8606
8745
|
const status = session.status.padEnd(9);
|
|
8607
8746
|
const facts = [];
|
|
8747
|
+
const hold = rowHold(row);
|
|
8748
|
+
if (hold !== null) facts.push(amber2(hold));
|
|
8608
8749
|
if (session.label !== null) facts.push(session.label);
|
|
8609
8750
|
if (annotation !== void 0 && annotation.openComments > 0) {
|
|
8610
8751
|
facts.push(amber2(`${annotation.openComments} open`));
|
|
@@ -8633,19 +8774,22 @@ var sessionsCommand = async (config, args) => {
|
|
|
8633
8774
|
return fail6(`no adopted project named "${projectName}"`);
|
|
8634
8775
|
}
|
|
8635
8776
|
let rows;
|
|
8636
|
-
if (all || projectName !== null) {
|
|
8777
|
+
if (all || projectName !== null || !json) {
|
|
8637
8778
|
const details = await Promise.all(
|
|
8638
8779
|
scope.map(
|
|
8639
8780
|
(p) => api(config, "GET", `/projects/${p.id}${all ? "?deadEnds=include" : ""}`)
|
|
8640
8781
|
)
|
|
8641
8782
|
);
|
|
8642
|
-
|
|
8783
|
+
const detailed = details.flatMap(
|
|
8643
8784
|
(detail) => detail.sessions.map((session) => ({
|
|
8644
8785
|
session,
|
|
8645
8786
|
projectName: detail.project.name,
|
|
8646
8787
|
annotation: detail.annotations.find((a) => a.sessionId === session.id)
|
|
8647
8788
|
}))
|
|
8648
8789
|
);
|
|
8790
|
+
rows = all || projectName !== null ? detailed : detailed.filter(
|
|
8791
|
+
(row) => ACTIVE_STATUSES.has(row.session.status) || rowHold(row) !== null
|
|
8792
|
+
);
|
|
8649
8793
|
} else {
|
|
8650
8794
|
const active = await api(config, "GET", "/sessions");
|
|
8651
8795
|
const nameById = new Map(projects.map((p) => [p.id, p.name]));
|
|
@@ -8831,7 +8975,7 @@ var dashboard = async (config, options = {}) => {
|
|
|
8831
8975
|
);
|
|
8832
8976
|
process.exit(rerun.status ?? 0);
|
|
8833
8977
|
}
|
|
8834
|
-
const { runDashboard } = await import("./dashboard-
|
|
8978
|
+
const { runDashboard } = await import("./dashboard-3HNFSQZD.js");
|
|
8835
8979
|
const agentShare = await startShareIfBridge(config);
|
|
8836
8980
|
const tunnels = options.noTunnel === true || serverIsLocal(config) ? null : createServiceTunnels({
|
|
8837
8981
|
listServices: () => fetchServices(config),
|
|
@@ -8949,6 +9093,8 @@ var main = async () => {
|
|
|
8949
9093
|
return uninstallCommand(config, rest);
|
|
8950
9094
|
case "keys":
|
|
8951
9095
|
return keysCommand(config, rest);
|
|
9096
|
+
case "git-author":
|
|
9097
|
+
return gitAuthorCommand(config, rest);
|
|
8952
9098
|
case "dotfiles":
|
|
8953
9099
|
return dotfilesCommand(config, rest);
|
|
8954
9100
|
case "skills":
|