knoxis-helper 1.5.2 → 1.6.2

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.
@@ -32,10 +32,45 @@ function extractFilesTouched(diff) {
32
32
  return Array.from(seen);
33
33
  }
34
34
 
35
- // Default git-call helpers return null on any failure (callers want a string or null).
35
+ // Snapshot the 6 well-known state files (docs/state/*.md) so the
36
+ // session record carries the latest STATUS / HANDOFF / DECISIONS / etc.
37
+ // up to the portal for display on qig.ai.
38
+ const STATE_FILES_TO_CAPTURE = [
39
+ 'docs/state/STATUS.md',
40
+ 'docs/state/HANDOFF.md',
41
+ 'docs/state/DECISIONS.md',
42
+ 'docs/state/CHANGELOG.md',
43
+ 'docs/state/OPEN_QUESTIONS.md',
44
+ 'docs/state/RISKS.md'
45
+ ];
46
+ const MAX_STATE_FILE_BYTES = 256 * 1024; // 256KB per file
47
+
48
+ function readStateFiles(workspace) {
49
+ const out = {};
50
+ if (!workspace) return out;
51
+ for (const rel of STATE_FILES_TO_CAPTURE) {
52
+ const abs = path.join(workspace, rel);
53
+ try {
54
+ const stat = fs.statSync(abs);
55
+ if (!stat.isFile()) continue;
56
+ if (stat.size > MAX_STATE_FILE_BYTES) {
57
+ out[rel] = `[File omitted: ${stat.size} bytes exceeds ${MAX_STATE_FILE_BYTES}-byte cap]`;
58
+ continue;
59
+ }
60
+ out[rel] = fs.readFileSync(abs, 'utf8');
61
+ } catch (e) {
62
+ // Missing file is normal — skip silently.
63
+ }
64
+ }
65
+ return out;
66
+ }
67
+
68
+ // Default git-call helpers — return null on any failure (callers want a string
69
+ // or null). stdio: 'pipe' prevents stderr from leaking to the parent process
70
+ // (e.g. "fatal: Needed a single revision" when the repo has no commits).
36
71
  function defaultSafeExec(cmd, cwd) {
37
72
  try {
38
- return execSync(cmd, { cwd, encoding: 'utf8', timeout: 30000 }).trim();
73
+ return execSync(cmd, { cwd, encoding: 'utf8', timeout: 30000, stdio: ['ignore', 'pipe', 'pipe'] }).trim();
39
74
  } catch (e) {
40
75
  return null;
41
76
  }
@@ -44,7 +79,10 @@ function defaultSafeExec(cmd, cwd) {
44
79
  const execAsync = util.promisify(exec);
45
80
  async function defaultSafeExecAsync(cmd, cwd) {
46
81
  try {
47
- const { stdout } = await execAsync(cmd, { cwd, encoding: 'utf8', timeout: 30000, maxBuffer: 10 * 1024 * 1024 });
82
+ // exec() inherits stderr by default; redirect to /dev/null at the shell
83
+ // level so failures (no commits, missing repo) don't pollute output.
84
+ const safeCmd = process.platform === 'win32' ? `${cmd} 2>nul` : `${cmd} 2>/dev/null`;
85
+ const { stdout } = await execAsync(safeCmd, { cwd, encoding: 'utf8', timeout: 30000, maxBuffer: 10 * 1024 * 1024 });
48
86
  return stdout.trim();
49
87
  } catch (e) {
50
88
  return null;
@@ -204,6 +242,10 @@ class SessionRecorder {
204
242
  completedSteps,
205
243
  closedCleanly,
206
244
  filesTouched: extractFilesTouched(totalDiff),
245
+ // Snapshot of docs/state/*.md at session-end so the QIG frontend can
246
+ // display the latest STATUS / HANDOFF / DECISIONS / etc. without
247
+ // needing live filesystem access on the dev's machine.
248
+ stateFiles: readStateFiles(this.workspace),
207
249
  decisionsLogged: [],
208
250
  waiversRequested: [],
209
251
  incidentsFlagged: [],
@@ -19,13 +19,17 @@ const STATE_LAYOUT = {
19
19
  overwrite: false
20
20
  },
21
21
  {
22
+ // Empty sections so the digest parser returns []s instead of inheriting
23
+ // scaffold copy. Claude populates Done / In flight / Next / Notes during
24
+ // session-end per the standards in the systemIntro.
22
25
  path: 'docs/state/STATUS.md',
23
- content: () => `# Status\n\n_Last updated: ${today()}_\n\n## Done\n- (Project initialized; nothing yet.)\n\n## In flight\n- (None.)\n\n## Next\n- Run \`knoxis-pair-program --mode kickoff\` to populate the context pack, then begin Session 1.\n\n## Notes\n- Scaffolded by knoxis-helper.\n`,
26
+ content: () => `# Status\n\n_Last updated: ${today()}_\n\n## Done\n\n## In flight\n\n## Next\n\n## Notes\n`,
24
27
  overwrite: false
25
28
  },
26
29
  {
30
+ // Empty placeholder. HANDOFF gets overwritten in full at every session-end.
27
31
  path: 'docs/state/HANDOFF.md',
28
- content: () => `# Handoff\n\n_Session ended: not yet project freshly scaffolded._\n\n## Where I stopped\nProject scaffold created. No code written yet.\n\n## Why I stopped here\nWaiting on the kickoff interview to populate the context pack.\n\n## First thing to do next session\nRun \`knoxis-pair-program --mode kickoff\` and complete the interview.\n\n## Landmines / gotchas\nNone.\n\n## Environment state\nNone.\n`,
32
+ content: () => `# Handoff\n\n_No prior sessionthis file is overwritten at session-end._\n\n## Where I stopped\n\n## Why I stopped here\n\n## First thing to do next session\n\n## Landmines / gotchas\n\n## Environment state\n`,
29
33
  overwrite: false
30
34
  },
31
35
  {
@@ -34,8 +38,11 @@ const STATE_LAYOUT = {
34
38
  overwrite: false
35
39
  },
36
40
  {
41
+ // Empty Unreleased block — Claude appends real entries at session-end
42
+ // when code actually shipped. No fake "scaffolded" entry that would
43
+ // surface as a real changelog item on the dashboard.
37
44
  path: 'docs/state/CHANGELOG.md',
38
- content: () => `# Changelog\n\nAll notable changes to this project will be documented in this file.\nFormat: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).\n\n## [Unreleased]\n\n### Added\n- Project scaffolded by knoxis-helper on ${today()}.\n`,
45
+ content: () => `# Changelog\n\nAll notable changes to this project will be documented in this file.\nFormat: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).\n\n## [Unreleased]\n\n### Added\n\n### Changed\n\n### Fixed\n\n### Removed\n`,
39
46
  overwrite: false
40
47
  },
41
48
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knoxis-helper",
3
- "version": "1.5.2",
3
+ "version": "1.6.2",
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"