ccg-workflow 3.1.4 → 3.1.6

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
@@ -253,4 +253,4 @@ MIT
253
253
 
254
254
  ---
255
255
 
256
- v3.1.4 | [Issues](https://github.com/fengshao1227/ccg-workflow/issues) | [Contributing](./CONTRIBUTING.md)
256
+ v3.1.6 | [Issues](https://github.com/fengshao1227/ccg-workflow/issues) | [Contributing](./CONTRIBUTING.md)
package/README.zh-CN.md CHANGED
@@ -248,4 +248,4 @@ MIT
248
248
 
249
249
  ---
250
250
 
251
- v3.1.4 | [Issues](https://github.com/fengshao1227/ccg-workflow/issues) | [Contributing](./CONTRIBUTING.md)
251
+ v3.1.6 | [Issues](https://github.com/fengshao1227/ccg-workflow/issues) | [Contributing](./CONTRIBUTING.md)
package/dist/cli.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import cac from 'cac';
3
3
  import ansis from 'ansis';
4
- import { B as diagnoseMcpConfig, C as isWindows, D as readClaudeCodeConfig, E as fixWindowsMcpConfig, F as writeClaudeCodeConfig, r as readCcgConfig, b as initI18n, a as i18n, s as showMainMenu, i as init, G as configMcp, H as version } from './shared/ccg-workflow.B4UibgqQ.mjs';
4
+ import { B as diagnoseMcpConfig, C as isWindows, D as readClaudeCodeConfig, E as fixWindowsMcpConfig, F as writeClaudeCodeConfig, r as readCcgConfig, b as initI18n, a as i18n, s as showMainMenu, i as init, G as configMcp, H as version } from './shared/ccg-workflow.DGFpJtDd.mjs';
5
5
  import 'inquirer';
6
6
  import 'ora';
7
7
  import 'node:child_process';
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { c as changeLanguage, z as checkForUpdates, A as compareVersions, d as createDefaultConfig, e as createDefaultRouting, g as getCcgDir, f as getConfigPath, x as getCurrentVersion, y as getLatestVersion, j as getWorkflowById, h as getWorkflowConfigs, a as i18n, i as init, b as initI18n, l as installAceTool, m as installAceToolRs, n as installCodexMode, k as installWorkflows, t as migrateToV1_4_0, v as needsMigration, r as readCcgConfig, s as showMainMenu, q as uninstallAceTool, o as uninstallCodexMode, p as uninstallWorkflows, u as update, w as writeCcgConfig } from './shared/ccg-workflow.B4UibgqQ.mjs';
1
+ export { c as changeLanguage, z as checkForUpdates, A as compareVersions, d as createDefaultConfig, e as createDefaultRouting, g as getCcgDir, f as getConfigPath, x as getCurrentVersion, y as getLatestVersion, j as getWorkflowById, h as getWorkflowConfigs, a as i18n, i as init, b as initI18n, l as installAceTool, m as installAceToolRs, n as installCodexMode, k as installWorkflows, t as migrateToV1_4_0, v as needsMigration, r as readCcgConfig, s as showMainMenu, q as uninstallAceTool, o as uninstallCodexMode, p as uninstallWorkflows, u as update, w as writeCcgConfig } from './shared/ccg-workflow.DGFpJtDd.mjs';
2
2
  import 'ansis';
3
3
  import 'inquirer';
4
4
  import 'ora';
@@ -10,7 +10,7 @@ import fs from 'fs-extra';
10
10
  import { parse, stringify } from 'smol-toml';
11
11
  import i18next from 'i18next';
12
12
 
13
- const version = "3.1.4";
13
+ const version = "3.1.6";
14
14
 
15
15
  function cmd(id, order, category, name, nameEn, description, descriptionEn, cmdOverride) {
16
16
  return {
@@ -887,7 +887,7 @@ async function removeFastContextPrompt() {
887
887
  await removeFromFile(join(homedir(), ".gemini", "GEMINI.md"));
888
888
  }
889
889
 
890
- const EXPECTED_BINARY_VERSION = "5.11.0";
890
+ const EXPECTED_BINARY_VERSION = "5.11.1";
891
891
  const GITHUB_REPO = "fengshao1227/ccg-workflow";
892
892
  const RELEASE_TAG = "preset";
893
893
  const BINARY_SOURCES = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccg-workflow",
3
- "version": "3.1.4",
3
+ "version": "3.1.6",
4
4
  "description": "Claude + Codex + Gemini multi-model collaboration system - smart routing development workflow",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.17.1",
@@ -16,6 +16,19 @@ from pathlib import Path
16
16
  from datetime import datetime
17
17
 
18
18
 
19
+ # Terminal task statuses — matched case-insensitively after trim. Covers common
20
+ # synonyms the model may write (done/finished/closed/...) so a finished task is
21
+ # never misjudged as still active. Canonical write value is "completed".
22
+ _TERMINAL_STATUSES = frozenset({
23
+ "completed", "complete", "done", "finished", "finish",
24
+ "archived", "archive", "cancelled", "canceled", "closed", "resolved", "abandoned",
25
+ })
26
+
27
+
28
+ def _is_terminal_status(status):
29
+ return str(status or "").strip().lower() in _TERMINAL_STATUSES
30
+
31
+
19
32
  def find_project_root():
20
33
  """Walk up to find .ccg/ or .git/"""
21
34
  d = os.environ.get("CODEX_PROJECT_DIR", os.getcwd())
@@ -43,7 +56,7 @@ def get_active_task(root):
43
56
  try:
44
57
  with open(task_file) as f:
45
58
  task = json.load(f)
46
- if task.get("status") not in ("completed", "archived"):
59
+ if not _is_terminal_status(task.get("status")):
47
60
  task["_dir"] = os.path.join(tasks_dir, name)
48
61
  task["_name"] = name
49
62
  return task
@@ -177,7 +190,7 @@ def build_guidance(task, progress, root):
177
190
  parts.append(f"Spec files available: {', '.join(specs)} — read before writing code.")
178
191
 
179
192
  # --- Archive reminder ---
180
- if phase == "completed" or (task.get("status") == "completed"):
193
+ if phase in ("completed", "done", "finished") or _is_terminal_status(task.get("status")):
181
194
  parts.append("")
182
195
  parts.append("⛔ Task completed. You MUST archive it now:")
183
196
  parts.append(f" mkdir -p .ccg/tasks/archive/$(date +%Y-%m) && mv .ccg/tasks/{task['_name']} .ccg/tasks/archive/$(date +%Y-%m)/")
@@ -18,6 +18,21 @@ function findProjectRoot(startDir) {
18
18
  return null;
19
19
  }
20
20
 
21
+ // Terminal task statuses — a task in any of these is no longer active, so the
22
+ // hooks stop injecting its breadcrumb. Matched case-insensitively after trim,
23
+ // covering common synonyms the model may write (done/finished/closed/...) so a
24
+ // committed-and-finished task is never misjudged as still in progress. The
25
+ // canonical write-side value is "completed" (see go.md), but the read side must
26
+ // be forgiving because status is free-text written by the model.
27
+ const TERMINAL_STATUSES = new Set([
28
+ 'completed', 'complete', 'done', 'finished', 'finish',
29
+ 'archived', 'archive', 'cancelled', 'canceled', 'closed', 'resolved', 'abandoned'
30
+ ]);
31
+
32
+ function isTerminalStatus(status) {
33
+ return TERMINAL_STATUSES.has(String(status == null ? '' : status).trim().toLowerCase());
34
+ }
35
+
21
36
  function getActiveTask(projectRoot) {
22
37
  const tasksDir = path.join(projectRoot, '.ccg', 'tasks');
23
38
  if (!fs.existsSync(tasksDir)) return null;
@@ -40,7 +55,7 @@ function getActiveTask(projectRoot) {
40
55
  if (!fs.existsSync(taskPath)) continue; // stale pointer detection
41
56
  const raw = fs.readFileSync(taskPath, 'utf-8');
42
57
  const task = JSON.parse(raw);
43
- if (task.status !== 'completed' && task.status !== 'archived') {
58
+ if (!isTerminalStatus(task.status)) {
44
59
  return { dir: path.join(tasksDir, dir), ...task, _stale: false };
45
60
  }
46
61
  } catch { /* skip malformed */ }
@@ -183,6 +198,7 @@ function detectLoop(turns, threshold) {
183
198
  module.exports = {
184
199
  findProjectRoot,
185
200
  getActiveTask,
201
+ isTerminalStatus,
186
202
  readFileSafe,
187
203
  readJsonSafe,
188
204
  readContextJsonl,