@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.
@@ -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>&quot;default&quot;: &quot;copilot&quot;</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 # a fine-grained token with Copilot Requests, or the GitHub CLI's sign-in
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. The variable holding the GitHub token; without it ForgeQE reads <code>COPILOT_GITHUB_TOKEN</code>, then the token <code>forgeqe auth login copilot</code> saved, then the GitHub CLI's sign-in.</td></tr>
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>A fine-grained token</strong> (recommended). 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>). 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>
581
- <li><strong>The GitHub CLI's sign-in</strong>, when <code>gh</code> is signed in.</li>
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 token 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> forgets a saved token.</p>
584
- <p>The 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>
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 needs a GitHub token, and there is none</code></td><td>Run <code>forgeqe auth login copilot</code> (or <code>/auth copilot</code> in the shell), or set <code>COPILOT_GITHUB_TOKEN</code>.</td></tr>
606
- <tr><td><code>GitHub Copilot does not take classic tokens (ghp_)</code></td><td>Make a fine-grained token with the Copilot Requests permission, owned by your personal account.</td></tr>
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>Paste a fine-grained token</strong> with the Copilot Requests permission (ForgeQE opens GitHub's token page), or use the GitHub CLI's sign-in. ForgeQE checks it with Copilot and lists the models your seat has. No other app is authorized on your GitHub account. 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>
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 GitHub CLI's sign-in</td></tr>
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, or the GitHub CLI's sign-in)"
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.5",
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 the GitHub token (fine-grained with Copilot Requests, or the GitHub CLI's)
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 = os.path.join(os.environ.get("FORGEQE_HOME") or os.path.join(os.path.expanduser("~"), ".forgeqe"), "copilot")
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.client = CopilotClient(github_token=token, use_logged_in_user=False, base_directory=home, working_directory=self.workdir, log_level="error")
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
- raise GatewayError(401, "GitHub Copilot did not accept the token: use a fine-grained token with the Copilot Requests permission, or the GitHub CLI's sign-in, for an account with a Copilot seat.")
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")