@lazyingart/agintiflow 0.20.50 → 0.20.52

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/README.md CHANGED
@@ -97,7 +97,7 @@ For larger repositories, use `--profile large-codebase` or choose **Large codeba
97
97
 
98
98
  AgInTiFlow can also spend cheap DeepSeek calls on parallel scout notes before the main executor starts a complicated task. It first writes a bounded project map to `.aginti/codebase-map.json`, then runs scouts for architecture, implementation, review, research, context mapping, tests, git workflow, integration, symbol tracing, and dependency risks. A coordinator Swarm Board is injected for the main agent and saved as `artifacts/scout-blackboard.json` in the session. The executor still does the real file/shell/browser work itself. Disable with `--no-parallel-scouts` or set `--scout-count 1..10`.
99
99
 
100
- For complicated tasks that need stricter quality control, enable Student-Committee-Supervisor mode with `/enabless`, `--enabless`, or `--enabless auto`. SCS uses the main model for a typed gate: committee drafts the next phase, student approves/monitors/rejects weak evidence, and supervisor executes with the normal guarded tools. It disables duplicate scout advice by default, logs typed `scs.*` events, caps retries to avoid deadlock, and stays off unless you opt in or choose auto mode. See [docs/student-committee-supervisor.md](docs/student-committee-supervisor.md).
100
+ For complicated tasks that need stricter quality control, enable Student-Committee-Supervisor mode with `/scs`, `--scs`, or `--scs auto`. SCS uses the main model for a typed gate: committee drafts the next phase, student approves/monitors/rejects weak evidence, and supervisor executes with the normal guarded tools. It disables duplicate scout advice by default, logs typed `scs.*` events, caps retries to avoid deadlock, and stays off unless you opt in or choose auto mode. See [docs/student-committee-supervisor.md](docs/student-committee-supervisor.md).
101
101
 
102
102
  The next productive-agent roadmap is tracked in [docs/productive-agent-roadmap.md](docs/productive-agent-roadmap.md): durable codebase maps, stronger scout blackboards, long-run checkpoints, LSP/symbol tools, test triage, and release automation. Runtime choices, Docker persistence, host full-access tradeoffs, tmux sessions, and rolling-plan autonomy are documented in [docs/runtime-modes-and-autonomy.md](docs/runtime-modes-and-autonomy.md). The supervised self-development protocol is in [docs/self-development-supervision.md](docs/self-development-supervision.md).
103
103
 
@@ -156,10 +156,10 @@ aginti aaps init "Project Workflow"
156
156
  aginti aaps validate
157
157
  aginti chat
158
158
  # then in chat: /review [focus]
159
- # then in chat: /enabless auto
159
+ # then in chat: /scs auto
160
160
  # then in chat: /aaps validate
161
161
  aginti --profile code "write a small Python CLI app with tests"
162
- aginti --enabless auto "fix this complicated project and verify it"
162
+ aginti --scs auto "fix this complicated project and verify it"
163
163
  aginti --latex "draw a figure, write a short LaTeX report, and compile the PDF"
164
164
  aginti "set up this project and run the tests"
165
165
  ```
@@ -170,7 +170,7 @@ Session cleanup is cwd-scoped by default. `aginti --remove-empty-sessions` shows
170
170
 
171
171
  In interactive chat, `/review [focus]` starts a bounded repository review. It begins from git status/diff and project instructions, reads manifests/entry points/tests/changed files first, avoids generated or binary folders, limits discovery passes, and reports findings before any summary.
172
172
 
173
- In interactive chat, `/enabless` turns on SCS for the session, `/enabless auto` activates it only for complex/risky work, `/enabless off` restores the normal fast pipeline, and `/enabless status` explains the current mode.
173
+ In interactive chat, `/scs` toggles SCS on or off for the session, `/scs auto` activates it only for complex/risky work, `/scs on` forces it on, `/scs off` restores the normal fast pipeline, and `/scs status` explains the current mode.
174
174
 
175
175
  Run from a source checkout:
176
176
 
@@ -7,21 +7,22 @@ It is intentionally separate from the normal fast pipeline. Small requests shoul
7
7
  ## Commands
8
8
 
9
9
  ```bash
10
- aginti --enabless "fix this complicated project and verify it"
11
- aginti --enabless auto "migrate this app and run the checks"
12
- aginti --no-enabless "answer this simple question"
10
+ aginti --scs "fix this complicated project and verify it"
11
+ aginti --scs auto "migrate this app and run the checks"
12
+ aginti --no-scs "answer this simple question"
13
13
  ```
14
14
 
15
15
  Inside interactive chat:
16
16
 
17
17
  ```text
18
- /enabless
19
- /enabless auto
20
- /enabless off
21
- /enabless status
18
+ /scs
19
+ /scs auto
20
+ /scs on
21
+ /scs off
22
+ /scs status
22
23
  ```
23
24
 
24
- `/scs` is also accepted as a serious alias.
25
+ `/scs` without arguments toggles the feature: off becomes on, and on/auto becomes off. The old `/enabless` spelling is accepted only as a compatibility alias for older sessions and scripts.
25
26
 
26
27
  ## Role Contract
27
28
 
@@ -57,7 +58,7 @@ The current implementation is deliberately bounded:
57
58
 
58
59
  ## Auto Mode
59
60
 
60
- `/enabless auto` and `--enabless auto` activate SCS for complex, risky, or long-running work. Signals include:
61
+ `/scs auto` and `--scs auto` activate SCS for complex, risky, or long-running work. Signals include:
61
62
 
62
63
  - high smart-routing complexity score;
63
64
  - profiles such as code, app, Android/iOS, large-codebase, GitHub, maintenance, security, LaTeX, research, and supervision;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazyingart/agintiflow",
3
- "version": "0.20.50",
3
+ "version": "0.20.52",
4
4
  "type": "module",
5
5
  "description": "AgInTiFlow is a web-first coding agent and CLI with DeepSeek routing, sandboxed tools, model providers, canvas artifacts, and optional wrappers.",
6
6
  "license": "Apache-2.0",
@@ -1,6 +1,6 @@
1
1
  # Student-Committee-Supervisor Mode
2
2
 
3
- This note researches the current AgInTiFlow execution pipeline and proposes a standalone `/enabless` mode: Student-Committee-Supervisor, abbreviated `SCS`.
3
+ This note researches the current AgInTiFlow execution pipeline and proposes a standalone `/scs` mode: Student-Committee-Supervisor, abbreviated `SCS`.
4
4
 
5
5
  The name intentionally keeps the reversed-role joke: the "student" supervises, the "supervisor" executes, and the "committee" drafts but cannot decide.
6
6
 
@@ -40,7 +40,7 @@ Relevant implementation files:
40
40
 
41
41
  ## Proposed SCS Contract
42
42
 
43
- `/enabless` enables a stricter internal workflow for the current interactive session.
43
+ `/scs` enables a stricter internal workflow for the current interactive session.
44
44
 
45
45
  Roles:
46
46
 
@@ -50,7 +50,7 @@ Roles:
50
50
  | Committee | Main model | Draft candidate plans and alternatives. | Cannot approve, veto, replan after execution starts, or call tools. |
51
51
  | Supervisor | Main model | Execute the approved plan with the existing tool loop. | Cannot draft its own initial plan, cannot approve its own plan, cannot declare strategic replans without student permission. |
52
52
 
53
- The user asked that once `/enabless` is enabled, all SCS work uses the main model. This is sensible for determinism: no route/main mismatch, no cheap planner producing a plan that a stronger executor dislikes, and no confusing cross-model responsibility. It also makes cost predictable because the feature is opt-in.
53
+ The user asked that once `/scs` is enabled, all SCS work uses the main model. This is sensible for determinism: no route/main mismatch, no cheap planner producing a plan that a stronger executor dislikes, and no confusing cross-model responsibility. It also makes cost predictable because the feature is opt-in.
54
54
 
55
55
  ## Pros
56
56
 
@@ -133,7 +133,7 @@ New config/state:
133
133
 
134
134
  - `AGINTI_SCS_MODE=true`
135
135
  - CLI flag: `--enable-scs`
136
- - interactive command: `/enabless`, `/enabless off`, `/enabless status`
136
+ - interactive command: `/scs`, `/scs on`, `/scs auto`, `/scs off`, `/scs status`
137
137
  - state fields:
138
138
  - `state.enableScs`
139
139
  - `state.scs.phase`
@@ -189,7 +189,7 @@ Recommended modes:
189
189
  | `on` | SCS gates all non-trivial work in the session. |
190
190
  | `auto` | SCS only activates for complex tasks, write actions, multi-step shell work, GitHub, system maintenance, Android/iOS, LaTeX/PDF, and long-running tasks. |
191
191
 
192
- `/enabless` should toggle `on` in interactive CLI for the joke and speed. `/enabless auto` can be the mature default later.
192
+ `/scs` should toggle SCS on/off in interactive CLI. `/scs auto` keeps the mature complex-task gate for users who want quality control without paying the SCS cost on simple turns.
193
193
 
194
194
  ## Model Policy
195
195
 
@@ -215,10 +215,11 @@ Possible future improvement:
215
215
  CLI:
216
216
 
217
217
  ```text
218
- /enabless
219
- /enabless off
220
- /enabless auto
221
- /enabless status
218
+ /scs
219
+ /scs on
220
+ /scs off
221
+ /scs auto
222
+ /scs status
222
223
  ```
223
224
 
224
225
  Status output:
@@ -283,8 +284,8 @@ Implemented first slice:
283
284
 
284
285
  - `src/scs-controller.js` provides mode normalization, auto activation, committee/student JSON calls, evidence packs, supervisor instructions, tool-failure monitoring, periodic progress review, and final finish gates.
285
286
  - `src/config.js` adds `enableScs`/`scsActive` and switches active execution to the main model role when SCS is active.
286
- - `src/interactive-cli.js` adds `/enabless`, `/enabless auto`, `/enabless off`, `/enabless status`, and `/scs` alias.
287
- - `src/cli.js` adds `--enabless`, `--enabless auto`, `--no-enabless`, and aliases.
287
+ - `src/interactive-cli.js` adds `/scs`, `/scs auto`, `/scs on`, `/scs off`, and `/scs status`. `/enabless` remains a compatibility alias only.
288
+ - `src/cli.js` adds `--scs`, `--scs auto`, and `--no-scs`. The older `--enabless` flags remain compatibility aliases only.
288
289
  - `src/agent-runner.js` persists typed `scs.*` events, saves `scs-phase-001.json`, injects the approved supervisor phase, reviews failed tools, and gates finish.
289
290
 
290
291
  Remaining roadmap:
@@ -317,12 +318,12 @@ Phase 5: auto mode
317
318
  - Should SCS approval be required before any write tool, or only before the first phase starts?
318
319
  - Should the student be allowed to require specific checks, or only accept/reject evidence?
319
320
  - Should committee be one call or multiple candidate calls synthesized into one plan?
320
- - Should `/enabless` be hidden as a playful alias while `/scs` is the serious public command?
321
+ - Should `/enabless` remain as a hidden compatibility alias now that `/scs` is the serious public command?
321
322
  - Should SCS decisions be shared through Skill Mesh as learned supervision skills?
322
323
 
323
324
  ## Recommendation
324
325
 
325
- Implement `/enabless` as a serious opt-in quality mode with a playful name.
326
+ Implement `/scs` as the serious opt-in quality mode.
326
327
 
327
328
  Start with one-main-model SCS and only gate the initial plan plus final finish. Then add failure-triggered student monitoring. Avoid per-tool approval in the first version; existing command and file guardrails already protect the dangerous paths, and too many monitor calls will make the product feel slow.
328
329
 
@@ -15,6 +15,7 @@ import {
15
15
  formatWorkspaceChange,
16
16
  stripMarkdown,
17
17
  } from "../src/interactive-cli.js";
18
+ import { parseArgs } from "../src/cli.js";
18
19
  import { dockerPolicyTimeoutMs, dockerUserCommand } from "../src/docker-sandbox.js";
19
20
 
20
21
  const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
@@ -263,11 +264,20 @@ try {
263
264
  if (
264
265
  canonicalSlashPromptBuffer("/ve") !== "/venice" ||
265
266
  canonicalSlashPromptBuffer("/v") !== "/venice" ||
267
+ canonicalSlashPromptBuffer("/sc") !== "/scs" ||
266
268
  canonicalSlashPromptBuffer("/not-a-command") !== "/not-a-command" ||
267
269
  canonicalSlashPromptBuffer("/venice off") !== "/venice off"
268
270
  ) {
269
271
  throw new Error("slash command prompt canonicalization did not preserve final submitted command correctly");
270
272
  }
273
+ const scsBooleanArgs = parseArgs(["--scs", "fix this project"]);
274
+ if (scsBooleanArgs.enableScs !== "on" || scsBooleanArgs.goal !== "fix this project") {
275
+ throw new Error("--scs should behave as a boolean flag when followed by a task");
276
+ }
277
+ const scsAutoArgs = parseArgs(["--scs", "auto", "fix this project"]);
278
+ if (scsAutoArgs.enableScs !== "auto" || scsAutoArgs.goal !== "fix this project") {
279
+ throw new Error("--scs auto should consume auto and preserve the task");
280
+ }
271
281
 
272
282
  await runCli(["init"], "");
273
283
  const instructions = await fs.readFile(path.join(tempRoot, "AGINTI.md"), "utf8");
@@ -280,8 +290,14 @@ try {
280
290
  }
281
291
  const helpResult = await runChat("/help\n/exit\n");
282
292
  const misspelledAuxiliary = "/auxil" + "liary";
283
- if (!helpResult.stdout.includes("/auxiliary") || !helpResult.stdout.includes("/review") || helpResult.stdout.includes(misspelledAuxiliary)) {
284
- throw new Error("interactive help did not expose only the correctly spelled /auxiliary command");
293
+ if (
294
+ !helpResult.stdout.includes("/auxiliary") ||
295
+ !helpResult.stdout.includes("/review") ||
296
+ !helpResult.stdout.includes("/scs") ||
297
+ helpResult.stdout.includes("/enabless") ||
298
+ helpResult.stdout.includes(misspelledAuxiliary)
299
+ ) {
300
+ throw new Error("interactive help did not expose the expected slash commands");
285
301
  }
286
302
  const zhHelpResult = await runCli(["chat", "--language", "zh-Hans"], "/help\n/exit\n");
287
303
  if (!zhHelpResult.stdout.includes("命令:") || !zhHelpResult.stdout.includes("输入普通任务")) {
@@ -295,6 +311,22 @@ try {
295
311
  if (!reviewResult.stdout.includes("Review focus: changed files only") || !reviewResult.stdout.includes("Mock run complete")) {
296
312
  throw new Error("interactive /review did not launch the bounded review workflow");
297
313
  }
314
+ const scsOnResult = await runChat("/scs\n");
315
+ if (!scsOnResult.stdout.includes("scs=on")) {
316
+ throw new Error("interactive /scs did not toggle SCS on");
317
+ }
318
+ const scsOffResult = await runCli(["chat", "--provider", "mock", "--routing", "manual", "--profile", "code", "--scs"], "/scs\n");
319
+ if (!scsOffResult.stdout.includes("scs=off")) {
320
+ throw new Error("interactive /scs did not toggle SCS off");
321
+ }
322
+ const scsStatusResult = await runChat("/scs status\n");
323
+ if (!scsStatusResult.stdout.includes("SCS mode: off")) {
324
+ throw new Error("interactive /scs status did not show current mode");
325
+ }
326
+ const scsAutoResult = await runChat("/scs auto\n");
327
+ if (!scsAutoResult.stdout.includes("scs=auto")) {
328
+ throw new Error("interactive /scs auto did not enable auto mode");
329
+ }
298
330
  const abbreviatedSkillsResult = await runChat("/sk website\n/ex\n");
299
331
  if (abbreviatedSkillsResult.stdout.includes("Unknown command") || !abbreviatedSkillsResult.stdout.includes("website-app")) {
300
332
  throw new Error("interactive slash command prefix did not auto-select the first matching command");
@@ -372,6 +404,7 @@ try {
372
404
  "auxiliary-command-spelling",
373
405
  "skills-command",
374
406
  "review-command",
407
+ "scs-command-toggle",
375
408
  "slash-prefix-autoselect",
376
409
  "slash-prefix-canonical-history",
377
410
  "instructions-chat-edit",
@@ -85,6 +85,52 @@ try {
85
85
  !staleDeepSeekState.messages.some((message) => message.role === "tool" && message.tool_call_id === "stale-call"),
86
86
  "repaired DeepSeek history retained an orphan stale tool message"
87
87
  );
88
+ const interruptedDeepSeekState = {
89
+ messages: [
90
+ { role: "system", content: "system" },
91
+ { role: "user", content: "old request" },
92
+ {
93
+ role: "assistant",
94
+ content: "Running checks.",
95
+ reasoning_content: "Need shell evidence.",
96
+ tool_calls: [
97
+ { id: "call-a", type: "function", function: { name: "run_command", arguments: "{}" } },
98
+ { id: "call-b", type: "function", function: { name: "run_command", arguments: "{}" } },
99
+ ],
100
+ },
101
+ { role: "tool", tool_call_id: "call-a", content: "{\"ok\":true}" },
102
+ { role: "user", content: "Continue with this new request: /review" },
103
+ ],
104
+ };
105
+ const interruptedRepair = repairModelMessageHistory(interruptedDeepSeekState, { provider: "deepseek" });
106
+ assert(interruptedRepair.changed, "interrupted tool-call history was not repaired");
107
+ assert(interruptedRepair.incompleteToolCallMessages === 1, "interrupted repair did not count the incomplete tool call");
108
+ assert(
109
+ !interruptedDeepSeekState.messages.some((message) => Array.isArray(message.tool_calls) && message.tool_calls.length > 0),
110
+ "interrupted repair retained incomplete assistant tool calls"
111
+ );
112
+ assert(
113
+ !interruptedDeepSeekState.messages.some((message) => message.role === "tool"),
114
+ "interrupted repair retained orphan partial tool result"
115
+ );
116
+ assert(
117
+ interruptedDeepSeekState.messages.at(-1)?.content === "Continue with this new request: /review",
118
+ "interrupted repair dropped the new user request"
119
+ );
120
+ const completeToolState = {
121
+ messages: [
122
+ { role: "system", content: "system" },
123
+ {
124
+ role: "assistant",
125
+ content: "Using a tool.",
126
+ tool_calls: [{ id: "call-ok", type: "function", function: { name: "list_files", arguments: "{}" } }],
127
+ },
128
+ { role: "tool", tool_call_id: "call-ok", content: "{\"ok\":true}" },
129
+ { role: "user", content: "next" },
130
+ ],
131
+ };
132
+ const completeRepair = repairModelMessageHistory(completeToolState, { provider: "openai" });
133
+ assert(!completeRepair.changed, "complete OpenAI-format tool history should not be modified");
88
134
  const patchRoute = selectModelRoute({
89
135
  routingMode: "smart",
90
136
  provider: "deepseek",
@@ -190,32 +190,68 @@ function preserveAssistantMessage(message) {
190
190
  }
191
191
 
192
192
  export function repairModelMessageHistory(state, config = {}) {
193
- if (config.provider !== "deepseek" || !Array.isArray(state?.messages)) {
194
- return { changed: false, droppedAssistantMessages: 0, convertedAssistantMessages: 0, droppedToolMessages: 0 };
193
+ if (!Array.isArray(state?.messages)) {
194
+ return {
195
+ changed: false,
196
+ droppedAssistantMessages: 0,
197
+ convertedAssistantMessages: 0,
198
+ droppedToolMessages: 0,
199
+ incompleteToolCallMessages: 0,
200
+ };
195
201
  }
196
202
 
197
203
  const repaired = [];
198
- const droppedToolCallIds = new Set();
199
204
  let droppedAssistantMessages = 0;
200
205
  let convertedAssistantMessages = 0;
201
206
  let droppedToolMessages = 0;
207
+ let incompleteToolCallMessages = 0;
202
208
 
203
- for (const message of state.messages) {
209
+ for (let index = 0; index < state.messages.length; index += 1) {
210
+ const message = state.messages[index];
204
211
  if (message.role === "assistant") {
205
212
  const hasReasoningContent = Boolean(message.reasoning_content || message.reasoningContent);
206
213
  const toolCalls = Array.isArray(message.tool_calls) ? message.tool_calls : [];
207
214
  const content = String(message.content || "");
215
+ const requiresDeepSeekReasoning = config.provider === "deepseek" && !hasReasoningContent;
216
+
217
+ if (toolCalls.length > 0) {
218
+ const expectedIds = toolCalls.map((call) => String(call?.id || "")).filter(Boolean);
219
+ const expected = new Set(expectedIds);
220
+ const followingToolMessages = [];
221
+ const duplicateOrUnexpectedToolMessages = [];
222
+ const seen = new Set();
223
+ let cursor = index + 1;
224
+
225
+ while (cursor < state.messages.length && state.messages[cursor]?.role === "tool") {
226
+ const toolMessage = state.messages[cursor];
227
+ const toolCallId = String(toolMessage.tool_call_id || "");
228
+ if (expected.has(toolCallId) && !seen.has(toolCallId)) {
229
+ followingToolMessages.push(toolMessage);
230
+ seen.add(toolCallId);
231
+ } else {
232
+ duplicateOrUnexpectedToolMessages.push(toolMessage);
233
+ }
234
+ cursor += 1;
235
+ }
208
236
 
209
- if (!hasReasoningContent) {
210
- if (content.startsWith("Execution plan:")) {
237
+ const completeToolResults = expectedIds.length > 0 && expectedIds.every((id) => seen.has(id));
238
+ if (requiresDeepSeekReasoning || !completeToolResults) {
211
239
  droppedAssistantMessages += 1;
240
+ droppedToolMessages += followingToolMessages.length + duplicateOrUnexpectedToolMessages.length;
241
+ if (!completeToolResults) incompleteToolCallMessages += 1;
242
+ index = cursor - 1;
212
243
  continue;
213
244
  }
214
245
 
215
- if (toolCalls.length > 0) {
216
- for (const call of toolCalls) {
217
- if (call?.id) droppedToolCallIds.add(call.id);
218
- }
246
+ repaired.push(preserveAssistantMessage(message));
247
+ repaired.push(...followingToolMessages);
248
+ droppedToolMessages += duplicateOrUnexpectedToolMessages.length;
249
+ index = cursor - 1;
250
+ continue;
251
+ }
252
+
253
+ if (requiresDeepSeekReasoning) {
254
+ if (content.startsWith("Execution plan:")) {
219
255
  droppedAssistantMessages += 1;
220
256
  continue;
221
257
  }
@@ -236,7 +272,7 @@ export function repairModelMessageHistory(state, config = {}) {
236
272
  continue;
237
273
  }
238
274
 
239
- if (message.role === "tool" && droppedToolCallIds.has(message.tool_call_id)) {
275
+ if (message.role === "tool") {
240
276
  droppedToolMessages += 1;
241
277
  continue;
242
278
  }
@@ -259,6 +295,7 @@ export function repairModelMessageHistory(state, config = {}) {
259
295
  droppedAssistantMessages,
260
296
  convertedAssistantMessages,
261
297
  droppedToolMessages,
298
+ incompleteToolCallMessages,
262
299
  };
263
300
  }
264
301
 
@@ -1314,6 +1351,13 @@ export async function runAgent(config) {
1314
1351
 
1315
1352
  ensureChatState(state);
1316
1353
 
1354
+ const initialRepair = repairModelMessageHistory(state, config);
1355
+ if (initialRepair.changed) {
1356
+ await store.appendEvent("history.repaired", initialRepair);
1357
+ observers.event("history.repaired", initialRepair);
1358
+ await store.saveState(state);
1359
+ }
1360
+
1317
1361
  observers.log("session.ready", {
1318
1362
  sessionId,
1319
1363
  provider: config.provider,
package/src/cli.js CHANGED
@@ -55,6 +55,15 @@ function readOption(argv, index) {
55
55
  return value;
56
56
  }
57
57
 
58
+ function readOptionalScsMode(argv, index) {
59
+ const value = readOption(argv, index);
60
+ const normalized = String(value || "").trim().toLowerCase();
61
+ if (!["on", "off", "auto", "smart", "true", "false", "yes", "no", "enable", "disable", "enabled", "disabled", "1", "0"].includes(normalized)) {
62
+ return { mode: "on", consumed: false };
63
+ }
64
+ return { mode: value, consumed: true };
65
+ }
66
+
58
67
  export function parseArgs(argv) {
59
68
  const result = {
60
69
  goal: "",
@@ -151,9 +160,9 @@ export function parseArgs(argv) {
151
160
  continue;
152
161
  }
153
162
  if (arg === "--enabless" || arg === "--enable-scs" || arg === "--scs") {
154
- const value = readOption(argv, i);
155
- result.enableScs = value || "on";
156
- if (value) i += 1;
163
+ const { mode, consumed } = readOptionalScsMode(argv, i);
164
+ result.enableScs = mode;
165
+ if (consumed) i += 1;
157
166
  continue;
158
167
  }
159
168
  if (arg === "--no-enabless" || arg === "--disable-scs" || arg === "--no-scs") {
@@ -395,7 +404,7 @@ export function parseArgs(argv) {
395
404
 
396
405
  function printUsage() {
397
406
  console.log(
398
- 'Usage: aginti [chat] OR aginti web [--port 3210] OR aginti update OR aginti models OR aginti aaps [status|init|files|validate|compile|check|run] OR aginti skills [query] OR aginti skillmesh [status|off|record|share|sync|serve|service] OR aginti housekeeping [--json] OR aginti auth [deepseek|openai|qwen|venice|grsai] OR aginti resume [--all-sessions] [latest|<session-id>] ["prompt"] OR aginti --remove-empty-sessions OR aginti --remove-sessions OR aginti queue <session-id> "message" OR aginti [--no-auto-update] [--language en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru] [--image] [--latex] [--enabless|--enabless auto|--no-enabless] [--routing smart|fast|complex|manual] [--provider deepseek|openai|qwen|venice|mock] [--model MODEL] [--route-model MODEL] [--main-model MODEL] [--spare-model MODEL --spare-reasoning medium] [--aux-provider grsai|venice --aux-model MODEL] [--sandbox-mode host|docker-readonly|docker-workspace] [--package-install-policy block|prompt|allow] [--approve-package-installs] [--allow-shell|--no-shell] [--allow-file-tools|--no-file-tools] [--web-search|--no-web-search] [--parallel-scouts|--no-parallel-scouts --scout-count 1..10] [--allow-auxiliary-tools|--no-auxiliary-tools] [--allow-wrappers --wrapper codex --wrapper-model gpt-5.5] [--list-models|--list-routes] "your task"'
407
+ 'Usage: aginti [chat] OR aginti web [--port 3210] OR aginti update OR aginti models OR aginti aaps [status|init|files|validate|compile|check|run] OR aginti skills [query] OR aginti skillmesh [status|off|record|share|sync|serve|service] OR aginti housekeeping [--json] OR aginti auth [deepseek|openai|qwen|venice|grsai] OR aginti resume [--all-sessions] [latest|<session-id>] ["prompt"] OR aginti --remove-empty-sessions OR aginti --remove-sessions OR aginti queue <session-id> "message" OR aginti [--no-auto-update] [--language en|ja|zh-Hans|zh-Hant|ko|fr|es|ar|vi|de|ru] [--image] [--latex] [--scs|--scs auto|--no-scs] [--routing smart|fast|complex|manual] [--provider deepseek|openai|qwen|venice|mock] [--model MODEL] [--route-model MODEL] [--main-model MODEL] [--spare-model MODEL --spare-reasoning medium] [--aux-provider grsai|venice --aux-model MODEL] [--sandbox-mode host|docker-readonly|docker-workspace] [--package-install-policy block|prompt|allow] [--approve-package-installs] [--allow-shell|--no-shell] [--allow-file-tools|--no-file-tools] [--web-search|--no-web-search] [--parallel-scouts|--no-parallel-scouts --scout-count 1..10] [--allow-auxiliary-tools|--no-auxiliary-tools] [--allow-wrappers --wrapper codex --wrapper-model gpt-5.5] [--list-models|--list-routes] "your task"'
399
408
  );
400
409
  console.log(`Languages: ${["en", "ja", "zh-Hans", "zh-Hant", "ko", "fr", "es", "ar", "vi", "de", "ru"].map((code) => `${code}=${languageLabel(code)}`).join(", ")}`);
401
410
  }
package/src/i18n.js CHANGED
@@ -138,6 +138,7 @@ const TRANSLATIONS = {
138
138
  helpSkillMesh: "Manage strict reviewed skill sharing.",
139
139
  helpProfile: "Set task profile, e.g. code, website, latex, maintenance.",
140
140
  helpWebSearch: "Enable or disable the web_search tool.",
141
+ helpEnableScs: "Toggle Student-Committee-Supervisor gated execution.",
141
142
  helpScouts: "Enable parallel DeepSeek scouts and set scout count.",
142
143
  helpRouting: "Set routing: smart, fast, complex, manual.",
143
144
  helpProvider: "Open provider selector, or set deepseek/openai/qwen/venice/mock.",
@@ -87,9 +87,8 @@ const SLASH_COMMANDS = [
87
87
  "/skillsync",
88
88
  "/profile",
89
89
  "/web-search",
90
- "/scouts",
91
- "/enabless",
92
90
  "/scs",
91
+ "/scouts",
93
92
  "/models",
94
93
  "/venice",
95
94
  "/route",
@@ -667,8 +666,8 @@ function printHelp() {
667
666
  ` ${command("/skillmesh [status|off|record|share|sync]", "Manage strict reviewed skill sharing.", "helpSkillMesh")}`,
668
667
  ` ${command("/profile <name>", "Set task profile, e.g. code, website, latex, maintenance.", "helpProfile")}`,
669
668
  ` ${command("/web-search on|off", "Enable or disable the web_search tool.", "helpWebSearch")}`,
669
+ ` ${command("/scs [on|auto|off|status]", "Toggle Student-Committee-Supervisor gated execution.", "helpEnableScs")}`,
670
670
  ` ${command("/scouts on|off|<1-10>", "Enable parallel DeepSeek scouts and set scout count.", "helpScouts")}`,
671
- ` ${command("/enabless [auto|off|status]", "Enable Student-Committee-Supervisor gated execution.", "helpEnableScs")}`,
672
671
  ` ${command("/routing <mode>", "Set routing: smart, fast, complex, manual.", "helpRouting")}`,
673
672
  ` ${command("/provider [name]", "Open provider selector, or set deepseek/openai/qwen/venice/mock.", "helpProvider")}`,
674
673
  ` ${command("/docker on", "Use docker-workspace with approved package installs.", "helpDockerOn")}`,
@@ -2808,14 +2807,40 @@ async function handleCommand(line, state, packageDir) {
2808
2807
  }
2809
2808
  if (command === "enabless" || command === "scs") {
2810
2809
  const rawMode = String(value || "").trim().toLowerCase();
2811
- const mode = value ? normalizeScsMode(value) : "on";
2810
+ const currentMode = normalizeScsMode(state.enableScs || "off");
2811
+ const mode =
2812
+ rawMode === "toggle" || !rawMode
2813
+ ? command === "scs"
2814
+ ? currentMode === "off"
2815
+ ? "on"
2816
+ : "off"
2817
+ : "on"
2818
+ : normalizeScsMode(value);
2812
2819
  const knownMode =
2813
2820
  !rawMode ||
2814
- ["on", "off", "auto", "smart", "status", "?", "true", "false", "yes", "no", "y", "n", "1", "0", "enable", "disable", "enabled", "disabled"].includes(
2815
- rawMode
2816
- );
2821
+ [
2822
+ "on",
2823
+ "off",
2824
+ "auto",
2825
+ "smart",
2826
+ "status",
2827
+ "?",
2828
+ "toggle",
2829
+ "true",
2830
+ "false",
2831
+ "yes",
2832
+ "no",
2833
+ "y",
2834
+ "n",
2835
+ "1",
2836
+ "0",
2837
+ "enable",
2838
+ "disable",
2839
+ "enabled",
2840
+ "disabled",
2841
+ ].includes(rawMode);
2817
2842
  if (!knownMode) {
2818
- printAgentMessage("Usage: /enabless [auto|off|status]. `/enabless` turns SCS on for the session.");
2843
+ printAgentMessage("Usage: /scs [on|auto|off|status]. `/scs` toggles SCS on/off for the session.");
2819
2844
  return true;
2820
2845
  }
2821
2846
  if (value === "status" || value === "?") {
@@ -2823,7 +2848,7 @@ async function handleCommand(line, state, packageDir) {
2823
2848
  [
2824
2849
  `SCS mode: ${state.enableScs || "off"}`,
2825
2850
  "Student-Committee-Supervisor gates complex work with one main model: committee drafts, student approves/monitors, supervisor executes.",
2826
- "Use `/enabless` for on, `/enabless auto` for complex-task auto mode, or `/enabless off` for the normal fast pipeline.",
2851
+ "Use `/scs` to toggle, `/scs auto` for complex-task auto mode, `/scs on` to force it on, or `/scs off` for the normal fast pipeline.",
2827
2852
  ].join("\n")
2828
2853
  );
2829
2854
  return true;
@@ -2837,6 +2862,8 @@ async function handleCommand(line, state, packageDir) {
2837
2862
  printAgentMessage("SCS enabled. Next run uses the main model for committee planning, student gates, and supervisor execution.");
2838
2863
  } else if (state.enableScs === "auto") {
2839
2864
  printAgentMessage("SCS auto enabled. It activates for complex, risky, or long-running tasks and stays off for simple turns.");
2865
+ } else {
2866
+ printAgentMessage("SCS disabled. Next run uses the normal routing pipeline.");
2840
2867
  }
2841
2868
  return true;
2842
2869
  }