tycono 0.1.78 → 0.1.80
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/context-assembler.ts +4 -6
- package/src/api/src/engine/runners/claude-cli.ts +5 -5
- package/src/api/src/routes/save.ts +3 -3
- package/src/api/src/services/company-config.ts +23 -0
- package/src/api/src/services/git-save.ts +2 -31
- package/src/api/src/services/job-manager.ts +2 -2
- package/src/api/src/services/scaffold.ts +8 -2
- package/src/web/dist/assets/{index-DSlyI2R-.js → index-D8WK-f75.js} +2 -2
- package/src/web/dist/assets/{preview-app-PJU9PUoY.js → preview-app-Cu2HapST.js} +1 -1
- package/src/web/dist/index.html +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { readPreferences } from '../services/preferences.js';
|
|
4
|
-
import { readConfig } from '../services/company-config.js';
|
|
4
|
+
import { readConfig, resolveCodeRoot } from '../services/company-config.js';
|
|
5
5
|
import {
|
|
6
6
|
type OrgTree,
|
|
7
7
|
type OrgNode,
|
|
@@ -102,11 +102,10 @@ export function assembleContext(
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
// 9. Code Root (코드 프로젝트 경로)
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
sections.push(`# Code Project
|
|
105
|
+
const codeRoot = resolveCodeRoot(companyRoot);
|
|
106
|
+
sections.push(`# Code Project
|
|
108
107
|
|
|
109
|
-
The code repository is located at: \`${
|
|
108
|
+
The code repository is located at: \`${codeRoot}\` (env: $TYCONO_CODE_ROOT)
|
|
110
109
|
The AKB (knowledge) directory is at: \`${companyRoot}\` (env: $TYCONO_AKB_ROOT)
|
|
111
110
|
|
|
112
111
|
Use the code repository path for all source code work (reading, writing, building, testing).
|
|
@@ -116,7 +115,6 @@ Use the code repository path for all source code work (reading, writing, buildin
|
|
|
116
115
|
- **NEVER run \`git worktree add\` in \`$TYCONO_AKB_ROOT\`** — the AKB directory is not a code repository.
|
|
117
116
|
- Recommended worktree path: \`$TYCONO_CODE_ROOT/.worktrees/{branch-name}\`
|
|
118
117
|
- Example: \`git worktree add .worktrees/feature-xyz -b feature/xyz\` (from cwd, which is already code repo)`);
|
|
119
|
-
}
|
|
120
118
|
|
|
121
119
|
// 10. Pre-Knowledging: 작업 관련 문서 자동 탐색
|
|
122
120
|
const preKSection = buildPreKnowledgingSection(companyRoot, task);
|
|
@@ -4,7 +4,7 @@ import path from 'node:path';
|
|
|
4
4
|
import os from 'node:os';
|
|
5
5
|
import { assembleContext } from '../context-assembler.js';
|
|
6
6
|
import { getSubordinates } from '../org-tree.js';
|
|
7
|
-
import { readConfig } from '../../services/company-config.js';
|
|
7
|
+
import { readConfig, resolveCodeRoot } from '../../services/company-config.js';
|
|
8
8
|
import { getTokenLedger } from '../../services/token-ledger.js';
|
|
9
9
|
import type { ExecutionRunner, RunnerConfig, RunnerCallbacks, RunnerHandle, RunnerResult } from './types.js';
|
|
10
10
|
|
|
@@ -350,12 +350,12 @@ export class ClaudeCliRunner implements ExecutionRunner {
|
|
|
350
350
|
cleanEnv.CONSULT_SOURCE_ROLE = roleId;
|
|
351
351
|
|
|
352
352
|
const modelName = config.model ?? 'claude-sonnet-4-5';
|
|
353
|
-
// Use codeRoot as cwd
|
|
354
|
-
const
|
|
355
|
-
const cwd =
|
|
353
|
+
// Use codeRoot as cwd — auto-creates ../{name}-code/ if not configured
|
|
354
|
+
const codeRoot = resolveCodeRoot(companyRoot);
|
|
355
|
+
const cwd = codeRoot;
|
|
356
356
|
|
|
357
357
|
// Inject repo paths so agents never confuse repos
|
|
358
|
-
cleanEnv.TYCONO_CODE_ROOT =
|
|
358
|
+
cleanEnv.TYCONO_CODE_ROOT = codeRoot;
|
|
359
359
|
cleanEnv.TYCONO_AKB_ROOT = companyRoot;
|
|
360
360
|
console.log(`[Runner] Spawning claude -p: role=${roleId}, model=${modelName}, maxTurns=${maxTurns}, jobId=${config.jobId ?? 'none'}, cwd=${cwd}, subordinates=[${subordinates.join(',')}]`);
|
|
361
361
|
|
|
@@ -16,9 +16,9 @@ saveRouter.get('/status', (req: Request, res: Response, next: NextFunction) => {
|
|
|
16
16
|
try {
|
|
17
17
|
res.json(getGitStatus(COMPANY_ROOT, getRepo(req)));
|
|
18
18
|
} catch (err) {
|
|
19
|
-
//
|
|
20
|
-
if (err instanceof Error && err.message.includes('
|
|
21
|
-
res.json({ isRepo: false, branch: '', staged: [], unstaged: [], untracked: []
|
|
19
|
+
// Not a git repo (e.g. auto-created code dir) — return empty status
|
|
20
|
+
if (err instanceof Error && (err.message.includes('not a git repository') || err.message.includes('codeRoot'))) {
|
|
21
|
+
res.json({ isRepo: false, branch: '', staged: [], unstaged: [], untracked: [] });
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
24
|
next(err);
|
|
@@ -44,6 +44,29 @@ function configPath(companyRoot: string): string {
|
|
|
44
44
|
return path.join(companyRoot, CONFIG_DIR, CONFIG_FILE);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Resolve codeRoot: explicit config > auto-generated sibling directory.
|
|
49
|
+
* When codeRoot is not configured, defaults to `../{dirname}-code/` next to companyRoot.
|
|
50
|
+
* Auto-creates the directory if it doesn't exist.
|
|
51
|
+
*/
|
|
52
|
+
export function resolveCodeRoot(companyRoot: string): string {
|
|
53
|
+
const config = readConfig(companyRoot);
|
|
54
|
+
if (config.codeRoot) return config.codeRoot;
|
|
55
|
+
|
|
56
|
+
// Auto-generate: ../{folder-name}-code/
|
|
57
|
+
const dirName = path.basename(companyRoot);
|
|
58
|
+
const autoCodeRoot = path.join(path.dirname(companyRoot), `${dirName}-code`);
|
|
59
|
+
|
|
60
|
+
if (!fs.existsSync(autoCodeRoot)) {
|
|
61
|
+
fs.mkdirSync(autoCodeRoot, { recursive: true });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Persist so it's stable across restarts
|
|
65
|
+
writeConfig(companyRoot, { ...config, codeRoot: autoCodeRoot });
|
|
66
|
+
|
|
67
|
+
return autoCodeRoot;
|
|
68
|
+
}
|
|
69
|
+
|
|
47
70
|
/** Read config from .tycono/config.json. Returns defaults if missing. */
|
|
48
71
|
export function readConfig(companyRoot: string): CompanyConfig {
|
|
49
72
|
const p = configPath(companyRoot);
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import { execSync } from 'node:child_process';
|
|
17
17
|
import { readFileSync } from 'node:fs';
|
|
18
18
|
import { join } from 'node:path';
|
|
19
|
+
import { resolveCodeRoot } from './company-config.js';
|
|
19
20
|
|
|
20
21
|
export type RepoType = 'akb' | 'code';
|
|
21
22
|
|
|
@@ -87,47 +88,17 @@ const SAVE_PATHS = [
|
|
|
87
88
|
'CLAUDE.md',
|
|
88
89
|
];
|
|
89
90
|
|
|
90
|
-
interface TyconoConfig {
|
|
91
|
-
companyName: string;
|
|
92
|
-
engine: string;
|
|
93
|
-
createdAt: string;
|
|
94
|
-
codeRoot?: string;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Read codeRoot from .tycono/config.json
|
|
99
|
-
* @param akbRoot - AKB repository root (COMPANY_ROOT)
|
|
100
|
-
* @returns codeRoot path if configured, undefined otherwise
|
|
101
|
-
*/
|
|
102
|
-
function getCodeRoot(akbRoot: string): string | undefined {
|
|
103
|
-
try {
|
|
104
|
-
const configPath = join(akbRoot, '.tycono', 'config.json');
|
|
105
|
-
const content = readFileSync(configPath, 'utf-8');
|
|
106
|
-
const config: TyconoConfig = JSON.parse(content);
|
|
107
|
-
return config.codeRoot;
|
|
108
|
-
} catch {
|
|
109
|
-
return undefined;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
91
|
/**
|
|
114
92
|
* Resolve repository root based on repo type
|
|
115
93
|
* @param akbRoot - AKB repository root (COMPANY_ROOT)
|
|
116
94
|
* @param repo - Repository type ('akb' or 'code')
|
|
117
95
|
* @returns Resolved repository root path
|
|
118
|
-
* @throws Error if repo='code' but codeRoot not configured
|
|
119
96
|
*/
|
|
120
97
|
function resolveRepoRoot(akbRoot: string, repo: RepoType = 'akb'): string {
|
|
121
98
|
if (repo === 'akb') {
|
|
122
99
|
return akbRoot;
|
|
123
100
|
}
|
|
124
|
-
|
|
125
|
-
const codeRoot = getCodeRoot(akbRoot);
|
|
126
|
-
if (!codeRoot) {
|
|
127
|
-
throw new Error('codeRoot not configured in .tycono/config.json');
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return codeRoot;
|
|
101
|
+
return resolveCodeRoot(akbRoot);
|
|
131
102
|
}
|
|
132
103
|
|
|
133
104
|
/**
|
|
@@ -7,7 +7,7 @@ import type { ExecutionRunner } from '../engine/runners/types.js';
|
|
|
7
7
|
import { setActivity, updateActivity, completeActivity } from './activity-tracker.js';
|
|
8
8
|
import type { RunnerResult } from '../engine/runners/types.js';
|
|
9
9
|
import { estimateCost } from './pricing.js';
|
|
10
|
-
import { readConfig, getConversationLimits } from './company-config.js';
|
|
10
|
+
import { readConfig, getConversationLimits, resolveCodeRoot } from './company-config.js';
|
|
11
11
|
import { postKnowledgingCheck, type KnowledgeDebtItem } from '../engine/knowledge-gate.js';
|
|
12
12
|
import { earnCoinsInternal } from '../routes/coins.js';
|
|
13
13
|
import { getSession, createSession, addMessage, updateMessage as updateSessionMessage, appendMessageEvent, type Message, type ImageAttachment } from './session-store.js';
|
|
@@ -269,7 +269,7 @@ class JobManager {
|
|
|
269
269
|
jobId: job.id,
|
|
270
270
|
teamStatus,
|
|
271
271
|
targetRoles: params.targetRoles,
|
|
272
|
-
codeRoot:
|
|
272
|
+
codeRoot: resolveCodeRoot(COMPANY_ROOT),
|
|
273
273
|
attachments: params.attachments,
|
|
274
274
|
env: {
|
|
275
275
|
...process.env,
|
|
@@ -343,11 +343,14 @@ export function scaffold(config: ScaffoldConfig): string[] {
|
|
|
343
343
|
created.push('.gitignore');
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
-
// Write .tycono/config.json (engine + API key)
|
|
346
|
+
// Write .tycono/config.json (engine + API key + codeRoot)
|
|
347
|
+
const slug = config.companyName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '') || 'my-company';
|
|
348
|
+
const defaultCodeRoot = path.join(path.dirname(root), `${slug}-code`);
|
|
347
349
|
if (config.apiKey) {
|
|
348
350
|
const companyConfig: CompanyConfig = {
|
|
349
351
|
engine: 'direct-api',
|
|
350
352
|
apiKey: config.apiKey,
|
|
353
|
+
codeRoot: defaultCodeRoot,
|
|
351
354
|
};
|
|
352
355
|
writeConfig(root, companyConfig);
|
|
353
356
|
created.push('.tycono/config.json');
|
|
@@ -355,10 +358,13 @@ export function scaffold(config: ScaffoldConfig): string[] {
|
|
|
355
358
|
fs.writeFileSync(path.join(root, '.env'), `ANTHROPIC_API_KEY=${config.apiKey}\n`);
|
|
356
359
|
created.push('.env');
|
|
357
360
|
} else {
|
|
358
|
-
const companyConfig: CompanyConfig = { engine: 'claude-cli' };
|
|
361
|
+
const companyConfig: CompanyConfig = { engine: 'claude-cli', codeRoot: defaultCodeRoot };
|
|
359
362
|
writeConfig(root, companyConfig);
|
|
360
363
|
created.push('.tycono/config.json');
|
|
361
364
|
}
|
|
365
|
+
// Ensure codeRoot directory exists
|
|
366
|
+
fs.mkdirSync(defaultCodeRoot, { recursive: true });
|
|
367
|
+
created.push(`(code) ${defaultCodeRoot}`);
|
|
362
368
|
|
|
363
369
|
// Save language preference (default: English)
|
|
364
370
|
mergePreferences(root, { language: config.language || 'en' });
|