@sayknow-cli/coding-agent 0.3.7 → 0.3.8
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/types/append-only-mode.d.ts +31 -0
- package/dist/types/capability/rule.d.ts +8 -0
- package/dist/types/cli/completion-cli.d.ts +41 -0
- package/dist/types/cli/config-cli.d.ts +1 -0
- package/dist/types/cli/fixture-report.d.ts +20 -0
- package/dist/types/cli/fixture-report.test.d.ts +1 -0
- package/dist/types/cli/nofile-limit.d.ts +11 -0
- package/dist/types/cli/notify-cli.d.ts +7 -0
- package/dist/types/cli/update-cli.d.ts +22 -0
- package/dist/types/cli.d.ts +124 -1
- package/dist/types/commands/completion.d.ts +29 -0
- package/dist/types/commands/config.d.ts +3 -0
- package/dist/types/commands/deep-interview.d.ts +3 -0
- package/dist/types/config/file-lock.d.ts +7 -6
- package/dist/types/config/keybindings.d.ts +2 -2
- package/dist/types/config/model-profile-activation.d.ts +6 -0
- package/dist/types/config/model-profiles.d.ts +1 -0
- package/dist/types/config/settings-schema.d.ts +105 -1
- package/dist/types/config/settings.d.ts +8 -0
- package/dist/types/discovery/index.d.ts +1 -0
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/export/ttsr.d.ts +14 -3
- package/dist/types/extensibility/extensions/runner.d.ts +2 -1
- package/dist/types/extensibility/extensions/types.d.ts +8 -0
- package/dist/types/goals/runtime.d.ts +1 -0
- package/dist/types/hooks/native-skill-hook.d.ts +12 -0
- package/dist/types/main.d.ts +4 -1
- package/dist/types/modes/components/assistant-message.d.ts +5 -1
- package/dist/types/modes/components/model-selector.d.ts +4 -0
- package/dist/types/modes/components/queued-message-selector.d.ts +12 -0
- package/dist/types/modes/components/settings-selector.d.ts +2 -0
- package/dist/types/modes/components/status-line.d.ts +9 -0
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/controllers/event-controller.d.ts +5 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -3
- package/dist/types/modes/interactive-mode.d.ts +2 -0
- package/dist/types/modes/print-mode.d.ts +13 -1
- package/dist/types/modes/prompt-action-autocomplete.d.ts +1 -1
- package/dist/types/modes/rpc/rpc-types.d.ts +14 -0
- package/dist/types/modes/shared/agent-wire/event-contract.d.ts +19 -0
- package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +23 -1
- package/dist/types/modes/types.d.ts +1 -0
- package/dist/types/modes/utils/ui-helpers.d.ts +1 -0
- package/dist/types/notifications/config.d.ts +14 -1
- package/dist/types/notifications/daemon-paths.d.ts +1 -0
- package/dist/types/notifications/index.d.ts +6 -3
- package/dist/types/notifications/lifecycle-commands.d.ts +11 -3
- package/dist/types/notifications/telegram-daemon.d.ts +23 -3
- package/dist/types/notifications/telegram-reference.d.ts +0 -5
- package/dist/types/notifications/threaded-render.d.ts +6 -0
- package/dist/types/runtime-api-key.d.ts +7 -0
- package/dist/types/sdk.d.ts +3 -0
- package/dist/types/session/agent-session.d.ts +61 -6
- package/dist/types/session/agent-storage.d.ts +1 -0
- package/dist/types/session/file-mention-pruning.d.ts +8 -0
- package/dist/types/session/messages.d.ts +4 -0
- package/dist/types/session/session-manager.d.ts +17 -1
- package/dist/types/skc-runtime/deep-interview-ambiguity.d.ts +39 -0
- package/dist/types/skc-runtime/deep-interview-recorder.d.ts +10 -1
- package/dist/types/skc-runtime/deep-interview-state.d.ts +17 -2
- package/dist/types/skc-runtime/session-state-sidecar.d.ts +7 -0
- package/dist/types/skc-runtime/state-writer.d.ts +3 -0
- package/dist/types/skc-runtime/ultragoal-receipt-freshness.d.ts +42 -0
- package/dist/types/skc-runtime/ultragoal-runtime.d.ts +120 -13
- package/dist/types/skill-state/active-state.d.ts +18 -1
- package/dist/types/system-prompt.d.ts +18 -2
- package/dist/types/task/executor.d.ts +3 -0
- package/dist/types/task/fork-context-budget.d.ts +7 -0
- package/dist/types/task/token-log.d.ts +30 -0
- package/dist/types/task/token-log.test.d.ts +1 -0
- package/dist/types/tools/bisect.d.ts +81 -0
- package/dist/types/tools/computer.d.ts +2 -2
- package/dist/types/tools/index.d.ts +1 -0
- package/dist/types/tools/search.d.ts +2 -2
- package/dist/types/tools/ultragoal-ask-guard.d.ts +9 -2
- package/dist/types/utils/file-mentions.d.ts +14 -0
- package/dist/types/utils/git.d.ts +32 -0
- package/dist/types/web/scrapers/youtube.d.ts +8 -0
- package/dist/types/workflow/workflow-intent-diff.d.ts +8 -2
- package/dist/types/workflow/workflow-intent-report-consumer.d.ts +50 -0
- package/dist/types/workflow/workflow-intent-report-schema.d.ts +2 -0
- package/dist/types/workflow/workflow-intent-report.d.ts +48 -0
- package/package.json +8 -8
- package/src/append-only-mode.ts +58 -0
- package/src/autoresearch/prompt.md +1 -1
- package/src/autoresearch/tools/log-experiment.ts +1 -1
- package/src/capability/rule.ts +9 -0
- package/src/cli/completion-cli.ts +234 -0
- package/src/cli/config-cli.ts +61 -9
- package/src/cli/fast-help.ts +1 -0
- package/src/cli/fixture-report.test.ts +230 -0
- package/src/cli/fixture-report.ts +171 -0
- package/src/cli/nofile-limit.ts +48 -0
- package/src/cli/notify-cli.ts +92 -8
- package/src/cli/telegram-cli.ts +1 -1
- package/src/cli/update-cli.ts +85 -9
- package/src/cli.ts +29 -1
- package/src/commands/completion.ts +84 -0
- package/src/commands/config.ts +2 -0
- package/src/commands/contribution-prep.ts +1 -1
- package/src/commands/deep-interview.ts +2 -1
- package/src/config/file-lock.ts +73 -34
- package/src/config/keybindings.ts +2 -2
- package/src/config/model-profile-activation.ts +65 -0
- package/src/config/model-profiles.ts +31 -2
- package/src/config/settings-schema.ts +68 -1
- package/src/config/settings.ts +22 -0
- package/src/defaults/skc/skills/team/SKILL.md +17 -14
- package/src/defaults/skc/skills/ultragoal/SKILL.md +59 -4
- package/src/defaults/skc/skills/ultragoal/pipeline-validation-contracts.md +30 -0
- package/src/defaults/skc-defaults.ts +9 -0
- package/src/discovery/helpers.ts +10 -0
- package/src/discovery/index.ts +1 -0
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +60 -2
- package/src/export/ttsr.ts +96 -18
- package/src/extensibility/extensions/runner.ts +183 -219
- package/src/extensibility/extensions/types.ts +9 -0
- package/src/extensibility/skc-plugins/runtime-adapters.ts +156 -44
- package/src/goals/runtime.ts +10 -2
- package/src/hindsight/backend.ts +1 -3
- package/src/hooks/native-skill-hook.ts +124 -4
- package/src/internal-urls/docs-index.generated.ts +14 -5
- package/src/main.ts +95 -43
- package/src/memories/index.ts +12 -1
- package/src/modes/components/assistant-message.ts +241 -82
- package/src/modes/components/custom-editor.ts +1 -0
- package/src/modes/components/model-selector.ts +54 -11
- package/src/modes/components/queued-message-selector.ts +92 -0
- package/src/modes/components/settings-selector.ts +4 -0
- package/src/modes/components/status-line.ts +167 -54
- package/src/modes/components/tool-execution.ts +44 -19
- package/src/modes/components/welcome.ts +181 -44
- package/src/modes/controllers/command-controller.ts +40 -4
- package/src/modes/controllers/event-controller.ts +66 -47
- package/src/modes/controllers/extension-ui-controller.ts +4 -10
- package/src/modes/controllers/input-controller.ts +180 -18
- package/src/modes/controllers/selector-controller.ts +127 -24
- package/src/modes/interactive-mode.ts +51 -16
- package/src/modes/print-mode.ts +43 -4
- package/src/modes/prompt-action-autocomplete.ts +21 -20
- package/src/modes/rpc/rpc-mode.ts +29 -3
- package/src/modes/rpc/rpc-types.ts +9 -0
- package/src/modes/shared/agent-wire/command-validation.ts +4 -0
- package/src/modes/shared/agent-wire/event-contract.ts +22 -0
- package/src/modes/shared/agent-wire/event-envelope.ts +82 -0
- package/src/modes/shared/agent-wire/scopes.ts +1 -0
- package/src/modes/types.ts +1 -0
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +20 -7
- package/src/notifications/config.ts +25 -5
- package/src/notifications/daemon-paths.ts +2 -0
- package/src/notifications/index.ts +117 -14
- package/src/notifications/lifecycle-commands.ts +37 -7
- package/src/notifications/lifecycle-orchestrator.ts +19 -6
- package/src/notifications/telegram-daemon-control.ts +5 -3
- package/src/notifications/telegram-daemon.ts +302 -51
- package/src/notifications/telegram-reference.ts +0 -16
- package/src/notifications/threaded-render.ts +17 -1
- package/src/prompts/agents/architect.md +19 -10
- package/src/prompts/agents/critic.md +16 -18
- package/src/prompts/agents/executor.md +14 -11
- package/src/prompts/agents/planner.md +18 -13
- package/src/prompts/ci-green-request.md +3 -8
- package/src/prompts/goals/goal-continuation.md +0 -5
- package/src/prompts/goals/goal-mode-active.md +0 -5
- package/src/prompts/system/agent-creation-architect.md +2 -2
- package/src/prompts/system/plan-mode-active.md +1 -1
- package/src/prompts/system/plan-mode-subagent.md +3 -3
- package/src/prompts/system/project-prompt.md +0 -13
- package/src/prompts/system/subagent-system-prompt.md +3 -2
- package/src/prompts/system/system-prompt.md +29 -17
- package/src/prompts/system/volatile-project-context.md +10 -0
- package/src/prompts/system/web-search.md +4 -7
- package/src/prompts/tools/apply-patch.md +6 -0
- package/src/prompts/tools/ast-edit.md +1 -0
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/bisect.md +22 -0
- package/src/prompts/tools/browser.md +1 -1
- package/src/prompts/tools/computer.md +2 -2
- package/src/prompts/tools/cron.md +0 -2
- package/src/prompts/tools/eval.md +2 -2
- package/src/prompts/tools/find.md +1 -1
- package/src/prompts/tools/github.md +6 -6
- package/src/prompts/tools/goal.md +1 -3
- package/src/prompts/tools/image-gen.md +12 -5
- package/src/prompts/tools/irc.md +5 -4
- package/src/prompts/tools/job.md +2 -2
- package/src/prompts/tools/lsp.md +1 -1
- package/src/prompts/tools/monitor.md +2 -2
- package/src/prompts/tools/patch.md +2 -2
- package/src/prompts/tools/replace.md +2 -21
- package/src/prompts/tools/rewind.md +1 -1
- package/src/prompts/tools/search-tool-bm25.md +1 -11
- package/src/prompts/tools/search.md +1 -1
- package/src/prompts/tools/skill.md +3 -2
- package/src/prompts/tools/ssh.md +2 -1
- package/src/prompts/tools/subagent.md +2 -2
- package/src/prompts/tools/task.md +4 -5
- package/src/prompts/tools/todo-write.md +1 -1
- package/src/prompts/tools/vim.md +1 -0
- package/src/prompts/tools/web-search.md +2 -0
- package/src/prompts/tools/write.md +8 -2
- package/src/runtime-api-key.ts +16 -0
- package/src/sdk.ts +52 -28
- package/src/session/agent-session.ts +1011 -141
- package/src/session/agent-storage.ts +4 -0
- package/src/session/file-mention-pruning.ts +64 -0
- package/src/session/messages.ts +4 -0
- package/src/session/session-manager.ts +103 -4
- package/src/skc-runtime/deep-interview-ambiguity.ts +206 -0
- package/src/skc-runtime/deep-interview-recorder.ts +62 -8
- package/src/skc-runtime/deep-interview-state.ts +44 -2
- package/src/skc-runtime/session-state-sidecar.ts +263 -20
- package/src/skc-runtime/state-runtime.ts +12 -2
- package/src/skc-runtime/state-writer.ts +15 -0
- package/src/skc-runtime/ultragoal-guard.ts +55 -66
- package/src/skc-runtime/ultragoal-receipt-freshness.ts +315 -0
- package/src/skc-runtime/ultragoal-runtime.ts +1663 -159
- package/src/skc-runtime/workflow-manifest.generated.json +113 -2
- package/src/skc-runtime/workflow-manifest.ts +74 -1
- package/src/skill-state/active-state.ts +141 -5
- package/src/skill-state/deep-interview-mutation-guard.ts +67 -3
- package/src/slash-commands/builtin-registry.ts +218 -71
- package/src/system-prompt.ts +57 -16
- package/src/task/executor.ts +132 -24
- package/src/task/fork-context-advisory.ts +2 -7
- package/src/task/fork-context-budget.ts +9 -0
- package/src/task/index.ts +13 -6
- package/src/task/output-manager.ts +20 -8
- package/src/task/receipt.ts +26 -7
- package/src/task/token-log.test.ts +188 -0
- package/src/task/token-log.ts +179 -0
- package/src/tools/bisect.ts +367 -0
- package/src/tools/computer.ts +246 -43
- package/src/tools/index.ts +3 -0
- package/src/tools/output-meta.ts +116 -4
- package/src/tools/search.ts +8 -2
- package/src/tools/skill.ts +15 -0
- package/src/tools/telegram-send.ts +6 -0
- package/src/tools/ultragoal-ask-guard.ts +39 -5
- package/src/utils/file-mentions.ts +39 -7
- package/src/utils/git.ts +73 -0
- package/src/web/scrapers/youtube.ts +24 -12
- package/src/workflow/workflow-intent-diff.ts +29 -6
- package/src/workflow/workflow-intent-report-consumer.ts +221 -0
- package/src/workflow/workflow-intent-report-schema.ts +129 -0
- package/src/workflow/workflow-intent-report.ts +135 -0
|
@@ -8,6 +8,7 @@ export default class DeepInterview extends Command {
|
|
|
8
8
|
quick: Flags.boolean({ description: "Seed a quick deep-interview run" }),
|
|
9
9
|
standard: Flags.boolean({ description: "Seed a standard deep-interview run" }),
|
|
10
10
|
deep: Flags.boolean({ description: "Seed a deep deep-interview run" }),
|
|
11
|
+
trace: Flags.boolean({ description: "Run a bounded trace evidence pre-step before interview questions" }),
|
|
11
12
|
threshold: Flags.string({ description: "Override ambiguity threshold for kickoff" }),
|
|
12
13
|
"threshold-source": Flags.string({ description: "Describe the threshold override source" }),
|
|
13
14
|
"session-id": Flags.string({
|
|
@@ -25,7 +26,7 @@ export default class DeepInterview extends Command {
|
|
|
25
26
|
json: Flags.boolean({ description: "Output JSON" }),
|
|
26
27
|
};
|
|
27
28
|
static examples = [
|
|
28
|
-
'$ skc deep-interview --standard "<idea>"',
|
|
29
|
+
'$ skc deep-interview --trace --standard "<idea>"',
|
|
29
30
|
"$ skc deep-interview --write --stage final --slug my-feature --spec ./final-spec.md",
|
|
30
31
|
"$ skc deep-interview --write --stage final --slug my-feature --spec ./final-spec.md --deliberate",
|
|
31
32
|
];
|
package/src/config/file-lock.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Stats } from "node:fs";
|
|
1
2
|
import * as fs from "node:fs/promises";
|
|
2
3
|
import { isEnoent } from "@sayknow-cli/utils/fs-error";
|
|
3
4
|
|
|
@@ -22,9 +23,10 @@ function getLockPath(filePath: string): string {
|
|
|
22
23
|
return `${filePath}.lock`;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
async function writeLockInfo(lockPath: string): Promise<
|
|
26
|
+
async function writeLockInfo(lockPath: string): Promise<LockInfo> {
|
|
26
27
|
const info: LockInfo = { pid: process.pid, timestamp: Date.now() };
|
|
27
28
|
await Bun.write(`${lockPath}/info`, JSON.stringify(info));
|
|
29
|
+
return info;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
async function readLockInfo(lockPath: string): Promise<LockInfo | null> {
|
|
@@ -51,17 +53,30 @@ export interface FileLockOwnerToken {
|
|
|
51
53
|
timestamp: number;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
/** Outcome of a guarded
|
|
56
|
+
/** Outcome of a guarded lock-dir removal attempt (`removeFileLockDirForGc`). */
|
|
55
57
|
export type FileLockGcRemoval = "removed" | "owner_changed" | "missing";
|
|
56
58
|
|
|
59
|
+
interface LockDirStatToken {
|
|
60
|
+
dev: number;
|
|
61
|
+
ino: number;
|
|
62
|
+
mtimeMs: number;
|
|
63
|
+
ctimeMs: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
type LockStaleSnapshot =
|
|
67
|
+
| { stale: false }
|
|
68
|
+
| { stale: true; owner: FileLockOwnerToken }
|
|
69
|
+
| { stale: true; owner: null; stat: LockDirStatToken };
|
|
70
|
+
|
|
57
71
|
/**
|
|
58
72
|
* @internal
|
|
59
|
-
* Fail-closed removal of a
|
|
60
|
-
* token as close to the unlink as possible
|
|
61
|
-
* STILL holds the exact `{pid, timestamp}`
|
|
73
|
+
* Fail-closed removal of a lock dir whose owner is expected to be dead or
|
|
74
|
+
* finished. Re-reads the on-disk owner token as close to the unlink as possible
|
|
75
|
+
* and only deletes the dir when it STILL holds the exact `{pid, timestamp}`
|
|
76
|
+
* identity the caller observed.
|
|
62
77
|
*
|
|
63
|
-
* Closes
|
|
64
|
-
*
|
|
78
|
+
* Closes stale-cleanup TOCTOU windows (#606): between a dead/stale re-read and
|
|
79
|
+
* the unlink, a live process can reclaim a stale lock at the same path
|
|
65
80
|
* (`acquireLock` rms the stale dir, then re-`mkdir`s and rewrites `info` with a
|
|
66
81
|
* fresh pid+timestamp). Deleting by path alone would reap that LIVE lock. Any
|
|
67
82
|
* mismatch (`owner_changed`) or absent/unreadable info (`missing` — e.g. a
|
|
@@ -99,14 +114,28 @@ function ownerLiveness(pid: number): OwnerLiveness {
|
|
|
99
114
|
}
|
|
100
115
|
}
|
|
101
116
|
|
|
102
|
-
|
|
117
|
+
function statToken(stats: Stats): LockDirStatToken {
|
|
118
|
+
return {
|
|
119
|
+
dev: stats.dev,
|
|
120
|
+
ino: stats.ino,
|
|
121
|
+
mtimeMs: stats.mtimeMs,
|
|
122
|
+
ctimeMs: stats.ctimeMs,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function sameStatToken(a: LockDirStatToken, b: LockDirStatToken): boolean {
|
|
127
|
+
return a.dev === b.dev && a.ino === b.ino && a.mtimeMs === b.mtimeMs && a.ctimeMs === b.ctimeMs;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function staleLockSnapshot(lockPath: string, staleMs: number): Promise<LockStaleSnapshot> {
|
|
103
131
|
const info = await readLockInfo(lockPath);
|
|
104
132
|
if (!info) {
|
|
105
133
|
try {
|
|
106
134
|
const stats = await fs.stat(lockPath);
|
|
107
|
-
|
|
135
|
+
if (Date.now() - stats.mtimeMs <= staleMs) return { stale: false };
|
|
136
|
+
return { stale: true, owner: null, stat: statToken(stats) };
|
|
108
137
|
} catch (err) {
|
|
109
|
-
if (isEnoent(err)) return false;
|
|
138
|
+
if (isEnoent(err)) return { stale: false };
|
|
110
139
|
throw err;
|
|
111
140
|
}
|
|
112
141
|
}
|
|
@@ -115,53 +144,63 @@ async function isLockStale(lockPath: string, staleMs: number): Promise<boolean>
|
|
|
115
144
|
// not have its lock stolen (#652). Reclaim a dead owner immediately. Only when owner
|
|
116
145
|
// liveness is indeterminate do we fall back to the staleMs elapsed-time heuristic.
|
|
117
146
|
const liveness = ownerLiveness(info.pid);
|
|
118
|
-
if (liveness === "
|
|
119
|
-
if (liveness === "
|
|
120
|
-
|
|
147
|
+
if (liveness === "alive") return { stale: false };
|
|
148
|
+
if (liveness === "dead" || Date.now() - info.timestamp > staleMs) {
|
|
149
|
+
return { stale: true, owner: { pid: info.pid, timestamp: info.timestamp } };
|
|
150
|
+
}
|
|
151
|
+
return { stale: false };
|
|
121
152
|
}
|
|
122
153
|
|
|
123
|
-
async function
|
|
154
|
+
async function removeStaleLockForAcquire(lockPath: string, snapshot: LockStaleSnapshot): Promise<boolean> {
|
|
155
|
+
if (!snapshot.stale) return false;
|
|
156
|
+
if (snapshot.owner) {
|
|
157
|
+
return (await removeFileLockDirForGc(lockPath, snapshot.owner)) === "removed";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const currentInfo = await readLockInfo(lockPath);
|
|
161
|
+
if (currentInfo) return false;
|
|
124
162
|
try {
|
|
125
|
-
await fs.
|
|
126
|
-
|
|
163
|
+
const currentStats = await fs.stat(lockPath);
|
|
164
|
+
if (!sameStatToken(statToken(currentStats), snapshot.stat)) return false;
|
|
165
|
+
await fs.rm(lockPath, { recursive: true, force: true });
|
|
127
166
|
return true;
|
|
167
|
+
} catch (err) {
|
|
168
|
+
if (isEnoent(err)) return false;
|
|
169
|
+
throw err;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async function tryAcquireLock(lockPath: string): Promise<LockInfo | null> {
|
|
174
|
+
try {
|
|
175
|
+
await fs.mkdir(lockPath);
|
|
176
|
+
return await writeLockInfo(lockPath);
|
|
128
177
|
} catch (error) {
|
|
129
178
|
if ((error as NodeJS.ErrnoException).code === "EEXIST") {
|
|
130
|
-
return
|
|
179
|
+
return null;
|
|
131
180
|
}
|
|
132
181
|
throw error;
|
|
133
182
|
}
|
|
134
183
|
}
|
|
135
184
|
|
|
136
|
-
async function releaseLock(lockPath: string): Promise<void> {
|
|
185
|
+
async function releaseLock(lockPath: string, owner: FileLockOwnerToken): Promise<void> {
|
|
137
186
|
try {
|
|
138
|
-
await
|
|
187
|
+
await removeFileLockDirForGc(lockPath, owner);
|
|
139
188
|
} catch {
|
|
140
189
|
// Ignore errors on release
|
|
141
190
|
}
|
|
142
191
|
}
|
|
143
|
-
|
|
144
|
-
async function lockExists(lockPath: string): Promise<boolean> {
|
|
145
|
-
try {
|
|
146
|
-
await fs.stat(lockPath);
|
|
147
|
-
return true;
|
|
148
|
-
} catch (err) {
|
|
149
|
-
if (isEnoent(err)) return false;
|
|
150
|
-
throw err;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
192
|
async function acquireLock(filePath: string, options: FileLockOptions = {}): Promise<() => Promise<void>> {
|
|
155
193
|
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
156
194
|
const lockPath = getLockPath(filePath);
|
|
157
195
|
|
|
158
196
|
for (let attempt = 0; attempt < opts.retries; attempt++) {
|
|
159
|
-
|
|
160
|
-
|
|
197
|
+
const owner = await tryAcquireLock(lockPath);
|
|
198
|
+
if (owner) {
|
|
199
|
+
return () => releaseLock(lockPath, owner);
|
|
161
200
|
}
|
|
162
201
|
|
|
163
|
-
|
|
164
|
-
|
|
202
|
+
const stale = await staleLockSnapshot(lockPath, opts.staleMs);
|
|
203
|
+
if (await removeStaleLockForAcquire(lockPath, stale)) {
|
|
165
204
|
continue;
|
|
166
205
|
}
|
|
167
206
|
|
|
@@ -134,8 +134,8 @@ export const KEYBINDINGS = {
|
|
|
134
134
|
description: "Queue message for next turn",
|
|
135
135
|
},
|
|
136
136
|
"app.message.dequeue": {
|
|
137
|
-
defaultKeys: "alt+up",
|
|
138
|
-
description: "
|
|
137
|
+
defaultKeys: ["alt+up", "alt+down"],
|
|
138
|
+
description: "Select queued message to edit",
|
|
139
139
|
},
|
|
140
140
|
"app.clipboard.pasteImage": {
|
|
141
141
|
defaultKeys: process.platform === "win32" ? "alt+v" : "ctrl+v",
|
|
@@ -76,6 +76,34 @@ export interface MaterializeModelProfileAssignmentOptions {
|
|
|
76
76
|
selector: string;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
export interface MaterializeModelProfileAssignmentsOptions {
|
|
80
|
+
session: Pick<
|
|
81
|
+
ModelProfileActivationSession,
|
|
82
|
+
"model" | "thinkingLevel" | "setActiveModelProfile" | "getActiveModelProfile"
|
|
83
|
+
>;
|
|
84
|
+
settings: Pick<Settings, "clearOverride" | "get" | "override" | "set">;
|
|
85
|
+
assignments: ReadonlyMap<SkcModelAssignmentTargetId, string> | Partial<Record<SkcModelAssignmentTargetId, string>>;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function isReadonlyAssignmentMap(
|
|
89
|
+
assignments: ReadonlyMap<SkcModelAssignmentTargetId, string> | Partial<Record<SkcModelAssignmentTargetId, string>>,
|
|
90
|
+
): assignments is ReadonlyMap<SkcModelAssignmentTargetId, string> {
|
|
91
|
+
return typeof (assignments as { entries?: unknown }).entries === "function";
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function getMaterializedAssignments(
|
|
95
|
+
assignments: ReadonlyMap<SkcModelAssignmentTargetId, string> | Partial<Record<SkcModelAssignmentTargetId, string>>,
|
|
96
|
+
): Array<[SkcModelAssignmentTargetId, string]> {
|
|
97
|
+
if (isReadonlyAssignmentMap(assignments)) return [...assignments.entries()];
|
|
98
|
+
const assignmentRecord: Partial<Record<SkcModelAssignmentTargetId, string>> = assignments;
|
|
99
|
+
const result: Array<[SkcModelAssignmentTargetId, string]> = [];
|
|
100
|
+
for (const role of Object.keys(assignmentRecord) as SkcModelAssignmentTargetId[]) {
|
|
101
|
+
const selector = assignmentRecord[role];
|
|
102
|
+
if (selector !== undefined) result.push([role, selector]);
|
|
103
|
+
}
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
|
|
79
107
|
export function materializeActiveModelProfileAssignment(options: MaterializeModelProfileAssignmentOptions): boolean {
|
|
80
108
|
const activeProfile = options.session.getActiveModelProfile?.() ?? options.settings.get("modelProfile.default");
|
|
81
109
|
if (!activeProfile) return false;
|
|
@@ -109,6 +137,43 @@ export function materializeActiveModelProfileAssignment(options: MaterializeMode
|
|
|
109
137
|
return true;
|
|
110
138
|
}
|
|
111
139
|
|
|
140
|
+
export function materializeActiveModelProfileAssignments(options: MaterializeModelProfileAssignmentsOptions): boolean {
|
|
141
|
+
const activeProfile = options.session.getActiveModelProfile?.() ?? options.settings.get("modelProfile.default");
|
|
142
|
+
if (!activeProfile) return false;
|
|
143
|
+
|
|
144
|
+
const materializedAssignments = getMaterializedAssignments(options.assignments);
|
|
145
|
+
if (materializedAssignments.length === 0) return true;
|
|
146
|
+
|
|
147
|
+
const nextModelRoles = { ...options.settings.get("modelRoles") };
|
|
148
|
+
const nextAgentModelOverrides = { ...options.settings.get("task.agentModelOverrides") };
|
|
149
|
+
const includesDefault = materializedAssignments.some(([role]) => role === "default");
|
|
150
|
+
|
|
151
|
+
if (!includesDefault && !nextModelRoles.default && options.session.model) {
|
|
152
|
+
nextModelRoles.default = formatModelSelectorValue(
|
|
153
|
+
`${options.session.model.provider}/${options.session.model.id}`,
|
|
154
|
+
options.session.thinkingLevel,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
for (const [role, selector] of materializedAssignments) {
|
|
159
|
+
const target = SKC_MODEL_ASSIGNMENT_TARGETS[role];
|
|
160
|
+
if (target.settingsPath === "modelRoles") {
|
|
161
|
+
nextModelRoles[role] = selector;
|
|
162
|
+
} else {
|
|
163
|
+
nextAgentModelOverrides[role] = selector;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
options.settings.set("modelRoles", nextModelRoles);
|
|
168
|
+
options.settings.set("task.agentModelOverrides", nextAgentModelOverrides);
|
|
169
|
+
options.settings.set("modelProfile.default", undefined);
|
|
170
|
+
options.settings.clearOverride("modelProfile.default");
|
|
171
|
+
options.settings.override("modelRoles", nextModelRoles);
|
|
172
|
+
options.settings.override("task.agentModelOverrides", nextAgentModelOverrides);
|
|
173
|
+
options.session.setActiveModelProfile?.(undefined);
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
|
|
112
177
|
export function formatModelProfileCredentialError(profileName: string, providers: readonly string[]): string {
|
|
113
178
|
return `Model profile "${profileName}" requires credentials for: ${providers.join(", ")}. Run /login and configure the missing provider(s), then retry.`;
|
|
114
179
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sanitizeText } from "@sayknow-cli/utils";
|
|
1
2
|
import type { SkcModelAssignmentTargetId } from "./model-registry";
|
|
2
3
|
import type { ModelsConfig } from "./models-config-schema";
|
|
3
4
|
|
|
@@ -98,11 +99,18 @@ export const BUILTIN_MODEL_PROFILES: readonly ModelProfileDefinition[] = [
|
|
|
98
99
|
}),
|
|
99
100
|
profile("claude-opus", ["anthropic"], {
|
|
100
101
|
default: "anthropic/claude-opus-4-8:xhigh",
|
|
101
|
-
executor: "anthropic/claude-sonnet-
|
|
102
|
+
executor: "anthropic/claude-sonnet-5",
|
|
102
103
|
planner: "anthropic/claude-opus-4-8:low",
|
|
103
104
|
critic: "anthropic/claude-opus-4-8:high",
|
|
104
105
|
architect: "anthropic/claude-opus-4-8:xhigh",
|
|
105
106
|
}),
|
|
107
|
+
profile("claude-fable", ["anthropic"], {
|
|
108
|
+
default: "anthropic/claude-fable-5:xhigh",
|
|
109
|
+
executor: "anthropic/claude-sonnet-5",
|
|
110
|
+
planner: "anthropic/claude-fable-5:low",
|
|
111
|
+
critic: "anthropic/claude-fable-5:high",
|
|
112
|
+
architect: "anthropic/claude-fable-5:xhigh",
|
|
113
|
+
}),
|
|
106
114
|
profile("glm-eco", ["zai"], {
|
|
107
115
|
default: "zai/glm-5.2:low",
|
|
108
116
|
executor: "zai/glm-5.2:minimal",
|
|
@@ -260,6 +268,13 @@ export const BUILTIN_MODEL_PROFILES: readonly ModelProfileDefinition[] = [
|
|
|
260
268
|
critic: "opencode-go/mimo-v2.5-pro",
|
|
261
269
|
architect: "openai-codex/gpt-5.5:xhigh",
|
|
262
270
|
}),
|
|
271
|
+
profile("fable-opus-codex", ["anthropic", "openai-codex"], {
|
|
272
|
+
default: "anthropic/claude-fable-5:high",
|
|
273
|
+
executor: "openai-codex/gpt-5.5:high",
|
|
274
|
+
planner: "anthropic/claude-opus-4-8:medium",
|
|
275
|
+
critic: "anthropic/claude-opus-4-8:high",
|
|
276
|
+
architect: "openai-codex/gpt-5.5:xhigh",
|
|
277
|
+
}),
|
|
263
278
|
];
|
|
264
279
|
|
|
265
280
|
export interface ModelProfilePresentation {
|
|
@@ -267,12 +282,17 @@ export interface ModelProfilePresentation {
|
|
|
267
282
|
providerGroup: string;
|
|
268
283
|
}
|
|
269
284
|
|
|
285
|
+
function sanitizeModelProfileLabel(value: string): string {
|
|
286
|
+
return sanitizeText(value).replace(/\s+/g, " ").trim();
|
|
287
|
+
}
|
|
288
|
+
|
|
270
289
|
const PROFILE_PRESENTATION: Record<string, ModelProfilePresentation> = {
|
|
271
290
|
"codex-eco": { displayName: "Codex Eco", providerGroup: "CODEX" },
|
|
272
291
|
"codex-medium": { displayName: "Codex Medium", providerGroup: "CODEX" },
|
|
273
292
|
"codex-pro": { displayName: "Codex Pro", providerGroup: "CODEX" },
|
|
274
293
|
opencodego: { displayName: "OpenCodeGo", providerGroup: "OPENCODEGO" },
|
|
275
294
|
"claude-opus": { displayName: "Claude Opus", providerGroup: "CLAUDE" },
|
|
295
|
+
"claude-fable": { displayName: "Claude Fable", providerGroup: "CLAUDE" },
|
|
276
296
|
"glm-eco": { displayName: "GLM Eco", providerGroup: "GLM" },
|
|
277
297
|
"glm-medium": { displayName: "GLM Medium", providerGroup: "GLM" },
|
|
278
298
|
"glm-pro": { displayName: "GLM Pro", providerGroup: "GLM" },
|
|
@@ -294,6 +314,7 @@ const PROFILE_PRESENTATION: Record<string, ModelProfilePresentation> = {
|
|
|
294
314
|
"minimax-pro": { displayName: "MiniMax Pro", providerGroup: "MINIMAX" },
|
|
295
315
|
"opus-codex": { displayName: "Opus + Codex", providerGroup: "COMBOS" },
|
|
296
316
|
"codex-opencodego": { displayName: "Codex + OpenCodeGo", providerGroup: "COMBOS" },
|
|
317
|
+
"fable-opus-codex": { displayName: "Fable + Opus + Codex", providerGroup: "COMBOS" },
|
|
297
318
|
};
|
|
298
319
|
|
|
299
320
|
const PROFILE_GROUP_ORDER = [
|
|
@@ -332,7 +353,15 @@ export function getModelProfilePresentation(
|
|
|
332
353
|
const displayName = typeof profile === "string" ? undefined : profile.displayName;
|
|
333
354
|
const presentation = PROFILE_PRESENTATION[name];
|
|
334
355
|
if (presentation) return presentation;
|
|
335
|
-
return { displayName:
|
|
356
|
+
return { displayName: formatModelProfileDisplayLabel({ name, displayName }), providerGroup: "CUSTOM" };
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export function formatModelProfileDisplayLabel(profile: Pick<ModelProfileDefinition, "name" | "displayName">): string {
|
|
360
|
+
return (
|
|
361
|
+
sanitizeModelProfileLabel(profile.displayName ?? profile.name) ||
|
|
362
|
+
sanitizeModelProfileLabel(profile.name) ||
|
|
363
|
+
"Unnamed profile"
|
|
364
|
+
);
|
|
336
365
|
}
|
|
337
366
|
|
|
338
367
|
export function groupModelProfilesForPresetLanding(
|
|
@@ -570,6 +570,42 @@ export const SETTINGS_SCHEMA = {
|
|
|
570
570
|
],
|
|
571
571
|
},
|
|
572
572
|
},
|
|
573
|
+
|
|
574
|
+
"tools.readArtifactSpillThreshold": {
|
|
575
|
+
type: "number",
|
|
576
|
+
default: 0,
|
|
577
|
+
ui: {
|
|
578
|
+
tab: "tools",
|
|
579
|
+
label: "Experimental read-tool artifact spill threshold (KB)",
|
|
580
|
+
description:
|
|
581
|
+
"Advanced opt-in only: combined-size cap for `read` output across all requested ranges. Above this the full output is saved as an artifact and a bounded head+tail snippet is kept inline. Live layofflabs/gpt-5.5 medium evidence on 2026-07-07 found no token savings and a lower cache-hit rate at 50 KB, so normal coding sessions should leave this Off unless intentionally measuring large-read behavior.",
|
|
582
|
+
options: [
|
|
583
|
+
{ value: "0", label: "Off", description: "Default; no read-specific spill (backstop only)" },
|
|
584
|
+
{ value: "50", label: "50 KB", description: "~12.5K tokens" },
|
|
585
|
+
{ value: "100", label: "100 KB", description: "~25K tokens" },
|
|
586
|
+
{ value: "256", label: "256 KB", description: "~64K tokens" },
|
|
587
|
+
{ value: "512", label: "512 KB", description: "~128K tokens" },
|
|
588
|
+
{ value: "1000", label: "1 MB", description: "~250K tokens" },
|
|
589
|
+
],
|
|
590
|
+
},
|
|
591
|
+
},
|
|
592
|
+
|
|
593
|
+
"tools.fileMentionInlineBytes": {
|
|
594
|
+
type: "number",
|
|
595
|
+
default: 20,
|
|
596
|
+
ui: {
|
|
597
|
+
tab: "tools",
|
|
598
|
+
label: "File-mention inline cap (KB)",
|
|
599
|
+
description:
|
|
600
|
+
"Inline byte cap for auto-read `@path` file mentions, deliberately below the read-tool cap so an incidental mention injects a smaller snippet than an explicit read. The full file is still available via the read tool.",
|
|
601
|
+
options: [
|
|
602
|
+
{ value: "5", label: "5 KB", description: "~1.25K tokens" },
|
|
603
|
+
{ value: "10", label: "10 KB", description: "~2.5K tokens" },
|
|
604
|
+
{ value: "20", label: "20 KB", description: "Default; ~5K tokens" },
|
|
605
|
+
{ value: "50", label: "50 KB", description: "~12.5K tokens (matches read cap)" },
|
|
606
|
+
],
|
|
607
|
+
},
|
|
608
|
+
},
|
|
573
609
|
"tools.artifactTailBytes": {
|
|
574
610
|
type: "number",
|
|
575
611
|
default: 20,
|
|
@@ -648,6 +684,25 @@ export const SETTINGS_SCHEMA = {
|
|
|
648
684
|
},
|
|
649
685
|
},
|
|
650
686
|
|
|
687
|
+
"tools.maxInlineResultBytes": {
|
|
688
|
+
type: "number",
|
|
689
|
+
default: 0,
|
|
690
|
+
ui: {
|
|
691
|
+
tab: "tools",
|
|
692
|
+
label: "Max inline tool-result size (KB)",
|
|
693
|
+
description:
|
|
694
|
+
"Absolute backstop cap on inline tool-result text, enforced after artifact spill for every tool (including read and tools that set their own partial artifact meta). Output above this size is force-saved as an artifact and truncated to head+tail. 0 disables (default; opt-in pending measurement).",
|
|
695
|
+
options: [
|
|
696
|
+
{ value: "0", label: "Off", description: "Disabled; no absolute inline cap" },
|
|
697
|
+
{ value: "20", label: "20 KB", description: "~5K tokens" },
|
|
698
|
+
{ value: "30", label: "30 KB", description: "~7.5K tokens" },
|
|
699
|
+
{ value: "50", label: "50 KB", description: "~12.5K tokens" },
|
|
700
|
+
{ value: "75", label: "75 KB", description: "~19K tokens" },
|
|
701
|
+
{ value: "100", label: "100 KB", description: "~25K tokens" },
|
|
702
|
+
],
|
|
703
|
+
},
|
|
704
|
+
},
|
|
705
|
+
|
|
651
706
|
"statusLine.showHookStatus": {
|
|
652
707
|
type: "boolean",
|
|
653
708
|
default: false,
|
|
@@ -1410,6 +1465,15 @@ export const SETTINGS_SCHEMA = {
|
|
|
1410
1465
|
|
|
1411
1466
|
"compaction.remoteEndpoint": { type: "string", default: undefined },
|
|
1412
1467
|
|
|
1468
|
+
// Below-threshold maintenance pruning (Finding 13). Internal/measurement-only:
|
|
1469
|
+
// keep the runtime setting for targeted experiments, but do not expose it in
|
|
1470
|
+
// settings UI. Live layofflabs/gpt-5.5 medium evidence on 2026-07-07 showed no
|
|
1471
|
+
// savings and a cache-hit regression; pruning rewrites already-sent history and
|
|
1472
|
+
// can force a provider cache-epoch reset.
|
|
1473
|
+
"compaction.maintenancePruningEnabled": { type: "boolean", default: false },
|
|
1474
|
+
|
|
1475
|
+
"compaction.maintenancePruningMinSavingsTokens": { type: "number", default: 8000 },
|
|
1476
|
+
|
|
1413
1477
|
// Idle compaction
|
|
1414
1478
|
"compaction.idleEnabled": {
|
|
1415
1479
|
type: "boolean",
|
|
@@ -1683,7 +1747,8 @@ export const SETTINGS_SCHEMA = {
|
|
|
1683
1747
|
ui: {
|
|
1684
1748
|
tab: "context",
|
|
1685
1749
|
label: "TTSR Context Mode",
|
|
1686
|
-
description:
|
|
1750
|
+
description:
|
|
1751
|
+
"What to do with partial output when TTSR triggers. 'discard' (recommended) drops the aborted partial turn so it never accumulates in context. 'keep' retains every aborted partial turn, which grows the token footprint each time a rule fires — prefer 'discard' unless you specifically need the partial output.",
|
|
1687
1752
|
},
|
|
1688
1753
|
},
|
|
1689
1754
|
|
|
@@ -3421,6 +3486,8 @@ export interface CompactionSettings {
|
|
|
3421
3486
|
autoContinue: boolean;
|
|
3422
3487
|
remoteEnabled: boolean;
|
|
3423
3488
|
remoteEndpoint: string | undefined;
|
|
3489
|
+
maintenancePruningEnabled: boolean;
|
|
3490
|
+
maintenancePruningMinSavingsTokens: number;
|
|
3424
3491
|
idleEnabled: boolean;
|
|
3425
3492
|
idleThresholdTokens: number;
|
|
3426
3493
|
idleTimeoutSeconds: number;
|
package/src/config/settings.ts
CHANGED
|
@@ -476,6 +476,28 @@ export class Settings {
|
|
|
476
476
|
this.override("modelRoles", { ...shallowStringRecord(runtimeOverrides), [role]: modelId });
|
|
477
477
|
}
|
|
478
478
|
}
|
|
479
|
+
/**
|
|
480
|
+
* Set an agent model override while keeping any live runtime override aligned.
|
|
481
|
+
*
|
|
482
|
+
* Runtime model profiles override `task.agentModelOverrides` for the current
|
|
483
|
+
* session. A user-selected role assignment must win immediately in that same
|
|
484
|
+
* session, but only the explicit agent change should be persisted.
|
|
485
|
+
*/
|
|
486
|
+
setAgentModelOverride(agentName: string, modelId: string): void {
|
|
487
|
+
const current = shallowStringRecord(getByPath(this.#global, ["task", "agentModelOverrides"]));
|
|
488
|
+
const runtimeOverrides = getByPath(this.#overrides, ["task", "agentModelOverrides"]);
|
|
489
|
+
const updateRuntimeOverride =
|
|
490
|
+
!!runtimeOverrides && typeof runtimeOverrides === "object" && !Array.isArray(runtimeOverrides);
|
|
491
|
+
|
|
492
|
+
this.set("task.agentModelOverrides", { ...current, [agentName]: modelId });
|
|
493
|
+
|
|
494
|
+
if (updateRuntimeOverride) {
|
|
495
|
+
this.override("task.agentModelOverrides", {
|
|
496
|
+
...shallowStringRecord(runtimeOverrides),
|
|
497
|
+
[agentName]: modelId,
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
}
|
|
479
501
|
|
|
480
502
|
/**
|
|
481
503
|
* Get a model role (helper for modelRoles record).
|
|
@@ -112,7 +112,7 @@ Before launching `skc team`, require a grounded context snapshot:
|
|
|
112
112
|
- unknowns/open questions
|
|
113
113
|
- likely codebase touchpoints
|
|
114
114
|
4. If ambiguity remains high, gather brownfield facts with focused repo inspection or a canonical read-only role agent first, then run `$deep-interview --quick <task>` before team launch.
|
|
115
|
-
5. If current correctness depends on official docs, version-aware framework guidance, best practices, or external dependency behavior,
|
|
115
|
+
5. If current correctness depends on official docs, version-aware framework guidance, best practices, or external dependency behavior, gather evidence before or alongside worker launch using supported surfaces only: focused repo inspection for local facts, `planner` for broad context mapping/sequencing, `architect` for architecture or external-doc-risk assessment, and direct web/search tools when configured.
|
|
116
116
|
|
|
117
117
|
Do not start the worker pane until this gate is satisfied; if forced to proceed quickly, state explicit scope/risk limitations in the launch report.
|
|
118
118
|
|
|
@@ -343,14 +343,15 @@ Use only after checking `skc team status <team>` and state evidence:
|
|
|
343
343
|
- `.skc/_session-{sessionid}/state/team/<team>/config.json`
|
|
344
344
|
- `.skc/_session-{sessionid}/state/team/<team>/tasks/task-1.json`
|
|
345
345
|
- `.skc/_session-{sessionid}/state/team/<team>/mailbox/worker-1.json`
|
|
346
|
-
2.
|
|
347
|
-
- `
|
|
348
|
-
-
|
|
349
|
-
|
|
350
|
-
|
|
346
|
+
2. Use supported team surfaces before manual pane intervention:
|
|
347
|
+
- `skc team status <team>` for current recorded state
|
|
348
|
+
- `skc team monitor <team>` when a live monitor/update loop is needed
|
|
349
|
+
- `skc team api <team>` only for documented programmatic operations
|
|
350
|
+
3. If the recorded worker pane is stuck in an interactive state, safely return to idle prompt first:
|
|
351
|
+
- optional interrupt `C-c` or escape flow (CLI-specific) once, then re-check `skc team status <team>` and relevant state files
|
|
351
352
|
4. Send one concise trigger only when runtime/state checks show manual prompt input is needed:
|
|
352
353
|
- `tmux send-keys -t %<worker-pane> "continue current task; report status" C-m`
|
|
353
|
-
5. Re-check
|
|
354
|
+
5. Re-check task state, worker mailbox, and `skc team status <team>`.
|
|
354
355
|
|
|
355
356
|
### Shutdown reports success but stale worker panes remain
|
|
356
357
|
|
|
@@ -372,8 +373,9 @@ tmux list-panes -F '#{pane_id} #{pane_current_command} #{pane_start_command}'
|
|
|
372
373
|
tmux kill-pane -t %450
|
|
373
374
|
tmux kill-pane -t %451
|
|
374
375
|
|
|
375
|
-
# 3)
|
|
376
|
-
#
|
|
376
|
+
# 3) Shut down recorded team state/workers through the supported team runtime
|
|
377
|
+
# Replace <team-name> with the team from `skc team list` / `skc team status`.
|
|
378
|
+
skc team shutdown <team-name>
|
|
377
379
|
|
|
378
380
|
# 4) Retry
|
|
379
381
|
skc team executor "fresh retry"
|
|
@@ -396,7 +398,7 @@ When operating this skill, provide concrete progress evidence:
|
|
|
396
398
|
|
|
397
399
|
Do not claim success without file/pane evidence.
|
|
398
400
|
Do not claim clean completion if shutdown occurred with `in_progress>0`.
|
|
399
|
-
Use `skc
|
|
401
|
+
Use `skc team status <team>` and `skc team monitor <team>` as the supported operator aids for status inspection; keep raw state-file or pane evidence available for manual intervention and proof.
|
|
400
402
|
|
|
401
403
|
## Programmatic Team Orchestration
|
|
402
404
|
|
|
@@ -405,14 +407,15 @@ Use the `skc team ...` CLI as the supported team-launch surface. For automation,
|
|
|
405
407
|
### Supported current surfaces
|
|
406
408
|
|
|
407
409
|
- **`skc team ...` CLI** — Primary method for interactive or automated team orchestration. Use this when you want direct tmux-pane visibility or a scriptable launch path.
|
|
410
|
+
- **`skc team status <team>`** — Read current team/task/worker state.
|
|
411
|
+
- **`skc team monitor <team>`** — Follow live progress through the supported runtime surface.
|
|
412
|
+
- **`skc team shutdown <team>`** — Stop recorded active workers and move the team toward terminal state.
|
|
413
|
+
- **`skc team api <team>`** — Use only for documented programmatic operations exposed by the team runtime.
|
|
408
414
|
- **Team state files** — Inspect `.skc/_session-{sessionid}/state/team/<team>/` when you need status, task, or mailbox evidence after launch.
|
|
409
415
|
|
|
410
416
|
### Cleanup distinction
|
|
411
417
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
- `team_cleanup` (**state-server**): Deletes team state **files** on disk (`.skc/_session-{sessionid}/state/team/<team>/`). Use after a team run is fully complete.
|
|
415
|
-
- tmux/session cleanup: Use the documented `skc team` shutdown / cleanup flow when you need to stop the worker pane or clean up an interrupted run.
|
|
418
|
+
Use `skc team shutdown <team>` for recorded active workers. After shutdown reports a terminal state and required evidence is preserved, use supported `skc state ...` session/mode cleanup commands only when you are intentionally clearing state; do not delete team state by hand during an active run. Use manual tmux/session cleanup only for verified stale panes that are not handled by the documented shutdown flow.
|
|
416
419
|
|
|
417
420
|
### Automation example
|
|
418
421
|
|