@2kw/ai 7.1.0-dev.3 → 7.1.0-dev.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/README.md +2 -1
- package/dist/commands/auth.d.ts +5 -0
- package/dist/commands/auth.js +7 -3
- package/dist/commands/context.d.ts +6 -1
- package/dist/commands/context.js +22 -4
- package/dist/lib/agent-run.js +3 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -85,7 +85,8 @@ kubectl-style contexts switch between organizations and environments:
|
|
|
85
85
|
```bash
|
|
86
86
|
2kw context list # List all contexts
|
|
87
87
|
2kw context use acme-corp # Switch active context
|
|
88
|
-
2kw context create staging
|
|
88
|
+
2kw context create staging --base-url https://api.staging.example # Create a context, sign in through the browser
|
|
89
|
+
2kw context create ci --api-key sk_... # Or store an API key instead
|
|
89
90
|
```
|
|
90
91
|
|
|
91
92
|
`2kw config set memory true` makes an API-key context send `X-Backbone-Memory: enabled` on `ai respond` and `agents run` calls, which opts those runs into agent memory; `AI_2KW_MEMORY=true|false` overrides it per shell. Runs from a browser-login (session) context are always eligible for agent memory regardless of this setting, so `memory false` only affects API-key contexts.
|
package/dist/commands/auth.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ type SessionConfig = Extract<ResolvedConfig, {
|
|
|
14
14
|
* or a code that already carries its own separator) is shown untouched.
|
|
15
15
|
*/
|
|
16
16
|
export declare function formatUserCode(code: string): string;
|
|
17
|
+
/** Trailing slashes make `${authUrl}/api/auth/...` double up — drop them once, here. */
|
|
18
|
+
export declare function stripTrailingSlash(url: string): string;
|
|
17
19
|
/** Injection points for {@link deviceFlowLogin}; all default to the real thing. */
|
|
18
20
|
export interface DeviceLoginDeps {
|
|
19
21
|
requestCode?: typeof requestDeviceCode;
|
|
@@ -33,6 +35,9 @@ export interface DeviceLoginTarget {
|
|
|
33
35
|
contextName: string;
|
|
34
36
|
baseUrl: string;
|
|
35
37
|
authUrl: string;
|
|
38
|
+
/** Make the context active once stored. Defaults to true; `context create`
|
|
39
|
+
* turns it off for every context but the first. */
|
|
40
|
+
activate?: boolean;
|
|
36
41
|
}
|
|
37
42
|
/**
|
|
38
43
|
* The browser login, end to end: ask for a device code, wait for the user to
|
package/dist/commands/auth.js
CHANGED
|
@@ -27,7 +27,7 @@ export function formatUserCode(code) {
|
|
|
27
27
|
return code.length === 8 ? `${code.slice(0, 4)}-${code.slice(4)}` : code;
|
|
28
28
|
}
|
|
29
29
|
/** Trailing slashes make `${authUrl}/api/auth/...` double up — drop them once, here. */
|
|
30
|
-
function stripTrailingSlash(url) {
|
|
30
|
+
export function stripTrailingSlash(url) {
|
|
31
31
|
return url.replace(/\/+$/, "");
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
@@ -65,7 +65,7 @@ async function tryOpenBrowser(url) {
|
|
|
65
65
|
*/
|
|
66
66
|
export async function deviceFlowLogin(target, deps = {}) {
|
|
67
67
|
const { requestCode = requestDeviceCode, poll = pollDeviceToken, runPolling = runDevicePolling, sessionInfo = getSessionInfo, listOrgs = listOrganizations, chooseOrg = selectOrganization, setActiveOrg = setActiveOrganization, revoke = revokeSession, openBrowser = tryOpenBrowser, saveContext = setContext, activateContext = setActiveContext, } = deps;
|
|
68
|
-
const { contextName, baseUrl, authUrl } = target;
|
|
68
|
+
const { contextName, baseUrl, authUrl, activate = true } = target;
|
|
69
69
|
const device = await requestCode(authUrl, CLI_CLIENT_ID);
|
|
70
70
|
console.log("");
|
|
71
71
|
console.log(`Open ${chalk.cyan(device.verification_uri_complete)}`);
|
|
@@ -121,10 +121,14 @@ export async function deviceFlowLogin(target, deps = {}) {
|
|
|
121
121
|
}
|
|
122
122
|
// Outside the guard on purpose: the session is on disk now, so a failure to
|
|
123
123
|
// mark the context active still leaves a credential the user can reach.
|
|
124
|
-
|
|
124
|
+
if (activate)
|
|
125
|
+
activateContext(contextName);
|
|
125
126
|
console.log(chalk.green(`Logged in as ${email}`));
|
|
126
127
|
console.log(chalk.dim(` — organization: ${org.name}`));
|
|
127
128
|
console.log(chalk.dim(`Config stored at: ${store.path}`));
|
|
129
|
+
if (!activate) {
|
|
130
|
+
console.log(chalk.dim(`Switch to it with "2kw context use ${contextName}".`));
|
|
131
|
+
}
|
|
128
132
|
}
|
|
129
133
|
/**
|
|
130
134
|
* The pre-device-flow login: take an API key from the flag or the terminal and
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import { updateContext } from "../lib/config.js";
|
|
3
|
+
import { type DeviceLoginDeps } from "./auth.js";
|
|
3
4
|
import { listOrganizations, setActiveOrganization } from "../lib/auth-service.js";
|
|
4
5
|
import { selectOrganization, type Asker } from "../lib/auth-session.js";
|
|
5
6
|
/** Injection points for {@link performSetOrg}; all default to the real thing. */
|
|
@@ -24,5 +25,9 @@ export interface SetOrgDeps {
|
|
|
24
25
|
* @param orgArg an organization id or slug; omitted means "prompt".
|
|
25
26
|
*/
|
|
26
27
|
export declare function performSetOrg(orgArg: string | undefined, deps?: SetOrgDeps): Promise<void>;
|
|
27
|
-
|
|
28
|
+
/**
|
|
29
|
+
* @param deviceDeps forwarded to {@link deviceFlowLogin} by `context create` —
|
|
30
|
+
* a seam for tests, as on `makeAuthCommand`.
|
|
31
|
+
*/
|
|
32
|
+
export declare function makeContextCommand(deviceDeps?: DeviceLoginDeps): Command;
|
|
28
33
|
//# sourceMappingURL=context.d.ts.map
|
package/dist/commands/context.js
CHANGED
|
@@ -2,7 +2,8 @@ import { Command } from "commander";
|
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import Table from "cli-table3";
|
|
4
4
|
import { createInterface } from "node:readline/promises";
|
|
5
|
-
import { store, isJsonOutput, getAllContexts, getActiveContext, getActiveContextName, getContextCount, setContext, deleteContext, renameContext, setActiveContext, updateContext, validateContextName, DEFAULT_BASE_URL, } from "../lib/config.js";
|
|
5
|
+
import { store, isJsonOutput, getAllContexts, getActiveContext, getActiveContextName, getContextCount, setContext, deleteContext, renameContext, setActiveContext, updateContext, validateContextName, defaultAuthUrlFor, DEFAULT_BASE_URL, } from "../lib/config.js";
|
|
6
|
+
import { deviceFlowLogin, stripTrailingSlash } from "./auth.js";
|
|
6
7
|
import { listOrganizations, setActiveOrganization, } from "../lib/auth-service.js";
|
|
7
8
|
import { selectOrganization } from "../lib/auth-session.js";
|
|
8
9
|
import { runAction } from "../lib/client.js";
|
|
@@ -76,7 +77,11 @@ export async function performSetOrg(orgArg, deps = {}) {
|
|
|
76
77
|
}
|
|
77
78
|
console.log(chalk.green(`Active organization: ${org.name} (${org.slug})`));
|
|
78
79
|
}
|
|
79
|
-
|
|
80
|
+
/**
|
|
81
|
+
* @param deviceDeps forwarded to {@link deviceFlowLogin} by `context create` —
|
|
82
|
+
* a seam for tests, as on `makeAuthCommand`.
|
|
83
|
+
*/
|
|
84
|
+
export function makeContextCommand(deviceDeps = {}) {
|
|
80
85
|
const cmd = new Command("context").description("Manage CLI contexts for multiple environments");
|
|
81
86
|
cmd
|
|
82
87
|
.command("list")
|
|
@@ -125,10 +130,12 @@ export function makeContextCommand() {
|
|
|
125
130
|
});
|
|
126
131
|
cmd
|
|
127
132
|
.command("create")
|
|
128
|
-
.description("Create a new context")
|
|
133
|
+
.description("Create a new context and sign in through the browser (or with an API key)")
|
|
129
134
|
.argument("<name>", "Context name")
|
|
130
135
|
.option("--base-url <url>", "Base URL")
|
|
131
|
-
.option("--
|
|
136
|
+
.option("--auth-url <url>", "Auth service URL (defaults to the one matching the base URL)")
|
|
137
|
+
.option("--api-key <key>", "Save an API key instead of signing in through the browser")
|
|
138
|
+
.option("--manual", "Prompt for an API key instead of signing in through the browser")
|
|
132
139
|
.action(async (name, _opts, command) => {
|
|
133
140
|
validateContextName(name);
|
|
134
141
|
// Merged, not own — the root program declares --base-url and --api-key
|
|
@@ -140,6 +147,17 @@ export function makeContextCommand() {
|
|
|
140
147
|
if (contexts[name]) {
|
|
141
148
|
throw new Error(`Context "${name}" already exists. Delete it first or choose a different name.`);
|
|
142
149
|
}
|
|
150
|
+
// The same browser login as `auth login`, written into the new context
|
|
151
|
+
// instead of the active one. Only the first context becomes active, as
|
|
152
|
+
// with an API key below: creating one is not switching to it.
|
|
153
|
+
if (!opts.apiKey && !opts.manual) {
|
|
154
|
+
const baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;
|
|
155
|
+
const authUrl = stripTrailingSlash(opts.authUrl ?? defaultAuthUrlFor(baseUrl));
|
|
156
|
+
const activate = getContextCount() === 0;
|
|
157
|
+
console.log(chalk.dim(`Auth service: ${authUrl} (override with --auth-url)`));
|
|
158
|
+
await runAction(command, () => deviceFlowLogin({ contextName: name, baseUrl, authUrl, activate }, deviceDeps));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
143
161
|
let baseUrl = opts.baseUrl;
|
|
144
162
|
let apiKey = opts.apiKey;
|
|
145
163
|
if (!baseUrl || !apiKey) {
|
package/dist/lib/agent-run.js
CHANGED
|
@@ -156,7 +156,8 @@ function relayDecideCommand(ref, responseId, calls, withApprovals) {
|
|
|
156
156
|
/**
|
|
157
157
|
* A connector tool's open approval, decoded from the standard `mcp_approval_request` item (#949). The item
|
|
158
158
|
* is the MCP twin of `backbone:approval_request` (#805): it names the server and the tool, carries no call
|
|
159
|
-
* id
|
|
159
|
+
* id or status (its policy class is an optional extension, #1084; "unknown" without it), and exists only
|
|
160
|
+
* while the decision is open, so its id doubles as the call id
|
|
160
161
|
* and the tool is named as the approval row stores it, `mcp__<server_label>__<tool>`.
|
|
161
162
|
*/
|
|
162
163
|
function connectorApproval(i) {
|
|
@@ -165,7 +166,7 @@ function connectorApproval(i) {
|
|
|
165
166
|
callId: String(i.id),
|
|
166
167
|
tool: `mcp__${String(i.server_label)}__${String(i.name)}`,
|
|
167
168
|
arguments: parseArguments(i.arguments),
|
|
168
|
-
policyClass: "unknown",
|
|
169
|
+
policyClass: typeof i.policy_class === "string" ? i.policy_class : "unknown",
|
|
169
170
|
reason: null,
|
|
170
171
|
preview: null,
|
|
171
172
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@2kw/ai",
|
|
3
|
-
"version": "7.1.0-dev.
|
|
3
|
+
"version": "7.1.0-dev.7",
|
|
4
4
|
"description": "CLI for 2kw.ai — schema-driven document extraction, an OpenAI-compatible EU LLM gateway, transcription, prompts, datasets, and experiments from your terminal or agentic workflows. Ships as 2kw, backbone, and bb.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|