@joynt/foundry 0.0.0-stage → 0.1.50

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 (216) hide show
  1. package/dist/backends/command.d.ts +37 -0
  2. package/dist/backends/command.d.ts.map +1 -0
  3. package/dist/backends/command.js +79 -0
  4. package/dist/backends/command.js.map +1 -0
  5. package/dist/backends/index.d.ts +9 -0
  6. package/dist/backends/index.d.ts.map +1 -0
  7. package/dist/backends/index.js +37 -0
  8. package/dist/backends/index.js.map +1 -0
  9. package/dist/cli.d.ts +3 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +191 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/commands/action.d.ts +6 -0
  14. package/dist/commands/action.d.ts.map +1 -0
  15. package/dist/commands/action.js +171 -0
  16. package/dist/commands/action.js.map +1 -0
  17. package/dist/commands/cancelled.d.ts +5 -0
  18. package/dist/commands/cancelled.d.ts.map +1 -0
  19. package/dist/commands/cancelled.js +107 -0
  20. package/dist/commands/cancelled.js.map +1 -0
  21. package/dist/commands/init.d.ts +5 -0
  22. package/dist/commands/init.d.ts.map +1 -0
  23. package/dist/commands/init.js +323 -0
  24. package/dist/commands/init.js.map +1 -0
  25. package/dist/commands/preview.d.ts +4 -0
  26. package/dist/commands/preview.d.ts.map +1 -0
  27. package/dist/commands/preview.js +108 -0
  28. package/dist/commands/preview.js.map +1 -0
  29. package/dist/commands/release.d.ts +2 -0
  30. package/dist/commands/release.d.ts.map +1 -0
  31. package/dist/commands/release.js +89 -0
  32. package/dist/commands/release.js.map +1 -0
  33. package/dist/commands/report.d.ts +14 -0
  34. package/dist/commands/report.d.ts.map +1 -0
  35. package/dist/commands/report.js +91 -0
  36. package/dist/commands/report.js.map +1 -0
  37. package/dist/commands/reset.d.ts +4 -0
  38. package/dist/commands/reset.d.ts.map +1 -0
  39. package/dist/commands/reset.js +155 -0
  40. package/dist/commands/reset.js.map +1 -0
  41. package/dist/commands/review.d.ts +2 -0
  42. package/dist/commands/review.d.ts.map +1 -0
  43. package/dist/commands/review.js +73 -0
  44. package/dist/commands/review.js.map +1 -0
  45. package/dist/commands/setup-bot.d.ts +31 -0
  46. package/dist/commands/setup-bot.d.ts.map +1 -0
  47. package/dist/commands/setup-bot.js +429 -0
  48. package/dist/commands/setup-bot.js.map +1 -0
  49. package/dist/commands/sync.d.ts +2 -0
  50. package/dist/commands/sync.d.ts.map +1 -0
  51. package/dist/commands/sync.js +77 -0
  52. package/dist/commands/sync.js.map +1 -0
  53. package/dist/config.d.ts +9 -0
  54. package/dist/config.d.ts.map +1 -0
  55. package/dist/config.js +147 -0
  56. package/dist/config.js.map +1 -0
  57. package/dist/index.d.ts +15 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +29 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/lib/agent-output.d.ts +49 -0
  62. package/dist/lib/agent-output.d.ts.map +1 -0
  63. package/dist/lib/agent-output.js +256 -0
  64. package/dist/lib/agent-output.js.map +1 -0
  65. package/dist/lib/agent-report.d.ts +107 -0
  66. package/dist/lib/agent-report.d.ts.map +1 -0
  67. package/dist/lib/agent-report.js +233 -0
  68. package/dist/lib/agent-report.js.map +1 -0
  69. package/dist/lib/authorize.d.ts +3 -0
  70. package/dist/lib/authorize.d.ts.map +1 -0
  71. package/dist/lib/authorize.js +67 -0
  72. package/dist/lib/authorize.js.map +1 -0
  73. package/dist/lib/branches.d.ts +22 -0
  74. package/dist/lib/branches.d.ts.map +1 -0
  75. package/dist/lib/branches.js +82 -0
  76. package/dist/lib/branches.js.map +1 -0
  77. package/dist/lib/claim.d.ts +22 -0
  78. package/dist/lib/claim.d.ts.map +1 -0
  79. package/dist/lib/claim.js +129 -0
  80. package/dist/lib/claim.js.map +1 -0
  81. package/dist/lib/completion.d.ts +5 -0
  82. package/dist/lib/completion.d.ts.map +1 -0
  83. package/dist/lib/completion.js +63 -0
  84. package/dist/lib/completion.js.map +1 -0
  85. package/dist/lib/deployments.d.ts +21 -0
  86. package/dist/lib/deployments.d.ts.map +1 -0
  87. package/dist/lib/deployments.js +104 -0
  88. package/dist/lib/deployments.js.map +1 -0
  89. package/dist/lib/event-handler.d.ts +74 -0
  90. package/dist/lib/event-handler.d.ts.map +1 -0
  91. package/dist/lib/event-handler.js +1002 -0
  92. package/dist/lib/event-handler.js.map +1 -0
  93. package/dist/lib/events.d.ts +72 -0
  94. package/dist/lib/events.d.ts.map +1 -0
  95. package/dist/lib/events.js +3 -0
  96. package/dist/lib/events.js.map +1 -0
  97. package/dist/lib/gh-cli-client.d.ts +46 -0
  98. package/dist/lib/gh-cli-client.d.ts.map +1 -0
  99. package/dist/lib/gh-cli-client.js +260 -0
  100. package/dist/lib/gh-cli-client.js.map +1 -0
  101. package/dist/lib/git.d.ts +42 -0
  102. package/dist/lib/git.d.ts.map +1 -0
  103. package/dist/lib/git.js +247 -0
  104. package/dist/lib/git.js.map +1 -0
  105. package/dist/lib/github-client.d.ts +98 -0
  106. package/dist/lib/github-client.d.ts.map +1 -0
  107. package/dist/lib/github-client.js +3 -0
  108. package/dist/lib/github-client.js.map +1 -0
  109. package/dist/lib/github.d.ts +82 -0
  110. package/dist/lib/github.d.ts.map +1 -0
  111. package/dist/lib/github.js +202 -0
  112. package/dist/lib/github.js.map +1 -0
  113. package/dist/lib/issue-file.d.ts +15 -0
  114. package/dist/lib/issue-file.d.ts.map +1 -0
  115. package/dist/lib/issue-file.js +84 -0
  116. package/dist/lib/issue-file.js.map +1 -0
  117. package/dist/lib/labels.d.ts +14 -0
  118. package/dist/lib/labels.d.ts.map +1 -0
  119. package/dist/lib/labels.js +70 -0
  120. package/dist/lib/labels.js.map +1 -0
  121. package/dist/lib/log.d.ts +11 -0
  122. package/dist/lib/log.d.ts.map +1 -0
  123. package/dist/lib/log.js +53 -0
  124. package/dist/lib/log.js.map +1 -0
  125. package/dist/lib/octokit-client.d.ts +112 -0
  126. package/dist/lib/octokit-client.d.ts.map +1 -0
  127. package/dist/lib/octokit-client.js +507 -0
  128. package/dist/lib/octokit-client.js.map +1 -0
  129. package/dist/lib/preview-verify.d.ts +48 -0
  130. package/dist/lib/preview-verify.d.ts.map +1 -0
  131. package/dist/lib/preview-verify.js +148 -0
  132. package/dist/lib/preview-verify.js.map +1 -0
  133. package/dist/lib/preview.d.ts +33 -0
  134. package/dist/lib/preview.d.ts.map +1 -0
  135. package/dist/lib/preview.js +308 -0
  136. package/dist/lib/preview.js.map +1 -0
  137. package/dist/lib/reconcile.d.ts +14 -0
  138. package/dist/lib/reconcile.d.ts.map +1 -0
  139. package/dist/lib/reconcile.js +114 -0
  140. package/dist/lib/reconcile.js.map +1 -0
  141. package/dist/lib/review.d.ts +38 -0
  142. package/dist/lib/review.d.ts.map +1 -0
  143. package/dist/lib/review.js +284 -0
  144. package/dist/lib/review.js.map +1 -0
  145. package/dist/lib/stale-prs.d.ts +31 -0
  146. package/dist/lib/stale-prs.d.ts.map +1 -0
  147. package/dist/lib/stale-prs.js +161 -0
  148. package/dist/lib/stale-prs.js.map +1 -0
  149. package/dist/lib/state-store.d.ts +23 -0
  150. package/dist/lib/state-store.d.ts.map +1 -0
  151. package/dist/lib/state-store.js +3 -0
  152. package/dist/lib/state-store.js.map +1 -0
  153. package/dist/lib/state.d.ts +23 -0
  154. package/dist/lib/state.d.ts.map +1 -0
  155. package/dist/lib/state.js +57 -0
  156. package/dist/lib/state.js.map +1 -0
  157. package/dist/lib/status-comment.d.ts +14 -0
  158. package/dist/lib/status-comment.d.ts.map +1 -0
  159. package/dist/lib/status-comment.js +195 -0
  160. package/dist/lib/status-comment.js.map +1 -0
  161. package/dist/lib/stores/file-store.d.ts +22 -0
  162. package/dist/lib/stores/file-store.d.ts.map +1 -0
  163. package/dist/lib/stores/file-store.js +172 -0
  164. package/dist/lib/stores/file-store.js.map +1 -0
  165. package/dist/lib/stores/index.d.ts +13 -0
  166. package/dist/lib/stores/index.d.ts.map +1 -0
  167. package/dist/lib/stores/index.js +20 -0
  168. package/dist/lib/stores/index.js.map +1 -0
  169. package/dist/lib/task-recovery.d.ts +22 -0
  170. package/dist/lib/task-recovery.d.ts.map +1 -0
  171. package/dist/lib/task-recovery.js +172 -0
  172. package/dist/lib/task-recovery.js.map +1 -0
  173. package/dist/lib/templates.d.ts +8 -0
  174. package/dist/lib/templates.d.ts.map +1 -0
  175. package/dist/lib/templates.js +58 -0
  176. package/dist/lib/templates.js.map +1 -0
  177. package/dist/lib/thread.d.ts +13 -0
  178. package/dist/lib/thread.d.ts.map +1 -0
  179. package/dist/lib/thread.js +75 -0
  180. package/dist/lib/thread.js.map +1 -0
  181. package/dist/lib/verify.d.ts +31 -0
  182. package/dist/lib/verify.d.ts.map +1 -0
  183. package/dist/lib/verify.js +90 -0
  184. package/dist/lib/verify.js.map +1 -0
  185. package/dist/lib/version.d.ts +9 -0
  186. package/dist/lib/version.d.ts.map +1 -0
  187. package/dist/lib/version.js +134 -0
  188. package/dist/lib/version.js.map +1 -0
  189. package/dist/lib/webhook.d.ts +39 -0
  190. package/dist/lib/webhook.d.ts.map +1 -0
  191. package/dist/lib/webhook.js +248 -0
  192. package/dist/lib/webhook.js.map +1 -0
  193. package/dist/lib/worker.d.ts +42 -0
  194. package/dist/lib/worker.d.ts.map +1 -0
  195. package/dist/lib/worker.js +9 -0
  196. package/dist/lib/worker.js.map +1 -0
  197. package/dist/lib/workers/index.d.ts +11 -0
  198. package/dist/lib/workers/index.d.ts.map +1 -0
  199. package/dist/lib/workers/index.js +18 -0
  200. package/dist/lib/workers/index.js.map +1 -0
  201. package/dist/lib/workers/subprocess.d.ts +8 -0
  202. package/dist/lib/workers/subprocess.d.ts.map +1 -0
  203. package/dist/lib/workers/subprocess.js +105 -0
  204. package/dist/lib/workers/subprocess.js.map +1 -0
  205. package/dist/lib/worktree.d.ts +21 -0
  206. package/dist/lib/worktree.d.ts.map +1 -0
  207. package/dist/lib/worktree.js +113 -0
  208. package/dist/lib/worktree.js.map +1 -0
  209. package/dist/types.d.ts +201 -0
  210. package/dist/types.d.ts.map +1 -0
  211. package/dist/types.js +6 -0
  212. package/dist/types.js.map +1 -0
  213. package/package.json +44 -4
  214. package/templates/foundry.yml +121 -0
  215. package/templates/vercel-preview-url.sh +61 -0
  216. package/README.md +0 -3
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.preserveWork = preserveWork;
37
+ exports.ensureWorktree = ensureWorktree;
38
+ /**
39
+ * Worktree lifecycle across jobs.
40
+ *
41
+ * A task's worktree lives only as long as the job that created it. When a job
42
+ * ends with the agent waiting on a human, the branch is pushed so nothing is
43
+ * lost; when a later job resumes the task, the worktree is recreated from the
44
+ * pushed branch. Both functions are idempotent and safe to call when there is
45
+ * nothing to do.
46
+ */
47
+ const fs = __importStar(require("node:fs"));
48
+ const git = __importStar(require("./git.js"));
49
+ const log = __importStar(require("./log.js"));
50
+ const branches_js_1 = require("./branches.js");
51
+ /**
52
+ * Make the agent's work survive the end of this job: commit anything
53
+ * uncommitted, then push the branch if it has commits beyond its base.
54
+ * Never throws; a failure is logged and reported in the result so the
55
+ * status comment can say so.
56
+ */
57
+ function preserveWork(config, task, repoDir, reason) {
58
+ const result = { committed: false, pushed: false };
59
+ const wt = task.worktree;
60
+ if (!fs.existsSync(wt))
61
+ return result;
62
+ try {
63
+ if (git.isDirty(wt)) {
64
+ git.commitAll(`chore(foundry): work in progress (${reason})`, wt);
65
+ result.committed = true;
66
+ log.info(`#${task.issue}: committed work in progress before pausing.`);
67
+ }
68
+ }
69
+ catch (err) {
70
+ log.warn(`#${task.issue}: could not commit work in progress: ${err.message}`);
71
+ }
72
+ try {
73
+ const base = (0, branches_js_1.resolveBaseBranch)(config, repoDir);
74
+ if (git.countCommits(`${base}..HEAD`, wt) > 0) {
75
+ git.push(task.branch, wt, true);
76
+ result.pushed = true;
77
+ log.info(`#${task.issue}: pushed ${task.branch}.`);
78
+ }
79
+ }
80
+ catch (err) {
81
+ log.warn(`#${task.issue}: could not push ${task.branch}: ${err.message}`);
82
+ }
83
+ return result;
84
+ }
85
+ /**
86
+ * Make sure the task's worktree exists before an agent is launched into it.
87
+ * In a fresh job it is recreated from the pushed branch; if the branch was
88
+ * never pushed, from the base branch.
89
+ */
90
+ function ensureWorktree(config, task, repoDir) {
91
+ if (git.worktreeExists(task.worktree, repoDir) && fs.existsSync(task.worktree))
92
+ return;
93
+ try {
94
+ git.fetchAll(repoDir);
95
+ }
96
+ catch (err) {
97
+ log.warn(`Fetch failed before recreating worktree: ${err.message}`);
98
+ }
99
+ // A stale registration with no directory (job ended, path gone) must be pruned first.
100
+ git.pruneWorktrees(repoDir);
101
+ if (git.remoteBranchExists(task.branch, repoDir)) {
102
+ git.addWorktreeTracking(task.worktree, task.branch, repoDir);
103
+ log.info(`#${task.issue}: recreated worktree from origin/${task.branch}.`);
104
+ }
105
+ else {
106
+ const base = (0, branches_js_1.resolveBaseBranch)(config, repoDir);
107
+ if (git.branchExists(task.branch, repoDir))
108
+ git.deleteBranch(task.branch, repoDir);
109
+ git.addWorktree(task.worktree, task.branch, base, repoDir);
110
+ log.info(`#${task.issue}: created worktree for ${task.branch} from ${base} (branch was never pushed).`);
111
+ }
112
+ }
113
+ //# sourceMappingURL=worktree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/lib/worktree.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Joynt Foundry — Core type definitions
3
+ */
4
+ export interface AgentBackendDef {
5
+ type: 'command';
6
+ /** Use a command Foundry maintains instead of copying one into config, where it would drift. */
7
+ preset?: 'claude-code';
8
+ /** Required unless `preset` is set. Overrides the preset's command when both are given. */
9
+ command?: string;
10
+ env?: Record<string, string>;
11
+ }
12
+ export interface FoundryConfig {
13
+ repo: string;
14
+ /**
15
+ * State labels. Foundry owns them: exactly one is on a tracked issue at a
16
+ * time and only Foundry adds or removes them. Humans never set a state
17
+ * label to make something happen; they comment a command.
18
+ */
19
+ labels: {
20
+ in_progress: string;
21
+ done: string;
22
+ ready_for_review: string;
23
+ waiting_for_input: string;
24
+ failed: string;
25
+ plan_review: string;
26
+ };
27
+ mode_labels?: {
28
+ plan: string;
29
+ auto: string;
30
+ default: string;
31
+ };
32
+ /**
33
+ * The repo's long-lived branches, by name. Feature branches are cut from
34
+ * and merged into `integration`; `production` is what it is promoted to.
35
+ * Never assumed: onboarding must not require renaming a branch that
36
+ * deploy tooling already keys on.
37
+ */
38
+ branches: {
39
+ integration: string;
40
+ production: string;
41
+ };
42
+ branch_template: string;
43
+ worktree_base: string;
44
+ max_input_rounds: number;
45
+ /** Passed to the agent as FOUNDRY_MAX_TURNS; the preset uses --max-turns. Default 150. */
46
+ agent_max_turns?: number;
47
+ /** An in-progress issue with no status update for this long is marked failed by `foundry reconcile`. Default 120. */
48
+ reconcile_stale_minutes?: number;
49
+ verify: string[];
50
+ /** Run against the live preview (FOUNDRY_PREVIEW_URL) before ready-for-review. Default []. */
51
+ verify_preview?: string[];
52
+ integration_rebuild: string;
53
+ /**
54
+ * The three commands, the only comments that start or stop work. Every
55
+ * other comment is context: it reaches the agent through the issue file
56
+ * on the next launch, and never starts a job.
57
+ */
58
+ comment_triggers: {
59
+ go: string;
60
+ restart: string;
61
+ stop: string;
62
+ };
63
+ version_sources: string[];
64
+ tag_prefix: string;
65
+ default_agent_backend: string;
66
+ agent_backends: Record<string, AgentBackendDef>;
67
+ agent_label_map?: Record<string, string>;
68
+ github_backend: 'gh-cli' | 'octokit';
69
+ preview?: {
70
+ mode: 'template' | 'provider';
71
+ url_template?: string;
72
+ up_command?: string;
73
+ down_command?: string;
74
+ comment?: boolean;
75
+ /**
76
+ * Also preview any pull request whose base branch is listed here, task or
77
+ * not: up on open/reopen, redeploy on push, down on close. For the
78
+ * promotion PR from `integration` into `main`.
79
+ */
80
+ pull_request_bases?: string[];
81
+ /** How long to wait for the preview URL to answer before verify_preview runs. Default 300. */
82
+ ready_timeout_seconds?: number;
83
+ /**
84
+ * Text the preview's body must contain before it counts as up, with
85
+ * {sha}, {branch}, {pr_number} expanded. Without it a redeploy is
86
+ * verified against the previous version still being served.
87
+ */
88
+ ready_match?: string;
89
+ };
90
+ review?: {
91
+ /** On an approving review: rebase onto the base, wait for checks, merge (rebase method). Default true. */
92
+ merge_on_approval?: boolean;
93
+ /** How long to wait for the PR's checks before giving up. Default 900. */
94
+ checks_timeout_seconds?: number;
95
+ };
96
+ github_deployments?: {
97
+ enabled: boolean;
98
+ environment?: string;
99
+ production?: boolean;
100
+ auto_inactive?: boolean;
101
+ };
102
+ }
103
+ export type TaskStatus = 'claimed' | 'agent-running' | 'verifying' | 'pr-open' | 'reviewing' | 'waiting-for-input' | 'resuming' | 'pr-changes-requested' | 'plan-review' | 'done' | 'failed' | 'stopped';
104
+ export interface TaskState {
105
+ issue: number;
106
+ title: string;
107
+ repo: string;
108
+ branch: string;
109
+ worktree: string;
110
+ tmux_session: string;
111
+ pr_url?: string;
112
+ pr_number?: number;
113
+ agent_backend: string;
114
+ agent_command?: string;
115
+ status: TaskStatus;
116
+ claimed_at: string;
117
+ updated_at: string;
118
+ runner_id: string;
119
+ session_id?: string;
120
+ permission_mode?: string;
121
+ input_request_count?: number;
122
+ last_agent_message?: string;
123
+ /** Usage of the most recent agent run, from the transcript's result event. */
124
+ last_run?: {
125
+ cost_usd?: number;
126
+ turns?: number;
127
+ duration_ms?: number;
128
+ };
129
+ /** The issue body at claim time; written to FOUNDRY_ISSUE_FILE on every launch. */
130
+ issue_body?: string;
131
+ preview_url?: string;
132
+ deployment_id?: number;
133
+ }
134
+ export interface RunnerState {
135
+ runner_id: string;
136
+ repo: string;
137
+ tasks: Record<number, TaskState>;
138
+ }
139
+ export interface AgentLaunchParams {
140
+ worktree: string;
141
+ issue_url: string;
142
+ issue_number: number;
143
+ repo: string;
144
+ title: string;
145
+ body: string;
146
+ labels: string[];
147
+ log_dir: string;
148
+ state_dir: string;
149
+ permission_mode: string;
150
+ }
151
+ export interface AgentBackend {
152
+ name: string;
153
+ resolveCommand(params: AgentLaunchParams): string;
154
+ resolveEnv(params: AgentLaunchParams): Record<string, string>;
155
+ }
156
+ export interface GitHubIssue {
157
+ number: number;
158
+ title: string;
159
+ body: string | null;
160
+ labels: Array<{
161
+ name: string;
162
+ }>;
163
+ html_url: string;
164
+ state: string;
165
+ }
166
+ export interface GitHubComment {
167
+ id: number;
168
+ body: string;
169
+ user: {
170
+ login: string;
171
+ } | null;
172
+ created_at: string;
173
+ }
174
+ export type AgentOutcomeType = 'completed' | 'needs-input' | 'plan-completed' | 'blocked' | 'errored';
175
+ export interface AskUserQuestionOption {
176
+ label: string;
177
+ description: string;
178
+ }
179
+ export interface AskUserQuestionData {
180
+ question: string;
181
+ options: AskUserQuestionOption[];
182
+ multiSelect: boolean;
183
+ }
184
+ export interface AgentOutcome {
185
+ type: AgentOutcomeType;
186
+ session_id: string | null;
187
+ /** Text to show a human: the report summary, the plan, or a failure explanation. Never branched on. */
188
+ final_message: string | null;
189
+ ask_user_questions: AskUserQuestionData[] | null;
190
+ /** The agent's typed report, when it submitted a valid one. */
191
+ report?: import('./lib/agent-report.js').AgentReport | null;
192
+ /** Why the task failed or is blocked, for `errored` and `blocked`. */
193
+ reason?: string;
194
+ /** From the result event when present. */
195
+ usage?: {
196
+ cost_usd?: number;
197
+ turns?: number;
198
+ duration_ms?: number;
199
+ };
200
+ }
201
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,CAAC;IAChB,gGAAgG;IAChG,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,2FAA2F;IAC3F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IAEb;;;;OAIG;IACH,MAAM,EAAE;QACN,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,gBAAgB,EAAE,MAAM,CAAC;QACzB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IAEF,WAAW,CAAC,EAAE;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IAEF;;;;;OAKG;IACH,QAAQ,EAAE;QACR,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IAEF,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IAEtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,0FAA0F;IAC1F,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qHAAqH;IACrH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAEjC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,8FAA8F;IAC9F,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,mBAAmB,EAAE,MAAM,CAAC;IAE5B;;;;OAIG;IACH,gBAAgB,EAAE;QAChB,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IAEF,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IAEnB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAEhD,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,cAAc,EAAE,QAAQ,GAAG,SAAS,CAAC;IAGrC,OAAO,CAAC,EAAE;QACR,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;QAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB;;;;WAIG;QACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;QAC9B,8FAA8F;QAC9F,qBAAqB,CAAC,EAAE,MAAM,CAAC;QAC/B;;;;WAIG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IAEF,MAAM,CAAC,EAAE;QACP,0GAA0G;QAC1G,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,0EAA0E;QAC1E,sBAAsB,CAAC,EAAE,MAAM,CAAC;KACjC,CAAC;IAEF,kBAAkB,CAAC,EAAE;QACnB,OAAO,EAAE,OAAO,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,aAAa,CAAC,EAAE,OAAO,CAAC;KACzB,CAAC;CACH;AAID,MAAM,MAAM,UAAU,GAClB,SAAS,GACT,eAAe,GACf,WAAW,GACX,SAAS,GACT,WAAW,GACX,mBAAmB,GACnB,UAAU,GACV,sBAAsB,GACtB,aAAa,GACb,MAAM,GACN,QAAQ,GACR,SAAS,CAAC;AAEd,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,8EAA8E;IAC9E,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE,mFAAmF;IACnF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CAClC;AAID,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAAC;IAClD,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/D;AAID,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;CACpB;AAID,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,aAAa,GAAG,gBAAgB,GAAG,SAAS,GAAG,SAAS,CAAC;AAEtG,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,qBAAqB,EAAE,CAAC;IACjC,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,gBAAgB,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,uGAAuG;IACvG,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,kBAAkB,EAAE,mBAAmB,EAAE,GAAG,IAAI,CAAC;IACjD,+DAA+D;IAC/D,MAAM,CAAC,EAAE,OAAO,uBAAuB,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5D,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,KAAK,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACrE"}
package/dist/types.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * Joynt Foundry — Core type definitions
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;GAEG"}
package/package.json CHANGED
@@ -1,6 +1,46 @@
1
1
  {
2
2
  "name": "@joynt/foundry",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.50",
4
+ "description": "Developer automation: GitHub Issues → agent sessions → validated PRs",
5
+ "license": "MIT",
6
+ "bin": {
7
+ "foundry": "dist/cli.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "files": [
12
+ "dist",
13
+ "templates"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "test": "vitest run",
18
+ "test:watch": "vitest",
19
+ "prepublishOnly": "npm run build",
20
+ "dev": "tsc --watch"
21
+ },
22
+ "publishConfig": {
23
+ "registry": "https://registry.npmjs.org",
24
+ "access": "public"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/joyntshops/foundry.git",
29
+ "directory": "packages/foundry"
30
+ },
31
+ "engines": {
32
+ "node": ">=18"
33
+ },
34
+ "dependencies": {
35
+ "@octokit/auth-app": "^8.2.0",
36
+ "@octokit/rest": "^22.0.1",
37
+ "chalk": "^5.4.1",
38
+ "commander": "^12.1.0",
39
+ "yaml": "^2.6.1"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^20.17.0",
43
+ "typescript": "^5.7.0",
44
+ "vitest": "^4.0.18"
45
+ }
46
+ }
@@ -0,0 +1,121 @@
1
+ # Foundry: GitHub Issues → coding agent → verified pull request.
2
+ #
3
+ # Every run is one GitHub event. Foundry reads the event, rebuilds task state
4
+ # from the issue (labels + claim comment), performs the transition, and exits.
5
+ # State lives on GitHub, not on any machine. Humans drive it with three issue
6
+ # comments: `@foundry go`, `@foundry restart`, `@foundry stop`.
7
+ #
8
+ # GitHub starts issue_comment, schedule, and workflow_dispatch runs from the
9
+ # DEFAULT branch, so this file and .joynt-foundry.yml govern those runs only
10
+ # once they are on it. `gh workflow run foundry.yml --ref <branch> ...` runs
11
+ # the copy on another branch.
12
+ #
13
+ # Secrets (repository or organization level):
14
+ # CLAUDE_CODE_OAUTH_TOKEN required. From `claude setup-token`; bills that Claude plan.
15
+ # FOUNDRY_APP_ID, FOUNDRY_APP_PRIVATE_KEY a GitHub App installed on this repo (`foundry setup-bot`).
16
+ # With it, Foundry's comments and PRs carry the App's name and
17
+ # its PRs trigger the repo's other workflows. Without it the
18
+ # job's built-in token is used and agent PRs get no CI.
19
+ name: Foundry
20
+
21
+ on:
22
+ issue_comment:
23
+ types: [created]
24
+ pull_request:
25
+ types: [opened, synchronize, reopened, closed]
26
+ pull_request_review:
27
+ types: [submitted]
28
+ # Foundry dispatches itself to hand a command to another issue's job (e.g.
29
+ # sending an agent to rebase after integration moved). Also how to run the
30
+ # workflow from a non-default branch: --ref <branch>.
31
+ workflow_dispatch:
32
+ inputs:
33
+ issue:
34
+ description: Issue number
35
+ required: true
36
+ type: string
37
+ command:
38
+ description: "Foundry command: go | restart | stop"
39
+ required: true
40
+ type: string
41
+ message:
42
+ description: Message for the agent
43
+ required: false
44
+ type: string
45
+ default: ""
46
+ # Reconcile: an in-progress issue whose run died without cleanup is marked
47
+ # failed. Each run costs about 30 seconds of runner time.
48
+ schedule:
49
+ - cron: '0 */6 * * *'
50
+
51
+ permissions:
52
+ contents: write # push branches
53
+ issues: write # labels, claim/status comments
54
+ pull-requests: write # open PRs, PR comments
55
+ checks: write # verification results as a check run on the PR
56
+ actions: write # workflow_dispatch to itself; preview up/down
57
+ deployments: write # GitHub Deployment records for previews
58
+
59
+ jobs:
60
+ foundry:
61
+ # Comments: only `@foundry` commands, only on issues (not PRs), only from
62
+ # people associated with the repo; the job then requires write permission
63
+ # before acting. Plain comments and labels never start a run; the agent
64
+ # reads them at its next launch. PR events: merges, and PRs into the
65
+ # production branch (previewed when preview.pull_request_bases lists it).
66
+ if: >-
67
+ (github.event_name == 'issue_comment' &&
68
+ !endsWith(github.event.comment.user.login, '[bot]') &&
69
+ !github.event.issue.pull_request &&
70
+ startsWith(github.event.comment.body, '@foundry') &&
71
+ contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) ||
72
+ (github.event_name == 'pull_request' &&
73
+ (github.event.pull_request.merged == true ||
74
+ github.event.pull_request.base.ref == '__PRODUCTION_BRANCH__')) ||
75
+ (github.event_name == 'pull_request_review' &&
76
+ (github.event.review.state == 'changes_requested' || github.event.review.state == 'approved')) ||
77
+ github.event_name == 'workflow_dispatch' ||
78
+ github.event_name == 'schedule'
79
+ runs-on: ubuntu-latest
80
+ timeout-minutes: 90
81
+
82
+ # One job at a time per issue, declared on the job so runs filtered out by
83
+ # the `if:` above never enter the group. `@foundry stop` cancels the issue's
84
+ # running job; everything else queues.
85
+ concurrency:
86
+ group: foundry-${{ github.event.inputs.issue || github.event.issue.number || github.event.pull_request.number || github.event_name }}
87
+ cancel-in-progress: ${{ github.event_name == 'issue_comment' && contains(github.event.comment.body, '@foundry stop') }}
88
+
89
+ env:
90
+ FOUNDRY_APP_ID: ${{ secrets.FOUNDRY_APP_ID }} # secrets aren't readable in step `if:`
91
+
92
+ steps:
93
+ - name: Mint GitHub App token
94
+ id: app
95
+ if: env.FOUNDRY_APP_ID != ''
96
+ uses: actions/create-github-app-token@v1
97
+ with:
98
+ app-id: ${{ secrets.FOUNDRY_APP_ID }}
99
+ private-key: ${{ secrets.FOUNDRY_APP_PRIVATE_KEY }}
100
+
101
+ # Full history so the integration branch exists for worktrees and diffs.
102
+ - uses: actions/checkout@v4
103
+ with:
104
+ token: ${{ steps.app.outputs.token || github.token }}
105
+ fetch-depth: 0
106
+
107
+ - name: Foundry
108
+ id: foundry
109
+ uses: joyntshops/foundry@main
110
+ with:
111
+ github-token: ${{ steps.app.outputs.token || github.token }}
112
+ claude-code-oauth-token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
113
+
114
+ - name: Keep the agent transcript
115
+ if: always() && steps.foundry.outputs.log-dir != ''
116
+ uses: actions/upload-artifact@v4
117
+ with:
118
+ name: foundry-issue-${{ steps.foundry.outputs.issue }}-run-${{ github.run_id }}
119
+ path: ${{ steps.foundry.outputs.log-dir }}
120
+ if-no-files-found: ignore
121
+ retention-days: 30
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env bash
2
+ # Foundry preview `up_command` for a repo that Vercel's GitHub integration
3
+ # already deploys: print the URL of the Vercel deployment that built
4
+ # $FOUNDRY_SHA, waiting for it to succeed. No Vercel credential is needed.
5
+ #
6
+ # Vercel records each deployment in GitHub's Deployments API as
7
+ # "Preview – <project>" or "Production – <project>", with the deployment URL in
8
+ # `environment_url`. Reading that needs only the job's GitHub token. Each
9
+ # commit gets its own URL, so a relaunched task is never verified against a
10
+ # stale page, and no `down_command` is needed: Vercel expires previews itself.
11
+ #
12
+ # When the integration branch is the project's production branch, its commits
13
+ # get a Production deployment, whose generated hostname may not serve a
14
+ # host-keyed app correctly. For those, the project's production alias is
15
+ # printed instead (VERCEL_PRODUCTION_URL); it serves exactly this commit once
16
+ # the deployment has succeeded. This is the case for a promotion PR.
17
+ #
18
+ # Env: FOUNDRY_SHA and GH_TOKEN (set by Foundry's job), GITHUB_REPOSITORY (set by Actions),
19
+ # VERCEL_PREVIEW_PROJECT (required: the Vercel project name),
20
+ # VERCEL_PRODUCTION_URL (required only if the integration branch is the project's production branch),
21
+ # VERCEL_PREVIEW_TIMEOUT (seconds, default 900).
22
+ set -u
23
+
24
+ REPO="${GITHUB_REPOSITORY:?GITHUB_REPOSITORY is not set}"
25
+ PROJECT="${VERCEL_PREVIEW_PROJECT:?VERCEL_PREVIEW_PROJECT is not set}"
26
+ PRODUCTION_URL="${VERCEL_PRODUCTION_URL:-}"
27
+ SHA="${FOUNDRY_SHA:?FOUNDRY_SHA is not set}"
28
+ DEADLINE=$((SECONDS + ${VERCEL_PREVIEW_TIMEOUT:-900}))
29
+
30
+ while [ "$SECONDS" -lt "$DEADLINE" ]; do
31
+ # Deployments for this commit, newest first; keep the one for our project.
32
+ found=$(gh api "repos/$REPO/deployments?sha=$SHA&per_page=20" \
33
+ --jq "[.[] | select(.environment | endswith(\"– $PROJECT\"))] | sort_by(.created_at) | last | select(. != null) | \"\(.id) \(.environment)\"" 2>/dev/null || true)
34
+ if [ -z "$found" ]; then
35
+ echo "Waiting for Vercel: no deployment of ${SHA:0:7} on $PROJECT recorded yet" >&2
36
+ sleep 20; continue
37
+ fi
38
+ dep="${found%% *}"; environment="${found#* }"
39
+ # Latest status wins: success carries the URL; failure/error/inactive end it.
40
+ status=$(gh api "repos/$REPO/deployments/$dep/statuses?per_page=1" \
41
+ --jq '.[0] | "\(.state) \(.environment_url // .target_url // "")"' 2>/dev/null || echo "unknown ")
42
+ state="${status%% *}"; url="${status#* }"
43
+ case "$state" in
44
+ success)
45
+ case "$environment" in
46
+ Production*)
47
+ if [ -n "$PRODUCTION_URL" ]; then
48
+ echo "Deployment $dep of ${SHA:0:7} is the production deployment of $PROJECT; using its alias $PRODUCTION_URL" >&2
49
+ echo "$PRODUCTION_URL"; exit 0
50
+ fi ;;
51
+ esac
52
+ [ -n "$url" ] && { echo "$url"; exit 0; }
53
+ echo "Deployment $dep succeeded but has no URL" >&2; exit 1 ;;
54
+ failure|error|inactive)
55
+ echo "Vercel deployment of ${SHA:0:7} on $PROJECT ended in '$state' (deployment $dep)" >&2; exit 1 ;;
56
+ *)
57
+ echo "Waiting for Vercel: deployment $dep of ${SHA:0:7} on $PROJECT is '${state:-pending}'" >&2; sleep 20 ;;
58
+ esac
59
+ done
60
+ echo "Timed out waiting for the Vercel deployment of ${SHA:0:7} on $PROJECT" >&2
61
+ exit 1
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.