jeopi-cli 16.2.13 → 16.2.15
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 +21 -3
- package/README.md +1 -1
- package/dist/cli.js +3087 -3060
- package/dist/types/advisor/watchdog.d.ts +2 -2
- package/dist/types/autolearn/managed-skills.d.ts +2 -2
- package/dist/types/capability/types.d.ts +2 -2
- package/dist/types/cli/commands/migrate-legacy.d.ts +1 -0
- package/dist/types/cli/config-cli.d.ts +1 -1
- package/dist/types/cli/flag-tables.d.ts +1 -1
- package/dist/types/cli/grievances-cli.d.ts +1 -1
- package/dist/types/cli/models-cli.d.ts +1 -1
- package/dist/types/cli/update-cli.d.ts +2 -2
- package/dist/types/cli/worktree-cli.d.ts +1 -1
- package/dist/types/commit/index.d.ts +1 -1
- package/dist/types/commit/pipeline.d.ts +1 -1
- package/dist/types/commit/types.d.ts +1 -1
- package/dist/types/config/prompt-templates.d.ts +1 -1
- package/dist/types/config/settings-schema.d.ts +16 -6
- package/dist/types/config.d.ts +7 -7
- package/dist/types/discovery/helpers.d.ts +8 -8
- package/dist/types/discovery/omp-extension-roots.d.ts +2 -2
- package/dist/types/eval/py/runtime.d.ts +1 -1
- package/dist/types/extensibility/custom-tools/loader.d.ts +2 -2
- package/dist/types/extensibility/extensions/loader.d.ts +1 -1
- package/dist/types/extensibility/hooks/loader.d.ts +1 -1
- package/dist/types/extensibility/plugins/loader.d.ts +2 -2
- package/dist/types/extensibility/plugins/types.d.ts +13 -3
- package/dist/types/lsp/config.d.ts +2 -2
- package/dist/types/mcp/client.d.ts +1 -1
- package/dist/types/mcp/config-writer.d.ts +1 -1
- package/dist/types/mcp/oauth-flow.d.ts +1 -1
- package/dist/types/mcp/transports/http.d.ts +1 -1
- package/dist/types/memories/okf.d.ts +36 -0
- package/dist/types/modes/components/__tests__/assistant-agent-label.test.d.ts +1 -0
- package/dist/types/modes/components/assistant-message.d.ts +4 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/sdk.d.ts +5 -5
- package/dist/types/session/agent-session.d.ts +3 -0
- package/dist/types/session/auth-broker-config.d.ts +4 -4
- package/dist/types/session/snapcompact-savings-journal.d.ts +1 -1
- package/dist/types/task/commands.d.ts +1 -1
- package/dist/types/task/critic-gate.d.ts +76 -0
- package/dist/types/task/critic-gate.test.d.ts +1 -0
- package/dist/types/task/discovery.d.ts +1 -1
- package/dist/types/task/executor.d.ts +1 -1
- package/dist/types/tools/acp-bridge.d.ts +2 -2
- package/dist/types/tools/browser/tab-protocol.d.ts +1 -1
- package/dist/types/tools/index.d.ts +6 -1
- package/dist/types/tools/plan-mode-guard.d.ts +8 -0
- package/dist/types/tools/report-tool-issue.d.ts +1 -1
- package/dist/types/utils/changelog.d.ts +2 -2
- package/dist/types/utils/image-loading.d.ts +4 -4
- package/dist/types/utils/image-resize.d.ts +1 -1
- package/dist/types/web/search/index.d.ts +1 -1
- package/examples/custom-tools/README.md +1 -1
- package/examples/extensions/README.md +1 -1
- package/examples/extensions/pirate.ts +1 -1
- package/examples/extensions/plan-mode.ts +1 -1
- package/examples/extensions/tools.ts +1 -1
- package/examples/hooks/README.md +1 -1
- package/examples/sdk/01-minimal.ts +1 -1
- package/examples/sdk/04-skills.ts +1 -1
- package/examples/sdk/06-extensions.ts +3 -3
- package/examples/sdk/09-api-keys-and-oauth.ts +2 -2
- package/examples/sdk/12-redis-sessions.ts +1 -1
- package/examples/sdk/13-sql-sessions.ts +1 -1
- package/examples/sdk/README.md +1 -1
- package/package.json +12 -12
- package/scripts/jeopi +1 -1
- package/src/advisor/__tests__/config.test.ts +4 -4
- package/src/advisor/watchdog.ts +8 -8
- package/src/autolearn/managed-skills.ts +4 -4
- package/src/autoresearch/storage.ts +2 -2
- package/src/capability/types.ts +2 -2
- package/src/cli/agents-cli.ts +2 -2
- package/src/cli/args.ts +3 -3
- package/src/cli/auth-broker-cli.ts +5 -5
- package/src/cli/auth-gateway-cli.ts +4 -4
- package/src/cli/claude-trace-cli.ts +1 -1
- package/src/cli/commands/migrate-legacy.ts +24 -0
- package/src/cli/config-cli.ts +20 -5
- package/src/cli/flag-tables.ts +1 -1
- package/src/cli/gallery-fixtures/misc.ts +7 -7
- package/src/cli/gallery-screenshot.ts +2 -2
- package/src/cli/grievances-cli.ts +1 -1
- package/src/cli/models-cli.ts +1 -1
- package/src/cli/plugin-cli.ts +2 -2
- package/src/cli/profile-alias.ts +8 -8
- package/src/cli/read-cli.ts +1 -1
- package/src/cli/ssh-cli.ts +2 -2
- package/src/cli/update-cli.ts +27 -27
- package/src/cli/worktree-cli.ts +3 -3
- package/src/cli.ts +5 -5
- package/src/commands/agents.ts +2 -2
- package/src/commands/auth-broker.ts +1 -1
- package/src/commands/config.ts +1 -1
- package/src/commands/dry-balance.ts +6 -6
- package/src/commands/launch.ts +2 -2
- package/src/commands/models.ts +1 -1
- package/src/commands/say.ts +1 -1
- package/src/commands/token.ts +5 -5
- package/src/commands/ttsr.ts +2 -2
- package/src/commands/worktree.ts +3 -3
- package/src/commit/agentic/prompts/system.md +1 -1
- package/src/commit/cli.ts +1 -1
- package/src/commit/index.ts +1 -1
- package/src/commit/pipeline.ts +1 -1
- package/src/commit/types.ts +1 -1
- package/src/config/mcp-schema.json +5 -5
- package/src/config/models-config-schema.ts +1 -1
- package/src/config/prompt-templates.ts +2 -2
- package/src/config/settings-schema.ts +20 -8
- package/src/config/settings.ts +1 -1
- package/src/config.ts +10 -10
- package/src/dap/session.ts +2 -2
- package/src/debug/protocol-probe.ts +1 -1
- package/src/debug/raw-sse-buffer.ts +3 -3
- package/src/debug/raw-sse.ts +2 -2
- package/src/discovery/builtin.ts +9 -9
- package/src/discovery/helpers.ts +13 -13
- package/src/discovery/omp-extension-roots.ts +4 -4
- package/src/discovery/omp-plugins.ts +2 -2
- package/src/discovery/substitute-plugin-root.ts +3 -3
- package/src/eval/py/runtime.ts +1 -1
- package/src/eval/rb/runner.rb +6 -6
- package/src/export/custom-share.ts +1 -1
- package/src/extensibility/custom-tools/loader.ts +3 -3
- package/src/extensibility/extensions/loader.ts +4 -4
- package/src/extensibility/hooks/loader.ts +1 -1
- package/src/extensibility/plugins/loader.ts +16 -10
- package/src/extensibility/plugins/manager.ts +10 -9
- package/src/extensibility/plugins/types.ts +15 -4
- package/src/internal-urls/docs-index.generated.txt +1 -1
- package/src/lsp/config.ts +4 -4
- package/src/lsp/index.ts +1 -1
- package/src/main.ts +1 -1
- package/src/mcp/client.ts +1 -1
- package/src/mcp/config-writer.ts +2 -2
- package/src/mcp/manager.ts +1 -1
- package/src/mcp/oauth-flow.ts +1 -1
- package/src/mcp/timeout.ts +2 -2
- package/src/mcp/transports/http.ts +1 -1
- package/src/memories/index.ts +82 -11
- package/src/memories/okf.ts +129 -0
- package/src/modes/components/__tests__/assistant-agent-label.test.ts +87 -0
- package/src/modes/components/assistant-message.ts +27 -0
- package/src/modes/components/extensions/extension-dashboard.ts +1 -1
- package/src/modes/controllers/mcp-command-controller.ts +2 -2
- package/src/modes/controllers/omfg-controller.ts +2 -2
- package/src/modes/controllers/ssh-command-controller.ts +2 -2
- package/src/modes/interactive-mode.ts +3 -1
- package/src/modes/setup-wizard/index.ts +1 -1
- package/src/prompts/agents/jeo.md +20 -10
- package/src/prompts/system/autolearn-guidance.md +2 -2
- package/src/prompts/system/system-prompt.md +10 -1
- package/src/prompts/tools/learn.md +1 -1
- package/src/prompts/tools/manage-skill.md +1 -1
- package/src/sdk.ts +8 -6
- package/src/secrets/index.ts +2 -2
- package/src/session/agent-session.ts +86 -6
- package/src/session/auth-broker-config.ts +6 -6
- package/src/session/snapcompact-savings-journal.ts +1 -1
- package/src/slash-commands/helpers/mcp.ts +1 -1
- package/src/system-prompt.test.ts +14 -14
- package/src/task/commands.ts +1 -1
- package/src/task/critic-gate.test.ts +181 -0
- package/src/task/critic-gate.ts +148 -0
- package/src/task/discovery.ts +5 -5
- package/src/task/executor.ts +1 -1
- package/src/task/index.ts +35 -2
- package/src/tools/acp-bridge.ts +2 -2
- package/src/tools/browser/launch.ts +1 -1
- package/src/tools/browser/tab-protocol.ts +1 -1
- package/src/tools/grep.ts +2 -2
- package/src/tools/index.ts +6 -1
- package/src/tools/plan-mode-guard.ts +16 -0
- package/src/tools/read.ts +1 -1
- package/src/tools/report-tool-issue.ts +2 -2
- package/src/utils/changelog.ts +2 -2
- package/src/utils/image-loading.ts +4 -4
- package/src/utils/image-resize.ts +5 -5
- package/src/web/search/index.ts +1 -1
package/src/capability/types.ts
CHANGED
|
@@ -31,7 +31,7 @@ export interface LoadResult<T> {
|
|
|
31
31
|
* A provider that can load items for a capability.
|
|
32
32
|
*/
|
|
33
33
|
export interface Provider<T> {
|
|
34
|
-
/** Unique provider ID (e.g., "claude", "
|
|
34
|
+
/** Unique provider ID (e.g., "claude", "jeopi", "mcp-json", "agents-md") */
|
|
35
35
|
id: string;
|
|
36
36
|
|
|
37
37
|
/** Human-readable name for UI display (e.g., "Claude Code", "OpenAI Codex") */
|
|
@@ -43,7 +43,7 @@ export interface Provider<T> {
|
|
|
43
43
|
/**
|
|
44
44
|
* Priority (higher = checked first, wins on conflicts).
|
|
45
45
|
* Suggested ranges:
|
|
46
|
-
* 100+ : Primary providers (
|
|
46
|
+
* 100+ : Primary providers (jeopi, pi)
|
|
47
47
|
* 50-99: Tool-specific providers (claude, codex, gemini)
|
|
48
48
|
* 1-49 : Shared standards (mcp-json, agents-md)
|
|
49
49
|
*/
|
package/src/cli/agents-cli.ts
CHANGED
|
@@ -7,7 +7,7 @@ import * as fs from "node:fs/promises";
|
|
|
7
7
|
import * as path from "node:path";
|
|
8
8
|
import { YAML } from "bun";
|
|
9
9
|
import chalk from "chalk";
|
|
10
|
-
import { getAgentDir, getProjectDir, isEnoent } from "jeopi-utils";
|
|
10
|
+
import { CONFIG_DIR_NAME, getAgentDir, getProjectDir, isEnoent } from "jeopi-utils";
|
|
11
11
|
import { theme } from "../modes/theme/theme";
|
|
12
12
|
import { loadBundledAgents } from "../task/agents";
|
|
13
13
|
import type { AgentDefinition } from "../task/types";
|
|
@@ -46,7 +46,7 @@ function resolveTargetDir(flags: AgentsCommandArgs["flags"]): string {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
if (flags.project) {
|
|
49
|
-
return path.resolve(getProjectDir(),
|
|
49
|
+
return path.resolve(getProjectDir(), CONFIG_DIR_NAME, "agents");
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
return path.join(getAgentDir(), "agents");
|
package/src/cli/args.ts
CHANGED
|
@@ -349,7 +349,7 @@ export function getExtraHelpText(): string {
|
|
|
349
349
|
ANTHROPIC_SEARCH_BASE_URL - Anthropic web search base URL (override; pairs with ANTHROPIC_SEARCH_API_KEY)
|
|
350
350
|
|
|
351
351
|
${chalk.dim("# Configuration")}
|
|
352
|
-
|
|
352
|
+
JEOPI_PROFILE - Named profile for isolated agent state (same as --profile)
|
|
353
353
|
Use \`${APP_NAME} --profile <name> --alias <command>\` to create a shell shortcut for a profile
|
|
354
354
|
PI_CODING_AGENT_DIR - Session storage directory (default: ~/${CONFIG_DIR_NAME}/agent)
|
|
355
355
|
PI_PACKAGE_DIR - Override package directory (for Nix/Guix store paths)
|
|
@@ -380,8 +380,8 @@ ${chalk.bold("Plugin Options:")}
|
|
|
380
380
|
--plugin-dir <path> Load plugin from directory (repeatable)
|
|
381
381
|
|
|
382
382
|
${chalk.bold("Useful Commands:")}
|
|
383
|
-
jeopi agents unpack - Export bundled subagents to ~/.
|
|
384
|
-
jeopi agents unpack --project - Export bundled subagents to ./.
|
|
383
|
+
jeopi agents unpack - Export bundled subagents to ~/.jeopi/agent/agents (default)
|
|
384
|
+
jeopi agents unpack --project - Export bundled subagents to ./.jeopi/agents`;
|
|
385
385
|
}
|
|
386
386
|
|
|
387
387
|
export function printHelp(): void {
|
|
@@ -122,7 +122,7 @@ async function ensureToken(): Promise<string> {
|
|
|
122
122
|
async function runServe(flags: AuthBrokerCommandArgs["flags"]): Promise<void> {
|
|
123
123
|
// The broker is a long-running headless service: route structured logs to
|
|
124
124
|
// stdout so a process supervisor (pm2, journald, k8s) captures them, and
|
|
125
|
-
// skip the rotating ~/.
|
|
125
|
+
// skip the rotating ~/.jeopi/logs/ file the TUI default would have used.
|
|
126
126
|
setLoggerTransports({ console: true, file: false });
|
|
127
127
|
|
|
128
128
|
const bind = flags.bind ?? DEFAULT_AUTH_BROKER_BIND;
|
|
@@ -412,7 +412,7 @@ async function runList(flags: AuthBrokerCommandArgs["flags"]): Promise<void> {
|
|
|
412
412
|
// ─── CLIProxyAPI import ─────────────────────────────────────────────────
|
|
413
413
|
|
|
414
414
|
/**
|
|
415
|
-
* Maps the `type` field of a CLIProxyAPI credential JSON to the
|
|
415
|
+
* Maps the `type` field of a CLIProxyAPI credential JSON to the jeopi provider id.
|
|
416
416
|
* The filename also encodes the type (e.g. `claude-foo@bar.json`), but the
|
|
417
417
|
* in-file `type` is authoritative — we only fall back to filename if absent.
|
|
418
418
|
*/
|
|
@@ -508,7 +508,7 @@ async function loadImportPlan(
|
|
|
508
508
|
if (!provider) {
|
|
509
509
|
skipped.push({
|
|
510
510
|
file,
|
|
511
|
-
reason: `cannot determine
|
|
511
|
+
reason: `cannot determine jeopi provider from type=${json.type ?? "?"} (pass --provider to override)`,
|
|
512
512
|
});
|
|
513
513
|
continue;
|
|
514
514
|
}
|
|
@@ -693,7 +693,7 @@ async function runMigrate(flags: AuthBrokerCommandArgs["flags"]): Promise<void>
|
|
|
693
693
|
const brokerConfig = await resolveAuthBrokerConfig();
|
|
694
694
|
if (!brokerConfig) {
|
|
695
695
|
throw new Error(
|
|
696
|
-
"
|
|
696
|
+
"JEOPI_AUTH_BROKER_URL must be set (or `auth.broker.url` in config.yml). `migrate` uploads local credentials to a configured broker.",
|
|
697
697
|
);
|
|
698
698
|
}
|
|
699
699
|
if (flags.fromLocal !== true) {
|
|
@@ -846,7 +846,7 @@ async function runMigrate(flags: AuthBrokerCommandArgs["flags"]): Promise<void>
|
|
|
846
846
|
async function runStatus(flags: AuthBrokerCommandArgs["flags"]): Promise<void> {
|
|
847
847
|
const cfg = await resolveAuthBrokerConfig();
|
|
848
848
|
if (!cfg) {
|
|
849
|
-
const message = "No auth-broker configured (set
|
|
849
|
+
const message = "No auth-broker configured (set JEOPI_AUTH_BROKER_URL to enable).";
|
|
850
850
|
if (flags.json) process.stdout.write(`${JSON.stringify({ ok: false, reason: "not_configured" })}\n`);
|
|
851
851
|
else process.stdout.write(`${chalk.yellow(message)}\n`);
|
|
852
852
|
return;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* usage widget, robomp containers, …) make provider API calls without ever
|
|
6
6
|
* seeing the access token. The gateway is itself a broker client and
|
|
7
7
|
* resolves credentials through the configured broker (via the same
|
|
8
|
-
* `
|
|
8
|
+
* `JEOPI_AUTH_BROKER_URL` / `auth.broker.url` precedence used elsewhere).
|
|
9
9
|
*
|
|
10
10
|
* Sub-verbs:
|
|
11
11
|
* - `serve [--bind=…]` — boots the gateway against the configured broker.
|
|
@@ -139,7 +139,7 @@ async function runServe(flags: AuthGatewayCommandArgs["flags"]): Promise<void> {
|
|
|
139
139
|
const brokerConfig = await resolveAuthBrokerConfig();
|
|
140
140
|
if (!brokerConfig) {
|
|
141
141
|
throw new Error(
|
|
142
|
-
"`jeopi auth-gateway serve` requires
|
|
142
|
+
"`jeopi auth-gateway serve` requires JEOPI_AUTH_BROKER_URL (or `auth.broker.url`/`auth.broker.token` in config.yml). The gateway is itself a broker client.",
|
|
143
143
|
);
|
|
144
144
|
}
|
|
145
145
|
const bind = flags.bind ?? DEFAULT_AUTH_GATEWAY_BIND;
|
|
@@ -266,7 +266,7 @@ async function runStatus(flags: AuthGatewayCommandArgs["flags"]): Promise<void>
|
|
|
266
266
|
if (flags.json) {
|
|
267
267
|
process.stdout.write(`${JSON.stringify(status)}\n`);
|
|
268
268
|
} else {
|
|
269
|
-
process.stdout.write(`${chalk.yellow("No broker configured.")} Set
|
|
269
|
+
process.stdout.write(`${chalk.yellow("No broker configured.")} Set JEOPI_AUTH_BROKER_URL.\n`);
|
|
270
270
|
process.stdout.write(
|
|
271
271
|
`token: ${status.tokenPresent ? chalk.green("present") : chalk.red("missing")} at ${status.tokenFile}\n`,
|
|
272
272
|
);
|
|
@@ -534,7 +534,7 @@ async function runCheck(flags: AuthGatewayCommandArgs["flags"]): Promise<void> {
|
|
|
534
534
|
const brokerConfig = await resolveAuthBrokerConfig();
|
|
535
535
|
if (!brokerConfig) {
|
|
536
536
|
throw new Error(
|
|
537
|
-
"`jeopi auth-gateway check` requires
|
|
537
|
+
"`jeopi auth-gateway check` requires JEOPI_AUTH_BROKER_URL (or `auth.broker.url`/`auth.broker.token` in config.yml). It probes the same credentials the gateway would serve.",
|
|
538
538
|
);
|
|
539
539
|
}
|
|
540
540
|
|
|
@@ -749,7 +749,7 @@ export async function runClaudeMessagesCapture(args: ClaudeTraceCommandArgs = {}
|
|
|
749
749
|
try {
|
|
750
750
|
session.write(`${message}\r`);
|
|
751
751
|
} catch (error) {
|
|
752
|
-
ptyOutput += `\n[
|
|
752
|
+
ptyOutput += `\n[jeopi input write failed: ${errorMessage(error)}]\n`;
|
|
753
753
|
}
|
|
754
754
|
})();
|
|
755
755
|
const captureRace = proxy.waitForCapture(timeoutMs).then(
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { APP_NAME, hasUnmigratedLegacyConfigDir, LEGACY_CONFIG_DIR_NAME, migrateLegacyConfigDir } from "jeopi-utils";
|
|
2
|
+
|
|
3
|
+
export async function migrateLegacyConfig(): Promise<void> {
|
|
4
|
+
if (process.env.PI_CONFIG_DIR) {
|
|
5
|
+
console.error(
|
|
6
|
+
"PI_CONFIG_DIR is set — you already control the config directory name; there is nothing to migrate.",
|
|
7
|
+
);
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (!hasUnmigratedLegacyConfigDir()) {
|
|
12
|
+
console.log(`No unmigrated ${LEGACY_CONFIG_DIR_NAME} directory found. Nothing to do.`);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const { from, to } = migrateLegacyConfigDir();
|
|
18
|
+
console.log(`Migrated ${from} -> ${to}`);
|
|
19
|
+
console.log(`${APP_NAME} now reads auth, sessions, and settings from ${to}.`);
|
|
20
|
+
} catch (err) {
|
|
21
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
}
|
package/src/cli/config-cli.ts
CHANGED
|
@@ -21,12 +21,13 @@ import {
|
|
|
21
21
|
import { SETTINGS_SCHEMA } from "../config/settings-schema";
|
|
22
22
|
import { theme } from "../modes/theme/theme";
|
|
23
23
|
import { initXdg } from "./commands/init-xdg";
|
|
24
|
+
import { migrateLegacyConfig } from "./commands/migrate-legacy";
|
|
24
25
|
|
|
25
26
|
// =============================================================================
|
|
26
27
|
// Types
|
|
27
28
|
// =============================================================================
|
|
28
29
|
|
|
29
|
-
export type ConfigAction = "list" | "get" | "set" | "reset" | "path" | "init-xdg";
|
|
30
|
+
export type ConfigAction = "list" | "get" | "set" | "reset" | "path" | "init-xdg" | "migrate-legacy";
|
|
30
31
|
|
|
31
32
|
export interface ConfigCommandArgs {
|
|
32
33
|
action: ConfigAction;
|
|
@@ -74,7 +75,7 @@ function getSettingValues(def: CliSettingDef): readonly string[] | undefined {
|
|
|
74
75
|
// Argument Parser
|
|
75
76
|
// =============================================================================
|
|
76
77
|
|
|
77
|
-
const VALID_ACTIONS: ConfigAction[] = ["list", "get", "set", "reset", "path", "init-xdg"];
|
|
78
|
+
const VALID_ACTIONS: ConfigAction[] = ["list", "get", "set", "reset", "path", "init-xdg", "migrate-legacy"];
|
|
78
79
|
|
|
79
80
|
/**
|
|
80
81
|
* Parse config subcommand arguments.
|
|
@@ -237,6 +238,21 @@ function parseAndSetValue(path: SettingPath, rawValue: string): void {
|
|
|
237
238
|
// =============================================================================
|
|
238
239
|
|
|
239
240
|
export async function runConfigCommand(cmd: ConfigCommandArgs): Promise<void> {
|
|
241
|
+
// migrate-legacy and init-xdg are directory-bootstrapping operations that
|
|
242
|
+
// must run BEFORE Settings.init() touches the config root: Settings.init()
|
|
243
|
+
// opens AgentStorage (agent.db), which mkdir's the agent dir as a side
|
|
244
|
+
// effect. Running it first would silently create `~/.jeopi` ahead of the
|
|
245
|
+
// migration check, making `hasUnmigratedLegacyConfigDir()` always report
|
|
246
|
+
// "nothing to migrate" even when a real `~/.omp` install exists.
|
|
247
|
+
if (cmd.action === "migrate-legacy") {
|
|
248
|
+
await migrateLegacyConfig();
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
if (cmd.action === "init-xdg") {
|
|
252
|
+
await initXdg();
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
240
256
|
await Settings.init();
|
|
241
257
|
|
|
242
258
|
switch (cmd.action) {
|
|
@@ -255,9 +271,6 @@ export async function runConfigCommand(cmd: ConfigCommandArgs): Promise<void> {
|
|
|
255
271
|
case "path":
|
|
256
272
|
handlePath();
|
|
257
273
|
break;
|
|
258
|
-
case "init-xdg":
|
|
259
|
-
await initXdg();
|
|
260
|
-
break;
|
|
261
274
|
}
|
|
262
275
|
}
|
|
263
276
|
|
|
@@ -402,6 +415,7 @@ ${chalk.bold("Commands:")}
|
|
|
402
415
|
reset <key> Reset a setting to its default value
|
|
403
416
|
path Print the config directory path
|
|
404
417
|
init-xdg Initialize XDG Base Directory structure
|
|
418
|
+
migrate-legacy Migrate ~/.omp to ~/.jeopi (pre-rebrand config directory)
|
|
405
419
|
|
|
406
420
|
${chalk.bold("Options:")}
|
|
407
421
|
--json Output as JSON
|
|
@@ -415,6 +429,7 @@ ${chalk.bold("Examples:")}
|
|
|
415
429
|
${APP_NAME} config reset steeringMode
|
|
416
430
|
${APP_NAME} config list --json
|
|
417
431
|
${APP_NAME} config init-xdg
|
|
432
|
+
${APP_NAME} config migrate-legacy
|
|
418
433
|
|
|
419
434
|
${chalk.bold("Boolean Values:")}
|
|
420
435
|
true, false, yes, no, on, off, 1, 0
|
package/src/cli/flag-tables.ts
CHANGED
|
@@ -247,7 +247,7 @@ export const OPTIONAL_VALUE_FLAGS: ReadonlySet<string> = new Set(Object.keys(OPT
|
|
|
247
247
|
* value of a preceding optional/extension flag. `parseArgs` ignores it, but its
|
|
248
248
|
* flag-looking shape preserves argv boundaries during the second parse.
|
|
249
249
|
*/
|
|
250
|
-
export const PROFILE_BOOTSTRAP_BOUNDARY_ARG = "--
|
|
250
|
+
export const PROFILE_BOOTSTRAP_BOUNDARY_ARG = "--jeopi-profile-boundary";
|
|
251
251
|
|
|
252
252
|
/**
|
|
253
253
|
* Long-form launch flags that take NO value (booleans). The bootstrap pre-parser
|
|
@@ -110,8 +110,8 @@ export const miscFixtures: Record<string, GalleryFixture> = {
|
|
|
110
110
|
},
|
|
111
111
|
args: {
|
|
112
112
|
host: "deploy@web-01",
|
|
113
|
-
command: "systemctl status
|
|
114
|
-
cwd: "/srv/
|
|
113
|
+
command: "systemctl status jeopi-api --no-pager | head -n 12",
|
|
114
|
+
cwd: "/srv/jeopi",
|
|
115
115
|
timeout: 60,
|
|
116
116
|
},
|
|
117
117
|
result: {
|
|
@@ -119,14 +119,14 @@ export const miscFixtures: Record<string, GalleryFixture> = {
|
|
|
119
119
|
{
|
|
120
120
|
type: "text",
|
|
121
121
|
text: [
|
|
122
|
-
"●
|
|
123
|
-
" Loaded: loaded (/etc/systemd/system/
|
|
122
|
+
"● jeopi-api.service - jeopi API",
|
|
123
|
+
" Loaded: loaded (/etc/systemd/system/jeopi-api.service; enabled)",
|
|
124
124
|
" Active: active (running) since Sat 2026-06-06 09:14:02 UTC; 3h 21min ago",
|
|
125
125
|
" Main PID: 4812 (bun)",
|
|
126
126
|
" Tasks: 17 (limit: 4915)",
|
|
127
127
|
" Memory: 142.6M",
|
|
128
128
|
" CPU: 38.214s",
|
|
129
|
-
" CGroup: /system.slice/
|
|
129
|
+
" CGroup: /system.slice/jeopi-api.service",
|
|
130
130
|
" └─4812 /usr/local/bin/bun run dist/server.js",
|
|
131
131
|
].join("\n"),
|
|
132
132
|
},
|
|
@@ -152,7 +152,7 @@ export const miscFixtures: Record<string, GalleryFixture> = {
|
|
|
152
152
|
args: {
|
|
153
153
|
op: "search_prs",
|
|
154
154
|
query: "is:open review-requested:@me sort:updated",
|
|
155
|
-
repo: "
|
|
155
|
+
repo: "akillness/jeopi",
|
|
156
156
|
},
|
|
157
157
|
result: {
|
|
158
158
|
content: [
|
|
@@ -173,7 +173,7 @@ export const miscFixtures: Record<string, GalleryFixture> = {
|
|
|
173
173
|
content: [
|
|
174
174
|
{
|
|
175
175
|
type: "text",
|
|
176
|
-
text: "gh: Could not resolve to a Repository with the name '
|
|
176
|
+
text: "gh: Could not resolve to a Repository with the name 'akillness/jeopi'. (HTTP 404)",
|
|
177
177
|
},
|
|
178
178
|
],
|
|
179
179
|
isError: true,
|
|
@@ -77,7 +77,7 @@ export async function captureGalleryScreenshots(
|
|
|
77
77
|
|
|
78
78
|
const baseDir = options.out
|
|
79
79
|
? path.dirname(path.resolve(options.out))
|
|
80
|
-
: fs.mkdtempSync(path.join(os.tmpdir(), "
|
|
80
|
+
: fs.mkdtempSync(path.join(os.tmpdir(), "jeopi-gallery-"));
|
|
81
81
|
await fs.promises.mkdir(baseDir, { recursive: true });
|
|
82
82
|
|
|
83
83
|
const outPaths: string[] = [];
|
|
@@ -194,7 +194,7 @@ function buildVhsTheme(): string {
|
|
|
194
194
|
const foreground = theme.isLight ? "#1a1a1a" : "#d4d4d4";
|
|
195
195
|
const selection = theme.isLight ? "#c8d6ff" : "#404862";
|
|
196
196
|
return JSON.stringify({
|
|
197
|
-
name: "
|
|
197
|
+
name: "jeopi-gallery",
|
|
198
198
|
background,
|
|
199
199
|
foreground,
|
|
200
200
|
cursor: foreground,
|
|
@@ -195,7 +195,7 @@ function makeProgressBar(total: number, width = 30): ProgressBar {
|
|
|
195
195
|
* ignoring the user-facing consent gate (manual push is the user's
|
|
196
196
|
* explicit "yes ship these now" intent).
|
|
197
197
|
*
|
|
198
|
-
* Requires endpoint configuration (default `qa.
|
|
198
|
+
* Requires endpoint configuration (default `qa.jeopi.sh/v1/grievances`).
|
|
199
199
|
*/
|
|
200
200
|
export async function pushGrievances(options: PushGrievancesOptions): Promise<void> {
|
|
201
201
|
const db = openAutoQaDb();
|
package/src/cli/models-cli.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* - `ls` (default): list every available model grouped by provider.
|
|
6
6
|
* - `find <substring>`: list models whose provider, id, or name contains the substring.
|
|
7
7
|
* - `refresh`: force an online catalog re-fetch (ignoring the model cache TTL),
|
|
8
|
-
* then list. This is the supported replacement for `rm -rf ~/.
|
|
8
|
+
* then list. This is the supported replacement for `rm -rf ~/.jeopi/models.db`
|
|
9
9
|
* when a provider ships a new model that the 24h cache has not picked up yet.
|
|
10
10
|
*
|
|
11
11
|
* `ls`/`find` use the cache when fresh (`online-if-uncached`); only `refresh`
|
package/src/cli/plugin-cli.ts
CHANGED
|
@@ -350,7 +350,7 @@ async function handleInstall(
|
|
|
350
350
|
if (packages.length === 0) {
|
|
351
351
|
console.error(chalk.red(`Usage: ${APP_NAME} plugin install <source>[features] ...`));
|
|
352
352
|
console.error(chalk.dim("Examples:"));
|
|
353
|
-
console.error(chalk.dim(` ${APP_NAME} plugin install @
|
|
353
|
+
console.error(chalk.dim(` ${APP_NAME} plugin install @jeopi/exa`));
|
|
354
354
|
console.error(chalk.dim(` ${APP_NAME} plugin install name@marketplace`));
|
|
355
355
|
console.error(chalk.dim(` ${APP_NAME} plugin install github:user/repo`));
|
|
356
356
|
console.error(chalk.dim(` ${APP_NAME} plugin install https://github.com/user/repo#v1.0`));
|
|
@@ -985,7 +985,7 @@ ${chalk.bold("Options:")}
|
|
|
985
985
|
-l, --local Use project-local overrides
|
|
986
986
|
|
|
987
987
|
${chalk.bold("Examples:")}
|
|
988
|
-
${APP_NAME} plugin install @
|
|
988
|
+
${APP_NAME} plugin install @jeopi/exa[search]
|
|
989
989
|
${APP_NAME} plugin list --json
|
|
990
990
|
${APP_NAME} plugin features my-plugin --enable search,web
|
|
991
991
|
${APP_NAME} plugin config set my-plugin apiKey sk-xxx
|
package/src/cli/profile-alias.ts
CHANGED
|
@@ -147,8 +147,8 @@ function validateAliasName(aliasName: string, shell: ProfileAliasShell): string
|
|
|
147
147
|
if (!ALIAS_NAME_RE.test(normalized)) {
|
|
148
148
|
throw new Error(`Invalid alias "${aliasName}". Alias names must match ${ALIAS_NAME_RE.source}.`);
|
|
149
149
|
}
|
|
150
|
-
if (normalized.toLowerCase() === "
|
|
151
|
-
throw new Error('Invalid alias "
|
|
150
|
+
if (normalized.toLowerCase() === "jeopi") {
|
|
151
|
+
throw new Error('Invalid alias "jeopi". Refusing to shadow the base jeopi command.');
|
|
152
152
|
}
|
|
153
153
|
if (getReservedAliasNames(shell).has(normalized.toLowerCase())) {
|
|
154
154
|
throw new Error(`Invalid alias "${aliasName}". Refusing to create a ${shell} reserved word.`);
|
|
@@ -254,7 +254,7 @@ function resolveShellConfigPath(
|
|
|
254
254
|
// a hard-coded ~/.config would be silently ignored when the user relocates
|
|
255
255
|
// their XDG config root, leaving the alias unsourced after a restart.
|
|
256
256
|
const configHome = env.XDG_CONFIG_HOME ? toPosix(env.XDG_CONFIG_HOME) : posixJoinUnc(posixHome, ".config");
|
|
257
|
-
return posixJoinUnc(configHome, "fish", "conf.d", "
|
|
257
|
+
return posixJoinUnc(configHome, "fish", "conf.d", "jeopi-profiles.fish");
|
|
258
258
|
}
|
|
259
259
|
case "pwsh":
|
|
260
260
|
return platform === "win32"
|
|
@@ -272,13 +272,13 @@ function renderAliasBlock(
|
|
|
272
272
|
command: ProfileAliasCommand,
|
|
273
273
|
): { block: string; command: string } {
|
|
274
274
|
const profiledCommand = `${command.display} --profile=${profile}`;
|
|
275
|
-
const start = `# >>>
|
|
276
|
-
const end = `# <<<
|
|
275
|
+
const start = `# >>> jeopi profile alias: ${aliasName} >>>`;
|
|
276
|
+
const end = `# <<< jeopi profile alias: ${aliasName} <<<`;
|
|
277
277
|
let body: string;
|
|
278
278
|
switch (shell) {
|
|
279
279
|
case "fish":
|
|
280
280
|
body = [
|
|
281
|
-
`function ${aliasName} --wraps jeopi --description '
|
|
281
|
+
`function ${aliasName} --wraps jeopi --description 'jeopi profile ${profile}'`,
|
|
282
282
|
` command ${command.fish} --profile=${profile} $argv`,
|
|
283
283
|
"end",
|
|
284
284
|
].join("\n");
|
|
@@ -295,8 +295,8 @@ function renderAliasBlock(
|
|
|
295
295
|
}
|
|
296
296
|
|
|
297
297
|
function upsertBlock(content: string, aliasName: string, block: string): string {
|
|
298
|
-
const start = `# >>>
|
|
299
|
-
const end = `# <<<
|
|
298
|
+
const start = `# >>> jeopi profile alias: ${aliasName} >>>`;
|
|
299
|
+
const end = `# <<< jeopi profile alias: ${aliasName} <<<`;
|
|
300
300
|
const startIndex = content.indexOf(start);
|
|
301
301
|
if (startIndex !== -1) {
|
|
302
302
|
const endIndex = content.indexOf(end, startIndex + start.length);
|
package/src/cli/read-cli.ts
CHANGED
|
@@ -38,7 +38,7 @@ export async function runReadCommand(cmd: ReadCommandArgs): Promise<void> {
|
|
|
38
38
|
const tool = wrapToolWithMetaNotice(new ReadTool(session));
|
|
39
39
|
|
|
40
40
|
try {
|
|
41
|
-
const result = await tool.execute("
|
|
41
|
+
const result = await tool.execute("jeopi-read", { path: cmd.path });
|
|
42
42
|
|
|
43
43
|
for (const block of result.content) {
|
|
44
44
|
if (block.type === "text") {
|
package/src/cli/ssh-cli.ts
CHANGED
|
@@ -149,7 +149,7 @@ async function handleList(cmd: SSHCommandArgs): Promise<void> {
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
if (hasProject) {
|
|
152
|
-
process.stdout.write(chalk.bold("Project SSH Hosts (.
|
|
152
|
+
process.stdout.write(chalk.bold("Project SSH Hosts (.jeopi/ssh.json):\n"));
|
|
153
153
|
printHosts(projectHosts);
|
|
154
154
|
}
|
|
155
155
|
|
|
@@ -158,7 +158,7 @@ async function handleList(cmd: SSHCommandArgs): Promise<void> {
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
if (hasUser) {
|
|
161
|
-
process.stdout.write(chalk.bold("User SSH Hosts (~/.
|
|
161
|
+
process.stdout.write(chalk.bold("User SSH Hosts (~/.jeopi/agent/ssh.json):\n"));
|
|
162
162
|
printHosts(userHosts);
|
|
163
163
|
}
|
|
164
164
|
}
|
package/src/cli/update-cli.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Update CLI command handler.
|
|
3
3
|
*
|
|
4
4
|
* Handles `jeopi update` to check for and install updates.
|
|
5
|
-
* Uses the installer that owns the active
|
|
5
|
+
* Uses the installer that owns the active jeopi executable when it can be detected.
|
|
6
6
|
*/
|
|
7
7
|
import * as fs from "node:fs";
|
|
8
8
|
import * as os from "node:os";
|
|
@@ -14,7 +14,7 @@ import { $which, APP_NAME, isEnoent, VERSION } from "jeopi-utils";
|
|
|
14
14
|
import { theme } from "../modes/theme/theme";
|
|
15
15
|
|
|
16
16
|
const REPO = "akillness/jeopi";
|
|
17
|
-
const PACKAGE = "jeopi";
|
|
17
|
+
const PACKAGE = "jeopi-cli";
|
|
18
18
|
const HOMEBREW_FORMULA = "akillness/tap/jeopi";
|
|
19
19
|
const MISE_TOOL = "github:akillness/jeopi";
|
|
20
20
|
/**
|
|
@@ -170,10 +170,10 @@ function isPathInDirectory(filePath: string, directoryPath: string): boolean {
|
|
|
170
170
|
if (isPathInDirectoryLexical(filePath, directoryPath)) return true;
|
|
171
171
|
// Layer realpath resolution on top of the lexical guard. On Windows, ~/.bun
|
|
172
172
|
// is a junction when Bun is installed via Scoop, so `bun pm bin -g` and the
|
|
173
|
-
// PATH-resolved
|
|
173
|
+
// PATH-resolved jeopi path can refer to the same directory through different
|
|
174
174
|
// strings. path.resolve does not traverse junctions/symlinks; realpath does.
|
|
175
175
|
// Resolve both the file and its parent directory: the file catches manager
|
|
176
|
-
// links like Homebrew's `bin/
|
|
176
|
+
// links like Homebrew's `bin/jeopi -> Cellar/.../bin/jeopi`; the parent fallback
|
|
177
177
|
// still tolerates fresh install paths where the file does not exist yet.
|
|
178
178
|
const dirReal = tryRealpath(path.resolve(directoryPath));
|
|
179
179
|
if (!dirReal) return false;
|
|
@@ -196,24 +196,24 @@ interface UpdateMethodResolutionOptions {
|
|
|
196
196
|
type UpdateTarget = { method: "brew" } | { method: "mise" } | { method: "bun" } | { method: "binary"; path: string };
|
|
197
197
|
|
|
198
198
|
function resolveUpdateMethod(
|
|
199
|
-
|
|
199
|
+
jeopiPath: string,
|
|
200
200
|
bunBinDir: string | undefined,
|
|
201
201
|
options: UpdateMethodResolutionOptions = {},
|
|
202
202
|
): UpdateMethod {
|
|
203
203
|
const { homebrewPrefix, miseBinDirs = [], miseDataDir } = options;
|
|
204
|
-
if (homebrewPrefix && isPathInDirectory(
|
|
205
|
-
if (miseBinDirs.some(dir => isPathInDirectory(
|
|
206
|
-
if (miseDataDir && isPathInDirectory(
|
|
207
|
-
if (bunBinDir && isPathInDirectory(
|
|
204
|
+
if (homebrewPrefix && isPathInDirectory(jeopiPath, path.join(homebrewPrefix, "bin"))) return "brew";
|
|
205
|
+
if (miseBinDirs.some(dir => isPathInDirectory(jeopiPath, dir))) return "mise";
|
|
206
|
+
if (miseDataDir && isPathInDirectory(jeopiPath, path.join(miseDataDir, "shims"))) return "mise";
|
|
207
|
+
if (bunBinDir && isPathInDirectory(jeopiPath, bunBinDir)) return "bun";
|
|
208
208
|
return "binary";
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
export function resolveUpdateMethodForTest(
|
|
212
|
-
|
|
212
|
+
jeopiPath: string,
|
|
213
213
|
bunBinDir: string | undefined,
|
|
214
214
|
options: UpdateMethodResolutionOptions = {},
|
|
215
215
|
): UpdateMethod {
|
|
216
|
-
return resolveUpdateMethod(
|
|
216
|
+
return resolveUpdateMethod(jeopiPath, bunBinDir, options);
|
|
217
217
|
}
|
|
218
218
|
async function resolveUpdateTarget(): Promise<UpdateTarget> {
|
|
219
219
|
const bunBinDir = await getBunGlobalBinDir();
|
|
@@ -221,11 +221,11 @@ async function resolveUpdateTarget(): Promise<UpdateTarget> {
|
|
|
221
221
|
const miseAvailable = $which("mise") !== undefined;
|
|
222
222
|
const miseBinDirs = miseAvailable ? await getMiseBinDirs() : [];
|
|
223
223
|
const miseDataDir = miseAvailable ? getMiseDataDir() : undefined;
|
|
224
|
-
const
|
|
224
|
+
const jeopiPath = resolveJeopiPath();
|
|
225
225
|
|
|
226
|
-
if (
|
|
227
|
-
const method = resolveUpdateMethod(
|
|
228
|
-
if (method === "binary") return { method, path:
|
|
226
|
+
if (jeopiPath) {
|
|
227
|
+
const method = resolveUpdateMethod(jeopiPath, bunBinDir, { homebrewPrefix, miseBinDirs, miseDataDir });
|
|
228
|
+
if (method === "binary") return { method, path: jeopiPath };
|
|
229
229
|
return { method };
|
|
230
230
|
}
|
|
231
231
|
|
|
@@ -514,7 +514,7 @@ async function pruneBunCacheAfterGlobalInstall(): Promise<BunInstallCachePruneRe
|
|
|
514
514
|
const packageNames = globalNodeModulesDir
|
|
515
515
|
? await collectInstalledPackageNames(globalNodeModulesDir)
|
|
516
516
|
: new Set<string>();
|
|
517
|
-
if (packageNames.size === 0 && !path.basename(cacheDir).toLowerCase().includes("
|
|
517
|
+
if (packageNames.size === 0 && !path.basename(cacheDir).toLowerCase().includes("jeopi")) return undefined;
|
|
518
518
|
return await pruneBunInstallCache(cacheDir, packageNames.size === 0 ? undefined : packageNames);
|
|
519
519
|
}
|
|
520
520
|
|
|
@@ -561,26 +561,26 @@ function getBinaryName(): string {
|
|
|
561
561
|
/**
|
|
562
562
|
* Resolve the path that `jeopi` maps to in the user's PATH.
|
|
563
563
|
*/
|
|
564
|
-
function
|
|
564
|
+
function resolveJeopiPath(): string | undefined {
|
|
565
565
|
return $which(APP_NAME) ?? undefined;
|
|
566
566
|
}
|
|
567
567
|
|
|
568
568
|
/**
|
|
569
|
-
* Run the resolved
|
|
569
|
+
* Run the resolved jeopi binary and check if it reports the expected version.
|
|
570
570
|
*/
|
|
571
571
|
async function verifyInstalledVersion(expectedVersion: string): Promise<InstalledVersionVerification> {
|
|
572
|
-
const
|
|
573
|
-
if (!
|
|
572
|
+
const jeopiPath = resolveJeopiPath();
|
|
573
|
+
if (!jeopiPath) return { ok: false };
|
|
574
574
|
try {
|
|
575
|
-
const result = await $`${
|
|
576
|
-
if (result.exitCode !== 0) return { ok: false, path:
|
|
575
|
+
const result = await $`${jeopiPath} --version`.quiet().nothrow();
|
|
576
|
+
if (result.exitCode !== 0) return { ok: false, path: jeopiPath };
|
|
577
577
|
const output = result.text().trim();
|
|
578
|
-
// Output format: "
|
|
578
|
+
// Output format: "jeopi/X.Y.Z"
|
|
579
579
|
const match = output.match(/\/(\d+\.\d+\.\d+)/);
|
|
580
580
|
const actual = match?.[1];
|
|
581
|
-
return { ok: actual === expectedVersion, actual, path:
|
|
581
|
+
return { ok: actual === expectedVersion, actual, path: jeopiPath };
|
|
582
582
|
} catch {
|
|
583
|
-
return { ok: false, path:
|
|
583
|
+
return { ok: false, path: jeopiPath };
|
|
584
584
|
}
|
|
585
585
|
}
|
|
586
586
|
|
|
@@ -702,7 +702,7 @@ export async function replaceBinaryForUpdate(options: BinaryReplacementOptions):
|
|
|
702
702
|
}
|
|
703
703
|
|
|
704
704
|
/**
|
|
705
|
-
* Build the bun argv used to globally install a specific
|
|
705
|
+
* Build the bun argv used to globally install a specific jeopi version.
|
|
706
706
|
*
|
|
707
707
|
* The version is selected by hitting {@link NPM_REGISTRY} directly in
|
|
708
708
|
* {@link getLatestRelease}, so the install MUST observe the same catalog:
|
|
@@ -886,7 +886,7 @@ export async function runUpdateCommand(opts: { force: boolean; check: boolean })
|
|
|
886
886
|
return;
|
|
887
887
|
}
|
|
888
888
|
|
|
889
|
-
// Choose update method based on the prioritized
|
|
889
|
+
// Choose update method based on the prioritized jeopi binary in PATH
|
|
890
890
|
try {
|
|
891
891
|
const target = await resolveUpdateTarget();
|
|
892
892
|
if (target.method === "brew") {
|
package/src/cli/worktree-cli.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CLI handler for `jeopi worktree` — list and clean up agent-managed worktrees.
|
|
3
3
|
*
|
|
4
|
-
* Layout under `~/.
|
|
4
|
+
* Layout under `~/.jeopi/wt/`:
|
|
5
5
|
*
|
|
6
6
|
* - **PR-checkout worktrees** (`tools/gh.ts`): a regular git worktree dir
|
|
7
7
|
* containing a `.git` *file* that points back at
|
|
@@ -25,7 +25,7 @@ type WorktreeKind = "pr-checkout" | "task-isolation" | "empty" | "stray";
|
|
|
25
25
|
const TASK_ISOLATION_MOUNT_DIRS = ["m", "merged"] as const;
|
|
26
26
|
|
|
27
27
|
export interface WorktreeEntry {
|
|
28
|
-
/** Absolute path to the worktree dir (or stray container) under `~/.
|
|
28
|
+
/** Absolute path to the worktree dir (or stray container) under `~/.jeopi/wt/`. */
|
|
29
29
|
path: string;
|
|
30
30
|
/** Classification of what we found on disk. */
|
|
31
31
|
kind: WorktreeKind;
|
|
@@ -176,7 +176,7 @@ async function scanWorktrees(): Promise<WorktreeEntry[]> {
|
|
|
176
176
|
continue;
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
// Legacy nesting: ~/.
|
|
179
|
+
// Legacy nesting: ~/.jeopi/wt/<encoded-project>/<branch-or-id>
|
|
180
180
|
let children: string[];
|
|
181
181
|
try {
|
|
182
182
|
children = await fs.readdir(dir);
|
package/src/cli.ts
CHANGED
|
@@ -229,20 +229,20 @@ export async function runCli(argv: string[]): Promise<void> {
|
|
|
229
229
|
if (extracted.profile !== undefined) {
|
|
230
230
|
setProfile(extracted.profile);
|
|
231
231
|
} else {
|
|
232
|
-
// No explicit --profile: activate any
|
|
232
|
+
// No explicit --profile: activate any JEOPI_PROFILE/PI_PROFILE inherited
|
|
233
233
|
// from the environment. Module-load resolution deliberately swallows an
|
|
234
234
|
// invalid value to avoid an uncaught throw before this try/catch is in
|
|
235
235
|
// scope (see `readProfileFromEnvSafe` in dirs.ts), and callers may set
|
|
236
|
-
//
|
|
237
|
-
// validation here turns `
|
|
236
|
+
// JEOPI_PROFILE after importing this module (profile aliases/tests). Surfacing
|
|
237
|
+
// validation here turns `JEOPI_PROFILE=.. jeopi --version` into a clean error;
|
|
238
238
|
// calling setProfile keeps every later path helper on the env-selected
|
|
239
239
|
// profile instead of the default agent directory.
|
|
240
|
-
setProfile(resolveProfileEnv(process.env.
|
|
240
|
+
setProfile(resolveProfileEnv(process.env.JEOPI_PROFILE, process.env.PI_PROFILE));
|
|
241
241
|
}
|
|
242
242
|
if (extracted.aliasName !== undefined) {
|
|
243
243
|
const profile = extracted.profile ?? getActiveProfile();
|
|
244
244
|
if (!profile) {
|
|
245
|
-
throw new Error("--alias requires --profile <name> or
|
|
245
|
+
throw new Error("--alias requires --profile <name> or JEOPI_PROFILE");
|
|
246
246
|
}
|
|
247
247
|
const result = await installProfileAlias({
|
|
248
248
|
profile,
|
package/src/commands/agents.ts
CHANGED
|
@@ -23,8 +23,8 @@ export default class Agents extends Command {
|
|
|
23
23
|
force: Flags.boolean({ char: "f", description: "Overwrite existing agent files" }),
|
|
24
24
|
json: Flags.boolean({ description: "Output JSON" }),
|
|
25
25
|
dir: Flags.string({ description: "Output directory (overrides --user/--project)" }),
|
|
26
|
-
user: Flags.boolean({ description: "Write to ~/.
|
|
27
|
-
project: Flags.boolean({ description: "Write to ./.
|
|
26
|
+
user: Flags.boolean({ description: "Write to ~/.jeopi/agent/agents (default)" }),
|
|
27
|
+
project: Flags.boolean({ description: "Write to ./.jeopi/agents" }),
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
static examples = [
|