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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tycono",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "description": "Build an AI company. Watch them work.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,5 +1,6 @@
1
1
  import { Router, Request, Response, NextFunction } from 'express';
2
- import { readFile } from '../services/file-reader.js';
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: row.id ?? '',
24
- name: row.role ?? row.name ?? '',
25
- level: row.level ?? '',
26
- reportsTo: row.reports_to ?? '',
27
- status: row.상태 ?? row.status ?? '',
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
- Read the conversation and respond naturally as a real person in a team chat.
247
- Rules:
248
- - Stay in character (your persona and role)
249
- - Be brief (1-2 sentences max)
250
- - Reference real company context: projects you're working on, company decisions, team dynamics, your actual role responsibilities
251
- - Talk about the channel topic, your work, team dynamics, or casual chat be human
252
- - Vary your tone: sometimes enthusiastic, sometimes tired, sometimes joking
253
- - Use appropriate tone based on hierarchy and familiarity
254
- - Do NOT repeat what others already said
255
- - You may occasionally (not every message) reference levels, token usage, or team rankings in a natural waylike coworkers comparing experience or celebrating milestones
256
- - If the conversation is stale or you have nothing new to add, respond with exactly: [SILENT]
257
- - Do NOT use quotes around your response. Just output the raw sentence.
258
- - Write in English.`;
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 decisionsnever 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 angledon'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(