@capagents/forgeqe 2.2.5 → 2.2.7
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 +15 -12
- package/README.md +16 -0
- package/THIRD_PARTY_NOTICES.md +2 -30
- package/dist/forgeqe.js +841 -841
- package/docs/user-guide.html +14 -12
- package/llms.example.json +1 -1
- package/package.json +6 -1
- package/py/forgeqe_engine/copilot_gateway.py +21 -9
package/docs/user-guide.html
CHANGED
|
@@ -446,7 +446,7 @@ forgeqe models # check the profiles
|
|
|
446
446
|
forgeqe start # the shell
|
|
447
447
|
</code></pre>
|
|
448
448
|
<p>With GitHub Copilot licences instead of a model key, sign in rather than exporting one, and set <code>llm.active: copilot</code> in <code>forgeqe.yaml</code> (or <code>"default": "copilot"</code> in <code>llms.json</code>). The browser engine then runs on your Copilot seat; ForgeQE's agent and Scribe need another profile for now:</p>
|
|
449
|
-
<pre><code class="language-bash">forgeqe auth login copilot #
|
|
449
|
+
<pre><code class="language-bash">forgeqe auth login copilot # opens GitHub in your browser to sign in
|
|
450
450
|
forgeqe models # the copilot profile is active
|
|
451
451
|
</code></pre>
|
|
452
452
|
<p>In the shell, type a request and press Enter:</p>
|
|
@@ -569,19 +569,20 @@ bun src/index.ts init --global --profile azure-gpt4o
|
|
|
569
569
|
<tbody>
|
|
570
570
|
<tr><td><code>model</code></td><td>The Copilot model, as the Copilot SDK names it (<code>gpt-4.1</code>, <code>claude-sonnet-4.6</code>). It must take screenshots. The sign-in lists your seat's models and which of them take images.</td></tr>
|
|
571
571
|
<tr><td><code>engine_model</code></td><td>Optional. Another Copilot model for the browser engine and the desktop agent.</td></tr>
|
|
572
|
-
<tr><td><code>api_key_env</code></td><td>Optional.
|
|
572
|
+
<tr><td><code>api_key_env</code></td><td>Optional. A variable that must hold the GitHub token for this profile. Without it ForgeQE uses <code>COPILOT_GITHUB_TOKEN</code>, then a token <code>forgeqe auth login copilot</code> saved, then the browser sign-in.</td></tr>
|
|
573
573
|
</tbody>
|
|
574
574
|
</table></div>
|
|
575
|
-
<p>Sign in once per machine:</p>
|
|
575
|
+
<p>Sign in once per machine (Windows, macOS or Linux):</p>
|
|
576
576
|
<pre><code class="language-bash">forgeqe auth login copilot
|
|
577
577
|
</code></pre>
|
|
578
|
-
<p>It offers two ways:</p>
|
|
578
|
+
<p>It offers two ways, the ones GitHub's Copilot SDK recommends:</p>
|
|
579
579
|
<ul>
|
|
580
|
-
<li><strong>
|
|
581
|
-
<li><strong>
|
|
580
|
+
<li><strong>Sign in with GitHub in the browser</strong> (recommended on your own computer). ForgeQE runs GitHub's own Copilot sign-in (<code>copilot login</code> from GitHub's Copilot CLI, downloaded once into <code>~/.forgeqe/tools</code> and checked against GitHub's checksums). Your browser opens GitHub; approve <strong>GitHub Copilot CLI</strong> there and you are signed in. GitHub's CLI keeps the sign-in in your system's credential store (Windows Credential Manager, the macOS Keychain); ForgeQE never sees a token. On a remote machine it shows a code to enter at github.com/login/device instead.</li>
|
|
581
|
+
<li><strong>A fine-grained token</strong>, for machines without a browser. ForgeQE opens GitHub's token page: set <strong>Resource owner</strong> to your personal account and add the <strong>Copilot Requests</strong> permission, then paste the token (<code>github_pat_...</code>). Each character shows as <code>*</code>, and ForgeQE confirms what it got (<code>github_pat_11AB…Wz9Q (93 characters)</code>). The token goes to your system's credential store like ForgeQE's other secrets. Classic tokens (<code>ghp_</code>) do not work with Copilot.</li>
|
|
582
582
|
</ul>
|
|
583
|
-
<p>Either way ForgeQE checks the
|
|
584
|
-
<p>
|
|
583
|
+
<p>Either way ForgeQE checks the sign-in by asking Copilot for your seat's models and lists them; the first time, the Copilot SDK downloads Copilot's runtime from GitHub (checked against GitHub's checksums). <code>forgeqe auth</code> shows the sign-in on its <code>Copilot</code> line; <code>forgeqe auth logout copilot</code> makes ForgeQE stop using it (GitHub keeps a browser sign-in until you revoke <strong>GitHub Copilot CLI</strong> at github.com/settings/applications).</p>
|
|
584
|
+
<p>If your organization uses SAML single sign-on, GitHub asks you to authorize the organization during the browser sign-in. A Copilot Business or Enterprise seat needs your organization to allow <strong>Copilot CLI</strong> in its Copilot policies.</p>
|
|
585
|
+
<p>A token reaches only the gateway's process. The engine gets the gateway's address and a one-time key that works nowhere else; the gateway refuses requests without that key and any request a web page sends. Model-run shell commands never see the token or the key.</p>
|
|
585
586
|
<p>Which part uses what:</p>
|
|
586
587
|
<div class="tbl"><table>
|
|
587
588
|
<thead>
|
|
@@ -602,8 +603,9 @@ bun src/index.ts init --global --profile azure-gpt4o
|
|
|
602
603
|
<tr><th>ForgeQE says</th><th>What to do</th></tr>
|
|
603
604
|
</thead>
|
|
604
605
|
<tbody>
|
|
605
|
-
<tr><td><code>GitHub Copilot
|
|
606
|
-
<tr><td><code>GitHub
|
|
606
|
+
<tr><td><code>GitHub Copilot is not signed in</code></td><td>Run <code>forgeqe auth login copilot</code> (or <code>/auth copilot</code> in the shell) and sign in in the browser, or set <code>COPILOT_GITHUB_TOKEN</code>.</td></tr>
|
|
607
|
+
<tr><td><code>The GitHub sign-in did not finish</code></td><td>The browser sign-in was cancelled or denied. Run <code>forgeqe auth login copilot</code> again; with SAML single sign-on, authorize your organization when GitHub asks.</td></tr>
|
|
608
|
+
<tr><td><code>GitHub Copilot does not take classic tokens (ghp_)</code></td><td>Sign in in the browser instead, or make a fine-grained token with the Copilot Requests permission, owned by your personal account.</td></tr>
|
|
607
609
|
<tr><td><code>GitHub Copilot did not accept the token</code></td><td>The token has no Copilot Requests permission, has expired, or the account has no Copilot seat.</td></tr>
|
|
608
610
|
<tr><td><code>… must be a Copilot model id</code>, <code>engine_model must be a Copilot model id</code></td><td>Fix that field in <code>llms.json</code>: the sign-in lists the seat's models. A GitHub Models id such as <code>openai/gpt-4.1</code> is not a Copilot id; use <code>gpt-4.1</code>.</td></tr>
|
|
609
611
|
<tr><td><code>ForgeQE's agent and Scribe cannot run on a github_copilot profile yet</code></td><td>Pick another profile for them (<code>--profile</code>, or Tab in the shell), or set <code>code.model</code>.</td></tr>
|
|
@@ -633,7 +635,7 @@ forgeqe auth logout jira
|
|
|
633
635
|
<tbody>
|
|
634
636
|
<tr><td>Azure DevOps</td><td><strong>Sign in with Microsoft in the browser</strong> through the Azure CLI (<code>az login</code>); ForgeQE saves nothing, and the Azure CLI renews the sign-in. Or paste a personal access token: the token page opens with the scopes to tick. Azure DevOps Server (on-premises) uses a personal access token.</td></tr>
|
|
635
637
|
<tr><td>GitHub</td><td><strong>Sign in with GitHub in the browser</strong> through the GitHub CLI (<code>gh auth login</code>): ForgeQE shows the one-time code and opens the page. Or paste a token. Needs <code>gh</code> installed. <code>forgeqe auth login copilot</code> can use this sign-in for a <code>github_copilot</code> profile.</td></tr>
|
|
636
|
-
<tr><td>GitHub Copilot</td><td><code>forgeqe auth login copilot</code>: <strong>
|
|
638
|
+
<tr><td>GitHub Copilot</td><td><code>forgeqe auth login copilot</code>: <strong>Sign in with GitHub in the browser</strong> (GitHub's own Copilot sign-in), or paste a fine-grained token with the Copilot Requests permission. ForgeQE checks it with Copilot and lists the models your seat has. For a <code>github_copilot</code> profile; see <a href="../HOW_TO_USE.md#github-copilot-seats-as-the-model">GitHub Copilot seats as the model</a>.</td></tr>
|
|
637
639
|
<tr><td>Jira, Confluence</td><td>Your Atlassian API tokens page opens (Cloud) or your personal access tokens page (Server/Data Center); create one and paste it. Confluence on the same Cloud site as Jira reuses the Jira sign-in.</td></tr>
|
|
638
640
|
<tr><td>TestRail, Zephyr Scale, qTest, Xray Cloud</td><td>The page with your API key opens, or ForgeQE says where to find it; paste it.</td></tr>
|
|
639
641
|
<tr><td>Anything else</td><td><code>forgeqe auth login OPENAI_API_KEY</code> (any variable name) saves that one secret: a model key, a Teams webhook URL, an SMTP or saved-login password.</td></tr>
|
|
@@ -4650,7 +4652,7 @@ the list again. For a client that ignores it, <code>forgeqe mcp --all-tools</cod
|
|
|
4650
4652
|
<tr><td><code>WP_LLMS_JSON</code></td><td>Path to <code>llms.json</code></td></tr>
|
|
4651
4653
|
<tr><td><code>WP_LLM_PROFILE</code></td><td>Active profile, unless <code>--profile</code> is set</td></tr>
|
|
4652
4654
|
<tr><td><code>WP_AZURE_API_KEY</code> / <code>OPENAI_API_KEY</code> / <code>WP_API_KEY</code></td><td>Keys referenced by profiles</td></tr>
|
|
4653
|
-
<tr><td><code>COPILOT_GITHUB_TOKEN</code></td><td>A <code>github_copilot</code> profile's GitHub token (fine-grained, with the Copilot Requests permission), unless the profile's <code>api_key_env</code> names another; else the saved token, then the
|
|
4655
|
+
<tr><td><code>COPILOT_GITHUB_TOKEN</code></td><td>A <code>github_copilot</code> profile's GitHub token (fine-grained, with the Copilot Requests permission), unless the profile's <code>api_key_env</code> names another; else the saved token, then the browser sign-in (<code>forgeqe auth login copilot</code>)</td></tr>
|
|
4654
4656
|
<tr><td><code>FORGEQE_COPILOT_TOKEN</code></td><td>The token <code>forgeqe auth login copilot</code> saves; set by ForgeQE from the credential store, not by hand</td></tr>
|
|
4655
4657
|
<tr><td><code>FORGEQE_CONFIG_DIR</code></td><td>Global config folder (default <code>~/.config/forgeqe</code>): <code>forgeqe.yaml</code>, <code>llms.json</code> and <code>.env</code> used when a project has none</td></tr>
|
|
4656
4658
|
<tr><td><code>FORGEQE_PYTHON</code></td><td>A Python that already has the engine's libraries, used instead of the managed venv (skipped, with a note, when it cannot run the engine)</td></tr>
|
package/llms.example.json
CHANGED
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"copilot": {
|
|
52
52
|
"provider": "github_copilot",
|
|
53
53
|
"model": "gpt-4.1",
|
|
54
|
-
"description": "GitHub Copilot seat for the browser engine, through GitHub's Copilot SDK (forgeqe auth login copilot: a fine-grained token with Copilot Requests
|
|
54
|
+
"description": "GitHub Copilot seat for the browser engine, through GitHub's Copilot SDK (forgeqe auth login copilot: sign in with GitHub in the browser, or a fine-grained token with Copilot Requests)"
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capagents/forgeqe",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.7",
|
|
4
4
|
"description": "ForgeQE: a browser agent CLI that runs goals and test cases in local Chrome or Chromium, or BrowserStack and TestMu AI/LambdaTest when configured, and turns passing runs into tests in your repo",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/javed0211/cli-agents.git",
|
|
9
|
+
"directory": "ForgeQE"
|
|
10
|
+
},
|
|
6
11
|
"type": "module",
|
|
7
12
|
"bin": {
|
|
8
13
|
"forgeqe": "bin/forgeqe.js",
|
|
@@ -7,7 +7,8 @@ tools of its own (the system prompt replaced, screenshots attached, a JSON schem
|
|
|
7
7
|
OpenAI shape.
|
|
8
8
|
|
|
9
9
|
python -m forgeqe_engine copilot-gateway
|
|
10
|
-
env COPILOT_GITHUB_TOKEN
|
|
10
|
+
env COPILOT_GITHUB_TOKEN a fine-grained token with Copilot Requests; without it, the signed-in user
|
|
11
|
+
(forgeqe auth login copilot, kept under ~/.forgeqe/copilot)
|
|
11
12
|
FORGEQE_COPILOT_GATEWAY_KEY the one-time key every request must carry as "Bearer <key>"
|
|
12
13
|
stdout one line: {"port": N, "login": "<account>"} once it listens, or {"error": "..."}
|
|
13
14
|
stdin end of input stops it, so it never outlives ForgeQE
|
|
@@ -183,23 +184,37 @@ def local_origin(headers: Dict[str, str]) -> bool:
|
|
|
183
184
|
# The Copilot SDK
|
|
184
185
|
|
|
185
186
|
|
|
187
|
+
def copilot_home() -> str:
|
|
188
|
+
"""Copilot's home for ForgeQE, where `forgeqe auth login copilot` signed in (src/auth/copilotLogin.ts)."""
|
|
189
|
+
return os.path.join(os.environ.get("FORGEQE_HOME") or os.path.join(os.path.expanduser("~"), ".forgeqe"), "copilot")
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def client_options(token: Optional[str], home: str, workdir: str) -> Dict[str, Any]:
|
|
193
|
+
"""With a token, that token only; without one, the signed-in user, as the Copilot SDK recommends on a user's machine."""
|
|
194
|
+
auth: Dict[str, Any] = {"github_token": token, "use_logged_in_user": False} if token else {"use_logged_in_user": True}
|
|
195
|
+
return {**auth, "base_directory": home, "working_directory": workdir, "log_level": "error"}
|
|
196
|
+
|
|
197
|
+
|
|
186
198
|
class Copilot:
|
|
187
|
-
def __init__(self, token: str):
|
|
199
|
+
def __init__(self, token: Optional[str]):
|
|
188
200
|
from copilot import CopilotClient
|
|
189
201
|
|
|
190
202
|
# The SDK keeps its state under this folder, apart from the user's own Copilot CLI.
|
|
191
|
-
home =
|
|
203
|
+
home = copilot_home()
|
|
192
204
|
os.makedirs(home, exist_ok=True)
|
|
193
205
|
# An empty working folder: the session reads no project files and no custom instructions.
|
|
194
206
|
self.workdir = tempfile.mkdtemp(prefix="forgeqe-copilot-")
|
|
195
|
-
self.
|
|
207
|
+
self.signed_in_user = not token
|
|
208
|
+
self.client = CopilotClient(**client_options(token, home, self.workdir))
|
|
196
209
|
|
|
197
210
|
async def start(self) -> None:
|
|
198
211
|
await self.client.start()
|
|
199
212
|
status = await self.client.get_auth_status()
|
|
200
213
|
self.login = status.login or ""
|
|
201
214
|
if not status.isAuthenticated:
|
|
202
|
-
|
|
215
|
+
if self.signed_in_user:
|
|
216
|
+
raise GatewayError(401, "GitHub Copilot is not signed in: run forgeqe auth login copilot, which opens GitHub in your browser.")
|
|
217
|
+
raise GatewayError(401, "GitHub Copilot did not accept the token: use a fine-grained token with the Copilot Requests permission, for an account with a Copilot seat.")
|
|
203
218
|
|
|
204
219
|
async def stop(self) -> None:
|
|
205
220
|
try:
|
|
@@ -340,14 +355,11 @@ async def serve(out: TextIO, copilot: Any = None) -> int:
|
|
|
340
355
|
out.write(json.dumps({"error": f"{KEY_ENV} must hold the gateway's one-time key."}) + "\n")
|
|
341
356
|
return 2
|
|
342
357
|
if copilot is None:
|
|
343
|
-
if not token:
|
|
344
|
-
out.write(json.dumps({"error": "No GitHub token for Copilot: run forgeqe auth login copilot."}) + "\n")
|
|
345
|
-
return 1
|
|
346
358
|
if token.startswith("ghp_"):
|
|
347
359
|
out.write(json.dumps({"error": "GitHub Copilot does not take classic tokens (ghp_): use a fine-grained token with the Copilot Requests permission."}) + "\n")
|
|
348
360
|
return 1
|
|
349
361
|
try:
|
|
350
|
-
copilot = Copilot(token)
|
|
362
|
+
copilot = Copilot(token or None)
|
|
351
363
|
await copilot.start()
|
|
352
364
|
except GatewayError as e:
|
|
353
365
|
out.write(json.dumps({"error": e.message}) + "\n")
|