phoebe-agent 0.0.0 → 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 (75) hide show
  1. package/README.md +77 -8
  2. package/bootstrap/bin.mjs +42 -0
  3. package/bootstrap/boot.ts +383 -0
  4. package/bootstrap/cli.ts +29 -0
  5. package/bootstrap/crash-loop.ts +391 -0
  6. package/bootstrap/define-config.ts +20 -0
  7. package/bootstrap/engine-source.ts +83 -0
  8. package/bootstrap/github-engine.ts +169 -0
  9. package/bootstrap/index.mjs +9 -0
  10. package/bootstrap/index.ts +24 -0
  11. package/bootstrap/materialize.mjs +53 -0
  12. package/bootstrap/reconcile.ts +314 -0
  13. package/bootstrap/spawn-engine.mjs +78 -0
  14. package/package.json +26 -24
  15. package/prompts/checks-prompt.md +21 -6
  16. package/prompts/conflict-prompt.md +12 -1
  17. package/prompts/research-prompt.md +61 -0
  18. package/src/agent-env.ts +32 -0
  19. package/src/branded.ts +19 -0
  20. package/src/cli.ts +187 -0
  21. package/src/config-schema.ts +278 -0
  22. package/src/drain.ts +74 -0
  23. package/src/execution-gate.ts +27 -0
  24. package/src/git-model.ts +113 -0
  25. package/src/init.ts +277 -0
  26. package/src/load-config.ts +168 -0
  27. package/src/main.ts +1636 -0
  28. package/src/orchestrator.ts +953 -0
  29. package/src/prompt.ts +98 -0
  30. package/src/providers/providers.ts +222 -0
  31. package/src/providers/run-agent.ts +90 -0
  32. package/src/providers/types.ts +26 -0
  33. package/src/resolved-config.ts +55 -0
  34. package/templates/.env.example +11 -5
  35. package/templates/container/Dockerfile +41 -19
  36. package/templates/container/compose.local.yml +37 -0
  37. package/templates/container/compose.yml +34 -13
  38. package/templates/phoebe.config.ts +30 -6
  39. package/dist/phoebe.config.d.ts +0 -2
  40. package/dist/phoebe.config.js +0 -43
  41. package/dist/src/agent-env.d.ts +0 -6
  42. package/dist/src/agent-env.js +0 -24
  43. package/dist/src/cli.d.ts +0 -25
  44. package/dist/src/cli.js +0 -161
  45. package/dist/src/config-schema.d.ts +0 -163
  46. package/dist/src/config-schema.js +0 -140
  47. package/dist/src/execution-gate.d.ts +0 -9
  48. package/dist/src/execution-gate.js +0 -17
  49. package/dist/src/git-model.d.ts +0 -30
  50. package/dist/src/git-model.js +0 -71
  51. package/dist/src/index.d.ts +0 -2
  52. package/dist/src/index.js +0 -12
  53. package/dist/src/init.d.ts +0 -82
  54. package/dist/src/init.js +0 -207
  55. package/dist/src/load-config.d.ts +0 -88
  56. package/dist/src/load-config.js +0 -153
  57. package/dist/src/main.d.ts +0 -7
  58. package/dist/src/main.js +0 -1180
  59. package/dist/src/orchestrator.d.ts +0 -275
  60. package/dist/src/orchestrator.js +0 -579
  61. package/dist/src/prompt.d.ts +0 -13
  62. package/dist/src/prompt.js +0 -55
  63. package/dist/src/providers/providers.d.ts +0 -3
  64. package/dist/src/providers/providers.js +0 -210
  65. package/dist/src/providers/run-agent.d.ts +0 -34
  66. package/dist/src/providers/run-agent.js +0 -57
  67. package/dist/src/providers/types.d.ts +0 -27
  68. package/dist/src/providers/types.js +0 -6
  69. package/dist/src/resolved-config.d.ts +0 -8
  70. package/dist/src/resolved-config.js +0 -49
  71. package/dist/src/supervisor-decision.d.ts +0 -70
  72. package/dist/src/supervisor-decision.js +0 -94
  73. package/templates/container/compose.daemon.yml +0 -16
  74. package/templates/container/supervisor.sh +0 -50
  75. /package/prompts/{prompt.md → issues-prompt.md} +0 -0
@@ -1,153 +0,0 @@
1
- // Consumer-facing config plumbing: `defineConfig` (identity typing helper),
2
- // `loadUserConfig` (dynamic TS import via native Node type-stripping), and
3
- // `applyEnvOverlay` (`PHOEBE_*` overrides for scalar fields).
4
- //
5
- // The Phoebe CLI (src/cli.ts) chains these three: load the user's config,
6
- // overlay env vars, then `resolveConfig` fills the shipped defaults. Kept
7
- // separate from `config-schema.ts` so the schema stays a pure data contract
8
- // and only the CLI path pulls in Node's fs/url runtime.
9
- var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
10
- if (typeof path === "string" && /^\.\.?\//.test(path)) {
11
- return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
12
- return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
13
- });
14
- }
15
- return path;
16
- };
17
- import { pathToFileURL } from "node:url";
18
- import { existsSync } from "node:fs";
19
- import { isAbsolute, resolve as resolvePath } from "node:path";
20
- import { PROVIDER_NAMES } from "./config-schema.js";
21
- /**
22
- * Identity function that types a consumer's `phoebe.config.ts` export as
23
- * `PhoebeUserConfig`. Consumers write:
24
- *
25
- * ```ts
26
- * import { defineConfig } from "phoebe-agent";
27
- * export default defineConfig({ repoSlug: "...", ... });
28
- * ```
29
- *
30
- * The engine never reads this at runtime beyond forwarding the value; the
31
- * whole benefit is editor autocomplete and a compile-time check that only
32
- * known fields appear.
33
- */
34
- export function defineConfig(config) {
35
- return config;
36
- }
37
- /**
38
- * Scalar-only overlay: each `PHOEBE_*` env var, when set to a non-empty
39
- * string, replaces the corresponding user-config field. Nested records
40
- * (`promptFiles`, `paths`, `defaultModels`, `providerEnv`, `workOrder`) stay
41
- * config-file territory — env vars are for one-off run overrides where the
42
- * consumer doesn't want to edit `phoebe.config.ts`, and expanding structured
43
- * shapes into env keys defeats the point.
44
- *
45
- * A field-scoped list (rather than magic name-mangling) keeps the surface
46
- * documented and predictable: users can grep for `PHOEBE_` here and see the
47
- * complete overlay contract.
48
- */
49
- export const ENV_OVERLAY_KEYS = [
50
- { env: "PHOEBE_REPO_SLUG", key: "repoSlug" },
51
- { env: "PHOEBE_REPO_URL", key: "repoUrl" },
52
- { env: "PHOEBE_DEFAULT_BRANCH", key: "defaultBranch" },
53
- { env: "PHOEBE_BRANCH_PREFIX", key: "branchPrefix" },
54
- { env: "PHOEBE_READY_LABEL", key: "readyLabel" },
55
- { env: "PHOEBE_PROCESSING_LABEL", key: "processingLabel" },
56
- { env: "PHOEBE_PR_OPT_OUT_LABEL", key: "prOptOutLabel" },
57
- { env: "PHOEBE_INSTALL_COMMAND", key: "installCommand" },
58
- { env: "PHOEBE_CHECK_COMMAND", key: "checkCommand" },
59
- { env: "PHOEBE_TEST_COMMAND", key: "testCommand" },
60
- { env: "PHOEBE_READY_COMMAND", key: "readyCommand" },
61
- { env: "PHOEBE_BLOCKED_BY_PATTERN", key: "blockedByPattern" },
62
- { env: "PHOEBE_REVIEWS_SUCCESS_HEADING", key: "reviewsSuccessHeading" },
63
- ];
64
- const PR_SCOPE_VALUES = ["phoebe", "all"];
65
- const DRAFT_PRS_VALUES = ["skip-non-phoebe", "skip-all", "include"];
66
- function readNonEmpty(env, key) {
67
- const raw = env[key];
68
- if (typeof raw !== "string" || raw.length === 0)
69
- return undefined;
70
- return raw;
71
- }
72
- /**
73
- * Apply the `PHOEBE_*` overlay onto a user config and return a new object.
74
- * The overlay is additive over what the config file declared — an unset env
75
- * var leaves the field untouched (so `resolveConfig` can still fall back to
76
- * `CONFIG_DEFAULTS` if the field was also absent from the config file).
77
- */
78
- export function applyEnvOverlay(user, env) {
79
- const overlaid = { ...user };
80
- for (const { env: envKey, key } of ENV_OVERLAY_KEYS) {
81
- const value = readNonEmpty(env, envKey);
82
- if (value !== undefined) {
83
- overlaid[key] = value;
84
- }
85
- }
86
- const prScope = readNonEmpty(env, "PHOEBE_PR_SCOPE");
87
- if (prScope !== undefined) {
88
- if (!PR_SCOPE_VALUES.includes(prScope)) {
89
- throw new Error(`PHOEBE_PR_SCOPE must be one of ${PR_SCOPE_VALUES.join(", ")} (got "${prScope}").`);
90
- }
91
- overlaid.prScope = prScope;
92
- }
93
- const draftPrs = readNonEmpty(env, "PHOEBE_DRAFT_PRS");
94
- if (draftPrs !== undefined) {
95
- if (!DRAFT_PRS_VALUES.includes(draftPrs)) {
96
- throw new Error(`PHOEBE_DRAFT_PRS must be one of ${DRAFT_PRS_VALUES.join(", ")} (got "${draftPrs}").`);
97
- }
98
- overlaid.draftPrs = draftPrs;
99
- }
100
- const defaultProvider = readNonEmpty(env, "PHOEBE_DEFAULT_PROVIDER");
101
- if (defaultProvider !== undefined) {
102
- if (!PROVIDER_NAMES.includes(defaultProvider)) {
103
- throw new Error(`PHOEBE_DEFAULT_PROVIDER must be one of ${PROVIDER_NAMES.join(", ")} (got "${defaultProvider}").`);
104
- }
105
- overlaid.defaultProvider = defaultProvider;
106
- }
107
- return overlaid;
108
- }
109
- /**
110
- * Resolve a `--config` argument (or the default) to an absolute path and
111
- * assert the file exists. Split from `loadUserConfig` so the CLI can print
112
- * a precise "file not found" message before attempting the dynamic import.
113
- */
114
- export function resolveConfigPath(argPath, cwd) {
115
- const candidate = argPath ?? "phoebe.config.ts";
116
- const absolute = isAbsolute(candidate) ? candidate : resolvePath(cwd, candidate);
117
- if (!existsSync(absolute)) {
118
- throw new Error(argPath
119
- ? `Config file not found: ${absolute} (passed via --config).`
120
- : `Config file not found: ${absolute}. ` +
121
- `Create a phoebe.config.ts in the current directory or pass --config <path>.`);
122
- }
123
- return absolute;
124
- }
125
- /**
126
- * Dynamically import a `phoebe.config.ts` and return the user shape. Native
127
- * Node type-stripping (Node ≥ 22.7 with `--experimental-strip-types`, or
128
- * ≥ 23 by default) handles the TS syntax — no bundler needed on the consumer
129
- * side. Accepts either a default export or a named `config` export so the
130
- * pre-`defineConfig` scaffold still loads.
131
- */
132
- export async function loadUserConfig(configPath) {
133
- const url = pathToFileURL(configPath).href;
134
- let mod;
135
- try {
136
- mod = await import(__rewriteRelativeImportExtension(url));
137
- }
138
- catch (error) {
139
- throw new Error(`Failed to load ${configPath}: ${error instanceof Error ? error.message : String(error)}`);
140
- }
141
- const record = mod;
142
- const candidate = (typeof record["default"] === "object" && record["default"] !== null
143
- ? record["default"]
144
- : undefined) ??
145
- (typeof record["config"] === "object" && record["config"] !== null
146
- ? record["config"]
147
- : undefined);
148
- if (!candidate) {
149
- throw new Error(`${configPath} must export a Phoebe config as \`export default defineConfig({ ... })\` ` +
150
- `or a named \`export const config = { ... }\`.`);
151
- }
152
- return candidate;
153
- }
@@ -1,7 +0,0 @@
1
- /**
2
- * Drive the Phoebe worker loop until it exits (persistent mode) or completes
3
- * one unit (`--run-once`). Called by src/cli.ts after the resolved config is
4
- * installed; the CLI passes its argv with `--config <path>` already stripped
5
- * so this only sees engine-level flags.
6
- */
7
- export declare function runEngine(argv?: readonly string[]): Promise<void>;