@sealant/mend 0.36.0-next.643 → 0.36.0-next.645
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/README.md +4 -1
- package/dist/{chunk-2TDRYRGO.js → chunk-ASHAV3UV.js} +259 -0
- package/dist/{dashboard-2HF3KTTU.js → dashboard-4J2WMT3G.js} +134 -17
- package/dist/main.js +646 -461
- 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 +3 -1
- package/man/mend-completions.1 +1 -1
- package/man/mend-connect-pi.1 +1 -1
- package/man/mend-connect.1 +3 -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 +1 -1
- 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 +1 -1
- 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-memory-import.1 +1 -1
- package/man/mend-memory-rm.1 +1 -1
- package/man/mend-memory-show.1 +1 -1
- package/man/mend-memory.1 +1 -1
- package/man/mend-models.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-secrets-add.1 +1 -1
- package/man/mend-secrets-rm.1 +1 -1
- package/man/mend-secrets.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 +13 -3
- package/man/mend-sessions.1 +3 -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 +1 -1
- package/man/mend-ui.1 +1 -1
- package/man/mend-uninstall.1 +1 -1
- package/man/mend-version.1 +1 -1
- package/man/mend-workspace-replace.1 +24 -0
- package/man/mend-worktrees-rm.1 +1 -1
- package/man/mend-worktrees.1 +1 -1
- package/man/mend.1 +5 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -171,6 +171,8 @@ mend refresh [project] fetch origin's branches into the store
|
|
|
171
171
|
mend land <session> [--branch b] [--no-pr] [--title t] | --check
|
|
172
172
|
push the change to origin, open or update its pull request
|
|
173
173
|
mend pull <session> [--force] fetch the change into this clone as mend/<name>
|
|
174
|
+
mend workspace replace <session> [--yes]
|
|
175
|
+
replace a workspace that started before Mend 0.36
|
|
174
176
|
|
|
175
177
|
services
|
|
176
178
|
mend service run|add|connect|list|logs|restart|stop|init
|
|
@@ -193,7 +195,8 @@ mend members who belongs to your organization, and thei
|
|
|
193
195
|
mend invite [--role member|owner] [--email <address>] [--days <n>]
|
|
194
196
|
print a one-time invitation link
|
|
195
197
|
mend folder list|create|push|rm your organization's folders
|
|
196
|
-
mend session share <session> on|off
|
|
198
|
+
mend session share <session> on|off [--yes]
|
|
199
|
+
shared control: each turn runs on its sender's login
|
|
197
200
|
|
|
198
201
|
this machine
|
|
199
202
|
mend operator org list|create|rename|invite-owner
|
|
@@ -28038,6 +28038,12 @@ var NativeIngestCursor = Schema_exports.Struct({
|
|
|
28038
28038
|
lastEntryUuid: Schema_exports.NullOr(Schema_exports.String),
|
|
28039
28039
|
lineCount: Schema_exports.Int
|
|
28040
28040
|
});
|
|
28041
|
+
var LivePerson = class extends Schema_exports.Class("LivePerson")({
|
|
28042
|
+
accountId: Schema_exports.String,
|
|
28043
|
+
/** Their name as the instance knows it. */
|
|
28044
|
+
name: Schema_exports.String
|
|
28045
|
+
}) {
|
|
28046
|
+
};
|
|
28041
28047
|
var Session = class extends Schema_exports.Class("Session")({
|
|
28042
28048
|
id: SessionId,
|
|
28043
28049
|
projectId: ProjectId,
|
|
@@ -28126,6 +28132,24 @@ var Session = class extends Schema_exports.Class("Session")({
|
|
|
28126
28132
|
Schema_exports.withDecodingDefaultKey(Effect_exports.succeed(null)),
|
|
28127
28133
|
Schema_exports.withConstructorDefault(Effect_exports.succeed(null))
|
|
28128
28134
|
),
|
|
28135
|
+
/**
|
|
28136
|
+
* The people with a process live in the session's executor as their own user, in a per-person
|
|
28137
|
+
* executor (docs/adr/0016, decision 13): filled by the API's session list and view only, in the
|
|
28138
|
+
* same query; empty everywhere else, in a shared executor, and from older servers.
|
|
28139
|
+
*/
|
|
28140
|
+
livePeople: Schema_exports.Array(LivePerson).pipe(
|
|
28141
|
+
Schema_exports.withDecodingDefaultKey(Effect_exports.succeed([])),
|
|
28142
|
+
Schema_exports.withConstructorDefault(Effect_exports.succeed([]))
|
|
28143
|
+
),
|
|
28144
|
+
/**
|
|
28145
|
+
* The session's executor waits to be replaced (docs/adr/0016, decision 14): `marked` or
|
|
28146
|
+
* `retiring`; null otherwise. Read with `livePeople`, in the same query, so a client asks for the
|
|
28147
|
+
* retirement's detail only when there is one. Null everywhere else and from older servers.
|
|
28148
|
+
*/
|
|
28149
|
+
workspaceRetirement: Schema_exports.NullOr(Schema_exports.Literals(["marked", "retiring"])).pipe(
|
|
28150
|
+
Schema_exports.withDecodingDefaultKey(Effect_exports.succeed(null)),
|
|
28151
|
+
Schema_exports.withConstructorDefault(Effect_exports.succeed(null))
|
|
28152
|
+
),
|
|
28129
28153
|
/**
|
|
28130
28154
|
* Whether the harness left a conversation behind — a transcript Mend captured at settle or
|
|
28131
28155
|
* found in the live harness home. False is a dead end: nothing to resume, nothing to hand
|
|
@@ -28382,6 +28406,62 @@ var LinuxIdentity = class extends Schema_exports.Class("LinuxIdentity")({
|
|
|
28382
28406
|
uid: Schema_exports.Number
|
|
28383
28407
|
}) {
|
|
28384
28408
|
};
|
|
28409
|
+
var WorkspaceRetirementStopKind = Schema_exports.Literals([
|
|
28410
|
+
"terminal",
|
|
28411
|
+
"shell",
|
|
28412
|
+
"service",
|
|
28413
|
+
"turn",
|
|
28414
|
+
"process",
|
|
28415
|
+
"container",
|
|
28416
|
+
"unchecked"
|
|
28417
|
+
]);
|
|
28418
|
+
var WorkspaceRetirementStop = class extends Schema_exports.Class(
|
|
28419
|
+
"WorkspaceRetirementStop"
|
|
28420
|
+
)({
|
|
28421
|
+
kind: WorkspaceRetirementStopKind,
|
|
28422
|
+
/**
|
|
28423
|
+
* What it is, as observed: a session's label, a Service's name, a process's command name and
|
|
28424
|
+
* pid, a container's name, or why something could not be checked. Empty for a process or a
|
|
28425
|
+
* container when the viewer is not the change's owner: they see its kind only.
|
|
28426
|
+
*/
|
|
28427
|
+
label: Schema_exports.String
|
|
28428
|
+
}) {
|
|
28429
|
+
};
|
|
28430
|
+
var WorkspaceRetirementState = Schema_exports.Literals(["marked", "retiring"]);
|
|
28431
|
+
var WorkspaceRetirement = class extends Schema_exports.Class("WorkspaceRetirement")({
|
|
28432
|
+
state: WorkspaceRetirementState,
|
|
28433
|
+
/** The executor started before Mend 0.36 (no layout recorded for its launch). */
|
|
28434
|
+
preRelease: Schema_exports.Boolean,
|
|
28435
|
+
/** The account whose launch made the executor: the only one whose joins and turns it takes. */
|
|
28436
|
+
launcher: Schema_exports.NullOr(Schema_exports.String),
|
|
28437
|
+
/** What would stop if it were replaced now; empty when nothing would. */
|
|
28438
|
+
stops: Schema_exports.Array(WorkspaceRetirementStop),
|
|
28439
|
+
/** Why the last automatic replacement did not go ahead, as observed; null when none was tried. */
|
|
28440
|
+
reason: Schema_exports.NullOr(Schema_exports.String),
|
|
28441
|
+
/**
|
|
28442
|
+
* When what runs in the executor was last checked beyond Mend's own records (processes Mend did
|
|
28443
|
+
* not start, the sidecar's containers); null when only Mend's records were read.
|
|
28444
|
+
*/
|
|
28445
|
+
checkedAt: Schema_exports.NullOr(Timestamp),
|
|
28446
|
+
/**
|
|
28447
|
+
* What the viewer was shown, as one token: "Replace this workspace now" names it, so Mend ends
|
|
28448
|
+
* nothing that was not listed (the replacement is refused if more would stop now).
|
|
28449
|
+
*/
|
|
28450
|
+
fingerprint: Schema_exports.String,
|
|
28451
|
+
/** The viewer may replace it now: they own the change, and no agent turn is in flight. */
|
|
28452
|
+
canReplace: Schema_exports.Boolean
|
|
28453
|
+
}) {
|
|
28454
|
+
};
|
|
28455
|
+
var PreReleaseMemory = class extends Schema_exports.Class("PreReleaseMemory")({
|
|
28456
|
+
/** The capture it read, by its place on the worktree's chain. */
|
|
28457
|
+
captureN: Schema_exports.Number,
|
|
28458
|
+
provisional: Schema_exports.Boolean,
|
|
28459
|
+
creditedTo: Schema_exports.NullOr(Schema_exports.String),
|
|
28460
|
+
decidedBy: Schema_exports.Literals(["home-record", "only-person", "nobody", "nothing"]),
|
|
28461
|
+
/** Memory paths credited to nobody: two or more people's sessions shared the home. */
|
|
28462
|
+
notCredited: Schema_exports.Array(Schema_exports.String)
|
|
28463
|
+
}) {
|
|
28464
|
+
};
|
|
28385
28465
|
|
|
28386
28466
|
// ../../packages/domain/src/workbench/host-user-namespaces.ts
|
|
28387
28467
|
var HOST_USER_NAMESPACE_FILES = [
|
|
@@ -29095,6 +29175,54 @@ var SlackLinkedMentionJob = Schema_exports.Struct({
|
|
|
29095
29175
|
linkedAt: Schema_exports.String
|
|
29096
29176
|
});
|
|
29097
29177
|
|
|
29178
|
+
// ../../packages/domain/src/workbench/shared-workspace.ts
|
|
29179
|
+
var listed = (names) => names.length <= 1 ? names[0] ?? "" : `${names.slice(0, -1).join(", ")} and ${names[names.length - 1] ?? ""}`;
|
|
29180
|
+
var joinWorktreeLine = (others) => others.length <= 1 ? `${others[0] ?? "Another person"}'s session is running in this worktree. You share its workspace: everything you run runs as you, on your own logins, but either of you can read the other's files, logins included.` : `${listed(others)}'s sessions are running in this worktree. You share its workspace: everything you run runs as you, on your own logins, but any of you can read the others' files, logins included.`;
|
|
29181
|
+
var JOIN_SHARED_HOME_LINE = "Another person's session is running in this worktree, in a workspace that shares one home: what you start there runs on the logins and Git identity of whoever started that workspace, not yours.";
|
|
29182
|
+
var sharedWorkspaceLine = (livePeople, viewer) => {
|
|
29183
|
+
if (livePeople.length < 2) return null;
|
|
29184
|
+
const others = livePeople.filter((person) => person.accountId !== viewer).map((p) => p.name);
|
|
29185
|
+
if (others.length === livePeople.length) {
|
|
29186
|
+
return `Shared workspace: ${listed(others)} \xB7 each runs as themselves \xB7 ${others.length === 2 ? "either can read the other's files" : "any of them can read the others' files"}.`;
|
|
29187
|
+
}
|
|
29188
|
+
return others.length === 1 && livePeople.length === 2 ? `Shared workspace with ${others[0]} \xB7 each of you runs as yourself \xB7 either of you can read the other's files.` : `Shared workspace with ${listed(others)} \xB7 each of you runs as yourself \xB7 any of you can read the others' files.`;
|
|
29189
|
+
};
|
|
29190
|
+
var SHARED_CONTROL_LINE = "Each turn runs on its sender's login. From now until this session ends, the agent uses no one's personal memory or instructions. The conversation so far, including what your agent loaded before, becomes visible to whoever steers.";
|
|
29191
|
+
var SHARED_CONTROL_LINE_OWNER_LOGINS = "Each turn runs on your provider logins and Git access, whoever sends it.";
|
|
29192
|
+
var sharedControlLine = (turnsOnSendersLogin) => turnsOnSendersLogin ? SHARED_CONTROL_LINE : SHARED_CONTROL_LINE_OWNER_LOGINS;
|
|
29193
|
+
var sharedControlConfirm = (turnsOnSendersLogin) => ({
|
|
29194
|
+
title: "Turn on shared control?",
|
|
29195
|
+
body: turnsOnSendersLogin ? SHARED_CONTROL_LINE : `Everyone who can see this project can send turns, answer approvals and interrupt. ${SHARED_CONTROL_LINE_OWNER_LOGINS}`,
|
|
29196
|
+
confirm: "Turn on",
|
|
29197
|
+
cancel: "Keep it off"
|
|
29198
|
+
});
|
|
29199
|
+
var workspaceRetirementLine = (retirement, launcherName) => {
|
|
29200
|
+
if (retirement.state === "retiring") {
|
|
29201
|
+
return "Replacing this workspace so that each person runs as themselves \xB7 nothing new starts until it has been saved and replaced";
|
|
29202
|
+
}
|
|
29203
|
+
const started = retirement.preRelease ? "This workspace started before Mend 0.36 and shares one home" : "This workspace shares one home";
|
|
29204
|
+
const reason = retirement.reason === null ? "" : ` \xB7 ${retirement.reason}`;
|
|
29205
|
+
return `${started} \xB7 it takes only ${launcherName}'s sessions and turns until it is replaced${reason}`;
|
|
29206
|
+
};
|
|
29207
|
+
var STOP_WORDS = {
|
|
29208
|
+
terminal: "terminal session (ends resumable)",
|
|
29209
|
+
shell: "shell",
|
|
29210
|
+
service: "Service started by hand",
|
|
29211
|
+
turn: "agent turn in flight",
|
|
29212
|
+
process: "process Mend did not start",
|
|
29213
|
+
container: "running container",
|
|
29214
|
+
unchecked: "could not check"
|
|
29215
|
+
};
|
|
29216
|
+
var REPLACE_WORKSPACE_ACTION = "Replace this workspace now";
|
|
29217
|
+
var timeOf3 = (at) => `${at.toISOString().slice(11, 16)} UTC`;
|
|
29218
|
+
var retirementStopLines = (retirement) => {
|
|
29219
|
+
const checked = retirement.checkedAt === null ? "Checked: Mend's records only \xB7 processes Mend did not start and running containers not checked yet" : `Checked at ${timeOf3(retirement.checkedAt)}: Mend's records, the processes in the workspace and its running containers`;
|
|
29220
|
+
const found = retirement.stops.length === 0 ? ["Found nothing that would stop."] : retirement.stops.map(
|
|
29221
|
+
(stop) => stop.label === "" ? STOP_WORDS[stop.kind] : `${STOP_WORDS[stop.kind]} \xB7 ${stop.label}`
|
|
29222
|
+
);
|
|
29223
|
+
return [checked, ...found, "Mend starts the launching session's mend.toml Services again."];
|
|
29224
|
+
};
|
|
29225
|
+
|
|
29098
29226
|
// ../../packages/domain/src/workbench/steering.ts
|
|
29099
29227
|
var ConversationWaitWork = Schema_exports.Struct({
|
|
29100
29228
|
kind: Schema_exports.Literals([
|
|
@@ -29547,6 +29675,120 @@ var GATEWAY_STATUSES = /* @__PURE__ */ new Set([
|
|
|
29547
29675
|
]);
|
|
29548
29676
|
var mayStillBeWorking = (error) => error instanceof MendRequestError && (error.kind === "timeout" || error.kind === "dropped" || error.kind === "http" && error.status !== null && GATEWAY_STATUSES.has(error.status));
|
|
29549
29677
|
|
|
29678
|
+
// src/shared-workspace.ts
|
|
29679
|
+
var checkedAtOf = (retirement) => {
|
|
29680
|
+
if (retirement.checkedAt === null) return null;
|
|
29681
|
+
const at = new Date(retirement.checkedAt);
|
|
29682
|
+
return Number.isNaN(at.getTime()) ? null : at;
|
|
29683
|
+
};
|
|
29684
|
+
var retirementEvidenceLines = (retirement) => retirementStopLines({ stops: retirement.stops, checkedAt: checkedAtOf(retirement) });
|
|
29685
|
+
var workspaceReadsOf = (session) => ({
|
|
29686
|
+
waiting: (session.livePeople ?? []).length > 0 && session.sharedControlEnabledAt !== void 0 && session.sharedControlEnabledAt !== null,
|
|
29687
|
+
retirement: session.workspaceRetirement !== void 0 && session.workspaceRetirement !== null
|
|
29688
|
+
});
|
|
29689
|
+
var hasPersonFacts = (sessions) => sessions.some(
|
|
29690
|
+
(session) => (session.livePeople ?? []).length > 0 || session.workspaceRetirement !== void 0 && session.workspaceRetirement !== null
|
|
29691
|
+
);
|
|
29692
|
+
var worktreeListsPeople = (sessions, worktreeId) => sessions.some(
|
|
29693
|
+
(session) => session.worktreeId === worktreeId && (session.livePeople ?? []).length > 0
|
|
29694
|
+
);
|
|
29695
|
+
var othersLiveInWorktree = (sessions, worktreeId, viewer) => {
|
|
29696
|
+
if (viewer === null) return [];
|
|
29697
|
+
const names = /* @__PURE__ */ new Map();
|
|
29698
|
+
for (const session of sessions) {
|
|
29699
|
+
if (session.worktreeId !== worktreeId) continue;
|
|
29700
|
+
for (const person of session.livePeople ?? []) {
|
|
29701
|
+
if (person.accountId !== viewer) names.set(person.accountId, person.name);
|
|
29702
|
+
}
|
|
29703
|
+
}
|
|
29704
|
+
return [...names.values()];
|
|
29705
|
+
};
|
|
29706
|
+
var worktreeJoinLine = (sessions, worktreeId, viewer) => {
|
|
29707
|
+
const others = othersLiveInWorktree(sessions, worktreeId, viewer);
|
|
29708
|
+
if (others.length > 0) return joinWorktreeLine(others);
|
|
29709
|
+
if (viewer === null || worktreeListsPeople(sessions, worktreeId)) return null;
|
|
29710
|
+
const anotherLive = sessions.some(
|
|
29711
|
+
(session) => session.worktreeId === worktreeId && session.status !== void 0 && LIVE_STATUSES.has(session.status) && session.ownerUserId !== void 0 && session.ownerUserId !== null && session.ownerUserId !== viewer
|
|
29712
|
+
);
|
|
29713
|
+
return anotherLive ? JOIN_SHARED_HOME_LINE : null;
|
|
29714
|
+
};
|
|
29715
|
+
var launcherNameOf = (launcher, livePeople, members) => livePeople.find((person) => person.accountId === launcher)?.name ?? members.find((member) => member.userId === launcher)?.name ?? "its launcher";
|
|
29716
|
+
var sessionWorkspaceLines = (facts) => {
|
|
29717
|
+
const { retirement } = facts;
|
|
29718
|
+
return {
|
|
29719
|
+
shared: sharedWorkspaceLine(facts.livePeople, facts.viewer),
|
|
29720
|
+
waiting: facts.wait?.line ?? null,
|
|
29721
|
+
retirement: retirement === null ? null : workspaceRetirementLine(
|
|
29722
|
+
retirement,
|
|
29723
|
+
launcherNameOf(retirement.launcher, facts.livePeople, facts.members)
|
|
29724
|
+
),
|
|
29725
|
+
// Only the change's owner replaces it, and only while it is marked: a retiring one is
|
|
29726
|
+
// already being replaced.
|
|
29727
|
+
replace: retirement === null || !retirement.canReplace || retirement.state !== "marked" ? null : {
|
|
29728
|
+
action: REPLACE_WORKSPACE_ACTION,
|
|
29729
|
+
command: `mend workspace replace ${facts.sessionId.slice(0, 8)}`,
|
|
29730
|
+
stops: retirementEvidenceLines(retirement)
|
|
29731
|
+
}
|
|
29732
|
+
};
|
|
29733
|
+
};
|
|
29734
|
+
var workspaceLineList = (lines) => [
|
|
29735
|
+
...lines.shared === null ? [] : [lines.shared],
|
|
29736
|
+
...lines.waiting === null ? [] : [lines.waiting],
|
|
29737
|
+
...lines.retirement === null ? [] : [lines.retirement],
|
|
29738
|
+
...lines.replace === null ? [] : [
|
|
29739
|
+
`${lines.replace.action} \xB7 ${lines.replace.command}`,
|
|
29740
|
+
...lines.replace.stops.map((stop) => ` ${stop}`)
|
|
29741
|
+
]
|
|
29742
|
+
];
|
|
29743
|
+
var wrapWords = (text, width) => {
|
|
29744
|
+
const limit = Math.max(8, width);
|
|
29745
|
+
const lines = [];
|
|
29746
|
+
let current = "";
|
|
29747
|
+
for (const raw of text.split(/\s+/)) {
|
|
29748
|
+
if (raw === "") continue;
|
|
29749
|
+
let word = raw;
|
|
29750
|
+
while (word.length > limit) {
|
|
29751
|
+
if (current !== "") {
|
|
29752
|
+
lines.push(current);
|
|
29753
|
+
current = "";
|
|
29754
|
+
}
|
|
29755
|
+
lines.push(word.slice(0, limit));
|
|
29756
|
+
word = word.slice(limit);
|
|
29757
|
+
}
|
|
29758
|
+
if (current === "") current = word;
|
|
29759
|
+
else if (current.length + 1 + word.length <= limit) current = `${current} ${word}`;
|
|
29760
|
+
else {
|
|
29761
|
+
lines.push(current);
|
|
29762
|
+
current = word;
|
|
29763
|
+
}
|
|
29764
|
+
}
|
|
29765
|
+
if (current !== "") lines.push(current);
|
|
29766
|
+
return lines;
|
|
29767
|
+
};
|
|
29768
|
+
var confirmPlan = (args2, interactive) => args2.includes("--yes") || args2.includes("-y") ? "confirmed" : interactive ? "ask" : "refuse";
|
|
29769
|
+
var sharedControlConfirmLines = (turnsOnSendersLogin) => {
|
|
29770
|
+
const confirm = sharedControlConfirm(turnsOnSendersLogin);
|
|
29771
|
+
return [confirm.title, confirm.body];
|
|
29772
|
+
};
|
|
29773
|
+
var sharedControlQuestion = (turnsOnSendersLogin) => {
|
|
29774
|
+
const confirm = sharedControlConfirm(turnsOnSendersLogin);
|
|
29775
|
+
return `${confirm.confirm.toLowerCase()}? (n: ${confirm.cancel.toLowerCase()})`;
|
|
29776
|
+
};
|
|
29777
|
+
var replaceConfirmLines = (retirement) => [
|
|
29778
|
+
`${REPLACE_WORKSPACE_ACTION}?`,
|
|
29779
|
+
...retirementEvidenceLines(retirement).map((stop) => ` ${stop}`)
|
|
29780
|
+
];
|
|
29781
|
+
var askYesNo = async (question) => {
|
|
29782
|
+
const readline = await import("node:readline/promises");
|
|
29783
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
29784
|
+
try {
|
|
29785
|
+
const answer = (await rl.question(`${question} [y/N] `)).trim().toLowerCase();
|
|
29786
|
+
return answer === "y" || answer === "yes";
|
|
29787
|
+
} finally {
|
|
29788
|
+
rl.close();
|
|
29789
|
+
}
|
|
29790
|
+
};
|
|
29791
|
+
|
|
29550
29792
|
// src/workbench-events.ts
|
|
29551
29793
|
var createSseParser = () => {
|
|
29552
29794
|
let buffer = "";
|
|
@@ -29625,6 +29867,10 @@ export {
|
|
|
29625
29867
|
servicesHoldLine,
|
|
29626
29868
|
validateSecretFilePath,
|
|
29627
29869
|
terminalReadOnlyLine,
|
|
29870
|
+
sharedControlLine,
|
|
29871
|
+
sharedControlConfirm,
|
|
29872
|
+
workspaceRetirementLine,
|
|
29873
|
+
REPLACE_WORKSPACE_ACTION,
|
|
29628
29874
|
WORKTREE_REMOVAL_FORCE_HINT,
|
|
29629
29875
|
HARNESS_COMMANDS,
|
|
29630
29876
|
pendingId,
|
|
@@ -29654,6 +29900,19 @@ export {
|
|
|
29654
29900
|
noAnswerError,
|
|
29655
29901
|
GATEWAY_STATUSES,
|
|
29656
29902
|
mayStillBeWorking,
|
|
29903
|
+
workspaceReadsOf,
|
|
29904
|
+
hasPersonFacts,
|
|
29905
|
+
worktreeListsPeople,
|
|
29906
|
+
worktreeJoinLine,
|
|
29907
|
+
launcherNameOf,
|
|
29908
|
+
sessionWorkspaceLines,
|
|
29909
|
+
workspaceLineList,
|
|
29910
|
+
wrapWords,
|
|
29911
|
+
confirmPlan,
|
|
29912
|
+
sharedControlConfirmLines,
|
|
29913
|
+
sharedControlQuestion,
|
|
29914
|
+
replaceConfirmLines,
|
|
29915
|
+
askYesNo,
|
|
29657
29916
|
createSseParser,
|
|
29658
29917
|
eventFamilies
|
|
29659
29918
|
};
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
createSseParser,
|
|
9
9
|
cwdFacts,
|
|
10
10
|
eventFamilies,
|
|
11
|
+
hasPersonFacts,
|
|
11
12
|
isPendingId,
|
|
12
13
|
launchPhaseOf,
|
|
13
14
|
matchProjectByCwd,
|
|
@@ -16,8 +17,13 @@ import {
|
|
|
16
17
|
pendingId,
|
|
17
18
|
repositoryCloneUrlIssue,
|
|
18
19
|
servicesHoldLine,
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
sessionWorkspaceLines,
|
|
21
|
+
withoutLaunchPhase,
|
|
22
|
+
workspaceLineList,
|
|
23
|
+
workspaceReadsOf,
|
|
24
|
+
worktreeJoinLine,
|
|
25
|
+
wrapWords
|
|
26
|
+
} from "./chunk-ASHAV3UV.js";
|
|
21
27
|
|
|
22
28
|
// src/dashboard.tsx
|
|
23
29
|
import { CliRenderEvents, createCliRenderer } from "@opentui/core";
|
|
@@ -541,6 +547,51 @@ var fitHints = (hints, width) => {
|
|
|
541
547
|
return kept.length === 0 ? "\u2026" : `${kept.join(" \xB7 ")} \u2026`;
|
|
542
548
|
};
|
|
543
549
|
var clampIndex = (length, index) => length === 0 ? 0 : Math.max(0, Math.min(length - 1, index));
|
|
550
|
+
var VIEWER_KEY = ["viewer"];
|
|
551
|
+
var viewerNeeded = (data) => data !== void 0 && [...data.details.values()].some((detail) => hasPersonFacts(detail.sessions));
|
|
552
|
+
var fetchViewer = async (ctx) => {
|
|
553
|
+
const [view, members] = await Promise.all([
|
|
554
|
+
ctx.api("GET", "/organization").catch(() => null),
|
|
555
|
+
ctx.api("GET", "/organization/members").catch(() => [])
|
|
556
|
+
]);
|
|
557
|
+
return { userId: view?.userId ?? null, members };
|
|
558
|
+
};
|
|
559
|
+
var WORKSPACE_FACTS_KEY = (sessionId, reads) => [
|
|
560
|
+
"workspace-facts",
|
|
561
|
+
sessionId,
|
|
562
|
+
reads.waiting,
|
|
563
|
+
reads.retirement
|
|
564
|
+
];
|
|
565
|
+
var fetchWorkspaceFacts = async (api, sessionId, reads) => {
|
|
566
|
+
const [wait, retirement] = await Promise.all([
|
|
567
|
+
reads.waiting ? api("GET", `/sessions/${sessionId}/waiting`).catch(() => null) : null,
|
|
568
|
+
reads.retirement ? api(
|
|
569
|
+
"GET",
|
|
570
|
+
`/sessions/${sessionId}/workspace-retirement`
|
|
571
|
+
).catch(() => null) : null
|
|
572
|
+
]);
|
|
573
|
+
return { wait, retirement };
|
|
574
|
+
};
|
|
575
|
+
var workspaceFactRows = (session, viewer, facts, width) => workspaceLineList(
|
|
576
|
+
sessionWorkspaceLines({
|
|
577
|
+
sessionId: session.id,
|
|
578
|
+
livePeople: session.livePeople ?? [],
|
|
579
|
+
viewer: viewer?.userId ?? null,
|
|
580
|
+
wait: facts?.wait ?? null,
|
|
581
|
+
retirement: facts?.retirement ?? null,
|
|
582
|
+
members: viewer?.members ?? []
|
|
583
|
+
})
|
|
584
|
+
).flatMap((line) => {
|
|
585
|
+
const indent = line.startsWith(" ") ? " " : "";
|
|
586
|
+
return wrapWords(line, width - indent.length).map((row) => `${indent}${row}`);
|
|
587
|
+
});
|
|
588
|
+
var worktreeJoinRows = (data, projectId, worktree, viewerId, width) => {
|
|
589
|
+
const detail = data?.details.get(projectId);
|
|
590
|
+
const id = "id" in worktree ? worktree.id : detail?.worktrees?.find((candidate) => candidate.name === worktree.name)?.id;
|
|
591
|
+
if (detail === void 0 || id === void 0) return [];
|
|
592
|
+
const line = worktreeJoinLine(detail.sessions, id, viewerId);
|
|
593
|
+
return line === null ? [] : wrapWords(line, width);
|
|
594
|
+
};
|
|
544
595
|
var KEY_BINDINGS = [
|
|
545
596
|
{
|
|
546
597
|
verb: "moveUp",
|
|
@@ -2445,7 +2496,8 @@ var SessionFacts = ({
|
|
|
2445
2496
|
group,
|
|
2446
2497
|
item,
|
|
2447
2498
|
rows,
|
|
2448
|
-
tunnels
|
|
2499
|
+
tunnels,
|
|
2500
|
+
workspaceRows
|
|
2449
2501
|
}) => {
|
|
2450
2502
|
const { session, annotation, services } = item;
|
|
2451
2503
|
const color = STATUS_COLOR[session.status] ?? MUTED;
|
|
@@ -2476,6 +2528,18 @@ var SessionFacts = ({
|
|
|
2476
2528
|
/* @__PURE__ */ jsx3("span", { fg: MUTED, children: session.branch }),
|
|
2477
2529
|
/* @__PURE__ */ jsx3("span", { fg: FAINT, children: session.baseSha === "" ? "" : ` vs ${session.baseRef ?? session.baseSha.slice(0, 12)}` })
|
|
2478
2530
|
] }, "status"),
|
|
2531
|
+
// Who else is live here, what a turn waits for, a workspace waiting to be replaced: right
|
|
2532
|
+
// under the status, before the facts a short pane may drop.
|
|
2533
|
+
...workspaceRows.map((row, index) => /* @__PURE__ */ jsx3(
|
|
2534
|
+
"text",
|
|
2535
|
+
{
|
|
2536
|
+
height: 1,
|
|
2537
|
+
bg: "transparent",
|
|
2538
|
+
fg: row.startsWith(" ") ? MUTED : INK_2,
|
|
2539
|
+
children: ` ${row}`
|
|
2540
|
+
},
|
|
2541
|
+
`workspace-${index}`
|
|
2542
|
+
)),
|
|
2479
2543
|
/* @__PURE__ */ jsx3("text", { height: 1, bg: "transparent", fg: FAINT, children: [
|
|
2480
2544
|
...timeAgo(session.createdAt) === "" ? [] : [`created ${timeAgo(session.createdAt)}`],
|
|
2481
2545
|
isPendingId(session.id) ? "provisioning" : session.id.slice(0, 8),
|
|
@@ -2638,6 +2702,28 @@ var App = ({ ctx, onQuit }) => {
|
|
|
2638
2702
|
refetchInterval: previewLive ? 8e3 : false,
|
|
2639
2703
|
retry: 1
|
|
2640
2704
|
});
|
|
2705
|
+
const viewer = useQuery2({
|
|
2706
|
+
queryKey: VIEWER_KEY,
|
|
2707
|
+
queryFn: () => fetchViewer(ctx),
|
|
2708
|
+
enabled: viewerNeeded(data),
|
|
2709
|
+
staleTime: Number.POSITIVE_INFINITY,
|
|
2710
|
+
retry: false
|
|
2711
|
+
});
|
|
2712
|
+
const workspaceReads = selectedSession === null ? { waiting: false, retirement: false } : workspaceReadsOf(selectedSession);
|
|
2713
|
+
const workspaceFacts = useQuery2({
|
|
2714
|
+
queryKey: WORKSPACE_FACTS_KEY(previewSessionId ?? "none", workspaceReads),
|
|
2715
|
+
queryFn: () => fetchWorkspaceFacts(ctx.api, previewSessionId ?? "", workspaceReads),
|
|
2716
|
+
enabled: previewSessionId !== null && previewLive && detailWidth > 0 && (workspaceReads.waiting || workspaceReads.retirement),
|
|
2717
|
+
staleTime: 3e3,
|
|
2718
|
+
refetchInterval: previewLive ? 8e3 : false,
|
|
2719
|
+
retry: 1
|
|
2720
|
+
});
|
|
2721
|
+
const workspaceRows = selectedSession === null || !previewLive || detailWidth === 0 ? [] : workspaceFactRows(
|
|
2722
|
+
selectedSession,
|
|
2723
|
+
viewer.data,
|
|
2724
|
+
workspaceFacts.data,
|
|
2725
|
+
Math.max(16, detailWidth - 4)
|
|
2726
|
+
);
|
|
2641
2727
|
const preview = useMemo2(
|
|
2642
2728
|
() => transcript.data === void 0 ? [] : previewLines(transcript.data, {
|
|
2643
2729
|
width: Math.max(16, detailWidth - 6),
|
|
@@ -2646,7 +2732,10 @@ var App = ({ ctx, onQuit }) => {
|
|
|
2646
2732
|
[transcript.data, detailWidth]
|
|
2647
2733
|
);
|
|
2648
2734
|
const [previewOffset, setPreviewOffset] = useState3(0);
|
|
2649
|
-
const factRows = Math.max(
|
|
2735
|
+
const factRows = Math.max(
|
|
2736
|
+
0,
|
|
2737
|
+
Math.min(SESSION_FACT_ROWS + workspaceRows.length, layout.detailRows - 2)
|
|
2738
|
+
);
|
|
2650
2739
|
const showFactRule = factRows > 0 && layout.detailRows - factRows > 1;
|
|
2651
2740
|
const waiting = selectedSession !== null && (selectedSession.status === "starting" || isPendingId(selectedSession.id));
|
|
2652
2741
|
const snake = useSnake({
|
|
@@ -3614,6 +3703,22 @@ ${tunneled}
|
|
|
3614
3703
|
return COLUMN_TITLE[column];
|
|
3615
3704
|
};
|
|
3616
3705
|
const pickerTitle = picker === null ? "" : picker.worktree === void 0 ? picker.session === null ? "new session \xB7 pick a harness" : `resume ${sessionDisplayName(picker.session)} \xB7 pick a harness` : `new session in ${picker.worktree.name} \xB7 pick a harness`;
|
|
3706
|
+
const modalWidth = Math.min(74, terminalCols - 4);
|
|
3707
|
+
const pickerJoinRows = picker?.worktree?.id == null || selectedProject === null ? [] : worktreeJoinRows(
|
|
3708
|
+
data,
|
|
3709
|
+
selectedProject.project.id,
|
|
3710
|
+
{ id: picker.worktree.id },
|
|
3711
|
+
viewer.data?.userId ?? null,
|
|
3712
|
+
modalWidth - 4
|
|
3713
|
+
);
|
|
3714
|
+
const pickerJoinHeight = pickerJoinRows.length === 0 ? 0 : pickerJoinRows.length + 1;
|
|
3715
|
+
const creatingJoinRows = creating === null || !creating.joins ? [] : worktreeJoinRows(
|
|
3716
|
+
data,
|
|
3717
|
+
creating.projectId,
|
|
3718
|
+
{ name: creating.name },
|
|
3719
|
+
viewer.data?.userId ?? null,
|
|
3720
|
+
modalWidth - 7
|
|
3721
|
+
);
|
|
3617
3722
|
const creatingHeight = 2 + 1 + 1 + 6 + 1 + deriveHarnesses(null).length;
|
|
3618
3723
|
const footerText = adoptOffer === null ? editing === null ? creating === null ? picker === null ? ` ${fitHints(verbHints(focus), Math.max(12, terminalCols - 2))}` : " \u2191\u2193 move \xB7 enter start \xB7 esc cancel" : creating.step === "name" ? " enter continue \xB7 esc cancel" : creating.step === "base" ? " type to filter \xB7 \u2191\u2193 move \xB7 enter choose base \xB7 esc back" : " \u2191\u2193 move \xB7 enter launch \xB7 esc back" : " enter save \xB7 esc cancel" : " enter adopt \xB7 \u2190\u2192 auth mode \xB7 esc not now";
|
|
3619
3724
|
const loadFailure = data === void 0 && failureReason !== null ? errorText(failureReason) : null;
|
|
@@ -3786,7 +3891,8 @@ ${tunneled}
|
|
|
3786
3891
|
group: selectedGroup,
|
|
3787
3892
|
item: selectedItem,
|
|
3788
3893
|
rows: factRows,
|
|
3789
|
-
tunnels: openTunnels
|
|
3894
|
+
tunnels: openTunnels,
|
|
3895
|
+
workspaceRows
|
|
3790
3896
|
}
|
|
3791
3897
|
),
|
|
3792
3898
|
showFactRule ? /* @__PURE__ */ jsx3("text", { height: 1, bg: "transparent", fg: FAINT, children: ` ${"\u2500".repeat(Math.max(4, detailWidth - 4))}` }) : null,
|
|
@@ -3881,15 +3987,18 @@ ${tunneled}
|
|
|
3881
3987
|
]
|
|
3882
3988
|
}
|
|
3883
3989
|
) : null,
|
|
3884
|
-
picker === null ? null : /* @__PURE__ */
|
|
3990
|
+
picker === null ? null : /* @__PURE__ */ jsxs3(
|
|
3885
3991
|
"box",
|
|
3886
3992
|
{
|
|
3887
3993
|
position: "absolute",
|
|
3888
3994
|
zIndex: 12,
|
|
3889
3995
|
left: Math.max(1, Math.floor((terminalCols - Math.min(74, terminalCols - 4)) / 2)),
|
|
3890
|
-
top: Math.max(
|
|
3996
|
+
top: Math.max(
|
|
3997
|
+
1,
|
|
3998
|
+
Math.floor((terminalRows - (2 + pickerItems.length + pickerJoinHeight)) / 2)
|
|
3999
|
+
),
|
|
3891
4000
|
width: Math.min(74, terminalCols - 4),
|
|
3892
|
-
height: 2 + pickerItems.length,
|
|
4001
|
+
height: 2 + pickerItems.length + pickerJoinHeight,
|
|
3893
4002
|
border: true,
|
|
3894
4003
|
borderStyle: "rounded",
|
|
3895
4004
|
borderColor: ACCENT,
|
|
@@ -3897,15 +4006,19 @@ ${tunneled}
|
|
|
3897
4006
|
titleAlignment: "left",
|
|
3898
4007
|
backgroundColor: SURFACE,
|
|
3899
4008
|
flexDirection: "column",
|
|
3900
|
-
children:
|
|
3901
|
-
|
|
3902
|
-
{
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
4009
|
+
children: [
|
|
4010
|
+
pickerJoinRows.map((row, index) => /* @__PURE__ */ jsx3("text", { height: 1, bg: SURFACE, fg: INK_2, children: ` ${row}` }, `join-${index}`)),
|
|
4011
|
+
pickerJoinRows.length === 0 ? null : /* @__PURE__ */ jsx3("text", { height: 1, bg: SURFACE, children: " " }),
|
|
4012
|
+
pickerItems.map((item, index) => /* @__PURE__ */ jsx3(
|
|
4013
|
+
HarnessRow,
|
|
4014
|
+
{
|
|
4015
|
+
item,
|
|
4016
|
+
selected: index === pickerIndex,
|
|
4017
|
+
background: SURFACE
|
|
4018
|
+
},
|
|
4019
|
+
String(item.harness)
|
|
4020
|
+
))
|
|
4021
|
+
]
|
|
3909
4022
|
}
|
|
3910
4023
|
),
|
|
3911
4024
|
editing === null ? null : /* @__PURE__ */ jsx3(
|
|
@@ -4061,6 +4174,10 @@ ${tunneled}
|
|
|
4061
4174
|
const branch = creating.joins || creating.branches === null ? void 0 : filterBranches(creating.branches, creating.query)[index];
|
|
4062
4175
|
const active = creating.step === "base";
|
|
4063
4176
|
if (branch === void 0) {
|
|
4177
|
+
const joinRow = creatingJoinRows[index];
|
|
4178
|
+
if (joinRow !== void 0) {
|
|
4179
|
+
return /* @__PURE__ */ jsx3("text", { height: 1, bg: SURFACE, fg: INK_2, children: ` ${joinRow}` }, `slot-${index}`);
|
|
4180
|
+
}
|
|
4064
4181
|
const notice = creating.joins ? null : baseStepNotice(creating);
|
|
4065
4182
|
return /* @__PURE__ */ jsx3(
|
|
4066
4183
|
"text",
|