@onepointfour-packs/flaredeck-agent 0.1.0

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 (148) hide show
  1. package/LICENSE.md +14 -0
  2. package/README.md +102 -0
  3. package/dist/agent.d.ts +104 -0
  4. package/dist/agent.js +329 -0
  5. package/dist/agent.js.map +1 -0
  6. package/dist/approval.d.ts +72 -0
  7. package/dist/approval.js +161 -0
  8. package/dist/approval.js.map +1 -0
  9. package/dist/approvals.d.ts +2 -0
  10. package/dist/approvals.js +148 -0
  11. package/dist/approvals.js.map +1 -0
  12. package/dist/auth.d.ts +79 -0
  13. package/dist/auth.js +181 -0
  14. package/dist/auth.js.map +1 -0
  15. package/dist/automode.d.ts +33 -0
  16. package/dist/automode.js +69 -0
  17. package/dist/automode.js.map +1 -0
  18. package/dist/branches.d.ts +25 -0
  19. package/dist/branches.js +81 -0
  20. package/dist/branches.js.map +1 -0
  21. package/dist/cli.d.ts +2 -0
  22. package/dist/cli.js +12 -0
  23. package/dist/cli.js.map +1 -0
  24. package/dist/codesearch.d.ts +27 -0
  25. package/dist/codesearch.js +111 -0
  26. package/dist/codesearch.js.map +1 -0
  27. package/dist/concurrency.d.ts +14 -0
  28. package/dist/concurrency.js +52 -0
  29. package/dist/concurrency.js.map +1 -0
  30. package/dist/config.d.ts +106 -0
  31. package/dist/config.js +119 -0
  32. package/dist/config.js.map +1 -0
  33. package/dist/engine-antigravity.d.ts +23 -0
  34. package/dist/engine-antigravity.js +357 -0
  35. package/dist/engine-antigravity.js.map +1 -0
  36. package/dist/engine-claude.d.ts +18 -0
  37. package/dist/engine-claude.js +64 -0
  38. package/dist/engine-claude.js.map +1 -0
  39. package/dist/engine.d.ts +122 -0
  40. package/dist/engine.js +36 -0
  41. package/dist/engine.js.map +1 -0
  42. package/dist/env.d.ts +1 -0
  43. package/dist/env.js +10 -0
  44. package/dist/env.js.map +1 -0
  45. package/dist/environment.d.ts +39 -0
  46. package/dist/environment.js +100 -0
  47. package/dist/environment.js.map +1 -0
  48. package/dist/flaredeck-check.d.ts +21 -0
  49. package/dist/flaredeck-check.js +12 -0
  50. package/dist/flaredeck-check.js.map +1 -0
  51. package/dist/flaredeck-proxy.d.ts +60 -0
  52. package/dist/flaredeck-proxy.js +186 -0
  53. package/dist/flaredeck-proxy.js.map +1 -0
  54. package/dist/flaredeck.d.ts +132 -0
  55. package/dist/flaredeck.js +106 -0
  56. package/dist/flaredeck.js.map +1 -0
  57. package/dist/gemini.d.ts +21 -0
  58. package/dist/gemini.js +59 -0
  59. package/dist/gemini.js.map +1 -0
  60. package/dist/gitguard.d.ts +2 -0
  61. package/dist/gitguard.js +90 -0
  62. package/dist/gitguard.js.map +1 -0
  63. package/dist/github.d.ts +38 -0
  64. package/dist/github.js +153 -0
  65. package/dist/github.js.map +1 -0
  66. package/dist/githubauth.d.ts +21 -0
  67. package/dist/githubauth.js +90 -0
  68. package/dist/githubauth.js.map +1 -0
  69. package/dist/intake.d.ts +124 -0
  70. package/dist/intake.js +383 -0
  71. package/dist/intake.js.map +1 -0
  72. package/dist/jam.d.ts +45 -0
  73. package/dist/jam.js +385 -0
  74. package/dist/jam.js.map +1 -0
  75. package/dist/jev.d.ts +31 -0
  76. package/dist/jev.js +75 -0
  77. package/dist/jev.js.map +1 -0
  78. package/dist/jevguard.d.ts +28 -0
  79. package/dist/jevguard.js +213 -0
  80. package/dist/jevguard.js.map +1 -0
  81. package/dist/mailbox.d.ts +22 -0
  82. package/dist/mailbox.js +51 -0
  83. package/dist/mailbox.js.map +1 -0
  84. package/dist/main.d.ts +2 -0
  85. package/dist/main.js +764 -0
  86. package/dist/main.js.map +1 -0
  87. package/dist/markdown.d.ts +5 -0
  88. package/dist/markdown.js +81 -0
  89. package/dist/markdown.js.map +1 -0
  90. package/dist/oauth.d.ts +30 -0
  91. package/dist/oauth.js +216 -0
  92. package/dist/oauth.js.map +1 -0
  93. package/dist/permissions.d.ts +43 -0
  94. package/dist/permissions.js +57 -0
  95. package/dist/permissions.js.map +1 -0
  96. package/dist/preflight.d.ts +71 -0
  97. package/dist/preflight.js +116 -0
  98. package/dist/preflight.js.map +1 -0
  99. package/dist/providers.d.ts +26 -0
  100. package/dist/providers.js +27 -0
  101. package/dist/providers.js.map +1 -0
  102. package/dist/repopicker.d.ts +3 -0
  103. package/dist/repopicker.js +111 -0
  104. package/dist/repopicker.js.map +1 -0
  105. package/dist/runs.d.ts +59 -0
  106. package/dist/runs.js +211 -0
  107. package/dist/runs.js.map +1 -0
  108. package/dist/sandbox.d.ts +13 -0
  109. package/dist/sandbox.js +110 -0
  110. package/dist/sandbox.js.map +1 -0
  111. package/dist/schedules.d.ts +11 -0
  112. package/dist/schedules.js +85 -0
  113. package/dist/schedules.js.map +1 -0
  114. package/dist/secretguard.d.ts +4 -0
  115. package/dist/secretguard.js +115 -0
  116. package/dist/secretguard.js.map +1 -0
  117. package/dist/secrets.d.ts +27 -0
  118. package/dist/secrets.js +51 -0
  119. package/dist/secrets.js.map +1 -0
  120. package/dist/serve.d.ts +17 -0
  121. package/dist/serve.js +1206 -0
  122. package/dist/serve.js.map +1 -0
  123. package/dist/status.d.ts +73 -0
  124. package/dist/status.js +98 -0
  125. package/dist/status.js.map +1 -0
  126. package/dist/stream.d.ts +91 -0
  127. package/dist/stream.js +103 -0
  128. package/dist/stream.js.map +1 -0
  129. package/dist/streamtoken.d.ts +2 -0
  130. package/dist/streamtoken.js +30 -0
  131. package/dist/streamtoken.js.map +1 -0
  132. package/dist/team.d.ts +61 -0
  133. package/dist/team.js +136 -0
  134. package/dist/team.js.map +1 -0
  135. package/dist/ui.d.ts +110 -0
  136. package/dist/ui.js +348 -0
  137. package/dist/ui.js.map +1 -0
  138. package/dist/updater.d.ts +15 -0
  139. package/dist/updater.js +178 -0
  140. package/dist/updater.js.map +1 -0
  141. package/dist/workspace.d.ts +115 -0
  142. package/dist/workspace.js +247 -0
  143. package/dist/workspace.js.map +1 -0
  144. package/dist/worktree.d.ts +42 -0
  145. package/dist/worktree.js +140 -0
  146. package/dist/worktree.js.map +1 -0
  147. package/package.json +52 -0
  148. package/python/sidecar.py +178 -0
@@ -0,0 +1,15 @@
1
+ export declare function installedSdkVersion(): string;
2
+ export declare const updatesEnabled: () => boolean;
3
+ /** A version waiting for the next start, or '' when none. */
4
+ export declare function pendingUpdate(): string;
5
+ /**
6
+ * Look for a newer, old-enough release of the same minor and warm the cache for it. Returns the
7
+ * version now waiting for a restart, or '' when there is nothing new. Never throws: an offline
8
+ * machine just stays where it is.
9
+ */
10
+ export declare function checkAndStage(): Promise<string>;
11
+ /**
12
+ * Called by the launcher before anything is loaded. Installs what was downloaded; on any
13
+ * failure puts the previous version back and never offers that release again.
14
+ */
15
+ export declare function applyPendingUpdate(): string;
@@ -0,0 +1,178 @@
1
+ import { execFile, execFileSync } from 'node:child_process';
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { dirname, join, resolve } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ /**
7
+ * Keeps the Claude Agent SDK current, the way Claude Code keeps itself current: fetch the new
8
+ * version in the background, say so in the pane, and switch to it on the next start.
9
+ *
10
+ * Never swapped under a running process. The SDK spawns its bundled CLI for every query, so
11
+ * replacing files mid-run would pair an old wrapper with a new binary. The download only warms
12
+ * npm's cache and records what is waiting; the launcher installs it before anything is loaded.
13
+ *
14
+ * Narrow on purpose: the same 0.minor only (in 0.x the minor is the breaking-change signal),
15
+ * releases at least two days old (time for a bad or hijacked one to be pulled), a post-install
16
+ * check, and a rollback that remembers the version it rejected.
17
+ */
18
+ const PKG = '@anthropic-ai/claude-agent-sdk';
19
+ const MIN_AGE_MS = 2 * 24 * 60 * 60 * 1000;
20
+ const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
21
+ const stateFile = () => join(process.env['XDG_CONFIG_HOME'] || join(homedir(), '.config'), 'flaredeck-agent', 'update.json');
22
+ function load() {
23
+ try {
24
+ return existsSync(stateFile()) ? JSON.parse(readFileSync(stateFile(), 'utf8')) : {};
25
+ }
26
+ catch {
27
+ return {};
28
+ }
29
+ }
30
+ function save(s) {
31
+ mkdirSync(dirname(stateFile()), { recursive: true });
32
+ writeFileSync(stateFile(), `${JSON.stringify(s, null, 2)}\n`);
33
+ }
34
+ /** The preload in some shells breaks npm; the child never needs it. */
35
+ const childEnv = () => {
36
+ const env = { ...process.env };
37
+ delete env['NODE_OPTIONS'];
38
+ return env;
39
+ };
40
+ export function installedSdkVersion() {
41
+ try {
42
+ return JSON.parse(readFileSync(join(ROOT, 'node_modules', PKG, 'package.json'), 'utf8')).version;
43
+ }
44
+ catch {
45
+ return '';
46
+ }
47
+ }
48
+ export const updatesEnabled = () => process.env['FLAREDECK_AGENT_NO_UPDATE'] !== '1';
49
+ /** A version waiting for the next start, or '' when none. */
50
+ export function pendingUpdate() {
51
+ const v = load().pending?.version ?? '';
52
+ return v && v !== installedSdkVersion() ? v : '';
53
+ }
54
+ const parse = (v) => {
55
+ const m = /^(\d+)\.(\d+)\.(\d+)$/.exec(v);
56
+ return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null;
57
+ };
58
+ function run(args, timeout) {
59
+ return new Promise((ok, fail) => execFile('npm', args, { cwd: ROOT, env: childEnv(), timeout }, (err) => (err ? fail(err) : ok())));
60
+ }
61
+ /**
62
+ * Look for a newer, old-enough release of the same minor and warm the cache for it. Returns the
63
+ * version now waiting for a restart, or '' when there is nothing new. Never throws: an offline
64
+ * machine just stays where it is.
65
+ */
66
+ export async function checkAndStage() {
67
+ if (!updatesEnabled())
68
+ return '';
69
+ try {
70
+ const state = load();
71
+ const current = installedSdkVersion();
72
+ const cur = parse(current);
73
+ if (!cur)
74
+ return '';
75
+ const res = await fetch(`https://registry.npmjs.org/${PKG}`, { signal: AbortSignal.timeout(30_000) });
76
+ if (!res.ok)
77
+ return '';
78
+ const doc = (await res.json());
79
+ const best = Object.keys(doc.versions ?? {})
80
+ .filter((v) => !state.bad?.includes(v))
81
+ .map((v) => ({ v, p: parse(v), at: Date.parse(doc.time?.[v] ?? '') }))
82
+ .filter((x) => !!x.p && Number.isFinite(x.at))
83
+ .filter((x) => x.p[0] === cur[0] && x.p[1] === cur[1] && x.p[2] > cur[2] && Date.now() - x.at >= MIN_AGE_MS)
84
+ .sort((a, b) => b.p[2] - a.p[2])[0];
85
+ state.lastCheck = Date.now();
86
+ if (!best) {
87
+ save(state);
88
+ return state.pending && state.pending.version !== current ? state.pending.version : '';
89
+ }
90
+ if (state.pending?.version !== best.v) {
91
+ await run(['cache', 'add', `${PKG}@${best.v}`], 120_000);
92
+ state.pending = { version: best.v, at: Date.now() };
93
+ }
94
+ save(state);
95
+ return best.v;
96
+ }
97
+ catch {
98
+ return '';
99
+ }
100
+ }
101
+ /**
102
+ * Install `version` here, then prove the SDK still loads, still has what the harness uses, AND can
103
+ * still start its CLI.
104
+ *
105
+ * That last check is not belt-and-braces. From 0.3.289 the SDK ships its CLI as a per-platform
106
+ * OPTIONAL dependency (`@anthropic-ai/claude-agent-sdk-darwin-arm64` and friends) instead of
107
+ * vendoring it. An optional dependency that fails to install is not an npm error — it is silently
108
+ * skipped — and the JS half still imports perfectly, so `query`/`tool`/`createSdkMcpServer` are all
109
+ * functions and the old check passed. The agent then came up looking healthy and died on the first
110
+ * question with "Native CLI binary for darwin-arm64 not found", which no rollback caught because
111
+ * nothing had failed yet.
112
+ *
113
+ * So: ask for optional dependencies explicitly, and verify by RUNNING the binary.
114
+ */
115
+ function installAndVerify(version) {
116
+ try {
117
+ execFileSync('npm', [
118
+ 'install',
119
+ '--no-save',
120
+ '--no-audit',
121
+ '--no-fund',
122
+ // The platform binary is only ever an optional dep; never let npm skip it quietly.
123
+ '--include=optional',
124
+ '--engine-strict=false',
125
+ `${PKG}@${version}`,
126
+ ], { cwd: ROOT, env: childEnv(), stdio: 'ignore', timeout: 300_000 });
127
+ execFileSync(process.execPath, [
128
+ '--input-type=module',
129
+ '-e',
130
+ `const m = await import('${PKG}'); for (const k of ['query','createSdkMcpServer','tool']) if (typeof m[k] !== 'function') process.exit(1);`,
131
+ ], { cwd: ROOT, env: childEnv(), stdio: 'ignore', timeout: 60_000 });
132
+ if (!cliRuns())
133
+ return false;
134
+ return installedSdkVersion() === version;
135
+ }
136
+ catch {
137
+ return false;
138
+ }
139
+ }
140
+ /**
141
+ * Can the SDK's CLI for THIS platform actually start? `--version` is enough: it exits non-zero (or
142
+ * throws ENOENT) when the binary is missing, which is the whole failure this guards against.
143
+ */
144
+ function cliRuns() {
145
+ const bin = join(ROOT, 'node_modules', `${PKG}-${process.platform}-${process.arch}`, 'claude');
146
+ try {
147
+ execFileSync(bin, ['--version'], { cwd: ROOT, env: childEnv(), stdio: 'ignore', timeout: 60_000 });
148
+ return true;
149
+ }
150
+ catch {
151
+ return false;
152
+ }
153
+ }
154
+ /**
155
+ * Called by the launcher before anything is loaded. Installs what was downloaded; on any
156
+ * failure puts the previous version back and never offers that release again.
157
+ */
158
+ export function applyPendingUpdate() {
159
+ if (!updatesEnabled())
160
+ return '';
161
+ const state = load();
162
+ const target = state.pending?.version;
163
+ const before = installedSdkVersion();
164
+ if (!target || !before || target === before)
165
+ return '';
166
+ process.stdout.write(`Updating the Claude Agent SDK ${before} → ${target}…\n`);
167
+ if (installAndVerify(target)) {
168
+ delete state.pending;
169
+ save(state);
170
+ return `SDK updated ${before} → ${target}`;
171
+ }
172
+ installAndVerify(before);
173
+ delete state.pending;
174
+ state.bad = [...(state.bad ?? []), target];
175
+ save(state);
176
+ return `SDK ${target} failed its check — staying on ${before}`;
177
+ }
178
+ //# sourceMappingURL=updater.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updater.js","sourceRoot":"","sources":["../src/updater.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,115 @@
1
+ import type { StreamEvent } from './stream.js';
2
+ /**
3
+ * Which repositories an agent may work in — answered by the directory it was started in, and by
4
+ * nothing else.
5
+ *
6
+ * The rule is the one a person already has in their head when they type the command: start the
7
+ * agent in a repo and it works that repo; start it in a folder that holds five repos and it works
8
+ * all five, because that is what choosing that folder meant. There is no list to configure, which
9
+ * is the point — a config field for this was always half-set, and a stale one silently either
10
+ * hides a repo the agent should have or hands it one it should not touch.
11
+ *
12
+ * Nothing here decides WHICH repo a card belongs to by itself. The card does that: FlareDeck
13
+ * resolves a branch per repository from the board's config and the card's Component, and
14
+ * `resolveCheckout` matches those against the checkouts actually on disk. The folder says what is
15
+ * allowed; the card says where the work goes.
16
+ */
17
+ export type Checkout = {
18
+ /** The checkout's path on disk. */
19
+ path: string;
20
+ /** Its directory name, which is what a person calls it. */
21
+ name: string;
22
+ /** `origin`, or empty for a repo with no remote. */
23
+ origin: string;
24
+ };
25
+ /** A git URL reduced to host/owner/name, so ssh and https forms of one repo compare equal. */
26
+ /** `owner/name`, which is how a person says which repo they mean. */
27
+ export declare function shortName(url: string): string;
28
+ export declare function repoIdentity(url: string): string;
29
+ /**
30
+ * The checkouts this agent may work in.
31
+ *
32
+ * A repo is itself, and nothing else — a repo that happens to contain a vendored checkout is one
33
+ * project, not two. Otherwise the immediate children: one level only, because a folder of
34
+ * projects is the shape people actually have, and recursing would drag in node_modules and the
35
+ * worktrees this harness creates. Hidden directories are skipped, which is also what keeps
36
+ * `.worktrees-*` — written beside each repo by `ensureWorktree` — from being mistaken for repos
37
+ * of their own.
38
+ *
39
+ * The directory list is re-read on every call so a repo cloned while the agent runs is simply
40
+ * there; only the remotes are cached.
41
+ */
42
+ export declare function checkouts(root: string, allow?: readonly string[]): Promise<Checkout[]>;
43
+ export type RepoChoice = {
44
+ checkout: Checkout;
45
+ branch: string;
46
+ role: string;
47
+ };
48
+ export type Resolved =
49
+ /** One checkout owns this card. `branch`/`role` come from the board when it said. */
50
+ ({
51
+ kind: 'repo';
52
+ } & RepoChoice)
53
+ /** The workspace holds no git checkout at all: work in place, with no branch and no isolation. */
54
+ | {
55
+ kind: 'none';
56
+ }
57
+ /**
58
+ * The card names repositories, none of which this agent may work in. `notTicked` are the ones
59
+ * sitting in the folder that were simply not granted at login — a different problem with a
60
+ * different fix, and telling them apart is the difference between "clone it" and "tick it".
61
+ */
62
+ | {
63
+ kind: 'unknown';
64
+ wanted: string[];
65
+ have: Checkout[];
66
+ notTicked: string[];
67
+ }
68
+ /** Several of this agent's repos are in scope and the card does not say which. */
69
+ | {
70
+ kind: 'ambiguous';
71
+ candidates: RepoChoice[];
72
+ };
73
+ /**
74
+ * Which checkout this card's work belongs in.
75
+ *
76
+ * The card's own answer wins: `baseBranches` carries one entry per repository the card is scoped
77
+ * to — just the card's Component when it has one, and every repository on the board when it does
78
+ * not. So a card that names its component resolves to exactly one checkout, and a card that names
79
+ * nothing on a five-repo board is genuinely unanswered rather than defaulting to whichever repo
80
+ * the agent happened to start in. Guessing there is how work lands in the wrong repository, and
81
+ * the whole reason this returns a verdict instead of a path.
82
+ */
83
+ export declare function resolveCheckout(root: string, event: StreamEvent, allow?: readonly string[]): Promise<Resolved>;
84
+ /**
85
+ * Break a tie by asking the code. When a card names no component, the files that mention the
86
+ * card's own words are the best evidence available of where the work is, and it is evidence the
87
+ * harness can gather for nothing — a local `git grep` per candidate, run only in the rare case
88
+ * where the board left the question open.
89
+ *
90
+ * Returns null rather than a weak winner: a card whose terms appear nowhere, or appear evenly
91
+ * across repos, is one a person should route. Asking beats committing to the wrong repository.
92
+ */
93
+ export declare function voteByCode(candidates: RepoChoice[], text: string): Promise<RepoChoice | null>;
94
+ /** What to tell a person when the harness will not choose. */
95
+ export declare function askingForComponent(r: Extract<Resolved, {
96
+ kind: 'ambiguous' | 'unknown';
97
+ }>): string;
98
+ /**
99
+ * The layout, for the agent. Told only in a workspace of several repos, where it is the difference
100
+ * between knowing where you are and finding out by writing somewhere.
101
+ */
102
+ export declare function workspaceBrief(root: string, list: Checkout[], chosen: Checkout | null): string;
103
+ /**
104
+ * Which of the repositories in this folder the agent may work in — asked once, at login.
105
+ *
106
+ * The folder is still what is on offer; this is only the person narrowing it. A folder of twenty
107
+ * repos is rarely twenty an agent should be committing to, and the difference between "can read"
108
+ * and "may change" is worth one deliberate keystroke. A repo with no remote starts unticked — it
109
+ * cannot be pushed or opened as a pull request, so an agent given a card in one would do work
110
+ * nobody can receive.
111
+ *
112
+ * Returns the directory names, which is what the person just read on screen. Null when there was
113
+ * nothing to ask about, or when they backed out.
114
+ */
115
+ export declare function askRepos(root: string, say: (s: string) => void, already?: readonly string[]): Promise<string[] | null>;
@@ -0,0 +1,247 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { readdirSync, statSync } from 'node:fs';
3
+ import { basename, join } from 'node:path';
4
+ import { codeSearch } from './codesearch.js';
5
+ /** A git URL reduced to host/owner/name, so ssh and https forms of one repo compare equal. */
6
+ /** `owner/name`, which is how a person says which repo they mean. */
7
+ export function shortName(url) {
8
+ return repoIdentity(url).split('/').slice(-2).join('/') || url;
9
+ }
10
+ export function repoIdentity(url) {
11
+ return url.trim().toLowerCase()
12
+ .replace(/^git@([^:]+):/, '$1/')
13
+ .replace(/^[a-z]+:\/\//, '')
14
+ .replace(/\.git$/, '')
15
+ .replace(/\/+$/, '');
16
+ }
17
+ async function git(args, cwd) {
18
+ return new Promise((resolve) => {
19
+ const c = spawn('git', args, { cwd });
20
+ let out = '';
21
+ c.stdout.on('data', (d) => (out += String(d)));
22
+ c.on('close', () => resolve(out.trim()));
23
+ c.on('error', () => resolve(''));
24
+ });
25
+ }
26
+ /**
27
+ * A checkout's remote never changes in practice, and a card asks for it on every event, so it is
28
+ * read once per path per process rather than spawning git on every wake.
29
+ */
30
+ const remotes = new Map();
31
+ async function originOf(path) {
32
+ const cached = remotes.get(path);
33
+ if (cached !== undefined)
34
+ return cached;
35
+ const url = await git(['remote', 'get-url', 'origin'], path);
36
+ remotes.set(path, url);
37
+ return url;
38
+ }
39
+ /**
40
+ * A clone of its own, which means `.git` is a DIRECTORY. A linked worktree and a submodule both
41
+ * have `.git` as a FILE pointing elsewhere, and neither is an independent project: a card must
42
+ * never be worked in someone's ad-hoc worktree, where the branch is already checked out for
43
+ * something else. This harness's own worktrees are hidden (`.worktrees-*`) and skipped anyway;
44
+ * hand-made ones sitting in the open are exactly what this excludes.
45
+ */
46
+ const isRepo = (path) => statSafe(join(path, '.git'))?.isDirectory() ?? false;
47
+ function statSafe(path) {
48
+ try {
49
+ return statSync(path);
50
+ }
51
+ catch {
52
+ return null;
53
+ }
54
+ }
55
+ /**
56
+ * The checkouts this agent may work in.
57
+ *
58
+ * A repo is itself, and nothing else — a repo that happens to contain a vendored checkout is one
59
+ * project, not two. Otherwise the immediate children: one level only, because a folder of
60
+ * projects is the shape people actually have, and recursing would drag in node_modules and the
61
+ * worktrees this harness creates. Hidden directories are skipped, which is also what keeps
62
+ * `.worktrees-*` — written beside each repo by `ensureWorktree` — from being mistaken for repos
63
+ * of their own.
64
+ *
65
+ * The directory list is re-read on every call so a repo cloned while the agent runs is simply
66
+ * there; only the remotes are cached.
67
+ */
68
+ export async function checkouts(root, allow) {
69
+ if (isRepo(root))
70
+ return [{ path: root, name: basename(root), origin: await originOf(root) }];
71
+ let names;
72
+ try {
73
+ names = readdirSync(root, { withFileTypes: true })
74
+ .filter((e) => (e.isDirectory() || e.isSymbolicLink()) && !e.name.startsWith('.'))
75
+ .map((e) => e.name)
76
+ .sort();
77
+ }
78
+ catch {
79
+ return [];
80
+ }
81
+ // A folder of twenty repos is rarely twenty an agent should touch, so login asks once and the
82
+ // answer narrows what the folder offers. It narrows and never widens: a repo that is not in the
83
+ // folder cannot be granted by a config file, and a repo removed from the folder is gone whatever
84
+ // the config still says. An empty or absent list means everything found here — which is what a
85
+ // config written before this question existed means too.
86
+ const picked = allow?.length ? new Set(allow) : null;
87
+ const found = names
88
+ .filter((name) => !picked || picked.has(name))
89
+ .map((name) => join(root, name))
90
+ .filter(isRepo);
91
+ return Promise.all(found.map(async (path) => ({ path, name: basename(path), origin: await originOf(path) })));
92
+ }
93
+ /**
94
+ * Which checkout this card's work belongs in.
95
+ *
96
+ * The card's own answer wins: `baseBranches` carries one entry per repository the card is scoped
97
+ * to — just the card's Component when it has one, and every repository on the board when it does
98
+ * not. So a card that names its component resolves to exactly one checkout, and a card that names
99
+ * nothing on a five-repo board is genuinely unanswered rather than defaulting to whichever repo
100
+ * the agent happened to start in. Guessing there is how work lands in the wrong repository, and
101
+ * the whole reason this returns a verdict instead of a path.
102
+ */
103
+ export async function resolveCheckout(root, event, allow) {
104
+ const list = await checkouts(root, allow);
105
+ if (!list.length)
106
+ return { kind: 'none' };
107
+ const entries = (event.baseBranches ?? []).filter((e) => e.repository);
108
+ if (!entries.length) {
109
+ // The board declares no repositories. One checkout is then unambiguous; several are not.
110
+ const only = list[0];
111
+ return list.length === 1 && only
112
+ ? { kind: 'repo', checkout: only, branch: '', role: '' }
113
+ : { kind: 'ambiguous', candidates: list.map((c) => ({ checkout: c, branch: '', role: '' })) };
114
+ }
115
+ const hits = [];
116
+ for (const e of entries) {
117
+ const id = repoIdentity(e.repository);
118
+ for (const c of list) {
119
+ if (!c.origin || repoIdentity(c.origin) !== id)
120
+ continue;
121
+ // Two directories can be clones of one remote (a spare checkout, a case-study copy). They
122
+ // are the same repository, so the card is not ambiguous — prefer the one named after it.
123
+ const already = hits.find((h) => repoIdentity(h.checkout.origin) === id);
124
+ if (already) {
125
+ const wanted = id.split('/').pop() ?? '';
126
+ if (c.name.toLowerCase() === wanted && already.checkout.name.toLowerCase() !== wanted) {
127
+ already.checkout = c;
128
+ }
129
+ continue;
130
+ }
131
+ hits.push({ checkout: c, branch: e.branch, role: e.role });
132
+ }
133
+ }
134
+ const one = hits[0];
135
+ if (hits.length === 1 && one)
136
+ return { kind: 'repo', ...one };
137
+ if (!hits.length) {
138
+ // Is it here but ungranted? That is a tick at login, not a clone, and the person should be
139
+ // told which it is.
140
+ const everything = allow?.length ? await checkouts(root) : list;
141
+ const wantedIds = new Set(entries.map((e) => repoIdentity(e.repository)));
142
+ const notTicked = everything
143
+ .filter((c) => c.origin && wantedIds.has(repoIdentity(c.origin)) && !list.some((m) => m.path === c.path))
144
+ .map((c) => c.name);
145
+ return { kind: 'unknown', wanted: entries.map((e) => shortName(e.repository)), have: list, notTicked };
146
+ }
147
+ return { kind: 'ambiguous', candidates: hits };
148
+ }
149
+ /**
150
+ * Break a tie by asking the code. When a card names no component, the files that mention the
151
+ * card's own words are the best evidence available of where the work is, and it is evidence the
152
+ * harness can gather for nothing — a local `git grep` per candidate, run only in the rare case
153
+ * where the board left the question open.
154
+ *
155
+ * Returns null rather than a weak winner: a card whose terms appear nowhere, or appear evenly
156
+ * across repos, is one a person should route. Asking beats committing to the wrong repository.
157
+ */
158
+ export async function voteByCode(candidates, text) {
159
+ if (!text.trim())
160
+ return null;
161
+ const scored = await Promise.all(candidates.map(async (c) => {
162
+ const found = await codeSearch(c.checkout.path, text).catch(() => null);
163
+ return { c, score: (found?.files ?? []).reduce((n, f) => n + f.score, 0) };
164
+ }));
165
+ scored.sort((a, b) => b.score - a.score);
166
+ const [best, next] = scored;
167
+ if (!best || best.score <= 0)
168
+ return null;
169
+ // Clearly ahead, not merely ahead: a repo that shares a term or two with its neighbour is not
170
+ // an answer. Twice the runner-up, or the only one with any hits at all.
171
+ if (next && next.score > 0 && best.score < next.score * 2)
172
+ return null;
173
+ return best.c;
174
+ }
175
+ /** What to tell a person when the harness will not choose. */
176
+ export function askingForComponent(r) {
177
+ if (r.kind === 'unknown') {
178
+ const mine = r.have.map((c) => c.name).join(', ') || 'no repository';
179
+ if (r.notTicked.length) {
180
+ return (`This card is for ${r.wanted.join(', ')}, which is on the machine working it ` +
181
+ `(${r.notTicked.join(', ')}) but was not granted to this agent. It works in ${mine}. ` +
182
+ `Run "flaredeck-agent login" in that folder and tick it, or give the card to the agent ` +
183
+ `that has it.`);
184
+ }
185
+ return (`This card is for ${r.wanted.join(', ')}, which is not on the machine working it. This agent ` +
186
+ `works in ${mine}. Either the card is for another agent, or that repository needs cloning ` +
187
+ `into the same folder.`);
188
+ }
189
+ return (`This card does not say which repository it is for, and this agent works in several: ` +
190
+ `${r.candidates.map((c) => c.checkout.name).join(', ')}. Set the card's Component and it will ` +
191
+ `be picked up — nothing else is needed.`);
192
+ }
193
+ /**
194
+ * The layout, for the agent. Told only in a workspace of several repos, where it is the difference
195
+ * between knowing where you are and finding out by writing somewhere.
196
+ */
197
+ export function workspaceBrief(root, list, chosen) {
198
+ if (list.length < 2)
199
+ return '';
200
+ const others = list.filter((c) => c.path !== chosen?.path).map((c) => c.name);
201
+ return (`\n\n## The workspace\n\n` +
202
+ `This machine works ${list.length} repositories under ${root}: ${list.map((c) => c.name).join(', ')}.\n` +
203
+ (chosen
204
+ ? `This card is in ${chosen.name}, and your checkout for it is below. The others — ` +
205
+ `${others.join(', ')} — you may READ to understand how things fit together, and must not ` +
206
+ `change: they are other cards' repositories and other branches, with no worktree of yours ` +
207
+ `in them. Work that turns out to belong in one of them is a comment on the card saying so, ` +
208
+ `not an edit made there.`
209
+ : `No repository is established for this card, so you have NO checkout of your own and must ` +
210
+ `not change any of these — every one of them is someone's working tree. You can still ` +
211
+ `read all of them, which is usually enough to answer. If this turn needs a change made, ` +
212
+ `say on the card which repository it belongs in and leave it to be picked up with that ` +
213
+ `set: a change made in place here would be lost or would land on someone else's branch.`));
214
+ }
215
+ /**
216
+ * Which of the repositories in this folder the agent may work in — asked once, at login.
217
+ *
218
+ * The folder is still what is on offer; this is only the person narrowing it. A folder of twenty
219
+ * repos is rarely twenty an agent should be committing to, and the difference between "can read"
220
+ * and "may change" is worth one deliberate keystroke. A repo with no remote starts unticked — it
221
+ * cannot be pushed or opened as a pull request, so an agent given a card in one would do work
222
+ * nobody can receive.
223
+ *
224
+ * Returns the directory names, which is what the person just read on screen. Null when there was
225
+ * nothing to ask about, or when they backed out.
226
+ */
227
+ export async function askRepos(root, say, already) {
228
+ const list = await checkouts(root);
229
+ if (list.length < 2)
230
+ return null;
231
+ const prior = already?.length ? new Set(already) : null;
232
+ const initial = new Set(list.filter((c) => (prior ? prior.has(c.name) : !!c.origin)).map((c) => c.name));
233
+ // Nothing to ask when there is nobody to answer. A login run from a script or a pipe would
234
+ // otherwise block forever on a prompt no one can see, which looks exactly like a hang.
235
+ if (!process.stdin.isTTY) {
236
+ say(`\nNot a terminal, so nothing was asked — keeping: ${[...initial].join(', ') || 'none'}`);
237
+ return initial.size === list.length ? [] : [...initial];
238
+ }
239
+ const { pickRepos } = await import('./repopicker.js');
240
+ const picked = await pickRepos(root, list, initial);
241
+ if (!picked)
242
+ return null;
243
+ // Everything ticked is the same as no restriction, and saying so beats a saved list that has to
244
+ // be maintained in step with the folder.
245
+ return picked.length === list.length ? [] : picked;
246
+ }
247
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * A checkout per card.
3
+ *
4
+ * Without this the agent edits the repo it was pointed at — which, on a machine anyone also uses,
5
+ * means editing a working tree while someone is in it: uncommitted changes colliding, the branch
6
+ * moving under them. A worktree costs almost nothing (git shares the object store) and makes the
7
+ * question "what did the agent change?" answerable with one diff.
8
+ *
9
+ * It also makes abandoning safe. A stalled card leaves its worktree behind rather than half-edited
10
+ * files in the checkout someone else is using, so nothing has to be unpicked.
11
+ */
12
+ export type Worktree = {
13
+ path: string;
14
+ branch: string;
15
+ created: boolean;
16
+ from?: string;
17
+ };
18
+ export declare function ensureWorktree(repo: string, card: string, onStep: (text: string) => void,
19
+ /**
20
+ * Where work is cut FROM, which is not always the repo's default branch. Some projects have agents
21
+ * branch from `dev` — the lead owns it, agents take the latest and hand a feature branch back.
22
+ * Cutting from the default instead would base every card on the wrong history, and the merge
23
+ * would look like a much bigger change than it is.
24
+ */
25
+ base?: string): Promise<Worktree | null>;
26
+ /** Told to the agent so it knows where it is and what it is on. */
27
+ export declare function worktreeBrief(tree: Worktree | null): string;
28
+ /**
29
+ * Remove a card's worktree once the card is finished with.
30
+ *
31
+ * Worktrees accumulate: one repository here had fourteen, most of them long-done cards, each a
32
+ * full checkout on disk. But a worktree is also the ONLY copy of anything an agent has committed
33
+ * and not published, so this refuses far more readily than it deletes.
34
+ *
35
+ * It removes only when there is nothing to lose: no uncommitted changes, no untracked files, and
36
+ * no commit that is not already on the remote. Anything else is left exactly where it is, and the
37
+ * reason is returned so a person can be told rather than left to find an orphan later.
38
+ */
39
+ export declare function releaseWorktree(repo: string, card: string, onStep: (text: string) => void): Promise<{
40
+ removed: boolean;
41
+ why: string;
42
+ }>;