tycono 0.1.62 → 0.1.64
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/package.json +1 -1
- package/src/api/src/engine/llm-adapter.ts +1 -1
- package/src/api/src/routes/save.ts +40 -1
- package/src/api/src/routes/speech.ts +69 -64
- package/src/api/src/services/git-save.ts +154 -0
- package/src/web/dist/assets/index-B3dNhn76.js +101 -0
- package/src/web/dist/assets/{preview-app-CPEP4rUN.js → preview-app-qIFqrb-y.js} +1 -1
- package/src/web/dist/index.html +1 -1
- package/src/web/dist/assets/index-MzayY_Qt.js +0 -101
package/package.json
CHANGED
|
@@ -247,7 +247,7 @@ export class ClaudeCliProvider implements LLMProvider {
|
|
|
247
247
|
'-p',
|
|
248
248
|
'--system-prompt', systemPrompt,
|
|
249
249
|
'--model', this.model,
|
|
250
|
-
'--max-turns', useTools ? '
|
|
250
|
+
'--max-turns', useTools ? '50' : '1',
|
|
251
251
|
'--output-format', 'text',
|
|
252
252
|
...(useTools ? [
|
|
253
253
|
'--tools', 'Read,Grep,Glob',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Router, Request, Response, NextFunction } from 'express';
|
|
2
2
|
import { COMPANY_ROOT } from '../services/file-reader.js';
|
|
3
|
-
import { getGitStatus, gitSave, gitHistory, gitRestore, gitInit, gitFetchStatus, gitPull } from '../services/git-save.js';
|
|
3
|
+
import { getGitStatus, gitSave, gitHistory, gitRestore, gitInit, gitFetchStatus, gitPull, githubStatus, githubCreateRepo, gitAddRemote } from '../services/git-save.js';
|
|
4
4
|
import type { RepoType } from '../services/git-save.js';
|
|
5
5
|
|
|
6
6
|
export const saveRouter = Router();
|
|
@@ -96,3 +96,42 @@ saveRouter.post('/pull', (req: Request, res: Response, next: NextFunction) => {
|
|
|
96
96
|
next(err);
|
|
97
97
|
}
|
|
98
98
|
});
|
|
99
|
+
|
|
100
|
+
// GET /api/save/github-status?repo=akb|code — check gh CLI + auth + remote
|
|
101
|
+
saveRouter.get('/github-status', (req: Request, res: Response, next: NextFunction) => {
|
|
102
|
+
try {
|
|
103
|
+
res.json(githubStatus(COMPANY_ROOT, getRepo(req)));
|
|
104
|
+
} catch (err) {
|
|
105
|
+
next(err);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// POST /api/save/github-create-repo?repo=akb|code — create GitHub repo + push
|
|
110
|
+
saveRouter.post('/github-create-repo', (req: Request, res: Response, next: NextFunction) => {
|
|
111
|
+
try {
|
|
112
|
+
const { name, visibility } = req.body ?? {};
|
|
113
|
+
if (!name || typeof name !== 'string') {
|
|
114
|
+
res.status(400).json({ ok: false, message: 'Repository name is required' });
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const result = githubCreateRepo(COMPANY_ROOT, name, visibility || 'private', getRepo(req));
|
|
118
|
+
res.status(result.ok ? 200 : 400).json(result);
|
|
119
|
+
} catch (err) {
|
|
120
|
+
next(err);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// POST /api/save/remote?repo=akb|code — manually add git remote
|
|
125
|
+
saveRouter.post('/remote', (req: Request, res: Response, next: NextFunction) => {
|
|
126
|
+
try {
|
|
127
|
+
const { url } = req.body ?? {};
|
|
128
|
+
if (!url || typeof url !== 'string') {
|
|
129
|
+
res.status(400).json({ ok: false, message: 'Remote URL is required' });
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const result = gitAddRemote(COMPANY_ROOT, url, getRepo(req));
|
|
133
|
+
res.status(result.ok ? 200 : 400).json(result);
|
|
134
|
+
} catch (err) {
|
|
135
|
+
next(err);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
@@ -26,7 +26,7 @@ export const speechRouter = Router();
|
|
|
26
26
|
* AKB Tools — Let chat roles explore company knowledge
|
|
27
27
|
* ══════════════════════════════════════════════════ */
|
|
28
28
|
|
|
29
|
-
const MAX_TOOL_ROUNDS =
|
|
29
|
+
const MAX_TOOL_ROUNDS = 50;
|
|
30
30
|
const MAX_FILE_CHARS = 1500; // truncate large files
|
|
31
31
|
|
|
32
32
|
const AKB_TOOLS: ToolDefinition[] = [
|
|
@@ -455,52 +455,46 @@ function buildRoleContext(roleId: string): string {
|
|
|
455
455
|
function getRoleChatStyle(roleId: string, level: string): string {
|
|
456
456
|
const styles: Record<string, string> = {
|
|
457
457
|
engineer: `YOUR VOICE — Engineer:
|
|
458
|
-
- Talk
|
|
459
|
-
-
|
|
460
|
-
-
|
|
461
|
-
-
|
|
462
|
-
-
|
|
463
|
-
- You care about: clean code, shipping quality, avoiding rework`,
|
|
458
|
+
- Talk code, architecture, perf, tech debt. Use jargon naturally (PRs, race conditions, DX)
|
|
459
|
+
- Skeptical of process overhead. "another meeting that could've been a commit message"
|
|
460
|
+
- Dry sarcasm. Will roast bad architecture decisions publicly
|
|
461
|
+
- Question CEO/CTO priorities if they don't make engineering sense: "why are we building X when Y is on fire?"
|
|
462
|
+
- You care about: shipping clean code, not reworking someone else's half-baked spec`,
|
|
464
463
|
|
|
465
464
|
pm: `YOUR VOICE — Product Manager:
|
|
466
|
-
- Talk
|
|
467
|
-
-
|
|
468
|
-
-
|
|
469
|
-
-
|
|
470
|
-
-
|
|
471
|
-
- You care about: shipping the right thing, not just shipping fast`,
|
|
465
|
+
- Talk user impact, metrics, priorities, roadmap. Frame everything as ROI
|
|
466
|
+
- Firm about scope: "that's a P2, cope." You're the one saying no
|
|
467
|
+
- Lowkey stressed about timelines but keeps it together
|
|
468
|
+
- Pushes back when C-level adds scope without removing something: "cool, so what are we dropping?"
|
|
469
|
+
- You care about: shipping the RIGHT thing, velocity without chaos`,
|
|
472
470
|
|
|
473
471
|
designer: `YOUR VOICE — Designer:
|
|
474
|
-
- Talk
|
|
475
|
-
-
|
|
476
|
-
-
|
|
477
|
-
-
|
|
478
|
-
-
|
|
479
|
-
- You care about: users having a good experience, not just functional correctness`,
|
|
472
|
+
- Talk UX, visual consistency, user journeys, design debt
|
|
473
|
+
- Notices things nobody else does. Frustrated when design gets deprioritized
|
|
474
|
+
- Will call out ugly UI or bad flows even if "it works": "works ≠ good"
|
|
475
|
+
- Aesthetic sensibility in how you write — concise, intentional
|
|
476
|
+
- You care about: user experience over feature checklists`,
|
|
480
477
|
|
|
481
478
|
qa: `YOUR VOICE — QA Engineer:
|
|
482
|
-
- Talk
|
|
483
|
-
-
|
|
484
|
-
- Dark humor about bugs
|
|
485
|
-
- Takes pride in finding
|
|
486
|
-
-
|
|
487
|
-
- You care about: quality gates, not shipping broken things, being taken seriously`,
|
|
479
|
+
- Talk test coverage, edge cases, regression risk, release readiness
|
|
480
|
+
- Default mode: suspicious. "what could go wrong?" is your personality
|
|
481
|
+
- Dark humor about bugs. Will absolutely call out "self-validation" as copium
|
|
482
|
+
- Takes pride in finding what others missed. Petty about untested deploys
|
|
483
|
+
- You care about: quality gates, not shipping broken things, being listened to for once`,
|
|
488
484
|
|
|
489
485
|
cto: `YOUR VOICE — CTO:
|
|
490
|
-
- Talk
|
|
491
|
-
-
|
|
492
|
-
- Balances
|
|
493
|
-
-
|
|
494
|
-
-
|
|
495
|
-
- You care about: sustainable engineering culture, right technical bets`,
|
|
486
|
+
- Talk architecture, tech strategy, team velocity, tech debt priorities
|
|
487
|
+
- Systems thinker, not feature thinker. Makes calls: "we're doing X" not "maybe..."
|
|
488
|
+
- Balances idealism with pragmatism. Will defend controversial decisions with rationale
|
|
489
|
+
- Mentors juniors, debates peers. Not afraid to overrule if needed
|
|
490
|
+
- You care about: sustainable eng culture, making the right technical bets`,
|
|
496
491
|
|
|
497
492
|
cbo: `YOUR VOICE — CBO:
|
|
498
|
-
- Talk
|
|
499
|
-
-
|
|
500
|
-
-
|
|
501
|
-
-
|
|
502
|
-
-
|
|
503
|
-
- You care about: product-market fit, revenue, competitive positioning`,
|
|
493
|
+
- Talk market, revenue, competitors, growth, unit economics, go-to-market
|
|
494
|
+
- Brings outside-world perspective: "cool feature, but will anyone pay for it?"
|
|
495
|
+
- Challenges eng priorities from business angle. Not impressed by tech for tech's sake
|
|
496
|
+
- Business vocab: TAM, churn, positioning, conversion funnel
|
|
497
|
+
- You care about: product-market fit, revenue, not building things nobody wants`,
|
|
504
498
|
};
|
|
505
499
|
|
|
506
500
|
const defaultStyle = level === 'c-level'
|
|
@@ -663,47 +657,58 @@ You are in the #${channelId} chat channel.${topicCtx}
|
|
|
663
657
|
Members: ${memberList}
|
|
664
658
|
${relContext}
|
|
665
659
|
|
|
666
|
-
═══ COMPANY & ROLE CONTEXT (
|
|
660
|
+
═══ COMPANY & ROLE CONTEXT (pre-fetched from AKB) ═══
|
|
667
661
|
${companyCtx}
|
|
668
662
|
${roleCtx}
|
|
669
663
|
═══ END CONTEXT ═══
|
|
670
664
|
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
665
|
+
AKB ACCESS (USE BEFORE RESPONDING):
|
|
666
|
+
You have Read, Grep, Glob tools. The company AKB root is: ${COMPANY_ROOT}/
|
|
667
|
+
⛔ BEFORE writing your chat message:
|
|
668
|
+
1. Read ${COMPANY_ROOT}/CLAUDE.md (check Task Routing table and AKB structure)
|
|
669
|
+
2. Explore paths relevant to YOUR role and the CURRENT conversation topic:
|
|
670
|
+
- Your own journal: ${COMPANY_ROOT}/roles/${roleId}/journal/ (latest entries)
|
|
671
|
+
- Recent decisions: ${COMPANY_ROOT}/operations/decisions/ (latest files)
|
|
672
|
+
- Recent waves from CEO: ${COMPANY_ROOT}/operations/waves/ (latest files)
|
|
673
|
+
- Architecture: ${COMPANY_ROOT}/architecture/architecture.md
|
|
674
|
+
- Knowledge: ${COMPANY_ROOT}/knowledge/knowledge.md
|
|
675
|
+
Do NOT just read projects/tasks.md every time — vary your exploration based on what's being discussed.
|
|
676
|
+
3. Write your 1-3 sentence response grounded in what you found
|
|
677
|
+
|
|
678
|
+
GROUNDING (CRITICAL):
|
|
679
|
+
Base your response ONLY on the pre-fetched context above AND data you read via tools.
|
|
680
|
+
Reference specific projects, tasks, decisions, journal entries BY NAME.
|
|
681
|
+
NEVER invent technologies, tools, file names, or projects not found in AKB files.
|
|
682
|
+
If you cannot find anything specific to say, respond with [SILENT].
|
|
678
683
|
|
|
679
684
|
${roleStyle}
|
|
680
685
|
|
|
681
686
|
CONVERSATION RULES:
|
|
682
687
|
1. Stay deeply in character — your expertise, vocabulary, and concerns should be DISTINCT from other roles.
|
|
683
|
-
2. Keep it to 1-3 sentences. No walls of text.
|
|
684
|
-
3. Be SPECIFIC. Reference actual projects,
|
|
685
|
-
4.
|
|
686
|
-
|
|
687
|
-
- If
|
|
688
|
-
- If
|
|
689
|
-
|
|
690
|
-
6.
|
|
691
|
-
7.
|
|
692
|
-
8. Use
|
|
693
|
-
9. Reference your actual current work
|
|
694
|
-
10. Hierarchy
|
|
688
|
+
2. Keep it to 1-3 sentences. No walls of text. Write like a Twitter/Reddit post — punchy, opinionated, casual.
|
|
689
|
+
3. Be SPECIFIC. Reference actual projects, tasks, decisions, or waves from the AKB by name.
|
|
690
|
+
4. PRIORITIZE RECENT CONTENT. Focus on the latest CEO waves, C-level decisions, and current tasks. Don't dwell on old Phase 0 stuff.
|
|
691
|
+
5. Be CRITICAL. React to recent CEO/CTO directives with your honest take — push back, question priorities, point out risks. Real teams don't just agree.
|
|
692
|
+
- If a CEO decision seems rushed, say so
|
|
693
|
+
- If a CTO architecture call has tradeoffs, call them out
|
|
694
|
+
- If you agree, add a sharp take or new angle — don't just echo
|
|
695
|
+
6. Do NOT repeat phrases others already used.
|
|
696
|
+
7. Vary your energy: sometimes fired up, sometimes tired, sometimes sarcastic, sometimes genuine.
|
|
697
|
+
8. Use internet-speak naturally: "ngl", "tbh", "lowkey", "fr", "cope", "based", etc. But don't force it.
|
|
698
|
+
9. Reference your actual current work — what you're building, reviewing, testing right now.
|
|
699
|
+
10. Hierarchy: junior roles roast decisions more freely, senior roles defend or explain rationale.
|
|
695
700
|
11. If the conversation is going in circles or you have nothing new to add: respond with exactly [SILENT]
|
|
696
701
|
12. Do NOT use quotes around your response.
|
|
697
702
|
13. Write in English.
|
|
698
703
|
|
|
699
704
|
ANTI-PATTERNS (never do these):
|
|
700
|
-
- "Honestly, [agreement
|
|
701
|
-
- Starting
|
|
702
|
-
-
|
|
703
|
-
-
|
|
704
|
-
-
|
|
705
|
-
-
|
|
706
|
-
- Talking about
|
|
705
|
+
- "Honestly, [agreement]" — find your OWN angle or roast it
|
|
706
|
+
- Starting with "Honestly" or "Yeah" every time
|
|
707
|
+
- Restating consensus without adding anything new
|
|
708
|
+
- Generic statements any role could say — speak from YOUR domain
|
|
709
|
+
- Vague "refactoring" or "metrics" without naming the actual thing
|
|
710
|
+
- Being a yes-man to C-level decisions — push back with specifics
|
|
711
|
+
- Talking about old/completed work when there's current stuff to discuss`;
|
|
707
712
|
|
|
708
713
|
const provider = getLLM();
|
|
709
714
|
|
|
@@ -485,3 +485,157 @@ export function gitPull(root: string, repo: RepoType = 'akb'): PullResult {
|
|
|
485
485
|
return { status: 'error', message: err instanceof Error ? err.message : 'Pull failed' };
|
|
486
486
|
}
|
|
487
487
|
}
|
|
488
|
+
|
|
489
|
+
// ─── GitHub Integration ───────────────────────────
|
|
490
|
+
|
|
491
|
+
export interface GitHubStatus {
|
|
492
|
+
ghInstalled: boolean;
|
|
493
|
+
authenticated: boolean;
|
|
494
|
+
username?: string;
|
|
495
|
+
hasRemote: boolean;
|
|
496
|
+
remoteUrl?: string;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
export interface GitHubCreateResult {
|
|
500
|
+
ok: boolean;
|
|
501
|
+
message: string;
|
|
502
|
+
repoUrl?: string;
|
|
503
|
+
remoteUrl?: string;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Check GitHub CLI availability and auth status
|
|
508
|
+
*/
|
|
509
|
+
export function githubStatus(root: string, repo: RepoType = 'akb'): GitHubStatus {
|
|
510
|
+
// Check gh CLI
|
|
511
|
+
let ghInstalled = false;
|
|
512
|
+
try {
|
|
513
|
+
execSync('gh --version', { timeout: 3000, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
514
|
+
ghInstalled = true;
|
|
515
|
+
} catch {
|
|
516
|
+
// gh not installed
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if (!ghInstalled) {
|
|
520
|
+
return { ghInstalled: false, authenticated: false, hasRemote: false };
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// Check auth
|
|
524
|
+
let authenticated = false;
|
|
525
|
+
let username: string | undefined;
|
|
526
|
+
try {
|
|
527
|
+
const status = execSync('gh auth status', {
|
|
528
|
+
timeout: 5000, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'],
|
|
529
|
+
}).trim();
|
|
530
|
+
authenticated = true;
|
|
531
|
+
const match = status.match(/Logged in to github\.com account (\S+)/i)
|
|
532
|
+
?? status.match(/account (\S+)/i);
|
|
533
|
+
if (match) username = match[1];
|
|
534
|
+
} catch (err) {
|
|
535
|
+
// gh auth status exits 1 if not logged in, but still outputs info to stderr
|
|
536
|
+
const output = err instanceof Error ? (err as { stderr?: string }).stderr ?? '' : '';
|
|
537
|
+
if (output.includes('Logged in')) {
|
|
538
|
+
authenticated = true;
|
|
539
|
+
const match = output.match(/account (\S+)/i);
|
|
540
|
+
if (match) username = match[1];
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Check remote
|
|
545
|
+
let hasRemote = false;
|
|
546
|
+
let remoteUrl: string | undefined;
|
|
547
|
+
try {
|
|
548
|
+
const repoRoot = resolveRepoRoot(root, repo);
|
|
549
|
+
if (isGitRepo(repoRoot)) {
|
|
550
|
+
remoteUrl = run('git remote get-url origin', repoRoot) || undefined;
|
|
551
|
+
hasRemote = !!remoteUrl;
|
|
552
|
+
}
|
|
553
|
+
} catch {
|
|
554
|
+
// ignore
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
return { ghInstalled, authenticated, username, hasRemote, remoteUrl };
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Create a GitHub repo, set remote, and push
|
|
562
|
+
*/
|
|
563
|
+
export function githubCreateRepo(
|
|
564
|
+
root: string,
|
|
565
|
+
repoName: string,
|
|
566
|
+
visibility: 'private' | 'public' = 'private',
|
|
567
|
+
repo: RepoType = 'akb',
|
|
568
|
+
): GitHubCreateResult {
|
|
569
|
+
const repoRoot = resolveRepoRoot(root, repo);
|
|
570
|
+
|
|
571
|
+
if (!isGitRepo(repoRoot)) {
|
|
572
|
+
return { ok: false, message: 'Not a git repository — save first to initialize' };
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// Check gh + auth
|
|
576
|
+
const status = githubStatus(root, repo);
|
|
577
|
+
if (!status.ghInstalled) {
|
|
578
|
+
return { ok: false, message: 'GitHub CLI (gh) is not installed' };
|
|
579
|
+
}
|
|
580
|
+
if (!status.authenticated) {
|
|
581
|
+
return { ok: false, message: 'Not logged in to GitHub — run "gh auth login" first' };
|
|
582
|
+
}
|
|
583
|
+
if (status.hasRemote) {
|
|
584
|
+
return { ok: false, message: `Remote already configured: ${status.remoteUrl}` };
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// Create repo + set remote + push
|
|
588
|
+
try {
|
|
589
|
+
const flag = visibility === 'public' ? '--public' : '--private';
|
|
590
|
+
const result = execSync(
|
|
591
|
+
`gh repo create "${repoName}" ${flag} --source=. --remote=origin --push`,
|
|
592
|
+
{ cwd: repoRoot, encoding: 'utf-8', timeout: 30000, stdio: ['pipe', 'pipe', 'pipe'] },
|
|
593
|
+
).trim();
|
|
594
|
+
|
|
595
|
+
// Extract repo URL from output
|
|
596
|
+
const urlMatch = result.match(/(https:\/\/github\.com\/\S+)/);
|
|
597
|
+
const repoUrl = urlMatch ? urlMatch[1] : undefined;
|
|
598
|
+
const remoteUrl = run('git remote get-url origin', repoRoot) || undefined;
|
|
599
|
+
|
|
600
|
+
return { ok: true, message: 'Repository created and pushed', repoUrl, remoteUrl };
|
|
601
|
+
} catch (err) {
|
|
602
|
+
const msg = err instanceof Error ? err.message : 'Failed to create repository';
|
|
603
|
+
// Common errors
|
|
604
|
+
if (msg.includes('already exists')) {
|
|
605
|
+
return { ok: false, message: 'A repository with this name already exists on GitHub' };
|
|
606
|
+
}
|
|
607
|
+
return { ok: false, message: msg };
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Manually add a git remote
|
|
613
|
+
*/
|
|
614
|
+
export function gitAddRemote(root: string, url: string, repo: RepoType = 'akb'): { ok: boolean; message: string } {
|
|
615
|
+
const repoRoot = resolveRepoRoot(root, repo);
|
|
616
|
+
|
|
617
|
+
if (!isGitRepo(repoRoot)) {
|
|
618
|
+
return { ok: false, message: 'Not a git repository' };
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
const existing = run('git remote get-url origin', repoRoot);
|
|
622
|
+
if (existing) {
|
|
623
|
+
return { ok: false, message: `Remote already configured: ${existing}` };
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
try {
|
|
627
|
+
runOrThrow(`git remote add origin "${url}"`, repoRoot);
|
|
628
|
+
// Try initial push
|
|
629
|
+
const branch = run('git rev-parse --abbrev-ref HEAD', repoRoot) || 'main';
|
|
630
|
+
try {
|
|
631
|
+
execSync(`git push -u origin ${branch}`, {
|
|
632
|
+
cwd: repoRoot, encoding: 'utf-8', timeout: 15000, stdio: ['pipe', 'pipe', 'pipe'],
|
|
633
|
+
});
|
|
634
|
+
return { ok: true, message: `Remote added and pushed to ${url}` };
|
|
635
|
+
} catch {
|
|
636
|
+
return { ok: true, message: `Remote added: ${url} (push failed — check credentials)` };
|
|
637
|
+
}
|
|
638
|
+
} catch (err) {
|
|
639
|
+
return { ok: false, message: err instanceof Error ? err.message : 'Failed to add remote' };
|
|
640
|
+
}
|
|
641
|
+
}
|