Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 37 additions & 21 deletions Sources/OrreryCore/Commands/InstallCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ public struct InstallCommand: ParsableCommand {
record.packageID,
shortRef,
record.copiedFiles.count,
claudeAccountLabel(forEnv: resolvedEnv)
claudeAccountLabel(forEnv: resolvedEnv),
claudeWorkspaceLabel(forEnv: resolvedEnv)
))
}
}
Expand All @@ -54,27 +55,42 @@ func installCurrentEnvOrThrow() throws -> String {
return env ?? Workspace.reservedOriginName
}

/// The claude account add-ons are actually installed into / removed from (the
/// account dir, not the workspace). Resolves the active `CLAUDE_CONFIG_DIR`, else
/// the claude account pinned to `env`, and returns its display name. Falls back
/// to the env name when no account can be resolved.
func claudeAccountLabel(forEnv env: String) -> String {
let configDir: String?
/// Resolve the claude account dir add-ons install into / are removed from (the
/// account dir, not the workspace): the active `CLAUDE_CONFIG_DIR`, else the
/// claude account pinned to `env`. Nil when no account can be resolved.
func claudeAccountDirPath(forEnv env: String) -> String? {
if let live = ProcessInfo.processInfo.environment["CLAUDE_CONFIG_DIR"], !live.isEmpty {
configDir = live
} else {
let store = EnvironmentStore.default
let pins = (env == Workspace.reservedOriginName)
? store.loadOriginWorkspace().accounts
: ((try? store.load(named: env).accounts) ?? [:])
configDir = pins[Tool.claude.rawValue]
.map { AccountStore.default.accountDir(id: $0, tool: .claude).path }
return live
}
guard let configDir,
let data = try? Data(contentsOf: URL(fileURLWithPath: configDir)
let store = EnvironmentStore.default
let pins = (env == Workspace.reservedOriginName)
? store.loadOriginWorkspace().accounts
: ((try? store.load(named: env).accounts) ?? [:])
return pins[Tool.claude.rawValue]
.map { AccountStore.default.accountDir(id: $0, tool: .claude).path }
}

/// The resolved account's `metadata.json` as a dict, if readable.
private func claudeAccountMetadata(forEnv env: String) -> [String: Any]? {
guard let dir = claudeAccountDirPath(forEnv: env),
let data = try? Data(contentsOf: URL(fileURLWithPath: dir)
.appendingPathComponent("metadata.json")),
let obj = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let name = obj["displayName"] as? String
else { return env }
return name
let obj = try? JSONSerialization.jsonObject(with: data) as? [String: Any]
else { return nil }
return obj
}

/// Display name of the account add-ons install into. Falls back to the env name.
func claudeAccountLabel(forEnv env: String) -> String {
claudeAccountMetadata(forEnv: env)?["displayName"] as? String ?? env
}

/// The workspace the target account is pinned to (`metadata.json` `workspace`,
/// absent ⇒ origin) — where the shared add-on files (e.g. the statusline
/// program) actually land.
func claudeWorkspaceLabel(forEnv env: String) -> String {
guard let ws = claudeAccountMetadata(forEnv: env)?["workspace"] as? String,
!ws.isEmpty
else { return Workspace.reservedOriginName }
return ws
}
2 changes: 1 addition & 1 deletion Sources/OrreryCore/Resources/Localization/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@
"install.urlHelp": "Override the manifest source URL (use a custom git repository)",
"install.refHelp": "Override the manifest source ref (git branch/tag/sha)",
"install.forceRefreshHelp": "Re-clone the source even if the cached copy already exists",
"install.success": "Installed {id} ({shortRef}) into account '{env}'. {fileCount} files copied, settings patched.",
"install.success": "Installed {id} ({shortRef}) into account '{env}' in workspace '{workspace}'. {fileCount} files copied, settings patched.",
"thirdparty.abstract": "Manage installed third-party add-ons for an environment",
"thirdparty.idHelp": "Package id (e.g. statusline)",
"thirdparty.envHelp": "Target environment name",
Expand Down
2 changes: 1 addition & 1 deletion Sources/OrreryCore/Resources/Localization/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@
"install.urlHelp": "Override the manifest source URL (use a custom git repository)",
"install.refHelp": "Override the manifest source ref (git branch/tag/sha)",
"install.forceRefreshHelp": "Re-clone the source even if the cached copy already exists",
"install.success": "Installed {id} ({shortRef}) into account '{env}'. {fileCount} files copied, settings patched.",
"install.success": "Installed {id} ({shortRef}) into account '{env}' in workspace '{workspace}'. {fileCount} files copied, settings patched.",
"thirdparty.abstract": "Manage installed third-party add-ons for an environment",
"thirdparty.idHelp": "Package id (e.g. statusline)",
"thirdparty.envHelp": "Target environment name",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2335,7 +2335,8 @@
{ "label": "_", "name": "id", "type": "String" },
{ "label": "_", "name": "shortRef", "type": "String" },
{ "label": "_", "name": "fileCount", "type": "Int" },
{ "label": "_", "name": "env", "type": "String" }
{ "label": "_", "name": "env", "type": "String" },
{ "label": "_", "name": "workspace", "type": "String" }
]
},
{ "path": ["Thirdparty", "abstract"], "kind": "var", "parameters": [] },
Expand Down
2 changes: 1 addition & 1 deletion Sources/OrreryCore/Resources/Localization/zh-Hant.json
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@
"install.urlHelp": "覆寫 manifest 的來源 URL(改用自訂 git repo)",
"install.refHelp": "覆寫 manifest 的來源 ref(git branch/tag/sha)",
"install.forceRefreshHelp": "即使 cache 已存在也強制重新 clone",
"install.success": "已將 {id}({shortRef})安裝到帳號「{env}」,複製 {fileCount} 個檔案並更新 settings。",
"install.success": "已將 {id}({shortRef})安裝到帳號「{env}」所在的 workspace「{workspace}」,複製 {fileCount} 個檔案並更新 settings。",
"thirdparty.abstract": "管理環境已安裝的第三方外掛",
"thirdparty.idHelp": "套件 id(例如 statusline)",
"thirdparty.envHelp": "目標環境名稱",
Expand Down
8 changes: 8 additions & 0 deletions Tests/OrreryTests/LocalizationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ final class LocalizationTests: XCTestCase {
XCTAssertTrue(value.contains("foo"))
}

func testInstallSuccessNamesAccountAndWorkspace() {
// `orrery install` reports the account AND the workspace it's pinned to.
let msg = L10n.Install.success("statusline", "latest@v0.2.9", 1, "work", "team")
XCTAssertTrue(msg.contains("statusline"))
XCTAssertTrue(msg.contains("work"), "should name the account")
XCTAssertTrue(msg.contains("team"), "should name the workspace")
}

func testBothLocalesContainKnownKeys() {
// Strings are compiled directly into the binary via codegen; the
// generated `L10nData` holds the per-locale dictionaries.
Expand Down
Loading