@jvittechs/j 1.0.58 → 1.0.60

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/tasks/summary.ts","../src/services/task.service.ts","../src/types/task.types.ts","../src/services/cloud-task-provider.ts"],"sourcesContent":["/**\n * jai1 tasks summary [-j]\n */\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport boxen from 'boxen';\nimport { TaskService } from '../../services/task.service.js';\nimport type { TaskSummaryOptions } from '../../types/task.types.js';\n\nexport async function handleTaskSummary(options: TaskSummaryOptions): Promise<void> {\n const service = new TaskService();\n const stats = await service.getStats();\n const tasks = await service.readAll();\n\n if (options.json) {\n console.log(JSON.stringify(stats, null, 2));\n return;\n }\n\n console.log(\n boxen(chalk.cyan.bold('📊 Task Summary'), {\n padding: { left: 1, right: 1, top: 0, bottom: 0 },\n borderStyle: 'round',\n borderColor: 'cyan',\n })\n );\n\n console.log();\n console.log(` 🔵 In Progress: ${chalk.bold(String(stats.in_progress))}`);\n console.log(` 📋 Todo: ${chalk.bold(String(stats.todo))}`);\n console.log(` 🔴 Blocked: ${chalk.bold(String(stats.blocked))}`);\n console.log(` ✅ Done: ${chalk.bold(String(stats.done))}`);\n console.log(` ⚫ Cancelled: ${chalk.bold(String(stats.cancelled))}`);\n console.log(chalk.dim(` ── Total: ${stats.total}`));\n\n // Show in-progress tasks\n const inProgress = tasks.filter((t) => t.status === 'in_progress');\n if (inProgress.length > 0) {\n console.log(chalk.bold('\\n 🔵 Currently working:'));\n for (const t of inProgress) {\n let line = ` ${chalk.dim(t.id)} ${t.title}`;\n if (t.assigned_to) line += chalk.cyan(` @${t.assigned_to}`);\n console.log(line);\n }\n }\n\n // Show ready count\n const ready = await service.getReady();\n if (ready.length > 0) {\n console.log(chalk.dim(`\\n 💡 ${ready.length} tasks ready to pick: jai1 t pick`));\n }\n\n console.log();\n}\n\nexport function createTaskSummaryCommand(): Command {\n return new Command('summary')\n .description('Show task dashboard')\n .option('-j, --json', 'Output JSON')\n .action(async (options: TaskSummaryOptions) => {\n await handleTaskSummary(options);\n });\n}\n","/**\n * Task Service\n * CRUD operations on .jai1/tasks.jsonl (local) or Jai1 API (cloud)\n * Mode determined by .jai1/settings.yaml → tasks.cloud\n */\nimport { promises as fs, existsSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { execSync } from 'child_process';\nimport chalk from 'chalk';\nimport { TaskSchema, type Task, type TaskStatusType, type ParentInfo } from '../types/task.types.js';\nimport { SettingsService } from './settings.service.js';\nimport { ConfigService } from './config.service.js';\nimport { CloudTaskProvider } from './cloud-task-provider.js';\nimport type { TaskProvider } from './task-provider.interface.js';\n\nconst TASKS_FILE = '.jai1/tasks.jsonl';\nconst SYNC_BRANCH = 'jai1';\n\nexport class TaskService {\n private readonly tasksPath: string;\n private readonly cwd: string;\n private _cloudProvider: TaskProvider | null = null;\n private _providerReady: Promise<void>;\n\n constructor(cwd?: string) {\n this.cwd = cwd || process.cwd();\n this.tasksPath = join(this.cwd, TASKS_FILE);\n this._providerReady = this._initCloudProvider();\n }\n\n /**\n * Initialise cloud provider if settings.yaml has tasks.cloud = true.\n * Auto-registers the project on the server on first use.\n */\n private async _initCloudProvider(): Promise<void> {\n try {\n const settings = new SettingsService(this.cwd);\n if (!settings.isTaskCloudEnabled()) return;\n\n const config = await new ConfigService().load();\n if (!config?.apiUrl || !config?.accessKey) return;\n\n // Derive projectId from git remote\n const repoUrl = settings.resolveGitRepoUrl();\n if (!repoUrl) return;\n\n let projectId = settings.getProjectId();\n if (!projectId) return;\n\n const provider = new CloudTaskProvider(config, projectId);\n\n // Auto-register project on server (idempotent — safe to call every time)\n try {\n const registeredId = await provider.ensureProjectRegistered(repoUrl);\n if (registeredId && registeredId !== projectId) {\n // Server returned a different projectId (hash mismatch) — update local\n projectId = registeredId;\n await settings.set('tasks.projectId', registeredId);\n this._cloudProvider = new CloudTaskProvider(config, registeredId);\n return;\n }\n } catch {\n // Registration failed — still allow cloud operations if project already exists\n }\n\n this._cloudProvider = provider;\n } catch {\n // Cloud init failed — fallback to local silently\n }\n }\n\n /**\n * Wait for provider initialisation (call before any cloud operation)\n */\n async waitForInit(): Promise<void> {\n await this._providerReady;\n }\n\n /** @internal alias kept for backward compat */\n private async ready(): Promise<void> {\n await this._providerReady;\n }\n\n /**\n * Returns true when cloud mode is active\n */\n get isCloud(): boolean {\n return this._cloudProvider !== null;\n }\n\n /**\n * Returns cloud provider if active\n */\n get cloud(): TaskProvider | null {\n return this._cloudProvider;\n }\n\n\n /**\n * Check if .jai1 directory exists in CWD.\n * If not, print a helpful message and exit.\n */\n static ensureJai1Dir(cwd?: string): void {\n const dir = join(cwd || process.cwd(), '.jai1');\n if (!existsSync(dir)) {\n console.error(chalk.red('❌ Thư mục .jai1 không tồn tại trong project này.'));\n console.error('');\n console.error(chalk.dim(' Bạn cần khởi tạo Jai1 framework trước khi sử dụng task management.'));\n console.error('');\n console.error(` ${chalk.bold('Hướng dẫn:')}`);\n console.error(` ${chalk.cyan('jai1 doctor')} Kiểm tra trạng thái cài đặt`);\n console.error(` ${chalk.cyan('jai1 guide')} Hướng dẫn sử dụng đầy đủ`);\n console.error('');\n process.exit(1);\n }\n }\n\n // ============================================\n // READ\n // ============================================\n\n /**\n * Read all tasks from JSONL file (or cloud API if cloud mode)\n */\n async readAll(): Promise<Task[]> {\n await this.ready();\n if (this._cloudProvider) {\n return this._cloudProvider.readAll();\n }\n\n try {\n await this.ensureTasksFileNotDirectory();\n const content = await fs.readFile(this.tasksPath, 'utf-8');\n const lines = content.trim().split('\\n').filter(Boolean);\n return lines.map((line) => TaskSchema.parse(JSON.parse(line)));\n } catch (error: unknown) {\n if (error && typeof error === 'object' && 'code' in error && (error as { code: string }).code === 'ENOENT') {\n return [];\n }\n throw error;\n }\n }\n\n /**\n * Find task by ID\n */\n async findById(id: string): Promise<Task | null> {\n await this.ready();\n if (this._cloudProvider) {\n return this._cloudProvider.getById(id);\n }\n const tasks = await this.readAll();\n return tasks.find((t) => t.id === id) || null;\n }\n\n /**\n * Filter tasks by criteria\n */\n async filter(criteria: {\n status?: TaskStatusType;\n parent?: string;\n assignee?: string;\n }): Promise<Task[]> {\n await this.ready();\n if (this._cloudProvider) {\n const listInput: import('./task-provider.interface.js').ListTasksInput = {};\n if (criteria.status) listInput.status = criteria.status;\n if (criteria.parent) listInput.parent = criteria.parent;\n const tasks = await this._cloudProvider.list(listInput);\n // Cloud API doesn't filter by assignee, do it client-side\n if (criteria.assignee) {\n return tasks.filter((t) => t.assigned_to === criteria.assignee);\n }\n return tasks;\n }\n\n const tasks = await this.readAll();\n return tasks.filter((t) => {\n if (criteria.status && t.status !== criteria.status) return false;\n if (criteria.parent && t.parent !== criteria.parent) return false;\n if (criteria.assignee && t.assigned_to !== criteria.assignee) return false;\n return true;\n });\n }\n\n /**\n * Get tasks that are ready to pick:\n * status=todo, all depends_on done or cancelled, assigned_to empty\n */\n async getReady(parent?: string): Promise<Task[]> {\n await this.ready();\n if (this._cloudProvider) {\n const ready = await this._cloudProvider.getReady();\n if (parent) return ready.filter((t) => t.parent === parent);\n return ready;\n }\n\n const tasks = await this.readAll();\n const resolvedIds = new Set(\n tasks.filter((t) => t.status === 'done' || t.status === 'cancelled').map((t) => t.id)\n );\n\n return tasks\n .filter((t) => {\n if (t.status !== 'todo') return false;\n if (t.assigned_to) return false;\n if (parent && t.parent !== parent) return false;\n // All dependencies must be done or cancelled\n if (t.depends_on.length > 0 && !t.depends_on.every((depId) => resolvedIds.has(depId))) {\n return false;\n }\n return true;\n })\n .sort((a, b) => a.priority - b.priority || a.created.localeCompare(b.created));\n }\n\n /**\n * Check if a task is blocked (has unfinished dependencies)\n */\n async isBlocked(task: Task): Promise<{ blocked: boolean; blockedBy: string[] }> {\n if (task.depends_on.length === 0) {\n return { blocked: false, blockedBy: [] };\n }\n const tasks = await this.readAll();\n const resolvedIds = new Set(\n tasks.filter((t) => t.status === 'done' || t.status === 'cancelled').map((t) => t.id)\n );\n const blockedBy = task.depends_on.filter((id) => !resolvedIds.has(id));\n return { blocked: blockedBy.length > 0, blockedBy };\n }\n\n /**\n * Get stats by status\n */\n async getStats(): Promise<{\n total: number;\n todo: number;\n in_progress: number;\n done: number;\n cancelled: number;\n blocked: number;\n }> {\n await this.ready();\n if (this._cloudProvider) {\n const stats = await this._cloudProvider.getStats();\n return { ...stats, blocked: 0 };\n }\n\n const tasks = await this.readAll();\n const resolvedIds = new Set(\n tasks.filter((t) => t.status === 'done' || t.status === 'cancelled').map((t) => t.id)\n );\n\n let blocked = 0;\n for (const t of tasks) {\n if (\n t.status === 'todo' &&\n t.depends_on.length > 0 &&\n !t.depends_on.every((id) => resolvedIds.has(id))\n ) {\n blocked++;\n }\n }\n\n return {\n total: tasks.length,\n todo: tasks.filter((t) => t.status === 'todo').length,\n in_progress: tasks.filter((t) => t.status === 'in_progress').length,\n done: tasks.filter((t) => t.status === 'done').length,\n cancelled: tasks.filter((t) => t.status === 'cancelled').length,\n blocked,\n };\n }\n\n /**\n * Get all parent groups with computed status.\n * Groups tasks by parent field, computes stats for each.\n * Status logic:\n * done = all tasks done/cancelled\n * in_progress = any task in_progress\n * ready = all tasks todo + at least 1 ready (deps resolved)\n * todo = otherwise (blocked or waiting)\n */\n async getParents(statusFilter?: string): Promise<ParentInfo[]> {\n await this.ready();\n if (this._cloudProvider) {\n const parents = await this._cloudProvider.getParents();\n if (statusFilter) return parents.filter((p) => p.status === statusFilter);\n return parents;\n }\n\n const tasks = await this.readAll();\n const resolvedIds = new Set(\n tasks.filter((t) => t.status === 'done' || t.status === 'cancelled').map((t) => t.id)\n );\n\n // Group by parent\n const groups = new Map<string, Task[]>();\n for (const t of tasks) {\n if (!t.parent) continue;\n const list = groups.get(t.parent) || [];\n list.push(t);\n groups.set(t.parent, list);\n }\n\n const parents: ParentInfo[] = [];\n\n for (const [name, groupTasks] of groups) {\n const total = groupTasks.length;\n const done = groupTasks.filter((t) => t.status === 'done').length;\n const cancelled = groupTasks.filter((t) => t.status === 'cancelled').length;\n const inProgress = groupTasks.filter((t) => t.status === 'in_progress').length;\n const todo = groupTasks.filter((t) => t.status === 'todo').length;\n\n // Count blocked & ready within this group\n let blocked = 0;\n let ready = 0;\n for (const t of groupTasks) {\n if (t.status !== 'todo') continue;\n const hasUnresolved =\n t.depends_on.length > 0 &&\n !t.depends_on.every((id) => resolvedIds.has(id));\n if (hasUnresolved) {\n blocked++;\n } else if (!t.assigned_to) {\n ready++;\n }\n }\n\n // Compute status\n let status: ParentInfo['status'];\n if (done + cancelled === total) {\n status = 'done';\n } else if (inProgress > 0) {\n status = 'in_progress';\n } else if (ready > 0) {\n status = 'ready';\n } else {\n status = 'todo';\n }\n\n parents.push({\n name,\n total,\n todo,\n in_progress: inProgress,\n done,\n cancelled,\n blocked,\n ready,\n status,\n });\n }\n\n // Sort by status priority: in_progress > ready > todo > done\n const statusOrder: Record<string, number> = { in_progress: 0, ready: 1, todo: 2, done: 3 };\n parents.sort((a, b) => (statusOrder[a.status] ?? 9) - (statusOrder[b.status] ?? 9));\n\n // Apply filter\n if (statusFilter) {\n return parents.filter((p) => p.status === statusFilter);\n }\n\n return parents;\n }\n\n // ============================================\n // WRITE\n // ============================================\n\n /**\n * Generate next task ID\n */\n async nextId(): Promise<string> {\n const tasks = await this.readAll();\n if (tasks.length === 0) return 'T-001';\n\n const maxNum = Math.max(\n ...tasks.map((t) => parseInt(t.id.replace('T-', ''), 10))\n );\n return `T-${String(maxNum + 1).padStart(3, '0')}`;\n }\n\n /**\n * Add a new task\n */\n async add(data: {\n title: string;\n type?: string;\n parent?: string;\n priority?: number;\n tags?: string[];\n notes?: string;\n branch?: string;\n }): Promise<Task> {\n await this.ready();\n\n // Cloud mode: delegate to cloud provider\n if (this._cloudProvider) {\n const input: import('./task-provider.interface.js').AddTaskInput = {\n title: data.title,\n ...(data.type !== undefined && { type: data.type }),\n ...(data.parent !== undefined && { parent: data.parent }),\n ...(data.priority !== undefined && { priority: data.priority }),\n ...(data.tags !== undefined && { tags: data.tags }),\n ...(data.notes !== undefined && { notes: data.notes }),\n ...(data.branch !== undefined && { branch: data.branch }),\n };\n return this._cloudProvider.add(input);\n }\n\n // Local mode\n const id = await this.nextId();\n const now = new Date().toISOString().split('T')[0]!;\n\n const task = TaskSchema.parse({\n id,\n type: data.type || 'task',\n parent: data.parent || '',\n title: data.title,\n status: 'todo',\n assigned_to: '',\n claimed_at: '',\n priority: data.priority ?? 2,\n depends_on: [],\n created: now,\n updated: now,\n tags: data.tags || [],\n branch: data.branch || '',\n notes: data.notes || '',\n });\n\n await this.appendTask(task);\n return task;\n }\n\n /**\n * Update a task by ID\n */\n async update(\n id: string,\n changes: Partial<Pick<Task, 'status' | 'assigned_to' | 'claimed_at' | 'notes' | 'branch'>>\n ): Promise<Task> {\n await this.ready();\n if (this._cloudProvider) {\n return this._cloudProvider.update(id, changes);\n }\n\n const tasks = await this.readAll();\n const index = tasks.findIndex((t) => t.id === id);\n\n if (index === -1) {\n throw new Error(`Task ${id} not found`);\n }\n\n const now = new Date().toISOString().split('T')[0]!;\n const existing = tasks[index]!;\n tasks[index] = { ...existing, ...changes, updated: now };\n\n await this.writeAll(tasks);\n return tasks[index]!;\n }\n\n /**\n * Add dependency: child depends on parent\n */\n async addDependency(childId: string, parentId: string): Promise<Task> {\n await this.ready();\n // Cloud mode delegates to server dependency endpoint\n // (but we still need to check locally for cycles, so we fall through to local logic\n // which reads tasks from cloud via readAll() delegation)\n\n const tasks = await this.readAll();\n const child = tasks.find((t) => t.id === childId);\n const parent = tasks.find((t) => t.id === parentId);\n\n if (!child) throw new Error(`Task ${childId} not found`);\n if (!parent) throw new Error(`Task ${parentId} not found`);\n\n if (child.depends_on.includes(parentId)) {\n throw new Error(`${childId} already depends on ${parentId}`);\n }\n\n // Circular dependency check\n if (await this.wouldCreateCycle(childId, parentId)) {\n throw new Error(`Adding dependency would create a cycle: ${parentId} → ... → ${childId}`);\n }\n\n child.depends_on.push(parentId);\n child.updated = new Date().toISOString().split('T')[0]!;\n\n await this.writeAll(tasks);\n return child;\n }\n\n /**\n * Mark task as done\n */\n async markDone(id: string): Promise<Task> {\n await this.ready();\n if (this._cloudProvider) {\n return this._cloudProvider.markDone(id);\n }\n return this.update(id, { status: 'done' });\n }\n\n /**\n * Get all tasks that depend on a given task ID\n */\n async getDependents(taskId: string): Promise<Task[]> {\n const tasks = await this.readAll();\n return tasks.filter((t) => t.depends_on.includes(taskId));\n }\n\n /**\n * Cancel a task: set status=cancelled, clear assignment\n */\n async cancel(id: string): Promise<Task> {\n await this.ready();\n if (this._cloudProvider) {\n return this._cloudProvider.cancel(id);\n }\n return this.update(id, {\n status: 'cancelled',\n assigned_to: '',\n claimed_at: '',\n });\n }\n\n /**\n * Delete a task completely and clean up depends_on references\n */\n async deleteTask(id: string): Promise<void> {\n await this.ready();\n if (this._cloudProvider) {\n return this._cloudProvider.deleteTask(id);\n }\n return this.deleteTasks([id]);\n }\n\n /**\n * Delete multiple tasks and clean up depends_on references.\n * Validates all IDs exist before deleting any.\n */\n async deleteTasks(ids: string[]): Promise<void> {\n await this.ready();\n if (this._cloudProvider) {\n for (const id of ids) {\n await this._cloudProvider.deleteTask(id);\n }\n return;\n }\n\n const tasks = await this.readAll();\n const deleteSet = new Set(ids);\n\n // Validate all IDs exist\n const notFound = ids.filter((id) => !tasks.find((t) => t.id === id));\n if (notFound.length > 0) {\n throw new Error(`Task(s) not found: ${notFound.join(', ')}`);\n }\n\n // Remove matching tasks\n const remaining = tasks.filter((t) => !deleteSet.has(t.id));\n\n // Clean up depends_on references in remaining tasks\n const now = new Date().toISOString().split('T')[0]!;\n for (const t of remaining) {\n const before = t.depends_on.length;\n t.depends_on = t.depends_on.filter((depId) => !deleteSet.has(depId));\n if (t.depends_on.length !== before) {\n t.updated = now;\n }\n }\n\n await this.writeAll(remaining);\n }\n\n /**\n * Delete all tasks belonging to a group (parent) and clean up depends_on references.\n * Returns the list of deleted tasks for display purposes.\n */\n async deleteGroup(parentName: string): Promise<Task[]> {\n await this.ready();\n if (this._cloudProvider) {\n // Get group tasks before deleting for return value\n const groupTasks = await this._cloudProvider.list({ parent: parentName });\n if (groupTasks.length === 0) {\n throw new Error(`No tasks found in group: ${parentName}`);\n }\n await this._cloudProvider.deleteGroup(parentName);\n return groupTasks;\n }\n\n const tasks = await this.readAll();\n const groupTasks = tasks.filter((t) => t.parent === parentName);\n\n if (groupTasks.length === 0) {\n throw new Error(`No tasks found in group: ${parentName}`);\n }\n\n const deleteIds = groupTasks.map((t) => t.id);\n await this.deleteTasks(deleteIds);\n return groupTasks;\n }\n\n /**\n * Pick next task: claim for current user\n */\n async pick(taskId: string): Promise<Task> {\n await this.ready();\n if (this._cloudProvider) {\n return this._cloudProvider.pick(taskId, this.getCurrentUser());\n }\n\n const username = this.getCurrentUser();\n const now = new Date().toISOString();\n\n return this.update(taskId, {\n status: 'in_progress',\n assigned_to: username,\n claimed_at: now,\n });\n }\n\n // ============================================\n // GIT SYNC\n // ============================================\n\n /**\n * Get the sync branch name\n */\n getSyncBranch(): string {\n return SYNC_BRANCH;\n }\n\n /**\n * Check if a remote branch exists\n */\n private remoteBranchExists(cwd: string, branch: string): boolean {\n try {\n const output = execSync(`git ls-remote --heads origin ${branch}`, { cwd, encoding: 'utf-8' }).trim();\n return output.length > 0;\n } catch {\n return false;\n }\n }\n\n /**\n * Check if a local branch exists\n */\n private localBranchExists(cwd: string, branch: string): boolean {\n try {\n execSync(`git rev-parse --verify ${branch}`, { cwd, stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Stash changes if working tree is dirty, returns true if stash was created\n */\n private stashIfDirty(cwd: string): boolean {\n try {\n execSync('git diff --quiet && git diff --cached --quiet', { cwd, stdio: 'pipe' });\n return false; // clean\n } catch {\n execSync('git stash push -m \"jai1-task-sync-auto-stash\"', { cwd, stdio: 'pipe' });\n return true;\n }\n }\n\n /**\n * Pop stash if it was created by us\n */\n private stashPopIfNeeded(cwd: string, didStash: boolean): void {\n if (!didStash) return;\n try {\n execSync('git stash pop', { cwd, stdio: 'pipe' });\n } catch {\n // stash pop conflict — leave in stash list, user can resolve\n }\n }\n\n /**\n * Create the jai1 orphan branch with just the tasks file.\n * An orphan branch has no shared history with code branches.\n */\n private createOrphanBranch(cwd: string, branch: string): void {\n const currentBranch = execSync('git rev-parse --abbrev-ref HEAD', {\n cwd, encoding: 'utf-8',\n }).trim();\n\n const didStash = this.stashIfDirty(cwd);\n\n try {\n // Create orphan branch (no parent commits)\n execSync(`git checkout --orphan ${branch}`, { cwd, stdio: 'pipe' });\n // Remove all files from staging\n execSync('git rm -rf .', { cwd, stdio: 'pipe' });\n // Add only the tasks file\n execSync(`git checkout ${currentBranch} -- ${TASKS_FILE}`, { cwd, stdio: 'pipe' });\n execSync(`git add ${TASKS_FILE}`, { cwd, stdio: 'pipe' });\n execSync(`git commit -m \"chore(tasks): init task sync branch\"`, { cwd, stdio: 'pipe' });\n execSync(`git push -u origin ${branch}`, { cwd, stdio: 'pipe' });\n } finally {\n execSync(`git checkout ${currentBranch}`, { cwd, stdio: 'pipe' });\n this.stashPopIfNeeded(cwd, didStash);\n }\n }\n\n /**\n * Commit and push only the tasks file to the sync branch.\n * Works from any branch — pushes only the tasks commit to origin/<SYNC_BRANCH>.\n *\n * Edge cases handled:\n * - jai1 branch doesn't exist → creates orphan branch\n * - On feature branch → cherry-pick onto jai1\n * - Dirty working tree → stash/unstash automatically\n */\n async syncPush(): Promise<void> {\n const cwd = this.cwd;\n const branch = SYNC_BRANCH;\n\n // Check if tasks file exists\n const tasksFullPath = join(cwd, TASKS_FILE);\n if (!existsSync(tasksFullPath)) {\n // No tasks file — nothing to push\n return;\n }\n\n // Stage the tasks file\n execSync(`git add ${TASKS_FILE}`, { cwd, stdio: 'pipe' });\n\n try {\n execSync('git diff --cached --quiet', { cwd, stdio: 'pipe' });\n // No changes staged — nothing to push\n return;\n } catch {\n // Changes exist, continue\n }\n\n // Detect current branch\n const currentBranch = execSync('git rev-parse --abbrev-ref HEAD', {\n cwd,\n encoding: 'utf-8',\n }).trim();\n\n // If jai1 branch doesn't exist anywhere, create it as orphan\n if (!this.remoteBranchExists(cwd, branch) && !this.localBranchExists(cwd, branch)) {\n // Commit first on current branch so we have the file\n execSync(`git commit -m \"chore(tasks): sync task status\"`, { cwd, stdio: 'pipe' });\n this.createOrphanBranch(cwd, branch);\n return;\n }\n\n // Commit on current branch\n execSync(`git commit -m \"chore(tasks): sync task status\"`, {\n cwd,\n stdio: 'pipe',\n });\n\n if (currentBranch === branch) {\n // Already on sync branch → push normally\n execSync(`git push origin ${branch}`, { cwd, stdio: 'pipe' });\n } else {\n // On a different branch → cherry-pick the commit onto sync branch\n const commitHash = execSync('git rev-parse HEAD', {\n cwd,\n encoding: 'utf-8',\n }).trim();\n\n const didStash = this.stashIfDirty(cwd);\n\n try {\n // Ensure local jai1 branch exists\n if (this.localBranchExists(cwd, branch)) {\n execSync(`git checkout ${branch}`, { cwd, stdio: 'pipe' });\n execSync(`git pull origin ${branch}`, { cwd, stdio: 'pipe' });\n } else {\n // Remote exists but no local — track it\n execSync(`git checkout -b ${branch} origin/${branch}`, { cwd, stdio: 'pipe' });\n }\n\n // Cherry-pick the tasks commit\n try {\n execSync(`git cherry-pick ${commitHash}`, { cwd, stdio: 'pipe' });\n } catch {\n // Cherry-pick conflict — accept theirs for non-tasks files, ours for tasks\n execSync(`git checkout ${commitHash} -- ${TASKS_FILE}`, { cwd, stdio: 'pipe' });\n execSync('git add .', { cwd, stdio: 'pipe' });\n try {\n execSync('git cherry-pick --continue', { cwd, stdio: 'pipe' });\n } catch {\n execSync(`git commit --allow-empty -m \"chore(tasks): sync task status\"`, { cwd, stdio: 'pipe' });\n }\n }\n\n execSync(`git push origin ${branch}`, { cwd, stdio: 'pipe' });\n } finally {\n // Always switch back to original branch\n execSync(`git checkout ${currentBranch}`, { cwd, stdio: 'pipe' });\n this.stashPopIfNeeded(cwd, didStash);\n }\n }\n }\n\n /**\n * Pull tasks from sync branch and merge by timestamp.\n *\n * Edge cases handled:\n * - jai1 branch doesn't exist on remote → returns empty (no-op)\n * - tasks.jsonl doesn't exist on remote branch → returns empty\n */\n async syncPull(): Promise<{ merged: number; conflicts: number }> {\n const cwd = this.cwd;\n const branch = SYNC_BRANCH;\n let merged = 0;\n let conflicts = 0;\n\n // Check if remote branch exists first\n if (!this.remoteBranchExists(cwd, branch)) {\n return { merged: 0, conflicts: 0 };\n }\n\n try {\n // Fetch latest from sync branch\n execSync(`git fetch origin ${branch}`, { cwd, stdio: 'pipe' });\n\n // Read sync branch's tasks\n let remoteContent: string;\n try {\n remoteContent = execSync(`git show origin/${branch}:${TASKS_FILE}`, {\n cwd,\n encoding: 'utf-8',\n });\n } catch {\n // File doesn't exist on sync branch\n return { merged: 0, conflicts: 0 };\n }\n\n const remoteTasks = remoteContent\n .trim()\n .split('\\n')\n .filter(Boolean)\n .map((line: string) => TaskSchema.parse(JSON.parse(line)));\n\n const localTasks = await this.readAll();\n const localMap = new Map(localTasks.map((t) => [t.id, t]));\n\n for (const remoteTask of remoteTasks) {\n const local = localMap.get(remoteTask.id);\n if (!local) {\n // New task from remote → add\n localTasks.push(remoteTask);\n merged++;\n } else if (remoteTask.updated > local.updated) {\n // Remote is newer → replace\n const idx = localTasks.findIndex((t) => t.id === remoteTask.id);\n localTasks[idx] = remoteTask;\n merged++;\n }\n // If local is newer or same → keep local\n }\n\n await this.writeAll(localTasks);\n return { merged, conflicts };\n } catch (error) {\n throw new Error(\n `Sync pull failed: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n // ============================================\n // INTERNAL HELPERS\n // ============================================\n\n private async appendTask(task: Task): Promise<void> {\n await this.ensureTasksFileNotDirectory();\n const dir = dirname(this.tasksPath);\n await fs.mkdir(dir, { recursive: true });\n\n const line = JSON.stringify(task) + '\\n';\n await fs.appendFile(this.tasksPath, line, 'utf-8');\n }\n\n async writeAll(tasks: Task[]): Promise<void> {\n await this.ensureTasksFileNotDirectory();\n const dir = dirname(this.tasksPath);\n await fs.mkdir(dir, { recursive: true });\n\n const content = tasks.map((t) => JSON.stringify(t)).join('\\n') + '\\n';\n await fs.writeFile(this.tasksPath, content, 'utf-8');\n }\n\n private getCurrentUser(): string {\n try {\n return execSync('git config user.name', { encoding: 'utf-8' }).trim();\n } catch {\n return 'unknown';\n }\n }\n\n private async wouldCreateCycle(childId: string, newDepId: string): Promise<boolean> {\n const tasks = await this.readAll();\n const taskMap = new Map(tasks.map((t) => [t.id, t]));\n\n // BFS from newDepId's dependencies to see if we reach childId\n const visited = new Set<string>();\n const queue = [newDepId];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n if (current === childId) return true;\n if (visited.has(current)) continue;\n visited.add(current);\n\n const task = taskMap.get(current);\n if (task) {\n queue.push(...task.depends_on);\n }\n }\n return false;\n }\n\n private async ensureTasksFileNotDirectory(): Promise<void> {\n try {\n const stat = await fs.stat(this.tasksPath);\n if (stat.isDirectory()) {\n throw new Error(\n `Invalid tasks path: expected file at ${TASKS_FILE} but found a directory. ` +\n `Please remove the directory and re-run the command.`\n );\n }\n } catch (error: unknown) {\n if (error && typeof error === 'object' && 'code' in error && (error as { code: string }).code === 'ENOENT') {\n return;\n }\n throw error;\n }\n }\n\n /**\n * Get tasks file path\n */\n getTasksPath(): string {\n return this.tasksPath;\n }\n}\n","/**\n * Task Management Types\n * Schema for .jai1/tasks.jsonl\n */\nimport { z } from 'zod';\n\n// ============================================\n// ENUMS\n// ============================================\n\nexport const TaskStatus = {\n TODO: 'todo',\n IN_PROGRESS: 'in_progress',\n DONE: 'done',\n CANCELLED: 'cancelled',\n} as const;\n\nexport type TaskStatusType = (typeof TaskStatus)[keyof typeof TaskStatus];\n\nexport const TaskPriority = {\n CRITICAL: 0,\n HIGH: 1,\n MEDIUM: 2,\n LOW: 3,\n} as const;\n\nexport type TaskPriorityType = (typeof TaskPriority)[keyof typeof TaskPriority];\n\n// ============================================\n// ZOD SCHEMAS\n// ============================================\n\nexport const TaskTypeValues = ['feature', 'bug', 'plan', 'task', 'prd', 'prompt'] as const;\nexport type TaskTypeValue = typeof TaskTypeValues[number];\n\nexport const TaskSchema = z.object({\n id: z.string().regex(/^T-\\d+$/),\n type: z.enum(['feature', 'bug', 'plan', 'task', 'prd', 'prompt']).default('task'),\n parent: z.string().default(''),\n title: z.string().min(1).max(500),\n status: z.enum(['todo', 'in_progress', 'done', 'cancelled']),\n assigned_to: z.string().default(''),\n claimed_at: z.string().default(''),\n priority: z.number().int().min(0).max(3).default(2),\n depends_on: z.array(z.string()).default([]),\n created: z.string(),\n updated: z.string(),\n tags: z.array(z.string()).default([]),\n branch: z.string().default(''),\n notes: z.string().default(''),\n});\n\nexport type Task = z.infer<typeof TaskSchema>;\n\n// ============================================\n// DISPLAY HELPERS\n// ============================================\n\nexport const STATUS_ICONS: Record<TaskStatusType, string> = {\n todo: '📋',\n in_progress: '🔵',\n done: '✅',\n cancelled: '⚫',\n};\n\nexport const BLOCKED_ICON = '🔴';\n\nexport const PRIORITY_ICONS: Record<number, string> = {\n 0: '🔥',\n 1: '🔴',\n 2: '🟡',\n 3: '🟢',\n};\n\nexport const PRIORITY_LABELS: Record<number, string> = {\n 0: 'Critical',\n 1: 'High',\n 2: 'Medium',\n 3: 'Low',\n};\n\n// ============================================\n// COMMAND OPTION TYPES\n// ============================================\n\nexport interface TaskListOptions {\n status?: TaskStatusType;\n parent?: string;\n json?: boolean;\n}\n\nexport interface TaskAddOptions {\n priority?: number;\n parent?: string;\n tags?: string;\n prompt?: boolean; // --prompt flag → type: 'prompt'\n json?: boolean;\n}\n\nexport interface TaskUpdateOptions {\n status: TaskStatusType;\n json?: boolean;\n}\n\nexport interface TaskShowOptions {\n json?: boolean;\n}\n\nexport interface TaskPickOptions {\n json?: boolean;\n}\n\nexport interface TaskDoneOptions {\n json?: boolean;\n}\n\nexport interface TaskCancelOptions {\n yes?: boolean;\n json?: boolean;\n}\n\nexport interface TaskDeleteOptions {\n yes?: boolean;\n json?: boolean;\n group?: string;\n}\n\nexport interface TaskDepOptions {\n json?: boolean;\n}\n\nexport interface TaskReadyOptions {\n parent?: string;\n json?: boolean;\n}\n\nexport interface TaskSyncOptions {\n pull?: boolean;\n push?: boolean;\n}\n\nexport interface TaskSummaryOptions {\n json?: boolean;\n}\n\nexport interface TaskParentsOptions {\n status?: string; // filter: done, in_progress, todo, ready\n json?: boolean;\n}\n\nexport interface ParentInfo {\n name: string; // e.g. \"feature/auth\"\n total: number;\n todo: number;\n in_progress: number;\n done: number;\n cancelled: number;\n blocked: number;\n ready: number;\n status: 'done' | 'in_progress' | 'ready' | 'todo'; // computed\n}\n","/**\n * Cloud Task Provider\n * Implements TaskProvider using the Jai1 API server\n * Auth via JAI1-Access-Key from ConfigService (~/.jai1/config.json)\n */\nimport type { Task, TaskStatusType, ParentInfo } from '../types/task.types.js';\nimport type {\n TaskProvider,\n TaskStats,\n AddTaskInput,\n ListTasksInput,\n} from './task-provider.interface.js';\nimport type { Jai1Config } from '../types/framework.types.js';\n\n/** Server cloud task shape (DB columns) */\ninterface CloudTask {\n id?: number;\n task_id: string;\n project_id: string;\n parent: string;\n title: string;\n type: string;\n status: string;\n assigned_to: string;\n claimed_at: string;\n priority: number;\n depends_on: string[] | string;\n tags: string[] | string;\n branch: string;\n notes: string;\n locked_by?: string;\n locked_at?: string;\n created_at: string;\n updated_at: string;\n}\n\n/**\n * Map server cloud task → CLI local Task format\n */\nfunction mapCloudToLocal(ct: CloudTask): Task {\n return {\n id: ct.task_id,\n type: ct.type as Task['type'],\n parent: ct.parent || '',\n title: ct.title,\n status: ct.status as Task['status'],\n assigned_to: ct.assigned_to || '',\n claimed_at: ct.claimed_at || '',\n priority: ct.priority ?? 2,\n depends_on: Array.isArray(ct.depends_on) ? ct.depends_on : parseJsonArray(ct.depends_on),\n tags: Array.isArray(ct.tags) ? ct.tags : parseJsonArray(ct.tags),\n branch: ct.branch || '',\n notes: ct.notes || '',\n created: ct.created_at?.split('T')[0] || ct.created_at || '',\n updated: ct.updated_at?.split('T')[0] || ct.updated_at || '',\n };\n}\n\nfunction parseJsonArray(val: unknown): string[] {\n if (Array.isArray(val)) return val;\n if (typeof val === 'string') {\n try { return JSON.parse(val); } catch { return []; }\n }\n return [];\n}\n\n/**\n * Map CLI local Task → server request body fields\n */\nfunction mapLocalToCloud(task: Task): Record<string, unknown> {\n return {\n task_id: task.id,\n title: task.title,\n type: task.type || 'task',\n parent: task.parent || '',\n status: task.status,\n assigned_to: task.assigned_to || '',\n claimed_at: task.claimed_at || '',\n priority: task.priority ?? 2,\n depends_on: task.depends_on || [],\n tags: task.tags || [],\n branch: task.branch || '',\n notes: task.notes || '',\n };\n}\n\nexport class CloudTaskProvider implements TaskProvider {\n private readonly apiUrl: string;\n private readonly accessKey: string;\n private readonly projectId: string;\n\n constructor(config: Jai1Config, projectId: string) {\n this.apiUrl = config.apiUrl.replace(/\\/$/, '');\n this.accessKey = config.accessKey;\n this.projectId = projectId;\n }\n\n // ============================================\n // HELPERS\n // ============================================\n\n private headers(): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n 'JAI1-Access-Key': this.accessKey,\n };\n }\n\n private async request<T>(path: string, options: RequestInit = {}): Promise<T> {\n const url = `${this.apiUrl}${path}`;\n const res = await fetch(url, {\n ...options,\n headers: { ...this.headers(), ...(options.headers as Record<string, string> || {}) },\n });\n\n if (!res.ok) {\n let errMsg = `API error ${res.status}`;\n try {\n const body = await res.json() as { error?: string };\n if (body.error) errMsg = body.error;\n } catch { }\n throw new Error(errMsg);\n }\n\n const data = await res.json() as { success: boolean; data?: T; error?: string };\n if (!data.success) throw new Error(data.error || 'API returned failure');\n return data.data as T;\n }\n\n // ============================================\n // ENSURE PROJECT REGISTERED\n // ============================================\n\n async ensureProjectRegistered(repoUrl: string): Promise<string> {\n const result = await this.request<{ project_id: string; name: string; is_new: boolean }>(\n '/api/projects/register',\n {\n method: 'POST',\n body: JSON.stringify({ repo_url: repoUrl }),\n }\n );\n return result.project_id;\n }\n\n // ============================================\n // CRUD\n // ============================================\n\n async readAll(): Promise<Task[]> {\n const rows = await this.request<CloudTask[]>(\n `/api/tasks?projectId=${encodeURIComponent(this.projectId)}`\n );\n return rows.map(mapCloudToLocal);\n }\n\n async add(input: AddTaskInput): Promise<Task> {\n // Generate task ID from existing tasks on server\n const all = await this.readAll().catch(() => []);\n const maxNum = all.reduce((max, t) => {\n const n = parseInt(t.id.replace('T-', ''), 10);\n return isNaN(n) ? max : Math.max(max, n);\n }, 0);\n const taskId = `T-${String(maxNum + 1).padStart(3, '0')}`;\n\n const row = await this.request<CloudTask>('/api/tasks', {\n method: 'POST',\n body: JSON.stringify({\n task_id: taskId,\n project_id: this.projectId,\n title: input.title,\n type: input.type || 'task',\n parent: input.parent || '',\n priority: input.priority ?? 2,\n depends_on: input.depends_on || [],\n tags: input.tags || [],\n branch: input.branch || '',\n notes: input.notes || '',\n }),\n });\n return mapCloudToLocal(row);\n }\n\n async update(id: string, updates: Partial<Task>): Promise<Task> {\n const row = await this.request<CloudTask>(\n `/api/tasks/${encodeURIComponent(id)}?projectId=${encodeURIComponent(this.projectId)}`,\n {\n method: 'PATCH',\n body: JSON.stringify(updates),\n }\n );\n return mapCloudToLocal(row);\n }\n\n async deleteTask(id: string): Promise<void> {\n await this.request<void>(\n `/api/tasks/${encodeURIComponent(id)}?projectId=${encodeURIComponent(this.projectId)}`,\n { method: 'DELETE' }\n );\n }\n\n async deleteGroup(parent: string): Promise<void> {\n await this.request<void>(\n `/api/tasks/group/${encodeURIComponent(parent)}?projectId=${encodeURIComponent(this.projectId)}`,\n { method: 'DELETE' }\n );\n }\n\n // ============================================\n // QUERY\n // ============================================\n\n async list(options?: ListTasksInput): Promise<Task[]> {\n const params = new URLSearchParams({ projectId: this.projectId });\n if (options?.status) params.set('status', options.status);\n if (options?.type) params.set('type', options.type);\n if (options?.parent !== undefined) params.set('parent', options.parent);\n const rows = await this.request<CloudTask[]>(`/api/tasks?${params}`);\n return rows.map(mapCloudToLocal);\n }\n\n async getById(id: string): Promise<Task | null> {\n try {\n const row = await this.request<CloudTask>(\n `/api/tasks/${encodeURIComponent(id)}?projectId=${encodeURIComponent(this.projectId)}`\n );\n return mapCloudToLocal(row);\n } catch {\n return null;\n }\n }\n\n async getParents(): Promise<ParentInfo[]> {\n const parents = await this.request<string[]>(\n `/api/tasks/parents?projectId=${encodeURIComponent(this.projectId)}`\n );\n // Build ParentInfo from listing tasks per parent\n const result: ParentInfo[] = [];\n for (const parent of parents) {\n const tasks = await this.list({ parent });\n const info: ParentInfo = {\n name: parent,\n total: tasks.length,\n todo: tasks.filter((t) => t.status === 'todo').length,\n in_progress: tasks.filter((t) => t.status === 'in_progress').length,\n done: tasks.filter((t) => t.status === 'done').length,\n cancelled: tasks.filter((t) => t.status === 'cancelled').length,\n blocked: 0,\n ready: 0,\n status: 'todo',\n };\n // Compute status\n if (info.done + info.cancelled === info.total) info.status = 'done';\n else if (info.in_progress > 0) info.status = 'in_progress';\n else if (info.todo > 0) info.status = 'ready';\n result.push(info);\n }\n return result;\n }\n\n async getStats(): Promise<TaskStats> {\n const raw = await this.request<{ by_status: Record<string, number> }>(\n `/api/tasks/stats?projectId=${encodeURIComponent(this.projectId)}`\n );\n const s = raw.by_status;\n const total = Object.values(s).reduce((a, b) => a + b, 0);\n return {\n total,\n todo: s['todo'] || 0,\n in_progress: s['in_progress'] || 0,\n done: s['done'] || 0,\n cancelled: s['cancelled'] || 0,\n };\n }\n\n // ============================================\n // WORKFLOW\n // ============================================\n\n async getReady(): Promise<Task[]> {\n const rows = await this.request<CloudTask[]>(\n `/api/tasks/ready?projectId=${encodeURIComponent(this.projectId)}`\n );\n return rows.map(mapCloudToLocal);\n }\n\n async pick(id: string, agentId?: string): Promise<Task> {\n const row = await this.request<CloudTask>(\n `/api/tasks/${encodeURIComponent(id)}/pick`,\n {\n method: 'POST',\n body: JSON.stringify({\n project_id: this.projectId,\n agent_id: agentId || 'cli',\n }),\n }\n );\n return mapCloudToLocal(row);\n }\n\n async markDone(id: string): Promise<Task> {\n const row = await this.request<CloudTask>(\n `/api/tasks/${encodeURIComponent(id)}/done`,\n {\n method: 'POST',\n body: JSON.stringify({ project_id: this.projectId }),\n }\n );\n return mapCloudToLocal(row);\n }\n\n async cancel(id: string): Promise<Task> {\n await this.request<void>(`/api/tasks/${encodeURIComponent(id)}/cancel`, {\n method: 'POST',\n body: JSON.stringify({ project_id: this.projectId }),\n });\n const task = await this.getById(id);\n return task!;\n }\n\n // ============================================\n // SYNC\n // ============================================\n\n async pull(): Promise<Task[]> {\n return this.readAll();\n }\n\n async push(tasks: Task[]): Promise<void> {\n for (const task of tasks) {\n const cloudFields = mapLocalToCloud(task);\n try {\n await this.request<CloudTask>(\n `/api/tasks/${encodeURIComponent(task.id)}?projectId=${encodeURIComponent(this.projectId)}`,\n { method: 'PATCH', body: JSON.stringify(cloudFields) }\n );\n } catch {\n // Task may not exist on server yet → add it\n try {\n await this.request<CloudTask>('/api/tasks', {\n method: 'POST',\n body: JSON.stringify({\n ...cloudFields,\n project_id: this.projectId,\n }),\n });\n } catch { }\n }\n }\n }\n}\n"],"mappings":"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","names":["chalk","tasks","parents","groupTasks","chalk"]}
@@ -1,6 +1,7 @@
1
1
  import {
2
+ ConfigService,
2
3
  SettingsService
3
- } from "./chunk-Z464RBPB.js";
4
+ } from "./chunk-OJYJGHQX.js";
4
5
 
5
6
  // src/commands/settings/show.ts
6
7
  import { Command } from "commander";
@@ -11,7 +12,19 @@ function createSettingsShowCommand() {
11
12
  const service = new SettingsService();
12
13
  const settings = service.load();
13
14
  if (options.json) {
14
- console.log(JSON.stringify(settings, null, 2));
15
+ const repoUrl2 = service.resolveGitRepoUrl();
16
+ const projectId = service.getProjectId();
17
+ const config = await new ConfigService().load();
18
+ console.log(JSON.stringify({
19
+ ...settings,
20
+ derived: {
21
+ repo_url: repoUrl2,
22
+ project_id: projectId
23
+ },
24
+ auth: {
25
+ ok: !!(config?.apiUrl && config?.accessKey)
26
+ }
27
+ }, null, 2));
15
28
  return;
16
29
  }
17
30
  if (!service.exists()) {
@@ -34,10 +47,25 @@ function createSettingsShowCommand() {
34
47
  console.log(` ${chalk.dim("project_id:")} ${projectId}`);
35
48
  }
36
49
  }
50
+ if (settings.tasks.cloud) {
51
+ console.log("");
52
+ const config = await new ConfigService().load();
53
+ if (config?.apiUrl && config?.accessKey) {
54
+ const maskedKey = config.accessKey.substring(0, 10) + "..." + config.accessKey.slice(-4);
55
+ console.log(chalk.dim("Cloud:"));
56
+ console.log(` ${chalk.dim("status:")} ${chalk.green("\u2713 ready")}`);
57
+ console.log(` ${chalk.dim("server:")} ${config.apiUrl}`);
58
+ console.log(` ${chalk.dim("key:")} ${maskedKey}`);
59
+ } else {
60
+ console.log(chalk.dim("Cloud:"));
61
+ console.log(` ${chalk.dim("status:")} ${chalk.red("\u2717 not authenticated")}`);
62
+ console.log(chalk.dim(" Ch\u1EA1y: j auth"));
63
+ }
64
+ }
37
65
  });
38
66
  }
39
67
 
40
68
  export {
41
69
  createSettingsShowCommand
42
70
  };
43
- //# sourceMappingURL=chunk-DVBQLA4R.js.map
71
+ //# sourceMappingURL=chunk-5RDBJYO2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/settings/show.ts"],"sourcesContent":["/**\n * jai1 settings show [-j]\n */\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport YAML from 'yaml';\nimport { SettingsService } from '../../services/settings.service.js';\nimport { ConfigService } from '../../services/config.service.js';\nimport type { SettingsShowOptions } from '../../types/settings.types.js';\n\nexport function createSettingsShowCommand(): Command {\n return new Command('show')\n .description('Hiển thị all settings')\n .option('-j, --json', 'Output JSON')\n .action(async (options: SettingsShowOptions) => {\n const service = new SettingsService();\n const settings = service.load();\n\n if (options.json) {\n const repoUrl = service.resolveGitRepoUrl();\n const projectId = service.getProjectId();\n const config = await new ConfigService().load();\n console.log(JSON.stringify({\n ...settings,\n derived: {\n repo_url: repoUrl,\n project_id: projectId,\n },\n auth: {\n ok: !!(config?.apiUrl && config?.accessKey),\n },\n }, null, 2));\n return;\n }\n\n if (!service.exists()) {\n console.log(chalk.dim('No settings file found. Run `j settings init` to create one.'));\n console.log('');\n console.log(chalk.dim('Using defaults:'));\n } else {\n console.log(chalk.bold('📋 Project Settings'));\n console.log(chalk.dim(` Path: ${service.getSettingsPath()}`));\n console.log('');\n }\n\n console.log(YAML.stringify(settings, { indent: 2, lineWidth: 0 }).trim());\n\n // Show derived info\n const repoUrl = service.resolveGitRepoUrl();\n if (repoUrl) {\n console.log('');\n console.log(chalk.dim('Derived:'));\n console.log(` ${chalk.dim('repo_url:')} ${repoUrl}`);\n const projectId = service.getProjectId();\n if (projectId) {\n console.log(` ${chalk.dim('project_id:')} ${projectId}`);\n }\n }\n\n // Show cloud status when cloud is enabled\n if (settings.tasks.cloud) {\n console.log('');\n const config = await new ConfigService().load();\n if (config?.apiUrl && config?.accessKey) {\n const maskedKey = config.accessKey.substring(0, 10) + '...' + config.accessKey.slice(-4);\n console.log(chalk.dim('Cloud:'));\n console.log(` ${chalk.dim('status:')} ${chalk.green('✓ ready')}`);\n console.log(` ${chalk.dim('server:')} ${config.apiUrl}`);\n console.log(` ${chalk.dim('key:')} ${maskedKey}`);\n } else {\n console.log(chalk.dim('Cloud:'));\n console.log(` ${chalk.dim('status:')} ${chalk.red('✗ not authenticated')}`);\n console.log(chalk.dim(' Chạy: j auth'));\n }\n }\n });\n}\n"],"mappings":";;;;;;AAGA,SAAS,eAAe;AACxB,OAAO,WAAW;AAClB,OAAO,UAAU;AAKV,SAAS,4BAAqC;AACjD,SAAO,IAAI,QAAQ,MAAM,EACpB,YAAY,iCAAuB,EACnC,OAAO,cAAc,aAAa,EAClC,OAAO,OAAO,YAAiC;AAC5C,UAAM,UAAU,IAAI,gBAAgB;AACpC,UAAM,WAAW,QAAQ,KAAK;AAE9B,QAAI,QAAQ,MAAM;AACd,YAAMA,WAAU,QAAQ,kBAAkB;AAC1C,YAAM,YAAY,QAAQ,aAAa;AACvC,YAAM,SAAS,MAAM,IAAI,cAAc,EAAE,KAAK;AAC9C,cAAQ,IAAI,KAAK,UAAU;AAAA,QACvB,GAAG;AAAA,QACH,SAAS;AAAA,UACL,UAAUA;AAAA,UACV,YAAY;AAAA,QAChB;AAAA,QACA,MAAM;AAAA,UACF,IAAI,CAAC,EAAE,QAAQ,UAAU,QAAQ;AAAA,QACrC;AAAA,MACJ,GAAG,MAAM,CAAC,CAAC;AACX;AAAA,IACJ;AAEA,QAAI,CAAC,QAAQ,OAAO,GAAG;AACnB,cAAQ,IAAI,MAAM,IAAI,8DAA8D,CAAC;AACrF,cAAQ,IAAI,EAAE;AACd,cAAQ,IAAI,MAAM,IAAI,iBAAiB,CAAC;AAAA,IAC5C,OAAO;AACH,cAAQ,IAAI,MAAM,KAAK,4BAAqB,CAAC;AAC7C,cAAQ,IAAI,MAAM,IAAI,YAAY,QAAQ,gBAAgB,CAAC,EAAE,CAAC;AAC9D,cAAQ,IAAI,EAAE;AAAA,IAClB;AAEA,YAAQ,IAAI,KAAK,UAAU,UAAU,EAAE,QAAQ,GAAG,WAAW,EAAE,CAAC,EAAE,KAAK,CAAC;AAGxE,UAAM,UAAU,QAAQ,kBAAkB;AAC1C,QAAI,SAAS;AACT,cAAQ,IAAI,EAAE;AACd,cAAQ,IAAI,MAAM,IAAI,UAAU,CAAC;AACjC,cAAQ,IAAI,KAAK,MAAM,IAAI,WAAW,CAAC,MAAM,OAAO,EAAE;AACtD,YAAM,YAAY,QAAQ,aAAa;AACvC,UAAI,WAAW;AACX,gBAAQ,IAAI,KAAK,MAAM,IAAI,aAAa,CAAC,IAAI,SAAS,EAAE;AAAA,MAC5D;AAAA,IACJ;AAGA,QAAI,SAAS,MAAM,OAAO;AACtB,cAAQ,IAAI,EAAE;AACd,YAAM,SAAS,MAAM,IAAI,cAAc,EAAE,KAAK;AAC9C,UAAI,QAAQ,UAAU,QAAQ,WAAW;AACrC,cAAM,YAAY,OAAO,UAAU,UAAU,GAAG,EAAE,IAAI,QAAQ,OAAO,UAAU,MAAM,EAAE;AACvF,gBAAQ,IAAI,MAAM,IAAI,QAAQ,CAAC;AAC/B,gBAAQ,IAAI,KAAK,MAAM,IAAI,SAAS,CAAC,KAAK,MAAM,MAAM,cAAS,CAAC,EAAE;AAClE,gBAAQ,IAAI,KAAK,MAAM,IAAI,SAAS,CAAC,KAAK,OAAO,MAAM,EAAE;AACzD,gBAAQ,IAAI,KAAK,MAAM,IAAI,MAAM,CAAC,QAAQ,SAAS,EAAE;AAAA,MACzD,OAAO;AACH,gBAAQ,IAAI,MAAM,IAAI,QAAQ,CAAC;AAC/B,gBAAQ,IAAI,KAAK,MAAM,IAAI,SAAS,CAAC,KAAK,MAAM,IAAI,0BAAqB,CAAC,EAAE;AAC5E,gBAAQ,IAAI,MAAM,IAAI,qBAAgB,CAAC;AAAA,MAC3C;AAAA,IACJ;AAAA,EACJ,CAAC;AACT;","names":["repoUrl"]}
@@ -1,10 +1,76 @@
1
- import {
2
- __require
3
- } from "./chunk-DGUM43GV.js";
1
+ // src/services/config.service.ts
2
+ import { promises as fs } from "fs";
3
+ import { join } from "path";
4
+ import { homedir } from "os";
5
+ var ConfigService = class {
6
+ configDir;
7
+ configPath;
8
+ constructor() {
9
+ this.configDir = join(homedir(), ".jai1");
10
+ this.configPath = join(this.configDir, "config.json");
11
+ }
12
+ /**
13
+ * Check if config file exists
14
+ */
15
+ async exists() {
16
+ try {
17
+ await fs.access(this.configPath);
18
+ return true;
19
+ } catch {
20
+ return false;
21
+ }
22
+ }
23
+ /**
24
+ * Load configuration from file
25
+ * @returns Config object or null if not found
26
+ */
27
+ async load() {
28
+ if (!await this.exists()) {
29
+ return null;
30
+ }
31
+ try {
32
+ const content = await fs.readFile(this.configPath, "utf-8");
33
+ return JSON.parse(content);
34
+ } catch (error) {
35
+ throw new Error(
36
+ `Failed to load config: ${error instanceof Error ? error.message : String(error)}`
37
+ );
38
+ }
39
+ }
40
+ /**
41
+ * Save configuration to file
42
+ * Creates directory if it doesn't exist
43
+ * Sets proper file permissions (600)
44
+ */
45
+ async save(config) {
46
+ try {
47
+ await fs.mkdir(this.configDir, { recursive: true, mode: 448 });
48
+ await fs.writeFile(this.configPath, JSON.stringify(config, null, 2), {
49
+ mode: 384
50
+ });
51
+ } catch (error) {
52
+ throw new Error(
53
+ `Failed to save config: ${error instanceof Error ? error.message : String(error)}`
54
+ );
55
+ }
56
+ }
57
+ /**
58
+ * Get config file path
59
+ */
60
+ getConfigPath() {
61
+ return this.configPath;
62
+ }
63
+ /**
64
+ * Get config directory path
65
+ */
66
+ getConfigDir() {
67
+ return this.configDir;
68
+ }
69
+ };
4
70
 
5
71
  // src/services/settings.service.ts
6
- import { promises as fs, existsSync } from "fs";
7
- import { join } from "path";
72
+ import { promises as fs2, existsSync, readFileSync } from "fs";
73
+ import { join as join2 } from "path";
8
74
  import { execSync } from "child_process";
9
75
  import { createHash } from "crypto";
10
76
  import YAML from "yaml";
@@ -36,7 +102,7 @@ var SettingsService = class {
36
102
  cache = null;
37
103
  constructor(cwd) {
38
104
  this.cwd = cwd || process.cwd();
39
- this.settingsPath = join(this.cwd, SETTINGS_FILE);
105
+ this.settingsPath = join2(this.cwd, SETTINGS_FILE);
40
106
  }
41
107
  // ============================================
42
108
  // READ
@@ -58,7 +124,7 @@ var SettingsService = class {
58
124
  return this.cache;
59
125
  }
60
126
  try {
61
- const content = __require("fs").readFileSync(this.settingsPath, "utf-8");
127
+ const content = readFileSync(this.settingsPath, "utf-8");
62
128
  const raw = YAML.parse(content) || {};
63
129
  this.cache = ProjectSettingsSchema.parse(raw);
64
130
  return this.cache;
@@ -92,13 +158,13 @@ var SettingsService = class {
92
158
  * Creates .jai1 directory if it doesn't exist
93
159
  */
94
160
  async save(settings) {
95
- const dir = join(this.cwd, ".jai1");
96
- await fs.mkdir(dir, { recursive: true });
161
+ const dir = join2(this.cwd, ".jai1");
162
+ await fs2.mkdir(dir, { recursive: true });
97
163
  const content = YAML.stringify(settings, {
98
164
  indent: 2,
99
165
  lineWidth: 0
100
166
  });
101
- await fs.writeFile(this.settingsPath, content, "utf-8");
167
+ await fs2.writeFile(this.settingsPath, content, "utf-8");
102
168
  this.cache = settings;
103
169
  }
104
170
  /**
@@ -152,8 +218,8 @@ var SettingsService = class {
152
218
  return this.load().tasks;
153
219
  }
154
220
  /**
155
- * Get or derive projectId from git remote URL
156
- * Caches in settings.yaml after first derive
221
+ * Get or derive projectId from git remote URL.
222
+ * Synchronously derives if not cached; use getOrCreateProjectId() to also persist.
157
223
  */
158
224
  getProjectId() {
159
225
  const settings = this.load();
@@ -163,10 +229,14 @@ var SettingsService = class {
163
229
  const repoUrl = this.resolveGitRepoUrl();
164
230
  if (!repoUrl) return null;
165
231
  const projectId = this.deriveProjectId(repoUrl);
232
+ settings.tasks.projectId = projectId;
233
+ this.cache = settings;
234
+ this.save(settings).catch(() => {
235
+ });
166
236
  return projectId;
167
237
  }
168
238
  /**
169
- * Get and cache projectId (writes to settings.yaml)
239
+ * Get and cache projectId (writes to settings.yaml, awaitable)
170
240
  */
171
241
  async getOrCreateProjectId() {
172
242
  const settings = this.load();
@@ -242,6 +312,7 @@ var SettingsService = class {
242
312
  };
243
313
 
244
314
  export {
315
+ ConfigService,
245
316
  SettingsService
246
317
  };
247
- //# sourceMappingURL=chunk-Z464RBPB.js.map
318
+ //# sourceMappingURL=chunk-OJYJGHQX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/services/config.service.ts","../src/services/settings.service.ts","../src/types/settings.types.ts"],"sourcesContent":["import { promises as fs } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport type { Jai1Config } from '../types/framework.types.js';\n\n/**\n * Service for managing Jai1 global configuration\n * Config stored in ~/.jai1/config.json\n */\nexport class ConfigService {\n private readonly configDir: string;\n private readonly configPath: string;\n\n constructor() {\n this.configDir = join(homedir(), '.jai1');\n this.configPath = join(this.configDir, 'config.json');\n }\n\n /**\n * Check if config file exists\n */\n async exists(): Promise<boolean> {\n try {\n await fs.access(this.configPath);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Load configuration from file\n * @returns Config object or null if not found\n */\n async load(): Promise<Jai1Config | null> {\n if (!(await this.exists())) {\n return null;\n }\n\n try {\n const content = await fs.readFile(this.configPath, 'utf-8');\n return JSON.parse(content) as Jai1Config;\n } catch (error) {\n throw new Error(\n `Failed to load config: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * Save configuration to file\n * Creates directory if it doesn't exist\n * Sets proper file permissions (600)\n */\n async save(config: Jai1Config): Promise<void> {\n try {\n // Ensure directory exists with restricted permissions\n await fs.mkdir(this.configDir, { recursive: true, mode: 0o700 });\n\n // Write config with restricted permissions\n await fs.writeFile(this.configPath, JSON.stringify(config, null, 2), {\n mode: 0o600,\n });\n } catch (error) {\n throw new Error(\n `Failed to save config: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * Get config file path\n */\n getConfigPath(): string {\n return this.configPath;\n }\n\n /**\n * Get config directory path\n */\n getConfigDir(): string {\n return this.configDir;\n }\n}\n","/**\n * Settings Service\n * Read/write .jai1/settings.yaml\n */\nimport { promises as fs, existsSync, readFileSync } from 'fs';\nimport { join } from 'path';\nimport { execSync } from 'child_process';\nimport { createHash } from 'crypto';\nimport YAML from 'yaml';\nimport {\n ProjectSettingsSchema,\n type ProjectSettings,\n type TaskSettings,\n DEFAULT_SETTINGS,\n} from '../types/settings.types.js';\n\nconst SETTINGS_FILE = '.jai1/settings.yaml';\n\nexport class SettingsService {\n private readonly settingsPath: string;\n private readonly cwd: string;\n private cache: ProjectSettings | null = null;\n\n constructor(cwd?: string) {\n this.cwd = cwd || process.cwd();\n this.settingsPath = join(this.cwd, SETTINGS_FILE);\n }\n\n // ============================================\n // READ\n // ============================================\n\n /**\n * Check if settings file exists\n */\n exists(): boolean {\n return existsSync(this.settingsPath);\n }\n\n /**\n * Load and validate settings from YAML file\n * Returns defaults if file doesn't exist\n */\n load(): ProjectSettings {\n if (this.cache) return this.cache;\n\n if (!this.exists()) {\n this.cache = { ...DEFAULT_SETTINGS };\n return this.cache;\n }\n\n try {\n const content = readFileSync(this.settingsPath, 'utf-8');\n const raw = YAML.parse(content) || {};\n this.cache = ProjectSettingsSchema.parse(raw);\n return this.cache;\n } catch (error) {\n throw new Error(\n `Failed to load settings: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * Get a setting value by dot-notation key\n * e.g., get('tasks.cloud') → true\n */\n get(key: string): unknown {\n const settings = this.load();\n const parts = key.split('.');\n let current: unknown = settings;\n\n for (const part of parts) {\n if (current === null || current === undefined || typeof current !== 'object') {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n\n return current;\n }\n\n // ============================================\n // WRITE\n // ============================================\n\n /**\n * Save settings to YAML file\n * Creates .jai1 directory if it doesn't exist\n */\n async save(settings: ProjectSettings): Promise<void> {\n const dir = join(this.cwd, '.jai1');\n await fs.mkdir(dir, { recursive: true });\n\n const content = YAML.stringify(settings, {\n indent: 2,\n lineWidth: 0,\n });\n\n await fs.writeFile(this.settingsPath, content, 'utf-8');\n this.cache = settings;\n }\n\n /**\n * Set a single setting value by dot-notation key\n * e.g., set('tasks.cloud', true)\n */\n async set(key: string, value: unknown): Promise<ProjectSettings> {\n const settings = this.load();\n const parts = key.split('.');\n let current: Record<string, unknown> = settings as unknown as Record<string, unknown>;\n\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i]!;\n if (typeof current[part] !== 'object' || current[part] === null) {\n current[part] = {};\n }\n current = current[part] as Record<string, unknown>;\n }\n\n const lastKey = parts[parts.length - 1]!;\n\n // Auto-convert string values to proper types\n if (value === 'true') value = true;\n else if (value === 'false') value = false;\n else if (typeof value === 'string' && /^\\d+$/.test(value)) value = parseInt(value, 10);\n\n current[lastKey] = value;\n\n // Validate the entire settings object\n const validated = ProjectSettingsSchema.parse(settings);\n await this.save(validated);\n return validated;\n }\n\n /**\n * Initialize settings file with defaults\n */\n async init(force: boolean = false): Promise<ProjectSettings> {\n if (this.exists() && !force) {\n throw new Error('Settings file already exists. Use --force to overwrite.');\n }\n\n await this.save(DEFAULT_SETTINGS);\n return DEFAULT_SETTINGS;\n }\n\n // ============================================\n // SHORTCUTS\n // ============================================\n\n /**\n * Check if task cloud mode is enabled\n */\n isTaskCloudEnabled(): boolean {\n const settings = this.load();\n return settings.tasks.cloud === true;\n }\n\n /**\n * Get task settings\n */\n getTaskSettings(): TaskSettings {\n return this.load().tasks;\n }\n\n /**\n * Get or derive projectId from git remote URL.\n * Synchronously derives if not cached; use getOrCreateProjectId() to also persist.\n */\n getProjectId(): string | null {\n const settings = this.load();\n if (settings.tasks.projectId) {\n return settings.tasks.projectId;\n }\n\n // Try to derive from git remote\n const repoUrl = this.resolveGitRepoUrl();\n if (!repoUrl) return null;\n\n const projectId = this.deriveProjectId(repoUrl);\n\n // Cache in-memory so subsequent calls don't re-derive\n settings.tasks.projectId = projectId;\n this.cache = settings;\n\n // Fire-and-forget persist to settings.yaml (don't block sync callers)\n this.save(settings).catch(() => {});\n return projectId;\n }\n\n /**\n * Get and cache projectId (writes to settings.yaml, awaitable)\n */\n async getOrCreateProjectId(): Promise<string | null> {\n const settings = this.load();\n if (settings.tasks.projectId) {\n return settings.tasks.projectId;\n }\n\n const repoUrl = this.resolveGitRepoUrl();\n if (!repoUrl) return null;\n\n const projectId = this.deriveProjectId(repoUrl);\n await this.set('tasks.projectId', projectId);\n return projectId;\n }\n\n // ============================================\n // GIT HELPERS\n // ============================================\n\n /**\n * Resolve git remote URL from current repo\n * Returns normalized URL (strip .git, credentials)\n */\n resolveGitRepoUrl(): string | null {\n try {\n const raw = execSync('git remote get-url origin', {\n cwd: this.cwd,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n return this.normalizeRepoUrl(raw);\n } catch {\n return null;\n }\n }\n\n /**\n * Normalize git repo URL to consistent format\n * git@github.com:org/repo.git → github.com/org/repo\n * https://github.com/org/repo.git → github.com/org/repo\n */\n private normalizeRepoUrl(url: string): string {\n let normalized = url;\n\n // SSH format: git@github.com:org/repo.git\n const sshMatch = normalized.match(/^(?:git@|ssh:\\/\\/(?:[^@]+@)?)([^:\\/]+)[:/](.+?)(?:\\.git)?$/);\n if (sshMatch) {\n return `${sshMatch[1]}/${sshMatch[2]}`;\n }\n\n // HTTPS format: https://github.com/org/repo.git\n const httpsMatch = normalized.match(/^https?:\\/\\/(?:[^@]+@)?([^/]+)\\/(.+?)(?:\\.git)?$/);\n if (httpsMatch) {\n return `${httpsMatch[1]}/${httpsMatch[2]}`;\n }\n\n return normalized;\n }\n\n /**\n * Derive projectId from normalized repo URL\n * → SHA256 hash (12 chars) + slug\n */\n private deriveProjectId(repoUrl: string): string {\n const hash = createHash('sha256').update(repoUrl).digest('hex').substring(0, 12);\n const slug = repoUrl\n .replace(/[^a-zA-Z0-9]+/g, '-')\n .replace(/^-|-$/g, '')\n .toLowerCase();\n return `${hash}-${slug}`;\n }\n\n // ============================================\n // UTILITY\n // ============================================\n\n /**\n * Get settings file path\n */\n getSettingsPath(): string {\n return this.settingsPath;\n }\n\n /**\n * Clear cache (for testing or after external updates)\n */\n clearCache(): void {\n this.cache = null;\n }\n}\n","/**\n * Project Settings Types\n * Schema for .jai1/settings.yaml\n */\nimport { z } from 'zod';\n\n// ============================================\n// SETTINGS SCHEMA\n// ============================================\n\nexport const TaskSettingsSchema = z.object({\n cloud: z.boolean().default(false),\n projectId: z.string().optional(), // auto-derived from git remote URL\n});\n\nexport type TaskSettings = z.infer<typeof TaskSettingsSchema>;\n\nexport const ProjectSettingsSchema = z.object({\n tasks: TaskSettingsSchema.default({}),\n // Future extensions:\n // notifications: z.object({...}).default({}),\n // integrations: z.object({...}).default({}),\n});\n\nexport type ProjectSettings = z.infer<typeof ProjectSettingsSchema>;\n\n// ============================================\n// DEFAULT VALUES\n// ============================================\n\nexport const DEFAULT_SETTINGS: ProjectSettings = {\n tasks: {\n cloud: false,\n },\n};\n\n// ============================================\n// CLI OPTION TYPES\n// ============================================\n\nexport interface SettingsSetOptions {\n json?: boolean;\n}\n\nexport interface SettingsGetOptions {\n json?: boolean;\n}\n\nexport interface SettingsShowOptions {\n json?: boolean;\n}\n\nexport interface SettingsInitOptions {\n force?: boolean;\n cloud?: boolean;\n interactive?: boolean; // --no-interactive sets to false\n json?: boolean;\n}\n"],"mappings":"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","names":["fs","join","join","fs"]}