@yagni-app/code-staging 0.1.0-staging.997.1 → 0.2.0-staging.1025.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/README.md +58 -9
- package/dist/claudeCompat.d.ts +36 -5
- package/dist/claudeCompat.js +85 -23
- package/dist/claudePlugins.d.ts +109 -0
- package/dist/claudePlugins.js +336 -0
- package/dist/cli.js +14 -4
- package/dist/crashReport.d.ts +135 -0
- package/dist/crashReport.js +291 -0
- package/dist/doctor.d.ts +21 -0
- package/dist/doctor.js +52 -0
- package/dist/extension/askAdvisorTool.js +7 -1
- package/dist/extension/bless.js +16 -3
- package/dist/extension/boostCommand.d.ts +144 -0
- package/dist/extension/boostCommand.js +263 -0
- package/dist/extension/branding.d.ts +31 -0
- package/dist/extension/branding.js +37 -0
- package/dist/extension/chipEditor.js +7 -3
- package/dist/extension/claudeRules.d.ts +54 -0
- package/dist/extension/claudeRules.js +180 -0
- package/dist/extension/config.d.ts +61 -0
- package/dist/extension/config.js +86 -0
- package/dist/extension/costHud.d.ts +128 -15
- package/dist/extension/costHud.js +189 -19
- package/dist/extension/crashReport.d.ts +89 -0
- package/dist/extension/crashReport.js +241 -0
- package/dist/extension/index.d.ts +43 -4
- package/dist/extension/index.js +241 -32
- package/dist/extension/initPass.d.ts +65 -47
- package/dist/extension/initPass.js +145 -145
- package/dist/extension/mcpTools.d.ts +57 -0
- package/dist/extension/mcpTools.js +132 -0
- package/dist/extension/pipeline/eval.d.ts +42 -5
- package/dist/extension/pipeline/eval.js +44 -0
- package/dist/extension/pipeline/goCommand.d.ts +18 -0
- package/dist/extension/pipeline/goCommand.js +139 -26
- package/dist/extension/pipeline/goCompareCommand.d.ts +18 -8
- package/dist/extension/pipeline/goCompareCommand.js +42 -23
- package/dist/extension/pipeline/orchestrator.js +9 -0
- package/dist/extension/pipeline/runCostTable.d.ts +37 -0
- package/dist/extension/pipeline/runCostTable.js +165 -0
- package/dist/extension/pipeline/runState.d.ts +19 -0
- package/dist/extension/pipeline/runState.js +11 -0
- package/dist/extension/pipeline/runner.d.ts +19 -0
- package/dist/extension/pipeline/runner.js +13 -1
- package/dist/extension/pipeline/scrubSecrets.js +2 -2
- package/dist/extension/pipeline/stages.d.ts +3 -1
- package/dist/extension/pipeline/stages.js +3 -1
- package/dist/extension/pipeline/types.d.ts +7 -4
- package/dist/extension/pipeline/verify.js +6 -1
- package/dist/extension/pipeline/worktree.js +3 -1
- package/dist/extension/provider.d.ts +7 -1
- package/dist/extension/provider.js +8 -1
- package/dist/extension/recall.js +5 -2
- package/dist/extension/rerouteNotice.d.ts +42 -0
- package/dist/extension/rerouteNotice.js +67 -0
- package/dist/extension/sessionRuns.d.ts +45 -0
- package/dist/extension/sessionRuns.js +77 -0
- package/dist/extension/subagents.d.ts +17 -7
- package/dist/extension/subagents.js +52 -7
- package/dist/launch.d.ts +17 -3
- package/dist/launch.js +22 -9
- package/dist/login.d.ts +7 -0
- package/dist/login.js +3 -1
- package/package.json +2 -2
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAG-383: tracks the `/go` run ids a driver session has launched, so /cost's
|
|
3
|
+
* server-authoritative spend fetch can widen its query to include them.
|
|
4
|
+
*
|
|
5
|
+
* The backend writes a run-attributed dispatch's `llm_usage.session_id` as
|
|
6
|
+
* the RUN id, not the driver session id (see attributionHeaders in
|
|
7
|
+
* config.ts: a `/go` child's completions carry `x-yagni-run-id`, and the
|
|
8
|
+
* proxy stores THAT in `session_id` — the run id wins, by design, so a
|
|
9
|
+
* per-run query works on its own). A plain `GET /api/yagni-code/spend?
|
|
10
|
+
* sessionId=<driver>` therefore never sees a single `/go` run's spend: it is
|
|
11
|
+
* real spend, billed under this session's work, but invisible to that query.
|
|
12
|
+
* `/cost` (index.ts's `fetchSpend`) closes that gap by also asking for every
|
|
13
|
+
* run id this process has launched, via `runIds=`.
|
|
14
|
+
*
|
|
15
|
+
* Module-level state is the right shape here: one CLI process IS one driver
|
|
16
|
+
* session, so "run ids this process has launched" and "run ids this session
|
|
17
|
+
* has launched" are the same list. Capped at the most recent
|
|
18
|
+
* `MAX_TRACKED_RUN_IDS` so an extremely long-lived session's /cost call never
|
|
19
|
+
* grows an unbounded query string (the backend independently caps `runIds` at
|
|
20
|
+
* the same number — see MAX_SPEND_RUN_IDS in routes/yagniCode.ts — capping
|
|
21
|
+
* symmetrically here keeps a stable, useful most-recent set instead of
|
|
22
|
+
* trailing off into a 400 from the server).
|
|
23
|
+
*/
|
|
24
|
+
const MAX_TRACKED_RUN_IDS = 20;
|
|
25
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
26
|
+
let runIds = [];
|
|
27
|
+
/**
|
|
28
|
+
* Count of run ids ever pushed off the front of `runIds` by the
|
|
29
|
+
* `MAX_TRACKED_RUN_IDS` cap below. Carry-over from the /cost re-review: a
|
|
30
|
+
* long-lived session that launches more than 20 `/go` runs silently lost the
|
|
31
|
+
* oldest ones from /cost's `runIds=` widening, with no indication that
|
|
32
|
+
* anything was left out — an honesty gap identical in spirit to
|
|
33
|
+
* `counterfactualIncomplete` / `unbilledSellMillicents` elsewhere in this
|
|
34
|
+
* surface. Tracked here (not derived) because the dropped ids themselves are
|
|
35
|
+
* gone — only the count survives.
|
|
36
|
+
*/
|
|
37
|
+
let dropped = 0;
|
|
38
|
+
/**
|
|
39
|
+
* Record a `/go` run id once it is known (the goCommand.ts seam right after
|
|
40
|
+
* `runSession.start()` resolves). Ignores anything that is not UUID-shaped
|
|
41
|
+
* and de-dupes a repeat call for the same run (a resumed/re-adopted run can
|
|
42
|
+
* report the same id twice) — both defensive, since a malformed value here
|
|
43
|
+
* must never corrupt /cost's query string.
|
|
44
|
+
*/
|
|
45
|
+
export function recordSessionRun(runId) {
|
|
46
|
+
if (!UUID_RE.test(runId))
|
|
47
|
+
return;
|
|
48
|
+
if (runIds.includes(runId))
|
|
49
|
+
return;
|
|
50
|
+
runIds.push(runId);
|
|
51
|
+
if (runIds.length > MAX_TRACKED_RUN_IDS) {
|
|
52
|
+
const overflow = runIds.length - MAX_TRACKED_RUN_IDS;
|
|
53
|
+
dropped += overflow;
|
|
54
|
+
runIds = runIds.slice(overflow);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** The run ids recorded so far this process, oldest first, capped. */
|
|
58
|
+
export function sessionRunIds() {
|
|
59
|
+
return [...runIds];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* How many run ids this session has ever dropped off the front of the
|
|
63
|
+
* `MAX_TRACKED_RUN_IDS` cap. Zero for the overwhelming majority of sessions
|
|
64
|
+
* (20 `/go` runs in one process is a lot); /cost's server rendering
|
|
65
|
+
* (costHud.ts's `formatServerCostLines`) surfaces this as an "Excludes N
|
|
66
|
+
* earlier /go runs." note when it is nonzero, so a long session's spend total
|
|
67
|
+
* is never silently missing runs with no explanation.
|
|
68
|
+
*/
|
|
69
|
+
export function droppedSessionRuns() {
|
|
70
|
+
return dropped;
|
|
71
|
+
}
|
|
72
|
+
/** Test-only reset: module-level state otherwise leaks across test files/cases. */
|
|
73
|
+
export function _resetSessionRunsForTest() {
|
|
74
|
+
runIds = [];
|
|
75
|
+
dropped = 0;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=sessionRuns.js.map
|
|
@@ -9,9 +9,11 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Agent definitions are the Claude Code format — markdown with
|
|
11
11
|
* name/description/tools/model frontmatter — discovered from the repo's
|
|
12
|
-
* `.claude/agents/` and `.pi/agents
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* `.claude/agents/` and `.pi/agents/`, the user's `~/.claude/agents/`, and
|
|
13
|
+
* any Claude Code plugin `agents/` dirs the launcher passed via
|
|
14
|
+
* `YAGNI_CLAUDE_AGENT_DIRS` (project beats user beats plugin on a name
|
|
15
|
+
* collision). A built-in `general` agent is always available, so the tool
|
|
16
|
+
* works in a repo with no definitions at all.
|
|
15
17
|
* Claude model names map onto YAGNI tiers (opus→advanced, sonnet→standard,
|
|
16
18
|
* haiku→efficient); unknown models run on standard.
|
|
17
19
|
*/
|
|
@@ -28,7 +30,12 @@ export declare const MAX_PARALLEL_SUBAGENTS = 4;
|
|
|
28
30
|
* subagent would inherit.
|
|
29
31
|
*/
|
|
30
32
|
export declare const DEFAULT_SUBAGENT_TOOLS: string[];
|
|
31
|
-
export type SubagentSource = "project-claude" | "project-pi" | "user-claude" | "builtin";
|
|
33
|
+
export type SubagentSource = "project-claude" | "project-pi" | "user-claude" | "plugin" | "builtin";
|
|
34
|
+
/**
|
|
35
|
+
* Claude Code plugin `agents/` dirs, delimiter-joined by the yagni launcher
|
|
36
|
+
* (see yagni-code-cli claudeCompat.ts — trust gating happens there).
|
|
37
|
+
*/
|
|
38
|
+
export declare const CLAUDE_AGENT_DIRS_ENV = "YAGNI_CLAUDE_AGENT_DIRS";
|
|
32
39
|
export interface SubagentDef {
|
|
33
40
|
name: string;
|
|
34
41
|
description: string;
|
|
@@ -49,11 +56,14 @@ export declare function parseAgentMarkdown(content: string, fallbackName: string
|
|
|
49
56
|
export interface DiscoverDeps {
|
|
50
57
|
cwd: string;
|
|
51
58
|
homeDir?: string;
|
|
59
|
+
/** Env seam for the plugin agent dirs (defaults to process.env). */
|
|
60
|
+
env?: NodeJS.ProcessEnv;
|
|
52
61
|
}
|
|
53
62
|
/**
|
|
54
|
-
* All available agents: built-in general, then
|
|
55
|
-
*
|
|
56
|
-
*
|
|
63
|
+
* All available agents: built-in general, then Claude Code plugin `agents/`
|
|
64
|
+
* dirs (launcher-provided), then user `~/.claude/agents`, then the repo's
|
|
65
|
+
* `.pi/agents` and `.claude/agents` — later wins on a name collision, so a
|
|
66
|
+
* project definition beats a user one beats a plugin one beats the built-in.
|
|
57
67
|
*/
|
|
58
68
|
export declare function discoverSubagents(deps: DiscoverDeps): SubagentDef[];
|
|
59
69
|
export declare function formatAgentList(agents: SubagentDef[]): string;
|
|
@@ -9,18 +9,27 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Agent definitions are the Claude Code format — markdown with
|
|
11
11
|
* name/description/tools/model frontmatter — discovered from the repo's
|
|
12
|
-
* `.claude/agents/` and `.pi/agents
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* `.claude/agents/` and `.pi/agents/`, the user's `~/.claude/agents/`, and
|
|
13
|
+
* any Claude Code plugin `agents/` dirs the launcher passed via
|
|
14
|
+
* `YAGNI_CLAUDE_AGENT_DIRS` (project beats user beats plugin on a name
|
|
15
|
+
* collision). A built-in `general` agent is always available, so the tool
|
|
16
|
+
* works in a repo with no definitions at all.
|
|
15
17
|
* Claude model names map onto YAGNI tiers (opus→advanced, sonnet→standard,
|
|
16
18
|
* haiku→efficient); unknown models run on standard.
|
|
17
19
|
*/
|
|
18
20
|
import * as fs from "node:fs";
|
|
19
21
|
import { homedir } from "node:os";
|
|
20
|
-
import { join } from "node:path";
|
|
22
|
+
import { delimiter, join } from "node:path";
|
|
21
23
|
import { parseFrontmatter } from "@earendil-works/pi-coding-agent";
|
|
22
24
|
import { Type } from "typebox";
|
|
25
|
+
import { sanitizeCallerSegment } from "./config.js";
|
|
23
26
|
import { runStage } from "./pipeline/runner.js";
|
|
27
|
+
/**
|
|
28
|
+
* YAG-471 attribution: the `x-yagni-caller` prefix for a subagent invocation.
|
|
29
|
+
* The sanitized agent name is capped so the WHOLE label (prefix + name) stays
|
|
30
|
+
* within the model proxy's 64-char caller-label limit.
|
|
31
|
+
*/
|
|
32
|
+
const SUBAGENT_CALLER_PREFIX = "subagent:";
|
|
24
33
|
export const SUBAGENT_TOOL_NAME = "subagent";
|
|
25
34
|
export const GENERAL_AGENT_NAME = "general";
|
|
26
35
|
export const MAX_PARALLEL_SUBAGENTS = 4;
|
|
@@ -39,6 +48,21 @@ export const DEFAULT_SUBAGENT_TOOLS = [
|
|
|
39
48
|
"write",
|
|
40
49
|
"ask_yagni",
|
|
41
50
|
];
|
|
51
|
+
/**
|
|
52
|
+
* Claude Code plugin `agents/` dirs, delimiter-joined by the yagni launcher
|
|
53
|
+
* (see yagni-code-cli claudeCompat.ts — trust gating happens there).
|
|
54
|
+
*/
|
|
55
|
+
export const CLAUDE_AGENT_DIRS_ENV = "YAGNI_CLAUDE_AGENT_DIRS";
|
|
56
|
+
const CLAUDE_COMPAT_DISABLE_ENV = "YAGNI_DISABLE_CLAUDE_COMPAT";
|
|
57
|
+
function pluginAgentDirs(env) {
|
|
58
|
+
const disabled = env[CLAUDE_COMPAT_DISABLE_ENV];
|
|
59
|
+
if (disabled !== undefined && disabled !== "" && disabled !== "0")
|
|
60
|
+
return [];
|
|
61
|
+
const raw = env[CLAUDE_AGENT_DIRS_ENV];
|
|
62
|
+
if (!raw)
|
|
63
|
+
return [];
|
|
64
|
+
return raw.split(delimiter).filter(Boolean);
|
|
65
|
+
}
|
|
42
66
|
const GENERAL_BODY = `You are a capable software-engineering subagent with a fresh context window. Complete the task you are given end to end, autonomously.
|
|
43
67
|
|
|
44
68
|
You are grounded in how THIS company works: call ask_yagni before inferring a convention, an ownership rule, or anything organization-specific.
|
|
@@ -51,6 +75,10 @@ const GENERAL_AGENT = {
|
|
|
51
75
|
body: GENERAL_BODY,
|
|
52
76
|
source: "builtin",
|
|
53
77
|
};
|
|
78
|
+
// Concrete tiers a subagent can actually run on. `balanced` is deliberately NOT
|
|
79
|
+
// a member here even though it is a member of `ModelTier`: a subagent needs
|
|
80
|
+
// ONE model for its whole run, and balanced is a session-level routing policy,
|
|
81
|
+
// not a rung — see mapModelTier's explicit branch below.
|
|
54
82
|
const TIER_VALUES = ["peak", "advanced", "standard", "efficient"];
|
|
55
83
|
/** Claude Code model names → YAGNI tiers; YAGNI tiers pass through. */
|
|
56
84
|
export function mapModelTier(model) {
|
|
@@ -59,6 +87,15 @@ export function mapModelTier(model) {
|
|
|
59
87
|
const normalized = model.trim().toLowerCase();
|
|
60
88
|
if (TIER_VALUES.includes(normalized))
|
|
61
89
|
return normalized;
|
|
90
|
+
// `balanced` names a SESSION routing policy, not a tier a subagent can run
|
|
91
|
+
// on. Handled explicitly rather than falling through to the catch-all
|
|
92
|
+
// below, so frontmatter that names the policy reads as an intentional
|
|
93
|
+
// "router-decide" choice, not an unrecognized string: it lands on the
|
|
94
|
+
// built-in default lane (standard) — the session-level policy (driver
|
|
95
|
+
// turns) owns balanced's resolution; this is just a safe landing spot for
|
|
96
|
+
// frontmatter that names it.
|
|
97
|
+
if (normalized === "balanced")
|
|
98
|
+
return "standard";
|
|
62
99
|
if (normalized.includes("opus"))
|
|
63
100
|
return "advanced";
|
|
64
101
|
if (normalized.includes("sonnet"))
|
|
@@ -117,14 +154,16 @@ function loadAgentsFromDir(dir, source) {
|
|
|
117
154
|
return agents;
|
|
118
155
|
}
|
|
119
156
|
/**
|
|
120
|
-
* All available agents: built-in general, then
|
|
121
|
-
*
|
|
122
|
-
*
|
|
157
|
+
* All available agents: built-in general, then Claude Code plugin `agents/`
|
|
158
|
+
* dirs (launcher-provided), then user `~/.claude/agents`, then the repo's
|
|
159
|
+
* `.pi/agents` and `.claude/agents` — later wins on a name collision, so a
|
|
160
|
+
* project definition beats a user one beats a plugin one beats the built-in.
|
|
123
161
|
*/
|
|
124
162
|
export function discoverSubagents(deps) {
|
|
125
163
|
const home = deps.homeDir ?? homedir();
|
|
126
164
|
const layers = [
|
|
127
165
|
[GENERAL_AGENT],
|
|
166
|
+
...pluginAgentDirs(deps.env ?? process.env).map((dir) => loadAgentsFromDir(dir, "plugin")),
|
|
128
167
|
loadAgentsFromDir(join(home, ".claude", "agents"), "user-claude"),
|
|
129
168
|
loadAgentsFromDir(join(deps.cwd, ".pi", "agents"), "project-pi"),
|
|
130
169
|
loadAgentsFromDir(join(deps.cwd, ".claude", "agents"), "project-claude"),
|
|
@@ -138,6 +177,7 @@ export function discoverSubagents(deps) {
|
|
|
138
177
|
}
|
|
139
178
|
const SOURCE_LABEL = {
|
|
140
179
|
builtin: "built-in",
|
|
180
|
+
plugin: "claude plugin",
|
|
141
181
|
"user-claude": "~/.claude/agents",
|
|
142
182
|
"project-pi": ".pi/agents",
|
|
143
183
|
"project-claude": ".claude/agents",
|
|
@@ -234,6 +274,11 @@ export function makeSubagentTool(deps = {}) {
|
|
|
234
274
|
cwd,
|
|
235
275
|
signal,
|
|
236
276
|
personaBody: () => def.body,
|
|
277
|
+
// YAG-471: attribute this child's completions to the specific
|
|
278
|
+
// subagent, not the generic /go stage label the runner would
|
|
279
|
+
// otherwise derive from stage.id ("implement", reused as the
|
|
280
|
+
// synthetic subagent stage — see buildSubagentStage).
|
|
281
|
+
callerLabel: `${SUBAGENT_CALLER_PREFIX}${sanitizeCallerSegment(def.name, 64 - SUBAGENT_CALLER_PREFIX.length)}`,
|
|
237
282
|
});
|
|
238
283
|
return { agent: def.name, task, result };
|
|
239
284
|
}));
|
package/dist/launch.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Build the configured pi launch. `buildLaunch`
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Build the configured pi launch. `buildLaunch` has no spawn/fs side effects,
|
|
3
|
+
* so it stays fully unit-testable, though it is no longer strictly pure: it
|
|
4
|
+
* mints a fresh session id (`randomUUID()`) on every call. It returns the
|
|
5
|
+
* child environment and the pi argv that registers pi-extension-yagni and
|
|
6
|
+
* defaults the provider to `yagni`.
|
|
5
7
|
*/
|
|
6
8
|
import type { Credentials } from "./credentials.js";
|
|
7
9
|
export interface LaunchPlan {
|
|
@@ -61,6 +63,12 @@ export interface BuildLaunchOptions {
|
|
|
61
63
|
profilePath?: string;
|
|
62
64
|
/** Distribution-specific root shared with the bundled extension. */
|
|
63
65
|
stateDir?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Launcher version, forwarded as `YAGNI_CODE_VERSION` so the bundled
|
|
68
|
+
* extension (which has no package.json on disk to read) can label its crash
|
|
69
|
+
* reports with the shipping version. Optional: omitted, reports say "unknown".
|
|
70
|
+
*/
|
|
71
|
+
cliVersion?: string;
|
|
64
72
|
/** Base environment to extend (defaults to process.env at call sites). */
|
|
65
73
|
baseEnv?: NodeJS.ProcessEnv;
|
|
66
74
|
/** Clock seam for the token-expiry preflight (defaults to Date.now). */
|
|
@@ -71,6 +79,12 @@ export interface BuildLaunchOptions {
|
|
|
71
79
|
* anything the user passes explicitly still wins.
|
|
72
80
|
*/
|
|
73
81
|
extraAgentArgs?: string[];
|
|
82
|
+
/**
|
|
83
|
+
* Launcher-computed child env (e.g. Claude-compat plugin agent dirs and
|
|
84
|
+
* rules dirs). Merged before the YAGNI-critical keys so it can never
|
|
85
|
+
* override the token, base URL, or hermetic agent dir.
|
|
86
|
+
*/
|
|
87
|
+
extraEnv?: Record<string, string>;
|
|
74
88
|
}
|
|
75
89
|
export declare function buildLaunch(creds: Credentials | null, passthroughArgs: string[], opts: BuildLaunchOptions): LaunchPlan;
|
|
76
90
|
//# sourceMappingURL=launch.d.ts.map
|
package/dist/launch.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Build the configured pi launch. `buildLaunch`
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Build the configured pi launch. `buildLaunch` has no spawn/fs side effects,
|
|
3
|
+
* so it stays fully unit-testable, though it is no longer strictly pure: it
|
|
4
|
+
* mints a fresh session id (`randomUUID()`) on every call. It returns the
|
|
5
|
+
* child environment and the pi argv that registers pi-extension-yagni and
|
|
6
|
+
* defaults the provider to `yagni`.
|
|
5
7
|
*/
|
|
8
|
+
import { randomUUID } from "node:crypto";
|
|
6
9
|
import { agentDirEnvVar } from "./branding.js";
|
|
7
10
|
/**
|
|
8
11
|
* How close to expiry the token can be before launch warns. A coding session
|
|
@@ -50,6 +53,13 @@ export function buildLaunch(creds, passthroughArgs, opts) {
|
|
|
50
53
|
}
|
|
51
54
|
const env = {
|
|
52
55
|
...(opts.baseEnv ?? {}),
|
|
56
|
+
...(opts.extraEnv ?? {}),
|
|
57
|
+
// One session id per launch (YAG-471 attribution). The extension reads this
|
|
58
|
+
// as YAGNI_SESSION_ID and forwards it as the model proxy's x-yagni-session-id
|
|
59
|
+
// header on the driver's own completions. /go's children override
|
|
60
|
+
// YAGNI_CALLER with their own stage/subagent/advisor label but inherit this
|
|
61
|
+
// session id (unless they also carry a YAGNI_RUN_ID, which wins server-side).
|
|
62
|
+
YAGNI_SESSION_ID: randomUUID(),
|
|
53
63
|
YAGNI_TOKEN: creds.token,
|
|
54
64
|
YAGNI_BASE_URL: creds.baseUrl,
|
|
55
65
|
// Forward the token's expiry (when known) so the extension can surface a
|
|
@@ -63,6 +73,9 @@ export function buildLaunch(creds, passthroughArgs, opts) {
|
|
|
63
73
|
// the launcher read (0600). Absent when the caller can't resolve it.
|
|
64
74
|
...(opts.profilePath ? { YAGNI_PROFILE_PATH: opts.profilePath } : {}),
|
|
65
75
|
...(opts.stateDir ? { YAGNI_CODE_HOME: opts.stateDir } : {}),
|
|
76
|
+
// Forward the launcher's version so the extension's crash reports carry
|
|
77
|
+
// the shipping version (the bundled extension has no package.json to read).
|
|
78
|
+
...(opts.cliVersion ? { YAGNI_CODE_VERSION: opts.cliVersion } : {}),
|
|
66
79
|
// Rebrand pi's chrome ("pi"/"π" → "YAGNI Code"): pi reads piConfig.name from
|
|
67
80
|
// the package at PI_PACKAGE_DIR (a shadow package the launcher generates).
|
|
68
81
|
...(opts.piPackageDir ? { PI_PACKAGE_DIR: opts.piPackageDir } : {}),
|
|
@@ -87,12 +100,12 @@ export function buildLaunch(creds, passthroughArgs, opts) {
|
|
|
87
100
|
// explicitly chose one (so power users can still point pi elsewhere).
|
|
88
101
|
const userChoseProvider = passthroughArgs.some(arg => arg === "--provider" || arg.startsWith("--provider="));
|
|
89
102
|
// Default the model to the `balanced` tier (YAG-380). Balanced drives on the
|
|
90
|
-
// judgment-grade `advanced` model
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
//
|
|
103
|
+
// judgment-grade `advanced` model and additionally lets the session escalate
|
|
104
|
+
// hard calls to `peak` through the capped ask_advisor tool. So it is strictly
|
|
105
|
+
// additive: no session reasons worse than plain advanced, and the hard ones
|
|
106
|
+
// can reason better. A user `--model` (e.g. `standard` or `efficient`) still
|
|
107
|
+
// wins. Without this, pi's default-model heuristic could land an interactive
|
|
108
|
+
// session on a weaker tier.
|
|
96
109
|
// Detect if the user explicitly set a model, whether via "--model" as a separate
|
|
97
110
|
// argument or using the equals form "--model=efficient". The previous check only
|
|
98
111
|
// caught the separate form, causing a duplicate "--model balanced" to be added
|
package/dist/login.d.ts
CHANGED
|
@@ -9,6 +9,13 @@ export interface LoginDeps {
|
|
|
9
9
|
baseUrl?: string;
|
|
10
10
|
/** Which profile to store the minted token in. Defaults to the active one. */
|
|
11
11
|
profileName?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Client identifier sent with the token poll so the backend can attribute
|
|
14
|
+
* the minted credential to the app that requested it. Defaults to "cli";
|
|
15
|
+
* the desktop shell (which reuses this flow) passes "desktop". The server
|
|
16
|
+
* treats unknown values as absent, so this can never break a login.
|
|
17
|
+
*/
|
|
18
|
+
client?: string;
|
|
12
19
|
fetchImpl?: typeof fetch;
|
|
13
20
|
now?: () => number;
|
|
14
21
|
sleep?: (ms: number) => Promise<void>;
|
package/dist/login.js
CHANGED
|
@@ -100,7 +100,9 @@ export async function login(deps = {}) {
|
|
|
100
100
|
res = await fetchImpl(`${baseUrl}/api/yagni-code/auth/token`, {
|
|
101
101
|
method: "POST",
|
|
102
102
|
headers: { "content-type": "application/json" },
|
|
103
|
-
|
|
103
|
+
// `client` attributes the minted token to the requesting app; servers
|
|
104
|
+
// that predate the field simply ignore it.
|
|
105
|
+
body: JSON.stringify({ device_code: start.device_code, client: deps.client ?? "cli" }),
|
|
104
106
|
signal: AbortSignal.timeout(POLL_REQUEST_TIMEOUT_MS),
|
|
105
107
|
});
|
|
106
108
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yagni-app/code-staging",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0-staging.1025.1",
|
|
4
4
|
"description": "YAGNI Code: a terminal coding agent that already knows your company. One YAGNI login routes the model and grounds the agent in your team's context.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"author": "YAGNI, Inc. <jack@yagni.app> (https://yagni.app)",
|
|
@@ -38,5 +38,5 @@
|
|
|
38
38
|
"@earendil-works/pi-tui": "0.83.0",
|
|
39
39
|
"typebox": "^1.1.38"
|
|
40
40
|
},
|
|
41
|
-
"yagniSourceSha": "
|
|
41
|
+
"yagniSourceSha": "ad43200e08a990ead4d891e469d4b88e338b070a"
|
|
42
42
|
}
|