@ipul-labs/forge 1.14.0 → 1.15.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 +152 -96
  2. package/package.json +14 -22
  3. package/server/forge/core/ForgeAgent.js +42 -15
  4. package/server/forge/core/ForgeAgent.test.js +179 -0
  5. package/server/forge/core/claudeClient.js +27 -5
  6. package/server/forge/core/configStore.js +15 -0
  7. package/server/forge/core/configStore.test.js +89 -0
  8. package/server/forge/core/localRepo.js +4 -2
  9. package/server/forge/core/prompts.js +124 -17
  10. package/server/forge/core/prompts.test.js +219 -0
  11. package/server/forge/core/providers/azuredevops.js +4 -3
  12. package/server/forge/core/providers/github.js +3 -4
  13. package/server/forge/core/providers/gitlab.js +6 -6
  14. package/server/forge/core/validator/clone.js +3 -2
  15. package/server/forge/core/validator.js +3 -2
  16. package/server/forge/routes.js +10 -7
  17. package/dist-lib/favicon.svg +0 -8
  18. package/dist-lib/index.d.ts +0 -1
  19. package/dist-lib/style.css +0 -1
  20. package/dist-lib/ui.d.ts +0 -2
  21. package/dist-lib/ui.js +0 -5946
  22. package/dist-lib/views/Forge/ForgeDashboard.d.ts +0 -6
  23. package/dist-lib/views/Forge/activeJobs.d.ts +0 -29
  24. package/dist-lib/views/Forge/analysisCache.d.ts +0 -64
  25. package/dist-lib/views/Forge/api.d.ts +0 -4
  26. package/dist-lib/views/Forge/components/AnalysisProgress.d.ts +0 -13
  27. package/dist-lib/views/Forge/components/CITerminal.d.ts +0 -44
  28. package/dist-lib/views/Forge/components/DiffViewer.d.ts +0 -37
  29. package/dist-lib/views/Forge/components/ForgeConnect.d.ts +0 -6
  30. package/dist-lib/views/Forge/components/IssueList.d.ts +0 -28
  31. package/dist-lib/views/Forge/components/MRStatus.d.ts +0 -9
  32. package/dist-lib/views/Forge/components/NewTaskModal.d.ts +0 -1
  33. package/dist-lib/views/Forge/components/OpenMRList.d.ts +0 -11
  34. package/dist-lib/views/Forge/components/PipelineStatus.d.ts +0 -12
  35. package/dist-lib/views/Forge/components/PipelinesList.d.ts +0 -9
  36. package/dist-lib/views/Forge/components/RolloutStatus.d.ts +0 -5
  37. package/dist-lib/views/Forge/components/UsageWidget.d.ts +0 -8
  38. package/dist-lib/views/Forge/components/ValidationPanel.d.ts +0 -22
  39. package/dist-lib/views/Forge/context/ForgeProvider.d.ts +0 -23
  40. package/dist-lib/views/Forge/context/ForgeRouterContext.d.ts +0 -22
  41. package/dist-lib/views/Forge/hooks/useConfig.d.ts +0 -54
  42. package/dist-lib/views/Forge/hooks/useForgeDashboard.d.ts +0 -107
  43. package/dist-lib/views/Forge/hooks/useForgeQuota.d.ts +0 -22
  44. package/dist-lib/views/Forge/phases/AnalyzingView.d.ts +0 -1
  45. package/dist-lib/views/Forge/phases/IdleView.d.ts +0 -1
  46. package/dist-lib/views/Forge/phases/MonitoringIssueTab.d.ts +0 -1
  47. package/dist-lib/views/Forge/phases/MonitoringPipelineTab.d.ts +0 -1
  48. package/dist-lib/views/Forge/phases/MonitoringView.d.ts +0 -1
  49. package/dist-lib/views/Forge/phases/ReviewingView.d.ts +0 -1
  50. package/dist-lib/views/Forge/phases/SelectedIssueTab.d.ts +0 -11
  51. package/dist-lib/views/Forge/phases/SelectedMRTab.d.ts +0 -1
  52. package/dist-lib/views/Forge/phases/SelectedView.d.ts +0 -1
  53. package/dist-lib/views/Forge/phases/shared/CloseIssueConfirm.d.ts +0 -1
  54. package/dist-lib/views/Forge/phases/shared/DetailTabs.d.ts +0 -14
  55. package/dist-lib/views/Forge/phases/shared/EnvironmentsPanel.d.ts +0 -9
  56. package/dist-lib/views/Forge/phases/shared/ForgeActivity.d.ts +0 -1
  57. package/dist-lib/views/Forge/phases/shared/IssueHeaderBlock.d.ts +0 -13
  58. package/dist-lib/views/Forge/phases/shared/MergedMRList.d.ts +0 -4
  59. package/dist-lib/views/Forge/phases/shared/PreviousAnalyses.d.ts +0 -1
  60. package/dist-lib/views/Forge/phases/shared/ResolutionCheckPanel.d.ts +0 -6
  61. package/dist-lib/views/Forge/settings/ConnectionRow.d.ts +0 -16
  62. package/dist-lib/views/Forge/settings/ConnectionsSection.d.ts +0 -7
  63. package/dist-lib/views/Forge/settings/DefaultsSection.d.ts +0 -7
  64. package/dist-lib/views/Forge/settings/ReposSection.d.ts +0 -7
  65. package/dist-lib/views/Forge/settings/SettingsView.d.ts +0 -1
  66. package/dist-lib/views/Forge/shell/ConfigBar.d.ts +0 -1
  67. package/dist-lib/views/Forge/shell/ForgeRouter.d.ts +0 -9
  68. package/dist-lib/views/Forge/shell/ForgeShell.d.ts +0 -7
  69. package/dist-lib/views/Forge/shell/Sidebar.d.ts +0 -1
  70. package/dist-lib/views/Forge/shell/SidebarFooterMenu.d.ts +0 -1
  71. package/dist-lib/views/Forge/shell/SidebarNav.d.ts +0 -1
  72. package/dist-lib/views/Forge/shell/SidebarNavItem.d.ts +0 -10
  73. package/dist-lib/views/Forge/shell/TopBar.d.ts +0 -5
  74. package/dist-lib/views/Forge/types.d.ts +0 -235
  75. package/dist-lib/views/Forge/utils.d.ts +0 -11
@@ -1,13 +0,0 @@
1
- interface Props {
2
- editing: boolean;
3
- editTitle: string;
4
- setEditTitle: (t: string) => void;
5
- onStartEdit?: () => void;
6
- }
7
- /**
8
- * Issue summary header: id/labels + title (plain or editable input) + author.
9
- * `onStartEdit` toggles edit mode. When omitted, the "Edit" button is hidden
10
- * (monitoring view).
11
- */
12
- export declare function IssueHeaderBlock({ editing, editTitle, setEditTitle, onStartEdit }: Props): import("react/jsx-runtime").JSX.Element | null;
13
- export {};
@@ -1,4 +0,0 @@
1
- import { MergedMR } from '../../types';
2
- export declare function MergedMRList({ mrs }: {
3
- mrs: MergedMR[];
4
- }): import("react/jsx-runtime").JSX.Element | null;
@@ -1 +0,0 @@
1
- export declare function PreviousAnalyses(): import("react/jsx-runtime").JSX.Element | null;
@@ -1,6 +0,0 @@
1
- interface Props {
2
- /** Show a "Try Again" button when unresolved. Monitoring view sets this. */
3
- showTryAgain?: boolean;
4
- }
5
- export declare function ResolutionCheckPanel({ showTryAgain }: Props): import("react/jsx-runtime").JSX.Element;
6
- export {};
@@ -1,16 +0,0 @@
1
- import { PublicConnection } from '../hooks/useConfig';
2
- export type ProviderKey = "gitlab" | "github" | "azuredevops";
3
- interface Props {
4
- provider: ProviderKey;
5
- connection: PublicConnection & {
6
- baseUrl?: string;
7
- };
8
- newToken: string;
9
- setNewToken: (v: string) => void;
10
- clearToken: boolean;
11
- setClearToken: (v: boolean) => void;
12
- baseUrl?: string;
13
- setBaseUrl?: (v: string) => void;
14
- }
15
- export declare function ConnectionRow({ provider, connection, newToken, setNewToken, clearToken, setClearToken, baseUrl, setBaseUrl, }: Props): import("react/jsx-runtime").JSX.Element;
16
- export {};
@@ -1,7 +0,0 @@
1
- import { ConfigPatch, ForgeConfig } from '../hooks/useConfig';
2
- interface Props {
3
- connections: ForgeConfig["connections"];
4
- onSave: (patch: ConfigPatch["connections"]) => Promise<void>;
5
- }
6
- export declare function ConnectionsSection({ connections, onSave }: Props): import("react/jsx-runtime").JSX.Element;
7
- export {};
@@ -1,7 +0,0 @@
1
- import { ForgeConfig } from '../hooks/useConfig';
2
- interface Props {
3
- defaults: ForgeConfig["defaults"];
4
- onSave: (defaults: ForgeConfig["defaults"]) => Promise<void>;
5
- }
6
- export declare function DefaultsSection({ defaults, onSave }: Props): import("react/jsx-runtime").JSX.Element;
7
- export {};
@@ -1,7 +0,0 @@
1
- import { ForgeRepo } from '../types';
2
- interface Props {
3
- repos: ForgeRepo[];
4
- onSave: (repos: ForgeRepo[]) => Promise<void>;
5
- }
6
- export declare function ReposSection({ repos, onSave }: Props): import("react/jsx-runtime").JSX.Element;
7
- export {};
@@ -1 +0,0 @@
1
- export declare function SettingsView(): import("react/jsx-runtime").JSX.Element | null;
@@ -1 +0,0 @@
1
- export declare function ConfigBar(): import("react/jsx-runtime").JSX.Element;
@@ -1,9 +0,0 @@
1
- /**
2
- * Headless component that keeps the URL and the dashboard phase in sync.
3
- *
4
- * - activeDetailTab ← URL (issue | mr)
5
- * - phase → URL (push new history entries for major transitions)
6
- * - URL → phase (back/forward swaps restore the correct phase)
7
- * - URL → issue (initial mount with a deep link fetches + restores analysis)
8
- */
9
- export declare function ForgeRouter(): null;
@@ -1,7 +0,0 @@
1
- import { ReactNode } from 'react';
2
- interface Props {
3
- popoutUrl?: string;
4
- children: ReactNode;
5
- }
6
- export declare function ForgeShell({ popoutUrl, children }: Props): import("react/jsx-runtime").JSX.Element;
7
- export {};
@@ -1 +0,0 @@
1
- export declare function Sidebar(): import("react/jsx-runtime").JSX.Element;
@@ -1 +0,0 @@
1
- export declare function SidebarFooterMenu(): import("react/jsx-runtime").JSX.Element;
@@ -1 +0,0 @@
1
- export declare function SidebarNav(): import("react/jsx-runtime").JSX.Element;
@@ -1,10 +0,0 @@
1
- import { ReactNode } from 'react';
2
- interface Props {
3
- label: string;
4
- icon?: ReactNode;
5
- active: boolean;
6
- onClick: () => void;
7
- badgeCount?: number;
8
- }
9
- export declare function SidebarNavItem({ label, icon, active, onClick, badgeCount }: Props): import("react/jsx-runtime").JSX.Element;
10
- export {};
@@ -1,5 +0,0 @@
1
- interface Props {
2
- popoutUrl?: string;
3
- }
4
- export declare function TopBar({ popoutUrl }: Props): import("react/jsx-runtime").JSX.Element;
5
- export {};
@@ -1,235 +0,0 @@
1
- export interface GitLabIssue {
2
- iid: number;
3
- title: string;
4
- description: string | null;
5
- labels: string[];
6
- author: {
7
- name: string;
8
- };
9
- created_at: string;
10
- web_url: string;
11
- /** Forge branch attached to this issue, if one exists on the remote. */
12
- forgeBranch?: string;
13
- /** Commits on `forgeBranch` not yet on main. `0` = stale / no pending changes.
14
- * `null` = could not be computed. `undefined` = no forgeBranch. */
15
- branchAhead?: number | null;
16
- /** Recently merged MR whose description closes this issue (`Closes #N` /
17
- * `Fixes #N` / `Resolves #N`). Present → the fix almost certainly shipped. */
18
- likelyFixedByMr?: {
19
- iid: number;
20
- webUrl: string;
21
- };
22
- }
23
- /**
24
- * Ephemeral review-app environment attached to a forge branch. Shape comes
25
- * from the SCM provider's normalised `NormalEnvironment` plus the branch
26
- * name we matched on (server-side) so the UI can colocate it with the
27
- * branch's pipeline. `external_url` is the preview URL (null while the
28
- * deploy is still in-flight).
29
- */
30
- export interface ForgeEnvironment {
31
- id: number;
32
- name: string;
33
- state: "available" | "stopping" | "stopped" | string;
34
- external_url: string | null;
35
- ref: string | null;
36
- updated_at: string | null;
37
- web_url: string | null;
38
- branchName: string;
39
- }
40
- export interface ForgeChange {
41
- /** Repo id this change belongs to. Optional for backward compat with single-repo analyses. */
42
- repo?: string;
43
- file: string;
44
- action: "create" | "modify" | "delete";
45
- proposed: string;
46
- original: string | null;
47
- summary: string;
48
- }
49
- export interface AnalysisResult {
50
- issue: GitLabIssue;
51
- mrTitle?: string;
52
- explanation: string;
53
- reasoning: string;
54
- changes: ForgeChange[];
55
- /** The set of repos the analysis was run against (primary first). */
56
- repos?: string[];
57
- }
58
- export interface ApplicationResult {
59
- repo: string;
60
- branchName: string;
61
- mr: {
62
- iid: number;
63
- web_url: string;
64
- title: string;
65
- } | null;
66
- pipelineUrl: string | null;
67
- }
68
- export interface ApplyResult {
69
- applications: ApplicationResult[];
70
- }
71
- export interface OpenMRDetail {
72
- iid: number;
73
- title: string;
74
- web_url: string;
75
- source_branch: string;
76
- target_branch: string;
77
- state: string;
78
- has_conflicts: boolean;
79
- rebase_in_progress: boolean;
80
- merge_status: string;
81
- detailed_merge_status: string | null;
82
- }
83
- export interface MRDiff {
84
- old_path: string;
85
- new_path: string;
86
- diff: string;
87
- new_file: boolean;
88
- renamed_file: boolean;
89
- deleted_file: boolean;
90
- }
91
- export type ForgeMRState = "open" | "merged" | "closed";
92
- export interface ForgeMRSummary {
93
- iid: number;
94
- title: string;
95
- web_url: string;
96
- source_branch: string;
97
- target_branch: string;
98
- state?: string;
99
- created_at: string;
100
- merged_at?: string | null;
101
- author: {
102
- name: string;
103
- };
104
- has_conflicts: boolean;
105
- merge_status: string;
106
- pipeline: {
107
- status: string;
108
- web_url: string;
109
- } | null;
110
- }
111
- export interface MergedMR {
112
- iid: number;
113
- web_url: string;
114
- title: string;
115
- merged_at: string;
116
- branchName: string;
117
- merge_commit_sha?: string | null;
118
- /** The post-merge pipeline that ran on the merge commit, if any. */
119
- pipeline?: {
120
- id: number;
121
- status: string;
122
- web_url: string;
123
- } | null;
124
- }
125
- export interface ProgressStep {
126
- step: string;
127
- message: string;
128
- }
129
- export interface ForgeModel {
130
- id: string;
131
- label: string;
132
- provider: string;
133
- rates?: {
134
- input: number;
135
- output: number;
136
- };
137
- }
138
- export type ForgeProjectType = "auto" | "node" | "go";
139
- export interface ForgeRepo {
140
- id: string;
141
- label: string;
142
- projectType?: ForgeProjectType;
143
- }
144
- export interface ForgeAgentBackend {
145
- id: "claude" | "openclaw";
146
- label: string;
147
- configured: boolean;
148
- }
149
- export interface ResolutionCheck {
150
- resolved: boolean;
151
- reasoning: string;
152
- cost?: number;
153
- serviceTier?: string;
154
- inputTokens?: number;
155
- outputTokens?: number;
156
- }
157
- export interface ForgeUsage {
158
- sessionCost: number;
159
- serviceTier: string;
160
- inputTokens: number;
161
- outputTokens: number;
162
- cacheCreationTokens: number;
163
- cacheReadTokens: number;
164
- }
165
- export interface ForgeRateLimit {
166
- tokensLimit: number | null;
167
- tokensRemaining: number | null;
168
- tokensReset: string | null;
169
- requestsLimit: number | null;
170
- requestsRemaining: number | null;
171
- requestsReset: string | null;
172
- }
173
- export interface CILogEntry {
174
- ts: string;
175
- message: string;
176
- level?: "info" | "warn" | "error" | "debug" | "success";
177
- }
178
- export type ValidationStepKey = string;
179
- export type ValidationStatus = "idle" | "running" | "passed" | "failed" | "skipped";
180
- export interface ValidationStepState {
181
- status: ValidationStatus;
182
- passed?: boolean;
183
- skipped?: boolean;
184
- exitCode?: number;
185
- durationMs?: number;
186
- tail?: string;
187
- logs: CILogEntry[];
188
- }
189
- export interface RepoValidationState {
190
- repo: string;
191
- projectType?: ForgeProjectType;
192
- /** Per-step status, keyed by ValidationStepKey. Only populated for steps
193
- * the runner actually emitted — missing entries are hidden in the UI. */
194
- steps: Record<string, ValidationStepState>;
195
- /** Canonical step order declared by the runner (e.g. fmt/vet/build/test
196
- * for Go). Drives row order; falls back to event-arrival order when the
197
- * backend hasn't sent one. */
198
- stepOrder?: ValidationStepKey[];
199
- /** Steps that get a "Fix with AI" button when they fail. Runner-specific. */
200
- fixableSteps?: ValidationStepKey[];
201
- /** Per-repo summary; set when the backend emits `repo_result`. */
202
- result?: {
203
- allPassed: boolean;
204
- checkedAt: string;
205
- };
206
- /** True when the validator skipped this repo (e.g. misattributed change).
207
- * Renders an explainer instead of the per-step rows. */
208
- skipped?: boolean;
209
- skipReason?: string;
210
- }
211
- export interface ValidationState {
212
- /** Aggregate result across every repo — drives the headline + auto-push. */
213
- result: null | {
214
- repo: string;
215
- allPassed: boolean;
216
- checkedAt: string;
217
- };
218
- /** Per-repo state. One block is rendered for each entry, in `repoOrder`. */
219
- byRepo: Record<string, RepoValidationState>;
220
- /** Insertion order of repos (primary first). */
221
- repoOrder: string[];
222
- /** Top-level log lines emitted before any per-repo block is open
223
- * (candidate cloning, attribution plan, drop reasons). Renders as a
224
- * compact strip at the top of the panel. */
225
- aggregateLogs: {
226
- ts: string;
227
- message: string;
228
- }[];
229
- /** True when the proposal has changed since the last validation ran — the
230
- * rows stay visible but get an "outdated" banner so scroll position is
231
- * preserved instead of the panel collapsing. */
232
- stale: boolean;
233
- }
234
- export type { StoredAnalysis } from './analysisCache';
235
- export type Phase = "connect" | "idle" | "selected" | "analyzing" | "reviewing" | "applying" | "monitoring";
@@ -1,11 +0,0 @@
1
- import { ProgressStep } from './types';
2
- /**
3
- * Opens an EventSource, parses each message as JSON, and calls onMessage.
4
- * Returns the EventSource so the caller can close it.
5
- */
6
- export declare function openSSE(url: string, onMessage: (event: Record<string, unknown>) => void, onError: () => void): EventSource;
7
- /**
8
- * Replaces an existing step with the same key or appends a new one.
9
- * Keeps the list ordered by arrival so the latest step is always last.
10
- */
11
- export declare function upsertProgressStep(prev: ProgressStep[], step: string, message: string): ProgressStep[];