@capagents/forgeqe 1.3.2 → 2.0.1
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/HOW_TO_USE.md +373 -9
- package/README.md +55 -4
- package/docs/ARCHITECTURE.md +62 -1
- package/docs/CONTAINERS.md +227 -0
- package/docs/COST_ARCHITECTURE.md +32 -0
- package/docs/DESKTOP-CI.md +87 -0
- package/docs/DESKTOP.md +387 -0
- package/docs/MOBILE.md +228 -0
- package/docs/feature-test-prompts.md +25 -0
- package/docs/security-data-flow.html +440 -3
- package/docs/user-guide.html +797 -415
- package/env.example.yaml +67 -0
- package/forgeqe.example.yaml +56 -1
- package/llms.example.json +7 -0
- package/package.json +4 -1
- package/prompts/brain.md +31 -0
- package/prompts/find-tests.md +1 -0
- package/py/forgeqe_desktop/__init__.py +1 -0
- package/py/forgeqe_desktop/__main__.py +3 -0
- package/py/forgeqe_desktop/apps.py +80 -0
- package/py/forgeqe_desktop/checks.py +168 -0
- package/py/forgeqe_desktop/cli.py +90 -0
- package/py/forgeqe_desktop/handhooks.py +293 -0
- package/py/forgeqe_desktop/handrecord.py +239 -0
- package/py/forgeqe_desktop/heal.py +107 -0
- package/py/forgeqe_desktop/models.py +208 -0
- package/py/forgeqe_desktop/pywinauto_driver.py +217 -0
- package/py/forgeqe_desktop/record.py +150 -0
- package/py/forgeqe_desktop/replay.py +345 -0
- package/py/forgeqe_desktop/service.py +356 -0
- package/py/forgeqe_desktop/session.py +60 -0
- package/py/forgeqe_desktop/ufo_bridge.py +86 -0
- package/py/forgeqe_desktop/ufo_runner.py +305 -0
- package/py/forgeqe_desktop/visual.py +112 -0
- package/py/forgeqe_desktop/workflow.py +338 -0
- package/py/forgeqe_engine/llm.py +54 -4
- package/py/forgeqe_engine/model_params.py +169 -0
- package/py/forgeqe_mobile/__init__.py +1 -0
- package/py/forgeqe_mobile/__main__.py +3 -0
- package/py/forgeqe_mobile/appium_driver.py +342 -0
- package/py/forgeqe_mobile/apps.py +84 -0
- package/py/forgeqe_mobile/cli.py +70 -0
- package/py/forgeqe_mobile/explore.py +203 -0
- package/py/forgeqe_mobile/hyperexecute.py +261 -0
- package/py/forgeqe_mobile/maestro.py +321 -0
- package/py/forgeqe_mobile/service.py +332 -0
- package/skills/testcontainers/SKILL.md +42 -0
- package/src/agents.ts +11 -2
- package/src/api/plan.ts +2 -0
- package/src/api/write.ts +2 -0
- package/src/auth/copilot.ts +130 -0
- package/src/auth/signin.ts +54 -1
- package/src/brain/index.ts +26 -4
- package/src/capabilities/guide.ts +2 -0
- package/src/capabilities/registry.ts +110 -2
- package/src/capabilities/status.ts +15 -0
- package/src/cases/rca.ts +2 -0
- package/src/childEnv.ts +4 -1
- package/src/cli/args.ts +3 -2
- package/src/cli/help.ts +24 -3
- package/src/cli/index.ts +47 -3
- package/src/code/find.ts +26 -0
- package/src/code/loop.ts +4 -1
- package/src/code/prompt.ts +2 -1
- package/src/code/prreview.ts +2 -0
- package/src/code/review.ts +6 -2
- package/src/code/runtime.ts +34 -3
- package/src/commands.ts +6 -1
- package/src/config.ts +159 -3
- package/src/containers/command.ts +68 -0
- package/src/containers/compose.ts +173 -0
- package/src/containers/config.ts +283 -0
- package/src/containers/mock.ts +156 -0
- package/src/containers/run.ts +362 -0
- package/src/containers/tests.ts +80 -0
- package/src/context.ts +33 -6
- package/src/copilot.ts +155 -0
- package/src/desktop/bridge.ts +229 -0
- package/src/desktop/command.ts +350 -0
- package/src/desktop/edit.ts +217 -0
- package/src/desktop/junit.ts +35 -0
- package/src/desktop/report.ts +155 -0
- package/src/desktop/run.ts +252 -0
- package/src/desktop/setup.ts +134 -0
- package/src/engine/bridge.ts +12 -5
- package/src/engine/setup.ts +3 -3
- package/src/environments.ts +566 -0
- package/src/evals/domain.ts +1 -0
- package/src/explore/charters.ts +2 -0
- package/src/guardrails.ts +145 -0
- package/src/heal/loop.ts +4 -1
- package/src/heal/prompt.ts +2 -1
- package/src/init.ts +5 -2
- package/src/llm.ts +23 -2
- package/src/mcp/attachtools.ts +16 -4
- package/src/mcp/captools.ts +27 -0
- package/src/mcp/containertools.ts +212 -0
- package/src/mcp/desktoptools.ts +334 -0
- package/src/mcp/mobiletools.ts +132 -0
- package/src/mcp/reporttools.ts +17 -2
- package/src/mcp/repotests.ts +22 -3
- package/src/mcp/routing.ts +11 -5
- package/src/mcp/scope.ts +210 -0
- package/src/mcp/server.ts +80 -5
- package/src/mcp/tools.ts +38 -1
- package/src/mobile/command.ts +245 -0
- package/src/mobile/run.ts +226 -0
- package/src/pack/pipeline.ts +44 -2
- package/src/refine.ts +3 -0
- package/src/report/html.ts +3 -0
- package/src/report/template.html +48 -48
- package/src/run.ts +7 -3
- package/src/tokenomics/ledger.ts +3 -1
- package/src/tui/App.tsx +23 -0
- package/src/usage.ts +1 -1
package/src/run.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { createRequire } from "node:module"
|
|
|
4
4
|
import path from "node:path"
|
|
5
5
|
|
|
6
6
|
import { assertGoalUrlsAllowed, hostAllowed, normalizeHttpUrl } from "./guard.ts"
|
|
7
|
+
import { ghAuthToken } from "./cases/github.ts"
|
|
7
8
|
import { missingKey } from "./llm.ts"
|
|
8
9
|
import type { AgentEvent, ReplayMode, RunResult } from "./types.ts"
|
|
9
10
|
import { browserConfigFor, type AppConfig, type BrowserProvider } from "./config.ts"
|
|
@@ -21,7 +22,9 @@ import { historyFile, recordQuality } from "./quality/history.ts"
|
|
|
21
22
|
import { compareVisual, engineVisual } from "./quality/visual.ts"
|
|
22
23
|
import { enginePrompts, prompt } from "./prompts.ts"
|
|
23
24
|
import { knowledgeBlock, readKnowledge, relevantKnowledge } from "./knowledge.ts"
|
|
25
|
+
import { environmentBrief } from "./environments.ts"
|
|
24
26
|
import { registryMode } from "./registry/index.ts"
|
|
27
|
+
import { guardrailsNotes } from "./guardrails.ts"
|
|
25
28
|
|
|
26
29
|
export type ExecuteOptions = {
|
|
27
30
|
config: AppConfig
|
|
@@ -211,7 +214,7 @@ export async function executeRun(opts: ExecuteOptions): Promise<{ result: RunRes
|
|
|
211
214
|
return withReport(out)
|
|
212
215
|
}
|
|
213
216
|
|
|
214
|
-
const missing = missingKey(opts.config.llm)
|
|
217
|
+
const missing = missingKey(opts.config.llm, "engine", ghAuthToken)
|
|
215
218
|
if (missing) throw new Error(missing)
|
|
216
219
|
// A remote grid's keys are checked here, before the engine starts, rather than failing inside it.
|
|
217
220
|
if (browser.remote) {
|
|
@@ -220,9 +223,10 @@ export async function executeRun(opts: ExecuteOptions): Promise<{ result: RunRes
|
|
|
220
223
|
}
|
|
221
224
|
const log = (text: string) => opts.onEvent?.({ type: "log", level: "info", text })
|
|
222
225
|
const python = await ensureEngine(log)
|
|
223
|
-
// The browser agent's added instructions: forgeqe.yaml's, prompts/browser-extra.md,
|
|
226
|
+
// The browser agent's added instructions: forgeqe.yaml's, prompts/browser-extra.md, the product knowledge that matches the goal, and the guardrails.
|
|
224
227
|
const knowledge = opts.config.knowledge && opts.config.knowledge.browserMaxChars > 0 ? knowledgeBlock(relevantKnowledge(readKnowledge(opts.config.knowledge.dir), goal, opts.config.knowledge.browserMaxChars, 2)) : ""
|
|
225
|
-
|
|
228
|
+
// The team's guardrails come last, so nothing added after them reads as overriding them.
|
|
229
|
+
const extend = [opts.config.prompts.stepInstruction, prompt("browser-extra"), knowledge, environmentBrief(opts.config, "browser"), guardrailsNotes(opts.config) || ""]
|
|
226
230
|
.map((s) => s.trim())
|
|
227
231
|
.filter(Boolean)
|
|
228
232
|
.join("\n\n")
|
package/src/tokenomics/ledger.ts
CHANGED
|
@@ -18,7 +18,7 @@ import { costOf, recordUsage, type Price, type Role } from "../usage.ts"
|
|
|
18
18
|
export type Trigger = "tui" | "cli" | "mcp" | "ci" | "monitor" | "schedule"
|
|
19
19
|
|
|
20
20
|
/** What a call was for, from the tools it asked for: no tools is the model thinking or answering. */
|
|
21
|
-
export type Purpose = "reasoning" | "planning" | "search" | "file read" | "edit" | "shell" | "browser" | "integration" | "delegation" | "unattributed"
|
|
21
|
+
export type Purpose = "reasoning" | "planning" | "search" | "file read" | "edit" | "shell" | "browser" | "desktop" | "mobile" | "integration" | "delegation" | "unattributed"
|
|
22
22
|
|
|
23
23
|
/** What ForgeQE was doing when the call was made. Set with withUsageScope; inner scopes add to outer ones. */
|
|
24
24
|
export type UsageScope = {
|
|
@@ -130,6 +130,8 @@ export function purposeOf(tools: string[] | undefined): Purpose {
|
|
|
130
130
|
const DEFAULT_JOB: Record<Role, string> = {
|
|
131
131
|
"ForgeQE's agent": "chat",
|
|
132
132
|
"browser agent": "browser test",
|
|
133
|
+
"desktop agent": "desktop test",
|
|
134
|
+
"mobile agent": "mobile test",
|
|
133
135
|
Scribe: "write tests",
|
|
134
136
|
reviewer: "review",
|
|
135
137
|
judge: "eval",
|
package/src/tui/App.tsx
CHANGED
|
@@ -15,6 +15,7 @@ import { FAILURE_ACTION, FAILURE_LABEL } from "../cases/failure.ts"
|
|
|
15
15
|
import { authStatus, openInBrowser, signIn, signOut, type AuthIO } from "../auth/signin.ts"
|
|
16
16
|
import { HELP, parseCommand } from "../commands.ts"
|
|
17
17
|
import { loadConfig, selectProfile, type AppConfig, type BrowserProvider } from "../config.ts"
|
|
18
|
+
import { appsText, exportEnvironment, withEnvironment } from "../environments.ts"
|
|
18
19
|
import { TOOLS, type AskQuestion, type ToolEvent } from "../mcp/tools.ts"
|
|
19
20
|
import type { executeRun } from "../run.ts"
|
|
20
21
|
import { bundleLogs, logEvent } from "../sessionLog.ts"
|
|
@@ -1443,6 +1444,28 @@ export function App({ options }: { options: TuiOptions }) {
|
|
|
1443
1444
|
}
|
|
1444
1445
|
return
|
|
1445
1446
|
}
|
|
1447
|
+
if (cmd.type === "env") {
|
|
1448
|
+
try {
|
|
1449
|
+
const cfg = configRef.current
|
|
1450
|
+
if (!cfg) throw new Error("Config is not loaded.")
|
|
1451
|
+
if (!cmd.name) {
|
|
1452
|
+
push("sys", appsText(cfg))
|
|
1453
|
+
return
|
|
1454
|
+
}
|
|
1455
|
+
configRef.current = withEnvironment(cfg, cmd.name)
|
|
1456
|
+
exportEnvironment(configRef.current)
|
|
1457
|
+
// Reloads in this session (/init, a profile switch) keep the environment.
|
|
1458
|
+
process.env.FORGEQE_ENV = cmd.name
|
|
1459
|
+
push("sys", `environment ${cmd.name}`)
|
|
1460
|
+
if (brainRef.current) {
|
|
1461
|
+
closeBrain()
|
|
1462
|
+
push("sys", "The agent switches to this environment on your next message and keeps the conversation.")
|
|
1463
|
+
}
|
|
1464
|
+
} catch (err) {
|
|
1465
|
+
push("err", (err as Error).message)
|
|
1466
|
+
}
|
|
1467
|
+
return
|
|
1468
|
+
}
|
|
1446
1469
|
if (cmd.type === "init") {
|
|
1447
1470
|
// forgeqe init in this folder, then the session reads what it wrote: the start screen updates at once.
|
|
1448
1471
|
try {
|
package/src/usage.ts
CHANGED
|
@@ -98,7 +98,7 @@ export function usageLine(usage: Usage, cost?: Cost | null): string {
|
|
|
98
98
|
// The meter: every model session reports here, by role
|
|
99
99
|
// ---------------------------------------------------------------------------------------------
|
|
100
100
|
|
|
101
|
-
export type Role = "ForgeQE's agent" | "browser agent" | "Scribe" | "reviewer" | "judge" | "refiner" | "root-cause analyst"
|
|
101
|
+
export type Role = "ForgeQE's agent" | "browser agent" | "desktop agent" | "mobile agent" | "Scribe" | "reviewer" | "judge" | "refiner" | "root-cause analyst"
|
|
102
102
|
|
|
103
103
|
type Entry = { usage: Usage; cost?: Cost; priced: boolean }
|
|
104
104
|
|