nubos-pilot 0.5.2 → 0.5.4

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.
Files changed (44) hide show
  1. package/bin/install.js +2 -12
  2. package/bin/np-tools/_commands.cjs +2 -0
  3. package/bin/np-tools/add-tests.cjs +4 -0
  4. package/bin/np-tools/add-todo.cjs +4 -0
  5. package/bin/np-tools/discuss-phase.cjs +5 -0
  6. package/bin/np-tools/discuss-phase.test.cjs +75 -18
  7. package/bin/np-tools/discuss-project.cjs +5 -0
  8. package/bin/np-tools/execute-milestone.cjs +5 -0
  9. package/bin/np-tools/lang-directive.cjs +64 -0
  10. package/bin/np-tools/lang-directive.test.cjs +88 -0
  11. package/bin/np-tools/new-milestone.cjs +6 -2
  12. package/bin/np-tools/new-project.cjs +6 -2
  13. package/bin/np-tools/plan-milestone.cjs +5 -0
  14. package/bin/np-tools/research-phase.cjs +5 -0
  15. package/bin/np-tools/resume-work.cjs +5 -0
  16. package/bin/np-tools/text-mode.cjs +56 -0
  17. package/bin/np-tools/text-mode.test.cjs +132 -0
  18. package/bin/np-tools/verify-work.cjs +5 -0
  19. package/lib/language.cjs +63 -0
  20. package/lib/language.test.cjs +99 -0
  21. package/lib/runtime/_readline.cjs +5 -1
  22. package/lib/runtime/_readline.test.cjs +2 -1
  23. package/lib/runtime/claude.cjs +21 -1
  24. package/lib/runtime/claude.test.cjs +63 -0
  25. package/lib/text-mode.cjs +79 -0
  26. package/lib/text-mode.test.cjs +139 -0
  27. package/np-tools.cjs +2 -0
  28. package/package.json +1 -1
  29. package/workflows/add-todo.md +10 -5
  30. package/workflows/discuss-phase.md +49 -17
  31. package/workflows/discuss-project.md +6 -0
  32. package/workflows/execute-phase.md +16 -2
  33. package/workflows/new-milestone.md +12 -0
  34. package/workflows/new-project.md +13 -0
  35. package/workflows/note.md +11 -0
  36. package/workflows/pause-work.md +5 -0
  37. package/workflows/plan-phase.md +13 -1
  38. package/workflows/research-phase.md +12 -0
  39. package/workflows/resume-work.md +12 -0
  40. package/workflows/scan-codebase.md +8 -0
  41. package/workflows/session-report.md +18 -0
  42. package/workflows/update-docs.md +7 -0
  43. package/workflows/validate-phase.md +13 -1
  44. package/workflows/verify-work.md +15 -1
@@ -41,11 +41,16 @@ TODO_PATH="${PENDING_DIR}/${DATE}-${SLUG}.md"
41
41
  ```
42
42
 
43
43
  Extract from init JSON: `commit_docs`, `date`, `timestamp`, `slug`,
44
- `todo_count`, `todos_dir_exists`, `pending_dir`, `state_path`. The
45
- init handler sanitises the slug through `lib/layout.cjs.slugify`
46
- (strips to `[a-z0-9-]` only; filename-injection mitigation) and
47
- validates the description length (<= 500 chars) before any filesystem
48
- write occurs.
44
+ `todo_count`, `todos_dir_exists`, `pending_dir`, `state_path`,
45
+ `text_mode`, `text_mode_source`. The init handler sanitises the slug
46
+ through `lib/layout.cjs.slugify` (strips to `[a-z0-9-]` only;
47
+ filename-injection mitigation) and validates the description length
48
+ (<= 500 chars) before any filesystem write occurs.
49
+
50
+ **Text-mode routing.** If `text_mode == true`, skip every `np-tools.cjs askuser`
51
+ call below and render questions as plain-text numbered lists in the main
52
+ chat. Auto-enabled in Claude Code (CLAUDECODE=1); opt-in via
53
+ `.nubos-pilot/config.json` → `workflow.text_mode`.
49
54
 
50
55
  ## Create Pending Dir
51
56
 
@@ -19,13 +19,37 @@ workflow delivers PLAN-01 and nothing beyond it.
19
19
  ## Initialize
20
20
 
21
21
  ```bash
22
+ LANG_DIRECTIVE=$(node .nubos-pilot/bin/np-tools.cjs lang-directive)
22
23
  INIT=$(node .nubos-pilot/bin/np-tools.cjs init discuss-phase "$PHASE")
23
24
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
24
25
  ```
25
26
 
27
+ **Language (SSOT = `.nubos-pilot/config.json` → `response_language`).**
28
+ `$LANG_DIRECTIVE` is authoritative for this workflow. Obey it for ALL
29
+ subsequent output, askuser prompt texts, status updates, and the CONTEXT.md
30
+ rendering. This supersedes any directive in CLAUDE.md managed block if they
31
+ conflict — the config is the single source of truth.
32
+
26
33
  Parse JSON for: `milestone`, `milestone_id`, `milestone_dir`, `milestone_name`,
27
34
  `milestone_context_path`, `has_context`, `has_milestone_dir`, `goal`,
28
- `requirements`, `agent_skills`, `mode`.
35
+ `requirements`, `agent_skills`, `mode`, `text_mode`, `text_mode_source`.
36
+
37
+ **Text-mode routing (SSOT = INIT payload).** If `text_mode` is `true`, do
38
+ **not** shell out to `np-tools.cjs askuser` for any prompt in this workflow.
39
+ Present every question inline as a plain-text numbered list and wait for the
40
+ user's reply in the main chat. This is the correct path whenever:
41
+
42
+ - `text_mode_source == "runtime"` → Claude Code Bash has no TTY and cannot
43
+ forward interactive menu selections; the askuser marker-block protocol
44
+ never completes.
45
+ - `text_mode_source == "config"` → the user explicitly opted into text mode
46
+ via `.nubos-pilot/config.json` → `workflow.text_mode`.
47
+
48
+ When text mode is active, skip every `node .nubos-pilot/bin/np-tools.cjs
49
+ askuser …` block below and substitute the plain-text equivalent. Collect the
50
+ answers from the user's reply, then proceed to the next step as normal. The
51
+ rest of the workflow (validation, canonical-ref accumulation, template
52
+ render, commit) is unchanged.
29
53
 
30
54
  If the user passed `--assumptions`, route to
31
55
  `workflows/discuss-phase-assumptions.md` and exit this workflow.
@@ -118,25 +142,33 @@ Capture the idea in a "Deferred Ideas" section. Don't lose it, don't act on it.
118
142
  ## Answer Validation
119
143
 
120
144
  <answer_validation>
121
- **IMPORTANT: Answer validation** After every interactive prompt, check if the
122
- response is empty or whitespace-only. If so:
123
- 1. Retry the question once with the same parameters
124
- 2. If still empty, present the options as a plain-text numbered list and ask
125
- the user to type their choice number
145
+ **Routing decision (made once at Initialize):** If INIT payload
146
+ `text_mode == true`, skip every `np-tools.cjs askuser` call in this workflow
147
+ and use plain-text numbered lists in the main chat instead. The
148
+ `text_mode_source` field (`runtime` / `config` / `default`) tells you why
149
+ text mode is active it is informational only and does not change behavior.
150
+
151
+ **When text_mode is false and askuser is used — per-prompt validation:**
152
+ 1. If `askuser` exits with structured error `askuser-no-tty` (exit code 1,
153
+ stderr JSON with `"code":"askuser-no-tty"`), that means the runtime
154
+ detection missed something; **skip retry** and treat the remainder of the
155
+ workflow as text-mode (plain-text numbered lists).
156
+ 2. If the response is empty or whitespace-only (exit 0 but no value), retry
157
+ the question once with the same parameters.
158
+ 3. If still empty, present the options as a plain-text numbered list and ask
159
+ the user to type their choice number.
126
160
  Never proceed with an empty answer.
127
161
 
128
- **Text mode (`workflow.text_mode: true` in config or `--text` flag):**
129
- When text mode is active, **do not use `np-tools.cjs askuser` at all**.
130
- Instead, present every question as a plain-text numbered list and ask the
131
- user to type their choice number. This is required for Claude Code remote
132
- sessions (`/rc` mode) where the Claude App cannot forward TUI menu selections
133
- back to the host.
134
-
135
- Enable text mode:
136
- - Per-session: pass `--text` flag
137
- - Per-project: `np-tools.cjs config-set workflow.text_mode true`
162
+ **Enable text mode:**
163
+ - Auto-detected: any Claude Code session (`CLAUDECODE=1` /
164
+ `CLAUDE_CODE_ENTRYPOINT` set) default behavior, no user action needed.
165
+ - Opt-in per project: set `workflow.text_mode: true` in
166
+ `.nubos-pilot/config.json`.
167
+ - Opt-out per project: set `workflow.text_mode: false` in
168
+ `.nubos-pilot/config.json` (overrides runtime detection).
138
169
 
139
- Text mode applies to ALL workflows in the session, not just discuss-phase.
170
+ Text mode applies to ALL workflows that emit `text_mode` in their INIT
171
+ payload, not just discuss-phase.
140
172
  </answer_validation>
141
173
 
142
174
  ## Process
@@ -51,10 +51,16 @@ Never:
51
51
  ## Single-Call Init
52
52
 
53
53
  ```bash
54
+ LANG_DIRECTIVE=$(node .nubos-pilot/bin/np-tools.cjs lang-directive)
54
55
  INIT=$(node .nubos-pilot/bin/np-tools.cjs init discuss-project ${BOOTSTRAP:+--bootstrap})
55
56
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
56
57
  ```
57
58
 
59
+ **Language (SSOT = `.nubos-pilot/config.json` → `response_language`).**
60
+ `$LANG_DIRECTIVE` is authoritative. Obey it for all askuser prompt texts,
61
+ narrative status updates, and the prose written into PROJECT.md sections.
62
+ Supersedes CLAUDE.md managed block.
63
+
58
64
  Parse: `mode`, `sub_mode` (`bootstrap` or `refresh`), `project_md_exists`,
59
65
  `scan_context`, `questions[]`, `required_fields[]`.
60
66
 
@@ -16,13 +16,27 @@ Execute every slice of a milestone in wave order: slice S001 first (all its task
16
16
 
17
17
  ```bash
18
18
  PHASE="$1"
19
- INIT=$(node .nubos-pilot/bin/np-tools.cjs init execute-milestone "$PHASE")
19
+ LANG_DIRECTIVE=$(node .nubos-pilot/bin/np-tools.cjs lang-directive)
20
+ INIT=$(node .nubos-pilot/bin/np-tools.cjs init execute-milestone init "$PHASE")
20
21
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
21
22
  AGENT_SKILLS_EXECUTOR=$(node .nubos-pilot/bin/np-tools.cjs agent-skills executor 2>/dev/null)
22
23
  RUNTIME=$(node -e "console.log(require('./lib/runtime/index.cjs').detect().runtime)")
23
24
  ```
24
25
 
25
- Parse JSON for: `milestone`, `milestone_id`, `milestone_dir`, `waves[]` (each with `wave` (= slice number), `slice_id`, `slice_full_id`, `slice_dir`, `tasks[]`), `total_tasks`, `slice_count`, `executor_tier`, `agent_skills`.
26
+ **Language (SSOT = `.nubos-pilot/config.json` `response_language`).**
27
+ `$LANG_DIRECTIVE` is authoritative for this workflow. Obey it for all user-
28
+ facing output, askuser prompts, and status updates. Pass `$LANG_DIRECTIVE`
29
+ into every np-executor spawn prompt as a system-level rule so task summaries
30
+ and checkpoint notes follow the project language. This supersedes any
31
+ directive in CLAUDE.md managed block.
32
+
33
+ Parse JSON for: `milestone`, `milestone_id`, `milestone_dir`, `waves[]` (each with `wave` (= slice number), `slice_id`, `slice_full_id`, `slice_dir`, `tasks[]`), `total_tasks`, `slice_count`, `executor_tier`, `text_mode`, `text_mode_source`, `agent_skills`.
34
+
35
+ **Text-mode routing.** If `text_mode == true`, skip every `np-tools.cjs askuser`
36
+ call below (including the orphan-checkpoint and empty-milestone prompts)
37
+ and render the options as a plain-text numbered list in the main chat.
38
+ Auto-enabled in Claude Code (CLAUDECODE=1); opt-in via
39
+ `.nubos-pilot/config.json` → `workflow.text_mode`.
26
40
 
27
41
  `PLAN_ID` is iterated per slice as `${milestone_id}-${slice_id}` (e.g. `M001-S001`). `TASK_ID` is iterated from each slice's `tasks[]` (e.g. `M001-S001-T0001`).
28
42
 
@@ -52,10 +52,22 @@ The subcommand raises `project-not-initialized` anyway, but the shell check give
52
52
  ## Single-Call Init
53
53
 
54
54
  ```bash
55
+ LANG_DIRECTIVE=$(node .nubos-pilot/bin/np-tools.cjs lang-directive)
55
56
  INIT=$(node .nubos-pilot/bin/np-tools.cjs init new-milestone)
56
57
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
57
58
  ```
58
59
 
60
+ **Language (SSOT = `.nubos-pilot/config.json` → `response_language`).**
61
+ `$LANG_DIRECTIVE` is authoritative. Obey it for askuser prompt texts,
62
+ user-facing output, and any prose written into milestone artefacts (YAML
63
+ keys, IDs, and identifiers stay canonical English). Supersedes CLAUDE.md.
64
+
65
+ **Text-mode routing.** If INIT payload `text_mode == true`, skip every
66
+ `np-tools.cjs askuser` call below and render each question as a plain-text
67
+ prompt in the main chat; collect the answer inline. Auto-enabled in Claude
68
+ Code (CLAUDECODE=1); opt-in via `.nubos-pilot/config.json` →
69
+ `workflow.text_mode`.
70
+
59
71
  Payload: three questions — `milestone_name`, `milestone_goal`, `create_req_prefix` (confirm).
60
72
 
61
73
  ## Interview
@@ -106,10 +106,23 @@ Use the scan to propose:
106
106
  The 5 structural questions. All prompts go through the askuser gateway.
107
107
 
108
108
  ```bash
109
+ LANG_DIRECTIVE=$(node .nubos-pilot/bin/np-tools.cjs lang-directive)
109
110
  INIT=$(node .nubos-pilot/bin/np-tools.cjs init new-project)
110
111
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
111
112
  ```
112
113
 
114
+ **Language (SSOT = `.nubos-pilot/config.json` → `response_language`).**
115
+ `$LANG_DIRECTIVE` is authoritative. Obey it for all askuser prompt texts,
116
+ user-facing output, and any narrative prose written into PROJECT.md /
117
+ REQUIREMENTS.md (field names and YAML keys stay canonical English).
118
+ Supersedes CLAUDE.md.
119
+
120
+ **Text-mode routing.** If INIT payload `text_mode == true`, skip every
121
+ `np-tools.cjs askuser` call below and render each question as a plain-text
122
+ prompt in the main chat; collect the user's answer inline and move on.
123
+ Auto-enabled in Claude Code (CLAUDECODE=1); opt-in via
124
+ `.nubos-pilot/config.json` → `workflow.text_mode`.
125
+
113
126
  ```bash
114
127
  ANS_PROJECT_NAME=$(node .nubos-pilot/bin/np-tools.cjs askuser --json '{"type":"input","prompt":"Project name?"}')
115
128
  ANS_CORE_VALUE=$(node .nubos-pilot/bin/np-tools.cjs askuser --json '{"type":"input","prompt":"Core value — one sentence that must stay true if everything else fails?"}')
package/workflows/note.md CHANGED
@@ -52,6 +52,17 @@ into `$TEXT`. Empty text after stripping is an error — there is no
52
52
  `list` or `promote` subcommand here (deferred to a future
53
53
  capture-management plan).
54
54
 
55
+ **Text-mode routing.** Resolve once at the start:
56
+
57
+ ```bash
58
+ TEXT_MODE=$(node .nubos-pilot/bin/np-tools.cjs text-mode 2>/dev/null || echo false)
59
+ ```
60
+
61
+ If `$TEXT_MODE == "true"`, skip every `np-tools.cjs askuser` call below and
62
+ render questions as plain-text numbered lists in the main chat. Auto-enabled
63
+ in Claude Code (CLAUDECODE=1); opt-in via `.nubos-pilot/config.json` →
64
+ `workflow.text_mode`.
65
+
55
66
  ## Compute Paths
56
67
 
57
68
  Scope branching is explicit (T-10-05-02 mitigation + Pitfall 10
@@ -15,9 +15,14 @@ progress.
15
15
  ## Execution
16
16
 
17
17
  ```bash
18
+ LANG_DIRECTIVE=$(node .nubos-pilot/bin/np-tools.cjs lang-directive)
18
19
  node .nubos-pilot/bin/np-tools.cjs init pause-work
19
20
  ```
20
21
 
22
+ **Language (SSOT = `.nubos-pilot/config.json` → `response_language`).**
23
+ Obey `$LANG_DIRECTIVE` for the resume-hint narration and any status lines
24
+ printed around the JSON payload. Supersedes CLAUDE.md.
25
+
21
26
  Output is a small JSON payload `{ ok, stopped_at, resume_file }`. The
22
27
  workflow simply displays it.
23
28
 
@@ -72,6 +72,7 @@ fi
72
72
  ### Read milestone state
73
73
 
74
74
  ```bash
75
+ LANG_DIRECTIVE=$(node .nubos-pilot/bin/np-tools.cjs lang-directive)
75
76
  INIT=$(node .nubos-pilot/bin/np-tools.cjs init plan-milestone init "$PHASE")
76
77
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
77
78
  AGENT_SKILLS_PLANNER=$(node .nubos-pilot/bin/np-tools.cjs agent-skills planner 2>/dev/null)
@@ -79,7 +80,18 @@ AGENT_SKILLS_CHECKER=$(node .nubos-pilot/bin/np-tools.cjs agent-skills plan-chec
79
80
  RUNTIME=$(node -e "console.log(require('./lib/runtime/index.cjs').detect().runtime)")
80
81
  ```
81
82
 
82
- Parse JSON for: `milestone`, `milestone_id`, `milestone_dir`, `milestone_context_path`, `milestone_roadmap_path`, `milestone_meta_path`, `name`, `goal`, `requirements`, `success_criteria`, `has_context`, `has_roadmap`, `has_meta`, `existing_slices[]`, `planner_tier`, `checker_tier`, `agent_skills`.
83
+ **Language (SSOT = `.nubos-pilot/config.json` `response_language`).**
84
+ `$LANG_DIRECTIVE` is authoritative. Obey it for all user-facing output,
85
+ askuser prompts, status updates, and any narrative text the spawned planner
86
+ or plan-checker subagents emit. Pass `$LANG_DIRECTIVE` into their spawn
87
+ prompts as a system-level rule. This supersedes any directive in CLAUDE.md.
88
+
89
+ Parse JSON for: `milestone`, `milestone_id`, `milestone_dir`, `milestone_context_path`, `milestone_roadmap_path`, `milestone_meta_path`, `name`, `goal`, `requirements`, `success_criteria`, `has_context`, `has_roadmap`, `has_meta`, `existing_slices[]`, `planner_tier`, `checker_tier`, `text_mode`, `text_mode_source`, `agent_skills`.
90
+
91
+ **Text-mode routing.** If `text_mode == true`, skip every `np-tools.cjs askuser`
92
+ call below and present questions as plain-text numbered lists in the main
93
+ chat. Auto-enabled in Claude Code (CLAUDECODE=1); opt-in per-project via
94
+ `.nubos-pilot/config.json` → `workflow.text_mode`.
83
95
 
84
96
  `PLAN_ID` and `TASK_ID` default to `${milestone_id}-plan` / `${milestone_id}-planner-run` for the metrics records.
85
97
 
@@ -92,14 +92,26 @@ payload; larger payloads are written to a tmp file and referenced via
92
92
  `@file:<path>`.
93
93
 
94
94
  ```bash
95
+ LANG_DIRECTIVE=$(node .nubos-pilot/bin/np-tools.cjs lang-directive)
95
96
  INIT=$(node .nubos-pilot/bin/np-tools.cjs init research-phase "$PHASE")
96
97
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
97
98
  RUNTIME=$(node -e "console.log(require('./lib/runtime/index.cjs').detect().runtime)")
98
99
  ```
99
100
 
101
+ **Language (SSOT = `.nubos-pilot/config.json` → `response_language`).**
102
+ `$LANG_DIRECTIVE` is authoritative. Obey it for user-facing output and
103
+ askuser prompts, and pass it into the np-researcher spawn prompt so
104
+ RESEARCH.md prose (not URLs, citations, or code snippets) follows the
105
+ project language. This supersedes CLAUDE.md.
106
+
100
107
  `RUNTIME` is resolved once here and reused by the metrics-record call at the
101
108
  researcher spawn site (Step 4) per D-06 workflow-writer pattern.
102
109
 
110
+ **Text-mode routing.** If `text_mode == true` in the payload below, skip every
111
+ `np-tools.cjs askuser` call in this workflow and render questions as
112
+ plain-text numbered lists in the main chat. Auto-enabled in Claude Code
113
+ (CLAUDECODE=1); opt-in via `.nubos-pilot/config.json` → `workflow.text_mode`.
114
+
103
115
  The payload shape:
104
116
 
105
117
  ```json
@@ -13,10 +13,22 @@ on each accordingly.
13
13
  ## Initialize
14
14
 
15
15
  ```bash
16
+ LANG_DIRECTIVE=$(node .nubos-pilot/bin/np-tools.cjs lang-directive)
16
17
  INIT=$(node .nubos-pilot/bin/np-tools.cjs init resume-work)
17
18
  STATUS=$(echo "$INIT" | node -e "process.stdin.on('data', d => console.log(JSON.parse(d).status))")
18
19
  ```
19
20
 
21
+ **Language (SSOT = `.nubos-pilot/config.json` → `response_language`).**
22
+ `$LANG_DIRECTIVE` is authoritative. Obey it for user-facing output and
23
+ askuser prompts. When spawning the np-executor to continue a checkpoint,
24
+ pass `$LANG_DIRECTIVE` into the spawn prompt so resumed task summaries
25
+ follow the project language. Supersedes CLAUDE.md.
26
+
27
+ **Text-mode routing.** If INIT payload `text_mode == true`, skip every
28
+ `np-tools.cjs askuser` call below and render prompts as plain-text numbered
29
+ lists in the main chat. Auto-enabled in Claude Code (CLAUDECODE=1); opt-in
30
+ via `.nubos-pilot/config.json` → `workflow.text_mode`.
31
+
20
32
  ## Execution
21
33
 
22
34
  ### status: resume
@@ -60,10 +60,18 @@ end.
60
60
  Scan, group, write manifest + stubs, emit module-facts in one call:
61
61
 
62
62
  ```bash
63
+ LANG_DIRECTIVE=$(node .nubos-pilot/bin/np-tools.cjs lang-directive)
63
64
  PLAN=$(node .nubos-pilot/bin/np-tools.cjs scan-codebase --project-name "$PROJECT_NAME")
64
65
  if [[ "$PLAN" == @file:* ]]; then PLAN=$(cat "${PLAN#@file:}"); fi
65
66
  ```
66
67
 
68
+ **Language (SSOT = `.nubos-pilot/config.json` → `response_language`).**
69
+ `$LANG_DIRECTIVE` is authoritative. Obey it for user-facing output and
70
+ askuser prompts. Pass it into any writer-subagent spawn so module-doc
71
+ prose (overview, responsibilities, notes) follows the project language.
72
+ Module IDs, file paths, symbol names, and language labels stay canonical
73
+ English. Supersedes CLAUDE.md.
74
+
67
75
  `--project-name` is optional; when provided it goes into `INDEX.md`. Other
68
76
  flags: `--batch-size N` (default 500), `--max-files N`.
69
77
 
@@ -32,6 +32,7 @@ record. Pitfall 9 / `workflow-missing-metrics` is exempt.
32
32
  ## Initialize
33
33
 
34
34
  ```bash
35
+ LANG_DIRECTIVE=$(node .nubos-pilot/bin/np-tools.cjs lang-directive)
35
36
  SINCE_OVERRIDE=""
36
37
  for arg in "$@"; do
37
38
  case "$arg" in
@@ -49,6 +50,23 @@ LOCAL_FILENAME_TS=$(date +"%Y-%m-%dT%H%M")
49
50
  REPORT_PATH="${REPORTS_DIR}/${LOCAL_FILENAME_TS}-session-report.md"
50
51
  ```
51
52
 
53
+ **Language (SSOT = `.nubos-pilot/config.json` → `response_language`).**
54
+ `$LANG_DIRECTIVE` is authoritative. Obey it for the report's narrative
55
+ sections (summary, highlights, notable events) and any askuser prompts.
56
+ Task IDs, milestone IDs, commit SHAs, metrics keys, and file paths stay
57
+ canonical English. Supersedes CLAUDE.md.
58
+
59
+ **Text-mode routing.** Resolve once:
60
+
61
+ ```bash
62
+ TEXT_MODE=$(node .nubos-pilot/bin/np-tools.cjs text-mode 2>/dev/null || echo false)
63
+ ```
64
+
65
+ If `$TEXT_MODE == "true"`, skip every `np-tools.cjs askuser` call below and
66
+ render questions as plain-text numbered lists in the main chat. Auto-enabled
67
+ in Claude Code (CLAUDECODE=1); opt-in via `.nubos-pilot/config.json` →
68
+ `workflow.text_mode`.
69
+
52
70
  The filename format is `YYYY-MM-DDTHHMM-session-report.md` (D-17 —
53
71
  4-char HHMM, no seconds, local time) so reports sort
54
72
  lexicographically by invocation order.
@@ -51,10 +51,17 @@ If `.doc-index.json` is missing, fall back to a full rescan via
51
51
  ## Single-Call Init
52
52
 
53
53
  ```bash
54
+ LANG_DIRECTIVE=$(node .nubos-pilot/bin/np-tools.cjs lang-directive)
54
55
  PLAN=$(node .nubos-pilot/bin/np-tools.cjs update-docs)
55
56
  if [[ "$PLAN" == @file:* ]]; then PLAN=$(cat "${PLAN#@file:}"); fi
56
57
  ```
57
58
 
59
+ **Language (SSOT = `.nubos-pilot/config.json` → `response_language`).**
60
+ `$LANG_DIRECTIVE` is authoritative. Obey it for user-facing output and
61
+ askuser prompts. Pass it into any writer-subagent spawn so refreshed
62
+ module-doc prose follows the project language. Module IDs, file paths,
63
+ and symbol names stay canonical English. Supersedes CLAUDE.md.
64
+
58
65
  Parse: `mode`, `diff_summary` (added/removed/changed/unchanged counts),
59
66
  `stale_modules[]`, `added_modules[]`, `removed_modules[]`.
60
67
 
@@ -19,12 +19,24 @@ if [[ -z "$PHASE" ]]; then
19
19
  exit 2
20
20
  fi
21
21
 
22
+ LANG_DIRECTIVE=$(node .nubos-pilot/bin/np-tools.cjs lang-directive)
22
23
  INIT=$(node .nubos-pilot/bin/np-tools.cjs init verify-work "$PHASE")
23
24
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
24
25
  RUNTIME=$(node -e "console.log(require('./lib/runtime/index.cjs').detect().runtime)")
25
26
  ```
26
27
 
27
- Parse JSON for: `milestone`, `milestone_id`, `milestone_dir`, `milestone_name`, `slice_uat`.
28
+ **Language (SSOT = `.nubos-pilot/config.json` `response_language`).**
29
+ `$LANG_DIRECTIVE` is authoritative. Obey it for user-facing output, askuser
30
+ prompts, and pass it into the np-nyquist-auditor spawn prompt so gap-fill
31
+ narrative follows the project language. Test IDs, file paths, and canonical
32
+ field names stay English. Supersedes CLAUDE.md.
33
+
34
+ Parse JSON for: `milestone`, `milestone_id`, `milestone_dir`, `milestone_name`, `slice_uat`, `text_mode`, `text_mode_source`.
35
+
36
+ **Text-mode routing.** If `text_mode == true`, skip every `np-tools.cjs askuser`
37
+ call in this workflow and render options as plain-text numbered lists in
38
+ the main chat. Auto-enabled in Claude Code (CLAUDECODE=1); opt-in via
39
+ `.nubos-pilot/config.json` → `workflow.text_mode`.
28
40
 
29
41
  ```bash
30
42
  MILESTONE_ID=$(echo "$INIT" | jq -r '.milestone_id')
@@ -16,12 +16,26 @@ Slice-level acceptance (UAT) is validated separately by `/np:validate-phase <N>`
16
16
 
17
17
  ```bash
18
18
  PHASE="$1"
19
+ LANG_DIRECTIVE=$(node .nubos-pilot/bin/np-tools.cjs lang-directive)
19
20
  INIT=$(node .nubos-pilot/bin/np-tools.cjs init verify-work "$PHASE")
20
21
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
21
22
  AGENT_SKILLS_VERIFIER=$(node .nubos-pilot/bin/np-tools.cjs agent-skills verifier 2>/dev/null)
22
23
  ```
23
24
 
24
- Parse: `milestone`, `milestone_id`, `milestone_dir`, `milestone_name`, `success_criteria`, `draft_results`, `verification_path`, `slice_uat`, `verifier_tier`, `agent_skills`.
25
+ **Language (SSOT = `.nubos-pilot/config.json` `response_language`).**
26
+ `$LANG_DIRECTIVE` is authoritative. Obey it for user-facing output, askuser
27
+ prompts, and pass it into the np-verifier spawn prompt so VERIFICATION.md
28
+ prose (Pass/Fail findings, root-cause notes) follows the project language.
29
+ Test-case IDs, file paths, and stack traces stay canonical. Supersedes
30
+ CLAUDE.md.
31
+
32
+ Parse: `milestone`, `milestone_id`, `milestone_dir`, `milestone_name`, `success_criteria`, `draft_results`, `verification_path`, `slice_uat`, `verifier_tier`, `text_mode`, `text_mode_source`, `agent_skills`.
33
+
34
+ **Text-mode routing.** If `text_mode == true`, skip every `np-tools.cjs askuser`
35
+ call below (including the Pass-2 `needs_user_confirm` gate) and render the
36
+ options as a plain-text numbered list in the main chat. Auto-enabled in
37
+ Claude Code (CLAUDECODE=1); opt-in via `.nubos-pilot/config.json` →
38
+ `workflow.text_mode`.
25
39
 
26
40
  ## Pass 1 — verifier agent
27
41