tycono 0.1.64 → 0.1.66

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 (35) hide show
  1. package/bin/tycono.ts +13 -4
  2. package/package.json +1 -1
  3. package/src/api/src/create-server.ts +5 -1
  4. package/src/api/src/engine/agent-loop.ts +17 -6
  5. package/src/api/src/engine/context-assembler.ts +156 -48
  6. package/src/api/src/engine/knowledge-gate.ts +335 -0
  7. package/src/api/src/engine/llm-adapter.ts +7 -1
  8. package/src/api/src/engine/runners/claude-cli.ts +98 -116
  9. package/src/api/src/engine/runners/types.ts +2 -0
  10. package/src/api/src/engine/tools/executor.ts +3 -5
  11. package/src/api/src/routes/active-sessions.ts +143 -0
  12. package/src/api/src/routes/coins.ts +137 -0
  13. package/src/api/src/routes/execute.ts +158 -48
  14. package/src/api/src/routes/knowledge.ts +30 -0
  15. package/src/api/src/routes/operations.ts +48 -11
  16. package/src/api/src/routes/sessions.ts +1 -1
  17. package/src/api/src/routes/setup.ts +68 -1
  18. package/src/api/src/routes/speech.ts +334 -142
  19. package/src/api/src/services/activity-stream.ts +1 -1
  20. package/src/api/src/services/job-manager.ts +185 -9
  21. package/src/api/src/services/port-registry.ts +222 -0
  22. package/src/api/src/services/scaffold.ts +90 -0
  23. package/src/api/src/services/session-store.ts +75 -5
  24. package/src/web/dist/assets/index-BDLT2xew.js +109 -0
  25. package/src/web/dist/assets/index-LvS5V8aP.css +1 -0
  26. package/src/web/dist/assets/{preview-app-qIFqrb-y.js → preview-app-AJtyaM6L.js} +1 -1
  27. package/src/web/dist/index.html +2 -2
  28. package/templates/skills/_manifest.json +6 -0
  29. package/templates/skills/agent-browser/SKILL.md +159 -0
  30. package/templates/skills/agent-browser/meta.json +19 -0
  31. package/templates/teams/agency.json +3 -3
  32. package/templates/teams/research.json +3 -3
  33. package/templates/teams/startup.json +3 -3
  34. package/src/web/dist/assets/index-B3dNhn76.js +0 -101
  35. package/src/web/dist/assets/index-C7IEX_o_.css +0 -1
@@ -1,7 +1,8 @@
1
1
  import { Router, Request, Response, NextFunction } from 'express';
2
- import { readFile, listFiles, fileExists } from '../services/file-reader.js';
2
+ import { readFile, listFiles, fileExists, COMPANY_ROOT } from '../services/file-reader.js';
3
3
  import { extractBoldKeyValues } from '../services/markdown-parser.js';
4
4
  import path from 'node:path';
5
+ import fs from 'node:fs';
5
6
 
6
7
  export const operationsRouter = Router();
7
8
 
@@ -39,16 +40,26 @@ operationsRouter.get('/standups/:date', (req: Request, res: Response, next: Next
39
40
  }
40
41
  });
41
42
 
42
- // --- Waves ---
43
+ // --- Waves (JSON-only) ---
43
44
  operationsRouter.get('/waves', (_req: Request, res: Response, next: NextFunction) => {
44
45
  try {
45
- const files = listFiles('operations/waves');
46
+ const files = listFiles('operations/waves', '*.json');
46
47
  const waves = files
47
- .filter(f => f.endsWith('.md'))
48
48
  .map(f => {
49
- const id = path.basename(f, '.md');
50
- const content = readFile(`operations/waves/${f}`);
51
- return { id, timestamp: id, content };
49
+ const id = path.basename(f, '.json');
50
+ try {
51
+ const data = JSON.parse(readFile(`operations/waves/${f}`));
52
+ return {
53
+ id,
54
+ timestamp: id,
55
+ directive: data.directive ?? '',
56
+ rolesCount: data.roles?.length ?? 0,
57
+ startedAt: data.startedAt ?? '',
58
+ ...(data.commit ? { commit: data.commit } : {}),
59
+ };
60
+ } catch {
61
+ return { id, timestamp: id, directive: '', rolesCount: 0, startedAt: '' };
62
+ }
52
63
  })
53
64
  .sort((a, b) => b.timestamp.localeCompare(a.timestamp));
54
65
 
@@ -61,13 +72,39 @@ operationsRouter.get('/waves', (_req: Request, res: Response, next: NextFunction
61
72
  operationsRouter.get('/waves/:id', (req: Request, res: Response, next: NextFunction) => {
62
73
  try {
63
74
  const { id } = req.params;
64
- const filePath = `operations/waves/${id}.md`;
65
- if (!fileExists(filePath)) {
75
+ const jsonPath = `operations/waves/${id}.json`;
76
+
77
+ if (!fileExists(jsonPath)) {
66
78
  res.status(404).json({ error: `Wave not found: ${id}` });
67
79
  return;
68
80
  }
69
- const content = readFile(filePath);
70
- res.json({ id, timestamp: id, content });
81
+
82
+ const data = JSON.parse(readFile(jsonPath));
83
+ res.json({ id, timestamp: id, replay: data });
84
+ } catch (err) {
85
+ next(err);
86
+ }
87
+ });
88
+
89
+ // PATCH /waves/:id — update wave metadata (e.g. commit info)
90
+ operationsRouter.patch('/waves/:id', (req: Request, res: Response, next: NextFunction) => {
91
+ try {
92
+ const { id } = req.params;
93
+ const jsonPath = `operations/waves/${id}.json`;
94
+
95
+ if (!fileExists(jsonPath)) {
96
+ res.status(404).json({ error: `Wave not found: ${id}` });
97
+ return;
98
+ }
99
+
100
+ const data = JSON.parse(readFile(jsonPath));
101
+ const { commitSha, commitMessage, committedAt } = req.body ?? {};
102
+ if (commitSha) {
103
+ data.commit = { sha: commitSha, message: commitMessage ?? '', committedAt: committedAt ?? new Date().toISOString() };
104
+ }
105
+ const absPath = path.resolve(COMPANY_ROOT, jsonPath);
106
+ fs.writeFileSync(absPath, JSON.stringify(data, null, 2), 'utf-8');
107
+ res.json({ ok: true });
71
108
  } catch (err) {
72
109
  next(err);
73
110
  }
@@ -18,7 +18,7 @@ sessionsRouter.post('/', (req, res) => {
18
18
  res.status(400).json({ error: 'roleId is required' });
19
19
  return;
20
20
  }
21
- const session = createSession(roleId, mode ?? 'talk');
21
+ const session = createSession(roleId, { mode: mode ?? 'talk' });
22
22
  res.status(201).json(session);
23
23
  });
24
24
 
@@ -9,7 +9,7 @@ import fs from 'node:fs';
9
9
  import path from 'node:path';
10
10
  import { execSync } from 'node:child_process';
11
11
  import os from 'node:os';
12
- import { scaffold, getAvailableTeams, loadTeam } from '../services/scaffold.js';
12
+ import { scaffold, getAvailableTeams, loadTeam, getRequiredTools, installSkillTools } from '../services/scaffold.js';
13
13
  import type { ScaffoldConfig } from '../services/scaffold.js';
14
14
  import { importKnowledge } from '../services/knowledge-importer.js';
15
15
  import { gitInit } from '../services/git-save.js';
@@ -342,3 +342,70 @@ setupRouter.get('/teams', (_req, res) => {
342
342
  }));
343
343
  res.json(result);
344
344
  });
345
+
346
+ /**
347
+ * POST /api/setup/required-tools
348
+ * Check which tools are needed for a team's skills.
349
+ */
350
+ setupRouter.post('/required-tools', (req, res) => {
351
+ const { team } = req.body;
352
+ if (!team || typeof team !== 'string') {
353
+ res.json({ tools: [] });
354
+ return;
355
+ }
356
+
357
+ const roles = loadTeam(team);
358
+ const skillIds = new Set<string>();
359
+ for (const role of roles) {
360
+ if (role.defaultSkills) {
361
+ for (const s of role.defaultSkills) skillIds.add(s);
362
+ }
363
+ }
364
+
365
+ const tools = getRequiredTools(Array.from(skillIds));
366
+ res.json({ tools });
367
+ });
368
+
369
+ /**
370
+ * POST /api/setup/install-tools (SSE)
371
+ * Install CLI tools required by team skills with progress streaming.
372
+ */
373
+ setupRouter.post('/install-tools', (req, res) => {
374
+ const { team } = req.body;
375
+ if (!team || typeof team !== 'string') {
376
+ res.status(400).json({ error: 'team is required' });
377
+ return;
378
+ }
379
+
380
+ const roles = loadTeam(team);
381
+ const skillIds = new Set<string>();
382
+ for (const role of roles) {
383
+ if (role.defaultSkills) {
384
+ for (const s of role.defaultSkills) skillIds.add(s);
385
+ }
386
+ }
387
+
388
+ // SSE headers
389
+ res.writeHead(200, {
390
+ 'Content-Type': 'text/event-stream',
391
+ 'Cache-Control': 'no-cache',
392
+ 'Connection': 'keep-alive',
393
+ 'X-Accel-Buffering': 'no',
394
+ });
395
+
396
+ const sendSSE = (event: string, data: unknown) => {
397
+ res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
398
+ };
399
+
400
+ installSkillTools(Array.from(skillIds), {
401
+ onChecking: (tool) => sendSSE('checking', { tool }),
402
+ onInstalling: (tool) => sendSSE('installing', { tool }),
403
+ onInstalled: (tool) => sendSSE('installed', { tool }),
404
+ onSkipped: (tool, reason) => sendSSE('skipped', { tool, reason }),
405
+ onError: (tool, error) => sendSSE('error', { tool, error }),
406
+ onDone: (stats) => {
407
+ sendSSE('done', stats);
408
+ res.end();
409
+ },
410
+ });
411
+ });