knoxis-helper 1.8.4 → 1.8.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.
@@ -101,6 +101,7 @@ function installAgentLocally(force) {
101
101
  const sourceStateScaffold = path.join(libDir, 'state-scaffold.js');
102
102
  const sourcePortalSync = path.join(libDir, 'portal-sync.js');
103
103
  const sourceSessionRecorder = path.join(libDir, 'session-recorder.js');
104
+ const sourceActiveSession = path.join(libDir, 'active-session.js');
104
105
  const sourceFrameworkVersion = path.join(libDir, 'framework-version.js');
105
106
  const sourceTemplatesDir = path.join(libDir, 'templates');
106
107
  const sourcePackage = path.join(__dirname, '..', 'package.json');
@@ -158,6 +159,11 @@ function installAgentLocally(force) {
158
159
  console.log(' Installed: session-recorder.js');
159
160
  }
160
161
 
162
+ if (fs.existsSync(sourceActiveSession)) {
163
+ fs.copyFileSync(sourceActiveSession, path.join(AGENT_DIR, 'active-session.js'));
164
+ console.log(' Installed: active-session.js');
165
+ }
166
+
161
167
  if (fs.existsSync(sourceFrameworkVersion)) {
162
168
  fs.copyFileSync(sourceFrameworkVersion, path.join(AGENT_DIR, 'framework-version.js'));
163
169
  console.log(' Installed: framework-version.js');
@@ -81,6 +81,48 @@ function loadTask() {
81
81
  return null;
82
82
  }
83
83
 
84
+ /**
85
+ * When QIG sends a portal task-list or PHASES prompt, the local agent should
86
+ * treat only that text as scope — not a stale multi-goal handoff wrapped by
87
+ * the backend. Unwraps "# Pair Programming Task / ## Goal" when present.
88
+ */
89
+ function extractScopedOperatorTask(raw) {
90
+ if (!raw) return raw;
91
+ let text = raw.trim();
92
+
93
+ const goalMatch = text.match(/## Goal\s*\n([\s\S]*?)(?=\n## |\n# |$)/i);
94
+ if (goalMatch && text.includes('# Pair Programming Task')) {
95
+ text = goalMatch[1].trim();
96
+ }
97
+
98
+ const selectedIdx = text.search(/Selected tasks:\s*\n/i);
99
+ if (selectedIdx >= 0) {
100
+ const header = text.includes('Execute the selected tasks')
101
+ ? 'Execute the selected tasks exactly as written below.\n'
102
+ : '';
103
+ return (header + text.slice(selectedIdx)).trim();
104
+ }
105
+
106
+ if (/execute the selected tasks/i.test(text)) {
107
+ return text;
108
+ }
109
+
110
+ if (/phases\.md/i.test(text) || /run all unchecked steps/i.test(text)) {
111
+ return text;
112
+ }
113
+
114
+ return raw.trim();
115
+ }
116
+
117
+ function isScopedOperatorTask(raw) {
118
+ if (!raw) return false;
119
+ const lower = raw.toLowerCase();
120
+ return lower.includes('selected tasks:')
121
+ || lower.includes('execute the selected tasks')
122
+ || lower.includes('phases.md')
123
+ || lower.includes('steps to complete:');
124
+ }
125
+
84
126
  // === LOAD PROJECT CONTEXT (from CLAUDE.md) ===
85
127
  function loadProjectContext() {
86
128
  const claudeMd = path.join(process.cwd(), 'CLAUDE.md');
@@ -479,7 +521,9 @@ async function runKitMode(kitMode, task, identity, scaffoldResult) {
479
521
  // === MAIN ===
480
522
  async function main() {
481
523
  const kitMode = process.env.KNOXIS_KIT_MODE || null;
482
- const task = loadTask();
524
+ const taskRaw = loadTask();
525
+ const scoped = isScopedOperatorTask(taskRaw);
526
+ const task = scoped ? extractScopedOperatorTask(taskRaw) : taskRaw;
483
527
  if (!task && !kitMode) {
484
528
  console.error('No task found. Set KNOXIS_TASK_FILE, pass as CLI argument, or include in CLAUDE.md.');
485
529
  process.exit(1);
@@ -527,6 +571,9 @@ async function main() {
527
571
  console.log('╚══════════════════════════════════════════════════════════════╝');
528
572
  console.log('');
529
573
  console.log(' Task: ' + task.substring(0, 100) + (task.length > 100 ? '...' : ''));
574
+ if (scoped) {
575
+ console.log(' Scope: portal task-list / PHASES (HANDOFF rounds ignored)');
576
+ }
530
577
  console.log(' Session: ' + SESSION_ID);
531
578
  console.log(' Recorded: ' + recorder.sessionId);
532
579
  persistActiveSession(recorder, identity, { mode: 'interactive', taskHint: task });
@@ -577,6 +624,9 @@ async function main() {
577
624
  '- NEVER ask Claude questions. You provide answers and direction only.',
578
625
  '- If Claude lists multiple options, pick the most practical one.',
579
626
  '- Push for minimal, focused changes. No scope creep.',
627
+ scoped
628
+ ? '- SCOPED SESSION: The operator task below is the only scope. Reject doc-only or HANDOFF re-affirmation plans that skip application source changes when the task requires implementation.'
629
+ : '',
580
630
  ].join('\n');
581
631
 
582
632
 
@@ -590,16 +640,21 @@ async function main() {
590
640
  appendLog('## Phase 1: Planning\n');
591
641
 
592
642
  const planPrompt = [
593
- task,
643
+ scoped
644
+ ? 'SCOPED TASK (only implement this — ignore unrelated HANDOFF.md round work):\n' + task
645
+ : task,
594
646
  '',
595
647
  'Before implementing, I need you to:',
596
648
  '1. Read the relevant existing code in this workspace',
597
649
  '2. Understand the current patterns and conventions',
598
650
  '3. Create a brief implementation plan (which files to change, what approach)',
599
651
  '4. Note any key decisions or trade-offs you see',
652
+ scoped
653
+ ? '5. Plan changes under src/ (application code), not docs-only re-affirmation unless the scoped task explicitly requires docs'
654
+ : '',
600
655
  '',
601
656
  'Share your plan and then STOP. Do not implement yet. I will review it first.',
602
- ].join('\n');
657
+ ].filter(Boolean).join('\n');
603
658
 
604
659
  const phase1Idx = recorder.startStep('understand-plan', 'Claude Code', planPrompt);
605
660
  recorder.setStepPrompt(phase1Idx, planPrompt);
@@ -635,7 +690,13 @@ async function main() {
635
690
 
636
691
  const planReviewPrompt = 'Claude produced the following plan:\n\n'
637
692
  + phase1.stdout.substring(0, 8000)
638
- + '\n\nReview this plan. Answer any questions Claude asked. Approve or suggest specific changes. Then tell Claude to proceed with implementation.';
693
+ + '\n\nScoped operator task (authoritative):\n'
694
+ + task.substring(0, 4000)
695
+ + '\n\nReview this plan against the scoped task only. Answer any questions Claude asked. '
696
+ + (scoped
697
+ ? 'Reject doc-only or HANDOFF re-affirmation plans that do not implement the scoped task in source code. '
698
+ : '')
699
+ + 'Approve or suggest specific changes. Then tell Claude to proceed with implementation.';
639
700
  const planReviewIdx = recorder.startStep('knoxis-plan-review', 'Knoxis (Groq)', planReviewPrompt);
640
701
  recorder.setStepPrompt(planReviewIdx, planReviewPrompt);
641
702
  const planReview = await callGroq(groqSystem, planReviewPrompt);
@@ -656,9 +717,26 @@ async function main() {
656
717
  console.log('');
657
718
  appendLog('## Phase 2: Implementation\n');
658
719
 
659
- const phase2Idx = recorder.startStep('implement', 'Claude Code', planReview);
660
- recorder.setStepPrompt(phase2Idx, planReview);
661
- const phase2 = await runClaudeTurn(planReview, true);
720
+ const phase2Prompt = scoped
721
+ ? [
722
+ 'IMPLEMENTATION PHASE implement the scoped task in application source code.',
723
+ '',
724
+ 'Scoped task (authoritative):',
725
+ task,
726
+ '',
727
+ 'Knoxis feedback on your plan:',
728
+ planReview,
729
+ '',
730
+ 'Requirements:',
731
+ '- Change application source (e.g. under src/) to complete the scoped task.',
732
+ '- Do NOT spend this phase only updating docs/state/*.md or HANDOFF re-affirmations unless the scoped task explicitly requires documentation.',
733
+ '- Follow existing patterns. Run the most relevant build/test when done.',
734
+ ].join('\n')
735
+ : planReview;
736
+
737
+ const phase2Idx = recorder.startStep('implement', 'Claude Code', phase2Prompt);
738
+ recorder.setStepPrompt(phase2Idx, phase2Prompt);
739
+ const phase2 = await runClaudeTurn(phase2Prompt, true);
662
740
  appendLog(phase2.stdout.substring(0, 10000) + '\n');
663
741
  recorder.completeStep(phase2Idx, phase2.stdout, phase2.code !== 0 ? `exit ${phase2.code}: ${(phase2.stderr || '').slice(0, 200)}` : null);
664
742
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knoxis-helper",
3
- "version": "1.8.4",
3
+ "version": "1.8.6",
4
4
  "description": "Local helper for Knoxis pair programming - connects your machine to Knoxis on qig.ai",
5
5
  "bin": {
6
6
  "knoxis-helper": "./bin/knoxis-helper.js"