@ipul-labs/forge 1.16.8 → 1.17.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/README.md +39 -21
- package/lib/bin/cli/analyze.d.ts +9 -0
- package/lib/bin/cli/analyze.d.ts.map +1 -0
- package/lib/bin/cli/analyze.js +491 -0
- package/lib/bin/cli/analyze.js.map +1 -0
- package/lib/bin/cli/apply.d.ts +2 -0
- package/lib/bin/cli/apply.d.ts.map +1 -0
- package/lib/bin/cli/apply.js +262 -0
- package/lib/bin/cli/apply.js.map +1 -0
- package/lib/bin/cli/cifix.d.ts +2 -0
- package/lib/bin/cli/cifix.d.ts.map +1 -0
- package/lib/bin/cli/cifix.js +310 -0
- package/lib/bin/cli/cifix.js.map +1 -0
- package/lib/bin/cli/close.d.ts +2 -0
- package/lib/bin/cli/close.d.ts.map +1 -0
- package/lib/bin/cli/close.js +113 -0
- package/lib/bin/cli/close.js.map +1 -0
- package/lib/bin/cli/createIssue.d.ts +2 -0
- package/lib/bin/cli/createIssue.d.ts.map +1 -0
- package/lib/bin/cli/createIssue.js +108 -0
- package/lib/bin/cli/createIssue.js.map +1 -0
- package/lib/bin/cli/doctor.d.ts +2 -0
- package/lib/bin/cli/doctor.d.ts.map +1 -0
- package/lib/bin/cli/doctor.js +145 -0
- package/lib/bin/cli/doctor.js.map +1 -0
- package/lib/bin/cli/init.d.ts +4 -0
- package/lib/bin/cli/init.d.ts.map +1 -0
- package/lib/bin/cli/init.js +288 -0
- package/lib/bin/cli/init.js.map +1 -0
- package/lib/bin/cli/ink.d.ts +23 -0
- package/lib/bin/cli/ink.d.ts.map +1 -0
- package/{bin → lib/bin}/cli/ink.js +18 -19
- package/lib/bin/cli/ink.js.map +1 -0
- package/lib/bin/cli/issue.d.ts +2 -0
- package/lib/bin/cli/issue.d.ts.map +1 -0
- package/lib/bin/cli/issue.js +114 -0
- package/lib/bin/cli/issue.js.map +1 -0
- package/lib/bin/cli/issues.d.ts +2 -0
- package/lib/bin/cli/issues.d.ts.map +1 -0
- package/lib/bin/cli/issues.js +149 -0
- package/lib/bin/cli/issues.js.map +1 -0
- package/lib/bin/cli/merge.d.ts +2 -0
- package/lib/bin/cli/merge.d.ts.map +1 -0
- package/lib/bin/cli/merge.js +162 -0
- package/lib/bin/cli/merge.js.map +1 -0
- package/lib/bin/cli/refine.d.ts +2 -0
- package/lib/bin/cli/refine.d.ts.map +1 -0
- package/lib/bin/cli/refine.js +249 -0
- package/lib/bin/cli/refine.js.map +1 -0
- package/lib/bin/cli/repl.d.ts +2 -0
- package/lib/bin/cli/repl.d.ts.map +1 -0
- package/lib/bin/cli/repl.js +309 -0
- package/lib/bin/cli/repl.js.map +1 -0
- package/lib/bin/cli/repos.d.ts +2 -0
- package/lib/bin/cli/repos.d.ts.map +1 -0
- package/lib/bin/cli/repos.js +86 -0
- package/lib/bin/cli/repos.js.map +1 -0
- package/lib/bin/cli/resolution.d.ts +2 -0
- package/lib/bin/cli/resolution.d.ts.map +1 -0
- package/lib/bin/cli/resolution.js +139 -0
- package/lib/bin/cli/resolution.js.map +1 -0
- package/lib/bin/cli/serverClient.d.ts +26 -0
- package/lib/bin/cli/serverClient.d.ts.map +1 -0
- package/lib/bin/cli/serverClient.js +111 -0
- package/lib/bin/cli/serverClient.js.map +1 -0
- package/lib/bin/cli/session.d.ts +8 -0
- package/lib/bin/cli/session.d.ts.map +1 -0
- package/lib/bin/cli/session.js +212 -0
- package/lib/bin/cli/session.js.map +1 -0
- package/lib/bin/cli/sessionStore.d.ts +69 -0
- package/lib/bin/cli/sessionStore.d.ts.map +1 -0
- package/lib/bin/cli/sessionStore.js +196 -0
- package/lib/bin/cli/sessionStore.js.map +1 -0
- package/lib/bin/cli/ship.d.ts +33 -0
- package/lib/bin/cli/ship.d.ts.map +1 -0
- package/lib/bin/cli/ship.js +737 -0
- package/lib/bin/cli/ship.js.map +1 -0
- package/lib/bin/cli/types.d.ts +59 -0
- package/lib/bin/cli/types.d.ts.map +1 -0
- package/lib/bin/cli/types.js +2 -0
- package/lib/bin/cli/types.js.map +1 -0
- package/lib/bin/cli/update.d.ts +2 -0
- package/lib/bin/cli/update.d.ts.map +1 -0
- package/lib/bin/cli/update.js +87 -0
- package/lib/bin/cli/update.js.map +1 -0
- package/lib/bin/cli/utils.d.ts +43 -0
- package/lib/bin/cli/utils.d.ts.map +1 -0
- package/lib/bin/cli/utils.js +171 -0
- package/lib/bin/cli/utils.js.map +1 -0
- package/lib/bin/cli/validate.d.ts +2 -0
- package/lib/bin/cli/validate.d.ts.map +1 -0
- package/lib/bin/cli/validate.js +283 -0
- package/lib/bin/cli/validate.js.map +1 -0
- package/lib/bin/cli/watch.d.ts +5 -0
- package/lib/bin/cli/watch.d.ts.map +1 -0
- package/lib/bin/cli/watch.js +263 -0
- package/lib/bin/cli/watch.js.map +1 -0
- package/lib/bin/forge-agent.d.ts +3 -0
- package/lib/bin/forge-agent.d.ts.map +1 -0
- package/{bin → lib/bin}/forge-agent.js +104 -105
- package/lib/bin/forge-agent.js.map +1 -0
- package/lib/server/forge/core/ForgeAgent.d.ts +260 -0
- package/lib/server/forge/core/ForgeAgent.d.ts.map +1 -0
- package/lib/server/forge/core/ForgeAgent.js +995 -0
- package/lib/server/forge/core/ForgeAgent.js.map +1 -0
- package/lib/server/forge/core/agentClient.d.ts +39 -0
- package/lib/server/forge/core/agentClient.d.ts.map +1 -0
- package/{server → lib/server}/forge/core/agentClient.js +7 -12
- package/lib/server/forge/core/agentClient.js.map +1 -0
- package/lib/server/forge/core/branchName.d.ts +20 -0
- package/lib/server/forge/core/branchName.d.ts.map +1 -0
- package/lib/server/forge/core/branchName.js +39 -0
- package/lib/server/forge/core/branchName.js.map +1 -0
- package/lib/server/forge/core/claudeClient.d.ts +60 -0
- package/lib/server/forge/core/claudeClient.d.ts.map +1 -0
- package/lib/server/forge/core/claudeClient.js +347 -0
- package/lib/server/forge/core/claudeClient.js.map +1 -0
- package/lib/server/forge/core/configStore.d.ts +76 -0
- package/lib/server/forge/core/configStore.d.ts.map +1 -0
- package/lib/server/forge/core/configStore.js +213 -0
- package/lib/server/forge/core/configStore.js.map +1 -0
- package/lib/server/forge/core/gitlabClient.d.ts +144 -0
- package/lib/server/forge/core/gitlabClient.d.ts.map +1 -0
- package/{server → lib/server}/forge/core/gitlabClient.js +98 -180
- package/lib/server/forge/core/gitlabClient.js.map +1 -0
- package/lib/server/forge/core/jobs.d.ts +67 -0
- package/lib/server/forge/core/jobs.d.ts.map +1 -0
- package/lib/server/forge/core/jobs.js +185 -0
- package/lib/server/forge/core/jobs.js.map +1 -0
- package/lib/server/forge/core/k8s.d.ts +18 -0
- package/lib/server/forge/core/k8s.d.ts.map +1 -0
- package/lib/server/forge/core/k8s.js +49 -0
- package/lib/server/forge/core/k8s.js.map +1 -0
- package/lib/server/forge/core/localRepo.d.ts +36 -0
- package/lib/server/forge/core/localRepo.d.ts.map +1 -0
- package/lib/server/forge/core/localRepo.js +165 -0
- package/lib/server/forge/core/localRepo.js.map +1 -0
- package/lib/server/forge/core/openclawClient.d.ts +61 -0
- package/lib/server/forge/core/openclawClient.d.ts.map +1 -0
- package/lib/server/forge/core/openclawClient.js +111 -0
- package/lib/server/forge/core/openclawClient.js.map +1 -0
- package/lib/server/forge/core/prompts.d.ts +96 -0
- package/lib/server/forge/core/prompts.d.ts.map +1 -0
- package/lib/server/forge/core/prompts.js +450 -0
- package/lib/server/forge/core/prompts.js.map +1 -0
- package/lib/server/forge/core/providers/azuredevops.d.ts +134 -0
- package/lib/server/forge/core/providers/azuredevops.d.ts.map +1 -0
- package/lib/server/forge/core/providers/azuredevops.js +360 -0
- package/lib/server/forge/core/providers/azuredevops.js.map +1 -0
- package/lib/server/forge/core/providers/base.d.ts +114 -0
- package/lib/server/forge/core/providers/base.d.ts.map +1 -0
- package/lib/server/forge/core/providers/base.js +98 -0
- package/lib/server/forge/core/providers/base.js.map +1 -0
- package/lib/server/forge/core/providers/github.d.ts +133 -0
- package/lib/server/forge/core/providers/github.d.ts.map +1 -0
- package/lib/server/forge/core/providers/github.js +307 -0
- package/lib/server/forge/core/providers/github.js.map +1 -0
- package/lib/server/forge/core/providers/gitlab.d.ts +144 -0
- package/lib/server/forge/core/providers/gitlab.d.ts.map +1 -0
- package/lib/server/forge/core/providers/gitlab.js +407 -0
- package/lib/server/forge/core/providers/gitlab.js.map +1 -0
- package/lib/server/forge/core/providers/index.d.ts +21 -0
- package/lib/server/forge/core/providers/index.d.ts.map +1 -0
- package/lib/server/forge/core/providers/index.js +43 -0
- package/lib/server/forge/core/providers/index.js.map +1 -0
- package/lib/server/forge/core/providers/types.d.ts +80 -0
- package/lib/server/forge/core/providers/types.d.ts.map +1 -0
- package/lib/server/forge/core/providers/types.js +2 -0
- package/lib/server/forge/core/providers/types.js.map +1 -0
- package/lib/server/forge/core/quotaClient.d.ts +48 -0
- package/lib/server/forge/core/quotaClient.d.ts.map +1 -0
- package/lib/server/forge/core/quotaClient.js +88 -0
- package/lib/server/forge/core/quotaClient.js.map +1 -0
- package/lib/server/forge/core/types.d.ts +160 -0
- package/lib/server/forge/core/types.d.ts.map +1 -0
- package/lib/server/forge/core/types.js +2 -0
- package/lib/server/forge/core/types.js.map +1 -0
- package/lib/server/forge/core/validator/attribute.d.ts +31 -0
- package/lib/server/forge/core/validator/attribute.d.ts.map +1 -0
- package/lib/server/forge/core/validator/attribute.js +82 -0
- package/lib/server/forge/core/validator/attribute.js.map +1 -0
- package/lib/server/forge/core/validator/clone.d.ts +14 -0
- package/lib/server/forge/core/validator/clone.d.ts.map +1 -0
- package/lib/server/forge/core/validator/clone.js +99 -0
- package/lib/server/forge/core/validator/clone.js.map +1 -0
- package/lib/server/forge/core/validator/cmd.d.ts +23 -0
- package/lib/server/forge/core/validator/cmd.d.ts.map +1 -0
- package/lib/server/forge/core/validator/cmd.js +87 -0
- package/lib/server/forge/core/validator/cmd.js.map +1 -0
- package/lib/server/forge/core/validator/fs.d.ts +5 -0
- package/lib/server/forge/core/validator/fs.d.ts.map +1 -0
- package/{server → lib/server}/forge/core/validator/fs.js +8 -3
- package/lib/server/forge/core/validator/fs.js.map +1 -0
- package/lib/server/forge/core/validator/overlay.d.ts +13 -0
- package/lib/server/forge/core/validator/overlay.d.ts.map +1 -0
- package/lib/server/forge/core/validator/overlay.js +53 -0
- package/lib/server/forge/core/validator/overlay.js.map +1 -0
- package/lib/server/forge/core/validator/projectType.d.ts +20 -0
- package/lib/server/forge/core/validator/projectType.d.ts.map +1 -0
- package/lib/server/forge/core/validator/projectType.js +94 -0
- package/lib/server/forge/core/validator/projectType.js.map +1 -0
- package/lib/server/forge/core/validator/runners/go.d.ts +21 -0
- package/lib/server/forge/core/validator/runners/go.d.ts.map +1 -0
- package/lib/server/forge/core/validator/runners/go.js +99 -0
- package/lib/server/forge/core/validator/runners/go.js.map +1 -0
- package/lib/server/forge/core/validator/runners/node.d.ts +12 -0
- package/lib/server/forge/core/validator/runners/node.d.ts.map +1 -0
- package/lib/server/forge/core/validator/runners/node.js +75 -0
- package/lib/server/forge/core/validator/runners/node.js.map +1 -0
- package/lib/server/forge/core/validator/tdd.d.ts +30 -0
- package/lib/server/forge/core/validator/tdd.d.ts.map +1 -0
- package/lib/server/forge/core/validator/tdd.js +96 -0
- package/lib/server/forge/core/validator/tdd.js.map +1 -0
- package/lib/server/forge/core/validator.d.ts +58 -0
- package/lib/server/forge/core/validator.d.ts.map +1 -0
- package/lib/server/forge/core/validator.js +150 -0
- package/lib/server/forge/core/validator.js.map +1 -0
- package/lib/server/forge/routes.d.ts +22 -0
- package/lib/server/forge/routes.d.ts.map +1 -0
- package/lib/server/forge/routes.js +984 -0
- package/lib/server/forge/routes.js.map +1 -0
- package/lib/server.d.ts +2 -0
- package/lib/server.d.ts.map +1 -0
- package/lib/server.js +52 -0
- package/lib/server.js.map +1 -0
- package/lib/shared/events.d.ts +12 -0
- package/lib/shared/events.d.ts.map +1 -0
- package/lib/shared/events.js +12 -0
- package/lib/shared/events.js.map +1 -0
- package/package.json +15 -13
- package/scripts/fix-shebang.cjs +10 -0
- package/bin/cli/analyze.js +0 -516
- package/bin/cli/apply.js +0 -264
- package/bin/cli/cifix.js +0 -300
- package/bin/cli/close.js +0 -125
- package/bin/cli/createIssue.js +0 -112
- package/bin/cli/doctor.js +0 -161
- package/bin/cli/init.js +0 -306
- package/bin/cli/issue.js +0 -116
- package/bin/cli/issues.js +0 -155
- package/bin/cli/merge.js +0 -175
- package/bin/cli/refine.js +0 -253
- package/bin/cli/repl.js +0 -301
- package/bin/cli/repos.js +0 -91
- package/bin/cli/resolution.js +0 -126
- package/bin/cli/session.js +0 -230
- package/bin/cli/sessionStore.js +0 -211
- package/bin/cli/ship.js +0 -762
- package/bin/cli/update.js +0 -95
- package/bin/cli/utils.js +0 -145
- package/bin/cli/validate.js +0 -280
- package/bin/cli/watch.js +0 -274
- package/server/forge/core/ForgeAgent.js +0 -1179
- package/server/forge/core/ForgeAgent.test.js +0 -179
- package/server/forge/core/branchName.js +0 -41
- package/server/forge/core/claudeClient.js +0 -378
- package/server/forge/core/configStore.js +0 -229
- package/server/forge/core/configStore.test.js +0 -89
- package/server/forge/core/jobs.js +0 -180
- package/server/forge/core/k8s.js +0 -54
- package/server/forge/core/localRepo.js +0 -163
- package/server/forge/core/openclawClient.js +0 -125
- package/server/forge/core/prompts.js +0 -483
- package/server/forge/core/prompts.test.js +0 -219
- package/server/forge/core/providers/azuredevops.js +0 -409
- package/server/forge/core/providers/base.js +0 -208
- package/server/forge/core/providers/github.js +0 -348
- package/server/forge/core/providers/gitlab.js +0 -529
- package/server/forge/core/providers/index.js +0 -47
- package/server/forge/core/quotaClient.js +0 -101
- package/server/forge/core/validator/attribute.js +0 -84
- package/server/forge/core/validator/clone.js +0 -116
- package/server/forge/core/validator/cmd.js +0 -98
- package/server/forge/core/validator/overlay.js +0 -52
- package/server/forge/core/validator/projectType.js +0 -87
- package/server/forge/core/validator/runners/go.js +0 -107
- package/server/forge/core/validator/runners/node.js +0 -84
- package/server/forge/core/validator/tdd.js +0 -105
- package/server/forge/core/validator.js +0 -167
- package/server/forge/routes.js +0 -1027
package/bin/cli/session.js
DELETED
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import { h, Box, Text, runApp } from "./ink.js";
|
|
4
|
-
import { getFlag, projectRoot } from "./utils.js";
|
|
5
|
-
import {
|
|
6
|
-
cleanAll,
|
|
7
|
-
cleanSession,
|
|
8
|
-
getHead,
|
|
9
|
-
listSessions,
|
|
10
|
-
readAnalysis,
|
|
11
|
-
readState,
|
|
12
|
-
resolveSessionTarget,
|
|
13
|
-
sessionDir,
|
|
14
|
-
} from "./sessionStore.js";
|
|
15
|
-
|
|
16
|
-
function relTime(iso) {
|
|
17
|
-
if (!iso) return "";
|
|
18
|
-
const ms = Date.now() - new Date(iso).getTime();
|
|
19
|
-
if (Number.isNaN(ms) || ms < 0) return "";
|
|
20
|
-
const s = Math.floor(ms / 1000);
|
|
21
|
-
if (s < 60) return `${s}s ago`;
|
|
22
|
-
const m = Math.floor(s / 60);
|
|
23
|
-
if (m < 60) return `${m}m ago`;
|
|
24
|
-
const h = Math.floor(m / 60);
|
|
25
|
-
if (h < 24) return `${h}h ago`;
|
|
26
|
-
return `${Math.floor(h / 24)}d ago`;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function SessionsTable({ sessions, head }) {
|
|
30
|
-
if (sessions.length === 0) {
|
|
31
|
-
return h`<${Box} flexDirection="column">
|
|
32
|
-
<${Text} dimColor>No sessions yet.</>
|
|
33
|
-
<${Text}>${"Run: forge analyze <iid>"}</>
|
|
34
|
-
</>`;
|
|
35
|
-
}
|
|
36
|
-
const rows = sessions.map((s) => {
|
|
37
|
-
const isHead = head && head.repo === s.repo && head.iid === s.iid;
|
|
38
|
-
return {
|
|
39
|
-
marker: isHead ? "*" : " ",
|
|
40
|
-
ref: `${s.repo}#${s.iid}`,
|
|
41
|
-
phase: s.phase ?? "?",
|
|
42
|
-
when: relTime(s.updatedAt),
|
|
43
|
-
};
|
|
44
|
-
});
|
|
45
|
-
const wRef = Math.max(3, ...rows.map((r) => r.ref.length));
|
|
46
|
-
const wPhase = Math.max(5, ...rows.map((r) => r.phase.length));
|
|
47
|
-
return h`<${Box} flexDirection="column" marginTop=${1}>
|
|
48
|
-
${rows.map((r, i) =>
|
|
49
|
-
h`<${Box} key=${i}>
|
|
50
|
-
<${Text} color=${r.marker === "*" ? "green" : undefined}> ${r.marker}</>
|
|
51
|
-
<${Box} width=${wRef + 2}><${Text}> ${r.ref}</></>
|
|
52
|
-
<${Box} width=${wPhase + 2}><${Text} color="yellow">${r.phase}</></>
|
|
53
|
-
<${Text} dimColor>${r.when}</>
|
|
54
|
-
</>`,
|
|
55
|
-
)}
|
|
56
|
-
<${Box} marginTop=${1}>
|
|
57
|
-
<${Text} dimColor>${"* HEAD — commands without <iid> resume here"}</>
|
|
58
|
-
</>
|
|
59
|
-
</>`;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function SessionDetail({ state, analysisSummary }) {
|
|
63
|
-
return h`<${Box} flexDirection="column">
|
|
64
|
-
<${Box}>
|
|
65
|
-
<${Text} color="yellow">Session </>
|
|
66
|
-
<${Text}>${state.repo}#${state.iid}</>
|
|
67
|
-
</>
|
|
68
|
-
<${Box}>
|
|
69
|
-
<${Text} color="yellow">Phase </>
|
|
70
|
-
<${Text}>${state.phase ?? "?"}</>
|
|
71
|
-
</>
|
|
72
|
-
${state.primary
|
|
73
|
-
? h`<${Box}>
|
|
74
|
-
<${Text} color="yellow">Primary </>
|
|
75
|
-
<${Text}>${state.primary}</>
|
|
76
|
-
</>`
|
|
77
|
-
: null}
|
|
78
|
-
${state.secondaries?.length
|
|
79
|
-
? h`<${Box}>
|
|
80
|
-
<${Text} color="yellow">Secondary</>
|
|
81
|
-
<${Text}> ${state.secondaries.join(", ")}</>
|
|
82
|
-
</>`
|
|
83
|
-
: null}
|
|
84
|
-
${state.branch
|
|
85
|
-
? h`<${Box}>
|
|
86
|
-
<${Text} color="yellow">Branch </>
|
|
87
|
-
<${Text}>${state.branch}</>
|
|
88
|
-
</>`
|
|
89
|
-
: null}
|
|
90
|
-
${state.mrIid
|
|
91
|
-
? h`<${Box}>
|
|
92
|
-
<${Text} color="yellow">MR </>
|
|
93
|
-
<${Text}>!${state.mrIid}</>
|
|
94
|
-
</>`
|
|
95
|
-
: null}
|
|
96
|
-
${state.lastError
|
|
97
|
-
? h`<${Box}>
|
|
98
|
-
<${Text} color="red">Error </>
|
|
99
|
-
<${Text}>${state.lastError}</>
|
|
100
|
-
</>`
|
|
101
|
-
: null}
|
|
102
|
-
<${Box} marginTop=${1}>
|
|
103
|
-
<${Text} dimColor>${`Created ${relTime(state.createdAt)} · Updated ${relTime(state.updatedAt)}`}</>
|
|
104
|
-
</>
|
|
105
|
-
${analysisSummary
|
|
106
|
-
? h`<${Box} flexDirection="column" marginTop=${1}>
|
|
107
|
-
<${Text} dimColor>${"Cached analysis:"}</>
|
|
108
|
-
<${Text}>${` ${analysisSummary.changes} change(s) · ${analysisSummary.repos} repo(s) · ${analysisSummary.mrTitle ?? "(no proposed title)"}`}</>
|
|
109
|
-
</>`
|
|
110
|
-
: h`<${Box} marginTop=${1}>
|
|
111
|
-
<${Text} dimColor>${"No cached analysis on disk."}</>
|
|
112
|
-
</>`}
|
|
113
|
-
</>`;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
async function listCommand(argv) {
|
|
117
|
-
const json = argv.includes("--json");
|
|
118
|
-
const sessions = await listSessions();
|
|
119
|
-
if (json) {
|
|
120
|
-
process.stdout.write(`${JSON.stringify(sessions, null, 2)}\n`);
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
const head = await getHead();
|
|
124
|
-
await runApp(h`<${SessionsTable} sessions=${sessions} head=${head} />`);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
async function showCommand(argv) {
|
|
128
|
-
const json = argv.includes("--json");
|
|
129
|
-
const explicitIid = Number(argv[2]);
|
|
130
|
-
const explicitRepo = getFlag(argv, "--repo");
|
|
131
|
-
const target = await resolveSessionTarget({
|
|
132
|
-
explicitIid: Number.isInteger(explicitIid) && explicitIid > 0 ? explicitIid : null,
|
|
133
|
-
explicitRepo,
|
|
134
|
-
});
|
|
135
|
-
if (!target?.repo || !target?.iid) {
|
|
136
|
-
console.error(
|
|
137
|
-
"No session target. Pass an <iid>, set --repo, or run analyze first.",
|
|
138
|
-
);
|
|
139
|
-
process.exit(1);
|
|
140
|
-
}
|
|
141
|
-
const state = await readState(target.repo, target.iid);
|
|
142
|
-
if (!state) {
|
|
143
|
-
console.error(`No session at ${sessionDir(target.repo, target.iid)}`);
|
|
144
|
-
process.exit(1);
|
|
145
|
-
}
|
|
146
|
-
const analysis = await readAnalysis(target.repo, target.iid);
|
|
147
|
-
if (json) {
|
|
148
|
-
process.stdout.write(`${JSON.stringify({ state, analysis }, null, 2)}\n`);
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
const summary = analysis
|
|
152
|
-
? {
|
|
153
|
-
changes: analysis.changes?.length ?? 0,
|
|
154
|
-
repos: analysis.repos?.length ?? 0,
|
|
155
|
-
mrTitle: analysis.mrTitle ?? null,
|
|
156
|
-
}
|
|
157
|
-
: null;
|
|
158
|
-
await runApp(h`<${SessionDetail} state=${state} analysisSummary=${summary} />`);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
async function cleanCommand(argv) {
|
|
162
|
-
if (argv.includes("--all")) {
|
|
163
|
-
await cleanAll();
|
|
164
|
-
process.stderr.write(`✓ Removed all sessions\n`);
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
const explicitIid = Number(argv[2]);
|
|
168
|
-
const explicitRepo = getFlag(argv, "--repo");
|
|
169
|
-
const target = await resolveSessionTarget({
|
|
170
|
-
explicitIid: Number.isInteger(explicitIid) && explicitIid > 0 ? explicitIid : null,
|
|
171
|
-
explicitRepo,
|
|
172
|
-
});
|
|
173
|
-
if (!target?.repo || !target?.iid) {
|
|
174
|
-
console.error(
|
|
175
|
-
"No session target. Pass an <iid>, set --repo, or use --all to wipe everything.",
|
|
176
|
-
);
|
|
177
|
-
process.exit(1);
|
|
178
|
-
}
|
|
179
|
-
const removed = await cleanSession(target.repo, target.iid);
|
|
180
|
-
if (removed) process.stderr.write(`✓ Removed ${target.repo}#${target.iid}\n`);
|
|
181
|
-
else process.stderr.write(`Nothing to remove at ${target.repo}#${target.iid}\n`);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export async function cmdSession(argv) {
|
|
185
|
-
const sub = argv[1] ?? "list";
|
|
186
|
-
if (sub === "list" || sub === "ls") return listCommand(argv);
|
|
187
|
-
if (sub === "show") return showCommand(argv);
|
|
188
|
-
if (sub === "clean" || sub === "rm") return cleanCommand(argv);
|
|
189
|
-
console.error(`Unknown subcommand: ${sub}`);
|
|
190
|
-
console.error("Subcommands: list, show, clean");
|
|
191
|
-
process.exit(1);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Top-level `forge show [<iid>]` — re-renders the cached analysis from
|
|
196
|
-
* the session through the same Ink view as live analyze. Resolves <iid> via
|
|
197
|
-
* positional arg or HEAD pointer.
|
|
198
|
-
*/
|
|
199
|
-
export async function cmdShow(argv) {
|
|
200
|
-
const explicitIid = Number(argv[1]);
|
|
201
|
-
const explicitRepo = getFlag(argv, "--repo");
|
|
202
|
-
const json = argv.includes("--json");
|
|
203
|
-
const target = await resolveSessionTarget({
|
|
204
|
-
explicitIid: Number.isInteger(explicitIid) && explicitIid > 0 ? explicitIid : null,
|
|
205
|
-
explicitRepo,
|
|
206
|
-
});
|
|
207
|
-
if (!target?.repo || !target?.iid) {
|
|
208
|
-
console.error(
|
|
209
|
-
"No session target. Pass an <iid>, or run analyze first to seed HEAD.",
|
|
210
|
-
);
|
|
211
|
-
process.exit(1);
|
|
212
|
-
}
|
|
213
|
-
const analysis = await readAnalysis(target.repo, target.iid);
|
|
214
|
-
if (!analysis) {
|
|
215
|
-
console.error(
|
|
216
|
-
`No cached analysis at ${sessionDir(target.repo, target.iid)}.\n` +
|
|
217
|
-
`Run: forge analyze ${target.iid}`,
|
|
218
|
-
);
|
|
219
|
-
process.exit(1);
|
|
220
|
-
}
|
|
221
|
-
if (json) {
|
|
222
|
-
process.stdout.write(`${JSON.stringify(analysis, null, 2)}\n`);
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
// Reuse analyze.js's ResultBlock by importing it lazily — keeps the
|
|
226
|
-
// dependency cycle simple (session.js depends on the analyze view, but
|
|
227
|
-
// analyze.js doesn't depend on session.js's UI).
|
|
228
|
-
const { renderCachedResult } = await import("./analyze.js");
|
|
229
|
-
await renderCachedResult(analysis);
|
|
230
|
-
}
|
package/bin/cli/sessionStore.js
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session store for the ship workflow.
|
|
3
|
-
*
|
|
4
|
-
* ~/.forge/sessions/<canonical-repo>/<iid>/
|
|
5
|
-
* analysis.json — last cached ForgeAgent.analyzeIssue result
|
|
6
|
-
* state.json — { phase, primary, secondaries, branch?, mrIid?, ... }
|
|
7
|
-
* events.ndjson — append-only log of every event we received
|
|
8
|
-
*
|
|
9
|
-
* ~/.forge/sessions/HEAD
|
|
10
|
-
* — single line: "<canonical-repo>/<iid>" of the most recently touched
|
|
11
|
-
* session. Used so subsequent commands without an explicit <iid> can
|
|
12
|
-
* resume the current unit of work, in the spirit of git's HEAD.
|
|
13
|
-
*
|
|
14
|
-
* Override the root with FORGE_SESSIONS_PATH (test isolation).
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { existsSync } from "node:fs";
|
|
18
|
-
import fs from "node:fs/promises";
|
|
19
|
-
import os from "node:os";
|
|
20
|
-
import path from "node:path";
|
|
21
|
-
import { canonicalRepoId } from "./utils.js";
|
|
22
|
-
|
|
23
|
-
export const PHASES = Object.freeze({
|
|
24
|
-
ANALYZED: "analyzed",
|
|
25
|
-
REFINED: "refined",
|
|
26
|
-
VALIDATED: "validated",
|
|
27
|
-
APPLIED: "applied",
|
|
28
|
-
WATCHING: "watching",
|
|
29
|
-
MERGED: "merged",
|
|
30
|
-
RESOLVED: "resolved",
|
|
31
|
-
CLOSED: "closed",
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
function rootDir() {
|
|
35
|
-
return (
|
|
36
|
-
process.env.FORGE_SESSIONS_PATH ??
|
|
37
|
-
path.join(os.homedir(), ".forge", "sessions")
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Resolve the on-disk directory for a session. Repo is canonicalised so
|
|
43
|
-
* "iplayulisten/web-app" and "gitlab:iplayulisten/web-app" map to the
|
|
44
|
-
* same folder.
|
|
45
|
-
*/
|
|
46
|
-
export function sessionDir(repo, iid) {
|
|
47
|
-
return path.join(rootDir(), canonicalRepoId(String(repo)), String(iid));
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async function ensureDir(dir) {
|
|
51
|
-
await fs.mkdir(dir, { recursive: true, mode: 0o700 });
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export async function writeAnalysis(repo, iid, analysis) {
|
|
55
|
-
const dir = sessionDir(repo, iid);
|
|
56
|
-
await ensureDir(dir);
|
|
57
|
-
const file = path.join(dir, "analysis.json");
|
|
58
|
-
await fs.writeFile(file, JSON.stringify(analysis, null, 2), { encoding: "utf8", mode: 0o600 });
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export async function readAnalysis(repo, iid) {
|
|
62
|
-
const file = path.join(sessionDir(repo, iid), "analysis.json");
|
|
63
|
-
if (!existsSync(file)) return null;
|
|
64
|
-
return JSON.parse(await fs.readFile(file, "utf8"));
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export async function readState(repo, iid) {
|
|
68
|
-
const file = path.join(sessionDir(repo, iid), "state.json");
|
|
69
|
-
if (!existsSync(file)) return null;
|
|
70
|
-
return JSON.parse(await fs.readFile(file, "utf8"));
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export async function updateState(repo, iid, partial) {
|
|
74
|
-
const dir = sessionDir(repo, iid);
|
|
75
|
-
await ensureDir(dir);
|
|
76
|
-
const file = path.join(dir, "state.json");
|
|
77
|
-
const now = new Date().toISOString();
|
|
78
|
-
const prev = (await readState(repo, iid)) ?? {
|
|
79
|
-
repo: canonicalRepoId(String(repo)),
|
|
80
|
-
iid: Number(iid),
|
|
81
|
-
createdAt: now,
|
|
82
|
-
};
|
|
83
|
-
const next = { ...prev, ...partial, updatedAt: now };
|
|
84
|
-
await fs.writeFile(file, JSON.stringify(next, null, 2), { encoding: "utf8", mode: 0o600 });
|
|
85
|
-
return next;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export async function appendEvent(repo, iid, evt) {
|
|
89
|
-
const dir = sessionDir(repo, iid);
|
|
90
|
-
await ensureDir(dir);
|
|
91
|
-
await fs.appendFile(
|
|
92
|
-
path.join(dir, "events.ndjson"),
|
|
93
|
-
`${JSON.stringify({ ts: new Date().toISOString(), ...evt })}\n`,
|
|
94
|
-
"utf8",
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export async function setHead(repo, iid) {
|
|
99
|
-
const root = rootDir();
|
|
100
|
-
await fs.mkdir(root, { recursive: true });
|
|
101
|
-
await fs.writeFile(
|
|
102
|
-
path.join(root, "HEAD"),
|
|
103
|
-
`${canonicalRepoId(String(repo))}/${iid}\n`,
|
|
104
|
-
"utf8",
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Return { repo, iid } of the HEAD session, or null.
|
|
110
|
-
*/
|
|
111
|
-
export async function getHead() {
|
|
112
|
-
const file = path.join(rootDir(), "HEAD");
|
|
113
|
-
if (!existsSync(file)) return null;
|
|
114
|
-
const raw = (await fs.readFile(file, "utf8")).trim();
|
|
115
|
-
const lastSlash = raw.lastIndexOf("/");
|
|
116
|
-
if (lastSlash <= 0) return null;
|
|
117
|
-
const repo = raw.slice(0, lastSlash);
|
|
118
|
-
const iid = Number(raw.slice(lastSlash + 1));
|
|
119
|
-
if (!Number.isInteger(iid) || iid <= 0) return null;
|
|
120
|
-
return { repo, iid };
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Walk the on-disk tree and return every session it finds. Sorted by
|
|
125
|
-
* updatedAt descending (most recent first).
|
|
126
|
-
*/
|
|
127
|
-
export async function listSessions() {
|
|
128
|
-
const root = rootDir();
|
|
129
|
-
if (!existsSync(root)) return [];
|
|
130
|
-
|
|
131
|
-
const out = [];
|
|
132
|
-
const repoDirs = await safeReadDir(root);
|
|
133
|
-
for (const repoEntry of repoDirs) {
|
|
134
|
-
if (!repoEntry.isDirectory()) continue;
|
|
135
|
-
// Repos may be nested one level (e.g. "iplayulisten/web-app").
|
|
136
|
-
const repoLevel1 = path.join(root, repoEntry.name);
|
|
137
|
-
const repoSubdirs = await safeReadDir(repoLevel1);
|
|
138
|
-
for (const sub of repoSubdirs) {
|
|
139
|
-
if (!sub.isDirectory()) continue;
|
|
140
|
-
const candidatePath = path.join(repoLevel1, sub.name);
|
|
141
|
-
|
|
142
|
-
// Two layouts:
|
|
143
|
-
// a) repoLevel1/<iid>/state.json (single-segment repo)
|
|
144
|
-
// b) repoLevel1/<sub>/<iid>/state.json (two-segment repo)
|
|
145
|
-
if (existsSync(path.join(candidatePath, "state.json"))) {
|
|
146
|
-
const state = JSON.parse(
|
|
147
|
-
await fs.readFile(path.join(candidatePath, "state.json"), "utf8"),
|
|
148
|
-
);
|
|
149
|
-
out.push(state);
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
const iidEntries = await safeReadDir(candidatePath);
|
|
153
|
-
for (const iidEntry of iidEntries) {
|
|
154
|
-
if (!iidEntry.isDirectory()) continue;
|
|
155
|
-
const stateFile = path.join(candidatePath, iidEntry.name, "state.json");
|
|
156
|
-
if (!existsSync(stateFile)) continue;
|
|
157
|
-
const state = JSON.parse(await fs.readFile(stateFile, "utf8"));
|
|
158
|
-
out.push(state);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
out.sort((a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? ""));
|
|
164
|
-
return out;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
async function safeReadDir(dir) {
|
|
168
|
-
try {
|
|
169
|
-
return await fs.readdir(dir, { withFileTypes: true });
|
|
170
|
-
} catch {
|
|
171
|
-
return [];
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export async function cleanSession(repo, iid) {
|
|
176
|
-
const dir = sessionDir(repo, iid);
|
|
177
|
-
if (!existsSync(dir)) return false;
|
|
178
|
-
await fs.rm(dir, { recursive: true, force: true });
|
|
179
|
-
const head = await getHead();
|
|
180
|
-
if (head && canonicalRepoId(head.repo) === canonicalRepoId(String(repo)) && head.iid === Number(iid)) {
|
|
181
|
-
await fs.rm(path.join(rootDir(), "HEAD"), { force: true });
|
|
182
|
-
}
|
|
183
|
-
return true;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
export async function cleanAll() {
|
|
187
|
-
const root = rootDir();
|
|
188
|
-
if (!existsSync(root)) return;
|
|
189
|
-
await fs.rm(root, { recursive: true, force: true });
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Resolve a session target from CLI argv. Honours an explicit positional iid
|
|
194
|
-
* or HEAD as fallback. Returns { repo, iid } or null.
|
|
195
|
-
*
|
|
196
|
-
* forge show → HEAD
|
|
197
|
-
* forge show 42 → primary repo + iid 42
|
|
198
|
-
* forge show 42 --repo X → repo X + iid 42
|
|
199
|
-
*/
|
|
200
|
-
export async function resolveSessionTarget({ explicitIid, explicitRepo }) {
|
|
201
|
-
if (Number.isInteger(explicitIid) && explicitIid > 0) {
|
|
202
|
-
// repo defaults to HEAD's repo if available, else explicitRepo, else
|
|
203
|
-
// the configStore primary. Keeps `show 42` working when there's a
|
|
204
|
-
// prior HEAD that was on the same repo.
|
|
205
|
-
if (explicitRepo) return { repo: explicitRepo, iid: explicitIid };
|
|
206
|
-
const head = await getHead();
|
|
207
|
-
if (head) return { repo: head.repo, iid: explicitIid };
|
|
208
|
-
return { repo: null, iid: explicitIid };
|
|
209
|
-
}
|
|
210
|
-
return await getHead();
|
|
211
|
-
}
|