@stackmemoryai/stackmemory 0.8.0 → 0.8.1

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.
@@ -1,174 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Claude Code hook for processing SMS responses and triggering next actions
4
- *
5
- * This hook:
6
- * 1. Checks for pending SMS responses on startup
7
- * 2. Executes queued actions from SMS responses
8
- * 3. Injects response context into Claude session
9
- *
10
- * Install: stackmemory notify install-response-hook
11
- */
12
-
13
- const fs = require('fs');
14
- const path = require('path');
15
- const os = require('os');
16
- const { execSync } = require('child_process');
17
-
18
- const QUEUE_PATH = path.join(
19
- os.homedir(),
20
- '.stackmemory',
21
- 'sms-action-queue.json'
22
- );
23
- const RESPONSE_PATH = path.join(
24
- os.homedir(),
25
- '.stackmemory',
26
- 'sms-latest-response.json'
27
- );
28
-
29
- function loadActionQueue() {
30
- try {
31
- if (fs.existsSync(QUEUE_PATH)) {
32
- return JSON.parse(fs.readFileSync(QUEUE_PATH, 'utf8'));
33
- }
34
- } catch {}
35
- return { actions: [] };
36
- }
37
-
38
- function saveActionQueue(queue) {
39
- const dir = path.join(os.homedir(), '.stackmemory');
40
- if (!fs.existsSync(dir)) {
41
- fs.mkdirSync(dir, { recursive: true });
42
- }
43
- fs.writeFileSync(QUEUE_PATH, JSON.stringify(queue, null, 2));
44
- }
45
-
46
- function loadLatestResponse() {
47
- try {
48
- if (fs.existsSync(RESPONSE_PATH)) {
49
- const data = JSON.parse(fs.readFileSync(RESPONSE_PATH, 'utf8'));
50
- // Only return if less than 5 minutes old
51
- const age = Date.now() - new Date(data.timestamp).getTime();
52
- if (age < 5 * 60 * 1000) {
53
- return data;
54
- }
55
- }
56
- } catch {}
57
- return null;
58
- }
59
-
60
- function clearLatestResponse() {
61
- try {
62
- if (fs.existsSync(RESPONSE_PATH)) {
63
- fs.unlinkSync(RESPONSE_PATH);
64
- }
65
- } catch {}
66
- }
67
-
68
- function executeAction(action) {
69
- try {
70
- console.error(`[sms-hook] Executing: ${action.action}`);
71
- const output = execSync(action.action, {
72
- encoding: 'utf8',
73
- timeout: 60000,
74
- stdio: ['pipe', 'pipe', 'pipe'],
75
- });
76
- return { success: true, output };
77
- } catch (err) {
78
- return { success: false, error: err.message };
79
- }
80
- }
81
-
82
- function processPendingActions() {
83
- const queue = loadActionQueue();
84
- const pending = queue.actions.filter((a) => a.status === 'pending');
85
-
86
- if (pending.length === 0) return null;
87
-
88
- const results = [];
89
-
90
- for (const action of pending) {
91
- action.status = 'running';
92
- saveActionQueue(queue);
93
-
94
- const result = executeAction(action);
95
-
96
- action.status = result.success ? 'completed' : 'failed';
97
- action.result = result.output;
98
- action.error = result.error;
99
- saveActionQueue(queue);
100
-
101
- results.push({
102
- action: action.action,
103
- response: action.response,
104
- success: result.success,
105
- output: result.output?.substring(0, 500),
106
- error: result.error,
107
- });
108
- }
109
-
110
- return results;
111
- }
112
-
113
- // Read hook input from stdin
114
- let input = '';
115
- process.stdin.setEncoding('utf8');
116
- process.stdin.on('data', (chunk) => (input += chunk));
117
- process.stdin.on('end', () => {
118
- try {
119
- const hookData = JSON.parse(input);
120
- const { hook_type } = hookData;
121
-
122
- // On session start, check for pending responses
123
- if (hook_type === 'on_startup' || hook_type === 'pre_tool_use') {
124
- // Check for SMS response waiting
125
- const latestResponse = loadLatestResponse();
126
- if (latestResponse) {
127
- console.error(
128
- `[sms-hook] SMS response received: "${latestResponse.response}"`
129
- );
130
-
131
- // Inject context for Claude
132
- const context = {
133
- type: 'sms_response',
134
- response: latestResponse.response,
135
- promptId: latestResponse.promptId,
136
- timestamp: latestResponse.timestamp,
137
- message: `User responded via SMS: "${latestResponse.response}"`,
138
- };
139
-
140
- clearLatestResponse();
141
-
142
- // Log context to stderr for visibility, allow the tool
143
- console.error(`[sms-hook] Context: ${JSON.stringify(context)}`);
144
- console.log(JSON.stringify({ permissionDecision: 'allow' }));
145
- return;
146
- }
147
-
148
- // Process any pending actions
149
- const results = processPendingActions();
150
- if (results && results.length > 0) {
151
- console.error(`[sms-hook] Processed ${results.length} action(s)`);
152
-
153
- const summary = results
154
- .map((r) =>
155
- r.success
156
- ? `Executed: ${r.action.substring(0, 50)}...`
157
- : `Failed: ${r.action.substring(0, 50)}... (${r.error})`
158
- )
159
- .join('\n');
160
-
161
- // Log results to stderr for visibility, allow the tool
162
- console.error(`[sms-hook] Actions summary:\n${summary}`);
163
- console.log(JSON.stringify({ permissionDecision: 'allow' }));
164
- return;
165
- }
166
- }
167
-
168
- // Default: allow everything
169
- console.log(JSON.stringify({ permissionDecision: 'allow' }));
170
- } catch (err) {
171
- console.error('[sms-hook] Error:', err.message);
172
- console.log(JSON.stringify({ permissionDecision: 'allow' }));
173
- }
174
- });