@akira-tl/forgerelay 1.2.3 → 1.2.4
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/CHANGELOG.md +15 -0
- package/capabilities/workspace/managed-worktrees/GUIDE.md +4 -2
- package/dist/mcp/server/core/schemas.js +6 -0
- package/dist/mcp/server/workspace/runtime/workspace-open-presentation.js +4 -2
- package/dist/mcp/server/workspace/runtime/workspace-open-schema.js +6 -1
- package/dist/mcp/server/workspace/runtime/workspace-open.js +19 -13
- package/dist/runtime/logging/logger.js +19 -19
- package/dist/ui/.vite/manifest.json +276 -276
- package/dist/ui/activity-panel-app.html +2 -2
- package/dist/ui/assets/activity-panel-app-Dq2xLIrs.css +1 -0
- package/dist/ui/assets/{activity-panel-app-BeDiwd7D.js → activity-panel-app-hkM8rX3z.js} +1 -1
- package/dist/ui/assets/{angular-html-DuoCE7nn.js → angular-html-UD0GEFFl.js} +1 -1
- package/dist/ui/assets/{angular-ts-D5tGk0hL.js → angular-ts-B2awh-Q1.js} +1 -1
- package/dist/ui/assets/{apl-lciOTPbw.js → apl-CpbhnJc8.js} +1 -1
- package/dist/ui/assets/{astro-vJbqfNnJ.js → astro-CkVVuF5B.js} +1 -1
- package/dist/ui/assets/{blade-C7655Q4K.js → blade-czG58aop.js} +1 -1
- package/dist/ui/assets/{c-DdHp1Jrw.js → c-DSq6h06b.js} +1 -1
- package/dist/ui/assets/{cobol-DgvzQxZP.js → cobol-CYnmhT2E.js} +1 -1
- package/dist/ui/assets/{coffee-BIjVUOUd.js → coffee-ClLhNqd5.js} +1 -1
- package/dist/ui/assets/{cpp-CU8tGzvI.js → cpp-BZDC6U43.js} +1 -1
- package/dist/ui/assets/{crystal-CUQAwsg9.js → crystal-BN9jCJyU.js} +1 -1
- package/dist/ui/assets/{css-DtMTqD3F.js → css-8dMfiihi.js} +1 -1
- package/dist/ui/assets/{edge-DoCX9RnL.js → edge-DemPBRNz.js} +1 -1
- package/dist/ui/assets/{elixir-DJxV9_U6.js → elixir-bLdHW8dz.js} +1 -1
- package/dist/ui/assets/{elm-DIgWqK4r.js → elm-DlZPcXmu.js} +1 -1
- package/dist/ui/assets/{erb-BHxP0c_e.js → erb-wmTqbHwm.js} +1 -1
- package/dist/ui/assets/{git-rebase-HbI_Vo8d.js → git-rebase-BqrZJVYO.js} +1 -1
- package/dist/ui/assets/{glimmer-js-CthY4Ty_.js → glimmer-js-CkPzdNHI.js} +1 -1
- package/dist/ui/assets/{glimmer-ts-B2-_A1Xz.js → glimmer-ts-Bd0vTdJC.js} +1 -1
- package/dist/ui/assets/{glsl-D9V9gq98.js → glsl-DKK0Kibz.js} +1 -1
- package/dist/ui/assets/{graphql-CddeAaS3.js → graphql-DmFr8ZvB.js} +1 -1
- package/dist/ui/assets/{hack-D_loGkOT.js → hack-BQcuk9lx.js} +1 -1
- package/dist/ui/assets/{haml-BoWDczd0.js → haml-Dbx0cG5B.js} +1 -1
- package/dist/ui/assets/{handlebars-ZoSOvw9y.js → handlebars-D0nD8yLi.js} +1 -1
- package/dist/ui/assets/{heavy-payload-DO34LwoZ.js → heavy-payload-CPOM8G8z.js} +3 -3
- package/dist/ui/assets/{html-CE-obXVo.js → html-9xkoIci1.js} +1 -1
- package/dist/ui/assets/{html-derivative-Cd-smAbW.js → html-derivative-Cg7n4YW0.js} +1 -1
- package/dist/ui/assets/{http-CZrkbrSl.js → http-Ckt_4_pP.js} +1 -1
- package/dist/ui/assets/{hurl-CxTuxBt1.js → hurl-BxMgqn9u.js} +1 -1
- package/dist/ui/assets/{java-BshLjCat.js → java-DxijgO-5.js} +1 -1
- package/dist/ui/assets/{javascript-D2pxQTiX.js → javascript-CusLzlRb.js} +1 -1
- package/dist/ui/assets/{jinja-kbfPP7-F.js → jinja-DBTRfImq.js} +1 -1
- package/dist/ui/assets/{jison-C2mt9l1M.js → jison-oCbVte0g.js} +1 -1
- package/dist/ui/assets/{json-DU_rg_AU.js → json-uq2yfoO2.js} +1 -1
- package/dist/ui/assets/{jsx-D_8aQMlx.js → jsx-B3AfJWyQ.js} +1 -1
- package/dist/ui/assets/{julia-BmefTaVV.js → julia-BFvq-UTm.js} +1 -1
- package/dist/ui/assets/{just-DXV8vk1S.js → just-Ck0W9Rcj.js} +1 -1
- package/dist/ui/assets/{latex-Cjm2MvGW.js → latex-BjKhTmaO.js} +1 -1
- package/dist/ui/assets/{liquid-DyQDlo0u.js → liquid-CsaE0q4b.js} +1 -1
- package/dist/ui/assets/{lua-B2A1vzzy.js → lua-D0MSBhv0.js} +1 -1
- package/dist/ui/assets/{marko-B9vOkXOU.js → marko-CTLxSPPr.js} +1 -1
- package/dist/ui/assets/{mdc-D42m6spU.js → mdc-BwDM_Bct.js} +1 -1
- package/dist/ui/assets/{nginx-TpfVxSUY.js → nginx-C5Q5rNaB.js} +1 -1
- package/dist/ui/assets/{nim-CJr5T1FK.js → nim-BjKHRt6k.js} +1 -1
- package/dist/ui/assets/{perl-cJZcsdm9.js → perl-BrABfniL.js} +1 -1
- package/dist/ui/assets/{php-CSZL5KRT.js → php-BWY__Khq.js} +1 -1
- package/dist/ui/assets/{pug-B1eMKzuA.js → pug-BD4PlwIK.js} +1 -1
- package/dist/ui/assets/{qml-Dl2_7zc9.js → qml-yQtdZNrK.js} +1 -1
- package/dist/ui/assets/{r-F0aaO9gG.js → r-D0tlixrf.js} +1 -1
- package/dist/ui/assets/{razor-BPnkSMCw.js → razor-CsmyuKJs.js} +1 -1
- package/dist/ui/assets/{regexp-BnGHMFbv.js → regexp-BXU4cTCD.js} +1 -1
- package/dist/ui/assets/{rst-B3CO7WYO.js → rst-CGlzAlrM.js} +1 -1
- package/dist/ui/assets/{ruby-B6VMzT1T.js → ruby-CRKDbfJj.js} +1 -1
- package/dist/ui/assets/{sas-Df2lHVuU.js → sas-CKDY6iPG.js} +1 -1
- package/dist/ui/assets/{scss-4XxI6sgu.js → scss-BCoXLSqD.js} +1 -1
- package/dist/ui/assets/{shellscript-DYASCN4r.js → shellscript-BVuRs_tF.js} +1 -1
- package/dist/ui/assets/{shellsession-Br6AGJO_.js → shellsession-alj1b7vN.js} +1 -1
- package/dist/ui/assets/{soy-p3ZNq1We.js → soy-BbQDrw9i.js} +1 -1
- package/dist/ui/assets/{sql-CAdv2OXL.js → sql-BdcqHaEA.js} +1 -1
- package/dist/ui/assets/{stata-Dx7yUbG_.js → stata-5IC5m_XB.js} +1 -1
- package/dist/ui/assets/{surrealql-6YsE8HQa.js → surrealql-BfVFLYzV.js} +1 -1
- package/dist/ui/assets/{svelte-YgzedwpD.js → svelte-B22aFi25.js} +1 -1
- package/dist/ui/assets/{templ-Bahqx3uD.js → templ-BRo7TcBX.js} +1 -1
- package/dist/ui/assets/{tex-o6fTQjkH.js → tex-CYhw-JbD.js} +1 -1
- package/dist/ui/assets/{ts-tags-BO-Co0Ju.js → ts-tags-C56aGOzq.js} +1 -1
- package/dist/ui/assets/{tsx-DtQe5AoH.js → tsx-IkFyQoro.js} +1 -1
- package/dist/ui/assets/{twig-BcUs6Kqc.js → twig-NkXaxf7l.js} +1 -1
- package/dist/ui/assets/{typescript-BPtM8h4u.js → typescript-AgbZakqy.js} +1 -1
- package/dist/ui/assets/{vue-5KkGUzJJ.js → vue-Cxz1Rk-f.js} +1 -1
- package/dist/ui/assets/{vue-html-Df_Xfsz9.js → vue-html-DWHLzP-w.js} +1 -1
- package/dist/ui/assets/{vue-vine-hUIe_u_Y.js → vue-vine-WR64TKte.js} +1 -1
- package/dist/ui/assets/{xml-C3Jy7as5.js → xml-CNdUn7jo.js} +1 -1
- package/dist/ui/assets/{xsl-BnF9OuFo.js → xsl-DLRRUZ98.js} +1 -1
- package/dist/ui/assets/{yaml-DyrFgCou.js → yaml-gltXViA8.js} +1 -1
- package/dist/workspace-colors.js +54 -0
- package/dist/workspaces/git/git-worktrees.js +53 -14
- package/dist/workspaces/inventory.js +2 -0
- package/dist/workspaces/presentation/workspace-presentation.js +13 -0
- package/dist/workspaces/relay/workspace-relay.js +3 -0
- package/dist/workspaces/sessions.js +28 -8
- package/dist/workspaces.js +9 -9
- package/docs/chatgpt-coding-workflow.md +16 -8
- package/docs/gotchas.md +2 -2
- package/package.json +2 -1
- package/scripts/ci/cmd-acceptance.mjs +3 -85
- package/scripts/ci/gates/acceptance-runtime.mjs +45 -0
- package/scripts/ci/gates/platform-tests.mjs +27 -17
- package/scripts/ci/gates/prepare-windows-shell-runtime.mjs +45 -0
- package/scripts/ci/gates/test-shard.mjs +29 -7
- package/scripts/ci/powershell51-acceptance.mjs +10 -91
- package/scripts/ci/pwsh-acceptance.mjs +7 -87
- package/scripts/ci/windows-product-acceptance.mjs +55 -0
- package/scripts/release/release-gate.test.mjs +121 -13
- package/scripts/release-parity.mjs +12 -1
- package/dist/ui/assets/activity-panel-app-DkfJzTZ3.css +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,21 @@ All notable ForgeRelay changes are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.2.4] - 2026-09-15
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Managed worktrees can now start from arbitrary Git commit-ish refs while keeping their integration target branch independent, so a pinned historical baseline no longer has to be a local branch.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Release verification now splits more independent CI work in parallel and reuses pinned npm / packaged shell runtime state where safe, reducing repeated setup in the cross-platform release matrix.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Pinned-base managed worktrees now preserve their baseline metadata across reuse, reopen, recovery, rebase, and close, while still integrating into the configured target branch; pinned workspaces with different immutable baselines no longer collapse onto one reuse identity.
|
|
20
|
+
- Workspace Panel long paths now wrap instead of truncating important Root / checkout details, and Workspace identity color is shared consistently between pretty logs and Panel SVG icons. The identity palette now uses 14 normal/bright terminal color slots, avoids duplicates for the first 14 distinct Workspace names in one process, and normalizes both POSIX and Windows-style paths consistently.
|
|
21
|
+
|
|
7
22
|
## [1.2.3] - 2026-09-14
|
|
8
23
|
|
|
9
24
|
### Fixed
|
|
@@ -15,8 +15,10 @@
|
|
|
15
15
|
|
|
16
16
|
- 默认 `mode="checkout"`,直接使用用户已有 checkout;
|
|
17
17
|
- 只有明确需要隔离/并行 Git 工作时才选 `mode="worktree"`;
|
|
18
|
-
- `baseRef` 只用于 managed worktree
|
|
19
|
-
-
|
|
18
|
+
- `baseRef` 只用于 managed worktree,表示新 managed branch 的起始 commit-ish;可以是本地 branch、tag、commit SHA 等可解析到 commit 的 ref,默认使用 source checkout 当前 `HEAD`;
|
|
19
|
+
- `targetBranch` 表示最终允许 `close_workspace` fast-forward 的本地 branch;未显式指定时,本地 branch `baseRef` 自身优先作为 target,否则使用 source checkout 当前本地 branch;detached source 无法推导 target 时必须显式提供;
|
|
20
|
+
- 显式固定到历史 base 的请求按解析后的 `baseSha` 区分复用身份,不会与同一 target 上另一历史 base 或普通 branch-following backing 混用;
|
|
21
|
+
- 已有 `workspaceId` 用于恢复同一个逻辑 workspace;closed managed-worktree Workspace reopen 时从当前持久化 `targetBranch` 建立新 backing,不重新钉回最初的历史 `baseRef`;
|
|
20
22
|
- `newWorkspace` 只创建新的逻辑 handle;
|
|
21
23
|
- `newWorktree` 才表示同一项目再创建一个独立物理 worktree。
|
|
22
24
|
|
|
@@ -122,6 +122,8 @@ export const workspaceInventoryEntryOutputSchema = z.object({
|
|
|
122
122
|
state: z.enum(["active", "stale", "invalid", "closed"]),
|
|
123
123
|
mode: z.enum(["checkout", "worktree"]),
|
|
124
124
|
sourceRoot: z.string().optional(),
|
|
125
|
+
baseRef: z.string().optional(),
|
|
126
|
+
baseSha: z.string().optional(),
|
|
125
127
|
branch: z.string().optional(),
|
|
126
128
|
targetBranch: z.string().optional(),
|
|
127
129
|
managed: z.boolean(),
|
|
@@ -181,6 +183,8 @@ export const workspaceInspectionOutputSchema = z.union([
|
|
|
181
183
|
state: z.enum(["active", "stale", "invalid", "closed"]),
|
|
182
184
|
mode: z.enum(["checkout", "worktree"]),
|
|
183
185
|
sourceRoot: z.string().optional(),
|
|
186
|
+
baseRef: z.string().optional(),
|
|
187
|
+
baseSha: z.string().optional(),
|
|
184
188
|
branch: z.string().optional(),
|
|
185
189
|
targetBranch: z.string().optional(),
|
|
186
190
|
managed: z.boolean(),
|
|
@@ -201,6 +205,8 @@ export const workspaceInspectionOutputSchema = z.union([
|
|
|
201
205
|
state: z.enum(["active", "stale", "invalid", "closed"]).optional(),
|
|
202
206
|
mode: z.enum(["checkout", "worktree"]),
|
|
203
207
|
sourceRoot: z.string().optional(),
|
|
208
|
+
baseRef: z.string().optional(),
|
|
209
|
+
baseSha: z.string().optional(),
|
|
204
210
|
branch: z.string().optional(),
|
|
205
211
|
targetBranch: z.string().optional(),
|
|
206
212
|
managed: z.boolean().optional(),
|
|
@@ -10,13 +10,14 @@ import { capabilityContextFor } from "../../core/capability-support.js";
|
|
|
10
10
|
import { redactSkillDiagnosticPaths } from "../../core/schemas.js";
|
|
11
11
|
import { logToolCall, workspaceLogContext } from "../../core/tool-support.js";
|
|
12
12
|
import { buildExecutionShellContext } from "../../../server-instructions.js";
|
|
13
|
+
import { workspaceColorFor, workspaceIdentityName } from "../../../../workspace-colors.js";
|
|
13
14
|
export const workspaceTaskUsageInstruction = "Use workspace.tasks proactively for work that spans multiple steps or sessions: create or update Tasks to preserve useful next steps and current state, and read its summary when resuming relevant unfinished work. Do not query it mechanically on every open_workspace call.";
|
|
14
15
|
export const capabilityDiscoveryInstruction = "For capability describe/run, use only names present in capabilityCatalog. capabilityFingerprint.capabilities is a semantic feature fingerprint, not a callable registry; capabilityGuides are documentation descriptors, not callable capabilities.";
|
|
15
16
|
export async function presentLocalWorkspaceOpen(options, input, contextData) {
|
|
16
17
|
const { config, forgerelayVersion: FORGERELAY_VERSION, workspaces, workspaceTasks, reviewCheckpoints, capabilityRegistry, subagentProviders, hooks, rememberWorkspacePanelState, } = options;
|
|
17
|
-
const { path, workspaceId, mode, baseRef, newWorktree, newWorkspace, context } = input;
|
|
18
|
+
const { path, workspaceId, mode, baseRef, targetBranch, newWorktree, newWorkspace, context } = input;
|
|
18
19
|
const { conversationScopeId, protectedWorkspaceIds, startedAt, sessionId } = contextData;
|
|
19
|
-
const { workspace, agentsFiles, availableAgentsFiles, hookReports, workspaceReused, bootstrapContextComponents, contextFingerprint, } = await workspaces.openWorkspace({ path, workspaceId, mode, baseRef, newWorktree, newWorkspace, context }, {
|
|
20
|
+
const { workspace, agentsFiles, availableAgentsFiles, hookReports, workspaceReused, bootstrapContextComponents, contextFingerprint, } = await workspaces.openWorkspace({ path, workspaceId, mode, baseRef, targetBranch, newWorktree, newWorkspace, context }, {
|
|
20
21
|
conversationScopeId,
|
|
21
22
|
protectedWorkspaceIds,
|
|
22
23
|
});
|
|
@@ -189,6 +190,7 @@ export async function presentLocalWorkspaceOpen(options, input, contextData) {
|
|
|
189
190
|
kind: "workspace",
|
|
190
191
|
root: workspace.root,
|
|
191
192
|
path: workspace.root,
|
|
193
|
+
workspaceColor: workspaceColorFor(workspaceIdentityName(workspace.root)),
|
|
192
194
|
mode: workspace.mode,
|
|
193
195
|
workspaceReused,
|
|
194
196
|
includeBootstrapContext: effectiveIncludeBootstrapContext,
|
|
@@ -21,6 +21,7 @@ export const openWorkspaceToolDefinition = {
|
|
|
21
21
|
relay: z.string().optional().describe("Optional registered remote ForgeRelay alias for a path-backed member."),
|
|
22
22
|
mode: z.enum(["checkout", "worktree"]).optional(),
|
|
23
23
|
baseRef: z.string().optional(),
|
|
24
|
+
targetBranch: z.string().optional(),
|
|
24
25
|
newWorktree: z.boolean().optional(),
|
|
25
26
|
newWorkspace: z.boolean().optional(),
|
|
26
27
|
}).optional().describe("Composite member definition used by action=member."),
|
|
@@ -55,7 +56,11 @@ export const openWorkspaceToolDefinition = {
|
|
|
55
56
|
baseRef: z
|
|
56
57
|
.string()
|
|
57
58
|
.optional()
|
|
58
|
-
.describe("
|
|
59
|
+
.describe("Commit-ish to base a managed worktree on. Only used with mode=\"worktree\"; may be a local branch, tag, commit SHA, or other ref that resolves to a commit. Defaults to HEAD."),
|
|
60
|
+
targetBranch: z
|
|
61
|
+
.string()
|
|
62
|
+
.optional()
|
|
63
|
+
.describe("Existing local branch that close_workspace may fast-forward when finalizing the managed worktree. Only used with mode=\"worktree\". Defaults to baseRef when baseRef names a local branch, otherwise the source checkout's current local branch."),
|
|
59
64
|
newWorktree: z
|
|
60
65
|
.boolean()
|
|
61
66
|
.optional()
|
|
@@ -4,6 +4,7 @@ import { formatPathForPrompt } from "../../../../workspaces/resources/skills.js"
|
|
|
4
4
|
import { compositeCapabilityContext } from "../../core/capability-support.js";
|
|
5
5
|
import { compositeWorkspaceLogContext, logToolCall, textBlock } from "../../core/tool-support.js";
|
|
6
6
|
import { openWorkspaceToolDefinition } from "./workspace-open-schema.js";
|
|
7
|
+
import { workspaceColorFor, workspaceIdentityName } from "../../../../workspace-colors.js";
|
|
7
8
|
import { presentLocalWorkspaceOpen, workspaceTaskUsageInstruction, } from "./workspace-open-presentation.js";
|
|
8
9
|
export function registerOpenWorkspaceTool(options) {
|
|
9
10
|
const { server } = options;
|
|
@@ -11,7 +12,7 @@ export function registerOpenWorkspaceTool(options) {
|
|
|
11
12
|
}
|
|
12
13
|
async function handleOpenWorkspace(options, input, requestContext) {
|
|
13
14
|
const { config, workspaces, remoteWorkspaces, compositeWorkspaces, workspaceTasks, processSessions, capabilityRegistry, compositeTaskGuides, loadCompositeMemberContext, rememberWorkspacePanelState, hostScopeIdFor, contextDeliveryScopeIdFor, presentation, } = options;
|
|
14
|
-
const { action = "open", memberAction, member, kind, name, memberName, path, relay, workspaceId, mode, baseRef, newWorktree, newWorkspace, context, root, status, state, staleOnly, offset, limit, } = input;
|
|
15
|
+
const { action = "open", memberAction, member, kind, name, memberName, path, relay, workspaceId, mode, baseRef, targetBranch, newWorktree, newWorkspace, context, root, status, state, staleOnly, offset, limit, } = input;
|
|
15
16
|
const startedAt = performance.now();
|
|
16
17
|
const conversationScopeId = contextDeliveryScopeIdFor(requestContext);
|
|
17
18
|
const protectedWorkspaceIds = processSessions.activeWorkspaceIds();
|
|
@@ -82,7 +83,7 @@ async function handleOpenWorkspace(options, input, requestContext) {
|
|
|
82
83
|
}
|
|
83
84
|
if (memberAction !== undefined || member !== undefined || kind !== undefined || name !== undefined ||
|
|
84
85
|
memberName !== undefined || path !== undefined || relay !== undefined || mode !== undefined ||
|
|
85
|
-
baseRef !== undefined || newWorktree !== undefined || newWorkspace !== undefined || context !== undefined ||
|
|
86
|
+
baseRef !== undefined || targetBranch !== undefined || newWorktree !== undefined || newWorkspace !== undefined || context !== undefined ||
|
|
86
87
|
root !== undefined || status !== undefined || state !== undefined || staleOnly !== undefined ||
|
|
87
88
|
offset !== undefined || limit !== undefined) {
|
|
88
89
|
throw new Error("open_workspace action=inspect accepts only workspaceId. It never opens, resumes, binds, or mutates the inspected Workspace.");
|
|
@@ -156,7 +157,7 @@ async function handleOpenWorkspace(options, input, requestContext) {
|
|
|
156
157
|
throw new Error("open_workspace action=member requires memberAction and member.");
|
|
157
158
|
}
|
|
158
159
|
if (kind !== undefined || name !== undefined || memberName !== undefined || path !== undefined || relay !== undefined || mode !== undefined ||
|
|
159
|
-
baseRef !== undefined || newWorktree !== undefined || newWorkspace !== undefined || context !== undefined ||
|
|
160
|
+
baseRef !== undefined || targetBranch !== undefined || newWorktree !== undefined || newWorkspace !== undefined || context !== undefined ||
|
|
160
161
|
root !== undefined || status !== undefined || state !== undefined || staleOnly !== undefined ||
|
|
161
162
|
offset !== undefined || limit !== undefined) {
|
|
162
163
|
throw new Error("open_workspace action=member accepts workspaceId, memberAction, and member only. Put any Workspace open definition inside member.");
|
|
@@ -173,8 +174,8 @@ async function handleOpenWorkspace(options, input, requestContext) {
|
|
|
173
174
|
throw new Error("A Composite Workspace cannot be mounted as a Composite Workspace member.");
|
|
174
175
|
}
|
|
175
176
|
if (member.relay !== undefined || member.mode !== undefined || member.baseRef !== undefined ||
|
|
176
|
-
member.newWorktree !== undefined || member.newWorkspace !== undefined) {
|
|
177
|
-
throw new Error("member.workspaceId cannot be combined with relay/mode/baseRef/newWorktree/newWorkspace.");
|
|
177
|
+
member.targetBranch !== undefined || member.newWorktree !== undefined || member.newWorkspace !== undefined) {
|
|
178
|
+
throw new Error("member.workspaceId cannot be combined with relay/mode/baseRef/targetBranch/newWorktree/newWorkspace.");
|
|
178
179
|
}
|
|
179
180
|
if (!remoteWorkspaces.has(targetWorkspaceId))
|
|
180
181
|
workspaces.getWorkspace(targetWorkspaceId);
|
|
@@ -185,6 +186,7 @@ async function handleOpenWorkspace(options, input, requestContext) {
|
|
|
185
186
|
path: member.path,
|
|
186
187
|
...(member.mode ? { mode: member.mode } : {}),
|
|
187
188
|
...(member.baseRef ? { baseRef: member.baseRef } : {}),
|
|
189
|
+
...(member.targetBranch ? { targetBranch: member.targetBranch } : {}),
|
|
188
190
|
...(member.newWorktree !== undefined ? { newWorktree: member.newWorktree } : {}),
|
|
189
191
|
...(member.newWorkspace !== undefined ? { newWorkspace: member.newWorkspace } : {}),
|
|
190
192
|
context: "none",
|
|
@@ -195,6 +197,7 @@ async function handleOpenWorkspace(options, input, requestContext) {
|
|
|
195
197
|
path: member.path,
|
|
196
198
|
...(member.mode ? { mode: member.mode } : {}),
|
|
197
199
|
...(member.baseRef ? { baseRef: member.baseRef } : {}),
|
|
200
|
+
...(member.targetBranch ? { targetBranch: member.targetBranch } : {}),
|
|
198
201
|
...(member.newWorktree !== undefined ? { newWorktree: member.newWorktree } : {}),
|
|
199
202
|
...(member.newWorkspace !== undefined ? { newWorkspace: member.newWorkspace } : {}),
|
|
200
203
|
context: "none",
|
|
@@ -218,8 +221,8 @@ async function handleOpenWorkspace(options, input, requestContext) {
|
|
|
218
221
|
}
|
|
219
222
|
else if (memberAction === "update") {
|
|
220
223
|
const targetFieldsPresent = member.workspaceId !== undefined || member.path !== undefined || member.relay !== undefined ||
|
|
221
|
-
member.mode !== undefined || member.baseRef !== undefined || member.
|
|
222
|
-
member.newWorkspace !== undefined;
|
|
224
|
+
member.mode !== undefined || member.baseRef !== undefined || member.targetBranch !== undefined ||
|
|
225
|
+
member.newWorktree !== undefined || member.newWorkspace !== undefined;
|
|
223
226
|
if (member.newName === undefined && member.purpose === undefined && !targetFieldsPresent) {
|
|
224
227
|
throw new Error("Updating a Composite Workspace member requires newName, purpose, or a replacement Workspace target.");
|
|
225
228
|
}
|
|
@@ -235,7 +238,7 @@ async function handleOpenWorkspace(options, input, requestContext) {
|
|
|
235
238
|
else {
|
|
236
239
|
if (member.newName !== undefined || member.purpose !== undefined || member.workspaceId !== undefined || member.path !== undefined ||
|
|
237
240
|
member.relay !== undefined || member.mode !== undefined || member.baseRef !== undefined ||
|
|
238
|
-
member.newWorktree !== undefined || member.newWorkspace !== undefined) {
|
|
241
|
+
member.targetBranch !== undefined || member.newWorktree !== undefined || member.newWorkspace !== undefined) {
|
|
239
242
|
throw new Error("Removing a Composite Workspace member accepts only member.name.");
|
|
240
243
|
}
|
|
241
244
|
composite = compositeWorkspaces.removeMember(workspaceId, member.name);
|
|
@@ -291,9 +294,9 @@ async function handleOpenWorkspace(options, input, requestContext) {
|
|
|
291
294
|
return response;
|
|
292
295
|
}
|
|
293
296
|
if (action === "list") {
|
|
294
|
-
if (path !== undefined || relay !== undefined || name !== undefined || memberName !== undefined || baseRef !== undefined ||
|
|
295
|
-
newWorkspace !== undefined || context !== undefined) {
|
|
296
|
-
throw new Error("open_workspace action=list does not accept path, relay, name, memberName, baseRef, newWorktree, newWorkspace, or context. Use kind/root/workspaceId/mode/status/state/staleOnly for inventory filters.");
|
|
297
|
+
if (path !== undefined || relay !== undefined || name !== undefined || memberName !== undefined || baseRef !== undefined || targetBranch !== undefined ||
|
|
298
|
+
newWorktree !== undefined || newWorkspace !== undefined || context !== undefined) {
|
|
299
|
+
throw new Error("open_workspace action=list does not accept path, relay, name, memberName, baseRef, targetBranch, newWorktree, newWorkspace, or context. Use kind/root/workspaceId/mode/status/state/staleOnly for inventory filters.");
|
|
297
300
|
}
|
|
298
301
|
const compositeInventory = () => compositeWorkspaces.list()
|
|
299
302
|
.filter((entry) => workspaceId === undefined || entry.id === workspaceId)
|
|
@@ -382,7 +385,7 @@ async function handleOpenWorkspace(options, input, requestContext) {
|
|
|
382
385
|
const openingComposite = kind === "composite" ||
|
|
383
386
|
(workspaceId !== undefined && compositeWorkspaces.has(workspaceId));
|
|
384
387
|
if (openingComposite) {
|
|
385
|
-
if (relay !== undefined || path !== undefined || mode !== undefined || baseRef !== undefined ||
|
|
388
|
+
if (relay !== undefined || path !== undefined || mode !== undefined || baseRef !== undefined || targetBranch !== undefined ||
|
|
386
389
|
newWorktree !== undefined || newWorkspace !== undefined) {
|
|
387
390
|
throw new Error("Composite Workspace open accepts name/workspaceId/context only; members are attached separately and keep their own Workspace definitions.");
|
|
388
391
|
}
|
|
@@ -432,6 +435,7 @@ async function handleOpenWorkspace(options, input, requestContext) {
|
|
|
432
435
|
kind: "composite",
|
|
433
436
|
name: composite.name,
|
|
434
437
|
path: composite.name,
|
|
438
|
+
workspaceColor: workspaceColorFor(workspaceIdentityName(composite.name)),
|
|
435
439
|
members: composite.members,
|
|
436
440
|
instruction,
|
|
437
441
|
summary: { members: composite.members.length, status: composite.status },
|
|
@@ -464,7 +468,7 @@ async function handleOpenWorkspace(options, input, requestContext) {
|
|
|
464
468
|
throw new Error("open_workspace name/memberName are only valid for a Composite Workspace.");
|
|
465
469
|
}
|
|
466
470
|
if (workspaceId !== undefined && remoteWorkspaces.has(workspaceId)) {
|
|
467
|
-
if (path !== undefined || relay !== undefined || mode !== undefined || baseRef !== undefined ||
|
|
471
|
+
if (path !== undefined || relay !== undefined || mode !== undefined || baseRef !== undefined || targetBranch !== undefined ||
|
|
468
472
|
newWorktree !== undefined || newWorkspace !== undefined) {
|
|
469
473
|
throw new Error("Resuming a relayed Workspace by workspaceId accepts context only.");
|
|
470
474
|
}
|
|
@@ -479,6 +483,7 @@ async function handleOpenWorkspace(options, input, requestContext) {
|
|
|
479
483
|
path,
|
|
480
484
|
mode,
|
|
481
485
|
baseRef,
|
|
486
|
+
targetBranch,
|
|
482
487
|
newWorktree,
|
|
483
488
|
newWorkspace,
|
|
484
489
|
context,
|
|
@@ -511,6 +516,7 @@ async function handleOpenWorkspace(options, input, requestContext) {
|
|
|
511
516
|
kind: "workspace",
|
|
512
517
|
root: opened.root,
|
|
513
518
|
path: opened.root,
|
|
519
|
+
workspaceColor: workspaceColorFor(workspaceIdentityName(opened.root)),
|
|
514
520
|
mode: opened.mode,
|
|
515
521
|
relay,
|
|
516
522
|
instruction: opened.instruction,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { basename } from "node:path";
|
|
2
1
|
import { styleText } from "node:util";
|
|
2
|
+
import { workspaceColorFor, workspaceIdentityName, } from "../../workspace-colors.js";
|
|
3
3
|
const LEVEL_WEIGHT = {
|
|
4
4
|
silent: 0,
|
|
5
5
|
error: 1,
|
|
@@ -13,14 +13,22 @@ const LEVEL_STYLE = {
|
|
|
13
13
|
info: "green",
|
|
14
14
|
debug: "gray",
|
|
15
15
|
};
|
|
16
|
-
const WORKSPACE_PROJECT_COLORS =
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
|
|
16
|
+
const WORKSPACE_PROJECT_COLORS = {
|
|
17
|
+
red: "red",
|
|
18
|
+
green: "green",
|
|
19
|
+
yellow: "yellow",
|
|
20
|
+
blue: "blue",
|
|
21
|
+
magenta: "magenta",
|
|
22
|
+
cyan: "cyan",
|
|
23
|
+
white: "white",
|
|
24
|
+
redBright: "redBright",
|
|
25
|
+
greenBright: "greenBright",
|
|
26
|
+
yellowBright: "yellowBright",
|
|
27
|
+
blueBright: "blueBright",
|
|
28
|
+
magentaBright: "magentaBright",
|
|
29
|
+
cyanBright: "cyanBright",
|
|
30
|
+
whiteBright: "whiteBright",
|
|
31
|
+
};
|
|
24
32
|
export function shouldLog(config, level) {
|
|
25
33
|
return LEVEL_WEIGHT[config.level] >= LEVEL_WEIGHT[level];
|
|
26
34
|
}
|
|
@@ -59,7 +67,7 @@ export function transportSessionIdPrefix(transportSessionId) {
|
|
|
59
67
|
/** @deprecated Use transportSessionIdPrefix. */
|
|
60
68
|
export const sessionIdPrefix = transportSessionIdPrefix;
|
|
61
69
|
export function workspaceLogLabel(root, workspaceId) {
|
|
62
|
-
return `${
|
|
70
|
+
return `${workspaceIdentityName(root)}/${workspaceId}`;
|
|
63
71
|
}
|
|
64
72
|
export function commandPreview(command) {
|
|
65
73
|
const normalized = command.replace(/\s+/g, " ").trim();
|
|
@@ -215,17 +223,9 @@ function formatPrettySource(source, options) {
|
|
|
215
223
|
}
|
|
216
224
|
const project = source.slice(0, separator);
|
|
217
225
|
const workspace = source.slice(separator + 1);
|
|
218
|
-
const projectColor = WORKSPACE_PROJECT_COLORS[
|
|
226
|
+
const projectColor = WORKSPACE_PROJECT_COLORS[workspaceColorFor(project)];
|
|
219
227
|
return `${style([projectColor, "bold"], project, options)}/${style(["cyan", "underline"], workspace, options)}`;
|
|
220
228
|
}
|
|
221
|
-
function stableColorIndex(value) {
|
|
222
|
-
let hash = 2166136261;
|
|
223
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
224
|
-
hash ^= value.charCodeAt(index);
|
|
225
|
-
hash = Math.imul(hash, 16777619);
|
|
226
|
-
}
|
|
227
|
-
return (hash >>> 0) % WORKSPACE_PROJECT_COLORS.length;
|
|
228
|
-
}
|
|
229
229
|
function formatRuntimeResources(entry) {
|
|
230
230
|
const rssMb = bytesToMegabytes(numberField(entry.rssBytes));
|
|
231
231
|
const heapUsedMb = bytesToMegabytes(numberField(entry.heapUsedBytes));
|