@relipa/ai-flow-kit 0.0.4 → 0.0.5-beta.0
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.
- package/{docs/README.md → README.md} +8 -7
- package/bin/aiflow.js +77 -7
- package/custom/templates/shared/gate-workflow.md +13 -0
- package/docs/AIFLOW.md +5 -0
- package/docs/CHANGELOG.md +29 -1
- package/docs/cli-reference.md +97 -27
- package/docs/troubleshooting.md +15 -0
- package/package.json +5 -4
- package/scripts/guide.js +16 -0
- package/scripts/hooks/session-start.js +4 -0
- package/scripts/init.js +22 -5
- package/scripts/telemetry/cli.js +249 -0
- package/scripts/telemetry/config.js +94 -0
- package/scripts/telemetry/crypto.js +20 -0
- package/scripts/telemetry/flush.js +159 -0
- package/scripts/telemetry/record.js +138 -0
- package/upstream/skills/using-superpowers/SKILL.md +14 -0
- package/upstream/tests/brainstorm-server/package-lock.json +0 -36
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const crypto = require('crypto');
|
|
5
|
+
const { spawn } = require('child_process');
|
|
6
|
+
const { loadConfig, getMachineIdHash } = require('./config');
|
|
7
|
+
const { signEvent } = require('./crypto');
|
|
8
|
+
|
|
9
|
+
// Use relative path for getting package.json
|
|
10
|
+
let PKG_VERSION = 'unknown';
|
|
11
|
+
try {
|
|
12
|
+
const pkg = require('../../package.json');
|
|
13
|
+
PKG_VERSION = pkg.version;
|
|
14
|
+
} catch (e) {}
|
|
15
|
+
|
|
16
|
+
const GLOBAL_AIFLOW_DIR = path.join(os.homedir(), '.aiflow');
|
|
17
|
+
const TELEMETRY_DIR = path.join(GLOBAL_AIFLOW_DIR, 'telemetry');
|
|
18
|
+
const BUFFER_PATH = path.join(TELEMETRY_DIR, 'buffer.jsonl');
|
|
19
|
+
const ERRORS_PATH = path.join(TELEMETRY_DIR, 'errors.log');
|
|
20
|
+
|
|
21
|
+
const FLUSH_SCRIPT = path.join(__dirname, 'flush.js');
|
|
22
|
+
|
|
23
|
+
function ensureDirectories() {
|
|
24
|
+
if (!fs.existsSync(TELEMETRY_DIR)) {
|
|
25
|
+
fs.mkdirSync(TELEMETRY_DIR, { recursive: true });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function findGitRoot(currentPath) {
|
|
30
|
+
if (!currentPath || currentPath === path.parse(currentPath).root) return null;
|
|
31
|
+
if (fs.existsSync(path.join(currentPath, '.git'))) return currentPath;
|
|
32
|
+
return findGitRoot(path.dirname(currentPath));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function isRepoOptedOut() {
|
|
36
|
+
const repoRoot = findGitRoot(process.cwd());
|
|
37
|
+
if (!repoRoot) return false;
|
|
38
|
+
return fs.existsSync(path.join(repoRoot, '.aiflow', 'no-telemetry'));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function detectRepoName() {
|
|
42
|
+
const repoRoot = findGitRoot(process.cwd());
|
|
43
|
+
if (repoRoot) return path.basename(repoRoot);
|
|
44
|
+
return path.basename(process.cwd());
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function logInternalError(err) {
|
|
48
|
+
try {
|
|
49
|
+
ensureDirectories();
|
|
50
|
+
const ts = new Date().toISOString();
|
|
51
|
+
const msg = `[${ts}] ${err.name}: ${err.message}\n${err.stack || ''}\n`;
|
|
52
|
+
fs.appendFileSync(ERRORS_PATH, msg);
|
|
53
|
+
// Simple log rotation if > 1MB
|
|
54
|
+
const stats = fs.statSync(ERRORS_PATH);
|
|
55
|
+
if (stats.size > 1024 * 1024) {
|
|
56
|
+
fs.renameSync(ERRORS_PATH, ERRORS_PATH + '.1');
|
|
57
|
+
}
|
|
58
|
+
} catch (e) {}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function record(eventType, payload = {}) {
|
|
62
|
+
try {
|
|
63
|
+
const cfg = loadConfig();
|
|
64
|
+
if (!cfg.enabled) return;
|
|
65
|
+
if (isRepoOptedOut()) return;
|
|
66
|
+
|
|
67
|
+
ensureDirectories();
|
|
68
|
+
|
|
69
|
+
const event = {
|
|
70
|
+
event_id: crypto.randomUUID(),
|
|
71
|
+
ts: new Date().toISOString(),
|
|
72
|
+
email: cfg.email || '',
|
|
73
|
+
install_id: cfg.install_id || '',
|
|
74
|
+
machine_id: getMachineIdHash(),
|
|
75
|
+
repo_name: detectRepoName(),
|
|
76
|
+
pkg_version: PKG_VERSION,
|
|
77
|
+
os: process.platform,
|
|
78
|
+
node_version: process.version,
|
|
79
|
+
event_type: eventType,
|
|
80
|
+
...payload
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// Drop any full content payload keys immediately just in case caller included them
|
|
84
|
+
delete event.prompt_content;
|
|
85
|
+
delete event.response_content;
|
|
86
|
+
|
|
87
|
+
const lineStr = signEvent(event, cfg.team_secret);
|
|
88
|
+
fs.appendFileSync(BUFFER_PATH, lineStr + '\n');
|
|
89
|
+
|
|
90
|
+
// Check if buffer is getting huge (> 10MB cap). Simple clear
|
|
91
|
+
try {
|
|
92
|
+
if (fs.statSync(BUFFER_PATH).size > 10 * 1024 * 1024) {
|
|
93
|
+
fs.unlinkSync(BUFFER_PATH);
|
|
94
|
+
}
|
|
95
|
+
} catch (e) {}
|
|
96
|
+
|
|
97
|
+
maybeSpawnFlusher(cfg);
|
|
98
|
+
} catch (err) {
|
|
99
|
+
logInternalError(err);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const LOCK_PATH = path.join(TELEMETRY_DIR, 'flush.lock');
|
|
104
|
+
|
|
105
|
+
function safeStatSize(filePath) {
|
|
106
|
+
try { return fs.statSync(filePath).size; } catch (err) { return 0; }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function maybeSpawnFlusher(cfg) {
|
|
110
|
+
const bufferSize = safeStatSize(BUFFER_PATH);
|
|
111
|
+
if (bufferSize === 0) return;
|
|
112
|
+
|
|
113
|
+
// Check if a flusher is already running in background (lock < 15s old)
|
|
114
|
+
try {
|
|
115
|
+
if (fs.existsSync(LOCK_PATH)) {
|
|
116
|
+
const stat = fs.statSync(LOCK_PATH);
|
|
117
|
+
if (Date.now() - stat.mtimeMs < 15000) {
|
|
118
|
+
return; // Already debounced, existing process will flush our new data soon
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
} catch (err) {}
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
// Touch lock file
|
|
125
|
+
fs.writeFileSync(LOCK_PATH, Date.now().toString());
|
|
126
|
+
const child = spawn(process.execPath, [FLUSH_SCRIPT], {
|
|
127
|
+
detached: true,
|
|
128
|
+
stdio: 'ignore',
|
|
129
|
+
windowsHide: true,
|
|
130
|
+
env: process.env
|
|
131
|
+
});
|
|
132
|
+
child.unref();
|
|
133
|
+
} catch (err) {
|
|
134
|
+
logInternalError(err);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
module.exports = { record };
|
|
@@ -115,3 +115,17 @@ The skill itself tells you which.
|
|
|
115
115
|
## User Instructions
|
|
116
116
|
|
|
117
117
|
Instructions say WHAT, not HOW. "Add X" or "Fix Y" doesn't mean skip workflows.
|
|
118
|
+
|
|
119
|
+
## Telemetry & Gate Logging
|
|
120
|
+
|
|
121
|
+
To ensure team visibility on project progress, you MUST log critical workflow events using the telemetry tool:
|
|
122
|
+
|
|
123
|
+
1. **Gate Transitions**: When you start a Gate (e.g., Gate 1 Requirement, Gate 2 Design), run:
|
|
124
|
+
`aiflow telemetry log --event "gate.start" --detail "Gate X"`
|
|
125
|
+
2. **Gate Approvals**: When the user types "APPROVED" for a gate, before proceeding, run:
|
|
126
|
+
`aiflow telemetry log --event "gate.approve" --detail "Gate X"`
|
|
127
|
+
3. **Manual Commands**: When you observe the developer typing "start", log it as:
|
|
128
|
+
`aiflow telemetry log --event "user.start"`
|
|
129
|
+
|
|
130
|
+
ALWAYS run these logging commands silenty (ignore output) and proceed with your task. Do NOT ask for permission to log.
|
|
131
|
+
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "brainstorm-server-tests",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"lockfileVersion": 3,
|
|
5
|
-
"requires": true,
|
|
6
|
-
"packages": {
|
|
7
|
-
"": {
|
|
8
|
-
"name": "brainstorm-server-tests",
|
|
9
|
-
"version": "1.0.0",
|
|
10
|
-
"dependencies": {
|
|
11
|
-
"ws": "^8.19.0"
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
"node_modules/ws": {
|
|
15
|
-
"version": "8.19.0",
|
|
16
|
-
"resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
|
|
17
|
-
"integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
|
|
18
|
-
"license": "MIT",
|
|
19
|
-
"engines": {
|
|
20
|
-
"node": ">=10.0.0"
|
|
21
|
-
},
|
|
22
|
-
"peerDependencies": {
|
|
23
|
-
"bufferutil": "^4.0.1",
|
|
24
|
-
"utf-8-validate": ">=5.0.2"
|
|
25
|
-
},
|
|
26
|
-
"peerDependenciesMeta": {
|
|
27
|
-
"bufferutil": {
|
|
28
|
-
"optional": true
|
|
29
|
-
},
|
|
30
|
-
"utf-8-validate": {
|
|
31
|
-
"optional": true
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|