@yagni-app/code 0.3.0 → 0.3.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.
Files changed (48) hide show
  1. package/dist/cli.js +12 -0
  2. package/dist/connectClaudeCode.d.ts +77 -0
  3. package/dist/connectClaudeCode.js +228 -0
  4. package/dist/connectCodex.d.ts +75 -0
  5. package/dist/connectCodex.js +201 -0
  6. package/dist/extension/approvedPrefixes.d.ts +11 -0
  7. package/dist/extension/approvedPrefixes.js +30 -0
  8. package/dist/extension/askAdvisorTool.d.ts +18 -3
  9. package/dist/extension/askAdvisorTool.js +121 -15
  10. package/dist/extension/askYagniTool.d.ts +23 -0
  11. package/dist/extension/askYagniTool.js +42 -2
  12. package/dist/extension/branding.d.ts +11 -1
  13. package/dist/extension/branding.js +47 -7
  14. package/dist/extension/config.d.ts +12 -0
  15. package/dist/extension/config.js +2 -1
  16. package/dist/extension/execPolicy.d.ts +17 -1
  17. package/dist/extension/execPolicy.js +164 -33
  18. package/dist/extension/flywheel.d.ts +44 -0
  19. package/dist/extension/flywheel.js +53 -0
  20. package/dist/extension/footer.d.ts +8 -1
  21. package/dist/extension/footer.js +33 -19
  22. package/dist/extension/guardian.d.ts +14 -4
  23. package/dist/extension/guardian.js +35 -11
  24. package/dist/extension/index.d.ts +20 -3
  25. package/dist/extension/index.js +92 -13
  26. package/dist/extension/mineBeat.d.ts +95 -0
  27. package/dist/extension/mineBeat.js +193 -0
  28. package/dist/extension/permission.d.ts +1 -0
  29. package/dist/extension/permission.js +23 -18
  30. package/dist/extension/pipeline/goCommand.js +6 -4
  31. package/dist/extension/pipeline/personas.js +1 -1
  32. package/dist/extension/pipeline/resilience.d.ts +2 -1
  33. package/dist/extension/pipeline/resilience.js +21 -2
  34. package/dist/extension/pipeline/runRegistry.d.ts +9 -1
  35. package/dist/extension/pipeline/runRegistry.js +22 -1
  36. package/dist/extension/recordDecisionTool.d.ts +8 -0
  37. package/dist/extension/recordDecisionTool.js +24 -0
  38. package/dist/extension/subagents.d.ts +7 -1
  39. package/dist/extension/subagents.js +60 -5
  40. package/dist/extension/todos.d.ts +28 -1
  41. package/dist/extension/todos.js +76 -1
  42. package/dist/extension/ultra.d.ts +27 -0
  43. package/dist/extension/ultra.js +76 -0
  44. package/dist/login.d.ts +4 -2
  45. package/dist/login.js +19 -4
  46. package/dist/token.d.ts +25 -0
  47. package/dist/token.js +45 -0
  48. package/package.json +3 -2
package/dist/login.d.ts CHANGED
@@ -34,8 +34,10 @@ type OpenRunner = (cmd: string, args: string[]) => Promise<void>;
34
34
  *
35
35
  * macOS: open <url>
36
36
  * Linux: xdg-open <url>
37
- * Windows: cmd /c start "" <url> (the empty "" is start's window-title slot;
38
- * without it `start` swallows the URL as the title and opens nothing)
37
+ * Windows: rundll32 url.dll,FileProtocolHandler <url> (opens the default
38
+ * browser without going through cmd.exe `cmd /c start <url>`
39
+ * re-parses its arguments as a shell line, so a hostile URL with
40
+ * `&`/`^` metacharacters could execute commands)
39
41
  */
40
42
  export declare function resolveOpenCommand(url: string, platform?: NodeJS.Platform): {
41
43
  cmd: string;
package/dist/login.js CHANGED
@@ -31,14 +31,17 @@ function isTimeoutError(err) {
31
31
  *
32
32
  * macOS: open <url>
33
33
  * Linux: xdg-open <url>
34
- * Windows: cmd /c start "" <url> (the empty "" is start's window-title slot;
35
- * without it `start` swallows the URL as the title and opens nothing)
34
+ * Windows: rundll32 url.dll,FileProtocolHandler <url> (opens the default
35
+ * browser without going through cmd.exe `cmd /c start <url>`
36
+ * re-parses its arguments as a shell line, so a hostile URL with
37
+ * `&`/`^` metacharacters could execute commands)
36
38
  */
37
39
  export function resolveOpenCommand(url, platform = process.platform) {
38
40
  if (platform === "darwin")
39
41
  return { cmd: "open", args: [url] };
40
- if (platform === "win32")
41
- return { cmd: "cmd", args: ["/c", "start", "", url] };
42
+ if (platform === "win32") {
43
+ return { cmd: "rundll32", args: ["url.dll,FileProtocolHandler", url] };
44
+ }
42
45
  return { cmd: "xdg-open", args: [url] };
43
46
  }
44
47
  const spawnRunner = (cmd, args) => new Promise((resolve, reject) => {
@@ -50,6 +53,18 @@ const spawnRunner = (cmd, args) => new Promise((resolve, reject) => {
50
53
  * URL is still printed for manual copy. `runner` is injectable for tests.
51
54
  */
52
55
  export const realOpenUrl = (url, runner = spawnRunner) => {
56
+ // Only ever hand http(s) URLs to the OS opener — refuse file:, javascript:,
57
+ // or custom schemes a compromised server response could try to smuggle in.
58
+ let parsed;
59
+ try {
60
+ parsed = new URL(url);
61
+ }
62
+ catch {
63
+ return Promise.resolve();
64
+ }
65
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
66
+ return Promise.resolve();
67
+ }
53
68
  const { cmd, args } = resolveOpenCommand(url);
54
69
  return runner(cmd, args).catch(() => {
55
70
  // Silently fail — the user can still copy the URL manually.
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `yagni token` — print the active environment's API token to stdout.
3
+ *
4
+ * This is the credential feed for `yagni connect claude-code`: Claude Code's
5
+ * `apiKeyHelper` runs this command (re-running on 401 and on a TTL), so the
6
+ * contract is strict — stdout carries the TOKEN AND NOTHING ELSE (Claude Code
7
+ * v2.1.227+ rejects helpers that print banners), and every notice goes to
8
+ * stderr. Riding the same refresh-at-launch client as the launcher means a
9
+ * token that enters the 7-day rotation window is rotated and persisted here
10
+ * too, so a Claude Code session keeps working without the user ever running
11
+ * `yagni` itself.
12
+ */
13
+ import { maybeRefreshAtLaunch } from "./refresh.js";
14
+ import type { Credentials } from "./credentials.js";
15
+ import { type Profile } from "./profiles.js";
16
+ export interface TokenCommandDeps {
17
+ readProfile?: () => Promise<Profile>;
18
+ refresh?: typeof maybeRefreshAtLaunch;
19
+ persist?: (name: string, creds: Credentials) => Promise<void>;
20
+ now?: () => number;
21
+ stdout?: (text: string) => void;
22
+ stderr?: (text: string) => void;
23
+ }
24
+ export declare function tokenCommand(deps?: TokenCommandDeps): Promise<number>;
25
+ //# sourceMappingURL=token.d.ts.map
package/dist/token.js ADDED
@@ -0,0 +1,45 @@
1
+ /**
2
+ * `yagni token` — print the active environment's API token to stdout.
3
+ *
4
+ * This is the credential feed for `yagni connect claude-code`: Claude Code's
5
+ * `apiKeyHelper` runs this command (re-running on 401 and on a TTL), so the
6
+ * contract is strict — stdout carries the TOKEN AND NOTHING ELSE (Claude Code
7
+ * v2.1.227+ rejects helpers that print banners), and every notice goes to
8
+ * stderr. Riding the same refresh-at-launch client as the launcher means a
9
+ * token that enters the 7-day rotation window is rotated and persisted here
10
+ * too, so a Claude Code session keeps working without the user ever running
11
+ * `yagni` itself.
12
+ */
13
+ import { classifyTokenExpiry } from "./launch.js";
14
+ import { maybeRefreshAtLaunch } from "./refresh.js";
15
+ import { credentialsFromProfile, persistProfileTokenRotation, readActiveProfile, } from "./profiles.js";
16
+ export async function tokenCommand(deps = {}) {
17
+ const readProfile = deps.readProfile ?? readActiveProfile;
18
+ const refresh = deps.refresh ?? maybeRefreshAtLaunch;
19
+ const persist = deps.persist ?? persistProfileTokenRotation;
20
+ const stdout = deps.stdout ?? ((t) => process.stdout.write(t));
21
+ const stderr = deps.stderr ?? ((t) => process.stderr.write(t));
22
+ const profile = await readProfile();
23
+ let creds = credentialsFromProfile(profile);
24
+ if (!creds?.token) {
25
+ stderr(`Not logged in to environment "${profile.name}" (${profile.baseUrl}). Run \`yagni login\` first.\n`);
26
+ return 1;
27
+ }
28
+ const outcome = await refresh(creds, {
29
+ persist: (c) => persist(profile.name, c),
30
+ ...(deps.now ? { now: deps.now } : {}),
31
+ });
32
+ for (const warning of outcome.warnings)
33
+ stderr(`${warning}\n`);
34
+ creds = outcome.creds;
35
+ // An expired token would send the consumer into a silent 401 loop — fail
36
+ // loudly instead so Claude Code surfaces a helper error the user can act on.
37
+ const nowMs = deps.now ? deps.now() : Date.now();
38
+ if (classifyTokenExpiry(creds.expiresAt, nowMs).kind === "expired") {
39
+ stderr("Your YAGNI Code session has expired. Run `yagni login` to re-authenticate.\n");
40
+ return 1;
41
+ }
42
+ stdout(`${creds.token}\n`);
43
+ return 0;
44
+ }
45
+ //# sourceMappingURL=token.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yagni-app/code",
3
- "version": "0.3.0",
3
+ "version": "0.3.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)",
@@ -36,7 +36,8 @@
36
36
  "dependencies": {
37
37
  "@earendil-works/pi-coding-agent": "0.84.1",
38
38
  "@earendil-works/pi-tui": "0.84.1",
39
+ "smol-toml": "^1.8.0",
39
40
  "typebox": "^1.3.11"
40
41
  },
41
- "yagniSourceSha": "7542705a2c99f19849bf98bbd5c2e712f5f47fd3"
42
+ "yagniSourceSha": "27482c0e8f72e0f171de23bd39e774d9661c0bc6"
42
43
  }