mintree 0.5.3 → 0.5.5
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/dist/commands/dashboard.js +3 -1
- package/dist/commands/orchestrate.d.ts +1 -0
- package/dist/commands/orchestrate.js +20 -7
- package/dist/lib/markers.d.ts +1 -0
- package/dist/lib/markers.js +3 -0
- package/dist/lib/orchestrate.d.ts +13 -0
- package/dist/lib/orchestrate.js +17 -0
- package/dist/lib/providers/linear.js +9 -5
- package/package.json +1 -1
- package/shell/init.bash +3 -0
- package/shell/init.zsh +3 -0
|
@@ -14,6 +14,7 @@ import { runCreate, runCreateDetached, } from "../lib/worktreeCreate.js";
|
|
|
14
14
|
import { runRemove, runRemoveByPath } from "../lib/worktreeRemove.js";
|
|
15
15
|
import { writePromptFile } from "../lib/worktreeCreate.js";
|
|
16
16
|
import { buildCreateMarkers, buildOrchestrateMarkers, emitMarkers } from "../lib/markers.js";
|
|
17
|
+
import { buildOrchestratorRcName } from "../lib/orchestrate.js";
|
|
17
18
|
import { readMetadata } from "../lib/metadata.js";
|
|
18
19
|
import { defaultOrchestratorPrompt, renderOrchestratorTemplate, renderPromptTemplate, } from "../lib/promptTemplate.js";
|
|
19
20
|
import { createProvider } from "../lib/providers/index.js";
|
|
@@ -1101,7 +1102,8 @@ export default function Dashboard() {
|
|
|
1101
1102
|
: defaultOrchestratorPrompt(idList);
|
|
1102
1103
|
const promptFile = writePromptFile(prompt);
|
|
1103
1104
|
const permissionMode = meta.defaultPermissionMode ?? "default";
|
|
1104
|
-
|
|
1105
|
+
const rcName = buildOrchestratorRcName(ids) ?? undefined;
|
|
1106
|
+
emitMarkers(buildOrchestrateMarkers({ repoRoot: root, promptFile, permissionMode, rcName }));
|
|
1105
1107
|
exit();
|
|
1106
1108
|
}
|
|
1107
1109
|
function openCreateOverlay(issue) {
|
|
@@ -10,6 +10,7 @@ import { findMainRepoRoot, getMintreeDir, pathExists } from "../lib/git.js";
|
|
|
10
10
|
import { readMetadata } from "../lib/metadata.js";
|
|
11
11
|
import { launchClaude, PERMISSION_MODES } from "../lib/claude.js";
|
|
12
12
|
import { defaultOrchestratorPrompt, renderOrchestratorTemplate } from "../lib/promptTemplate.js";
|
|
13
|
+
import { buildOrchestratorRcName } from "../lib/orchestrate.js";
|
|
13
14
|
export const description = "Launch a Claude orchestrator in the repo root to resolve a batch of tickets";
|
|
14
15
|
export const args = z
|
|
15
16
|
.array(z.string())
|
|
@@ -38,6 +39,12 @@ export const options = z.object({
|
|
|
38
39
|
description: `Claude --permission-mode (one of: ${PERMISSION_MODES.join(", ")}). Defaults to metadata.defaultPermissionMode, else "default".`,
|
|
39
40
|
alias: "m",
|
|
40
41
|
})),
|
|
42
|
+
rcName: z
|
|
43
|
+
.string()
|
|
44
|
+
.optional()
|
|
45
|
+
.describe(option({
|
|
46
|
+
description: "Remote Control name for the session. Defaults to orchestrator-<ids> derived from the positional ids (used by the dashboard, which has no positional ids), else orchestrator-<session-hash>.",
|
|
47
|
+
})),
|
|
41
48
|
});
|
|
42
49
|
function resolve(cwd, ids, opts) {
|
|
43
50
|
if (opts.prompt && opts.promptFile) {
|
|
@@ -96,9 +103,14 @@ function resolve(cwd, ids, opts) {
|
|
|
96
103
|
};
|
|
97
104
|
}
|
|
98
105
|
const permissionMode = opts.permissionMode ?? readMetadata(repoRoot).defaultPermissionMode ?? "default";
|
|
106
|
+
const sessionId = randomUUID();
|
|
107
|
+
// RC name priority: explicit --rc-name (the dashboard passes the
|
|
108
|
+
// ids-derived name this way) > derive from positional ids > session hash
|
|
109
|
+
// fallback for the prompt-only path with no tickets to name after.
|
|
110
|
+
const remoteControlName = opts.rcName ?? buildOrchestratorRcName(ids) ?? `orchestrator-${sessionId.slice(0, 8)}`;
|
|
99
111
|
return {
|
|
100
112
|
ok: true,
|
|
101
|
-
data: { repoRoot, sessionId
|
|
113
|
+
data: { repoRoot, sessionId, permissionMode, prompt, remoteControlName },
|
|
102
114
|
};
|
|
103
115
|
}
|
|
104
116
|
export default function Orchestrate({ args: ids, options }) {
|
|
@@ -124,11 +136,12 @@ export default function Orchestrate({ args: ids, options }) {
|
|
|
124
136
|
resume: false,
|
|
125
137
|
prompt: resolved.prompt,
|
|
126
138
|
cwd: resolved.repoRoot,
|
|
127
|
-
//
|
|
128
|
-
// orchestrator
|
|
129
|
-
//
|
|
130
|
-
//
|
|
131
|
-
|
|
139
|
+
// Name the RC session after the tickets it covers
|
|
140
|
+
// (orchestrator-VAL-12_BE-16_FE-3) so it's identifiable in the RC
|
|
141
|
+
// UI. Falls back to a session hash when there are no ids. Note:
|
|
142
|
+
// re-launching the exact same batch reuses the name, which can
|
|
143
|
+
// collide with a still-registered prior session.
|
|
144
|
+
remoteControlName: resolved.remoteControlName,
|
|
132
145
|
});
|
|
133
146
|
child.on("error", (err) => {
|
|
134
147
|
setState({ phase: "error", message: `Failed to launch claude: ${err.message}` });
|
|
@@ -152,7 +165,7 @@ export default function Orchestrate({ args: ids, options }) {
|
|
|
152
165
|
}
|
|
153
166
|
const { resolved } = state;
|
|
154
167
|
const sessionShort = resolved.sessionId.slice(0, 8);
|
|
155
|
-
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "mintree orchestrate" }), _jsxs(Text, { dimColor: true, children: [" \u00B7 ", resolved.repoRoot] })] }), _jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "session: " }), _jsxs(Text, { children: [sessionShort, "\u2026"] }), _jsx(Text, { dimColor: true, children: " (starting)" })] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "permission-mode: " }), _jsx(Text, { children: resolved.permissionMode })] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "prompt: " }), _jsxs(Text, { children: ["\"", truncate(resolved.prompt.replace(/\n/g, " "), 60), "\""] })] })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "green", bold: true, children: "\u2713 Launching Claude orchestrator..." }) })] }));
|
|
168
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "mintree orchestrate" }), _jsxs(Text, { dimColor: true, children: [" \u00B7 ", resolved.repoRoot] })] }), _jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "session: " }), _jsxs(Text, { children: [sessionShort, "\u2026"] }), _jsx(Text, { dimColor: true, children: " (starting)" })] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "rc: " }), _jsx(Text, { children: resolved.remoteControlName })] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "permission-mode: " }), _jsx(Text, { children: resolved.permissionMode })] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "prompt: " }), _jsxs(Text, { children: ["\"", truncate(resolved.prompt.replace(/\n/g, " "), 60), "\""] })] })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "green", bold: true, children: "\u2713 Launching Claude orchestrator..." }) })] }));
|
|
156
169
|
}
|
|
157
170
|
function truncate(s, max) {
|
|
158
171
|
if (s.length <= max)
|
package/dist/lib/markers.d.ts
CHANGED
package/dist/lib/markers.js
CHANGED
|
@@ -55,5 +55,8 @@ export function buildOrchestrateMarkers(input) {
|
|
|
55
55
|
if (input.permissionMode) {
|
|
56
56
|
lines.push(`MINTREE_PERMISSION_MODE:${input.permissionMode}`);
|
|
57
57
|
}
|
|
58
|
+
if (input.rcName) {
|
|
59
|
+
lines.push(`MINTREE_ORCHESTRATE_RC_NAME:${input.rcName}`);
|
|
60
|
+
}
|
|
58
61
|
return lines;
|
|
59
62
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derives the Remote Control name for an orchestrator session from the ticket
|
|
3
|
+
* ids it covers, e.g. ["VAL-12", "BE-16", "FE-3"] -> "orchestrator-VAL-12_BE-16_FE-3".
|
|
4
|
+
*
|
|
5
|
+
* The ids are joined with "_" (not spaces) so the result is a single
|
|
6
|
+
* shell-safe token — it travels through the dashboard markers and the shell
|
|
7
|
+
* wrapper as one `--rc-name` argument without quoting.
|
|
8
|
+
*
|
|
9
|
+
* Returns null when there are no ids, letting the caller fall back to a
|
|
10
|
+
* session-hash name (the `mintree orchestrate --prompt "..."` path, which has
|
|
11
|
+
* no tickets to name the session after).
|
|
12
|
+
*/
|
|
13
|
+
export declare function buildOrchestratorRcName(ids: string[]): string | null;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derives the Remote Control name for an orchestrator session from the ticket
|
|
3
|
+
* ids it covers, e.g. ["VAL-12", "BE-16", "FE-3"] -> "orchestrator-VAL-12_BE-16_FE-3".
|
|
4
|
+
*
|
|
5
|
+
* The ids are joined with "_" (not spaces) so the result is a single
|
|
6
|
+
* shell-safe token — it travels through the dashboard markers and the shell
|
|
7
|
+
* wrapper as one `--rc-name` argument without quoting.
|
|
8
|
+
*
|
|
9
|
+
* Returns null when there are no ids, letting the caller fall back to a
|
|
10
|
+
* session-hash name (the `mintree orchestrate --prompt "..."` path, which has
|
|
11
|
+
* no tickets to name the session after).
|
|
12
|
+
*/
|
|
13
|
+
export function buildOrchestratorRcName(ids) {
|
|
14
|
+
if (ids.length === 0)
|
|
15
|
+
return null;
|
|
16
|
+
return `orchestrator-${ids.join("_")}`;
|
|
17
|
+
}
|
|
@@ -21,7 +21,9 @@ import { readMetadata } from "../metadata.js";
|
|
|
21
21
|
const DEFAULT_API_URL = "https://api.linear.app/graphql";
|
|
22
22
|
// Linear state types we treat as "done" — work in these states is excluded
|
|
23
23
|
// from the assigned list and protected from transitions back to In Progress.
|
|
24
|
-
|
|
24
|
+
// "duplicate" is its own terminal state type in Linear (separate from
|
|
25
|
+
// "canceled"), so it has to be listed explicitly or those issues leak in.
|
|
26
|
+
const DEFAULT_PROTECTED_STATE_TYPES = ["completed", "canceled", "duplicate"];
|
|
25
27
|
const STATUS_ORDER_UNSET = 999;
|
|
26
28
|
// One query covers viewer + teams + issues; a single 20s budget comfortably
|
|
27
29
|
// fits even the slowest cold-start response without making real failures
|
|
@@ -261,7 +263,7 @@ const BOOTSTRAP_QUERY = /* GraphQL */ `
|
|
|
261
263
|
first: 100
|
|
262
264
|
filter: {
|
|
263
265
|
assignee: { isMe: { eq: true } }
|
|
264
|
-
state: { type: { nin: ["completed", "canceled"] } }
|
|
266
|
+
state: { type: { nin: ["completed", "canceled", "duplicate"] } }
|
|
265
267
|
team: { key: { in: $teamKeys } }
|
|
266
268
|
}
|
|
267
269
|
) {
|
|
@@ -403,9 +405,11 @@ export class LinearProvider {
|
|
|
403
405
|
const protectedTypes = new Set(cfg.protectedStateTypes ?? DEFAULT_PROTECTED_STATE_TYPES);
|
|
404
406
|
const out = [];
|
|
405
407
|
for (const wi of data.issues) {
|
|
406
|
-
// Defensive — the bootstrap query already excludes
|
|
407
|
-
// via state.type.nin, but a workspace
|
|
408
|
-
// the user added to the protected list
|
|
408
|
+
// Defensive — the bootstrap query already excludes
|
|
409
|
+
// completed/canceled/duplicate via state.type.nin, but a workspace
|
|
410
|
+
// could have custom state types the user added to the protected list
|
|
411
|
+
// locally (and a stale snapshot cache predating the query change
|
|
412
|
+
// still gets filtered here).
|
|
409
413
|
const type = wi.state?.type;
|
|
410
414
|
if (type && protectedTypes.has(type))
|
|
411
415
|
continue;
|
package/package.json
CHANGED
package/shell/init.bash
CHANGED
|
@@ -55,6 +55,9 @@ function mintree() {
|
|
|
55
55
|
orch_prompt_file=$(echo "$clean_output" | grep "MINTREE_ORCHESTRATE_PROMPT_FILE:" | sed 's/.*MINTREE_ORCHESTRATE_PROMPT_FILE://')
|
|
56
56
|
[[ -n "$orch_prompt_file" ]] && extra+=(--prompt-file "$orch_prompt_file")
|
|
57
57
|
[[ -n "$perm_mode" ]] && extra+=(--permission-mode "$perm_mode")
|
|
58
|
+
local orch_rc_name
|
|
59
|
+
orch_rc_name=$(echo "$clean_output" | grep "MINTREE_ORCHESTRATE_RC_NAME:" | sed 's/.*MINTREE_ORCHESTRATE_RC_NAME://')
|
|
60
|
+
[[ -n "$orch_rc_name" ]] && extra+=(--rc-name "$orch_rc_name")
|
|
58
61
|
command mintree orchestrate "${extra[@]}"
|
|
59
62
|
return $?
|
|
60
63
|
fi
|
package/shell/init.zsh
CHANGED
|
@@ -65,6 +65,9 @@ function mintree() {
|
|
|
65
65
|
orch_prompt_file=$(echo "$clean_output" | grep "MINTREE_ORCHESTRATE_PROMPT_FILE:" | sed 's/.*MINTREE_ORCHESTRATE_PROMPT_FILE://')
|
|
66
66
|
[[ -n "$orch_prompt_file" ]] && extra+=(--prompt-file "$orch_prompt_file")
|
|
67
67
|
[[ -n "$perm_mode" ]] && extra+=(--permission-mode "$perm_mode")
|
|
68
|
+
local orch_rc_name
|
|
69
|
+
orch_rc_name=$(echo "$clean_output" | grep "MINTREE_ORCHESTRATE_RC_NAME:" | sed 's/.*MINTREE_ORCHESTRATE_RC_NAME://')
|
|
70
|
+
[[ -n "$orch_rc_name" ]] && extra+=(--rc-name "$orch_rc_name")
|
|
68
71
|
command mintree orchestrate "${extra[@]}"
|
|
69
72
|
return $?
|
|
70
73
|
fi
|