sequant 2.2.0 → 2.4.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +81 -5
- package/dist/bin/cli.js +140 -13
- package/dist/src/commands/abort.d.ts +36 -0
- package/dist/src/commands/abort.js +138 -0
- package/dist/src/commands/doctor.d.ts +25 -0
- package/dist/src/commands/doctor.js +36 -1
- package/dist/src/commands/locks.d.ts +67 -0
- package/dist/src/commands/locks.js +290 -0
- package/dist/src/commands/merge.js +11 -0
- package/dist/src/commands/prompt.d.ts +46 -0
- package/dist/src/commands/prompt.js +273 -0
- package/dist/src/commands/run-display.d.ts +11 -2
- package/dist/src/commands/run-display.js +62 -28
- package/dist/src/commands/run-progress.d.ts +42 -0
- package/dist/src/commands/run-progress.js +93 -0
- package/dist/src/commands/run.js +90 -18
- package/dist/src/commands/stats.d.ts +2 -0
- package/dist/src/commands/stats.js +94 -8
- package/dist/src/commands/status.js +12 -0
- package/dist/src/commands/watch.d.ts +18 -0
- package/dist/src/commands/watch.js +211 -0
- package/dist/src/lib/ac-linter.d.ts +1 -1
- package/dist/src/lib/ac-linter.js +81 -0
- package/dist/src/lib/assess-collision-detect.d.ts +91 -0
- package/dist/src/lib/assess-collision-detect.js +217 -0
- package/dist/src/lib/assess-comment-parser.d.ts +59 -1
- package/dist/src/lib/assess-comment-parser.js +124 -2
- package/dist/src/lib/cli-ui/format.d.ts +19 -0
- package/dist/src/lib/cli-ui/format.js +34 -0
- package/dist/src/lib/cli-ui/run-renderer-types.d.ts +220 -0
- package/dist/src/lib/cli-ui/run-renderer-types.js +7 -0
- package/dist/src/lib/cli-ui/run-renderer.d.ts +265 -0
- package/dist/src/lib/cli-ui/run-renderer.js +1390 -0
- package/dist/src/lib/cli-ui/scrollback-harness.d.ts +112 -0
- package/dist/src/lib/cli-ui/scrollback-harness.js +294 -0
- package/dist/src/lib/heuristics/behavior-rule-detector.d.ts +94 -0
- package/dist/src/lib/heuristics/behavior-rule-detector.js +467 -0
- package/dist/src/lib/locks/index.d.ts +7 -0
- package/dist/src/lib/locks/index.js +5 -0
- package/dist/src/lib/locks/lock-manager.d.ts +168 -0
- package/dist/src/lib/locks/lock-manager.js +433 -0
- package/dist/src/lib/locks/types.d.ts +59 -0
- package/dist/src/lib/locks/types.js +31 -0
- package/dist/src/lib/merge-check/types.js +1 -1
- package/dist/src/lib/qa/markdown-only-ci.d.ts +46 -0
- package/dist/src/lib/qa/markdown-only-ci.js +74 -0
- package/dist/src/lib/relay/activation.d.ts +60 -0
- package/dist/src/lib/relay/activation.js +122 -0
- package/dist/src/lib/relay/archive.d.ts +34 -0
- package/dist/src/lib/relay/archive.js +112 -0
- package/dist/src/lib/relay/frame.d.ts +20 -0
- package/dist/src/lib/relay/frame.js +76 -0
- package/dist/src/lib/relay/index.d.ts +13 -0
- package/dist/src/lib/relay/index.js +13 -0
- package/dist/src/lib/relay/paths.d.ts +43 -0
- package/dist/src/lib/relay/paths.js +59 -0
- package/dist/src/lib/relay/pid.d.ts +34 -0
- package/dist/src/lib/relay/pid.js +72 -0
- package/dist/src/lib/relay/reader.d.ts +35 -0
- package/dist/src/lib/relay/reader.js +115 -0
- package/dist/src/lib/relay/types.d.ts +70 -0
- package/dist/src/lib/relay/types.js +85 -0
- package/dist/src/lib/relay/writer.d.ts +48 -0
- package/dist/src/lib/relay/writer.js +113 -0
- package/dist/src/lib/settings.d.ts +31 -1
- package/dist/src/lib/settings.js +18 -3
- package/dist/src/lib/version-check.d.ts +60 -5
- package/dist/src/lib/version-check.js +97 -9
- package/dist/src/lib/workflow/batch-executor.d.ts +20 -1
- package/dist/src/lib/workflow/batch-executor.js +274 -185
- package/dist/src/lib/workflow/config-resolver.js +4 -0
- package/dist/src/lib/workflow/drivers/agent-driver.d.ts +48 -1
- package/dist/src/lib/workflow/drivers/aider.d.ts +7 -1
- package/dist/src/lib/workflow/drivers/aider.js +9 -0
- package/dist/src/lib/workflow/drivers/claude-code.d.ts +17 -1
- package/dist/src/lib/workflow/drivers/claude-code.js +51 -2
- package/dist/src/lib/workflow/drivers/index.d.ts +1 -1
- package/dist/src/lib/workflow/event-emitter.d.ts +157 -0
- package/dist/src/lib/workflow/event-emitter.js +102 -0
- package/dist/src/lib/workflow/heartbeat.d.ts +71 -0
- package/dist/src/lib/workflow/heartbeat.js +194 -0
- package/dist/src/lib/workflow/notice.d.ts +32 -0
- package/dist/src/lib/workflow/notice.js +38 -0
- package/dist/src/lib/workflow/phase-executor.d.ts +58 -16
- package/dist/src/lib/workflow/phase-executor.js +244 -130
- package/dist/src/lib/workflow/phase-mapper.d.ts +27 -13
- package/dist/src/lib/workflow/phase-mapper.js +70 -51
- package/dist/src/lib/workflow/phase-registry.d.ts +127 -0
- package/dist/src/lib/workflow/phase-registry.js +233 -0
- package/dist/src/lib/workflow/platforms/github.d.ts +1 -1
- package/dist/src/lib/workflow/platforms/github.js +20 -3
- package/dist/src/lib/workflow/pr-status.d.ts +18 -2
- package/dist/src/lib/workflow/pr-status.js +41 -9
- package/dist/src/lib/workflow/qa-stagnation.d.ts +117 -0
- package/dist/src/lib/workflow/qa-stagnation.js +179 -0
- package/dist/src/lib/workflow/run-log-schema.d.ts +5 -55
- package/dist/src/lib/workflow/run-orchestrator.d.ts +70 -1
- package/dist/src/lib/workflow/run-orchestrator.js +464 -25
- package/dist/src/lib/workflow/run-reflect.js +1 -1
- package/dist/src/lib/workflow/run-state.d.ts +71 -0
- package/dist/src/lib/workflow/run-state.js +14 -0
- package/dist/src/lib/workflow/state-cleanup.d.ts +13 -5
- package/dist/src/lib/workflow/state-cleanup.js +17 -5
- package/dist/src/lib/workflow/state-manager.d.ts +31 -2
- package/dist/src/lib/workflow/state-manager.js +64 -1
- package/dist/src/lib/workflow/state-schema.d.ts +82 -35
- package/dist/src/lib/workflow/state-schema.js +63 -4
- package/dist/src/lib/workflow/types.d.ts +139 -16
- package/dist/src/lib/workflow/types.js +18 -13
- package/dist/src/lib/workflow/worktree-manager.d.ts +8 -1
- package/dist/src/lib/workflow/worktree-manager.js +15 -6
- package/dist/src/mcp/tools/run.d.ts +44 -0
- package/dist/src/mcp/tools/run.js +104 -13
- package/dist/src/ui/tui/App.d.ts +14 -0
- package/dist/src/ui/tui/App.js +41 -0
- package/dist/src/ui/tui/ElapsedTimer.d.ts +10 -0
- package/dist/src/ui/tui/ElapsedTimer.js +31 -0
- package/dist/src/ui/tui/Header.d.ts +6 -0
- package/dist/src/ui/tui/Header.js +15 -0
- package/dist/src/ui/tui/IssueBox.d.ts +16 -0
- package/dist/src/ui/tui/IssueBox.js +68 -0
- package/dist/src/ui/tui/Spinner.d.ts +9 -0
- package/dist/src/ui/tui/Spinner.js +18 -0
- package/dist/src/ui/tui/index.d.ts +15 -0
- package/dist/src/ui/tui/index.js +29 -0
- package/dist/src/ui/tui/theme.d.ts +29 -0
- package/dist/src/ui/tui/theme.js +52 -0
- package/dist/src/ui/tui/truncate.d.ts +11 -0
- package/dist/src/ui/tui/truncate.js +31 -0
- package/package.json +14 -6
- package/templates/agents/sequant-explorer.md +1 -0
- package/templates/agents/sequant-qa-checker.md +2 -1
- package/templates/agents/sequant-testgen.md +1 -0
- package/templates/hooks/post-tool.sh +92 -0
- package/templates/hooks/pre-tool.sh +18 -9
- package/templates/hooks/relay-check.sh +107 -0
- package/templates/relay/frame.txt +11 -0
- package/templates/scripts/cleanup-worktree.sh +25 -3
- package/templates/scripts/new-feature.sh +6 -0
- package/templates/skills/_shared/references/behavior-rule-detection.md +205 -0
- package/templates/skills/_shared/references/subagent-types.md +21 -8
- package/templates/skills/assess/SKILL.md +122 -68
- package/templates/skills/assess/references/predicted-collision-detection.md +109 -0
- package/templates/skills/docs/SKILL.md +141 -22
- package/templates/skills/exec/SKILL.md +10 -8
- package/templates/skills/fullsolve/SKILL.md +79 -5
- package/templates/skills/loop/SKILL.md +28 -0
- package/templates/skills/merger/SKILL.md +621 -0
- package/templates/skills/qa/SKILL.md +727 -8
- package/templates/skills/setup/SKILL.md +12 -6
- package/templates/skills/spec/SKILL.md +52 -0
- package/templates/skills/spec/references/parallel-groups.md +7 -0
- package/templates/skills/spec/references/recommended-workflow.md +4 -2
- package/templates/skills/testgen/SKILL.md +24 -17
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reader for the relay inbox. Tracks the last-read line via a `.cursor` file
|
|
3
|
+
* so each PostToolUse hook invocation only sees new messages (AC-11).
|
|
4
|
+
*
|
|
5
|
+
* Atomic cursor update: write to a temp file in the same directory, then
|
|
6
|
+
* rename. A crash mid-write never leaves a half-written cursor.
|
|
7
|
+
*/
|
|
8
|
+
import { type RelayMessage } from "./types.js";
|
|
9
|
+
import { type RelayPathOptions } from "./paths.js";
|
|
10
|
+
export interface ReadResult {
|
|
11
|
+
/** Newly read inbox messages, ordered by file appearance (timestamp). */
|
|
12
|
+
messages: RelayMessage[];
|
|
13
|
+
/** Cursor value after this read. */
|
|
14
|
+
cursor: number;
|
|
15
|
+
/** Total line count of inbox.jsonl after the read. */
|
|
16
|
+
inboxLineCount: number;
|
|
17
|
+
/** Malformed lines that were skipped (for logging). */
|
|
18
|
+
skipped: number;
|
|
19
|
+
}
|
|
20
|
+
/** Read the persisted cursor; missing/unparseable → 0 (AC-11 edge case). */
|
|
21
|
+
export declare function readCursor(issue: number, options?: RelayPathOptions): number;
|
|
22
|
+
/** Write the cursor atomically (temp file + rename). */
|
|
23
|
+
export declare function writeCursor(issue: number, value: number, options?: RelayPathOptions): void;
|
|
24
|
+
/**
|
|
25
|
+
* Read unread inbox messages and advance the cursor.
|
|
26
|
+
*
|
|
27
|
+
* - Missing or empty inbox → empty result (fast path).
|
|
28
|
+
* - Malformed JSON lines are logged via the `onMalformed` callback (if any)
|
|
29
|
+
* and skipped; the cursor still advances past them so we don't loop.
|
|
30
|
+
* - If the cursor points past EOF (inbox was truncated/rotated), reset to the
|
|
31
|
+
* current line count and return no messages.
|
|
32
|
+
*/
|
|
33
|
+
export declare function readUnreadMessages(issue: number, options?: RelayPathOptions & {
|
|
34
|
+
onMalformed?: (line: string, index: number) => void;
|
|
35
|
+
}): ReadResult;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reader for the relay inbox. Tracks the last-read line via a `.cursor` file
|
|
3
|
+
* so each PostToolUse hook invocation only sees new messages (AC-11).
|
|
4
|
+
*
|
|
5
|
+
* Atomic cursor update: write to a temp file in the same directory, then
|
|
6
|
+
* rename. A crash mid-write never leaves a half-written cursor.
|
|
7
|
+
*/
|
|
8
|
+
import { randomBytes } from "crypto";
|
|
9
|
+
import { closeSync, existsSync, mkdirSync, openSync, readFileSync, renameSync, statSync, unlinkSync, writeSync, } from "fs";
|
|
10
|
+
import { dirname, join } from "path";
|
|
11
|
+
import { RelayMessageSchema } from "./types.js";
|
|
12
|
+
import { cursorPathFor, inboxPathFor } from "./paths.js";
|
|
13
|
+
/** Read the persisted cursor; missing/unparseable → 0 (AC-11 edge case). */
|
|
14
|
+
export function readCursor(issue, options = {}) {
|
|
15
|
+
const path = cursorPathFor(issue, options);
|
|
16
|
+
if (!existsSync(path))
|
|
17
|
+
return 0;
|
|
18
|
+
try {
|
|
19
|
+
const raw = readFileSync(path, "utf-8").trim();
|
|
20
|
+
const n = Number.parseInt(raw, 10);
|
|
21
|
+
if (!Number.isInteger(n) || n < 0)
|
|
22
|
+
return 0;
|
|
23
|
+
return n;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** Write the cursor atomically (temp file + rename). */
|
|
30
|
+
export function writeCursor(issue, value, options = {}) {
|
|
31
|
+
const path = cursorPathFor(issue, options);
|
|
32
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
33
|
+
const tmp = join(dirname(path), `.cursor.${process.pid}.${Date.now()}.${randomBytes(2).toString("hex")}.tmp`);
|
|
34
|
+
try {
|
|
35
|
+
const fd = openSync(tmp, "w");
|
|
36
|
+
try {
|
|
37
|
+
writeSync(fd, String(value));
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
closeSync(fd);
|
|
41
|
+
}
|
|
42
|
+
renameSync(tmp, path);
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
if (existsSync(tmp)) {
|
|
46
|
+
try {
|
|
47
|
+
unlinkSync(tmp);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
/* swallow */
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
throw err;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Read unread inbox messages and advance the cursor.
|
|
58
|
+
*
|
|
59
|
+
* - Missing or empty inbox → empty result (fast path).
|
|
60
|
+
* - Malformed JSON lines are logged via the `onMalformed` callback (if any)
|
|
61
|
+
* and skipped; the cursor still advances past them so we don't loop.
|
|
62
|
+
* - If the cursor points past EOF (inbox was truncated/rotated), reset to the
|
|
63
|
+
* current line count and return no messages.
|
|
64
|
+
*/
|
|
65
|
+
export function readUnreadMessages(issue, options = {}) {
|
|
66
|
+
const inboxPath = inboxPathFor(issue, options);
|
|
67
|
+
if (!existsSync(inboxPath)) {
|
|
68
|
+
return { messages: [], cursor: 0, inboxLineCount: 0, skipped: 0 };
|
|
69
|
+
}
|
|
70
|
+
const st = statSync(inboxPath);
|
|
71
|
+
if (st.size === 0) {
|
|
72
|
+
return { messages: [], cursor: 0, inboxLineCount: 0, skipped: 0 };
|
|
73
|
+
}
|
|
74
|
+
const text = readFileSync(inboxPath, "utf-8");
|
|
75
|
+
const lines = text.split("\n").filter((l, idx, arr) => {
|
|
76
|
+
// Keep all but the final empty element from a trailing newline.
|
|
77
|
+
return !(idx === arr.length - 1 && l === "");
|
|
78
|
+
});
|
|
79
|
+
const totalLines = lines.length;
|
|
80
|
+
let cursor = readCursor(issue, options);
|
|
81
|
+
// If cursor is past EOF (file was rotated/truncated), reset to current end.
|
|
82
|
+
if (cursor > totalLines) {
|
|
83
|
+
writeCursor(issue, totalLines, options);
|
|
84
|
+
return {
|
|
85
|
+
messages: [],
|
|
86
|
+
cursor: totalLines,
|
|
87
|
+
inboxLineCount: totalLines,
|
|
88
|
+
skipped: 0,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const messages = [];
|
|
92
|
+
let skipped = 0;
|
|
93
|
+
for (let i = cursor; i < totalLines; i++) {
|
|
94
|
+
const raw = lines[i];
|
|
95
|
+
if (raw.trim() === "")
|
|
96
|
+
continue;
|
|
97
|
+
try {
|
|
98
|
+
const obj = JSON.parse(raw);
|
|
99
|
+
const parsed = RelayMessageSchema.safeParse(obj);
|
|
100
|
+
if (!parsed.success) {
|
|
101
|
+
skipped++;
|
|
102
|
+
options.onMalformed?.(raw, i);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
messages.push(parsed.data);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
skipped++;
|
|
109
|
+
options.onMalformed?.(raw, i);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
cursor = totalLines;
|
|
113
|
+
writeCursor(issue, cursor, options);
|
|
114
|
+
return { messages, cursor, inboxLineCount: totalLines, skipped };
|
|
115
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions and Zod schemas for the interactive relay (#383).
|
|
3
|
+
*
|
|
4
|
+
* The relay is a file-based IPC channel that allows a user terminal to send
|
|
5
|
+
* messages into a running headless Claude session. Messages flow through two
|
|
6
|
+
* JSONL files in `<worktree>/.sequant/relay/`:
|
|
7
|
+
*
|
|
8
|
+
* - `inbox.jsonl`: user → Claude (consumed by the PostToolUse hook)
|
|
9
|
+
* - `outbox.jsonl`: Claude → user (tailed by `sequant watch`)
|
|
10
|
+
*/
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
/** Maximum size (bytes) of a single relay message body. */
|
|
13
|
+
export declare const MAX_MESSAGE_BYTES: number;
|
|
14
|
+
/** Relay message types. `query` asks for status, `directive` nudges behavior, `abort` stops. */
|
|
15
|
+
export declare const RelayMessageTypeSchema: z.ZodEnum<{
|
|
16
|
+
abort: "abort";
|
|
17
|
+
query: "query";
|
|
18
|
+
directive: "directive";
|
|
19
|
+
}>;
|
|
20
|
+
export type RelayMessageType = z.infer<typeof RelayMessageTypeSchema>;
|
|
21
|
+
/** Inbox message id format: `msg_<hex>`. */
|
|
22
|
+
export declare const MESSAGE_ID_PATTERN: RegExp;
|
|
23
|
+
/** Outbox reply id format: `reply_<hex>`. */
|
|
24
|
+
export declare const REPLY_ID_PATTERN: RegExp;
|
|
25
|
+
/**
|
|
26
|
+
* Discriminated union over `type`. `query` and `directive` require a non-empty
|
|
27
|
+
* `message` body; `abort` allows an optional explanatory message but it is not
|
|
28
|
+
* required.
|
|
29
|
+
*/
|
|
30
|
+
export declare const RelayMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
31
|
+
type: z.ZodLiteral<"query">;
|
|
32
|
+
message: z.ZodString;
|
|
33
|
+
id: z.ZodString;
|
|
34
|
+
timestamp: z.ZodString;
|
|
35
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
36
|
+
type: z.ZodLiteral<"directive">;
|
|
37
|
+
message: z.ZodString;
|
|
38
|
+
id: z.ZodString;
|
|
39
|
+
timestamp: z.ZodString;
|
|
40
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
41
|
+
type: z.ZodLiteral<"abort">;
|
|
42
|
+
message: z.ZodOptional<z.ZodString>;
|
|
43
|
+
id: z.ZodString;
|
|
44
|
+
timestamp: z.ZodString;
|
|
45
|
+
}, z.core.$strip>], "type">;
|
|
46
|
+
export type RelayMessage = z.infer<typeof RelayMessageSchema>;
|
|
47
|
+
/** Outbox reply. `inReplyTo` is mandatory — every reply references an inbox id. */
|
|
48
|
+
export declare const RelayResponseSchema: z.ZodObject<{
|
|
49
|
+
id: z.ZodString;
|
|
50
|
+
inReplyTo: z.ZodString;
|
|
51
|
+
timestamp: z.ZodString;
|
|
52
|
+
message: z.ZodString;
|
|
53
|
+
}, z.core.$strip>;
|
|
54
|
+
export type RelayResponse = z.infer<typeof RelayResponseSchema>;
|
|
55
|
+
export { RelayStateSchema, type RelayState } from "../workflow/state-schema.js";
|
|
56
|
+
/**
|
|
57
|
+
* `meta.json` written alongside archived inbox/outbox in
|
|
58
|
+
* `.sequant/logs/relay/<issue>-<phase>-<ts>/`. Captures the run boundary so
|
|
59
|
+
* post-hoc inspection knows which phase/issue the messages belonged to.
|
|
60
|
+
*/
|
|
61
|
+
export declare const RelayArchiveMetaSchema: z.ZodObject<{
|
|
62
|
+
issue: z.ZodNumber;
|
|
63
|
+
phase: z.ZodString;
|
|
64
|
+
startedAt: z.ZodString;
|
|
65
|
+
endedAt: z.ZodString;
|
|
66
|
+
messageCount: z.ZodNumber;
|
|
67
|
+
inboxCount: z.ZodOptional<z.ZodNumber>;
|
|
68
|
+
outboxCount: z.ZodOptional<z.ZodNumber>;
|
|
69
|
+
}, z.core.$strip>;
|
|
70
|
+
export type RelayArchiveMeta = z.infer<typeof RelayArchiveMetaSchema>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions and Zod schemas for the interactive relay (#383).
|
|
3
|
+
*
|
|
4
|
+
* The relay is a file-based IPC channel that allows a user terminal to send
|
|
5
|
+
* messages into a running headless Claude session. Messages flow through two
|
|
6
|
+
* JSONL files in `<worktree>/.sequant/relay/`:
|
|
7
|
+
*
|
|
8
|
+
* - `inbox.jsonl`: user → Claude (consumed by the PostToolUse hook)
|
|
9
|
+
* - `outbox.jsonl`: Claude → user (tailed by `sequant watch`)
|
|
10
|
+
*/
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
/** Maximum size (bytes) of a single relay message body. */
|
|
13
|
+
export const MAX_MESSAGE_BYTES = 16 * 1024; // 16 KB
|
|
14
|
+
/** Relay message types. `query` asks for status, `directive` nudges behavior, `abort` stops. */
|
|
15
|
+
export const RelayMessageTypeSchema = z.enum(["query", "directive", "abort"]);
|
|
16
|
+
/** Inbox message id format: `msg_<hex>`. */
|
|
17
|
+
export const MESSAGE_ID_PATTERN = /^msg_[0-9a-f]+$/;
|
|
18
|
+
/** Outbox reply id format: `reply_<hex>`. */
|
|
19
|
+
export const REPLY_ID_PATTERN = /^reply_[0-9a-f]+$/;
|
|
20
|
+
const baseInboxFields = {
|
|
21
|
+
id: z.string().regex(MESSAGE_ID_PATTERN, "id must match /^msg_[0-9a-f]+$/"),
|
|
22
|
+
timestamp: z.string().datetime(),
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Discriminated union over `type`. `query` and `directive` require a non-empty
|
|
26
|
+
* `message` body; `abort` allows an optional explanatory message but it is not
|
|
27
|
+
* required.
|
|
28
|
+
*/
|
|
29
|
+
export const RelayMessageSchema = z.discriminatedUnion("type", [
|
|
30
|
+
z.object({
|
|
31
|
+
...baseInboxFields,
|
|
32
|
+
type: z.literal("query"),
|
|
33
|
+
message: z
|
|
34
|
+
.string()
|
|
35
|
+
.min(1, "message is required for query")
|
|
36
|
+
.max(MAX_MESSAGE_BYTES, `message exceeds ${MAX_MESSAGE_BYTES} bytes`),
|
|
37
|
+
}),
|
|
38
|
+
z.object({
|
|
39
|
+
...baseInboxFields,
|
|
40
|
+
type: z.literal("directive"),
|
|
41
|
+
message: z
|
|
42
|
+
.string()
|
|
43
|
+
.min(1, "message is required for directive")
|
|
44
|
+
.max(MAX_MESSAGE_BYTES, `message exceeds ${MAX_MESSAGE_BYTES} bytes`),
|
|
45
|
+
}),
|
|
46
|
+
z.object({
|
|
47
|
+
...baseInboxFields,
|
|
48
|
+
type: z.literal("abort"),
|
|
49
|
+
message: z.string().max(MAX_MESSAGE_BYTES).optional(),
|
|
50
|
+
}),
|
|
51
|
+
]);
|
|
52
|
+
/** Outbox reply. `inReplyTo` is mandatory — every reply references an inbox id. */
|
|
53
|
+
export const RelayResponseSchema = z.object({
|
|
54
|
+
id: z.string().regex(REPLY_ID_PATTERN, "id must match /^reply_[0-9a-f]+$/"),
|
|
55
|
+
inReplyTo: z
|
|
56
|
+
.string()
|
|
57
|
+
.min(1, "inReplyTo is required")
|
|
58
|
+
.regex(MESSAGE_ID_PATTERN, "inReplyTo must match /^msg_[0-9a-f]+$/"),
|
|
59
|
+
timestamp: z.string().datetime(),
|
|
60
|
+
message: z.string(),
|
|
61
|
+
});
|
|
62
|
+
// `RelayState` is defined in `src/lib/workflow/state-schema.ts` (canonical
|
|
63
|
+
// location alongside `IssueState`). Re-exported here as a convenience.
|
|
64
|
+
export { RelayStateSchema } from "../workflow/state-schema.js";
|
|
65
|
+
/**
|
|
66
|
+
* `meta.json` written alongside archived inbox/outbox in
|
|
67
|
+
* `.sequant/logs/relay/<issue>-<phase>-<ts>/`. Captures the run boundary so
|
|
68
|
+
* post-hoc inspection knows which phase/issue the messages belonged to.
|
|
69
|
+
*/
|
|
70
|
+
export const RelayArchiveMetaSchema = z.object({
|
|
71
|
+
issue: z.number().int().positive(),
|
|
72
|
+
phase: z.string(),
|
|
73
|
+
startedAt: z.string().datetime(),
|
|
74
|
+
endedAt: z.string().datetime(),
|
|
75
|
+
/** Total inbox + outbox messages exchanged during the run. */
|
|
76
|
+
messageCount: z.number().int().nonnegative(),
|
|
77
|
+
/**
|
|
78
|
+
* Inbox messages (user → agent). Split out from `messageCount` (#645, Gap 5)
|
|
79
|
+
* so post-hoc inspection can spot unanswered queries (inboxCount > outboxCount).
|
|
80
|
+
* Optional for backward compatibility with archives written before this split.
|
|
81
|
+
*/
|
|
82
|
+
inboxCount: z.number().int().nonnegative().optional(),
|
|
83
|
+
/** Outbox replies (agent → user). See `inboxCount` for context. */
|
|
84
|
+
outboxCount: z.number().int().nonnegative().optional(),
|
|
85
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Append-only writer for relay inbox/outbox JSONL files.
|
|
3
|
+
*
|
|
4
|
+
* Single-line appends use `O_APPEND` so concurrent writes interleave cleanly
|
|
5
|
+
* at the line boundary (POSIX guarantees atomicity for `write()` calls smaller
|
|
6
|
+
* than `PIPE_BUF`/4 KiB on local filesystems). Multi-line payloads use the
|
|
7
|
+
* temp-file + `rename()` pattern so partial reads never observe a half-written
|
|
8
|
+
* file (AC-5).
|
|
9
|
+
*/
|
|
10
|
+
import { type RelayMessage, type RelayMessageType, type RelayResponse } from "./types.js";
|
|
11
|
+
import { type RelayPathOptions } from "./paths.js";
|
|
12
|
+
/** Generate a `msg_<hex>` id with enough entropy to stay unique within a run. */
|
|
13
|
+
export declare function generateMessageId(): string;
|
|
14
|
+
/** Generate a `reply_<hex>` id. */
|
|
15
|
+
export declare function generateReplyId(): string;
|
|
16
|
+
/** Build an inbox message, validating against the schema. */
|
|
17
|
+
export declare function buildInboxMessage(input: {
|
|
18
|
+
type: RelayMessageType;
|
|
19
|
+
message?: string;
|
|
20
|
+
id?: string;
|
|
21
|
+
timestamp?: string;
|
|
22
|
+
}): RelayMessage;
|
|
23
|
+
/** Build an outbox reply, validating against the schema. */
|
|
24
|
+
export declare function buildOutboxReply(input: {
|
|
25
|
+
inReplyTo: string;
|
|
26
|
+
message: string;
|
|
27
|
+
id?: string;
|
|
28
|
+
timestamp?: string;
|
|
29
|
+
}): RelayResponse;
|
|
30
|
+
/**
|
|
31
|
+
* Append a single inbox message. Uses `O_APPEND` for crash-safe concurrent
|
|
32
|
+
* writes (AC-5). Throws on body sizes that exceed `MAX_MESSAGE_BYTES`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function appendInboxMessage(issue: number, input: {
|
|
35
|
+
type: RelayMessageType;
|
|
36
|
+
message?: string;
|
|
37
|
+
}, options?: RelayPathOptions): RelayMessage;
|
|
38
|
+
/** Append a single outbox reply via `O_APPEND`. */
|
|
39
|
+
export declare function appendOutboxReply(issue: number, input: {
|
|
40
|
+
inReplyTo: string;
|
|
41
|
+
message: string;
|
|
42
|
+
}, options?: RelayPathOptions): RelayResponse;
|
|
43
|
+
/**
|
|
44
|
+
* Write multiple inbox messages atomically (temp file + rename).
|
|
45
|
+
* Useful when seeding a relay dir from a backup or replaying. Single-message
|
|
46
|
+
* writes should use `appendInboxMessage` instead.
|
|
47
|
+
*/
|
|
48
|
+
export declare function writeInboxBatchAtomic(issue: number, messages: RelayMessage[], options?: RelayPathOptions): void;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Append-only writer for relay inbox/outbox JSONL files.
|
|
3
|
+
*
|
|
4
|
+
* Single-line appends use `O_APPEND` so concurrent writes interleave cleanly
|
|
5
|
+
* at the line boundary (POSIX guarantees atomicity for `write()` calls smaller
|
|
6
|
+
* than `PIPE_BUF`/4 KiB on local filesystems). Multi-line payloads use the
|
|
7
|
+
* temp-file + `rename()` pattern so partial reads never observe a half-written
|
|
8
|
+
* file (AC-5).
|
|
9
|
+
*/
|
|
10
|
+
import { randomBytes } from "crypto";
|
|
11
|
+
import { closeSync, existsSync, mkdirSync, openSync, renameSync, unlinkSync, writeSync, } from "fs";
|
|
12
|
+
import { dirname, join } from "path";
|
|
13
|
+
import { MAX_MESSAGE_BYTES, RelayMessageSchema, RelayResponseSchema, } from "./types.js";
|
|
14
|
+
import { inboxPathFor, outboxPathFor } from "./paths.js";
|
|
15
|
+
/** Generate a `msg_<hex>` id with enough entropy to stay unique within a run. */
|
|
16
|
+
export function generateMessageId() {
|
|
17
|
+
return `msg_${randomBytes(8).toString("hex")}`;
|
|
18
|
+
}
|
|
19
|
+
/** Generate a `reply_<hex>` id. */
|
|
20
|
+
export function generateReplyId() {
|
|
21
|
+
return `reply_${randomBytes(8).toString("hex")}`;
|
|
22
|
+
}
|
|
23
|
+
function ensureDir(path) {
|
|
24
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
/** Build an inbox message, validating against the schema. */
|
|
27
|
+
export function buildInboxMessage(input) {
|
|
28
|
+
const candidate = {
|
|
29
|
+
id: input.id ?? generateMessageId(),
|
|
30
|
+
timestamp: input.timestamp ?? new Date().toISOString(),
|
|
31
|
+
type: input.type,
|
|
32
|
+
...(input.message !== undefined ? { message: input.message } : {}),
|
|
33
|
+
};
|
|
34
|
+
return RelayMessageSchema.parse(candidate);
|
|
35
|
+
}
|
|
36
|
+
/** Build an outbox reply, validating against the schema. */
|
|
37
|
+
export function buildOutboxReply(input) {
|
|
38
|
+
return RelayResponseSchema.parse({
|
|
39
|
+
id: input.id ?? generateReplyId(),
|
|
40
|
+
inReplyTo: input.inReplyTo,
|
|
41
|
+
timestamp: input.timestamp ?? new Date().toISOString(),
|
|
42
|
+
message: input.message,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Append a single inbox message. Uses `O_APPEND` for crash-safe concurrent
|
|
47
|
+
* writes (AC-5). Throws on body sizes that exceed `MAX_MESSAGE_BYTES`.
|
|
48
|
+
*/
|
|
49
|
+
export function appendInboxMessage(issue, input, options = {}) {
|
|
50
|
+
if (input.message &&
|
|
51
|
+
Buffer.byteLength(input.message, "utf-8") > MAX_MESSAGE_BYTES) {
|
|
52
|
+
throw new Error(`relay: message body exceeds max size of ${MAX_MESSAGE_BYTES} bytes`);
|
|
53
|
+
}
|
|
54
|
+
const message = buildInboxMessage(input);
|
|
55
|
+
const path = inboxPathFor(issue, options);
|
|
56
|
+
appendJsonLine(path, message);
|
|
57
|
+
return message;
|
|
58
|
+
}
|
|
59
|
+
/** Append a single outbox reply via `O_APPEND`. */
|
|
60
|
+
export function appendOutboxReply(issue, input, options = {}) {
|
|
61
|
+
const reply = buildOutboxReply(input);
|
|
62
|
+
const path = outboxPathFor(issue, options);
|
|
63
|
+
appendJsonLine(path, reply);
|
|
64
|
+
return reply;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Write multiple inbox messages atomically (temp file + rename).
|
|
68
|
+
* Useful when seeding a relay dir from a backup or replaying. Single-message
|
|
69
|
+
* writes should use `appendInboxMessage` instead.
|
|
70
|
+
*/
|
|
71
|
+
export function writeInboxBatchAtomic(issue, messages, options = {}) {
|
|
72
|
+
const path = inboxPathFor(issue, options);
|
|
73
|
+
writeJsonLinesAtomic(path, messages);
|
|
74
|
+
}
|
|
75
|
+
function appendJsonLine(path, payload) {
|
|
76
|
+
ensureDir(path);
|
|
77
|
+
const line = JSON.stringify(payload) + "\n";
|
|
78
|
+
const fd = openSync(path, "a");
|
|
79
|
+
try {
|
|
80
|
+
writeSync(fd, line);
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
closeSync(fd);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function writeJsonLinesAtomic(path, items) {
|
|
87
|
+
ensureDir(path);
|
|
88
|
+
const body = items.map((it) => JSON.stringify(it)).join("\n") +
|
|
89
|
+
(items.length ? "\n" : "");
|
|
90
|
+
// Temp file must live on the SAME filesystem as `path` for rename() to be atomic.
|
|
91
|
+
const tmp = join(dirname(path), `.relay-tmp.${process.pid}.${Date.now()}.${randomBytes(4).toString("hex")}`);
|
|
92
|
+
try {
|
|
93
|
+
const fd = openSync(tmp, "w");
|
|
94
|
+
try {
|
|
95
|
+
writeSync(fd, body);
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
closeSync(fd);
|
|
99
|
+
}
|
|
100
|
+
renameSync(tmp, path);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
if (existsSync(tmp)) {
|
|
104
|
+
try {
|
|
105
|
+
unlinkSync(tmp);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
/* swallow */
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
throw err;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -42,7 +42,10 @@ export interface AgentSettings {
|
|
|
42
42
|
/**
|
|
43
43
|
* Default model for sub-agents.
|
|
44
44
|
* Options: "haiku" (cheapest), "sonnet" (balanced), "opus" (most capable)
|
|
45
|
-
* Default: "haiku"
|
|
45
|
+
* Default: "haiku" — currently inert per anthropics/claude-code#43869.
|
|
46
|
+
* @deprecated currently inert; see anthropics/claude-code#43869. Subagents
|
|
47
|
+
* inherit the parent session's model regardless of this value. Kept so
|
|
48
|
+
* existing user settings.json files continue to parse without error.
|
|
46
49
|
*/
|
|
47
50
|
model: "haiku" | "sonnet" | "opus";
|
|
48
51
|
/**
|
|
@@ -144,6 +147,13 @@ export interface RunSettings {
|
|
|
144
147
|
* Aider-specific configuration. Only used when agent is "aider".
|
|
145
148
|
*/
|
|
146
149
|
aider?: AiderSettings;
|
|
150
|
+
/**
|
|
151
|
+
* Enable interactive relay (#383): file-based IPC that lets a user terminal
|
|
152
|
+
* send `query`/`directive`/`abort` messages into a running headless session
|
|
153
|
+
* via the PostToolUse hook. Disable with `--no-relay`.
|
|
154
|
+
* Default: true.
|
|
155
|
+
*/
|
|
156
|
+
relay?: boolean;
|
|
147
157
|
}
|
|
148
158
|
/**
|
|
149
159
|
* Scope assessment threshold configuration
|
|
@@ -210,6 +220,20 @@ export interface QASettings {
|
|
|
210
220
|
* Default: 100
|
|
211
221
|
*/
|
|
212
222
|
smallDiffThreshold: number;
|
|
223
|
+
/**
|
|
224
|
+
* When a diff touches only markdown files, treat pending CI checks that match
|
|
225
|
+
* `markdownOnlySafeCiPatterns` as informational instead of forcing
|
|
226
|
+
* `NEEDS_VERIFICATION`. Failed checks always gate regardless of this setting.
|
|
227
|
+
* Default: true
|
|
228
|
+
*/
|
|
229
|
+
markdownOnlyCiRelaxed: boolean;
|
|
230
|
+
/**
|
|
231
|
+
* Glob patterns for CI check names that are safe to ignore when pending on a
|
|
232
|
+
* markdown-only diff (e.g., build matrix, plugin structure validation).
|
|
233
|
+
* Consumer projects should override these to match their CI step names.
|
|
234
|
+
* Default: ["build (*)", "Plugin Structure Validation"]
|
|
235
|
+
*/
|
|
236
|
+
markdownOnlySafeCiPatterns: string[];
|
|
213
237
|
}
|
|
214
238
|
/**
|
|
215
239
|
* Full settings schema
|
|
@@ -277,6 +301,7 @@ export declare const RunSettingsSchema: z.ZodObject<{
|
|
|
277
301
|
editFormat: z.ZodOptional<z.ZodString>;
|
|
278
302
|
extraArgs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
279
303
|
}, z.core.$strip>>;
|
|
304
|
+
relay: z.ZodDefault<z.ZodBoolean>;
|
|
280
305
|
}, z.core.$strip>;
|
|
281
306
|
/** Zod schema for ScopeThreshold (base — fields required, no defaults) */
|
|
282
307
|
export declare const ScopeThresholdSchema: z.ZodObject<{
|
|
@@ -318,6 +343,8 @@ export declare const ScopeAssessmentSettingsSchema: z.ZodObject<{
|
|
|
318
343
|
/** Zod schema for QASettings */
|
|
319
344
|
export declare const QASettingsSchema: z.ZodObject<{
|
|
320
345
|
smallDiffThreshold: z.ZodDefault<z.ZodNumber>;
|
|
346
|
+
markdownOnlyCiRelaxed: z.ZodDefault<z.ZodBoolean>;
|
|
347
|
+
markdownOnlySafeCiPatterns: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
321
348
|
}, z.core.$strip>;
|
|
322
349
|
/**
|
|
323
350
|
* Zod schema for the full SequantSettings (AC-1, AC-5).
|
|
@@ -359,6 +386,7 @@ export declare const SettingsSchema: z.ZodObject<{
|
|
|
359
386
|
editFormat: z.ZodOptional<z.ZodString>;
|
|
360
387
|
extraArgs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
361
388
|
}, z.core.$strip>>;
|
|
389
|
+
relay: z.ZodDefault<z.ZodBoolean>;
|
|
362
390
|
}, z.core.$strip>>;
|
|
363
391
|
agents: z.ZodDefault<z.ZodObject<{
|
|
364
392
|
parallel: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -397,6 +425,8 @@ export declare const SettingsSchema: z.ZodObject<{
|
|
|
397
425
|
}, z.core.$strip>>;
|
|
398
426
|
qa: z.ZodDefault<z.ZodObject<{
|
|
399
427
|
smallDiffThreshold: z.ZodDefault<z.ZodNumber>;
|
|
428
|
+
markdownOnlyCiRelaxed: z.ZodDefault<z.ZodBoolean>;
|
|
429
|
+
markdownOnlySafeCiPatterns: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
400
430
|
}, z.core.$strip>>;
|
|
401
431
|
}, z.core.$loose>;
|
|
402
432
|
/** A single validation warning about an unknown or invalid setting */
|
package/dist/src/lib/settings.js
CHANGED
|
@@ -57,6 +57,7 @@ export const RunSettingsSchema = z.object({
|
|
|
57
57
|
devUrl: z.string().optional(),
|
|
58
58
|
agent: z.string().optional(),
|
|
59
59
|
aider: AiderSettingsSchema.optional(),
|
|
60
|
+
relay: z.boolean().default(true),
|
|
60
61
|
});
|
|
61
62
|
/** Zod schema for ScopeThreshold (base — fields required, no defaults) */
|
|
62
63
|
export const ScopeThresholdSchema = z.object({
|
|
@@ -121,6 +122,10 @@ export const ScopeAssessmentSettingsSchema = z.object({
|
|
|
121
122
|
/** Zod schema for QASettings */
|
|
122
123
|
export const QASettingsSchema = z.object({
|
|
123
124
|
smallDiffThreshold: z.number().default(100),
|
|
125
|
+
markdownOnlyCiRelaxed: z.boolean().default(true),
|
|
126
|
+
markdownOnlySafeCiPatterns: z
|
|
127
|
+
.array(z.string())
|
|
128
|
+
.default(["build (*)", "Plugin Structure Validation"]),
|
|
124
129
|
});
|
|
125
130
|
/**
|
|
126
131
|
* Zod schema for the full SequantSettings (AC-1, AC-5).
|
|
@@ -167,6 +172,7 @@ const KNOWN_KEYS = {
|
|
|
167
172
|
"devUrl",
|
|
168
173
|
"agent",
|
|
169
174
|
"aider",
|
|
175
|
+
"relay",
|
|
170
176
|
]),
|
|
171
177
|
agents: new Set(["parallel", "model", "isolateParallel"]),
|
|
172
178
|
scopeAssessment: new Set([
|
|
@@ -175,7 +181,11 @@ const KNOWN_KEYS = {
|
|
|
175
181
|
"trivialThresholds",
|
|
176
182
|
"thresholds",
|
|
177
183
|
]),
|
|
178
|
-
qa: new Set([
|
|
184
|
+
qa: new Set([
|
|
185
|
+
"smallDiffThreshold",
|
|
186
|
+
"markdownOnlyCiRelaxed",
|
|
187
|
+
"markdownOnlySafeCiPatterns",
|
|
188
|
+
]),
|
|
179
189
|
"run.rotation": new Set(["enabled", "maxSizeMB", "maxFiles"]),
|
|
180
190
|
"run.aider": new Set(["model", "editFormat", "extraArgs"]),
|
|
181
191
|
"scopeAssessment.trivialThresholds": new Set([
|
|
@@ -310,6 +320,8 @@ export const DEFAULT_SCOPE_ASSESSMENT_SETTINGS = {
|
|
|
310
320
|
*/
|
|
311
321
|
export const DEFAULT_QA_SETTINGS = {
|
|
312
322
|
smallDiffThreshold: 100,
|
|
323
|
+
markdownOnlyCiRelaxed: true,
|
|
324
|
+
markdownOnlySafeCiPatterns: ["build (*)", "Plugin Structure Validation"],
|
|
313
325
|
};
|
|
314
326
|
/**
|
|
315
327
|
* Default settings
|
|
@@ -331,6 +343,7 @@ export const DEFAULT_SETTINGS = {
|
|
|
331
343
|
retry: true, // Enable automatic retry with MCP fallback by default
|
|
332
344
|
staleBranchThreshold: 5, // Block QA/test if feature is >5 commits behind main
|
|
333
345
|
resolvedIssueTTL: 7, // Auto-prune resolved issues after 7 days
|
|
346
|
+
relay: true, // Enable interactive relay (#383) by default
|
|
334
347
|
},
|
|
335
348
|
agents: DEFAULT_AGENT_SETTINGS,
|
|
336
349
|
scopeAssessment: DEFAULT_SCOPE_ASSESSMENT_SETTINGS,
|
|
@@ -482,7 +495,7 @@ export function generateSettingsJsonc(settings) {
|
|
|
482
495
|
lines.push(` "agents": {`);
|
|
483
496
|
lines.push(` // Run agents in parallel (faster, higher token usage)`);
|
|
484
497
|
lines.push(` "parallel": ${JSON.stringify(settings.agents.parallel)},`);
|
|
485
|
-
lines.push(` // Default model for sub-agents ("haiku", "sonnet", "opus")`);
|
|
498
|
+
lines.push(` // Default model for sub-agents ("haiku", "sonnet", "opus") — currently inert per anthropics/claude-code#43869`);
|
|
486
499
|
lines.push(` "model": ${JSON.stringify(settings.agents.model)},`);
|
|
487
500
|
lines.push(` // Isolate parallel agent groups in separate worktrees`);
|
|
488
501
|
lines.push(` "isolateParallel": ${JSON.stringify(settings.agents.isolateParallel)}`);
|
|
@@ -597,7 +610,7 @@ Generated by \`sequant init\`. See defaults below.
|
|
|
597
610
|
| Key | Type | Default | Description |
|
|
598
611
|
|-----|------|---------|-------------|
|
|
599
612
|
| \`parallel\` | boolean | \`false\` | Run agents in parallel (faster, higher token usage) |
|
|
600
|
-
| \`model\` | enum | \`"haiku"\` | Default model: \`"haiku"\`, \`"sonnet"\`, or \`"opus"
|
|
613
|
+
| \`model\` | enum | \`"haiku"\` | Default model: \`"haiku"\`, \`"sonnet"\`, or \`"opus"\`. **Currently inert** per [anthropics/claude-code#43869](https://github.com/anthropics/claude-code/issues/43869) — subagents inherit the parent session's model. Kept for forward compatibility. |
|
|
601
614
|
| \`isolateParallel\` | boolean | \`false\` | Isolate parallel agents in separate worktrees |
|
|
602
615
|
|
|
603
616
|
## \`scopeAssessment\` — Scope Assessment Settings
|
|
@@ -630,6 +643,8 @@ Each threshold has \`yellow\` (warning) and \`red\` (split recommended) values:
|
|
|
630
643
|
| Key | Type | Default | Description |
|
|
631
644
|
|-----|------|---------|-------------|
|
|
632
645
|
| \`smallDiffThreshold\` | number | \`100\` | Diff size threshold for small-diff fast path |
|
|
646
|
+
| \`markdownOnlyCiRelaxed\` | boolean | \`true\` | When diff touches only \`.md\` files, treat pending CI checks matching \`markdownOnlySafeCiPatterns\` as informational |
|
|
647
|
+
| \`markdownOnlySafeCiPatterns\` | string[] | \`["build (*)", "Plugin Structure Validation"]\` | Glob patterns for CI checks that are safe to ignore when pending on a markdown-only diff |
|
|
633
648
|
|
|
634
649
|
---
|
|
635
650
|
|