@cccarv82/freya 3.6.1 → 3.7.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.
@@ -44,14 +44,17 @@ function setWorkspaceVersion(workspaceDir, version) {
44
44
  }
45
45
 
46
46
  function needsNpmInstall(workspaceDir) {
47
- // Check if sql.js is installed in the workspace's node_modules
48
- const sqlJsPath = path.join(workspaceDir, 'node_modules', 'sql.js');
49
- try {
50
- fs.accessSync(sqlJsPath);
51
- return false;
52
- } catch {
53
- return true;
47
+ // Check if ALL required dependencies are installed in the workspace's node_modules
48
+ const requiredDeps = ['sql.js', '@huggingface/transformers'];
49
+ for (const dep of requiredDeps) {
50
+ const depPath = path.join(workspaceDir, 'node_modules', dep);
51
+ try {
52
+ fs.accessSync(depPath);
53
+ } catch {
54
+ return true; // At least one dependency missing
55
+ }
54
56
  }
57
+ return false;
55
58
  }
56
59
 
57
60
  function runNpmInstall(workspaceDir) {
@@ -85,8 +88,12 @@ async function autoUpdate(workspaceDir) {
85
88
  const installedVersion = getInstalledVersion();
86
89
  const workspaceVersion = getWorkspaceVersion(workspaceDir);
87
90
 
88
- // Already in sync
91
+ // Already in sync — but still check if deps are missing (e.g. new dep added in same version)
89
92
  if (workspaceVersion === installedVersion) {
93
+ if (needsNpmInstall(workspaceDir)) {
94
+ console.log('[FREYA] Missing workspace dependencies detected, installing...');
95
+ runNpmInstall(workspaceDir);
96
+ }
90
97
  return { updated: false, version: installedVersion };
91
98
  }
92
99
 
package/cli/init.js CHANGED
@@ -93,7 +93,8 @@ function ensurePackageJson(targetDir, force, summary) {
93
93
  };
94
94
 
95
95
  const depsToEnsure = {
96
- 'sql.js': '^1.12.0'
96
+ 'sql.js': '^1.12.0',
97
+ '@huggingface/transformers': '^3.8.1'
97
98
  };
98
99
 
99
100
  if (!existing) {
package/cli/web.js CHANGED
@@ -910,7 +910,8 @@ function run(cmd, args, cwd, extraEnv, stdinData) {
910
910
 
911
911
  try {
912
912
  // On Windows, reliably execute CLI tools through cmd.exe.
913
- if (process.platform === 'win32' && (cmd === 'npx' || cmd === 'npm')) {
913
+ // This ensures PATH resolution works for tools like copilot, gh, npx, npm.
914
+ if (process.platform === 'win32') {
914
915
  const comspec = process.env.ComSpec || 'cmd.exe';
915
916
  child = spawn(comspec, ['/d', '/s', '/c', cmd, ...args], { cwd, shell: false, env });
916
917
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cccarv82/freya",
3
- "version": "3.6.1",
3
+ "version": "3.7.2",
4
4
  "description": "Personal AI Assistant with local-first persistence",
5
5
  "scripts": {
6
6
  "health": "node scripts/validate-data.js && node scripts/validate-structure.js",
@@ -1,3 +1,56 @@
1
+ const path = require('path');
2
+
3
+ /**
4
+ * Resolve the @huggingface/transformers package from multiple locations:
5
+ * 1. Local workspace node_modules (preferred)
6
+ * 2. Global FREYA package node_modules (fallback)
7
+ * 3. Parent directory traversal (npm global installs)
8
+ */
9
+ async function resolveTransformers() {
10
+ // Try 1: direct dynamic import (works if in local node_modules)
11
+ try {
12
+ return await import('@huggingface/transformers');
13
+ } catch { /* not found locally */ }
14
+
15
+ // Try 2: resolve from the global FREYA package directory
16
+ // When installed globally, the package lives at <prefix>/node_modules/@cccarv82/freya/
17
+ // and its dependencies are at <prefix>/node_modules/@huggingface/transformers/
18
+ const globalPaths = [
19
+ // npm global: sibling of @cccarv82/freya in the same node_modules
20
+ path.resolve(__dirname, '..', '..', '..', 'node_modules', '@huggingface', 'transformers'),
21
+ // npm global: nested inside the FREYA package
22
+ path.resolve(__dirname, '..', '..', 'node_modules', '@huggingface', 'transformers'),
23
+ // Hoisted in global prefix
24
+ path.resolve(__dirname, '..', '..', '..', '..', '@huggingface', 'transformers'),
25
+ ];
26
+
27
+ for (const p of globalPaths) {
28
+ try {
29
+ const resolved = require.resolve(p);
30
+ if (resolved) return await import(resolved);
31
+ } catch { /* try next */ }
32
+ }
33
+
34
+ // Try 3: use require.resolve with paths option to search upward
35
+ try {
36
+ const modPath = require.resolve('@huggingface/transformers', {
37
+ paths: [
38
+ path.resolve(__dirname, '..', '..'), // workspace root
39
+ path.resolve(__dirname, '..', '..', '..'), // parent of workspace
40
+ path.resolve(__dirname, '..', '..', '..', '..'), // grandparent
41
+ process.execPath ? path.dirname(path.dirname(process.execPath)) : '', // node prefix
42
+ ].filter(Boolean)
43
+ });
44
+ return await import(modPath);
45
+ } catch { /* exhausted all options */ }
46
+
47
+ throw new Error(
48
+ 'Cannot find @huggingface/transformers. ' +
49
+ 'Run "npm install" in your FREYA workspace to install dependencies, ' +
50
+ 'or run "freya init" first to update your workspace package.json.'
51
+ );
52
+ }
53
+
1
54
  class Embedder {
2
55
  constructor() {
3
56
  // V3: use the official HuggingFace model name (same weights, new namespace)
@@ -10,9 +63,7 @@ class Embedder {
10
63
  if (this.extractorInfo) return;
11
64
  if (!this.initPromise) {
12
65
  this.initPromise = (async () => {
13
- // V3: @huggingface/transformers replaces @xenova/transformers
14
- // sharp 0.34+ uses prebuilt platform binaries (no node-gyp needed)
15
- const { pipeline } = await import('@huggingface/transformers');
66
+ const { pipeline } = await resolveTransformers();
16
67
  this.extractorInfo = await pipeline('feature-extraction', this.modelName, { quantized: true });
17
68
  })().catch((err) => {
18
69
  this.initPromise = null;
@@ -189,7 +189,28 @@ async function main() {
189
189
  // Step 3: Extract tasks/blockers from each daily log via planner
190
190
  console.log('── Step 3: Extracting tasks & blockers via planner ──');
191
191
 
192
- const cmd = process.env.COPILOT_CMD || 'copilot';
192
+ // Detect copilot command: try user override, then 'copilot', then 'gh copilot'
193
+ let cmd = process.env.COPILOT_CMD || '';
194
+ if (!cmd) {
195
+ // Quick test: try 'copilot --version'
196
+ const testCopilot = await run('copilot', ['--version'], workspaceDir);
197
+ if (testCopilot.code === 0) {
198
+ cmd = 'copilot';
199
+ } else {
200
+ // Try 'gh copilot' via 'gh'
201
+ const testGh = await run('gh', ['copilot', '--version'], workspaceDir);
202
+ if (testGh.code === 0) {
203
+ cmd = 'gh';
204
+ console.log(' ℹ Using "gh copilot" as planner command');
205
+ } else {
206
+ cmd = 'copilot'; // default, will fail with clear error
207
+ console.log(' ⚠ Could not detect copilot CLI. Set COPILOT_CMD env var if needed.');
208
+ console.log(` copilot test: code=${testCopilot.code} stderr=${(testCopilot.stderr || '').slice(0, 200)}`);
209
+ console.log(` gh copilot test: code=${testGh.code} stderr=${(testGh.stderr || '').slice(0, 200)}`);
210
+ }
211
+ }
212
+ }
213
+ const useGhCopilot = cmd === 'gh';
193
214
  const agentEnv = { FREYA_WORKSPACE_DIR: workspaceDir };
194
215
  const slugMap = readProjectSlugMap(workspaceDir);
195
216
  const validTaskCats = new Set(['DO_NOW', 'SCHEDULE', 'DELEGATE', 'IGNORE']);
@@ -242,20 +263,32 @@ IMPORTANTE: Extraia APENAS informações explícitas do log. NÃO invente dados.
242
263
 
243
264
  try {
244
265
  let r;
266
+ const baseArgs = useGhCopilot
267
+ ? ['copilot', '-s', '--no-color', '--stream', 'off']
268
+ : ['-s', '--no-color', '--stream', 'off'];
269
+
245
270
  if (fullPrompt.length > SAFE_ARG_LEN) {
246
271
  const tmpFile = path.join(os.tmpdir(), `freya-retro-${Date.now()}.txt`);
247
272
  fs.writeFileSync(tmpFile, fullPrompt, 'utf8');
248
273
  const filePrompt = `Leia o arquivo abaixo e extraia tasks/blockers conforme as instruções contidas nele.\nARQUIVO: ${tmpFile}`;
249
- r = await run(cmd, ['-s', '--no-color', '--stream', 'off', '--add-dir', os.tmpdir(), '--allow-all-tools', '-p', filePrompt], workspaceDir, agentEnv);
274
+ r = await run(cmd, [...baseArgs, '--add-dir', os.tmpdir(), '--allow-all-tools', '-p', filePrompt], workspaceDir, agentEnv);
250
275
  try { fs.unlinkSync(tmpFile); } catch { }
251
276
  } else {
252
- r = await run(cmd, ['-s', '--no-color', '--stream', 'off', '-p', fullPrompt], workspaceDir, agentEnv);
277
+ r = await run(cmd, [...baseArgs, '-p', fullPrompt], workspaceDir, agentEnv);
253
278
  }
254
279
 
255
280
  const out = (r.stdout + r.stderr).trim();
256
281
  if (r.code !== 0 || !out) {
257
282
  totalErrors++;
258
- process.stdout.write(`\r [${i + 1}/${files.length}] ${date} planner error `);
283
+ // On first error, show verbose diagnostic
284
+ if (totalErrors === 1) {
285
+ console.log(`\n ⚠ Planner diagnostic for ${date}:`);
286
+ console.log(` Command: ${cmd} ${(useGhCopilot ? baseArgs : ['-s', '--no-color', '--stream', 'off', '-p', '...']).join(' ')}`);
287
+ console.log(` Exit code: ${r.code}`);
288
+ console.log(` stdout: ${(r.stdout || '').slice(0, 300)}`);
289
+ console.log(` stderr: ${(r.stderr || '').slice(0, 300)}`);
290
+ }
291
+ process.stdout.write(`\r [${i + 1}/${files.length}] ${date} — ❌ planner error (code=${r.code}) `);
259
292
  continue;
260
293
  }
261
294
 
@@ -1,3 +1,56 @@
1
+ const path = require('path');
2
+
3
+ /**
4
+ * Resolve the @huggingface/transformers package from multiple locations:
5
+ * 1. Local workspace node_modules (preferred)
6
+ * 2. Global FREYA package node_modules (fallback)
7
+ * 3. Parent directory traversal (npm global installs)
8
+ */
9
+ async function resolveTransformers() {
10
+ // Try 1: direct dynamic import (works if in local node_modules)
11
+ try {
12
+ return await import('@huggingface/transformers');
13
+ } catch { /* not found locally */ }
14
+
15
+ // Try 2: resolve from the global FREYA package directory
16
+ // When installed globally, the package lives at <prefix>/node_modules/@cccarv82/freya/
17
+ // and its dependencies are at <prefix>/node_modules/@huggingface/transformers/
18
+ const globalPaths = [
19
+ // npm global: sibling of @cccarv82/freya in the same node_modules
20
+ path.resolve(__dirname, '..', '..', '..', 'node_modules', '@huggingface', 'transformers'),
21
+ // npm global: nested inside the FREYA package
22
+ path.resolve(__dirname, '..', '..', 'node_modules', '@huggingface', 'transformers'),
23
+ // Hoisted in global prefix
24
+ path.resolve(__dirname, '..', '..', '..', '..', '@huggingface', 'transformers'),
25
+ ];
26
+
27
+ for (const p of globalPaths) {
28
+ try {
29
+ const resolved = require.resolve(p);
30
+ if (resolved) return await import(resolved);
31
+ } catch { /* try next */ }
32
+ }
33
+
34
+ // Try 3: use require.resolve with paths option to search upward
35
+ try {
36
+ const modPath = require.resolve('@huggingface/transformers', {
37
+ paths: [
38
+ path.resolve(__dirname, '..', '..'), // workspace root
39
+ path.resolve(__dirname, '..', '..', '..'), // parent of workspace
40
+ path.resolve(__dirname, '..', '..', '..', '..'), // grandparent
41
+ process.execPath ? path.dirname(path.dirname(process.execPath)) : '', // node prefix
42
+ ].filter(Boolean)
43
+ });
44
+ return await import(modPath);
45
+ } catch { /* exhausted all options */ }
46
+
47
+ throw new Error(
48
+ 'Cannot find @huggingface/transformers. ' +
49
+ 'Run "npm install" in your FREYA workspace to install dependencies, ' +
50
+ 'or run "freya init" first to update your workspace package.json.'
51
+ );
52
+ }
53
+
1
54
  class Embedder {
2
55
  constructor() {
3
56
  // V3: use the official HuggingFace model name (same weights, new namespace)
@@ -10,9 +63,7 @@ class Embedder {
10
63
  if (this.extractorInfo) return;
11
64
  if (!this.initPromise) {
12
65
  this.initPromise = (async () => {
13
- // V3: @huggingface/transformers replaces @xenova/transformers
14
- // sharp 0.34+ uses prebuilt platform binaries (no node-gyp needed)
15
- const { pipeline } = await import('@huggingface/transformers');
66
+ const { pipeline } = await resolveTransformers();
16
67
  this.extractorInfo = await pipeline('feature-extraction', this.modelName, { quantized: true });
17
68
  })().catch((err) => {
18
69
  this.initPromise = null;
@@ -189,7 +189,28 @@ async function main() {
189
189
  // Step 3: Extract tasks/blockers from each daily log via planner
190
190
  console.log('── Step 3: Extracting tasks & blockers via planner ──');
191
191
 
192
- const cmd = process.env.COPILOT_CMD || 'copilot';
192
+ // Detect copilot command: try user override, then 'copilot', then 'gh copilot'
193
+ let cmd = process.env.COPILOT_CMD || '';
194
+ if (!cmd) {
195
+ // Quick test: try 'copilot --version'
196
+ const testCopilot = await run('copilot', ['--version'], workspaceDir);
197
+ if (testCopilot.code === 0) {
198
+ cmd = 'copilot';
199
+ } else {
200
+ // Try 'gh copilot' via 'gh'
201
+ const testGh = await run('gh', ['copilot', '--version'], workspaceDir);
202
+ if (testGh.code === 0) {
203
+ cmd = 'gh';
204
+ console.log(' ℹ Using "gh copilot" as planner command');
205
+ } else {
206
+ cmd = 'copilot'; // default, will fail with clear error
207
+ console.log(' ⚠ Could not detect copilot CLI. Set COPILOT_CMD env var if needed.');
208
+ console.log(` copilot test: code=${testCopilot.code} stderr=${(testCopilot.stderr || '').slice(0, 200)}`);
209
+ console.log(` gh copilot test: code=${testGh.code} stderr=${(testGh.stderr || '').slice(0, 200)}`);
210
+ }
211
+ }
212
+ }
213
+ const useGhCopilot = cmd === 'gh';
193
214
  const agentEnv = { FREYA_WORKSPACE_DIR: workspaceDir };
194
215
  const slugMap = readProjectSlugMap(workspaceDir);
195
216
  const validTaskCats = new Set(['DO_NOW', 'SCHEDULE', 'DELEGATE', 'IGNORE']);
@@ -242,20 +263,32 @@ IMPORTANTE: Extraia APENAS informações explícitas do log. NÃO invente dados.
242
263
 
243
264
  try {
244
265
  let r;
266
+ const baseArgs = useGhCopilot
267
+ ? ['copilot', '-s', '--no-color', '--stream', 'off']
268
+ : ['-s', '--no-color', '--stream', 'off'];
269
+
245
270
  if (fullPrompt.length > SAFE_ARG_LEN) {
246
271
  const tmpFile = path.join(os.tmpdir(), `freya-retro-${Date.now()}.txt`);
247
272
  fs.writeFileSync(tmpFile, fullPrompt, 'utf8');
248
273
  const filePrompt = `Leia o arquivo abaixo e extraia tasks/blockers conforme as instruções contidas nele.\nARQUIVO: ${tmpFile}`;
249
- r = await run(cmd, ['-s', '--no-color', '--stream', 'off', '--add-dir', os.tmpdir(), '--allow-all-tools', '-p', filePrompt], workspaceDir, agentEnv);
274
+ r = await run(cmd, [...baseArgs, '--add-dir', os.tmpdir(), '--allow-all-tools', '-p', filePrompt], workspaceDir, agentEnv);
250
275
  try { fs.unlinkSync(tmpFile); } catch { }
251
276
  } else {
252
- r = await run(cmd, ['-s', '--no-color', '--stream', 'off', '-p', fullPrompt], workspaceDir, agentEnv);
277
+ r = await run(cmd, [...baseArgs, '-p', fullPrompt], workspaceDir, agentEnv);
253
278
  }
254
279
 
255
280
  const out = (r.stdout + r.stderr).trim();
256
281
  if (r.code !== 0 || !out) {
257
282
  totalErrors++;
258
- process.stdout.write(`\r [${i + 1}/${files.length}] ${date} planner error `);
283
+ // On first error, show verbose diagnostic
284
+ if (totalErrors === 1) {
285
+ console.log(`\n ⚠ Planner diagnostic for ${date}:`);
286
+ console.log(` Command: ${cmd} ${(useGhCopilot ? baseArgs : ['-s', '--no-color', '--stream', 'off', '-p', '...']).join(' ')}`);
287
+ console.log(` Exit code: ${r.code}`);
288
+ console.log(` stdout: ${(r.stdout || '').slice(0, 300)}`);
289
+ console.log(` stderr: ${(r.stderr || '').slice(0, 300)}`);
290
+ }
291
+ process.stdout.write(`\r [${i + 1}/${files.length}] ${date} — ❌ planner error (code=${r.code}) `);
259
292
  continue;
260
293
  }
261
294