@devness/useai 0.4.12 → 0.4.14

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 (2) hide show
  1. package/dist/index.js +64 -16
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -112,7 +112,7 @@ var VERSION;
112
112
  var init_version = __esm({
113
113
  "../shared/dist/constants/version.js"() {
114
114
  "use strict";
115
- VERSION = "0.4.12";
115
+ VERSION = "0.4.14";
116
116
  }
117
117
  });
118
118
 
@@ -857,15 +857,32 @@ function writeSettings(settings) {
857
857
  function installClaudeCodeHooks() {
858
858
  mkdirSync3(USEAI_HOOKS_DIR, { recursive: true });
859
859
  writeFileSync3(STOP_GUARD_PATH, STOP_GUARD_SCRIPT);
860
+ writeFileSync3(PROMPT_GUARD_PATH, PROMPT_GUARD_SCRIPT);
860
861
  try {
861
862
  chmodSync(STOP_GUARD_PATH, "755");
862
863
  } catch {
863
864
  }
865
+ try {
866
+ chmodSync(PROMPT_GUARD_PATH, "755");
867
+ } catch {
868
+ }
864
869
  const settings = readSettings();
865
870
  const hooks = settings["hooks"] ?? {};
871
+ const promptCmd = `node "${PROMPT_GUARD_PATH}"`;
866
872
  const stopCmd = `node "${STOP_GUARD_PATH}"`;
867
873
  const sealCmd = `curl -sf -X POST http://127.0.0.1:${DAEMON_PORT}/api/seal-active --max-time 3 2>/dev/null || true`;
868
874
  let changed = false;
875
+ if (!hooks["UserPromptSubmit"])
876
+ hooks["UserPromptSubmit"] = [];
877
+ const promptArr = hooks["UserPromptSubmit"];
878
+ const hasPrompt = promptArr.some((g) => {
879
+ const inner = g["hooks"];
880
+ return inner?.some((h) => h["command"]?.includes("prompt-guard"));
881
+ });
882
+ if (!hasPrompt) {
883
+ promptArr.push({ hooks: [{ type: "command", command: promptCmd, timeout: 10 }] });
884
+ changed = true;
885
+ }
869
886
  if (!hooks["Stop"])
870
887
  hooks["Stop"] = [];
871
888
  const stopArr = hooks["Stop"];
@@ -898,6 +915,14 @@ function removeClaudeCodeHooks() {
898
915
  const settings = readSettings();
899
916
  const hooks = settings["hooks"];
900
917
  if (hooks) {
918
+ if (hooks["UserPromptSubmit"]) {
919
+ hooks["UserPromptSubmit"] = hooks["UserPromptSubmit"].filter((g) => {
920
+ const inner = g["hooks"];
921
+ return !inner?.some((h) => h["command"]?.includes("prompt-guard"));
922
+ });
923
+ if (hooks["UserPromptSubmit"].length === 0)
924
+ delete hooks["UserPromptSubmit"];
925
+ }
901
926
  if (hooks["Stop"]) {
902
927
  hooks["Stop"] = hooks["Stop"].filter((g) => {
903
928
  const inner = g["hooks"];
@@ -926,13 +951,19 @@ function removeClaudeCodeHooks() {
926
951
  unlinkSync3(STOP_GUARD_PATH);
927
952
  } catch {
928
953
  }
954
+ try {
955
+ if (existsSync5(PROMPT_GUARD_PATH))
956
+ unlinkSync3(PROMPT_GUARD_PATH);
957
+ } catch {
958
+ }
929
959
  }
930
- var STOP_GUARD_PATH, CLAUDE_SETTINGS_PATH, STOP_GUARD_SCRIPT;
960
+ var STOP_GUARD_PATH, PROMPT_GUARD_PATH, CLAUDE_SETTINGS_PATH, STOP_GUARD_SCRIPT, PROMPT_GUARD_SCRIPT;
931
961
  var init_claude_code = __esm({
932
962
  "../shared/dist/hooks/claude-code.js"() {
933
963
  "use strict";
934
964
  init_paths();
935
965
  STOP_GUARD_PATH = join3(USEAI_HOOKS_DIR, "stop-guard.js");
966
+ PROMPT_GUARD_PATH = join3(USEAI_HOOKS_DIR, "prompt-guard.js");
936
967
  CLAUDE_SETTINGS_PATH = join3(homedir3(), ".claude", "settings.json");
937
968
  STOP_GUARD_SCRIPT = `#!/usr/bin/env node
938
969
  'use strict';
@@ -950,17 +981,35 @@ process.stdin.on('end', () => {
950
981
  var starts = (transcript.match(/useai_session_start/g) || []).length;
951
982
  if (starts === 0) process.exit(0);
952
983
  var ends = (transcript.match(/useai_session_end/g) || []).length;
953
- if (starts > ends) {
954
- process.stdout.write(JSON.stringify({
955
- decision: 'block',
956
- reason: 'Before ending, call useai_session_end with milestones (generic descriptions of accomplishments), languages used, and files_touched_count.'
957
- }));
958
- } else {
959
- process.stdout.write(JSON.stringify({
960
- decision: 'block',
961
- reason: 'You did work without UseAI tracking. Call useai_session_start first, then useai_session_end with milestones (generic descriptions of accomplishments), languages used, and files_touched_count.'
962
- }));
963
- }
984
+ if (ends >= starts) process.exit(0);
985
+ process.stdout.write(JSON.stringify({
986
+ decision: 'block',
987
+ reason: 'Before ending, call useai_session_end with milestones (generic descriptions of accomplishments), languages used, and files_touched_count.'
988
+ }));
989
+ } catch { process.exit(0); }
990
+ });
991
+ `;
992
+ PROMPT_GUARD_SCRIPT = `#!/usr/bin/env node
993
+ 'use strict';
994
+ const { readFileSync } = require('node:fs');
995
+ let input = '';
996
+ process.stdin.setEncoding('utf-8');
997
+ process.stdin.on('data', chunk => input += chunk);
998
+ process.stdin.on('end', () => {
999
+ try {
1000
+ const hook = JSON.parse(input);
1001
+ if (!hook.transcript_path) process.exit(0);
1002
+ let transcript;
1003
+ try { transcript = readFileSync(hook.transcript_path, 'utf-8'); } catch { process.exit(0); }
1004
+ var starts = (transcript.match(/useai_session_start/g) || []).length;
1005
+ var ends = (transcript.match(/useai_session_end/g) || []).length;
1006
+ if (starts > ends) process.exit(0);
1007
+ process.stdout.write(JSON.stringify({
1008
+ hookSpecificOutput: {
1009
+ hookEventName: 'UserPromptSubmit',
1010
+ additionalContext: 'UseAI: Call useai_session_start with the appropriate task_type before doing any work.'
1011
+ }
1012
+ }));
964
1013
  } catch { process.exit(0); }
965
1014
  });
966
1015
  `;
@@ -1118,8 +1167,7 @@ function registerTools(server2, session2) {
1118
1167
  content: [
1119
1168
  {
1120
1169
  type: "text",
1121
- text: `useai session started \u2014 tracking ${session2.sessionTaskType} session on ${session2.clientName}.
1122
- Session: ${session2.sessionId.slice(0, 8)} \xB7 Chain: ${record.hash.slice(0, 12)} (${session2.signingAvailable ? "signed" : "unsigned"})`
1170
+ text: `${session2.sessionTaskType} \xB7 ${session2.sessionId.slice(0, 8)}`
1123
1171
  }
1124
1172
  ]
1125
1173
  };
@@ -1889,7 +1937,7 @@ async function daemonInstallFlow(tools, explicit) {
1889
1937
  try {
1890
1938
  const hooksInstalled = installClaudeCodeHooks();
1891
1939
  if (hooksInstalled) {
1892
- console.log(ok("\u2713 Claude Code hooks installed (Stop + SessionEnd)"));
1940
+ console.log(ok("\u2713 Claude Code hooks installed (UserPromptSubmit + Stop + SessionEnd)"));
1893
1941
  }
1894
1942
  } catch {
1895
1943
  console.log(chalk.yellow(" \u26A0 Could not install Claude Code hooks"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devness/useai",
3
- "version": "0.4.12",
3
+ "version": "0.4.14",
4
4
  "description": "Track your AI-assisted development workflow. MCP server that records usage metrics across all your AI tools.",
5
5
  "keywords": [
6
6
  "mcp",