maqcli 0.2.0

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.
Files changed (88) hide show
  1. package/README.md +223 -0
  2. package/dist/core/audit.d.ts +43 -0
  3. package/dist/core/audit.js +77 -0
  4. package/dist/core/board.d.ts +78 -0
  5. package/dist/core/board.js +256 -0
  6. package/dist/core/catalog.d.ts +50 -0
  7. package/dist/core/catalog.js +103 -0
  8. package/dist/core/command-catalog.d.ts +44 -0
  9. package/dist/core/command-catalog.js +86 -0
  10. package/dist/core/completion.d.ts +24 -0
  11. package/dist/core/completion.js +309 -0
  12. package/dist/core/complexity.d.ts +17 -0
  13. package/dist/core/complexity.js +87 -0
  14. package/dist/core/config-store.d.ts +33 -0
  15. package/dist/core/config-store.js +61 -0
  16. package/dist/core/connectivity.d.ts +34 -0
  17. package/dist/core/connectivity.js +49 -0
  18. package/dist/core/cost-tracker.d.ts +89 -0
  19. package/dist/core/cost-tracker.js +189 -0
  20. package/dist/core/cost.d.ts +35 -0
  21. package/dist/core/cost.js +89 -0
  22. package/dist/core/exec.d.ts +43 -0
  23. package/dist/core/exec.js +154 -0
  24. package/dist/core/flows.d.ts +36 -0
  25. package/dist/core/flows.js +96 -0
  26. package/dist/core/headroom.d.ts +36 -0
  27. package/dist/core/headroom.js +88 -0
  28. package/dist/core/help-topics.d.ts +26 -0
  29. package/dist/core/help-topics.js +294 -0
  30. package/dist/core/init-wizard.d.ts +26 -0
  31. package/dist/core/init-wizard.js +168 -0
  32. package/dist/core/interactive-registry.d.ts +50 -0
  33. package/dist/core/interactive-registry.js +86 -0
  34. package/dist/core/interactive.d.ts +48 -0
  35. package/dist/core/interactive.js +137 -0
  36. package/dist/core/logger.d.ts +16 -0
  37. package/dist/core/logger.js +46 -0
  38. package/dist/core/memory.d.ts +28 -0
  39. package/dist/core/memory.js +70 -0
  40. package/dist/core/metered.d.ts +9 -0
  41. package/dist/core/metered.js +16 -0
  42. package/dist/core/model.d.ts +74 -0
  43. package/dist/core/model.js +199 -0
  44. package/dist/core/pipeline.d.ts +33 -0
  45. package/dist/core/pipeline.js +223 -0
  46. package/dist/core/plugins.d.ts +21 -0
  47. package/dist/core/plugins.js +38 -0
  48. package/dist/core/probe.d.ts +48 -0
  49. package/dist/core/probe.js +156 -0
  50. package/dist/core/profiles.d.ts +42 -0
  51. package/dist/core/profiles.js +153 -0
  52. package/dist/core/providers.d.ts +84 -0
  53. package/dist/core/providers.js +275 -0
  54. package/dist/core/recall.d.ts +29 -0
  55. package/dist/core/recall.js +83 -0
  56. package/dist/core/registry.d.ts +41 -0
  57. package/dist/core/registry.js +162 -0
  58. package/dist/core/router.d.ts +33 -0
  59. package/dist/core/router.js +40 -0
  60. package/dist/core/sandbox.d.ts +78 -0
  61. package/dist/core/sandbox.js +268 -0
  62. package/dist/core/session.d.ts +105 -0
  63. package/dist/core/session.js +252 -0
  64. package/dist/core/skills.d.ts +56 -0
  65. package/dist/core/skills.js +289 -0
  66. package/dist/core/subagent.d.ts +40 -0
  67. package/dist/core/subagent.js +55 -0
  68. package/dist/core/supervisor.d.ts +37 -0
  69. package/dist/core/supervisor.js +40 -0
  70. package/dist/core/tools.d.ts +39 -0
  71. package/dist/core/tools.js +159 -0
  72. package/dist/core/types.d.ts +87 -0
  73. package/dist/core/types.js +10 -0
  74. package/dist/index.d.ts +11 -0
  75. package/dist/index.js +1032 -0
  76. package/dist/phases/execute.d.ts +39 -0
  77. package/dist/phases/execute.js +166 -0
  78. package/dist/phases/plan.d.ts +11 -0
  79. package/dist/phases/plan.js +118 -0
  80. package/dist/phases/scout.d.ts +10 -0
  81. package/dist/phases/scout.js +113 -0
  82. package/dist/phases/verify.d.ts +22 -0
  83. package/dist/phases/verify.js +81 -0
  84. package/dist/server/daemon.d.ts +50 -0
  85. package/dist/server/daemon.js +377 -0
  86. package/dist/server/relay-bridge.d.ts +44 -0
  87. package/dist/server/relay-bridge.js +175 -0
  88. package/package.json +39 -0
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Model catalog + cheapest-master resolver — the "$0 intelligence layer".
3
+ *
4
+ * The master's own thinking (Scout summaries, Plan candidates, Verify review)
5
+ * should cost as close to $0 as possible. This module answers "what is the
6
+ * cheapest capable master model available right now?" by inspecting the
7
+ * environment (provider API keys, a local Ollama, and — preferred — any
8
+ * already-authenticated worker CLI whose subscription the user already pays
9
+ * for). Heavy Worker executions stay BYO-key; only the light master loop is
10
+ * auto-optimized here.
11
+ *
12
+ * Ranking (best first) balances marginal cost against quality:
13
+ * 1. an authenticated worker CLI (reuse the user's existing subscription; $0 marginal)
14
+ * 2. a free-tier cloud key (Groq / Gemini Flash)
15
+ * 3. a local Ollama model ($0, uses local compute)
16
+ * 4. the cheapest paid key (gpt-4o-mini / claude-3-5-haiku)
17
+ * 5. the offline heuristic provider (always available, $0, deterministic)
18
+ */
19
+ import type { DetectedAgent } from "./types.js";
20
+ export type CostClass = "free-local" | "free-tier" | "byo-subscription" | "paid" | "offline";
21
+ export interface MasterOption {
22
+ /** Provider name for config (`provider`). */
23
+ provider: string;
24
+ /** Model name for config (`cheapModel`). For CLI it's `cli:<agent>`. */
25
+ model: string;
26
+ label: string;
27
+ costClass: CostClass;
28
+ /** USD per 1M input/output, 0 for free/local. */
29
+ pricePer1MIn: number;
30
+ pricePer1MOut: number;
31
+ available: boolean;
32
+ reason: string;
33
+ }
34
+ export interface CatalogEnv {
35
+ OPENAI_API_KEY?: string;
36
+ ANTHROPIC_API_KEY?: string;
37
+ GROQ_API_KEY?: string;
38
+ GEMINI_API_KEY?: string;
39
+ GOOGLE_API_KEY?: string;
40
+ OLLAMA_HOST?: string;
41
+ MAQ_PROVIDER_BASE_URL?: string;
42
+ }
43
+ export declare function resolveEnv(env?: NodeJS.ProcessEnv): CatalogEnv;
44
+ /**
45
+ * Build the ranked list of master options given the environment + detected
46
+ * agents. Only `available: true` options can actually be used now.
47
+ */
48
+ export declare function masterOptions(env?: CatalogEnv, agents?: DetectedAgent[]): MasterOption[];
49
+ /** The single cheapest available master option (never throws; heuristic is the floor). */
50
+ export declare function cheapestMaster(env?: CatalogEnv, agents?: DetectedAgent[]): MasterOption;
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Model catalog + cheapest-master resolver — the "$0 intelligence layer".
3
+ *
4
+ * The master's own thinking (Scout summaries, Plan candidates, Verify review)
5
+ * should cost as close to $0 as possible. This module answers "what is the
6
+ * cheapest capable master model available right now?" by inspecting the
7
+ * environment (provider API keys, a local Ollama, and — preferred — any
8
+ * already-authenticated worker CLI whose subscription the user already pays
9
+ * for). Heavy Worker executions stay BYO-key; only the light master loop is
10
+ * auto-optimized here.
11
+ *
12
+ * Ranking (best first) balances marginal cost against quality:
13
+ * 1. an authenticated worker CLI (reuse the user's existing subscription; $0 marginal)
14
+ * 2. a free-tier cloud key (Groq / Gemini Flash)
15
+ * 3. a local Ollama model ($0, uses local compute)
16
+ * 4. the cheapest paid key (gpt-4o-mini / claude-3-5-haiku)
17
+ * 5. the offline heuristic provider (always available, $0, deterministic)
18
+ */
19
+ import { detectAgents } from "./registry.js";
20
+ import { priceFor } from "./cost.js";
21
+ /** Preferred lightest master model per detected CLI agent. */
22
+ const CLI_MODEL_HINT = {
23
+ gemini: "cli:gemini",
24
+ "claude-code": "cli:claude-code",
25
+ codex: "cli:codex",
26
+ opencode: "cli:opencode",
27
+ "amazon-q": "cli:amazon-q",
28
+ aider: "cli:aider",
29
+ };
30
+ export function resolveEnv(env = process.env) {
31
+ return {
32
+ OPENAI_API_KEY: env.OPENAI_API_KEY,
33
+ ANTHROPIC_API_KEY: env.ANTHROPIC_API_KEY,
34
+ GROQ_API_KEY: env.GROQ_API_KEY,
35
+ GEMINI_API_KEY: env.GEMINI_API_KEY,
36
+ GOOGLE_API_KEY: env.GOOGLE_API_KEY,
37
+ OLLAMA_HOST: env.OLLAMA_HOST,
38
+ MAQ_PROVIDER_BASE_URL: env.MAQ_PROVIDER_BASE_URL,
39
+ };
40
+ }
41
+ /**
42
+ * Build the ranked list of master options given the environment + detected
43
+ * agents. Only `available: true` options can actually be used now.
44
+ */
45
+ export function masterOptions(env = resolveEnv(), agents = detectAgents()) {
46
+ const out = [];
47
+ // 1. Authenticated worker CLIs (reuse existing subscription; $0 marginal).
48
+ for (const a of agents) {
49
+ if (a.installed && a.authenticated && CLI_MODEL_HINT[a.name]) {
50
+ out.push({
51
+ provider: CLI_MODEL_HINT[a.name],
52
+ model: CLI_MODEL_HINT[a.name],
53
+ label: `${a.name} (headless CLI as master)`,
54
+ costClass: "byo-subscription",
55
+ pricePer1MIn: 0,
56
+ pricePer1MOut: 0,
57
+ available: true,
58
+ reason: "authenticated CLI reused for master thinking ($0 marginal)",
59
+ });
60
+ }
61
+ }
62
+ // 2. Free-tier cloud keys.
63
+ if (env.GROQ_API_KEY) {
64
+ out.push(opt("groq", "llama-3.3-70b-versatile", "Groq (free tier)", "free-tier", true, "GROQ_API_KEY present"));
65
+ }
66
+ if (env.GEMINI_API_KEY || env.GOOGLE_API_KEY) {
67
+ // Reached via an OpenAI-compatible/LiteLLM proxy; label reflects the free tier.
68
+ out.push(opt("openai-compatible", "gemini-2.0-flash", "Gemini Flash (free tier via proxy)", "free-tier", Boolean(env.MAQ_PROVIDER_BASE_URL), env.MAQ_PROVIDER_BASE_URL ? "Gemini key + proxy base URL present" : "set MAQ_PROVIDER_BASE_URL to a Gemini-compatible proxy"));
69
+ }
70
+ // 3. Local Ollama ($0, local compute).
71
+ out.push(opt("ollama", "llama3.1", "Ollama (local, $0)", "free-local", Boolean(env.OLLAMA_HOST), env.OLLAMA_HOST ? "OLLAMA_HOST set" : "start Ollama and/or set OLLAMA_HOST"));
72
+ // 4. Cheapest paid keys.
73
+ if (env.OPENAI_API_KEY) {
74
+ const p = priceFor("gpt-4o-mini");
75
+ out.push({ provider: "openai", model: "gpt-4o-mini", label: "OpenAI gpt-4o-mini", costClass: "paid", pricePer1MIn: p.in, pricePer1MOut: p.out, available: true, reason: "OPENAI_API_KEY present" });
76
+ }
77
+ if (env.ANTHROPIC_API_KEY) {
78
+ const p = priceFor("claude-3-5-haiku");
79
+ out.push({ provider: "anthropic", model: "claude-3-5-haiku-latest", label: "Anthropic Claude Haiku", costClass: "paid", pricePer1MIn: p.in, pricePer1MOut: p.out, available: true, reason: "ANTHROPIC_API_KEY present" });
80
+ }
81
+ // 5. Offline heuristic (always).
82
+ out.push({ provider: "heuristic", model: "heuristic-local", label: "Offline heuristic ($0, deterministic)", costClass: "offline", pricePer1MIn: 0, pricePer1MOut: 0, available: true, reason: "always available; no network or key" });
83
+ return out.sort((a, b) => rank(a) - rank(b));
84
+ }
85
+ function opt(provider, model, label, costClass, available, reason) {
86
+ return { provider, model, label, costClass, pricePer1MIn: 0, pricePer1MOut: 0, available, reason };
87
+ }
88
+ /** Lower rank = preferred. Available options always beat unavailable ones. */
89
+ function rank(o) {
90
+ const classRank = {
91
+ "byo-subscription": 0,
92
+ "free-tier": 1,
93
+ "free-local": 2,
94
+ paid: 3,
95
+ offline: 4,
96
+ };
97
+ return (o.available ? 0 : 100) + classRank[o.costClass];
98
+ }
99
+ /** The single cheapest available master option (never throws; heuristic is the floor). */
100
+ export function cheapestMaster(env = resolveEnv(), agents = detectAgents()) {
101
+ const avail = masterOptions(env, agents).filter((o) => o.available);
102
+ return avail[0];
103
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Command catalog — the machine-readable menu the app uses to "pitch" the CLI
3
+ * to a user: what commands exist, what each does, which args to prompt for, and
4
+ * whether an action is destructive (confirm first). Also carries a catalog of
5
+ * the AI worker CLIs' own commands/flags so the app can surface them.
6
+ *
7
+ * Non-Master edition: the app renders `maqCommands` as selectable actions and
8
+ * prompts for `args` / `needsInput`. Master edition: the app is a terminal and
9
+ * the user types freely; this catalog powers autocomplete.
10
+ */
11
+ export type ArgType = "string" | "enum" | "boolean" | "path";
12
+ export interface CommandArg {
13
+ name: string;
14
+ type: ArgType;
15
+ required?: boolean;
16
+ choices?: string[];
17
+ description: string;
18
+ }
19
+ export interface MaqCommand {
20
+ name: string;
21
+ category: "pipeline" | "session" | "model" | "agents" | "memory" | "system" | "control";
22
+ summary: string;
23
+ usage: string;
24
+ /** What free-text the app should collect before running (a task, a query, none). */
25
+ needsInput: "task" | "query" | "none";
26
+ args: CommandArg[];
27
+ destructive?: boolean;
28
+ }
29
+ export declare const maqCommands: MaqCommand[];
30
+ export interface AiCliEntry {
31
+ name: string;
32
+ bin: string;
33
+ /** Headless invocation MAQ uses; {task} is substituted. */
34
+ headless: string;
35
+ /** Notable interactive/slash commands the app can surface. */
36
+ commands: string[];
37
+ notes: string;
38
+ }
39
+ /** Catalog of AI worker CLIs' own commands/flags (verified 2026-07-01). */
40
+ export declare const aiCliCatalog: AiCliEntry[];
41
+ export declare function commandCatalog(): {
42
+ maq: MaqCommand[];
43
+ aiClis: AiCliEntry[];
44
+ };
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Command catalog — the machine-readable menu the app uses to "pitch" the CLI
3
+ * to a user: what commands exist, what each does, which args to prompt for, and
4
+ * whether an action is destructive (confirm first). Also carries a catalog of
5
+ * the AI worker CLIs' own commands/flags so the app can surface them.
6
+ *
7
+ * Non-Master edition: the app renders `maqCommands` as selectable actions and
8
+ * prompts for `args` / `needsInput`. Master edition: the app is a terminal and
9
+ * the user types freely; this catalog powers autocomplete.
10
+ */
11
+ export const maqCommands = [
12
+ { name: "run", category: "pipeline", summary: "Run a task through Scout→Plan→Execute→Verify.", usage: 'maq run "<task>" [--target t] [--provider p] [--model m] [--dry-run] [--audit]', needsInput: "task",
13
+ args: [
14
+ { name: "target", type: "enum", choices: ["auto", "claude-code", "codex", "gemini", "opencode", "aider", "amazon-q", "none"], description: "worker CLI (or none for raw)" },
15
+ { name: "provider", type: "string", description: "override model provider for this run" },
16
+ { name: "model", type: "string", description: "override tier model for this run" },
17
+ { name: "dry-run", type: "boolean", description: "plan without executing" },
18
+ { name: "audit", type: "boolean", description: "write hash-chained audit log" },
19
+ ] },
20
+ { name: "scout", category: "pipeline", summary: "Read-only recon; structured findings (0 tokens).", usage: 'maq scout "<task>"', needsInput: "task", args: [] },
21
+ { name: "plan", category: "pipeline", summary: "Verifier-gated candidate plan.", usage: 'maq plan "<task>"', needsInput: "task", args: [] },
22
+ { name: "verify", category: "pipeline", summary: "Run project tests / cross-model review.", usage: "maq verify [--cwd d]", needsInput: "none", args: [] },
23
+ { name: "swarm", category: "pipeline", summary: "Run several tasks across parallel workers, then join.", usage: 'maq swarm "<t1>" "<t2>" … [--target t] [--concurrency N]', needsInput: "none", args: [{ name: "concurrency", type: "string", description: "max parallel workers" }] },
24
+ { name: "interactive", category: "pipeline", summary: "Attach a steerable interactive worker (stdin steering).", usage: "maq interactive [-t agent]", needsInput: "task", args: [{ name: "target", type: "enum", choices: ["auto", "claude-code", "codex", "gemini"], description: "agent CLI" }] },
25
+ { name: "detect", category: "system", summary: "Scan for installed/authenticated worker CLIs.", usage: "maq detect", needsInput: "none", args: [] },
26
+ { name: "doctor", category: "system", summary: "One-shot health: provider, agents, connectivity, skills.", usage: "maq doctor", needsInput: "none", args: [] },
27
+ { name: "probe", category: "system", summary: "Connectivity tier probe (STUN/UDP + TCP + LAN).", usage: "maq probe", needsInput: "none", args: [] },
28
+ { name: "config", category: "system", summary: "Read/update configuration.", usage: "maq config [get|set|path|reset]", needsInput: "none", args: [] },
29
+ { name: "models", category: "model", summary: "Show/optimize the master model ($0 layer).", usage: "maq models [list|cheapest|auto]", needsInput: "none", args: [{ name: "sub", type: "enum", choices: ["", "list", "cheapest", "auto"], description: "subcommand" }] },
30
+ { name: "sessions", category: "session", summary: "List/inspect/control daemon sessions.", usage: "maq sessions [<id>] [pause|resume|cancel]", needsInput: "none", args: [] },
31
+ { name: "agents", category: "agents", summary: "Named agent profiles + tool restrictions.", usage: "maq agents [list|init|show <n>]", needsInput: "none", args: [] },
32
+ { name: "skills", category: "agents", summary: "Tier-aware skills/rules injected into planning.", usage: "maq skills [list|init|path] [--tier]", needsInput: "none", args: [] },
33
+ { name: "tools", category: "agents", summary: "Safe tool registry (read_file/list_dir/grep_text/…).", usage: "maq tools [<name>] [--args JSON]", needsInput: "none", args: [] },
34
+ { name: "subagent", category: "agents", summary: "Run an isolated sub-agent; returns a concise summary.", usage: 'maq subagent "<task>"', needsInput: "task", args: [] },
35
+ { name: "memory", category: "memory", summary: "Recall memory store (injected into planning).", usage: "maq memory [store|recall|list]", needsInput: "query", args: [] },
36
+ { name: "flow", category: "control", summary: "Scheduled agent sessions (run under the daemon).", usage: "maq flow [list|add|remove]", needsInput: "none", args: [] },
37
+ { name: "audit", category: "control", summary: "Verify a run's hash-chained audit log.", usage: "maq audit verify <run-dir>", needsInput: "none", args: [] },
38
+ ];
39
+ /** Catalog of AI worker CLIs' own commands/flags (verified 2026-07-01). */
40
+ export const aiCliCatalog = [
41
+ {
42
+ name: "claude-code",
43
+ bin: "claude",
44
+ headless: 'claude -p "{task}" --output-format json',
45
+ commands: ["-p/--print (headless)", "--output-format json|stream-json", "--json-schema", "/clear", "/compact [instructions]", "/model", "/review", "/agents", "/mcp", "/resume"],
46
+ notes: "Stable JSON stream (json / stream-json). Slash commands control session without a model call.",
47
+ },
48
+ {
49
+ name: "codex",
50
+ bin: "codex",
51
+ headless: 'codex exec --json "{task}"',
52
+ commands: ["exec (headless)", "--json", "--output-schema", "app-server (remote TUI)"],
53
+ notes: "Use exec --json for scripted runs. No fully stable event stream historically — MAQ normalizes stdout as fallback.",
54
+ },
55
+ {
56
+ name: "gemini",
57
+ bin: "gemini",
58
+ headless: 'gemini -p "{task}"',
59
+ commands: ["-p (prompt)", "/tools", "/mcp", "/memory", "/stats", "custom TOML commands", "checkpointing", "sandbox (docker/podman)"],
60
+ notes: "5 subcommand groups, 30+ flags, 25+ REPL slash commands, Skills framework, GEMINI.md.",
61
+ },
62
+ {
63
+ name: "opencode",
64
+ bin: "opencode",
65
+ headless: 'opencode run "{task}"',
66
+ commands: ["run", "serve"],
67
+ notes: "Open-source multi-provider agent CLI.",
68
+ },
69
+ {
70
+ name: "aider",
71
+ bin: "aider",
72
+ headless: 'aider --message "{task}"',
73
+ commands: ["--message", "--yes", "/add", "/drop", "/commit", "/diff"],
74
+ notes: "Pair-programming CLI; git-native.",
75
+ },
76
+ {
77
+ name: "amazon-q",
78
+ bin: "q",
79
+ headless: 'q chat "{task}"',
80
+ commands: ["chat", "/tools", "/context"],
81
+ notes: "Amazon Q Developer CLI.",
82
+ },
83
+ ];
84
+ export function commandCatalog() {
85
+ return { maq: maqCommands, aiClis: aiCliCatalog };
86
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @module completion
3
+ *
4
+ * Shell completion generator for the maq CLI.
5
+ * Produces completion scripts for bash, zsh, fish, and PowerShell.
6
+ * Also provides runtime shell detection.
7
+ *
8
+ * Zero npm dependencies. ESM module.
9
+ */
10
+ /** Supported shell types for completion generation. */
11
+ export type Shell = "bash" | "zsh" | "fish" | "powershell";
12
+ /**
13
+ * Generates a shell completion script for the given shell.
14
+ * The returned string can be written to a file or eval'd directly.
15
+ */
16
+ export declare function generateCompletion(shell: Shell): string;
17
+ /**
18
+ * Attempts to detect the current shell from environment variables.
19
+ * Returns `null` if the shell cannot be determined.
20
+ *
21
+ * On Unix: reads `$SHELL` and matches the basename.
22
+ * On Windows: checks for `$PSModulePath` (PowerShell indicator).
23
+ */
24
+ export declare function detectShell(): Shell | null;
@@ -0,0 +1,309 @@
1
+ /**
2
+ * @module completion
3
+ *
4
+ * Shell completion generator for the maq CLI.
5
+ * Produces completion scripts for bash, zsh, fish, and PowerShell.
6
+ * Also provides runtime shell detection.
7
+ *
8
+ * Zero npm dependencies. ESM module.
9
+ */
10
+ // ── Command Definitions ─────────────────────────────────────────────
11
+ const TOP_LEVEL_COMMANDS = [
12
+ "detect",
13
+ "scout",
14
+ "plan",
15
+ "run",
16
+ "verify",
17
+ "serve",
18
+ "sessions",
19
+ "models",
20
+ "probe",
21
+ "skills",
22
+ "subagent",
23
+ "tools",
24
+ "doctor",
25
+ "agents",
26
+ "memory",
27
+ "swarm",
28
+ "interactive",
29
+ "flow",
30
+ "audit",
31
+ "config",
32
+ "board",
33
+ "init",
34
+ "logs",
35
+ "stop",
36
+ "cost",
37
+ "help",
38
+ "version",
39
+ ];
40
+ const SUBCOMMANDS = {
41
+ config: ["get", "set", "path", "reset"],
42
+ models: ["list", "cheapest", "auto"],
43
+ skills: ["init", "path"],
44
+ agents: ["list", "init", "show"],
45
+ memory: ["store", "recall", "list"],
46
+ flow: ["list", "add", "remove"],
47
+ board: ["show", "list", "tail"],
48
+ cost: ["report", "reset"],
49
+ };
50
+ const RUN_FLAGS = [
51
+ "--target",
52
+ "--dry-run",
53
+ "--provider",
54
+ "--model",
55
+ "--audit",
56
+ "--json",
57
+ "--cwd",
58
+ ];
59
+ // ── Public API ──────────────────────────────────────────────────────
60
+ /**
61
+ * Generates a shell completion script for the given shell.
62
+ * The returned string can be written to a file or eval'd directly.
63
+ */
64
+ export function generateCompletion(shell) {
65
+ switch (shell) {
66
+ case "bash":
67
+ return generateBash();
68
+ case "zsh":
69
+ return generateZsh();
70
+ case "fish":
71
+ return generateFish();
72
+ case "powershell":
73
+ return generatePowerShell();
74
+ }
75
+ }
76
+ /**
77
+ * Attempts to detect the current shell from environment variables.
78
+ * Returns `null` if the shell cannot be determined.
79
+ *
80
+ * On Unix: reads `$SHELL` and matches the basename.
81
+ * On Windows: checks for `$PSModulePath` (PowerShell indicator).
82
+ */
83
+ export function detectShell() {
84
+ const env = typeof process !== "undefined" ? process.env : {};
85
+ // Windows: PowerShell sets PSModulePath
86
+ if (env.PSModulePath) {
87
+ return "powershell";
88
+ }
89
+ const shellPath = env.SHELL;
90
+ if (!shellPath) {
91
+ return null;
92
+ }
93
+ const basename = shellPath.split("/").pop() ?? "";
94
+ if (basename === "bash" || basename.startsWith("bash")) {
95
+ return "bash";
96
+ }
97
+ if (basename === "zsh" || basename.startsWith("zsh")) {
98
+ return "zsh";
99
+ }
100
+ if (basename === "fish" || basename.startsWith("fish")) {
101
+ return "fish";
102
+ }
103
+ return null;
104
+ }
105
+ // ── Generators ──────────────────────────────────────────────────────
106
+ function generateBash() {
107
+ const cmds = TOP_LEVEL_COMMANDS.join(" ");
108
+ const flags = RUN_FLAGS.join(" ");
109
+ const subcases = Object.entries(SUBCOMMANDS)
110
+ .map(([cmd, subs]) => ` ${cmd}) COMPREPLY=( $(compgen -W "${subs.join(" ")}" -- "$cur") ) ;;`)
111
+ .join("\n");
112
+ return `# maq bash completion — generated by maq completion bash
113
+ # Add to ~/.bashrc: eval "$(maq completion bash)"
114
+
115
+ _maq_completions() {
116
+ local cur prev words cword
117
+ _init_completion || return
118
+
119
+ local commands="${cmds}"
120
+ local run_flags="${flags}"
121
+
122
+ if [[ $cword -eq 1 ]]; then
123
+ COMPREPLY=( $(compgen -W "$commands" -- "$cur") )
124
+ return
125
+ fi
126
+
127
+ local cmd="\${words[1]}"
128
+
129
+ # Subcommand completion
130
+ case "$cmd" in
131
+ ${subcases}
132
+ esac
133
+
134
+ # Flag completion for run
135
+ if [[ "$cmd" == "run" && "$cur" == -* ]]; then
136
+ COMPREPLY=( $(compgen -W "$run_flags" -- "$cur") )
137
+ return
138
+ fi
139
+ }
140
+
141
+ complete -F _maq_completions maq
142
+ `;
143
+ }
144
+ function generateZsh() {
145
+ const cmds = TOP_LEVEL_COMMANDS.map((c) => `'${c}:${descriptionFor(c)}'`).join("\n ");
146
+ const subcmdFunctions = Object.entries(SUBCOMMANDS)
147
+ .map(([cmd, subs]) => {
148
+ const subList = subs.map((s) => `'${s}'`).join(" ");
149
+ return ` ${cmd})
150
+ _values 'subcommand' ${subList}
151
+ ;;`;
152
+ })
153
+ .join("\n ");
154
+ const flags = RUN_FLAGS.map((f) => `'${f}[${flagDescriptionFor(f)}]'`).join("\n ");
155
+ return `#compdef maq
156
+ # maq zsh completion — generated by maq completion zsh
157
+ # Add to ~/.zshrc: eval "$(maq completion zsh)"
158
+
159
+ _maq() {
160
+ local -a commands
161
+ commands=(
162
+ ${cmds}
163
+ )
164
+
165
+ _arguments -C \\
166
+ '1:command:->cmd' \\
167
+ '*::arg:->args'
168
+
169
+ case $state in
170
+ cmd)
171
+ _describe 'maq command' commands
172
+ ;;
173
+ args)
174
+ local cmd=\${words[1]}
175
+ case $cmd in
176
+ ${subcmdFunctions}
177
+ run)
178
+ _arguments \\
179
+ ${flags}
180
+ ;;
181
+ esac
182
+ ;;
183
+ esac
184
+ }
185
+
186
+ compdef _maq maq
187
+ `;
188
+ }
189
+ function generateFish() {
190
+ const lines = [
191
+ "# maq fish completion — generated by maq completion fish",
192
+ "# Save to ~/.config/fish/completions/maq.fish",
193
+ "",
194
+ "# Disable file completions by default",
195
+ "complete -c maq -f",
196
+ "",
197
+ "# Top-level commands",
198
+ ];
199
+ for (const cmd of TOP_LEVEL_COMMANDS) {
200
+ lines.push(`complete -c maq -n '__fish_use_subcommand' -a '${cmd}' -d '${descriptionFor(cmd)}'`);
201
+ }
202
+ lines.push("");
203
+ lines.push("# Subcommands");
204
+ for (const [cmd, subs] of Object.entries(SUBCOMMANDS)) {
205
+ for (const sub of subs) {
206
+ lines.push(`complete -c maq -n '__fish_seen_subcommand_from ${cmd}' -a '${sub}'`);
207
+ }
208
+ }
209
+ lines.push("");
210
+ lines.push("# Run flags");
211
+ for (const flag of RUN_FLAGS) {
212
+ lines.push(`complete -c maq -n '__fish_seen_subcommand_from run' -l '${flag.replace(/^--/, "")}' -d '${flagDescriptionFor(flag)}'`);
213
+ }
214
+ lines.push("");
215
+ return lines.join("\n");
216
+ }
217
+ function generatePowerShell() {
218
+ const cmdList = TOP_LEVEL_COMMANDS.map((c) => `'${c}'`).join(", ");
219
+ const flagList = RUN_FLAGS.map((f) => `'${f}'`).join(", ");
220
+ const subcmdCases = Object.entries(SUBCOMMANDS)
221
+ .map(([cmd, subs]) => {
222
+ const subList = subs.map((s) => `'${s}'`).join(", ");
223
+ return ` '${cmd}' {
224
+ @(${subList}) | Where-Object { $_ -like "$wordToComplete*" } |
225
+ ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
226
+ }`;
227
+ })
228
+ .join("\n");
229
+ return `# maq PowerShell completion — generated by maq completion powershell
230
+ # Add to $PROFILE: maq completion powershell | Invoke-Expression
231
+
232
+ Register-ArgumentCompleter -Native -CommandName 'maq' -ScriptBlock {
233
+ param($wordToComplete, $commandAst, $cursorPosition)
234
+
235
+ $commands = @(${cmdList})
236
+ $runFlags = @(${flagList})
237
+
238
+ $tokens = $commandAst.ToString().Split(' ', [System.StringSplitOptions]::RemoveEmptyEntries)
239
+ $tokenCount = $tokens.Count
240
+
241
+ # Complete top-level command
242
+ if ($tokenCount -le 1 -or ($tokenCount -eq 2 -and $wordToComplete)) {
243
+ $commands | Where-Object { $_ -like "$wordToComplete*" } |
244
+ ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
245
+ return
246
+ }
247
+
248
+ $cmd = $tokens[1]
249
+
250
+ # Subcommand completion
251
+ switch ($cmd) {
252
+ ${subcmdCases}
253
+ 'run' {
254
+ if ($wordToComplete.StartsWith('-')) {
255
+ $runFlags | Where-Object { $_ -like "$wordToComplete*" } |
256
+ ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
257
+ }
258
+ }
259
+ }
260
+ }
261
+ `;
262
+ }
263
+ // ── Helpers ─────────────────────────────────────────────────────────
264
+ /** Returns a short description for a top-level command. */
265
+ function descriptionFor(cmd) {
266
+ const descriptions = {
267
+ detect: "Detect project type and environment",
268
+ scout: "Scan repository and gather context",
269
+ plan: "Generate an execution plan",
270
+ run: "Execute a task through the pipeline",
271
+ verify: "Verify the last execution result",
272
+ serve: "Start the maq API server",
273
+ sessions: "List and manage sessions",
274
+ models: "List and configure models",
275
+ probe: "Probe model capabilities",
276
+ skills: "Manage reusable skills",
277
+ subagent: "Spawn and manage sub-agents",
278
+ tools: "List available tools",
279
+ doctor: "Diagnose installation issues",
280
+ agents: "Manage agent configurations",
281
+ memory: "Store and recall agent memory",
282
+ swarm: "Orchestrate multi-agent swarms",
283
+ interactive: "Start interactive REPL mode",
284
+ flow: "Manage multi-step workflows",
285
+ audit: "View and replay audit logs",
286
+ config: "Get and set configuration",
287
+ board: "Inspect the shared board",
288
+ init: "Initialize a new .maq directory",
289
+ logs: "View session logs",
290
+ stop: "Stop running agents or server",
291
+ cost: "View and reset cost tracking",
292
+ help: "Show help for a topic",
293
+ version: "Print version information",
294
+ };
295
+ return descriptions[cmd] ?? cmd;
296
+ }
297
+ /** Returns a short description for a run flag. */
298
+ function flagDescriptionFor(flag) {
299
+ const descriptions = {
300
+ "--target": "Target file or directory",
301
+ "--dry-run": "Preview without executing",
302
+ "--provider": "LLM provider to use",
303
+ "--model": "Specific model to use",
304
+ "--audit": "Enable audit logging",
305
+ "--json": "Output as JSON",
306
+ "--cwd": "Working directory",
307
+ };
308
+ return descriptions[flag] ?? flag;
309
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Task complexity classifier (deterministic, zero-token).
3
+ *
4
+ * Used to gate the cost/quality dial: trivial tasks skip the Scout+Plan phases
5
+ * and go straight to Execute; complex tasks get the full pipeline. This is the
6
+ * lever that keeps multi-agent overhead (which can reach ~15x single-turn
7
+ * tokens) from being paid on work that does not need it.
8
+ */
9
+ import type { Complexity } from "./types.js";
10
+ export interface ComplexityResult {
11
+ complexity: Complexity;
12
+ score: number;
13
+ reasons: string[];
14
+ }
15
+ export declare function classifyComplexity(task: string, fileHints?: string[]): ComplexityResult;
16
+ /** Whether the Scout+Plan pre-flight phases should run for this complexity. */
17
+ export declare function shouldRunPreflight(complexity: Complexity): boolean;