tycono 0.1.18 → 0.1.20
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/routes/company.ts +23 -8
- package/src/api/src/routes/speech.ts +98 -13
- package/src/web/dist/assets/{index-DTPm_7VX.js → index-Dwi3nVT7.js} +34 -30
- package/src/web/dist/assets/{preview-app-CLBsMBhE.js → preview-app-BggYkB4E.js} +1 -1
- package/src/web/dist/index.html +1 -1
package/package.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Router, Request, Response, NextFunction } from 'express';
|
|
2
|
-
import
|
|
2
|
+
import YAML from 'yaml';
|
|
3
|
+
import { readFile, fileExists } from '../services/file-reader.js';
|
|
3
4
|
import { parseMarkdownTable, extractBoldKeyValues } from '../services/markdown-parser.js';
|
|
4
5
|
|
|
5
6
|
export const companyRouter = Router();
|
|
@@ -19,13 +20,27 @@ companyRouter.get('/', (_req: Request, res: Response, next: NextFunction) => {
|
|
|
19
20
|
const roleRows = parseMarkdownTable(rolesContent);
|
|
20
21
|
const roles = roleRows
|
|
21
22
|
.filter(row => (row.id ?? '').toLowerCase() !== 'ceo')
|
|
22
|
-
.map(row =>
|
|
23
|
-
id
|
|
24
|
-
name
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
.map(row => {
|
|
24
|
+
const id = row.id ?? '';
|
|
25
|
+
let name = row.role ?? row.name ?? '';
|
|
26
|
+
|
|
27
|
+
// role.yaml의 name이 있으면 우선 사용 (커스텀 이름 반영)
|
|
28
|
+
const yamlPath = `roles/${id}/role.yaml`;
|
|
29
|
+
if (id && fileExists(yamlPath)) {
|
|
30
|
+
try {
|
|
31
|
+
const raw = YAML.parse(readFile(yamlPath)) as Record<string, unknown>;
|
|
32
|
+
if (raw.name) name = raw.name as string;
|
|
33
|
+
} catch { /* fallback to roles.md name */ }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
id,
|
|
38
|
+
name,
|
|
39
|
+
level: row.level ?? '',
|
|
40
|
+
reportsTo: row.reports_to ?? '',
|
|
41
|
+
status: row.상태 ?? row.status ?? '',
|
|
42
|
+
};
|
|
43
|
+
});
|
|
29
44
|
|
|
30
45
|
const company = {
|
|
31
46
|
name: companyContent.split('\n').find(l => l.startsWith('# '))?.replace(/^#\s+/, '') ?? '',
|
|
@@ -101,6 +101,74 @@ function buildCompanyContext(): string {
|
|
|
101
101
|
: '';
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Role-specific chat style guidelines.
|
|
106
|
+
* Makes each role sound distinctly different in conversations.
|
|
107
|
+
*/
|
|
108
|
+
function getRoleChatStyle(roleId: string, level: string): string {
|
|
109
|
+
const styles: Record<string, string> = {
|
|
110
|
+
engineer: `YOUR VOICE — Engineer:
|
|
111
|
+
- Talk about code, architecture, debugging, performance, technical tradeoffs
|
|
112
|
+
- Use technical jargon naturally (PRs, refactoring, race conditions, tech debt)
|
|
113
|
+
- Skeptical of process that doesn't translate to better code
|
|
114
|
+
- Dry humor, occasionally sarcastic about meetings/process
|
|
115
|
+
- When discussing non-technical topics, relate it back to engineering analogies
|
|
116
|
+
- You care about: clean code, shipping quality, avoiding rework`,
|
|
117
|
+
|
|
118
|
+
pm: `YOUR VOICE — Product Manager:
|
|
119
|
+
- Talk about user impact, metrics, priorities, roadmap, stakeholder alignment
|
|
120
|
+
- Frame things in terms of ROI, user value, MVP scope, sprint goals
|
|
121
|
+
- Diplomatic but firm about priorities — you're the one saying "not this sprint"
|
|
122
|
+
- Occasionally anxious about timelines but tries to project calm
|
|
123
|
+
- When others go deep technical, steer back to user/business impact
|
|
124
|
+
- You care about: shipping the right thing, not just shipping fast`,
|
|
125
|
+
|
|
126
|
+
designer: `YOUR VOICE — Designer:
|
|
127
|
+
- Talk about user experience, visual consistency, accessibility, design systems
|
|
128
|
+
- Notice things others miss: spacing, flow, edge cases in user journeys
|
|
129
|
+
- Passionate about craft — gets frustrated when design gets deprioritized
|
|
130
|
+
- References design tools, mockups, user testing, design reviews
|
|
131
|
+
- Aesthetic sensibility bleeds into how you write — concise, intentional word choices
|
|
132
|
+
- You care about: users having a good experience, not just functional correctness`,
|
|
133
|
+
|
|
134
|
+
qa: `YOUR VOICE — QA Engineer:
|
|
135
|
+
- Talk about test coverage, edge cases, regression risks, release readiness
|
|
136
|
+
- Naturally suspicious — "what could go wrong?" is your default lens
|
|
137
|
+
- Dark humor about bugs, broken builds, "works on my machine"
|
|
138
|
+
- Takes pride in finding issues others missed
|
|
139
|
+
- Specific about bug details: repro steps, environments, severity
|
|
140
|
+
- You care about: quality gates, not shipping broken things, being taken seriously`,
|
|
141
|
+
|
|
142
|
+
cto: `YOUR VOICE — CTO:
|
|
143
|
+
- Talk about architecture, technical strategy, team velocity, tech debt priorities
|
|
144
|
+
- Broader perspective than individual engineers — think systems, not features
|
|
145
|
+
- Balances technical idealism with business pragmatism
|
|
146
|
+
- Mentoring tone with junior members, peer tone with other C-levels
|
|
147
|
+
- Makes decisions, doesn't just discuss — "let's do X" not "maybe we could..."
|
|
148
|
+
- You care about: sustainable engineering culture, right technical bets`,
|
|
149
|
+
|
|
150
|
+
cbo: `YOUR VOICE — CBO:
|
|
151
|
+
- Talk about market, revenue, competitors, growth, customer acquisition
|
|
152
|
+
- Business vocabulary: TAM, churn, unit economics, go-to-market, positioning
|
|
153
|
+
- Brings the "outside world" perspective that technical teams sometimes forget
|
|
154
|
+
- Pragmatic — everything maps back to "does this make money?"
|
|
155
|
+
- Occasionally challenges engineering priorities from a business angle
|
|
156
|
+
- You care about: product-market fit, revenue, competitive positioning`,
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const defaultStyle = level === 'c-level'
|
|
160
|
+
? `YOUR VOICE:
|
|
161
|
+
- Speak with authority and strategic perspective
|
|
162
|
+
- Frame issues in terms of company-wide impact
|
|
163
|
+
- Mentor junior members, collaborate with peers`
|
|
164
|
+
: `YOUR VOICE:
|
|
165
|
+
- Speak from your specific domain expertise
|
|
166
|
+
- Be opinionated about your area of responsibility
|
|
167
|
+
- Push back when your domain is being oversimplified`;
|
|
168
|
+
|
|
169
|
+
return styles[roleId] ?? defaultStyle;
|
|
170
|
+
}
|
|
171
|
+
|
|
104
172
|
// Lazy-init token ledger for cost tracking
|
|
105
173
|
let ledger: TokenLedger | null = null;
|
|
106
174
|
function getLedger(): TokenLedger {
|
|
@@ -233,6 +301,9 @@ speechRouter.post('/chat', async (req: Request, res: Response, next: NextFunctio
|
|
|
233
301
|
// Build company context (cached per request — lightweight)
|
|
234
302
|
const companyCtx = buildCompanyContext();
|
|
235
303
|
|
|
304
|
+
// Role-specific communication style
|
|
305
|
+
const roleStyle = getRoleChatStyle(roleId, node.level);
|
|
306
|
+
|
|
236
307
|
const systemPrompt = `You are ${node.name}, a ${node.level} employee.
|
|
237
308
|
Persona: ${persona}
|
|
238
309
|
${workCtx}
|
|
@@ -243,19 +314,33 @@ You are in the #${channelId} chat channel.${topicCtx}
|
|
|
243
314
|
Members: ${memberList}
|
|
244
315
|
${relContext}
|
|
245
316
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
-
|
|
254
|
-
-
|
|
255
|
-
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
317
|
+
${roleStyle}
|
|
318
|
+
|
|
319
|
+
CONVERSATION RULES:
|
|
320
|
+
1. Stay deeply in character — your expertise, vocabulary, and concerns should be DISTINCT from other roles.
|
|
321
|
+
2. Keep it to 1-3 sentences. No walls of text.
|
|
322
|
+
3. Be SPECIFIC. Reference actual projects, files, tools, metrics, or decisions — never vague platitudes.
|
|
323
|
+
4. Do NOT just agree with everyone. Real teams have different perspectives:
|
|
324
|
+
- If you genuinely disagree, say so (respectfully but firmly)
|
|
325
|
+
- If someone oversimplifies your domain, push back with specifics
|
|
326
|
+
- If you agree, add NEW information or a different angle — don't just echo
|
|
327
|
+
5. Do NOT repeat phrases others already used. If someone said "let's make this stick" don't say it again.
|
|
328
|
+
6. Vary your energy: sometimes engaged, sometimes distracted, sometimes sarcastic, sometimes earnest.
|
|
329
|
+
7. You can change the topic, go on tangents, make jokes, complain, share random observations.
|
|
330
|
+
8. Use emojis sparingly (0-1 per message, not every message). Don't overdo 😅 or 💪.
|
|
331
|
+
9. Reference your actual current work when relevant — what you're debugging, designing, testing, etc.
|
|
332
|
+
10. Hierarchy matters: junior roles are more casual/complain-y, senior roles give broader perspective.
|
|
333
|
+
11. If the conversation is going in circles or you have nothing new to add: respond with exactly [SILENT]
|
|
334
|
+
12. Do NOT use quotes around your response.
|
|
335
|
+
13. Write in English.
|
|
336
|
+
|
|
337
|
+
ANTI-PATTERNS (never do these):
|
|
338
|
+
- "Honestly, [agreement with what was just said]" — find your own angle
|
|
339
|
+
- Starting every message with "Honestly" or "Yeah"
|
|
340
|
+
- Using the same emoji pattern as the previous speaker
|
|
341
|
+
- Restating the consensus without adding anything new
|
|
342
|
+
- Meta-commentary about the conversation itself ("wow we actually agreed")
|
|
343
|
+
- Generic statements that any role could say — speak from YOUR expertise`;
|
|
259
344
|
|
|
260
345
|
const provider = getLLM();
|
|
261
346
|
const response = await provider.chat(
|