@phamvuhoang/otto-core 0.1.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 (103) hide show
  1. package/README.md +53 -0
  2. package/dist/branch.d.ts +61 -0
  3. package/dist/branch.d.ts.map +1 -0
  4. package/dist/branch.js +215 -0
  5. package/dist/branch.js.map +1 -0
  6. package/dist/cli-help.d.ts +68 -0
  7. package/dist/cli-help.d.ts.map +1 -0
  8. package/dist/cli-help.js +365 -0
  9. package/dist/cli-help.js.map +1 -0
  10. package/dist/detach.d.ts +36 -0
  11. package/dist/detach.d.ts.map +1 -0
  12. package/dist/detach.js +52 -0
  13. package/dist/detach.js.map +1 -0
  14. package/dist/gh-main.d.ts +5 -0
  15. package/dist/gh-main.d.ts.map +1 -0
  16. package/dist/gh-main.js +16 -0
  17. package/dist/gh-main.js.map +1 -0
  18. package/dist/git.d.ts +14 -0
  19. package/dist/git.d.ts.map +1 -0
  20. package/dist/git.js +50 -0
  21. package/dist/git.js.map +1 -0
  22. package/dist/index.d.ts +8 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +8 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/keepalive.d.ts +24 -0
  27. package/dist/keepalive.d.ts.map +1 -0
  28. package/dist/keepalive.js +138 -0
  29. package/dist/keepalive.js.map +1 -0
  30. package/dist/loop.d.ts +42 -0
  31. package/dist/loop.d.ts.map +1 -0
  32. package/dist/loop.js +238 -0
  33. package/dist/loop.js.map +1 -0
  34. package/dist/main.d.ts +5 -0
  35. package/dist/main.d.ts.map +1 -0
  36. package/dist/main.js +16 -0
  37. package/dist/main.js.map +1 -0
  38. package/dist/notify.d.ts +28 -0
  39. package/dist/notify.d.ts.map +1 -0
  40. package/dist/notify.js +119 -0
  41. package/dist/notify.js.map +1 -0
  42. package/dist/pacing.d.ts +8 -0
  43. package/dist/pacing.d.ts.map +1 -0
  44. package/dist/pacing.js +33 -0
  45. package/dist/pacing.js.map +1 -0
  46. package/dist/panel.d.ts +24 -0
  47. package/dist/panel.d.ts.map +1 -0
  48. package/dist/panel.js +202 -0
  49. package/dist/panel.js.map +1 -0
  50. package/dist/rate-limit.d.ts +16 -0
  51. package/dist/rate-limit.d.ts.map +1 -0
  52. package/dist/rate-limit.js +35 -0
  53. package/dist/rate-limit.js.map +1 -0
  54. package/dist/render.d.ts +8 -0
  55. package/dist/render.d.ts.map +1 -0
  56. package/dist/render.js +130 -0
  57. package/dist/render.js.map +1 -0
  58. package/dist/retry.d.ts +17 -0
  59. package/dist/retry.d.ts.map +1 -0
  60. package/dist/retry.js +34 -0
  61. package/dist/retry.js.map +1 -0
  62. package/dist/run-bin.d.ts +35 -0
  63. package/dist/run-bin.d.ts.map +1 -0
  64. package/dist/run-bin.js +241 -0
  65. package/dist/run-bin.js.map +1 -0
  66. package/dist/runner.d.ts +55 -0
  67. package/dist/runner.d.ts.map +1 -0
  68. package/dist/runner.js +297 -0
  69. package/dist/runner.js.map +1 -0
  70. package/dist/stage-exec.d.ts +16 -0
  71. package/dist/stage-exec.d.ts.map +1 -0
  72. package/dist/stage-exec.js +35 -0
  73. package/dist/stage-exec.js.map +1 -0
  74. package/dist/stages.d.ts +38 -0
  75. package/dist/stages.d.ts.map +1 -0
  76. package/dist/stages.js +38 -0
  77. package/dist/stages.js.map +1 -0
  78. package/dist/state.d.ts +25 -0
  79. package/dist/state.d.ts.map +1 -0
  80. package/dist/state.js +30 -0
  81. package/dist/state.js.map +1 -0
  82. package/dist/stream-render.d.ts +68 -0
  83. package/dist/stream-render.d.ts.map +1 -0
  84. package/dist/stream-render.js +162 -0
  85. package/dist/stream-render.js.map +1 -0
  86. package/dist/watch.d.ts +22 -0
  87. package/dist/watch.d.ts.map +1 -0
  88. package/dist/watch.js +93 -0
  89. package/dist/watch.js.map +1 -0
  90. package/package.json +67 -0
  91. package/templates/afk.md +21 -0
  92. package/templates/apply-review.md +71 -0
  93. package/templates/ghafk-issue.md +29 -0
  94. package/templates/ghafk.md +29 -0
  95. package/templates/ghprompt-workflow.md +83 -0
  96. package/templates/ghprompt.md +39 -0
  97. package/templates/prompt.md +97 -0
  98. package/templates/review-lens.md +41 -0
  99. package/templates/review-synth.md +29 -0
  100. package/templates/review-verify.md +52 -0
  101. package/templates/review.md +62 -0
  102. package/templates/superpowers.md +70 -0
  103. package/templates/verify.md +74 -0
package/README.md ADDED
@@ -0,0 +1,53 @@
1
+ # @phamvuhoang/otto-core
2
+
3
+ Library half of **[Otto](https://github.com/phamvuhoang/otto)** — a harness that drives the
4
+ [Claude Code](https://docs.anthropic.com/claude/docs/claude-code) CLI against a target
5
+ repository in an iterating implementer → reviewer loop, running directly on the host OS.
6
+
7
+ This package is the engine: the iteration loop driver, the runner + NDJSON stream
8
+ renderer, the prompt-template renderer, and the stage registry. The user-facing CLI lives in
9
+ **[`@phamvuhoang/otto`](https://www.npmjs.com/package/@phamvuhoang/otto)** (`otto-afk` / `otto-ghafk`).
10
+
11
+ > **Security:** Otto runs Claude with `--permission-mode bypassPermissions`. Point it
12
+ > only at repositories and prompts you trust. See the repo's
13
+ > [SECURITY.md](https://github.com/phamvuhoang/otto/blob/main/SECURITY.md).
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ npm i @phamvuhoang/otto-core
19
+ ```
20
+
21
+ ## Use
22
+
23
+ ```ts
24
+ import {
25
+ runAfk,
26
+ runGhAfk,
27
+ runLoop,
28
+ STAGES,
29
+ renderTemplate,
30
+ } from "@phamvuhoang/otto-core";
31
+
32
+ // Drive the plan/PRD loop from argv (same entry the otto-afk bin uses):
33
+ await runAfk(["<plan-and-prd>", "5"]);
34
+ ```
35
+
36
+ Public surface: `runAfk`, `runGhAfk`, `runLoop`, `STAGES`, `Stage`, `renderTemplate`,
37
+ `runStage`. Subpath exports: `./loop`, `./runner`, `./stages`.
38
+
39
+ `runStage` spawns `claude` directly on the host with `cwd` set to the workspace directory.
40
+ By default (`OTTO_RUNNER=sandbox`) it writes a transient `--settings` JSON that enables
41
+ the native OS sandbox, confining writes to the workspace. Set `OTTO_RUNNER=host` to run
42
+ unsandboxed. Credentials (`~/.claude`, `~/.config/gh`) are read natively — no bind-mounts
43
+ required. The `templates/` directory (prompt playbooks) ships in the tarball.
44
+
45
+ ## Docs
46
+
47
+ Full usage, setup, environment variables, and architecture are in the
48
+ **[main README](https://github.com/phamvuhoang/otto#readme)** and
49
+ **[docs/ARCHITECTURE.md](https://github.com/phamvuhoang/otto/blob/main/docs/ARCHITECTURE.md)**.
50
+
51
+ ## License
52
+
53
+ [MIT](https://github.com/phamvuhoang/otto/blob/main/LICENSE) © Henry Pham.
@@ -0,0 +1,61 @@
1
+ export type BranchStrategy = "current" | "branch" | "worktree";
2
+ export type BranchConfig = {
3
+ branchStrategy?: BranchStrategy;
4
+ branchPrefix?: string;
5
+ };
6
+ export type ResolvedBranch = {
7
+ strategy: BranchStrategy;
8
+ branchName: string | null;
9
+ effectiveWorkspaceDir: string;
10
+ worktreePath?: string;
11
+ summaryLine: string;
12
+ };
13
+ export type BranchPromptResult = {
14
+ strategy: BranchStrategy;
15
+ remember: boolean;
16
+ };
17
+ export type ResolveBranchOptions = {
18
+ workspaceDir: string;
19
+ inputs: string;
20
+ isTTY: boolean;
21
+ flagStrategy?: BranchStrategy;
22
+ flagPrefix?: string;
23
+ /** Injectable for tests; defaults to a readline prompt. Only called when isTTY && unresolved. */
24
+ prompt?: () => Promise<BranchPromptResult>;
25
+ /** Injectable clock for the timestamp slug (test seam). */
26
+ now?: () => string;
27
+ };
28
+ /**
29
+ * Derive a branch slug from an inputs string. Uses the basename (sans extension)
30
+ * of the first whitespace-separated token, lowercased, with non-alphanumerics
31
+ * collapsed to single dashes and capped at 40 chars. "" when there is nothing usable.
32
+ */
33
+ export declare function slugify(inputs: string): string;
34
+ /** Read .otto/config.json. Absent or malformed → {} (never throws). */
35
+ export declare function readBranchConfig(workspaceDir: string): BranchConfig;
36
+ /** Merge `patch` into .otto/config.json, preserving unknown keys. Creates .otto/ if needed. */
37
+ export declare function writeBranchConfig(workspaceDir: string, patch: BranchConfig): void;
38
+ /**
39
+ * Resolve the branch strategy once at startup and perform its one-time git side
40
+ * effect. Precedence: flagStrategy → .otto/config.json → TTY prompt → "current".
41
+ * Returns the effective workspace dir the loop should run in (the worktree path
42
+ * in worktree mode, else the original workspaceDir).
43
+ */
44
+ export declare function resolveBranch(opts: ResolveBranchOptions): Promise<ResolvedBranch>;
45
+ /**
46
+ * Ensure `.otto-tmp/` is gitignored in the workspace. No-op outside a git repo
47
+ * or when a `.otto-tmp` entry already exists. Creates .gitignore if absent.
48
+ * Never ignores `.otto/` (LEARNINGS.md + config.json are durable, git-tracked
49
+ * memory).
50
+ *
51
+ * Idempotency is checked by scanning .gitignore text — NOT `git check-ignore`,
52
+ * which only matches a trailing-slash dir pattern once the dir exists on disk.
53
+ */
54
+ export declare function ensureTmpIgnored(workspaceDir: string): void;
55
+ /**
56
+ * Returns a warning string if `strategy` keeps work in the current checkout AND
57
+ * the tree has uncommitted tracked changes (which disables the review panel's
58
+ * read-only reset enforcement). null when there is nothing to warn about.
59
+ */
60
+ export declare function dirtyTreeWarning(workspaceDir: string, strategy: BranchStrategy): string | null;
61
+ //# sourceMappingURL=branch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"branch.d.ts","sourceRoot":"","sources":["../src/branch.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE/D,MAAM,MAAM,YAAY,GAAG;IACzB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,cAAc,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,cAAc,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iGAAiG;IACjG,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC3C,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB,CAAC;AAKF;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAU9C;AAED,uEAAuE;AACvE,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,YAAY,CAmBnE;AAED,+FAA+F;AAC/F,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,YAAY,GAClB,IAAI,CAgBN;AA0CD;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,cAAc,CAAC,CAmFzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAgB3D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,cAAc,GACvB,MAAM,GAAG,IAAI,CAKf"}
package/dist/branch.js ADDED
@@ -0,0 +1,215 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { appendFileSync, mkdirSync, readFileSync, writeFileSync, } from "node:fs";
3
+ import { basename, join } from "node:path";
4
+ import { git, hasUncommittedTrackedChanges, isGitRepo, refExists, } from "./git.js";
5
+ const DEFAULT_PREFIX = "otto/";
6
+ const CONFIG_REL = join(".otto", "config.json");
7
+ /**
8
+ * Derive a branch slug from an inputs string. Uses the basename (sans extension)
9
+ * of the first whitespace-separated token, lowercased, with non-alphanumerics
10
+ * collapsed to single dashes and capped at 40 chars. "" when there is nothing usable.
11
+ */
12
+ export function slugify(inputs) {
13
+ const first = inputs.trim().split(/\s+/)[0] ?? "";
14
+ if (!first)
15
+ return "";
16
+ const baseName = basename(first).replace(/\.[^.]+$/, "");
17
+ return baseName
18
+ .toLowerCase()
19
+ .replace(/[^a-z0-9]+/g, "-")
20
+ .replace(/^-+|-+$/g, "")
21
+ .slice(0, 40)
22
+ .replace(/-+$/g, "");
23
+ }
24
+ /** Read .otto/config.json. Absent or malformed → {} (never throws). */
25
+ export function readBranchConfig(workspaceDir) {
26
+ try {
27
+ const raw = JSON.parse(readFileSync(join(workspaceDir, CONFIG_REL), "utf8"));
28
+ const out = {};
29
+ if (raw.branchStrategy === "current" ||
30
+ raw.branchStrategy === "branch" ||
31
+ raw.branchStrategy === "worktree") {
32
+ out.branchStrategy = raw.branchStrategy;
33
+ }
34
+ if (typeof raw.branchPrefix === "string")
35
+ out.branchPrefix = raw.branchPrefix;
36
+ return out;
37
+ }
38
+ catch {
39
+ return {};
40
+ }
41
+ }
42
+ /** Merge `patch` into .otto/config.json, preserving unknown keys. Creates .otto/ if needed. */
43
+ export function writeBranchConfig(workspaceDir, patch) {
44
+ const path = join(workspaceDir, CONFIG_REL);
45
+ let existing = {};
46
+ try {
47
+ existing = JSON.parse(readFileSync(path, "utf8"));
48
+ }
49
+ catch {
50
+ existing = {};
51
+ }
52
+ mkdirSync(join(workspaceDir, ".otto"), { recursive: true });
53
+ writeFileSync(path, JSON.stringify({ ...existing, ...patch }, null, 2) + "\n");
54
+ }
55
+ /** Default readline prompt (only used in a TTY). */
56
+ async function defaultPrompt() {
57
+ const { createInterface } = await import("node:readline/promises");
58
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
59
+ try {
60
+ const ans = (await rl.question("Branch strategy [current/branch/worktree] (current): "))
61
+ .trim()
62
+ .toLowerCase();
63
+ const strategy = ans === "branch" || ans === "worktree" ? ans : "current";
64
+ let remember = false;
65
+ if (strategy !== "current") {
66
+ const r = (await rl.question("Remember for this repo? [y/N]: "))
67
+ .trim()
68
+ .toLowerCase();
69
+ remember = r === "y" || r === "yes";
70
+ }
71
+ return { strategy, remember };
72
+ }
73
+ finally {
74
+ rl.close();
75
+ }
76
+ }
77
+ function defaultNow() {
78
+ const d = new Date();
79
+ const p = (x) => String(x).padStart(2, "0");
80
+ return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}`;
81
+ }
82
+ /** Append -2, -3, … until the branch name is free. */
83
+ function uniqueBranchName(workspaceDir, name) {
84
+ if (!refExists(workspaceDir, name))
85
+ return name;
86
+ for (let n = 2;; n++) {
87
+ const candidate = `${name}-${n}`;
88
+ if (!refExists(workspaceDir, candidate))
89
+ return candidate;
90
+ }
91
+ }
92
+ /**
93
+ * Resolve the branch strategy once at startup and perform its one-time git side
94
+ * effect. Precedence: flagStrategy → .otto/config.json → TTY prompt → "current".
95
+ * Returns the effective workspace dir the loop should run in (the worktree path
96
+ * in worktree mode, else the original workspaceDir).
97
+ */
98
+ export async function resolveBranch(opts) {
99
+ const { workspaceDir, inputs, isTTY } = opts;
100
+ const now = opts.now ?? defaultNow;
101
+ const config = readBranchConfig(workspaceDir);
102
+ const prefix = opts.flagPrefix ?? config.branchPrefix ?? DEFAULT_PREFIX;
103
+ let strategy;
104
+ if (opts.flagStrategy) {
105
+ strategy = opts.flagStrategy;
106
+ }
107
+ else if (config.branchStrategy) {
108
+ strategy = config.branchStrategy;
109
+ }
110
+ else if (isTTY) {
111
+ const res = await (opts.prompt ?? defaultPrompt)();
112
+ strategy = res.strategy;
113
+ if (res.remember && strategy !== "current") {
114
+ writeBranchConfig(workspaceDir, {
115
+ branchStrategy: strategy,
116
+ branchPrefix: prefix,
117
+ });
118
+ }
119
+ }
120
+ else {
121
+ strategy = "current";
122
+ }
123
+ if (strategy === "current") {
124
+ return {
125
+ strategy,
126
+ branchName: null,
127
+ effectiveWorkspaceDir: workspaceDir,
128
+ summaryLine: "branch strategy: current (committing on the current branch)",
129
+ };
130
+ }
131
+ if (!isGitRepo(workspaceDir)) {
132
+ throw new Error(`branch strategy "${strategy}" requires a git repo, but ${workspaceDir} is not a git work tree`);
133
+ }
134
+ const slug = slugify(inputs) || now();
135
+ const branchName = uniqueBranchName(workspaceDir, prefix + slug);
136
+ if (strategy === "branch") {
137
+ const current = git(["branch", "--show-current"], workspaceDir);
138
+ if (current === branchName) {
139
+ return {
140
+ strategy,
141
+ branchName,
142
+ effectiveWorkspaceDir: workspaceDir,
143
+ summaryLine: `branch strategy: branch (already on ${branchName})`,
144
+ };
145
+ }
146
+ execFileSync("git", ["switch", "-c", branchName], {
147
+ cwd: workspaceDir,
148
+ stdio: "ignore",
149
+ });
150
+ return {
151
+ strategy,
152
+ branchName,
153
+ effectiveWorkspaceDir: workspaceDir,
154
+ summaryLine: `branch strategy: branch (created + switched to ${branchName})`,
155
+ };
156
+ }
157
+ // worktree
158
+ const worktreePath = join(workspaceDir, ".otto-tmp", "worktrees", slug);
159
+ mkdirSync(join(workspaceDir, ".otto-tmp", "worktrees"), { recursive: true });
160
+ execFileSync("git", ["worktree", "add", "-b", branchName, worktreePath, "HEAD"], { cwd: workspaceDir, stdio: "ignore" });
161
+ const dirtyNote = hasUncommittedTrackedChanges(workspaceDir)
162
+ ? " (uncommitted changes left in the main checkout)"
163
+ : "";
164
+ return {
165
+ strategy,
166
+ branchName,
167
+ effectiveWorkspaceDir: worktreePath,
168
+ worktreePath,
169
+ summaryLine: `branch strategy: worktree (${branchName} at ${worktreePath})${dirtyNote}`,
170
+ };
171
+ }
172
+ /**
173
+ * Ensure `.otto-tmp/` is gitignored in the workspace. No-op outside a git repo
174
+ * or when a `.otto-tmp` entry already exists. Creates .gitignore if absent.
175
+ * Never ignores `.otto/` (LEARNINGS.md + config.json are durable, git-tracked
176
+ * memory).
177
+ *
178
+ * Idempotency is checked by scanning .gitignore text — NOT `git check-ignore`,
179
+ * which only matches a trailing-slash dir pattern once the dir exists on disk.
180
+ */
181
+ export function ensureTmpIgnored(workspaceDir) {
182
+ if (!isGitRepo(workspaceDir))
183
+ return;
184
+ const path = join(workspaceDir, ".gitignore");
185
+ let text = "";
186
+ try {
187
+ text = readFileSync(path, "utf8");
188
+ }
189
+ catch {
190
+ text = "";
191
+ }
192
+ const already = text
193
+ .split("\n")
194
+ .map((l) => l.trim())
195
+ .some((l) => l === ".otto-tmp" || l === ".otto-tmp/");
196
+ if (already)
197
+ return;
198
+ const needsNl = text.length > 0 && !text.endsWith("\n");
199
+ appendFileSync(path, `${needsNl ? "\n" : ""}.otto-tmp/\n`);
200
+ }
201
+ /**
202
+ * Returns a warning string if `strategy` keeps work in the current checkout AND
203
+ * the tree has uncommitted tracked changes (which disables the review panel's
204
+ * read-only reset enforcement). null when there is nothing to warn about.
205
+ */
206
+ export function dirtyTreeWarning(workspaceDir, strategy) {
207
+ if (strategy === "worktree")
208
+ return null; // worktree starts clean by construction
209
+ if (!isGitRepo(workspaceDir))
210
+ return null;
211
+ if (!hasUncommittedTrackedChanges(workspaceDir))
212
+ return null;
213
+ return "working tree has uncommitted changes — review-panel read-only enforcement will be disabled; consider committing/stashing or using --branch worktree";
214
+ }
215
+ //# sourceMappingURL=branch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"branch.js","sourceRoot":"","sources":["../src/branch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ export type CliFlags = {
2
+ help: boolean;
3
+ version: boolean;
4
+ printConfig: boolean;
5
+ noKeepAlive: boolean;
6
+ maxRetries?: number;
7
+ detach: boolean;
8
+ log?: string;
9
+ notify: boolean;
10
+ budget?: number;
11
+ cooldownMs?: number;
12
+ reviewPanel: boolean;
13
+ watch: boolean;
14
+ watchIntervalSec?: number;
15
+ issue?: number;
16
+ maxWaitMs?: number;
17
+ fresh: boolean;
18
+ verify: boolean;
19
+ applyReview?: string;
20
+ branch?: "current" | "branch" | "worktree";
21
+ branchPrefix?: string;
22
+ rest: string[];
23
+ };
24
+ /** Parse a duration: bare integer = seconds; suffix s/m/h supported. Throws on invalid. */
25
+ export declare function parseDurationMs(raw: string): number;
26
+ /**
27
+ * Normalize a user-supplied issue reference to a positive integer.
28
+ * Accepts: `42`, `#42`, `owner/repo#42`, and GitHub issue URLs
29
+ * (`https://github.com/owner/repo/issues/42[#anchor]`). A repo component is
30
+ * ignored — only the number is used (gh resolves the repo from the workspace).
31
+ * Throws on anything that is not a positive integer.
32
+ *
33
+ * SECURITY: the returned integer is the ONLY part of the ref that may reach a
34
+ * shell (via the OTTO_ISSUE env var read by a static template command). Never
35
+ * pass the raw ref to a shell. See render.ts security invariant.
36
+ */
37
+ export declare function parseIssueRef(raw: string): number;
38
+ export declare function parseFlags(argv: string[]): CliFlags;
39
+ /**
40
+ * Resolve the @phamvuhoang/otto-core version by reading the package.json that
41
+ * sits two levels up from the compiled cli-help.js (packages/core/dist/ →
42
+ * packages/core/package.json). Returns "?" if unreadable so version reporting
43
+ * never crashes the bin.
44
+ */
45
+ export declare function readCoreVersion(): string;
46
+ export declare function printVersion(bin: string, cliVersion?: string): void;
47
+ export declare function printHelp(bin: string, usage: string, description: string): void;
48
+ export type PrintConfigOptions = {
49
+ cliVersion?: string;
50
+ noKeepAlive?: boolean;
51
+ maxRetries?: number;
52
+ detach?: boolean;
53
+ detachLogPath?: string;
54
+ notify?: boolean;
55
+ budget?: number;
56
+ cooldownMs?: number;
57
+ /** Resolved review lenses (empty array = single reviewer). */
58
+ reviewLenses?: string[];
59
+ watch?: boolean;
60
+ watchIntervalSec?: number;
61
+ issue?: number;
62
+ maxWaitMs?: number;
63
+ mode?: string;
64
+ branchStrategy?: "current" | "branch" | "worktree";
65
+ branchPrefix?: string;
66
+ };
67
+ export declare function printConfig(bin: string, workspaceDir: string, packageDir: string, opts?: PrintConfigOptions): void;
68
+ //# sourceMappingURL=cli-help.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-help.d.ts","sourceRoot":"","sources":["../src/cli-help.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;IACf,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;IAC3C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAAC;AAEF,2FAA2F;AAC3F,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAWnD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAmBjD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,CA2LnD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAWxC;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAInE;AAED,wBAAgB,SAAS,CACvB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAClB,IAAI,CA+CN;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;IACnD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,wBAAgB,WAAW,CACzB,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,kBAAuB,GAC5B,IAAI,CA0EN"}