@telora/daemon 0.19.28 → 0.19.33
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/build-info.json +2 -2
- package/dist/cli/connect.d.ts +115 -2
- package/dist/cli/connect.d.ts.map +1 -1
- package/dist/cli/connect.js +223 -18
- package/dist/cli/connect.js.map +1 -1
- package/dist/cli/harness-add.d.ts +37 -0
- package/dist/cli/harness-add.d.ts.map +1 -0
- package/dist/cli/harness-add.js +48 -0
- package/dist/cli/harness-add.js.map +1 -0
- package/dist/cli/open.d.ts +171 -0
- package/dist/cli/open.d.ts.map +1 -0
- package/dist/cli/open.js +323 -0
- package/dist/cli/open.js.map +1 -0
- package/dist/config-hot-reload.d.ts +91 -0
- package/dist/config-hot-reload.d.ts.map +1 -0
- package/dist/config-hot-reload.js +121 -0
- package/dist/config-hot-reload.js.map +1 -0
- package/dist/drain-teardown.d.ts +66 -0
- package/dist/drain-teardown.d.ts.map +1 -0
- package/dist/drain-teardown.js +56 -0
- package/dist/drain-teardown.js.map +1 -0
- package/dist/focus-executor.d.ts.map +1 -1
- package/dist/focus-executor.js +20 -0
- package/dist/focus-executor.js.map +1 -1
- package/dist/index.js +120 -12
- package/dist/index.js.map +1 -1
- package/dist/stop-request.d.ts +54 -0
- package/dist/stop-request.d.ts.map +1 -0
- package/dist/stop-request.js +89 -0
- package/dist/stop-request.js.map +1 -0
- package/dist/templates/agents-md.d.ts +8 -0
- package/dist/templates/agents-md.d.ts.map +1 -1
- package/dist/templates/agents-md.js +4 -3
- package/dist/templates/agents-md.js.map +1 -1
- package/dist/unified-engine-lifecycle.d.ts +68 -10
- package/dist/unified-engine-lifecycle.d.ts.map +1 -1
- package/dist/unified-engine-lifecycle.js +177 -71
- package/dist/unified-engine-lifecycle.js.map +1 -1
- package/dist/unified-shell.d.ts.map +1 -1
- package/dist/unified-shell.js +73 -8
- package/dist/unified-shell.js.map +1 -1
- package/dist/worker-pidfile.d.ts +77 -0
- package/dist/worker-pidfile.d.ts.map +1 -0
- package/dist/worker-pidfile.js +161 -0
- package/dist/worker-pidfile.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `telora-daemon harness add <target>` subcommand.
|
|
3
|
+
*
|
|
4
|
+
* A token-free, idempotent way to install or repair any operator harness on an
|
|
5
|
+
* ALREADY-connected workstation. Unlike `connect`, it never redeems a token,
|
|
6
|
+
* never rewrites `~/.telora/daemon.json`, and never starts the daemon -- it
|
|
7
|
+
* reads the identity `connect` already persisted (`readConnectedIdentity`) and
|
|
8
|
+
* writes exactly the same harness scaffolding (`writeHarnessScaffolding`), so
|
|
9
|
+
* `harness add <h>` and `connect --harness <h>` produce byte-identical files
|
|
10
|
+
* for a given identity.
|
|
11
|
+
*
|
|
12
|
+
* On a repo the workstation is not connected to, it refuses with an actionable
|
|
13
|
+
* message directing the operator to `connect` first.
|
|
14
|
+
*/
|
|
15
|
+
import { type ConnectIO, type OperatorHarness } from './connect.js';
|
|
16
|
+
export interface HarnessAddOptions {
|
|
17
|
+
/** The harness target to install or repair. */
|
|
18
|
+
target: OperatorHarness;
|
|
19
|
+
/** Repo path to scaffold (default: cwd). */
|
|
20
|
+
repoPath?: string;
|
|
21
|
+
/** Override IO (used by tests). */
|
|
22
|
+
io?: Partial<ConnectIO>;
|
|
23
|
+
}
|
|
24
|
+
export interface HarnessAddResult {
|
|
25
|
+
ok: boolean;
|
|
26
|
+
/** Human-facing message (success detail, or the not-connected remediation). */
|
|
27
|
+
message: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Install or repair the `target` harness scaffolding for a connected repo.
|
|
31
|
+
*
|
|
32
|
+
* Idempotent: the underlying writers skip the write when content is unchanged,
|
|
33
|
+
* so a second run leaves identical files and returns ok. Returns `ok: false`
|
|
34
|
+
* (no files touched) when the repo is not connected.
|
|
35
|
+
*/
|
|
36
|
+
export declare function runHarnessAdd(opts: HarnessAddOptions): HarnessAddResult;
|
|
37
|
+
//# sourceMappingURL=harness-add.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness-add.d.ts","sourceRoot":"","sources":["../../src/cli/harness-add.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,EAML,KAAK,SAAS,EACd,KAAK,eAAe,EACrB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,iBAAiB;IAChC,+CAA+C;IAC/C,MAAM,EAAE,eAAe,CAAC;IACxB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,EAAE,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,OAAO,CAAC;IACZ,+EAA+E;IAC/E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,gBAAgB,CA4BvE"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `telora-daemon harness add <target>` subcommand.
|
|
3
|
+
*
|
|
4
|
+
* A token-free, idempotent way to install or repair any operator harness on an
|
|
5
|
+
* ALREADY-connected workstation. Unlike `connect`, it never redeems a token,
|
|
6
|
+
* never rewrites `~/.telora/daemon.json`, and never starts the daemon -- it
|
|
7
|
+
* reads the identity `connect` already persisted (`readConnectedIdentity`) and
|
|
8
|
+
* writes exactly the same harness scaffolding (`writeHarnessScaffolding`), so
|
|
9
|
+
* `harness add <h>` and `connect --harness <h>` produce byte-identical files
|
|
10
|
+
* for a given identity.
|
|
11
|
+
*
|
|
12
|
+
* On a repo the workstation is not connected to, it refuses with an actionable
|
|
13
|
+
* message directing the operator to `connect` first.
|
|
14
|
+
*/
|
|
15
|
+
import { resolve } from 'node:path';
|
|
16
|
+
import { defaultIO, ensureGitignoreEntries, harnessGitignoreEntries, readConnectedIdentity, writeHarnessScaffolding, } from './connect.js';
|
|
17
|
+
/**
|
|
18
|
+
* Install or repair the `target` harness scaffolding for a connected repo.
|
|
19
|
+
*
|
|
20
|
+
* Idempotent: the underlying writers skip the write when content is unchanged,
|
|
21
|
+
* so a second run leaves identical files and returns ok. Returns `ok: false`
|
|
22
|
+
* (no files touched) when the repo is not connected.
|
|
23
|
+
*/
|
|
24
|
+
export function runHarnessAdd(opts) {
|
|
25
|
+
const io = defaultIO(opts.io);
|
|
26
|
+
const repoPath = resolve(opts.repoPath ?? process.cwd());
|
|
27
|
+
const identity = readConnectedIdentity(repoPath);
|
|
28
|
+
if (!identity) {
|
|
29
|
+
return {
|
|
30
|
+
ok: false,
|
|
31
|
+
message: `This workstation is not connected to Telora for ${repoPath}. ` +
|
|
32
|
+
`Run \`telora-daemon connect <token> --harness ${opts.target}\` to connect first.`,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const inv = {
|
|
36
|
+
productName: null,
|
|
37
|
+
teloraUrl: identity.teloraUrl,
|
|
38
|
+
organizationId: identity.organizationId,
|
|
39
|
+
productId: identity.productId,
|
|
40
|
+
};
|
|
41
|
+
ensureGitignoreEntries(repoPath, io, harnessGitignoreEntries(opts.target));
|
|
42
|
+
writeHarnessScaffolding(repoPath, opts.target, inv, io);
|
|
43
|
+
return {
|
|
44
|
+
ok: true,
|
|
45
|
+
message: `Installed ${opts.target} harness scaffolding for product ${identity.productId}.`,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=harness-add.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness-add.js","sourceRoot":"","sources":["../../src/cli/harness-add.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EACL,SAAS,EACT,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,EACrB,uBAAuB,GAGxB,MAAM,cAAc,CAAC;AAiBtB;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,IAAuB;IACnD,MAAM,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9B,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAEzD,MAAM,QAAQ,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACjD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EACL,mDAAmD,QAAQ,IAAI;gBAC/D,iDAAiD,IAAI,CAAC,MAAM,sBAAsB;SACrF,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAgC;QACvC,WAAW,EAAE,IAAI;QACjB,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,cAAc,EAAE,QAAQ,CAAC,cAAc;QACvC,SAAS,EAAE,QAAQ,CAAC,SAAS;KAC9B,CAAC;IAEF,sBAAsB,CAAC,QAAQ,EAAE,EAAE,EAAE,uBAAuB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3E,uBAAuB,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IAExD,OAAO;QACL,EAAE,EAAE,IAAI;QACR,OAAO,EAAE,aAAa,IAAI,CAAC,MAAM,oCAAoC,QAAQ,CAAC,SAAS,GAAG;KAC3F,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `telora-daemon open <focus>` subcommand.
|
|
3
|
+
*
|
|
4
|
+
* Resolves a focus (by UUID or by focus key like "f3") to its git branch,
|
|
5
|
+
* reuses or creates an OPERATOR-OWNED worktree on that branch, and launches the
|
|
6
|
+
* operator's editor there -- for a focus that is still in flight OR already
|
|
7
|
+
* merged/completed.
|
|
8
|
+
*
|
|
9
|
+
* Two invariants shape the design:
|
|
10
|
+
*
|
|
11
|
+
* 1. The operator worktree is NEVER the team's live worktree. Team worktrees
|
|
12
|
+
* live at `join(worktreeDir, branch.replace(/\//g,'-'))`; operator worktrees
|
|
13
|
+
* live under a distinct `operator-` prefixed namespace
|
|
14
|
+
* (`join(worktreeDir, 'operator-' + branch.replace(/\//g,'-'))`). The
|
|
15
|
+
* prefix keeps them provably a different path AND out of reach of the
|
|
16
|
+
* team-lifecycle sweeps: `cleanupOrphanFocusWorktrees` only reaps dirs whose
|
|
17
|
+
* name starts with `agent-`, so an `operator-agent-...` dir is never reaped.
|
|
18
|
+
*
|
|
19
|
+
* 2. A focus resolves to its branch even after merge. The `focus_worktrees`
|
|
20
|
+
* ROW survives a merge (only the worktree DIRECTORY is removed), so the row
|
|
21
|
+
* is the primary branch source. When no row exists we fall back to deriving
|
|
22
|
+
* the branch name and verifying it exists in git; a focus with neither is
|
|
23
|
+
* the actionable no-branch error path.
|
|
24
|
+
*
|
|
25
|
+
* All side-effecting pieces (record lookup, git ops, editor launch, IO) are
|
|
26
|
+
* injected so `runOpen` is testable without a network, a real git remote, or a
|
|
27
|
+
* real editor. `runOpenCommand` wires the real defaults for the CLI.
|
|
28
|
+
*/
|
|
29
|
+
/** Default editor command. `cursor` since this verb is the IDE bridge. */
|
|
30
|
+
export declare const DEFAULT_EDITOR = "cursor";
|
|
31
|
+
/** True when `ref` is a focus UUID (vs. an ephemeral focus key like "f3"). */
|
|
32
|
+
export declare function looksLikeUuid(ref: string): boolean;
|
|
33
|
+
/** True when `ref` is an ephemeral focus key like "f3". */
|
|
34
|
+
export declare function looksLikeFocusKey(ref: string): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Derive a focus branch name. Mirrors `generateFocusBranchName` in
|
|
37
|
+
* focus-executor.ts (`agent/<role>/<focus>-<shortId>`), reusing the same
|
|
38
|
+
* canonical `sanitizeGitSegment`. Used only as the fallback when a focus has no
|
|
39
|
+
* `focus_worktrees` row; the derived branch is git-verified before use.
|
|
40
|
+
*/
|
|
41
|
+
export declare function deriveFocusBranchName(roleName: string, focusName: string, focusId: string): string;
|
|
42
|
+
/**
|
|
43
|
+
* The team's worktree path for a branch. Mirrors `createWorktree` in
|
|
44
|
+
* worktree.ts. This is the LIVE worktree an executing team owns -- `open`
|
|
45
|
+
* never creates, removes, or writes to it.
|
|
46
|
+
*/
|
|
47
|
+
export declare function teamWorktreePath(worktreeDir: string, branchName: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* The OPERATOR worktree path for a branch: a distinct namespace under the same
|
|
50
|
+
* worktree dir, prefixed `operator-`. Distinct from `teamWorktreePath` by
|
|
51
|
+
* construction, and invisible to `cleanupOrphanFocusWorktrees` (which only
|
|
52
|
+
* reaps `agent-*` dirs).
|
|
53
|
+
*/
|
|
54
|
+
export declare function operatorWorktreePath(worktreeDir: string, branchName: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* Resolve the editor command with precedence: explicit `--editor` > `TELORA_EDITOR`
|
|
57
|
+
* env > `DEFAULT_EDITOR`.
|
|
58
|
+
*/
|
|
59
|
+
export declare function resolveEditor(optEditor?: string, env?: NodeJS.ProcessEnv): string;
|
|
60
|
+
/** The subset of a `focus_worktrees` row the resolver needs. */
|
|
61
|
+
export interface WorktreeLite {
|
|
62
|
+
focusId: string;
|
|
63
|
+
branchName: string;
|
|
64
|
+
worktreePath: string;
|
|
65
|
+
productId?: string | null;
|
|
66
|
+
}
|
|
67
|
+
/** The subset of a `focus_list` entry the resolver needs. */
|
|
68
|
+
export interface FocusLite {
|
|
69
|
+
id: string;
|
|
70
|
+
focusKey?: string | null;
|
|
71
|
+
name?: string | null;
|
|
72
|
+
assignedAgentRoleName?: string | null;
|
|
73
|
+
productId?: string | null;
|
|
74
|
+
}
|
|
75
|
+
/** Record-level resolution of a focus ref to a branch (no product paths yet). */
|
|
76
|
+
export interface FocusRecordResolution {
|
|
77
|
+
focusId: string;
|
|
78
|
+
focusName: string;
|
|
79
|
+
branchName: string;
|
|
80
|
+
productId: string | null;
|
|
81
|
+
/** True when the branch came from a focus_worktrees row; false when derived. */
|
|
82
|
+
fromWorktreeRow: boolean;
|
|
83
|
+
}
|
|
84
|
+
/** Full resolution including the product's repo + worktree directory. */
|
|
85
|
+
export interface FocusResolution extends FocusRecordResolution {
|
|
86
|
+
repoPath: string;
|
|
87
|
+
worktreeDir: string;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Pure resolution of a focus ref (UUID or focus key) to its branch, from
|
|
91
|
+
* already-fetched worktree rows + focus list. No I/O -- hermetic to test.
|
|
92
|
+
*
|
|
93
|
+
* Returns null when the ref is neither a UUID nor a key, when a key does not
|
|
94
|
+
* match any focus, or when there is no branch to open (no row and no derivable
|
|
95
|
+
* branch).
|
|
96
|
+
*/
|
|
97
|
+
export declare function resolveFocusWorktreeFromData(params: {
|
|
98
|
+
focusRef: string;
|
|
99
|
+
worktrees: WorktreeLite[];
|
|
100
|
+
focuses: FocusLite[];
|
|
101
|
+
}): FocusRecordResolution | null;
|
|
102
|
+
/** Git/worktree operations, injectable for tests. */
|
|
103
|
+
export interface OpenGitOps {
|
|
104
|
+
/** Whether a path exists on disk. */
|
|
105
|
+
pathExists: (path: string) => boolean;
|
|
106
|
+
/** Whether a local git branch exists in the repo. */
|
|
107
|
+
branchExists: (branchName: string, repoPath: string) => boolean;
|
|
108
|
+
/** `git worktree add <worktreePath> <branch>`. Throws on failure. */
|
|
109
|
+
addWorktree: (repoPath: string, worktreePath: string, branchName: string) => void;
|
|
110
|
+
}
|
|
111
|
+
/** Launch an editor at a path. Injectable for tests. */
|
|
112
|
+
export type LaunchEditor = (editorCmd: string, worktreePath: string) => void;
|
|
113
|
+
/** Message sink, injectable for tests. */
|
|
114
|
+
export interface OpenIO {
|
|
115
|
+
out: (msg: string) => void;
|
|
116
|
+
err: (msg: string) => void;
|
|
117
|
+
}
|
|
118
|
+
export interface RunOpenParams {
|
|
119
|
+
focusRef: string;
|
|
120
|
+
/** The resolved editor command (see resolveEditor). */
|
|
121
|
+
editor: string;
|
|
122
|
+
/** Injected focus-ref -> resolution lookup (network in real wiring). */
|
|
123
|
+
resolveWorktreeRecord: (focusRef: string) => Promise<FocusResolution | null>;
|
|
124
|
+
git: OpenGitOps;
|
|
125
|
+
launchEditor: LaunchEditor;
|
|
126
|
+
io: OpenIO;
|
|
127
|
+
}
|
|
128
|
+
export type OpenFailure = 'no_branch' | 'worktree_create_failed';
|
|
129
|
+
export interface RunOpenResult {
|
|
130
|
+
ok: boolean;
|
|
131
|
+
editor: string;
|
|
132
|
+
message: string;
|
|
133
|
+
failure?: OpenFailure;
|
|
134
|
+
focusName?: string;
|
|
135
|
+
branchName?: string;
|
|
136
|
+
operatorWorktreePath?: string;
|
|
137
|
+
teamWorktreePath?: string;
|
|
138
|
+
/** True when an existing operator worktree was reused (not created). */
|
|
139
|
+
reused?: boolean;
|
|
140
|
+
/** True when a new operator worktree was created. */
|
|
141
|
+
createdWorktree?: boolean;
|
|
142
|
+
/** True when the team's worktree still exists on disk (focus in flight). */
|
|
143
|
+
inFlight?: boolean;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Resolve a focus to an operator worktree and launch the editor there.
|
|
147
|
+
*
|
|
148
|
+
* Returns a result object; the CLI wrapper maps `ok === false` to a non-zero
|
|
149
|
+
* exit. Never touches the team's live worktree.
|
|
150
|
+
*/
|
|
151
|
+
export declare function runOpen(params: RunOpenParams): Promise<RunOpenResult>;
|
|
152
|
+
/** Default git ops backed by the real filesystem + git. */
|
|
153
|
+
export declare const defaultGitOps: OpenGitOps;
|
|
154
|
+
/** Default editor launcher: detached spawn so the CLI can return immediately. */
|
|
155
|
+
export declare function defaultLaunchEditor(editorCmd: string, worktreePath: string): void;
|
|
156
|
+
export interface RunOpenCommandOptions {
|
|
157
|
+
focusRef: string;
|
|
158
|
+
/** Explicit editor override (from --editor). */
|
|
159
|
+
editor?: string;
|
|
160
|
+
/** Path to daemon.json (from --config). */
|
|
161
|
+
config?: string;
|
|
162
|
+
/** IO override (tests). */
|
|
163
|
+
io?: Partial<OpenIO>;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* CLI entry: load config, wire the real defaults, run, print, and return an
|
|
167
|
+
* exit code (0 success, 1 failure). The `index.ts` action wrapper calls
|
|
168
|
+
* `process.exit` with the returned code.
|
|
169
|
+
*/
|
|
170
|
+
export declare function runOpenCommand(opts: RunOpenCommandOptions): Promise<number>;
|
|
171
|
+
//# sourceMappingURL=open.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open.d.ts","sourceRoot":"","sources":["../../src/cli/open.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAYH,0EAA0E;AAC1E,eAAO,MAAM,cAAc,WAAW,CAAC;AAMvC,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,2DAA2D;AAC3D,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,MAAM,CAER;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEhF;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEpF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,SAAS,CAAC,EAAE,MAAM,EAClB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAKR;AAID,gEAAgE;AAChE,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,6DAA6D;AAC7D,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,iFAAiF;AACjF,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,gFAAgF;IAChF,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,yEAAyE;AACzE,MAAM,WAAW,eAAgB,SAAQ,qBAAqB;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB,GAAG,qBAAqB,GAAG,IAAI,CA8C/B;AAID,qDAAqD;AACrD,MAAM,WAAW,UAAU;IACzB,qCAAqC;IACrC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACtC,qDAAqD;IACrD,YAAY,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAChE,qEAAqE;IACrE,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;CACnF;AAED,wDAAwD;AACxD,MAAM,MAAM,YAAY,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;AAE7E,0CAA0C;AAC1C,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,qBAAqB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IAC7E,GAAG,EAAE,UAAU,CAAC;IAChB,YAAY,EAAE,YAAY,CAAC;IAC3B,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,wBAAwB,CAAC;AAEjE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wEAAwE;IACxE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,qDAAqD;IACrD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CA4F3E;AAID,2DAA2D;AAC3D,eAAO,MAAM,aAAa,EAAE,UAe3B,CAAC;AAEF,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAYjF;AAuDD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,EAAE,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAwBjF"}
|
package/dist/cli/open.js
ADDED
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `telora-daemon open <focus>` subcommand.
|
|
3
|
+
*
|
|
4
|
+
* Resolves a focus (by UUID or by focus key like "f3") to its git branch,
|
|
5
|
+
* reuses or creates an OPERATOR-OWNED worktree on that branch, and launches the
|
|
6
|
+
* operator's editor there -- for a focus that is still in flight OR already
|
|
7
|
+
* merged/completed.
|
|
8
|
+
*
|
|
9
|
+
* Two invariants shape the design:
|
|
10
|
+
*
|
|
11
|
+
* 1. The operator worktree is NEVER the team's live worktree. Team worktrees
|
|
12
|
+
* live at `join(worktreeDir, branch.replace(/\//g,'-'))`; operator worktrees
|
|
13
|
+
* live under a distinct `operator-` prefixed namespace
|
|
14
|
+
* (`join(worktreeDir, 'operator-' + branch.replace(/\//g,'-'))`). The
|
|
15
|
+
* prefix keeps them provably a different path AND out of reach of the
|
|
16
|
+
* team-lifecycle sweeps: `cleanupOrphanFocusWorktrees` only reaps dirs whose
|
|
17
|
+
* name starts with `agent-`, so an `operator-agent-...` dir is never reaped.
|
|
18
|
+
*
|
|
19
|
+
* 2. A focus resolves to its branch even after merge. The `focus_worktrees`
|
|
20
|
+
* ROW survives a merge (only the worktree DIRECTORY is removed), so the row
|
|
21
|
+
* is the primary branch source. When no row exists we fall back to deriving
|
|
22
|
+
* the branch name and verifying it exists in git; a focus with neither is
|
|
23
|
+
* the actionable no-branch error path.
|
|
24
|
+
*
|
|
25
|
+
* All side-effecting pieces (record lookup, git ops, editor launch, IO) are
|
|
26
|
+
* injected so `runOpen` is testable without a network, a real git remote, or a
|
|
27
|
+
* real editor. `runOpenCommand` wires the real defaults for the CLI.
|
|
28
|
+
*/
|
|
29
|
+
import { existsSync } from 'node:fs';
|
|
30
|
+
import { join } from 'node:path';
|
|
31
|
+
import { spawn } from 'node:child_process';
|
|
32
|
+
import { loadConfig, configForProduct, findProduct } from '../config.js';
|
|
33
|
+
import { sanitizeGitSegment } from '../git-utils.js';
|
|
34
|
+
import { runGitSync } from '../git-types.js';
|
|
35
|
+
import { listWorktreeRecords } from '../queries/worktrees.js';
|
|
36
|
+
import { callApi, initSupabase } from '../queries/shared.js';
|
|
37
|
+
/** Default editor command. `cursor` since this verb is the IDE bridge. */
|
|
38
|
+
export const DEFAULT_EDITOR = 'cursor';
|
|
39
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
40
|
+
const FOCUS_KEY_RE = /^f\d+$/;
|
|
41
|
+
/** True when `ref` is a focus UUID (vs. an ephemeral focus key like "f3"). */
|
|
42
|
+
export function looksLikeUuid(ref) {
|
|
43
|
+
return UUID_RE.test(ref);
|
|
44
|
+
}
|
|
45
|
+
/** True when `ref` is an ephemeral focus key like "f3". */
|
|
46
|
+
export function looksLikeFocusKey(ref) {
|
|
47
|
+
return FOCUS_KEY_RE.test(ref);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Derive a focus branch name. Mirrors `generateFocusBranchName` in
|
|
51
|
+
* focus-executor.ts (`agent/<role>/<focus>-<shortId>`), reusing the same
|
|
52
|
+
* canonical `sanitizeGitSegment`. Used only as the fallback when a focus has no
|
|
53
|
+
* `focus_worktrees` row; the derived branch is git-verified before use.
|
|
54
|
+
*/
|
|
55
|
+
export function deriveFocusBranchName(roleName, focusName, focusId) {
|
|
56
|
+
return `agent/${sanitizeGitSegment(roleName)}/${sanitizeGitSegment(focusName)}-${focusId.slice(0, 8)}`;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The team's worktree path for a branch. Mirrors `createWorktree` in
|
|
60
|
+
* worktree.ts. This is the LIVE worktree an executing team owns -- `open`
|
|
61
|
+
* never creates, removes, or writes to it.
|
|
62
|
+
*/
|
|
63
|
+
export function teamWorktreePath(worktreeDir, branchName) {
|
|
64
|
+
return join(worktreeDir, branchName.replace(/\//g, '-'));
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The OPERATOR worktree path for a branch: a distinct namespace under the same
|
|
68
|
+
* worktree dir, prefixed `operator-`. Distinct from `teamWorktreePath` by
|
|
69
|
+
* construction, and invisible to `cleanupOrphanFocusWorktrees` (which only
|
|
70
|
+
* reaps `agent-*` dirs).
|
|
71
|
+
*/
|
|
72
|
+
export function operatorWorktreePath(worktreeDir, branchName) {
|
|
73
|
+
return join(worktreeDir, `operator-${branchName.replace(/\//g, '-')}`);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Resolve the editor command with precedence: explicit `--editor` > `TELORA_EDITOR`
|
|
77
|
+
* env > `DEFAULT_EDITOR`.
|
|
78
|
+
*/
|
|
79
|
+
export function resolveEditor(optEditor, env = process.env) {
|
|
80
|
+
if (optEditor && optEditor.trim())
|
|
81
|
+
return optEditor.trim();
|
|
82
|
+
const fromEnv = env.TELORA_EDITOR;
|
|
83
|
+
if (fromEnv && fromEnv.trim())
|
|
84
|
+
return fromEnv.trim();
|
|
85
|
+
return DEFAULT_EDITOR;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Pure resolution of a focus ref (UUID or focus key) to its branch, from
|
|
89
|
+
* already-fetched worktree rows + focus list. No I/O -- hermetic to test.
|
|
90
|
+
*
|
|
91
|
+
* Returns null when the ref is neither a UUID nor a key, when a key does not
|
|
92
|
+
* match any focus, or when there is no branch to open (no row and no derivable
|
|
93
|
+
* branch).
|
|
94
|
+
*/
|
|
95
|
+
export function resolveFocusWorktreeFromData(params) {
|
|
96
|
+
const { focusRef, worktrees, focuses } = params;
|
|
97
|
+
// 1. Resolve the ref to a focus id (+ carry the focus row for name/role).
|
|
98
|
+
let focusId = null;
|
|
99
|
+
let focus;
|
|
100
|
+
if (looksLikeUuid(focusRef)) {
|
|
101
|
+
focusId = focusRef;
|
|
102
|
+
focus = focuses.find((f) => f.id === focusRef);
|
|
103
|
+
}
|
|
104
|
+
else if (looksLikeFocusKey(focusRef)) {
|
|
105
|
+
focus = focuses.find((f) => f.focusKey === focusRef);
|
|
106
|
+
focusId = focus?.id ?? null;
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
return null; // Neither a UUID nor a focus key.
|
|
110
|
+
}
|
|
111
|
+
if (!focusId)
|
|
112
|
+
return null; // Key matched no focus.
|
|
113
|
+
const focusName = focus?.name ?? focusId;
|
|
114
|
+
// 2. Prefer the focus_worktrees row -- it survives a merge, so this is the
|
|
115
|
+
// branch source for BOTH in-flight and already-merged focuses.
|
|
116
|
+
const row = worktrees.find((w) => w.focusId === focusId);
|
|
117
|
+
if (row) {
|
|
118
|
+
return {
|
|
119
|
+
focusId,
|
|
120
|
+
focusName,
|
|
121
|
+
branchName: row.branchName,
|
|
122
|
+
productId: row.productId ?? focus?.productId ?? null,
|
|
123
|
+
fromWorktreeRow: true,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
// 3. Fallback: derive the branch when we know the focus name + assigned role.
|
|
127
|
+
// runOpen verifies the branch exists in git before using it, so a derived
|
|
128
|
+
// branch git does not have degrades to the no-branch error path.
|
|
129
|
+
if (focus?.name && focus.assignedAgentRoleName) {
|
|
130
|
+
return {
|
|
131
|
+
focusId,
|
|
132
|
+
focusName,
|
|
133
|
+
branchName: deriveFocusBranchName(focus.assignedAgentRoleName, focus.name, focusId),
|
|
134
|
+
productId: focus.productId ?? null,
|
|
135
|
+
fromWorktreeRow: false,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
return null; // No row, no derivable branch.
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Resolve a focus to an operator worktree and launch the editor there.
|
|
142
|
+
*
|
|
143
|
+
* Returns a result object; the CLI wrapper maps `ok === false` to a non-zero
|
|
144
|
+
* exit. Never touches the team's live worktree.
|
|
145
|
+
*/
|
|
146
|
+
export async function runOpen(params) {
|
|
147
|
+
const { focusRef, editor, resolveWorktreeRecord, git, launchEditor, io } = params;
|
|
148
|
+
const resolution = await resolveWorktreeRecord(focusRef);
|
|
149
|
+
if (!resolution) {
|
|
150
|
+
return {
|
|
151
|
+
ok: false,
|
|
152
|
+
editor,
|
|
153
|
+
failure: 'no_branch',
|
|
154
|
+
message: `Focus "${focusRef}" has no branch to open: no focus_worktrees row and no ` +
|
|
155
|
+
`derivable branch. It has never been provisioned by the daemon (no delivery ` +
|
|
156
|
+
`has entered coding yet). Nothing to open.`,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
const { branchName, focusName, repoPath, worktreeDir } = resolution;
|
|
160
|
+
const teamPath = teamWorktreePath(worktreeDir, branchName);
|
|
161
|
+
const operatorPath = operatorWorktreePath(worktreeDir, branchName);
|
|
162
|
+
// Reuse an existing operator worktree on this branch -- do not recreate.
|
|
163
|
+
if (git.pathExists(operatorPath)) {
|
|
164
|
+
io.out(`Reusing operator worktree for "${focusName}" at ${operatorPath} (branch ${branchName}).\n`);
|
|
165
|
+
launchEditor(editor, operatorPath);
|
|
166
|
+
return {
|
|
167
|
+
ok: true,
|
|
168
|
+
editor,
|
|
169
|
+
message: `Opened ${operatorPath} in ${editor}.`,
|
|
170
|
+
focusName,
|
|
171
|
+
branchName,
|
|
172
|
+
operatorWorktreePath: operatorPath,
|
|
173
|
+
teamWorktreePath: teamPath,
|
|
174
|
+
reused: true,
|
|
175
|
+
createdWorktree: false,
|
|
176
|
+
inFlight: git.pathExists(teamPath),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
// The branch must exist to base a worktree on it. A merged focus whose branch
|
|
180
|
+
// was deleted, or a never-provisioned focus, lands here.
|
|
181
|
+
if (!git.branchExists(branchName, repoPath)) {
|
|
182
|
+
return {
|
|
183
|
+
ok: false,
|
|
184
|
+
editor,
|
|
185
|
+
failure: 'no_branch',
|
|
186
|
+
focusName,
|
|
187
|
+
branchName,
|
|
188
|
+
message: `Focus "${focusName}" resolves to branch ${branchName}, but that branch does ` +
|
|
189
|
+
`not exist in ${repoPath} (it may have been deleted after merge). Nothing to open.`,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
// Create an OPERATOR-owned worktree on the focus branch. This is a distinct
|
|
193
|
+
// path from the team's worktree (${teamPath}) and never touches it.
|
|
194
|
+
try {
|
|
195
|
+
git.addWorktree(repoPath, operatorPath, branchName);
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
return {
|
|
199
|
+
ok: false,
|
|
200
|
+
editor,
|
|
201
|
+
failure: 'worktree_create_failed',
|
|
202
|
+
focusName,
|
|
203
|
+
branchName,
|
|
204
|
+
message: `Failed to create operator worktree at ${operatorPath}: ` +
|
|
205
|
+
`${err instanceof Error ? err.message : String(err)}`,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const inFlight = git.pathExists(teamPath);
|
|
209
|
+
io.out(inFlight
|
|
210
|
+
? `Focus "${focusName}" is in flight; opened a separate operator worktree at ` +
|
|
211
|
+
`${operatorPath} (branch ${branchName}). The team's worktree at ${teamPath} is untouched.\n`
|
|
212
|
+
: `Focus "${focusName}" branch ${branchName} checked out at operator worktree ${operatorPath}.\n`);
|
|
213
|
+
launchEditor(editor, operatorPath);
|
|
214
|
+
return {
|
|
215
|
+
ok: true,
|
|
216
|
+
editor,
|
|
217
|
+
message: `Opened ${operatorPath} in ${editor}.`,
|
|
218
|
+
focusName,
|
|
219
|
+
branchName,
|
|
220
|
+
operatorWorktreePath: operatorPath,
|
|
221
|
+
teamWorktreePath: teamPath,
|
|
222
|
+
reused: false,
|
|
223
|
+
createdWorktree: true,
|
|
224
|
+
inFlight,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
// ── Real CLI wiring ────────────────────────────────────────────────────────
|
|
228
|
+
/** Default git ops backed by the real filesystem + git. */
|
|
229
|
+
export const defaultGitOps = {
|
|
230
|
+
pathExists: (path) => existsSync(path),
|
|
231
|
+
branchExists: (branchName, repoPath) => {
|
|
232
|
+
const res = runGitSync(['rev-parse', '--verify', '--quiet', `refs/heads/${branchName}`], repoPath);
|
|
233
|
+
return res.success && res.output.trim().length > 0;
|
|
234
|
+
},
|
|
235
|
+
addWorktree: (repoPath, worktreePath, branchName) => {
|
|
236
|
+
const res = runGitSync(['worktree', 'add', worktreePath, branchName], repoPath);
|
|
237
|
+
if (!res.success) {
|
|
238
|
+
throw new Error(res.error || 'git worktree add failed');
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
/** Default editor launcher: detached spawn so the CLI can return immediately. */
|
|
243
|
+
export function defaultLaunchEditor(editorCmd, worktreePath) {
|
|
244
|
+
const child = spawn(editorCmd, [worktreePath], {
|
|
245
|
+
detached: true,
|
|
246
|
+
stdio: 'ignore',
|
|
247
|
+
});
|
|
248
|
+
child.on('error', (err) => {
|
|
249
|
+
process.stderr.write(`Could not launch editor "${editorCmd}": ${err.message}. ` +
|
|
250
|
+
`Open ${worktreePath} manually, or pass --editor / set TELORA_EDITOR.\n`);
|
|
251
|
+
});
|
|
252
|
+
child.unref();
|
|
253
|
+
}
|
|
254
|
+
/** Fetch focus id/key/name/role across all configured products (best-effort). */
|
|
255
|
+
async function fetchFocusLiteAcrossProducts(config) {
|
|
256
|
+
const out = [];
|
|
257
|
+
for (const product of config.products) {
|
|
258
|
+
try {
|
|
259
|
+
const res = await callApi('focus_list', { productId: product.id, limit: 500 });
|
|
260
|
+
for (const f of res.focuses ?? []) {
|
|
261
|
+
out.push({
|
|
262
|
+
id: f.id,
|
|
263
|
+
focusKey: f.focusKey ?? null,
|
|
264
|
+
name: f.name ?? null,
|
|
265
|
+
assignedAgentRoleName: f.assignedAgentRoleName ?? null,
|
|
266
|
+
productId: product.id,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
// Best-effort per product: a failure resolving one product's focuses must
|
|
272
|
+
// not block opening a focus in another.
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return out;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Real resolver wiring: hits the Telora API for worktree rows + focuses, runs
|
|
279
|
+
* the pure resolver, then attaches the resolved product's repo + worktree dir.
|
|
280
|
+
*/
|
|
281
|
+
async function resolveFocusWorktreeReal(focusRef, config) {
|
|
282
|
+
initSupabase(config);
|
|
283
|
+
const worktrees = await listWorktreeRecords();
|
|
284
|
+
const focuses = await fetchFocusLiteAcrossProducts(config);
|
|
285
|
+
const base = resolveFocusWorktreeFromData({ focusRef, worktrees, focuses });
|
|
286
|
+
if (!base)
|
|
287
|
+
return null;
|
|
288
|
+
const product = base.productId ? findProduct(config, base.productId) : undefined;
|
|
289
|
+
const scoped = product ? configForProduct(config, product) : config;
|
|
290
|
+
return {
|
|
291
|
+
...base,
|
|
292
|
+
repoPath: scoped.repoPath,
|
|
293
|
+
worktreeDir: scoped.worktreeDir,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* CLI entry: load config, wire the real defaults, run, print, and return an
|
|
298
|
+
* exit code (0 success, 1 failure). The `index.ts` action wrapper calls
|
|
299
|
+
* `process.exit` with the returned code.
|
|
300
|
+
*/
|
|
301
|
+
export async function runOpenCommand(opts) {
|
|
302
|
+
const io = {
|
|
303
|
+
out: opts.io?.out ?? ((m) => process.stdout.write(m)),
|
|
304
|
+
err: opts.io?.err ?? ((m) => process.stderr.write(m)),
|
|
305
|
+
};
|
|
306
|
+
const config = loadConfig(opts.config);
|
|
307
|
+
const editor = resolveEditor(opts.editor);
|
|
308
|
+
const result = await runOpen({
|
|
309
|
+
focusRef: opts.focusRef,
|
|
310
|
+
editor,
|
|
311
|
+
resolveWorktreeRecord: (ref) => resolveFocusWorktreeReal(ref, config),
|
|
312
|
+
git: defaultGitOps,
|
|
313
|
+
launchEditor: defaultLaunchEditor,
|
|
314
|
+
io,
|
|
315
|
+
});
|
|
316
|
+
if (!result.ok) {
|
|
317
|
+
io.err(result.message.endsWith('\n') ? result.message : `${result.message}\n`);
|
|
318
|
+
return 1;
|
|
319
|
+
}
|
|
320
|
+
io.out(result.message.endsWith('\n') ? result.message : `${result.message}\n`);
|
|
321
|
+
return 0;
|
|
322
|
+
}
|
|
323
|
+
//# sourceMappingURL=open.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open.js","sourceRoot":"","sources":["../../src/cli/open.ts"],"names":[],"mappings":"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"}
|