@oh-my-pi/pi-coding-agent 15.6.0 → 15.7.1
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 +35 -0
- package/dist/types/capability/rule-buckets.d.ts +30 -0
- package/dist/types/capability/rule.d.ts +7 -0
- package/dist/types/cli/completion-gen.d.ts +80 -0
- package/dist/types/commands/complete.d.ts +6 -0
- package/dist/types/commands/completions.d.ts +13 -0
- package/dist/types/commands/setup.d.ts +10 -1
- package/dist/types/config/settings-schema.d.ts +170 -10
- package/dist/types/discovery/builtin-defaults.d.ts +1 -0
- package/dist/types/discovery/builtin-rules/index.d.ts +7 -0
- package/dist/types/discovery/index.d.ts +1 -0
- package/dist/types/edit/hashline/block-resolver.d.ts +9 -0
- package/dist/types/edit/hashline/index.d.ts +1 -0
- package/dist/types/eval/py/kernel.d.ts +3 -0
- package/dist/types/eval/py/runtime.d.ts +11 -1
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/main.d.ts +1 -0
- package/dist/types/modes/components/index.d.ts +1 -0
- package/dist/types/modes/components/segment-track.d.ts +22 -0
- package/dist/types/modes/components/welcome.d.ts +21 -0
- package/dist/types/modes/interactive-mode.d.ts +3 -2
- package/dist/types/modes/setup-wizard/index.d.ts +16 -0
- package/dist/types/modes/setup-wizard/scenes/glyph.d.ts +2 -0
- package/dist/types/modes/setup-wizard/scenes/outro.d.ts +2 -0
- package/dist/types/modes/setup-wizard/scenes/providers.d.ts +2 -0
- package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +19 -0
- package/dist/types/modes/setup-wizard/scenes/splash.d.ts +11 -0
- package/dist/types/modes/setup-wizard/scenes/theme.d.ts +2 -0
- package/dist/types/modes/setup-wizard/scenes/types.d.ts +43 -0
- package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +19 -0
- package/dist/types/modes/setup-wizard/wizard-overlay.d.ts +14 -0
- package/dist/types/modes/theme/shimmer.d.ts +2 -0
- package/dist/types/modes/theme/theme.d.ts +11 -0
- package/dist/types/modes/types.d.ts +5 -1
- package/dist/types/tiny/device.d.ts +78 -0
- package/dist/types/tiny/dtype.d.ts +85 -0
- package/dist/types/tiny/models.d.ts +6 -6
- package/dist/types/tiny/text.d.ts +15 -0
- package/dist/types/tiny/title-client.d.ts +8 -0
- package/dist/types/tools/bash.d.ts +0 -1
- package/dist/types/tools/eval.d.ts +1 -1
- package/dist/types/tools/index.d.ts +0 -1
- package/dist/types/tui/code-cell.d.ts +2 -0
- package/dist/types/tui/output-block.d.ts +17 -0
- package/package.json +9 -9
- package/src/capability/rule-buckets.ts +64 -0
- package/src/capability/rule.ts +8 -0
- package/src/cli/completion-gen.ts +550 -0
- package/src/cli/setup-cli.ts +5 -3
- package/src/cli-commands.ts +2 -0
- package/src/cli.ts +1 -7
- package/src/commands/complete.ts +66 -0
- package/src/commands/completions.ts +60 -0
- package/src/commands/setup.ts +29 -4
- package/src/config/settings-schema.ts +70 -11
- package/src/discovery/builtin-defaults.ts +39 -0
- package/src/discovery/builtin-rules/index.ts +48 -0
- package/src/discovery/builtin-rules/rs-box-leak.md +48 -0
- package/src/discovery/builtin-rules/rs-future-prelude.md +23 -0
- package/src/discovery/builtin-rules/rs-lazylock.md +51 -0
- package/src/discovery/builtin-rules/rs-match-ergonomics.md +67 -0
- package/src/discovery/builtin-rules/rs-parking-lot.md +44 -0
- package/src/discovery/builtin-rules/rs-result-type.md +19 -0
- package/src/discovery/builtin-rules/ts-bare-catch.md +38 -0
- package/src/discovery/builtin-rules/ts-import-type.md +42 -0
- package/src/discovery/builtin-rules/ts-no-any.md +56 -0
- package/src/discovery/builtin-rules/ts-no-dynamic-import.md +39 -0
- package/src/discovery/builtin-rules/ts-no-return-type.md +45 -0
- package/src/discovery/builtin-rules/ts-no-tiny-functions.md +50 -0
- package/src/discovery/builtin-rules/ts-promise-with-resolvers.md +65 -0
- package/src/discovery/builtin-rules/ts-set-map.md +28 -0
- package/src/discovery/index.ts +1 -0
- package/src/edit/hashline/block-resolver.ts +14 -0
- package/src/edit/hashline/diff.ts +4 -1
- package/src/edit/hashline/execute.ts +2 -1
- package/src/edit/hashline/index.ts +1 -0
- package/src/eval/py/kernel.ts +37 -15
- package/src/eval/py/runtime.ts +57 -28
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +0 -12
- package/src/export/ttsr.ts +2 -0
- package/src/internal-urls/docs-index.generated.ts +7 -8
- package/src/main.ts +18 -1
- package/src/modes/components/hook-selector.ts +15 -17
- package/src/modes/components/index.ts +1 -0
- package/src/modes/components/segment-track.ts +52 -0
- package/src/modes/components/tips.txt +2 -1
- package/src/modes/components/tool-execution.ts +5 -1
- package/src/modes/components/welcome.ts +47 -42
- package/src/modes/controllers/input-controller.ts +12 -21
- package/src/modes/interactive-mode.ts +17 -5
- package/src/modes/setup-wizard/index.ts +88 -0
- package/src/modes/setup-wizard/scenes/glyph.ts +96 -0
- package/src/modes/setup-wizard/scenes/outro.ts +35 -0
- package/src/modes/setup-wizard/scenes/providers.ts +69 -0
- package/src/modes/setup-wizard/scenes/sign-in.ts +193 -0
- package/src/modes/setup-wizard/scenes/splash.ts +201 -0
- package/src/modes/setup-wizard/scenes/theme.ts +299 -0
- package/src/modes/setup-wizard/scenes/types.ts +48 -0
- package/src/modes/setup-wizard/scenes/web-search.ts +128 -0
- package/src/modes/setup-wizard/wizard-overlay.ts +275 -0
- package/src/modes/theme/shimmer.ts +5 -0
- package/src/modes/theme/theme.ts +44 -20
- package/src/modes/types.ts +6 -1
- package/src/prompts/system/orchestrate-notice.md +1 -1
- package/src/prompts/tools/read.md +4 -0
- package/src/sdk.ts +5 -15
- package/src/slash-commands/builtin-registry.ts +8 -0
- package/src/tiny/device.ts +117 -0
- package/src/tiny/dtype.ts +101 -0
- package/src/tiny/models.ts +7 -6
- package/src/tiny/text.ts +36 -1
- package/src/tiny/title-client.ts +58 -3
- package/src/tiny/worker.ts +93 -29
- package/src/tools/bash.ts +16 -13
- package/src/tools/eval.ts +9 -4
- package/src/tools/index.ts +0 -11
- package/src/tools/read.ts +1 -0
- package/src/tools/renderers.ts +0 -2
- package/src/tui/code-cell.ts +6 -1
- package/src/tui/output-block.ts +199 -38
- package/dist/types/tools/recipe/index.d.ts +0 -46
- package/dist/types/tools/recipe/render.d.ts +0 -36
- package/dist/types/tools/recipe/runner.d.ts +0 -60
- package/dist/types/tools/recipe/runners/cargo.d.ts +0 -16
- package/dist/types/tools/recipe/runners/index.d.ts +0 -2
- package/dist/types/tools/recipe/runners/just.d.ts +0 -2
- package/dist/types/tools/recipe/runners/make.d.ts +0 -2
- package/dist/types/tools/recipe/runners/pkg.d.ts +0 -2
- package/dist/types/tools/recipe/runners/task.d.ts +0 -2
- package/src/prompts/tools/recipe.md +0 -16
- package/src/tools/recipe/index.ts +0 -81
- package/src/tools/recipe/render.ts +0 -19
- package/src/tools/recipe/runner.ts +0 -219
- package/src/tools/recipe/runners/cargo.ts +0 -131
- package/src/tools/recipe/runners/index.ts +0 -8
- package/src/tools/recipe/runners/just.ts +0 -73
- package/src/tools/recipe/runners/make.ts +0 -101
- package/src/tools/recipe/runners/pkg.ts +0 -167
- package/src/tools/recipe/runners/task.ts +0 -72
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule bucketing
|
|
3
|
+
*
|
|
4
|
+
* Single funnel that every discovered rule passes through on its way into a
|
|
5
|
+
* session. It applies the user's disable levers, registers TTSR rules with the
|
|
6
|
+
* manager, and splits the rest into the always-apply and rulebook buckets.
|
|
7
|
+
*
|
|
8
|
+
* Bucket precedence (matches docs/rulebook-matching-pipeline.md §5):
|
|
9
|
+
* 1. TTSR — non-empty `condition` that `TtsrManager.addRule` accepts
|
|
10
|
+
* 2. always — `alwaysApply === true`
|
|
11
|
+
* 3. rulebook — has a `description`
|
|
12
|
+
*/
|
|
13
|
+
import type { TtsrManager } from "../export/ttsr";
|
|
14
|
+
import { BUILTIN_DEFAULTS_PROVIDER_ID, type Rule } from "./rule";
|
|
15
|
+
|
|
16
|
+
export interface RuleBuckets {
|
|
17
|
+
rulebookRules: Rule[];
|
|
18
|
+
alwaysApplyRules: Rule[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface BucketRulesOptions {
|
|
22
|
+
/** Rule names to drop entirely (bundled defaults and user rules alike). */
|
|
23
|
+
disabledRules?: readonly string[];
|
|
24
|
+
/** When false, drop every rule from the bundled `builtin-defaults` provider. */
|
|
25
|
+
builtinRules?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Filter and bucket rules, registering TTSR rules on `ttsrManager` as a side
|
|
30
|
+
* effect. Disabled rules are dropped before any bucket assignment, so a
|
|
31
|
+
* disabled rule is neither matched as TTSR nor surfaced via `rule://`.
|
|
32
|
+
*/
|
|
33
|
+
export function bucketRules(
|
|
34
|
+
rules: readonly Rule[],
|
|
35
|
+
ttsrManager: TtsrManager,
|
|
36
|
+
options: BucketRulesOptions = {},
|
|
37
|
+
): RuleBuckets {
|
|
38
|
+
const includeBuiltin = options.builtinRules !== false;
|
|
39
|
+
const disabled = new Set<string>();
|
|
40
|
+
for (const raw of options.disabledRules ?? []) {
|
|
41
|
+
const name = raw.trim();
|
|
42
|
+
if (name.length > 0) disabled.add(name);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const rulebookRules: Rule[] = [];
|
|
46
|
+
const alwaysApplyRules: Rule[] = [];
|
|
47
|
+
|
|
48
|
+
for (const rule of rules) {
|
|
49
|
+
if (disabled.has(rule.name)) continue;
|
|
50
|
+
if (!includeBuiltin && rule._source?.provider === BUILTIN_DEFAULTS_PROVIDER_ID) continue;
|
|
51
|
+
|
|
52
|
+
const isTtsrRule = rule.condition && rule.condition.length > 0 ? ttsrManager.addRule(rule) : false;
|
|
53
|
+
if (isTtsrRule) continue;
|
|
54
|
+
if (rule.alwaysApply === true) {
|
|
55
|
+
alwaysApplyRules.push(rule);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (rule.description) {
|
|
59
|
+
rulebookRules.push(rule);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return { rulebookRules, alwaysApplyRules };
|
|
64
|
+
}
|
package/src/capability/rule.ts
CHANGED
|
@@ -9,6 +9,14 @@ import type { SourceMeta } from "./types";
|
|
|
9
9
|
|
|
10
10
|
const CONDITION_GLOB_SCOPE_TOOLS = ["edit", "write"] as const;
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Provider id for the bundled default rules shipped with the agent.
|
|
14
|
+
* Lowest priority, so any user/project/tool rule of the same name overrides
|
|
15
|
+
* a bundled default. Also used to gate the whole bundled set via
|
|
16
|
+
* `ttsr.builtinRules`.
|
|
17
|
+
*/
|
|
18
|
+
export const BUILTIN_DEFAULTS_PROVIDER_ID = "builtin-defaults";
|
|
19
|
+
|
|
12
20
|
/**
|
|
13
21
|
* Parsed frontmatter from rule files.
|
|
14
22
|
*/
|
|
@@ -0,0 +1,550 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell-completion generation (bash, zsh, fish).
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth: the declarative `flags`/`args` descriptors carried by
|
|
5
|
+
* each `Command` subclass plus the registered subcommand table. {@link buildSpec}
|
|
6
|
+
* walks that metadata — the same data `renderCommandBody` renders for `--help` —
|
|
7
|
+
* and {@link generateCompletion} emits a self-contained completion script. Adding
|
|
8
|
+
* a flag to a command's static `flags` therefore propagates into completions with
|
|
9
|
+
* no edits here.
|
|
10
|
+
*
|
|
11
|
+
* Static candidates (enum `options`, the builtin tool list) are baked into the
|
|
12
|
+
* script. A small set of flags resolve dynamic candidates (the live model
|
|
13
|
+
* catalog and on-disk sessions) by calling back into `<bin> __complete <kind>`
|
|
14
|
+
* — see `commands/complete.ts`. The flag→source mapping below is the only manual
|
|
15
|
+
* knob and is keyed by flag name so it stays stable as flags are added.
|
|
16
|
+
*/
|
|
17
|
+
import type { ArgDescriptor, CliConfig, CommandCtor, FlagDescriptor } from "@oh-my-pi/pi-utils/cli";
|
|
18
|
+
import { BUILTIN_TOOLS } from "../tools";
|
|
19
|
+
|
|
20
|
+
export type Shell = "bash" | "zsh" | "fish";
|
|
21
|
+
|
|
22
|
+
/** How a flag/positional value should be completed. */
|
|
23
|
+
export type ValueSource =
|
|
24
|
+
| { kind: "flag" } // boolean — takes no value
|
|
25
|
+
| { kind: "value" } // takes a value with no completable candidates (e.g. integer, free text)
|
|
26
|
+
| { kind: "enum"; values: readonly string[] } // static single value
|
|
27
|
+
| { kind: "list"; values: readonly string[] } // static comma-separated list
|
|
28
|
+
| { kind: "models"; multiple: boolean } // dynamic: live model catalog
|
|
29
|
+
| { kind: "sessions" } // dynamic: on-disk sessions
|
|
30
|
+
| { kind: "file" }
|
|
31
|
+
| { kind: "dir" };
|
|
32
|
+
|
|
33
|
+
export interface CompletionFlag {
|
|
34
|
+
/** Long name without the leading `--`. */
|
|
35
|
+
name: string;
|
|
36
|
+
/** Short character without the leading `-`. */
|
|
37
|
+
char?: string;
|
|
38
|
+
description: string;
|
|
39
|
+
value: ValueSource;
|
|
40
|
+
/** Flag may appear multiple times (oclif `multiple`). */
|
|
41
|
+
repeatable: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface CompletionArg {
|
|
45
|
+
name: string;
|
|
46
|
+
description: string;
|
|
47
|
+
value: ValueSource;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface CompletionCommand {
|
|
51
|
+
name: string;
|
|
52
|
+
aliases: readonly string[];
|
|
53
|
+
description: string;
|
|
54
|
+
flags: CompletionFlag[];
|
|
55
|
+
args: CompletionArg[];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface CompletionSpec {
|
|
59
|
+
bin: string;
|
|
60
|
+
/** Flags/args of the default (no-subcommand) command. */
|
|
61
|
+
root: { flags: CompletionFlag[]; args: CompletionArg[] };
|
|
62
|
+
commands: CompletionCommand[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// --- Flag/arg value classification (the single manual mapping) ----------------
|
|
66
|
+
|
|
67
|
+
/** Single-value flags resolved against the live model catalog. */
|
|
68
|
+
const MODEL_FLAGS: Record<string, true> = { model: true, smol: true, slow: true, plan: true };
|
|
69
|
+
/** Single-value flags resolved against on-disk sessions. */
|
|
70
|
+
const SESSION_FLAGS: Record<string, true> = { resume: true, fork: true, session: true };
|
|
71
|
+
/** Flags whose value is a directory path. */
|
|
72
|
+
const DIR_FLAGS: Record<string, true> = { "session-dir": true, "plugin-dir": true };
|
|
73
|
+
|
|
74
|
+
function flagValue(name: string, desc: FlagDescriptor): ValueSource {
|
|
75
|
+
if (desc.kind === "boolean") return { kind: "flag" };
|
|
76
|
+
if (desc.options && desc.options.length > 0) return { kind: "enum", values: desc.options };
|
|
77
|
+
if (MODEL_FLAGS[name]) return { kind: "models", multiple: false };
|
|
78
|
+
if (name === "models") return { kind: "models", multiple: true };
|
|
79
|
+
if (SESSION_FLAGS[name]) return { kind: "sessions" };
|
|
80
|
+
if (name === "tools") return { kind: "list", values: Object.keys(BUILTIN_TOOLS) };
|
|
81
|
+
if (DIR_FLAGS[name]) return { kind: "dir" };
|
|
82
|
+
if (desc.kind === "integer") return { kind: "value" };
|
|
83
|
+
return { kind: "file" };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function argValue(desc: ArgDescriptor): ValueSource {
|
|
87
|
+
if (desc.options && desc.options.length > 0) return { kind: "enum", values: desc.options };
|
|
88
|
+
return { kind: "file" };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function buildFlags(Cmd: CommandCtor): CompletionFlag[] {
|
|
92
|
+
const out: CompletionFlag[] = [];
|
|
93
|
+
const flags = Cmd.flags ?? {};
|
|
94
|
+
for (const name in flags) {
|
|
95
|
+
const desc = flags[name];
|
|
96
|
+
out.push({
|
|
97
|
+
name,
|
|
98
|
+
char: desc.char,
|
|
99
|
+
description: desc.description ?? "",
|
|
100
|
+
value: flagValue(name, desc),
|
|
101
|
+
repeatable: Boolean(desc.multiple),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function buildArgs(Cmd: CommandCtor): CompletionArg[] {
|
|
108
|
+
const out: CompletionArg[] = [];
|
|
109
|
+
const args = Cmd.args ?? {};
|
|
110
|
+
for (const name in args) {
|
|
111
|
+
const desc = args[name];
|
|
112
|
+
out.push({ name, description: desc.description ?? "", value: argValue(desc) });
|
|
113
|
+
}
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Build a {@link CompletionSpec} from loaded command classes.
|
|
119
|
+
*
|
|
120
|
+
* @param rootName Entry name of the default command (its flags become top-level
|
|
121
|
+
* flags; it is excluded from the subcommand list).
|
|
122
|
+
* @param aliasMap Canonical-name → aliases (merged from the registration table
|
|
123
|
+
* and the command class's static `aliases`).
|
|
124
|
+
*/
|
|
125
|
+
export function buildSpec(
|
|
126
|
+
config: CliConfig,
|
|
127
|
+
rootName: string,
|
|
128
|
+
aliasMap: Map<string, readonly string[]>,
|
|
129
|
+
): CompletionSpec {
|
|
130
|
+
const commands: CompletionCommand[] = [];
|
|
131
|
+
let root: CompletionSpec["root"] = { flags: [], args: [] };
|
|
132
|
+
for (const [name, Cmd] of config.commands) {
|
|
133
|
+
const flags = buildFlags(Cmd);
|
|
134
|
+
const args = buildArgs(Cmd);
|
|
135
|
+
if (name === rootName) {
|
|
136
|
+
root = { flags, args };
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (Cmd.hidden) continue;
|
|
140
|
+
commands.push({
|
|
141
|
+
name,
|
|
142
|
+
aliases: aliasMap.get(name) ?? [],
|
|
143
|
+
description: Cmd.description ?? "",
|
|
144
|
+
flags,
|
|
145
|
+
args,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
commands.sort((a, b) => a.name.localeCompare(b.name));
|
|
149
|
+
return { bin: config.bin, root, commands };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// --- Shared helpers -----------------------------------------------------------
|
|
153
|
+
|
|
154
|
+
/** Every value source except a bare boolean flag consumes the following token. */
|
|
155
|
+
function takesValue(v: ValueSource): boolean {
|
|
156
|
+
return v.kind !== "flag";
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** All token forms (`name` + aliases) under which a subcommand can be invoked. */
|
|
160
|
+
function commandTokens(c: CompletionCommand): string[] {
|
|
161
|
+
return [c.name, ...c.aliases];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function generateCompletion(shell: Shell, spec: CompletionSpec): string {
|
|
165
|
+
switch (shell) {
|
|
166
|
+
case "bash":
|
|
167
|
+
return generateBash(spec);
|
|
168
|
+
case "zsh":
|
|
169
|
+
return generateZsh(spec);
|
|
170
|
+
case "fish":
|
|
171
|
+
return generateFish(spec);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// --- bash ---------------------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
/** Escape for use inside a bash double-quoted `compgen -W "…"` word list. */
|
|
178
|
+
function bashWords(values: readonly string[]): string {
|
|
179
|
+
return values.join(" ").replace(/"/g, '\\"');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** bash snippet that fills COMPREPLY for a flag value, then `return 0`. */
|
|
183
|
+
function bashValueBranch(bin: string, v: ValueSource): string {
|
|
184
|
+
switch (v.kind) {
|
|
185
|
+
case "flag":
|
|
186
|
+
case "value":
|
|
187
|
+
return "return 0";
|
|
188
|
+
case "enum":
|
|
189
|
+
return `COMPREPLY=( $(compgen -W "${bashWords(v.values)}" -- "$cur") ); return 0`;
|
|
190
|
+
case "list":
|
|
191
|
+
return `_omp_comma "${bashWords(v.values)}"; return 0`;
|
|
192
|
+
case "models":
|
|
193
|
+
return v.multiple
|
|
194
|
+
? `_omp_comma "$(command ${bin} __complete models 2>/dev/null | cut -f1)"; return 0`
|
|
195
|
+
: `COMPREPLY=( $(compgen -W "$(command ${bin} __complete models -- "$cur" 2>/dev/null | cut -f1)" -- "$cur") ); return 0`;
|
|
196
|
+
case "sessions":
|
|
197
|
+
return `COMPREPLY=( $(compgen -W "$(command ${bin} __complete sessions -- "$cur" 2>/dev/null | cut -f1)" -- "$cur") ); return 0`;
|
|
198
|
+
case "file":
|
|
199
|
+
return `COMPREPLY=( $(compgen -f -- "$cur") ); compopt -o filenames; return 0`;
|
|
200
|
+
case "dir":
|
|
201
|
+
return `COMPREPLY=( $(compgen -d -- "$cur") ); compopt -o filenames; return 0`;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Build the `case "$prev" in …` arms for every value-taking flag in scope. */
|
|
206
|
+
function bashFlagCase(bin: string, flags: CompletionFlag[]): string {
|
|
207
|
+
const lines: string[] = [];
|
|
208
|
+
for (const f of flags) {
|
|
209
|
+
if (!takesValue(f.value)) continue;
|
|
210
|
+
const labels = [`--${f.name}`, ...(f.char ? [`-${f.char}`] : [])];
|
|
211
|
+
lines.push(`\t\t${labels.join("|")})\n\t\t\t${bashValueBranch(bin, f.value)}\n\t\t\t;;`);
|
|
212
|
+
}
|
|
213
|
+
return lines.join("\n");
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function bashFlagWords(flags: CompletionFlag[]): string {
|
|
217
|
+
const words: string[] = [];
|
|
218
|
+
for (const f of flags) {
|
|
219
|
+
words.push(`--${f.name}`);
|
|
220
|
+
if (f.char) words.push(`-${f.char}`);
|
|
221
|
+
}
|
|
222
|
+
return words.join(" ");
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function generateBash(spec: CompletionSpec): string {
|
|
226
|
+
const { bin } = spec;
|
|
227
|
+
const parts: string[] = [];
|
|
228
|
+
parts.push(`# bash completion for ${bin} — generated by \`${bin} completions bash\``);
|
|
229
|
+
parts.push("");
|
|
230
|
+
|
|
231
|
+
// Comma-aware static/dynamic list completion helper.
|
|
232
|
+
parts.push(`_omp_comma() {
|
|
233
|
+
local words="$1" realcur prefix
|
|
234
|
+
realcur="\${cur##*,}"
|
|
235
|
+
prefix="\${cur%"$realcur"}"
|
|
236
|
+
local -a matches
|
|
237
|
+
matches=( $(compgen -W "$words" -- "$realcur") )
|
|
238
|
+
local i
|
|
239
|
+
for (( i=0; i < \${#matches[@]}; i++ )); do matches[i]="$prefix\${matches[i]}"; done
|
|
240
|
+
COMPREPLY=( "\${matches[@]}" )
|
|
241
|
+
compopt -o nospace 2>/dev/null
|
|
242
|
+
}`);
|
|
243
|
+
parts.push("");
|
|
244
|
+
|
|
245
|
+
// Root handler: top-level flags + subcommand names.
|
|
246
|
+
const subTokens = spec.commands.flatMap(commandTokens).sort();
|
|
247
|
+
parts.push(`_omp_root() {
|
|
248
|
+
case "$prev" in
|
|
249
|
+
${bashFlagCase(bin, spec.root.flags)}
|
|
250
|
+
esac
|
|
251
|
+
if [[ "$cur" == -* ]]; then
|
|
252
|
+
COMPREPLY=( $(compgen -W "${bashFlagWords(spec.root.flags)}" -- "$cur") )
|
|
253
|
+
else
|
|
254
|
+
COMPREPLY=( $(compgen -W "${bashWords(subTokens)} ${bashFlagWords(spec.root.flags)}" -- "$cur") )
|
|
255
|
+
fi
|
|
256
|
+
}`);
|
|
257
|
+
parts.push("");
|
|
258
|
+
|
|
259
|
+
// Per-subcommand handlers.
|
|
260
|
+
for (const c of spec.commands) {
|
|
261
|
+
const argEnum = c.args.find(a => a.value.kind === "enum");
|
|
262
|
+
const argWords = argEnum && argEnum.value.kind === "enum" ? bashWords(argEnum.value.values) : "";
|
|
263
|
+
const fileArg = c.args.some(a => a.value.kind === "file");
|
|
264
|
+
const elseBranch = argWords
|
|
265
|
+
? `COMPREPLY=( $(compgen -W "${argWords}" -- "$cur") )`
|
|
266
|
+
: fileArg
|
|
267
|
+
? `COMPREPLY=( $(compgen -f -- "$cur") ); compopt -o filenames`
|
|
268
|
+
: ":";
|
|
269
|
+
parts.push(`_omp_cmd_${bashFn(c.name)}() {
|
|
270
|
+
case "$prev" in
|
|
271
|
+
${bashFlagCase(bin, c.flags)}
|
|
272
|
+
esac
|
|
273
|
+
if [[ "$cur" == -* ]]; then
|
|
274
|
+
COMPREPLY=( $(compgen -W "${bashFlagWords(c.flags)}" -- "$cur") )
|
|
275
|
+
else
|
|
276
|
+
${elseBranch}
|
|
277
|
+
fi
|
|
278
|
+
}`);
|
|
279
|
+
parts.push("");
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Dispatcher.
|
|
283
|
+
const dispatch: string[] = [];
|
|
284
|
+
for (const c of spec.commands) {
|
|
285
|
+
dispatch.push(`\t\t${commandTokens(c).join("|")})\n\t\t\t_omp_cmd_${bashFn(c.name)}\n\t\t\t;;`);
|
|
286
|
+
}
|
|
287
|
+
parts.push(`_omp() {
|
|
288
|
+
local cur prev cmd i
|
|
289
|
+
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
290
|
+
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
291
|
+
cmd=""
|
|
292
|
+
for (( i=1; i < COMP_CWORD; i++ )); do
|
|
293
|
+
case "\${COMP_WORDS[i]}" in
|
|
294
|
+
-*) ;;
|
|
295
|
+
*) cmd="\${COMP_WORDS[i]}"; break ;;
|
|
296
|
+
esac
|
|
297
|
+
done
|
|
298
|
+
case "$cmd" in
|
|
299
|
+
${dispatch.join("\n")}
|
|
300
|
+
*) _omp_root ;;
|
|
301
|
+
esac
|
|
302
|
+
}
|
|
303
|
+
complete -F _omp ${bin}`);
|
|
304
|
+
parts.push("");
|
|
305
|
+
return `${parts.join("\n")}\n`;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function bashFn(name: string): string {
|
|
309
|
+
return name.replace(/[^A-Za-z0-9]/g, "_");
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// --- zsh ----------------------------------------------------------------------
|
|
313
|
+
|
|
314
|
+
/** Sanitize a description for embedding in a single-quoted zsh `_arguments` spec. */
|
|
315
|
+
function zshDesc(s: string): string {
|
|
316
|
+
return s
|
|
317
|
+
.replace(/'/g, "’")
|
|
318
|
+
.replace(/\[/g, "(")
|
|
319
|
+
.replace(/\]/g, ")")
|
|
320
|
+
.replace(/[\r\n]+/g, " ")
|
|
321
|
+
.replace(/:/g, " ")
|
|
322
|
+
.trim();
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function zshAction(v: ValueSource): string {
|
|
326
|
+
switch (v.kind) {
|
|
327
|
+
case "flag":
|
|
328
|
+
return "";
|
|
329
|
+
case "value":
|
|
330
|
+
return ":value:";
|
|
331
|
+
case "enum":
|
|
332
|
+
return `:value:(${v.values.join(" ")})`;
|
|
333
|
+
case "list":
|
|
334
|
+
return ":value:_omp_tools";
|
|
335
|
+
case "models":
|
|
336
|
+
return v.multiple ? ":models:_omp_models_list" : ":model:_omp_call models";
|
|
337
|
+
case "sessions":
|
|
338
|
+
return ":session:_omp_call sessions";
|
|
339
|
+
case "file":
|
|
340
|
+
return ":file:_files";
|
|
341
|
+
case "dir":
|
|
342
|
+
return ":dir:_files -/";
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function zshFlagSpec(f: CompletionFlag): string {
|
|
347
|
+
const body = `[${zshDesc(f.description)}]${zshAction(f.value)}`;
|
|
348
|
+
if (f.char && f.repeatable) return `'*'{-${f.char},--${f.name}}'${body}'`;
|
|
349
|
+
if (f.char) return `'(-${f.char} --${f.name})'{-${f.char},--${f.name}}'${body}'`;
|
|
350
|
+
if (f.repeatable) return `'*--${f.name}${body}'`;
|
|
351
|
+
return `'--${f.name}${body}'`;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function zshArgSpec(f: CompletionArg): string {
|
|
355
|
+
switch (f.value.kind) {
|
|
356
|
+
case "enum":
|
|
357
|
+
return `':${f.name}:(${f.value.values.join(" ")})'`;
|
|
358
|
+
default:
|
|
359
|
+
return `':${f.name}:_files'`;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function generateZsh(spec: CompletionSpec): string {
|
|
364
|
+
const { bin } = spec;
|
|
365
|
+
// The `:value:_omp_tools` action references this helper; bake its candidates
|
|
366
|
+
// from the spec's `list` flag so the generator stays a pure function of its
|
|
367
|
+
// input (bash/fish read `v.values` inline for the same reason).
|
|
368
|
+
const listFlag = [...spec.root.flags, ...spec.commands.flatMap(c => c.flags)].find(f => f.value.kind === "list");
|
|
369
|
+
const toolNames = listFlag?.value.kind === "list" ? listFlag.value.values.join(" ") : "";
|
|
370
|
+
const parts: string[] = [];
|
|
371
|
+
parts.push(`#compdef ${bin}`);
|
|
372
|
+
parts.push(`# zsh completion for ${bin} — generated by \`${bin} completions zsh\``);
|
|
373
|
+
parts.push("");
|
|
374
|
+
|
|
375
|
+
// Dynamic helpers (single source: `<bin> __complete <kind>` → value<TAB>desc).
|
|
376
|
+
parts.push(`_omp_call() {
|
|
377
|
+
local kind=$1
|
|
378
|
+
local -a items
|
|
379
|
+
local line
|
|
380
|
+
for line in "\${(@f)$(command ${bin} __complete $kind -- "$PREFIX" 2>/dev/null)}"; do
|
|
381
|
+
[[ -z $line ]] && continue
|
|
382
|
+
items+=( "\${line//$'\\t'/:}" )
|
|
383
|
+
done
|
|
384
|
+
_describe -t "$kind" "$kind" items
|
|
385
|
+
}
|
|
386
|
+
_omp_models_list() {
|
|
387
|
+
local -a items
|
|
388
|
+
local line
|
|
389
|
+
for line in "\${(@f)$(command ${bin} __complete models 2>/dev/null)}"; do
|
|
390
|
+
[[ -z $line ]] && continue
|
|
391
|
+
items+=( "\${line%%$'\\t'*}" )
|
|
392
|
+
done
|
|
393
|
+
_values -s , 'models' $items
|
|
394
|
+
}
|
|
395
|
+
_omp_tools() { _values -s , 'tools' ${toolNames} }`);
|
|
396
|
+
parts.push("");
|
|
397
|
+
|
|
398
|
+
// Subcommand description table.
|
|
399
|
+
const cmdRows = spec.commands.map(c => `\t\t'${c.name}:${zshDesc(c.description)}'`).join("\n");
|
|
400
|
+
parts.push(`_omp_commands() {
|
|
401
|
+
local -a commands
|
|
402
|
+
commands=(
|
|
403
|
+
${cmdRows}
|
|
404
|
+
)
|
|
405
|
+
_describe -t commands 'command' commands
|
|
406
|
+
}`);
|
|
407
|
+
parts.push("");
|
|
408
|
+
|
|
409
|
+
// Per-subcommand argument functions.
|
|
410
|
+
for (const c of spec.commands) {
|
|
411
|
+
const specs = ["'(-h --help)'{-h,--help}'[Show help]'", ...c.flags.map(zshFlagSpec), ...c.args.map(zshArgSpec)];
|
|
412
|
+
parts.push(`_omp_cmd_${bashFn(c.name)}() {
|
|
413
|
+
_arguments -s \\
|
|
414
|
+
${specs.join(" \\\n\t\t")}
|
|
415
|
+
}`);
|
|
416
|
+
parts.push("");
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Top-level dispatch.
|
|
420
|
+
const aliasArms = spec.commands
|
|
421
|
+
.map(c => `\t\t\t${commandTokens(c).join("|")}) _omp_cmd_${bashFn(c.name)} ;;`)
|
|
422
|
+
.join("\n");
|
|
423
|
+
const rootSpecs = [
|
|
424
|
+
"'(-h --help)'{-h,--help}'[Show help]'",
|
|
425
|
+
"'(-v --version)'{-v,--version}'[Show version]'",
|
|
426
|
+
...spec.root.flags.map(zshFlagSpec),
|
|
427
|
+
"'1: :_omp_commands'",
|
|
428
|
+
"'*::arg:->args'",
|
|
429
|
+
];
|
|
430
|
+
parts.push(`_omp() {
|
|
431
|
+
local curcontext="$curcontext" state line
|
|
432
|
+
typeset -A opt_args
|
|
433
|
+
_arguments -C -s \\
|
|
434
|
+
${rootSpecs.join(" \\\n\t\t")}
|
|
435
|
+
case $state in
|
|
436
|
+
args)
|
|
437
|
+
case $line[1] in
|
|
438
|
+
${aliasArms}
|
|
439
|
+
esac
|
|
440
|
+
;;
|
|
441
|
+
esac
|
|
442
|
+
}
|
|
443
|
+
# Works both ways: autoloaded from $fpath (file named _omp) or eval'd from a
|
|
444
|
+
# startup file. When autoloaded, funcstack[1] is _omp and we invoke it; when
|
|
445
|
+
# sourced/eval'd we register it with compdef instead.
|
|
446
|
+
if [ "$funcstack[1]" = "_omp" ]; then
|
|
447
|
+
_omp "$@"
|
|
448
|
+
else
|
|
449
|
+
compdef _omp ${bin}
|
|
450
|
+
fi`);
|
|
451
|
+
parts.push("");
|
|
452
|
+
return `${parts.join("\n")}\n`;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// --- fish ---------------------------------------------------------------------
|
|
456
|
+
|
|
457
|
+
function fishDesc(s: string): string {
|
|
458
|
+
return s
|
|
459
|
+
.replace(/'/g, "’")
|
|
460
|
+
.replace(/[\r\n]+/g, " ")
|
|
461
|
+
.trim();
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function fishValue(bin: string, v: ValueSource): string {
|
|
465
|
+
switch (v.kind) {
|
|
466
|
+
case "flag":
|
|
467
|
+
return "";
|
|
468
|
+
case "value":
|
|
469
|
+
return "-x";
|
|
470
|
+
case "enum":
|
|
471
|
+
case "list":
|
|
472
|
+
return `-x -a '${v.values.join(" ")}'`;
|
|
473
|
+
case "models":
|
|
474
|
+
return `-x -a '(command ${bin} __complete models -- (commandline -ct))'`;
|
|
475
|
+
case "sessions":
|
|
476
|
+
return `-x -a '(command ${bin} __complete sessions -- (commandline -ct))'`;
|
|
477
|
+
case "file":
|
|
478
|
+
return "-r -F";
|
|
479
|
+
case "dir":
|
|
480
|
+
return "-x -a '(__fish_complete_directories (commandline -ct))'";
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function fishFlagLine(bin: string, cond: string, f: CompletionFlag): string {
|
|
485
|
+
const segs = [`complete -c ${bin}`, `-n '${cond}'`];
|
|
486
|
+
if (f.char) segs.push(`-s ${f.char}`);
|
|
487
|
+
segs.push(`-l ${f.name}`);
|
|
488
|
+
if (f.description) segs.push(`-d '${fishDesc(f.description)}'`);
|
|
489
|
+
const val = fishValue(bin, f.value);
|
|
490
|
+
if (val) segs.push(val);
|
|
491
|
+
return segs.join(" ");
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function generateFish(spec: CompletionSpec): string {
|
|
495
|
+
const { bin } = spec;
|
|
496
|
+
const lines: string[] = [];
|
|
497
|
+
lines.push(`# fish completion for ${bin} — generated by \`${bin} completions fish\``);
|
|
498
|
+
lines.push("");
|
|
499
|
+
|
|
500
|
+
const allTokens = spec.commands.flatMap(commandTokens);
|
|
501
|
+
lines.push(`function __fish_omp_no_subcommand`);
|
|
502
|
+
lines.push(`\tfor i in (commandline -opc)`);
|
|
503
|
+
lines.push(`\t\tif contains -- $i ${allTokens.join(" ")}`);
|
|
504
|
+
lines.push(`\t\t\treturn 1`);
|
|
505
|
+
lines.push(`\t\tend`);
|
|
506
|
+
lines.push(`\tend`);
|
|
507
|
+
lines.push(`\treturn 0`);
|
|
508
|
+
lines.push(`end`);
|
|
509
|
+
lines.push("");
|
|
510
|
+
|
|
511
|
+
const rootCond = "__fish_omp_no_subcommand";
|
|
512
|
+
|
|
513
|
+
// Subcommand names.
|
|
514
|
+
for (const c of spec.commands) {
|
|
515
|
+
for (const token of commandTokens(c)) {
|
|
516
|
+
lines.push(`complete -c ${bin} -f -n '${rootCond}' -a '${token}' -d '${fishDesc(c.description)}'`);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
lines.push("");
|
|
520
|
+
|
|
521
|
+
// Top-level flags.
|
|
522
|
+
for (const f of spec.root.flags) {
|
|
523
|
+
lines.push(fishFlagLine(bin, rootCond, f));
|
|
524
|
+
}
|
|
525
|
+
lines.push("");
|
|
526
|
+
|
|
527
|
+
// Per-subcommand flags and positional args.
|
|
528
|
+
for (const c of spec.commands) {
|
|
529
|
+
const cond = `__fish_seen_subcommand_from ${commandTokens(c).join(" ")}`;
|
|
530
|
+
for (const f of c.flags) {
|
|
531
|
+
lines.push(fishFlagLine(bin, cond, f));
|
|
532
|
+
}
|
|
533
|
+
// Positionals: fish conditions can't gate on position, so emit enum
|
|
534
|
+
// candidates (if any) and otherwise a single file completion — never both,
|
|
535
|
+
// and never duplicated across multiple file-typed positionals.
|
|
536
|
+
const enumArgs = c.args.filter(a => a.value.kind === "enum");
|
|
537
|
+
if (enumArgs.length > 0) {
|
|
538
|
+
for (const a of enumArgs) {
|
|
539
|
+
if (a.value.kind !== "enum") continue;
|
|
540
|
+
lines.push(
|
|
541
|
+
`complete -c ${bin} -f -n '${cond}' -a '${a.value.values.join(" ")}' -d '${fishDesc(a.description)}'`,
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
} else if (c.args.some(a => a.value.kind === "file")) {
|
|
545
|
+
lines.push(`complete -c ${bin} -F -n '${cond}'`);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
lines.push("");
|
|
549
|
+
return `${lines.join("\n")}\n`;
|
|
550
|
+
}
|
package/src/cli/setup-cli.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Setup CLI command handler.
|
|
3
3
|
*
|
|
4
|
-
* Handles `omp setup <component>`
|
|
4
|
+
* Handles `omp setup` for onboarding and `omp setup <component>` for optional dependencies.
|
|
5
5
|
*/
|
|
6
6
|
import * as path from "node:path";
|
|
7
7
|
import { $which, APP_NAME, getPythonEnvDir } from "@oh-my-pi/pi-utils";
|
|
@@ -207,9 +207,10 @@ async function handleSttSetup(flags: { json?: boolean; check?: boolean }): Promi
|
|
|
207
207
|
* Print setup command help.
|
|
208
208
|
*/
|
|
209
209
|
export function printSetupHelp(): void {
|
|
210
|
-
console.log(`${chalk.bold(`${APP_NAME} setup`)} -
|
|
210
|
+
console.log(`${chalk.bold(`${APP_NAME} setup`)} - Run onboarding or install dependencies for optional features
|
|
211
211
|
|
|
212
212
|
${chalk.bold("Usage:")}
|
|
213
|
+
${APP_NAME} setup Run the onboarding wizard
|
|
213
214
|
${APP_NAME} setup <component> [options]
|
|
214
215
|
|
|
215
216
|
${chalk.bold("Components:")}
|
|
@@ -221,7 +222,8 @@ ${chalk.bold("Options:")}
|
|
|
221
222
|
--json Output status as JSON
|
|
222
223
|
|
|
223
224
|
${chalk.bold("Examples:")}
|
|
224
|
-
${APP_NAME} setup
|
|
225
|
+
${APP_NAME} setup Run the onboarding wizard
|
|
226
|
+
${APP_NAME} setup python Check Python execution dependencies
|
|
225
227
|
${APP_NAME} setup stt Install speech-to-text dependencies
|
|
226
228
|
${APP_NAME} setup stt --check Check if STT dependencies are available
|
|
227
229
|
${APP_NAME} setup python --check Check if Python execution is available
|
package/src/cli-commands.ts
CHANGED
|
@@ -17,6 +17,8 @@ export const commands: CommandEntry[] = [
|
|
|
17
17
|
{ name: "auth-gateway", load: () => import("./commands/auth-gateway").then(m => m.default) },
|
|
18
18
|
{ name: "agents", load: () => import("./commands/agents").then(m => m.default) },
|
|
19
19
|
{ name: "commit", load: () => import("./commands/commit").then(m => m.default) },
|
|
20
|
+
{ name: "completions", load: () => import("./commands/completions").then(m => m.default) },
|
|
21
|
+
{ name: "__complete", load: () => import("./commands/complete").then(m => m.default) },
|
|
20
22
|
{ name: "config", load: () => import("./commands/config").then(m => m.default) },
|
|
21
23
|
{ name: "grep", load: () => import("./commands/grep").then(m => m.default) },
|
|
22
24
|
{ name: "grievances", load: () => import("./commands/grievances").then(m => m.default) },
|
package/src/cli.ts
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import { APP_NAME, MIN_BUN_VERSION, procmgr, VERSION } from "@oh-my-pi/pi-utils";
|
|
3
|
-
|
|
4
|
-
// Strip macOS malloc-stack-logging env vars before any subprocess is spawned.
|
|
5
|
-
// Otherwise every child bun process (subagents, plugin installs, ptree spawns,
|
|
6
|
-
// etc.) prints a `MallocStackLogging: can't turn off …` warning to stderr.
|
|
7
|
-
procmgr.scrubProcessEnv();
|
|
8
|
-
|
|
9
2
|
/**
|
|
10
3
|
* CLI entry point — registers all commands explicitly and delegates to the
|
|
11
4
|
* lightweight CLI runner from pi-utils.
|
|
12
5
|
*/
|
|
13
6
|
import { type CliConfig, run } from "@oh-my-pi/pi-utils/cli";
|
|
7
|
+
import { APP_NAME, MIN_BUN_VERSION, VERSION } from "@oh-my-pi/pi-utils/dirs";
|
|
14
8
|
import { commands, isSubcommand } from "./cli-commands";
|
|
15
9
|
|
|
16
10
|
if (Bun.semver.order(Bun.version, MIN_BUN_VERSION) < 0) {
|