@danieltmn/tamnora 0.25.1 → 0.26.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.
Files changed (87) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +13 -25
  3. package/SECURITY.md +3 -4
  4. package/harness/packages/cli/src/cli.js +0 -3
  5. package/harness/packages/cli/src/commands/bridge.js +0 -1
  6. package/harness/packages/cli/src/commands/repl.js +3 -3
  7. package/harness/packages/cli/src/commands/run.js +1 -1
  8. package/harness/packages/cli/src/commands/server.js +1 -1
  9. package/harness/packages/cli/src/commands/tui.js +1 -1
  10. package/harness/packages/cli/src/lib/util.js +2 -2
  11. package/harness/packages/cli/src/tui/app.js +2 -2
  12. package/harness/packages/cli/test/tunnel.test.js +5 -32
  13. package/harness/packages/core/src/agents/index.js +13 -41
  14. package/harness/packages/core/src/config/app.js +0 -4
  15. package/harness/packages/core/src/config/home.js +1 -20
  16. package/harness/packages/core/src/config/index.js +5 -8
  17. package/harness/packages/core/src/extensions/load.js +22 -0
  18. package/harness/packages/core/src/frontmatter.js +32 -0
  19. package/harness/packages/core/src/hooks/index.js +2 -16
  20. package/harness/packages/core/src/index.js +2 -14
  21. package/harness/packages/core/src/plugins/index.js +2 -16
  22. package/harness/packages/core/src/procs/project.js +68 -0
  23. package/harness/packages/core/src/procs/static.js +17 -0
  24. package/harness/packages/core/src/rules/index.js +8 -27
  25. package/harness/packages/core/src/skills/index.js +8 -19
  26. package/harness/packages/core/src/storage/sqlite.js +595 -690
  27. package/harness/packages/core/src/tunnel.js +9 -147
  28. package/harness/packages/core/test/home.test.js +2 -35
  29. package/harness/packages/core/test/procs.test.js +3 -64
  30. package/harness/packages/core/test/storage.test.js +1 -12
  31. package/harness/packages/server/public/app.js +2 -19
  32. package/harness/packages/server/public/appearance.js +2 -56
  33. package/harness/packages/server/public/boot.js +2 -2
  34. package/harness/packages/server/public/cards.js +2 -21
  35. package/harness/packages/server/public/chat.js +0 -16
  36. package/harness/packages/server/public/chatFormat.js +0 -11
  37. package/harness/packages/server/public/chrome.js +2 -5
  38. package/harness/packages/server/public/commands.js +1 -2
  39. package/harness/packages/server/public/explorer.js +7 -10
  40. package/harness/packages/server/public/index.html +1228 -1326
  41. package/harness/packages/server/public/landing/boot.js +2 -3
  42. package/harness/packages/server/public/landing/index.html +3 -367
  43. package/harness/packages/server/public/settings.js +1255 -1322
  44. package/harness/packages/server/public/settingsNav.js +0 -1
  45. package/harness/packages/server/public/styles.css +2341 -2867
  46. package/harness/packages/server/public/system.js +356 -495
  47. package/harness/packages/server/public/voice.js +6 -22
  48. package/harness/packages/server/src/auth.js +4 -15
  49. package/harness/packages/server/src/cli.js +1 -1
  50. package/harness/packages/server/src/lib/agents.js +13 -27
  51. package/harness/packages/server/src/lib/appearance.js +3 -22
  52. package/harness/packages/server/src/lib/channels/telegram/commands.js +1 -1
  53. package/harness/packages/server/src/lib/definitions.js +40 -0
  54. package/harness/packages/server/src/lib/skills.js +14 -21
  55. package/harness/packages/server/src/lib/ttsSettings.js +2 -2
  56. package/harness/packages/server/src/lib/workspace.js +9 -11
  57. package/harness/packages/server/src/routes/chat.js +0 -43
  58. package/harness/packages/server/src/routes/preview.js +5 -22
  59. package/harness/packages/server/src/routes/procs.js +2 -4
  60. package/harness/packages/server/src/routes/tts.js +1 -1
  61. package/harness/packages/server/src/server.js +1 -5
  62. package/harness/packages/server/test/appearance-route.test.js +3 -3
  63. package/harness/packages/server/test/appearance.test.js +12 -38
  64. package/harness/packages/server/test/chatFormat.test.js +0 -8
  65. package/harness/packages/server/test/consoleTabs.test.js +4 -4
  66. package/harness/packages/server/test/ops.test.js +8 -56
  67. package/harness/packages/server/test/preview.test.js +2 -42
  68. package/harness/packages/server/test/security.test.js +194 -370
  69. package/harness/packages/server/test/settingsNav.test.js +2 -2
  70. package/harness/packages/server/test/tts.test.js +4 -4
  71. package/harness/tamnora.example.json +1 -1
  72. package/package.json +2 -2
  73. package/harness/packages/cli/src/commands/eval.js +0 -186
  74. package/harness/packages/core/src/eval/dataset.js +0 -47
  75. package/harness/packages/core/src/eval/judge.js +0 -39
  76. package/harness/packages/core/src/eval/report.js +0 -48
  77. package/harness/packages/core/src/eval/runTask.js +0 -62
  78. package/harness/packages/core/src/eval/runner.js +0 -153
  79. package/harness/packages/core/src/eval/scorers.js +0 -217
  80. package/harness/packages/core/src/eval/task.js +0 -59
  81. package/harness/packages/core/src/procs/detect.js +0 -149
  82. package/harness/packages/core/test/eval.test.js +0 -144
  83. package/harness/packages/server/src/lib/advisor.js +0 -198
  84. package/harness/packages/server/src/routes/advisor.js +0 -79
  85. package/harness/packages/server/src/routes/eval.js +0 -100
  86. package/harness/packages/server/test/advisor.test.js +0 -249
  87. package/harness/scripts/example-dataset.jsonl +0 -4
@@ -0,0 +1,68 @@
1
+ // Procesos de desarrollo declarados por el proyecto en `.tamnora/procs.json`.
2
+ // No se autodetecta nada: el usuario declara como arrancar cada servidor.
3
+
4
+ import { existsSync, readFileSync } from 'node:fs';
5
+ import path from 'node:path';
6
+
7
+ export const DEFAULT_PROCESS_ALLOW = [
8
+ 'npm',
9
+ 'node',
10
+ 'npx',
11
+ 'pnpm',
12
+ 'yarn',
13
+ 'bun',
14
+ 'bunx',
15
+ 'php',
16
+ 'python',
17
+ 'python3',
18
+ 'composer',
19
+ ];
20
+
21
+ /** Archivo por proyecto (relativo a su raiz) que define sus procesos de dev. */
22
+ export const PROCS_FILE = '.tamnora/procs.json';
23
+
24
+ /** True si `target` es `root` o vive dentro de el (sin salirse por `..`). */
25
+ function isInside(root, target) {
26
+ const rel = path.relative(root, target);
27
+ return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));
28
+ }
29
+
30
+ /**
31
+ * Procesos definidos a mano por el proyecto en `<root>/.tamnora/procs.json`.
32
+ * Formato: `{ "processes": [{ label?, dir?, command, args?, port? }] }` o un array
33
+ * directo. `dir` es relativo a la raiz y debe quedar dentro de ella. Cada chip
34
+ * sigue pasando por la whitelist (`processes.allow`) al arrancar.
35
+ */
36
+ export function loadProjectProcs(root) {
37
+ const file = path.join(root, PROCS_FILE);
38
+ if (!existsSync(file)) return [];
39
+ const raw = readJson(file);
40
+ const list = Array.isArray(raw) ? raw : Array.isArray(raw?.processes) ? raw.processes : [];
41
+ const chips = [];
42
+ for (const entry of list) {
43
+ if (!entry || typeof entry !== 'object') continue;
44
+ const command = String(entry.command ?? '').trim();
45
+ if (!command) continue;
46
+ const rel = String(entry.dir ?? '').trim().replace(/^[/\\]+/, '');
47
+ const cwd = path.resolve(root, rel || '.');
48
+ if (!isInside(root, cwd) || !existsSync(cwd)) continue;
49
+ const port = entry.port ? Number(entry.port) : undefined;
50
+ chips.push({
51
+ label: String(entry.label ?? command).trim() || command,
52
+ command,
53
+ args: Array.isArray(entry.args) ? entry.args.map(String) : [],
54
+ cwd,
55
+ port: Number.isInteger(port) && port > 0 ? port : undefined,
56
+ source: 'project',
57
+ });
58
+ }
59
+ return chips;
60
+ }
61
+
62
+ function readJson(file) {
63
+ try {
64
+ return JSON.parse(readFileSync(file, 'utf8'));
65
+ } catch {
66
+ return null;
67
+ }
68
+ }
@@ -0,0 +1,17 @@
1
+ // Chip para servir un directorio como sitio estatico con el servidor sin
2
+ // dependencias. Lo usa la vista previa de un HTML en el explorador.
3
+
4
+ import { fileURLToPath } from 'node:url';
5
+
6
+ const STATIC_SERVER = fileURLToPath(new URL('../../../../scripts/static-server.mjs', import.meta.url));
7
+ const STATIC_PORT = 8080;
8
+
9
+ export function staticServerChip(dir, { port = STATIC_PORT, label } = {}) {
10
+ return {
11
+ label: label ?? `sitio estático (${port})`,
12
+ command: process.execPath,
13
+ args: [STATIC_SERVER, dir, String(port)],
14
+ cwd: dir,
15
+ port,
16
+ };
17
+ }
@@ -5,36 +5,17 @@
5
5
  import { readFile } from 'node:fs/promises';
6
6
  import path from 'node:path';
7
7
  import { globToRegExp, globFiles } from '../tools/glob.js';
8
+ import { parseFrontmatter, parseListValue } from '../frontmatter.js';
8
9
 
9
10
  /** Parsea un archivo de reglas: frontmatter (name, paths/globs) + body. */
10
11
  export function parseRuleMarkdown(text, fallbackId = '') {
11
- const source = String(text ?? '');
12
- let name = fallbackId;
13
- let paths = [];
14
- let body = source.trim();
15
- const match = source.match(/^---\s*\r?\n([\s\S]*?)\r?\n---\s*\r?\n?([\s\S]*)$/);
16
- if (match) {
17
- body = match[2].trim();
18
- for (const line of match[1].split(/\r?\n/)) {
19
- const kv = line.match(/^([A-Za-z][\w-]*)\s*:\s*(.*)$/);
20
- if (!kv) continue;
21
- const key = kv[1].toLowerCase();
22
- const value = kv[2].trim();
23
- if (key === 'name') name = value.replace(/^["']|["']$/g, '');
24
- else if (key === 'paths' || key === 'globs' || key === 'path') paths = parseList(value);
25
- }
26
- }
27
- return { name: name || fallbackId, paths: normalizePaths(paths), body };
28
- }
29
-
30
- function parseList(value) {
31
- const raw = String(value ?? '').trim();
32
- if (!raw) return [];
33
- const inner = raw.startsWith('[') && raw.endsWith(']') ? raw.slice(1, -1) : raw;
34
- return inner
35
- .split(',')
36
- .map((s) => s.trim().replace(/^["']|["']$/g, ''))
37
- .filter(Boolean);
12
+ const { fields, body } = parseFrontmatter(text);
13
+ const listed = fields.paths ?? fields.globs ?? fields.path;
14
+ return {
15
+ name: fields.name || fallbackId,
16
+ paths: normalizePaths(listed === undefined ? [] : parseListValue(listed)),
17
+ body,
18
+ };
38
19
  }
39
20
 
40
21
  function normalizePaths(paths) {
@@ -5,28 +5,17 @@
5
5
  import { readdirSync, readFileSync, statSync } from 'node:fs';
6
6
  import { mkdir, writeFile } from 'node:fs/promises';
7
7
  import path from 'node:path';
8
+ import { parseFrontmatter } from '../frontmatter.js';
8
9
 
9
10
  /** Parse a SKILL.md: frontmatter `--- key: value ---` plus body. */
10
11
  export function parseSkillMarkdown(text, fallbackId = '') {
11
- const source = String(text ?? '');
12
- let name = fallbackId;
13
- let description = '';
14
- let when = '';
15
- let body = source.trim();
16
- const match = source.match(/^---\s*\r?\n([\s\S]*?)\r?\n---\s*\r?\n?([\s\S]*)$/);
17
- if (match) {
18
- body = match[2].trim();
19
- for (const line of match[1].split(/\r?\n/)) {
20
- const kv = line.match(/^([A-Za-z][\w-]*)\s*:\s*(.*)$/);
21
- if (!kv) continue;
22
- const key = kv[1].toLowerCase();
23
- const value = kv[2].trim().replace(/^["']|["']$/g, '');
24
- if (key === 'name') name = value;
25
- else if (key === 'description') description = value;
26
- else if (key === 'when' || key === 'when_to_use') when = value;
27
- }
28
- }
29
- return { name: name || fallbackId, description, when, body };
12
+ const { fields, body } = parseFrontmatter(text);
13
+ return {
14
+ name: fields.name || fallbackId,
15
+ description: fields.description || '',
16
+ when: fields.when || fields.when_to_use || '',
17
+ body,
18
+ };
30
19
  }
31
20
 
32
21
  /** List the skills under a root (`<root>/<slug>/SKILL.md`). Missing root -> []. */