@ipul-labs/forge 1.21.2 → 1.35.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.
- package/LICENSE +21 -0
- package/README.md +161 -78
- package/dist/apple-touch-icon.png +0 -0
- package/dist/assets/index-BmEuPeOG.js +27 -0
- package/dist/assets/index-CSH1OQYQ.css +1 -0
- package/dist/boot-check.js +98 -0
- package/dist/favicon.svg +8 -0
- package/dist/icon-192.png +0 -0
- package/dist/icon-512.png +0 -0
- package/dist/icon.svg +12 -0
- package/dist/index.html +33 -0
- package/dist/manifest.webmanifest +18 -0
- package/dist/theme-init.js +11 -0
- package/lib/bin/cli/analyze.d.ts.map +1 -1
- package/lib/bin/cli/analyze.js +3 -44
- package/lib/bin/cli/analyze.js.map +1 -1
- package/lib/bin/cli/apply.d.ts.map +1 -1
- package/lib/bin/cli/apply.js +2 -20
- package/lib/bin/cli/apply.js.map +1 -1
- package/lib/bin/cli/cifix.d.ts.map +1 -1
- package/lib/bin/cli/cifix.js +4 -28
- package/lib/bin/cli/cifix.js.map +1 -1
- package/lib/bin/cli/close.d.ts.map +1 -1
- package/lib/bin/cli/close.js +2 -33
- package/lib/bin/cli/close.js.map +1 -1
- package/lib/bin/cli/createIssue.d.ts.map +1 -1
- package/lib/bin/cli/createIssue.js +3 -12
- package/lib/bin/cli/createIssue.js.map +1 -1
- package/lib/bin/cli/doctor.d.ts.map +1 -1
- package/lib/bin/cli/doctor.js +3 -4
- package/lib/bin/cli/doctor.js.map +1 -1
- package/lib/bin/cli/init.js +1 -10
- package/lib/bin/cli/init.js.map +1 -1
- package/lib/bin/cli/issue.d.ts.map +1 -1
- package/lib/bin/cli/issue.js +3 -12
- package/lib/bin/cli/issue.js.map +1 -1
- package/lib/bin/cli/issues.d.ts.map +1 -1
- package/lib/bin/cli/issues.js +3 -12
- package/lib/bin/cli/issues.js.map +1 -1
- package/lib/bin/cli/merge.d.ts.map +1 -1
- package/lib/bin/cli/merge.js +4 -20
- package/lib/bin/cli/merge.js.map +1 -1
- package/lib/bin/cli/refine.d.ts.map +1 -1
- package/lib/bin/cli/refine.js +2 -26
- package/lib/bin/cli/refine.js.map +1 -1
- package/lib/bin/cli/repl.d.ts.map +1 -1
- package/lib/bin/cli/repl.js +4 -13
- package/lib/bin/cli/repl.js.map +1 -1
- package/lib/bin/cli/repos.d.ts.map +1 -1
- package/lib/bin/cli/repos.js +1 -11
- package/lib/bin/cli/repos.js.map +1 -1
- package/lib/bin/cli/resetPassword.d.ts +21 -0
- package/lib/bin/cli/resetPassword.d.ts.map +1 -0
- package/lib/bin/cli/resetPassword.js +69 -0
- package/lib/bin/cli/resetPassword.js.map +1 -0
- package/lib/bin/cli/resolution.d.ts.map +1 -1
- package/lib/bin/cli/resolution.js +2 -19
- package/lib/bin/cli/resolution.js.map +1 -1
- package/lib/bin/cli/serverClient.d.ts +2 -0
- package/lib/bin/cli/serverClient.d.ts.map +1 -1
- package/lib/bin/cli/serverClient.js +8 -4
- package/lib/bin/cli/serverClient.js.map +1 -1
- package/lib/bin/cli/session.d.ts.map +1 -1
- package/lib/bin/cli/session.js.map +1 -1
- package/lib/bin/cli/sessionStore.d.ts +1 -1
- package/lib/bin/cli/sessionStore.js +2 -2
- package/lib/bin/cli/sessionStore.js.map +1 -1
- package/lib/bin/cli/ship.d.ts.map +1 -1
- package/lib/bin/cli/ship.js +15 -23
- package/lib/bin/cli/ship.js.map +1 -1
- package/lib/bin/cli/update.d.ts.map +1 -1
- package/lib/bin/cli/update.js +34 -28
- package/lib/bin/cli/update.js.map +1 -1
- package/lib/bin/cli/updatePlan.d.ts +30 -0
- package/lib/bin/cli/updatePlan.d.ts.map +1 -0
- package/lib/bin/cli/updatePlan.js +50 -0
- package/lib/bin/cli/updatePlan.js.map +1 -0
- package/lib/bin/cli/utils.d.ts +3 -0
- package/lib/bin/cli/utils.d.ts.map +1 -1
- package/lib/bin/cli/utils.js +7 -23
- package/lib/bin/cli/utils.js.map +1 -1
- package/lib/bin/cli/validate.d.ts.map +1 -1
- package/lib/bin/cli/validate.js +3 -25
- package/lib/bin/cli/validate.js.map +1 -1
- package/lib/bin/cli/watch.d.ts.map +1 -1
- package/lib/bin/cli/watch.js +3 -12
- package/lib/bin/cli/watch.js.map +1 -1
- package/lib/bin/forge-agent.js +10 -22
- package/lib/bin/forge-agent.js.map +1 -1
- package/lib/server/app.d.ts +24 -0
- package/lib/server/app.d.ts.map +1 -0
- package/lib/server/app.js +58 -0
- package/lib/server/app.js.map +1 -0
- package/lib/server/forge/analyses/analysisStore.d.ts +53 -0
- package/lib/server/forge/analyses/analysisStore.d.ts.map +1 -0
- package/lib/server/forge/analyses/analysisStore.js +77 -0
- package/lib/server/forge/analyses/analysisStore.js.map +1 -0
- package/lib/server/forge/auth/apiTokens.d.ts +34 -0
- package/lib/server/forge/auth/apiTokens.d.ts.map +1 -0
- package/lib/server/forge/auth/apiTokens.js +44 -0
- package/lib/server/forge/auth/apiTokens.js.map +1 -0
- package/lib/server/forge/auth/auditLog.d.ts +36 -0
- package/lib/server/forge/auth/auditLog.d.ts.map +1 -0
- package/lib/server/forge/auth/auditLog.js +56 -0
- package/lib/server/forge/auth/auditLog.js.map +1 -0
- package/lib/server/forge/auth/authConfig.d.ts +13 -0
- package/lib/server/forge/auth/authConfig.d.ts.map +1 -0
- package/lib/server/forge/auth/authConfig.js +37 -0
- package/lib/server/forge/auth/authConfig.js.map +1 -0
- package/lib/server/forge/auth/createAuth.d.ts +130 -0
- package/lib/server/forge/auth/createAuth.d.ts.map +1 -0
- package/lib/server/forge/auth/createAuth.js +387 -0
- package/lib/server/forge/auth/createAuth.js.map +1 -0
- package/lib/server/forge/auth/middleware.d.ts +10 -0
- package/lib/server/forge/auth/middleware.d.ts.map +1 -0
- package/lib/server/forge/auth/middleware.js +22 -0
- package/lib/server/forge/auth/middleware.js.map +1 -0
- package/lib/server/forge/auth/oidc.d.ts +38 -0
- package/lib/server/forge/auth/oidc.d.ts.map +1 -0
- package/lib/server/forge/auth/oidc.js +63 -0
- package/lib/server/forge/auth/oidc.js.map +1 -0
- package/lib/server/forge/auth/passwords.d.ts +7 -0
- package/lib/server/forge/auth/passwords.d.ts.map +1 -0
- package/lib/server/forge/auth/passwords.js +28 -0
- package/lib/server/forge/auth/passwords.js.map +1 -0
- package/lib/server/forge/auth/resetPassword.d.ts +14 -0
- package/lib/server/forge/auth/resetPassword.d.ts.map +1 -0
- package/lib/server/forge/auth/resetPassword.js +29 -0
- package/lib/server/forge/auth/resetPassword.js.map +1 -0
- package/lib/server/forge/auth/roles.d.ts +7 -0
- package/lib/server/forge/auth/roles.d.ts.map +1 -0
- package/lib/server/forge/auth/roles.js +15 -0
- package/lib/server/forge/auth/roles.js.map +1 -0
- package/lib/server/forge/auth/sessions.d.ts +27 -0
- package/lib/server/forge/auth/sessions.d.ts.map +1 -0
- package/lib/server/forge/auth/sessions.js +37 -0
- package/lib/server/forge/auth/sessions.js.map +1 -0
- package/lib/server/forge/auth/testHarness.d.ts +104 -0
- package/lib/server/forge/auth/testHarness.d.ts.map +1 -0
- package/lib/server/forge/auth/testHarness.js +53 -0
- package/lib/server/forge/auth/testHarness.js.map +1 -0
- package/lib/server/forge/auth/tokenHash.d.ts +3 -0
- package/lib/server/forge/auth/tokenHash.d.ts.map +1 -0
- package/lib/server/forge/auth/tokenHash.js +4 -0
- package/lib/server/forge/auth/tokenHash.js.map +1 -0
- package/lib/server/forge/auth/users.d.ts +51 -0
- package/lib/server/forge/auth/users.d.ts.map +1 -0
- package/lib/server/forge/auth/users.js +118 -0
- package/lib/server/forge/auth/users.js.map +1 -0
- package/lib/server/forge/core/ForgeAgent.d.ts +58 -1
- package/lib/server/forge/core/ForgeAgent.d.ts.map +1 -1
- package/lib/server/forge/core/ForgeAgent.js +280 -32
- package/lib/server/forge/core/ForgeAgent.js.map +1 -1
- package/lib/server/forge/core/agentClient.d.ts +7 -5
- package/lib/server/forge/core/agentClient.d.ts.map +1 -1
- package/lib/server/forge/core/agentClient.js +11 -15
- package/lib/server/forge/core/agentClient.js.map +1 -1
- package/lib/server/forge/core/agentMode.d.ts +38 -0
- package/lib/server/forge/core/agentMode.d.ts.map +1 -0
- package/lib/server/forge/core/agentMode.js +43 -0
- package/lib/server/forge/core/agentMode.js.map +1 -0
- package/lib/server/forge/core/claudeClient.d.ts +63 -0
- package/lib/server/forge/core/claudeClient.d.ts.map +1 -1
- package/lib/server/forge/core/claudeClient.js +142 -50
- package/lib/server/forge/core/claudeClient.js.map +1 -1
- package/lib/server/forge/core/configStore.d.ts +12 -1
- package/lib/server/forge/core/configStore.d.ts.map +1 -1
- package/lib/server/forge/core/configStore.js +39 -2
- package/lib/server/forge/core/configStore.js.map +1 -1
- package/lib/server/forge/core/dependencyPaths.d.ts +19 -0
- package/lib/server/forge/core/dependencyPaths.d.ts.map +1 -0
- package/lib/server/forge/core/dependencyPaths.js +32 -0
- package/lib/server/forge/core/dependencyPaths.js.map +1 -0
- package/lib/server/forge/core/evidence.d.ts +43 -0
- package/lib/server/forge/core/evidence.d.ts.map +1 -0
- package/lib/server/forge/core/evidence.js +108 -0
- package/lib/server/forge/core/evidence.js.map +1 -0
- package/lib/server/forge/core/jobs.d.ts +2 -0
- package/lib/server/forge/core/jobs.d.ts.map +1 -1
- package/lib/server/forge/core/jobs.js +8 -0
- package/lib/server/forge/core/jobs.js.map +1 -1
- package/lib/server/forge/core/localRepo.d.ts +48 -7
- package/lib/server/forge/core/localRepo.d.ts.map +1 -1
- package/lib/server/forge/core/localRepo.js +123 -69
- package/lib/server/forge/core/localRepo.js.map +1 -1
- package/lib/server/forge/core/prompts.d.ts +20 -0
- package/lib/server/forge/core/prompts.d.ts.map +1 -1
- package/lib/server/forge/core/prompts.js +59 -0
- package/lib/server/forge/core/prompts.js.map +1 -1
- package/lib/server/forge/core/providers/azuredevops.d.ts +4 -2
- package/lib/server/forge/core/providers/azuredevops.d.ts.map +1 -1
- package/lib/server/forge/core/providers/azuredevops.js +12 -2
- package/lib/server/forge/core/providers/azuredevops.js.map +1 -1
- package/lib/server/forge/core/providers/base.d.ts +29 -4
- package/lib/server/forge/core/providers/base.d.ts.map +1 -1
- package/lib/server/forge/core/providers/base.js +21 -3
- package/lib/server/forge/core/providers/base.js.map +1 -1
- package/lib/server/forge/core/providers/github.d.ts +7 -7
- package/lib/server/forge/core/providers/github.d.ts.map +1 -1
- package/lib/server/forge/core/providers/github.js +13 -4
- package/lib/server/forge/core/providers/github.js.map +1 -1
- package/lib/server/forge/core/providers/gitlab.d.ts +20 -3
- package/lib/server/forge/core/providers/gitlab.d.ts.map +1 -1
- package/lib/server/forge/core/providers/gitlab.js +65 -5
- package/lib/server/forge/core/providers/gitlab.js.map +1 -1
- package/lib/server/forge/core/providers/types.d.ts +20 -0
- package/lib/server/forge/core/providers/types.d.ts.map +1 -1
- package/lib/server/forge/core/secretBox.d.ts +17 -0
- package/lib/server/forge/core/secretBox.d.ts.map +1 -0
- package/lib/server/forge/core/secretBox.js +74 -0
- package/lib/server/forge/core/secretBox.js.map +1 -0
- package/lib/server/forge/core/types.d.ts +8 -1
- package/lib/server/forge/core/types.d.ts.map +1 -1
- package/lib/server/forge/core/validator/clone.d.ts +5 -4
- package/lib/server/forge/core/validator/clone.d.ts.map +1 -1
- package/lib/server/forge/core/validator/clone.js +6 -86
- package/lib/server/forge/core/validator/clone.js.map +1 -1
- package/lib/server/forge/core/validator/cmd.d.ts.map +1 -1
- package/lib/server/forge/core/validator/cmd.js +4 -1
- package/lib/server/forge/core/validator/cmd.js.map +1 -1
- package/lib/server/forge/core/validator/projectType.d.ts.map +1 -1
- package/lib/server/forge/core/validator/projectType.js +2 -1
- package/lib/server/forge/core/validator/projectType.js.map +1 -1
- package/lib/server/forge/core/validator/runners/node.d.ts.map +1 -1
- package/lib/server/forge/core/validator/runners/node.js +6 -2
- package/lib/server/forge/core/validator/runners/node.js.map +1 -1
- package/lib/server/forge/core/validator.d.ts.map +1 -1
- package/lib/server/forge/core/validator.js +28 -22
- package/lib/server/forge/core/validator.js.map +1 -1
- package/lib/server/forge/core/workspaces.d.ts +70 -0
- package/lib/server/forge/core/workspaces.d.ts.map +1 -0
- package/lib/server/forge/core/workspaces.js +348 -0
- package/lib/server/forge/core/workspaces.js.map +1 -0
- package/lib/server/forge/db/database.d.ts +22 -0
- package/lib/server/forge/db/database.d.ts.map +1 -0
- package/lib/server/forge/db/database.js +71 -0
- package/lib/server/forge/db/database.js.map +1 -0
- package/lib/server/forge/db/migrations.d.ts +11 -0
- package/lib/server/forge/db/migrations.d.ts.map +1 -0
- package/lib/server/forge/db/migrations.js +87 -0
- package/lib/server/forge/db/migrations.js.map +1 -0
- package/lib/server/forge/routes.d.ts.map +1 -1
- package/lib/server/forge/routes.js +413 -163
- package/lib/server/forge/routes.js.map +1 -1
- package/lib/server/forge/sse.d.ts +10 -0
- package/lib/server/forge/sse.d.ts.map +1 -0
- package/lib/server/forge/sse.js +22 -0
- package/lib/server/forge/sse.js.map +1 -0
- package/lib/server/spa.d.ts +12 -0
- package/lib/server/spa.d.ts.map +1 -0
- package/lib/server/spa.js +23 -0
- package/lib/server/spa.js.map +1 -0
- package/lib/server.js +9 -24
- package/lib/server.js.map +1 -1
- package/lib/shared/events.d.ts +3 -0
- package/lib/shared/events.d.ts.map +1 -1
- package/lib/shared/events.js +3 -0
- package/lib/shared/events.js.map +1 -1
- package/lib/shared/packageRoot.d.ts +11 -0
- package/lib/shared/packageRoot.d.ts.map +1 -0
- package/lib/shared/packageRoot.js +23 -0
- package/lib/shared/packageRoot.js.map +1 -0
- package/lib/shared/project.d.ts +3 -0
- package/lib/shared/project.d.ts.map +1 -0
- package/lib/shared/project.js +3 -0
- package/lib/shared/project.js.map +1 -0
- package/package.json +24 -9
- package/lib/bin/cli/improve.d.ts +0 -2
- package/lib/bin/cli/improve.d.ts.map +0 -1
- package/lib/bin/cli/improve.js +0 -189
- package/lib/bin/cli/improve.js.map +0 -1
- package/lib/bin/cli/stats.d.ts +0 -2
- package/lib/bin/cli/stats.d.ts.map +0 -1
- package/lib/bin/cli/stats.js +0 -78
- package/lib/bin/cli/stats.js.map +0 -1
- package/lib/server/forge/core/k8s.d.ts +0 -18
- package/lib/server/forge/core/k8s.d.ts.map +0 -1
- package/lib/server/forge/core/k8s.js +0 -49
- package/lib/server/forge/core/k8s.js.map +0 -1
- package/lib/server/forge/core/openclawClient.d.ts +0 -61
- package/lib/server/forge/core/openclawClient.d.ts.map +0 -1
- package/lib/server/forge/core/openclawClient.js +0 -111
- package/lib/server/forge/core/openclawClient.js.map +0 -1
- package/lib/server/forge/core/quotaClient.d.ts +0 -48
- package/lib/server/forge/core/quotaClient.d.ts.map +0 -1
- package/lib/server/forge/core/quotaClient.js +0 -88
- package/lib/server/forge/core/quotaClient.js.map +0 -1
- package/lib/server/forge/core/selfImprove.d.ts +0 -43
- package/lib/server/forge/core/selfImprove.d.ts.map +0 -1
- package/lib/server/forge/core/selfImprove.js +0 -372
- package/lib/server/forge/core/selfImprove.js.map +0 -1
- package/lib/server/forge/core/telemetry.d.ts +0 -100
- package/lib/server/forge/core/telemetry.d.ts.map +0 -1
- package/lib/server/forge/core/telemetry.js +0 -273
- package/lib/server/forge/core/telemetry.js.map +0 -1
- package/scripts/fix-shebang.cjs +0 -11
- package/scripts/inject-readme.cjs +0 -23
- package/scripts/local-rollout.sh +0 -134
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ForgeAgent.d.ts","sourceRoot":"","sources":["../../../../server/forge/core/ForgeAgent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;
|
|
1
|
+
{"version":3,"file":"ForgeAgent.d.ts","sourceRoot":"","sources":["../../../../server/forge/core/ForgeAgent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAcH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAU1E,0CAA0C;AAC1C,UAAU,iBAAiB;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,2DAA2D;AAC3D,UAAU,SAAS;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACb;AAED,qDAAqD;AACrD,UAAU,QAAQ;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,0DAA0D;AAC1D,UAAU,WAAW;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CAChB;AAkBD,qDAAqD;AACrD,UAAU,aAAa;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AASD,wDAAwD;AACxD,UAAU,SAAS;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,qEAAqE;AACrE,UAAU,cAAe,SAAQ,SAAS;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,kDAAkD;AAClD,UAAU,sBAAuB,SAAQ,cAAc;IACtD,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjD;AAED,6CAA6C;AAC7C,UAAU,UAAU;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,yDAAyD;AACzD,UAAU,cAAc;IACvB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;CACzB;AAED,0DAA0D;AAC1D,UAAU,cAAc;IACvB,MAAM,EAAE,sBAAsB,CAAC;IAC/B,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,iEAAiE;IACjE,MAAM,EAAE,OAAO,CAAC;CAChB;AAYD,kDAAkD;AAClD,KAAK,YAAY,GAAG,OAAO,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEzD,qDAAqD;AACrD,UAAU,iBAAiB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,QAAQ,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,yCAAyC;AACzC,UAAU,eAAe;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjE,IAAI,EAAE,MAAM,EAAE,CAAC;CACf;AA+LD,qBAAa,UAAU;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,QAAQ,EAAE,WAAW,CAAC;gBAEV,IAAI,GAAE,iBAAsB;IAqBxC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW;IAMpC,IAAI,WAAW,WAEd;IAED,IAAI,YAAY,YAEf;IAIK,cAAc,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAgBpE,WAAW,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAkChG;;;;;OAKG;IACH,wBAAwB,CAAC,UAAU,EAAE,OAAO,EAAE,GAAG,SAAS,EAAE;IAa5D,mBAAmB,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG;QAAE,KAAK,EAAE,SAAS,EAAE,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE;IAiB3G,oEAAoE;IACpE,cAAc,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE;IAcpE,iBAAiB,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,cAAc,EAAE;IAYrG;;;;OAIG;IACH,yBAAyB,IAAI,MAAM,GAAG,IAAI;IAM1C;;;;;OAKG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,GAAE,UAAe,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAiBpN,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAOpP;;;OAGG;IACG,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAa,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;IA8ErO;;;;;;;OAOG;IACG,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,UAAU;;;;IA0BpL;;;;OAIG;IACG,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA6B3F;;;;;;;;;OASG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,CAAC,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,GAAE,YAAsB,EAAE,IAAI,GAAE,UAAe,EAAE,eAAe,GAAE,WAAW,EAAE,GAAG,IAAW,GAAG,OAAO,CAAC,sBAAsB,CAAC;IA0IvT;;;;OAIG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,CAAC,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,eAAe,EAAE,eAAe,GAAG,IAAI,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,GAAE,UAAe;;;;IAmN1S;;;;OAIG;IACH,iBAAiB,CAAC,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,sBAAsB;IA4ClK;;;OAGG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,CAAC,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,GAAE,UAAe;;;;;;;;IAqF3J;;;;OAIG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,MAA4B;IAWzF;;;;;;;OAOG;IACG,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,GAAG,OAAO,CAAC;QAAE,YAAY,EAAE,iBAAiB,EAAE,CAAA;KAAE,CAAC;IAuBhG;;;;;;;OAOG;IACG,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,sBAAsB,EAAE,IAAI,GAAE,MAA4B;;;;IAiC7G;;;;;;;;;OASG;IACG,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAsDvG;;;;;;OAMG;IACG,YAAY,CAAC,QAAQ,EAAE,sBAAsB,GAAG,OAAO,CAAC;QAAE,YAAY,EAAE,iBAAiB,EAAE,CAAA;KAAE,CAAC;IAwCpG;;;;;;OAMG;IACG,uBAAuB,CAAC,CAAC,SAAS;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAC7F,QAAQ,EAAE,WAAW,EACrB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,CAAC,EAAE,GACV,OAAO,CAAC,CAAC,EAAE,CAAC;IAkBf;;;;;;;OAOG;IACG,mBAAmB,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAiBzE,mBAAmB,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC;IAavE,iEAAiE;IACjE,aAAa,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,GAAG,MAAM,EAAE;IAKtD,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAgD9J;;;;;OAKG;IACG,aAAa,CAAC,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAU7F;;;;;OAKG;IACG,SAAS,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC;IAajF,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAIrC,mBAAmB,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,IAAI,GAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,iBAAiB,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,MAAM;CA6C/M"}
|
|
@@ -20,13 +20,20 @@
|
|
|
20
20
|
* - `applyFix` groups by repo and creates one branch + MR per repo.
|
|
21
21
|
*/
|
|
22
22
|
import { randomUUID } from "node:crypto";
|
|
23
|
-
import {
|
|
23
|
+
import { FORGE_PROJECT_URL } from "../../../shared/project.js";
|
|
24
|
+
import { checkResolution, identifyRelevantFiles, proposeFix, proposeFixAgentic, refineOrAsk } from "./agentClient.js";
|
|
25
|
+
import { AGENT_MODE, resolveAgentMode } from "./agentMode.js";
|
|
24
26
|
import { branchNameFor } from "./branchName.js";
|
|
27
|
+
import { AgentTimeoutError } from "./claudeClient.js";
|
|
25
28
|
import * as configStore from "./configStore.js";
|
|
26
|
-
import {
|
|
29
|
+
import { collectEvidence, prepareEvidenceDir, renderEvidence } from "./evidence.js";
|
|
30
|
+
import { acquireWorkingTree, captureChanges, overlayChanges } from "./localRepo.js";
|
|
27
31
|
import { classifyIssue } from "./prompts.js";
|
|
28
32
|
import { createProvider } from "./providers/index.js";
|
|
29
33
|
import { reattributeChanges } from "./validator/attribute.js";
|
|
34
|
+
// An agent editing a real checkout for a multi-part ticket regularly needs
|
|
35
|
+
// more than the CLI's 10-minute default.
|
|
36
|
+
const AGENTIC_TIMEOUT_MS = 30 * 60_000;
|
|
30
37
|
/**
|
|
31
38
|
* Whether Refine should give the model real Read/Glob/Grep access to a local
|
|
32
39
|
* checkout of the primary repo. Primary control is the Settings UI flag
|
|
@@ -102,6 +109,28 @@ const FILE_CAPS = {
|
|
|
102
109
|
fix: { total: 12, perRepo: 8 },
|
|
103
110
|
chore: { total: 12, perRepo: 8 },
|
|
104
111
|
};
|
|
112
|
+
/**
|
|
113
|
+
* Pulls the trailing `TITLE: <subject>` line out of an agentic run's final
|
|
114
|
+
* message. The title becomes the MR title (falling back to the issue title via
|
|
115
|
+
* buildCommitSubject if absent); the rest of the message is the explanation,
|
|
116
|
+
* with the TITLE line stripped so it doesn't leak into the UI.
|
|
117
|
+
*/
|
|
118
|
+
function parseAgenticSummary(text) {
|
|
119
|
+
const match = text.match(/^[ \t]*TITLE:[ \t]*(.+?)[ \t]*$/m);
|
|
120
|
+
if (!match)
|
|
121
|
+
return { explanation: text.trim() };
|
|
122
|
+
const title = match[1].trim();
|
|
123
|
+
const explanation = text.replace(match[0], "").trim();
|
|
124
|
+
return { title: title || undefined, explanation };
|
|
125
|
+
}
|
|
126
|
+
/** Whether two change sets touch the same files with the same content. */
|
|
127
|
+
function sameChanges(a, b) {
|
|
128
|
+
if (a.length !== b.length)
|
|
129
|
+
return false;
|
|
130
|
+
const key = (c) => `${c.file}\0${c.action}\0${c.action === "delete" ? "" : c.proposed ?? ""}`;
|
|
131
|
+
const seen = new Set(a.map(key));
|
|
132
|
+
return b.every((c) => seen.has(key(c)));
|
|
133
|
+
}
|
|
105
134
|
/**
|
|
106
135
|
* Builds a conventional-commit subject line from the analysis. Prefers
|
|
107
136
|
* `analysis.mrTitle` (the model's own commit-style summary), falling back to
|
|
@@ -217,7 +246,7 @@ export class ForgeAgent {
|
|
|
217
246
|
return p;
|
|
218
247
|
}
|
|
219
248
|
get _agentLabel() {
|
|
220
|
-
return
|
|
249
|
+
return "Claude";
|
|
221
250
|
}
|
|
222
251
|
get _isMultiRepo() {
|
|
223
252
|
return this.allRepos.length > 1;
|
|
@@ -336,6 +365,190 @@ export class ForgeAgent {
|
|
|
336
365
|
return { ...change, repo, original };
|
|
337
366
|
});
|
|
338
367
|
}
|
|
368
|
+
// ─── Agentic analyze ─────────────────────────────────────────────────────────
|
|
369
|
+
/**
|
|
370
|
+
* Returns a human-readable reason agentic mode can't run for this request, or
|
|
371
|
+
* null when it can. Logged (never silently dropped) so the user knows why a
|
|
372
|
+
* structured analysis happened instead.
|
|
373
|
+
*/
|
|
374
|
+
_agenticUnavailableReason() {
|
|
375
|
+
if (this._isMultiRepo)
|
|
376
|
+
return "multi-repo changes aren't supported in agentic mode yet";
|
|
377
|
+
if (!supportsLocalClone(this.primaryProject))
|
|
378
|
+
return "only GitLab repos support a local checkout";
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Agentic analysis: clone the primary repo, run Claude as a full Claude Code
|
|
383
|
+
* agent inside it (real tools + the repo's CLAUDE.md), then read the changes
|
|
384
|
+
* straight from git. Emits the same event/result shape as the structured
|
|
385
|
+
* pipeline so the route, UI, and apply flow are unchanged.
|
|
386
|
+
*/
|
|
387
|
+
async _analyzeAgentic(issueIid, emit, model, ciContext, userPrompt, opts = {}) {
|
|
388
|
+
const { signal } = opts;
|
|
389
|
+
const repo = this.primaryProject;
|
|
390
|
+
emit({ type: "progress", step: "fetch_issue", message: `Fetching issue #${issueIid}...` });
|
|
391
|
+
const issue = await this.provider.getIssue(issueIid);
|
|
392
|
+
const branchName = branchNameFor(issueIid, { issue });
|
|
393
|
+
emit({ type: "progress", step: "scan_repo", message: `Preparing a checkout of ${repo}...` });
|
|
394
|
+
const lease = await acquireWorkingTree(repo, branchName, (m) => emit({ type: "log", message: m }));
|
|
395
|
+
try {
|
|
396
|
+
return await this._runAgentic(lease.dir, issue, repo, emit, model, ciContext, userPrompt, { signal });
|
|
397
|
+
}
|
|
398
|
+
finally {
|
|
399
|
+
lease.release();
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
async _runAgentic(dir, issue, repo, emit, model, ciContext, userPrompt, { signal }) {
|
|
403
|
+
const { result, usage } = await this._executeAgentic(dir, issue, repo, emit, model, { signal, ciContext, userPrompt });
|
|
404
|
+
emit({ type: "result", data: result });
|
|
405
|
+
if (usage)
|
|
406
|
+
emit(usage);
|
|
407
|
+
return result;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Runs the agent in `dir` and reads back what it did: the captured changes,
|
|
411
|
+
* its summary and any evidence. Callers decide what to emit.
|
|
412
|
+
*/
|
|
413
|
+
async _executeAgentic(dir, issue, repo, emit, model, { signal, ciContext, userPrompt, feedback, baseline = [] }) {
|
|
414
|
+
await prepareEvidenceDir(dir);
|
|
415
|
+
emit({ type: "progress", step: "generate_fix", message: `Running ${this._agentLabel} as an agent in ${repo}...` });
|
|
416
|
+
const defaults = configStore.get().defaults;
|
|
417
|
+
let agentic = null;
|
|
418
|
+
let timedOut = null;
|
|
419
|
+
try {
|
|
420
|
+
agentic = await proposeFixAgentic({
|
|
421
|
+
issue,
|
|
422
|
+
cwd: dir,
|
|
423
|
+
model,
|
|
424
|
+
promptRules: defaults?.promptRules || "",
|
|
425
|
+
userPrompt,
|
|
426
|
+
ciContext,
|
|
427
|
+
feedback,
|
|
428
|
+
onEvent: emit,
|
|
429
|
+
signal,
|
|
430
|
+
timeout: defaults?.cliTimeout ?? AGENTIC_TIMEOUT_MS,
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
catch (err) {
|
|
434
|
+
// Out of time isn't nothing done: the edits are in the checkout. Keep
|
|
435
|
+
// them as a partial result (below) instead of losing the run.
|
|
436
|
+
if (!(err instanceof AgentTimeoutError))
|
|
437
|
+
throw err;
|
|
438
|
+
timedOut = err;
|
|
439
|
+
}
|
|
440
|
+
emit({ type: "progress", step: "fetch_files", message: "Capturing changes from the working tree..." });
|
|
441
|
+
const changes = await captureChanges({
|
|
442
|
+
dir,
|
|
443
|
+
repo,
|
|
444
|
+
onSkip: (file, reason) => emit({ type: "log", message: `Left out ${file} (${reason}): Forge never commits symlinks or dependency folders.` }),
|
|
445
|
+
});
|
|
446
|
+
const edited = !sameChanges(changes, baseline);
|
|
447
|
+
if (timedOut && !edited)
|
|
448
|
+
throw timedOut;
|
|
449
|
+
emit({
|
|
450
|
+
type: "log",
|
|
451
|
+
message: !edited
|
|
452
|
+
? baseline.length
|
|
453
|
+
? "The agent left the proposed changes as they were."
|
|
454
|
+
: "No file changes were captured — the agent reported done without editing the tree."
|
|
455
|
+
: `Captured ${changes.length} change(s): ${changes.map((c) => `${c.file} (${c.action})`).join(", ")}`,
|
|
456
|
+
});
|
|
457
|
+
const evidence = await this._attachEvidence(dir, emit);
|
|
458
|
+
const { title, explanation } = agentic
|
|
459
|
+
? parseAgenticSummary(agentic.text)
|
|
460
|
+
: {
|
|
461
|
+
title: undefined,
|
|
462
|
+
explanation: `The agent ran out of time after ${timedOut.minutes} minutes, before it finished. These are the changes it had made so far: review them, then refine to finish the rest.`,
|
|
463
|
+
};
|
|
464
|
+
const result = {
|
|
465
|
+
issue,
|
|
466
|
+
mrTitle: title,
|
|
467
|
+
explanation,
|
|
468
|
+
reasoning: "Agentic edit — Claude explored the checkout and edited files directly.",
|
|
469
|
+
changes,
|
|
470
|
+
removals: [],
|
|
471
|
+
repos: [repo],
|
|
472
|
+
...(evidence ? { evidence } : {}),
|
|
473
|
+
};
|
|
474
|
+
const usage = agentic
|
|
475
|
+
? {
|
|
476
|
+
type: "usage",
|
|
477
|
+
cost: agentic.cost,
|
|
478
|
+
serviceTier: agentic.serviceTier,
|
|
479
|
+
inputTokens: agentic.inputTokens,
|
|
480
|
+
outputTokens: agentic.outputTokens,
|
|
481
|
+
cacheCreationTokens: agentic.cacheCreationTokens,
|
|
482
|
+
cacheReadTokens: agentic.cacheReadTokens,
|
|
483
|
+
}
|
|
484
|
+
: null;
|
|
485
|
+
return { result, usage, edited };
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Agentic refine: overlays the current proposal on the issue's worktree and
|
|
489
|
+
* runs the reviewer's follow-up as a full agent, so asks like "check it in
|
|
490
|
+
* Playwright" can run things instead of hitting the read-only refine's
|
|
491
|
+
* Read/Glob/Grep wall. A run that leaves the tree untouched and gathers no
|
|
492
|
+
* evidence comes back as an answer, so a question doesn't replace the
|
|
493
|
+
* proposal (and its validation) with an identical one.
|
|
494
|
+
*/
|
|
495
|
+
async _refineAgentic(issue, previousChanges, feedback, emit, model, { signal }) {
|
|
496
|
+
const repo = this.primaryProject;
|
|
497
|
+
const log = (message) => emit({ type: "log", message });
|
|
498
|
+
emit({ type: "progress", step: "prepare_repo", message: `Preparing a checkout of ${repo}...` });
|
|
499
|
+
const lease = await acquireWorkingTree(repo, branchNameFor(issue.iid, { issue }), log);
|
|
500
|
+
try {
|
|
501
|
+
const baseline = (previousChanges ?? []).filter((c) => (c.repo ?? repo) === repo);
|
|
502
|
+
if (baseline.length)
|
|
503
|
+
await overlayChanges(lease.dir, baseline, log);
|
|
504
|
+
const { result, usage, edited } = await this._executeAgentic(lease.dir, issue, repo, emit, model, { signal, feedback, baseline });
|
|
505
|
+
if (!edited && !result.evidence) {
|
|
506
|
+
const text = result.explanation || "(no answer produced)";
|
|
507
|
+
log("Refine made no code changes — responding without changing the proposal.");
|
|
508
|
+
emit({ type: "answer", text });
|
|
509
|
+
if (usage)
|
|
510
|
+
emit(usage);
|
|
511
|
+
return { kind: "answer", answer: text };
|
|
512
|
+
}
|
|
513
|
+
emit({ type: "result", data: result });
|
|
514
|
+
if (usage)
|
|
515
|
+
emit(usage);
|
|
516
|
+
return result;
|
|
517
|
+
}
|
|
518
|
+
finally {
|
|
519
|
+
lease.release();
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Uploads whatever the agent left in the evidence folder and returns the
|
|
524
|
+
* markdown for the MR. A failed upload is logged, never fatal — the change
|
|
525
|
+
* itself is what matters.
|
|
526
|
+
*/
|
|
527
|
+
async _attachEvidence(dir, emit) {
|
|
528
|
+
const { notes, images, skipped } = await collectEvidence(dir);
|
|
529
|
+
for (const name of skipped) {
|
|
530
|
+
emit({ type: "log", message: `Evidence: skipped ${name} (over the size or count limit).` });
|
|
531
|
+
}
|
|
532
|
+
const uploads = [];
|
|
533
|
+
for (const image of images) {
|
|
534
|
+
try {
|
|
535
|
+
const uploaded = await this.provider.uploadFile(image);
|
|
536
|
+
if (!uploaded) {
|
|
537
|
+
emit({ type: "log", message: `Evidence: ${this.primaryProject} doesn't support uploads; screenshots stay out of the MR.` });
|
|
538
|
+
break;
|
|
539
|
+
}
|
|
540
|
+
uploads.push({ name: image.name, url: uploaded.url });
|
|
541
|
+
}
|
|
542
|
+
catch (err) {
|
|
543
|
+
emit({ type: "log", message: `Evidence: couldn't upload ${image.name}: ${err.message}` });
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
if (notes || uploads.length) {
|
|
547
|
+
const shots = uploads.length === 1 ? "1 screenshot" : `${uploads.length} screenshots`;
|
|
548
|
+
emit({ type: "log", message: `Evidence: attached ${notes ? "the write-up and " : ""}${shots} to the MR description.` });
|
|
549
|
+
}
|
|
550
|
+
return renderEvidence({ notes, uploads });
|
|
551
|
+
}
|
|
339
552
|
// ─── Analyze ───────────────────────────────────────────────────────────────
|
|
340
553
|
/**
|
|
341
554
|
* Runs the full analysis pipeline for an issue across all configured repos.
|
|
@@ -355,6 +568,19 @@ export class ForgeAgent {
|
|
|
355
568
|
: "";
|
|
356
569
|
const msgs = buildStepMessages(kind, issueIid, this._agentLabel, repoLine);
|
|
357
570
|
emit({ type: "log", message: msgs.intro });
|
|
571
|
+
// Agentic mode: run Claude as a full agent in a checkout and capture the
|
|
572
|
+
// diff, instead of the two-pass JSON pipeline below. Falls back to
|
|
573
|
+
// structured (and logs why) when the request can't support it.
|
|
574
|
+
const agentMode = resolveAgentMode({ requested: opts.agentMode, configured: configStore.get().defaults?.agentMode });
|
|
575
|
+
if (agentMode === AGENT_MODE.agentic) {
|
|
576
|
+
const reason = this._agenticUnavailableReason();
|
|
577
|
+
if (reason) {
|
|
578
|
+
emit({ type: "log", message: `Agentic mode unavailable (${reason}); using structured analysis.` });
|
|
579
|
+
}
|
|
580
|
+
else {
|
|
581
|
+
return this._analyzeAgentic(issueIid, emit, model, ciContext, userPrompt, { signal });
|
|
582
|
+
}
|
|
583
|
+
}
|
|
358
584
|
// Step 1 — fetch the issue from the primary repo
|
|
359
585
|
emit({ type: "progress", step: "fetch_issue", message: msgs.fetch_issue });
|
|
360
586
|
const issue = await this.provider.getIssue(issueIid);
|
|
@@ -372,7 +598,7 @@ export class ForgeAgent {
|
|
|
372
598
|
}
|
|
373
599
|
// Step 3 — identify relevant files (Claude pass 1)
|
|
374
600
|
emit({ type: "progress", step: "identify_files", message: msgs.identify_files });
|
|
375
|
-
const ident = await identifyRelevantFiles(issue, repoTrees, model,
|
|
601
|
+
const ident = await identifyRelevantFiles(issue, repoTrees, model, { signal });
|
|
376
602
|
const { files: rawFiles, reasoning = "", cost: cost1 = 0, serviceTier, inputTokens: it1 = 0, outputTokens: ot1 = 0, cacheCreationTokens: cc1 = 0, cacheReadTokens: cr1 = 0, } = ident;
|
|
377
603
|
const issueKind = classifyIssue(issue);
|
|
378
604
|
emit({ type: "log", message: `Issue classified as: ${issueKind}` });
|
|
@@ -399,7 +625,7 @@ export class ForgeAgent {
|
|
|
399
625
|
// Step 5 — propose fix (pass 2)
|
|
400
626
|
emit({ type: "progress", step: "generate_fix", message: msgs.generate_fix });
|
|
401
627
|
const promptRules = configStore.get().defaults?.promptRules || "";
|
|
402
|
-
const propose = await proposeFix(issue, fileContents, { ciContext, userPrompt, previousChanges, repos: this.allRepos, promptRules }, model,
|
|
628
|
+
const propose = await proposeFix(issue, fileContents, { ciContext, userPrompt, previousChanges, repos: this.allRepos, promptRules }, model, { signal });
|
|
403
629
|
const { title: mrTitle, explanation, changes, removals = [], cost: cost2 = 0, inputTokens: it2 = 0, outputTokens: ot2 = 0, cacheCreationTokens: cc2 = 0, cacheReadTokens: cr2 = 0, rateLimit: rl2 = null, } = propose;
|
|
404
630
|
const enrichedChanges = this._normalizeChanges(changes ?? [], fileContents);
|
|
405
631
|
emit({
|
|
@@ -448,11 +674,22 @@ export class ForgeAgent {
|
|
|
448
674
|
// a multi-turn session. CI-fix refines route through proposeFix (stateless)
|
|
449
675
|
// and OpenClaw has no session API. Generate a fresh UUID for turn 1 so we
|
|
450
676
|
// own the id from the start and can --resume it on turn 2+.
|
|
451
|
-
const useSession =
|
|
677
|
+
const useSession = !ciContext;
|
|
452
678
|
const resumeSession = Boolean(useSession && claudeSessionId);
|
|
453
679
|
const sessionId = useSession ? (claudeSessionId || randomUUID()) : null;
|
|
454
680
|
emit({ type: "progress", step: "fetch_issue", message: `Fetching issue #${issueIid}...` });
|
|
455
681
|
const issue = await this.provider.getIssue(issueIid);
|
|
682
|
+
// Agentic mode: reviewer follow-ups get the same full agent as the
|
|
683
|
+
// analysis. CI-fix refines stay on the targeted proposeFix path below.
|
|
684
|
+
if (!ciContext && resolveAgentMode({ requested: opts.agentMode, configured: configStore.get().defaults?.agentMode }) === AGENT_MODE.agentic) {
|
|
685
|
+
const reason = this._agenticUnavailableReason();
|
|
686
|
+
if (reason) {
|
|
687
|
+
emit({ type: "log", message: `Agentic refine unavailable (${reason}); refining with read-only repo access.` });
|
|
688
|
+
}
|
|
689
|
+
else {
|
|
690
|
+
return this._refineAgentic(issue, previousChanges, feedback, emit, model, { signal });
|
|
691
|
+
}
|
|
692
|
+
}
|
|
456
693
|
// Pull the unique (repo, path) pairs from the previous changes.
|
|
457
694
|
const uniq = new Map();
|
|
458
695
|
for (const c of previousChanges ?? []) {
|
|
@@ -475,7 +712,7 @@ export class ForgeAgent {
|
|
|
475
712
|
if (ciContext) {
|
|
476
713
|
emit({ type: "progress", step: "generate_fix", message: `Fixing CI failure with ${this._agentLabel}...` });
|
|
477
714
|
const ciRefineRules = configStore.get().defaults?.promptRules || "";
|
|
478
|
-
const propose = await proposeFix(issue, fileContents, { feedback, previousChanges, ciContext, repos: this.allRepos, promptRules: ciRefineRules }, model,
|
|
715
|
+
const propose = await proposeFix(issue, fileContents, { feedback, previousChanges, ciContext, repos: this.allRepos, promptRules: ciRefineRules }, model, { signal });
|
|
479
716
|
return this._emitRefineResult(propose, fileContents, issue, emit, "ci-fix");
|
|
480
717
|
}
|
|
481
718
|
// Give the refine model access to the full primary repo: prepare a local
|
|
@@ -484,15 +721,16 @@ export class ForgeAgent {
|
|
|
484
721
|
// when using a non-Claude agent, or when the primary repo isn't GitLab
|
|
485
722
|
// (validator/localRepo are GitLab-only for now).
|
|
486
723
|
let repoCwd = null;
|
|
724
|
+
let repoLease = null;
|
|
487
725
|
let repoTrees = null;
|
|
488
726
|
const canUseLocalClone = refineRepoAccessEnabled()
|
|
489
|
-
&& this.agent !== "openclaw"
|
|
490
727
|
&& supportsLocalClone(this.primaryProject);
|
|
491
728
|
if (canUseLocalClone) {
|
|
492
729
|
try {
|
|
493
730
|
emit({ type: "progress", step: "prepare_repo", message: `Preparing local checkout of ${this.primaryProject}...` });
|
|
494
731
|
const branchName = branchNameFor(issue.iid, { issue });
|
|
495
|
-
|
|
732
|
+
repoLease = await acquireWorkingTree(this.primaryProject, branchName, (msg) => emit({ type: "log", message: msg }));
|
|
733
|
+
const dir = repoLease.dir;
|
|
496
734
|
const primaryChanges = (previousChanges ?? []).filter((c) => (c.repo ?? this.primaryProject) === this.primaryProject);
|
|
497
735
|
if (primaryChanges.length) {
|
|
498
736
|
await overlayChanges(dir, primaryChanges, (msg) => emit({ type: "log", message: msg }));
|
|
@@ -503,6 +741,8 @@ export class ForgeAgent {
|
|
|
503
741
|
catch (err) {
|
|
504
742
|
const message = err instanceof Error ? err.message : String(err);
|
|
505
743
|
emit({ type: "log", message: `Could not prepare local checkout (${message}); falling back to file-tree mode.` });
|
|
744
|
+
repoLease?.release();
|
|
745
|
+
repoLease = null;
|
|
506
746
|
repoCwd = null;
|
|
507
747
|
}
|
|
508
748
|
}
|
|
@@ -529,29 +769,35 @@ export class ForgeAgent {
|
|
|
529
769
|
repoAccessMode: repoCwd ? "tools" : "tree",
|
|
530
770
|
promptRules: refinePromptRules,
|
|
531
771
|
...(sid ? { sessionId: sid, resumeSession: resume } : {}),
|
|
532
|
-
}, model,
|
|
772
|
+
}, model, (evt) => emit(evt), { signal });
|
|
533
773
|
let activeSessionId = sessionId;
|
|
534
774
|
let response;
|
|
535
775
|
try {
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
catch (err) {
|
|
539
|
-
// Resume failures (session pruned by the CLI, format drift after an
|
|
540
|
-
// upgrade, crashed half-turn leaving the session unreadable) should
|
|
541
|
-
// not kill the user's refine. Regenerate the session, tell the
|
|
542
|
-
// frontend to adopt the new id, and retry once with the full prompt.
|
|
543
|
-
if (resumeSession && isLikelyResumeFailure(err)) {
|
|
544
|
-
const fresh = randomUUID();
|
|
545
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
546
|
-
emit({ type: "log", message: `Could not resume Claude session ${activeSessionId} (${errMsg}). Starting fresh session ${fresh}.` });
|
|
547
|
-
activeSessionId = fresh;
|
|
548
|
-
emit({ type: "session", sessionId: fresh, resumed: false });
|
|
549
|
-
response = await callRefine(fresh, false);
|
|
776
|
+
try {
|
|
777
|
+
response = await callRefine(activeSessionId, resumeSession);
|
|
550
778
|
}
|
|
551
|
-
|
|
552
|
-
|
|
779
|
+
catch (err) {
|
|
780
|
+
// Resume failures (session pruned by the CLI, format drift after an
|
|
781
|
+
// upgrade, crashed half-turn leaving the session unreadable) should
|
|
782
|
+
// not kill the user's refine. Regenerate the session, tell the
|
|
783
|
+
// frontend to adopt the new id, and retry once with the full prompt.
|
|
784
|
+
if (resumeSession && isLikelyResumeFailure(err)) {
|
|
785
|
+
const fresh = randomUUID();
|
|
786
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
787
|
+
emit({ type: "log", message: `Could not resume Claude session ${activeSessionId} (${errMsg}). Starting fresh session ${fresh}.` });
|
|
788
|
+
activeSessionId = fresh;
|
|
789
|
+
emit({ type: "session", sessionId: fresh, resumed: false });
|
|
790
|
+
response = await callRefine(fresh, false);
|
|
791
|
+
}
|
|
792
|
+
else {
|
|
793
|
+
throw err;
|
|
794
|
+
}
|
|
553
795
|
}
|
|
554
796
|
}
|
|
797
|
+
finally {
|
|
798
|
+
// The session only reads the checkout while it runs.
|
|
799
|
+
repoLease?.release();
|
|
800
|
+
}
|
|
555
801
|
// CLI sometimes forks on resume and returns a different session id than
|
|
556
802
|
// the one we passed. Re-emit so the frontend persists the authoritative
|
|
557
803
|
// id — otherwise next refine would --resume a stale handle.
|
|
@@ -629,7 +875,7 @@ export class ForgeAgent {
|
|
|
629
875
|
const repoTrees = await this._fetchAllTrees(emit);
|
|
630
876
|
emit({ type: "progress", step: "identify_files", message: "Identifying files from CI failure..." });
|
|
631
877
|
const ciIssue = { ...issue, description: `CI pipeline failure:\n\n${ciContext}` };
|
|
632
|
-
const ident = await identifyRelevantFiles(ciIssue, repoTrees, model,
|
|
878
|
+
const ident = await identifyRelevantFiles(ciIssue, repoTrees, model, { signal });
|
|
633
879
|
const { files: rawFiles, cost: cost1 = 0, serviceTier, inputTokens: it1 = 0, outputTokens: ot1 = 0, cacheCreationTokens: cc1 = 0, cacheReadTokens: cr1 = 0, } = ident;
|
|
634
880
|
const { valid } = this._validateSelections(this._normalizeFileSelections(rawFiles), repoTrees);
|
|
635
881
|
const capped = this._capSelections(valid, "fix");
|
|
@@ -641,7 +887,7 @@ export class ForgeAgent {
|
|
|
641
887
|
const fileContents = await this._fetchFiles(capped, emit);
|
|
642
888
|
emit({ type: "progress", step: "generate_fix", message: `Fixing CI failure with ${this._agentLabel}...` });
|
|
643
889
|
const ciPromptRules = configStore.get().defaults?.promptRules || "";
|
|
644
|
-
const propose = await proposeFix(issue, fileContents, { ciContext, repos: this.allRepos, promptRules: ciPromptRules }, model,
|
|
890
|
+
const propose = await proposeFix(issue, fileContents, { ciContext, repos: this.allRepos, promptRules: ciPromptRules }, model, { signal });
|
|
645
891
|
const { title: mrTitle, explanation, changes, cost: cost2 = 0, inputTokens: it2 = 0, outputTokens: ot2 = 0, cacheCreationTokens: cc2 = 0, cacheReadTokens: cr2 = 0, rateLimit: rl2 = null, } = propose;
|
|
646
892
|
const enrichedChanges = this._normalizeChanges(changes ?? [], fileContents);
|
|
647
893
|
emit({
|
|
@@ -681,7 +927,7 @@ export class ForgeAgent {
|
|
|
681
927
|
this.provider.getIssue(issueIid),
|
|
682
928
|
provider.getMRDiffs(mrIid),
|
|
683
929
|
]);
|
|
684
|
-
return checkResolution(issue, diffs, undefined,
|
|
930
|
+
return checkResolution(issue, diffs, undefined, {});
|
|
685
931
|
}
|
|
686
932
|
// ─── Apply ─────────────────────────────────────────────────────────────────
|
|
687
933
|
/**
|
|
@@ -926,6 +1172,8 @@ _Opened by Forge._`;
|
|
|
926
1172
|
isPrimary,
|
|
927
1173
|
repo,
|
|
928
1174
|
priorApplications,
|
|
1175
|
+
// Evidence comes from the primary repo's checkout.
|
|
1176
|
+
evidence: isPrimary ? analysis.evidence : undefined,
|
|
929
1177
|
});
|
|
930
1178
|
const mr = await this._ensureMR(provider, {
|
|
931
1179
|
sourceBranch: branchName,
|
|
@@ -986,7 +1234,7 @@ _Opened by Forge._`;
|
|
|
986
1234
|
return repo.split("/").pop() || repo;
|
|
987
1235
|
}
|
|
988
1236
|
_buildMRDescription(issue, explanation, changes, opts = {}) {
|
|
989
|
-
const { isPrimary = true, repo = this.primaryProject, priorApplications = [] } = opts;
|
|
1237
|
+
const { isPrimary = true, repo = this.primaryProject, priorApplications = [], evidence } = opts;
|
|
990
1238
|
const changeList = changes
|
|
991
1239
|
.map((c) => `- **${c.file}** (${c.action}): ${c.summary}`)
|
|
992
1240
|
.join("\n");
|
|
@@ -1020,12 +1268,12 @@ ${changeList}
|
|
|
1020
1268
|
|
|
1021
1269
|
## 🧪 Testing
|
|
1022
1270
|
|
|
1023
|
-
- ⏳ Automated CI pipeline
|
|
1271
|
+
${evidence?.trim() ? `${evidence.trim()}\n\n` : ""}- ⏳ Automated CI pipeline
|
|
1024
1272
|
- ⏳ Manual review of diff before merge
|
|
1025
1273
|
|
|
1026
1274
|
---
|
|
1027
1275
|
|
|
1028
|
-
_Generated by [Forge](
|
|
1276
|
+
_Generated by [Forge](${FORGE_PROJECT_URL})_`;
|
|
1029
1277
|
}
|
|
1030
1278
|
}
|
|
1031
1279
|
//# sourceMappingURL=ForgeAgent.js.map
|