@fitlab-ai/agent-infra 0.7.0 → 0.7.2
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/bin/cli.ts +12 -1
- package/dist/bin/cli.js +13 -1
- package/dist/lib/builtin-tuis.js +45 -0
- package/dist/lib/defaults.json +3 -0
- package/dist/lib/init.js +62 -23
- package/dist/lib/prompt.js +49 -1
- package/dist/lib/sandbox/commands/create.js +10 -2
- package/dist/lib/sandbox/commands/enter.js +8 -7
- package/dist/lib/sandbox/commands/list-running.js +62 -28
- package/dist/lib/sandbox/commands/ls.js +20 -22
- package/dist/lib/sandbox/commands/rebuild.js +3 -11
- package/dist/lib/sandbox/commands/rm.js +2 -0
- package/dist/lib/sandbox/image-prune.js +18 -0
- package/dist/lib/sandbox/index.js +7 -3
- package/dist/lib/sandbox/task-resolver.js +18 -0
- package/dist/lib/sandbox/tools.js +1 -1
- package/dist/lib/table.js +29 -0
- package/dist/lib/task/commands/ls.js +122 -0
- package/dist/lib/task/commands/show.js +135 -0
- package/dist/lib/task/frontmatter.js +32 -0
- package/dist/lib/task/index.js +41 -0
- package/dist/lib/task/short-id.js +80 -0
- package/dist/lib/update.js +59 -18
- package/lib/builtin-tuis.ts +55 -0
- package/lib/defaults.json +3 -0
- package/lib/init.ts +87 -35
- package/lib/prompt.ts +54 -1
- package/lib/sandbox/commands/create.ts +11 -2
- package/lib/sandbox/commands/enter.ts +8 -7
- package/lib/sandbox/commands/list-running.ts +70 -31
- package/lib/sandbox/commands/ls.ts +25 -25
- package/lib/sandbox/commands/rebuild.ts +3 -12
- package/lib/sandbox/commands/rm.ts +3 -0
- package/lib/sandbox/image-prune.ts +23 -0
- package/lib/sandbox/index.ts +7 -3
- package/lib/sandbox/task-resolver.ts +23 -1
- package/lib/sandbox/tools.ts +1 -1
- package/lib/table.ts +32 -0
- package/lib/task/commands/ls.ts +138 -0
- package/lib/task/commands/show.ts +139 -0
- package/lib/task/frontmatter.ts +30 -0
- package/lib/task/index.ts +44 -0
- package/lib/task/short-id.ts +97 -0
- package/lib/update.ts +71 -30
- package/package.json +1 -1
- package/templates/.agents/README.en.md +32 -0
- package/templates/.agents/README.zh-CN.md +32 -0
- package/templates/.agents/hooks/auto-resume.sh +87 -0
- package/templates/.agents/rules/create-issue.github.en.md +1 -1
- package/templates/.agents/rules/create-issue.github.zh-CN.md +1 -1
- package/templates/.agents/rules/milestone-inference.github.en.md +4 -1
- package/templates/.agents/rules/milestone-inference.github.zh-CN.md +4 -1
- package/templates/.agents/rules/next-step-output.en.md +59 -0
- package/templates/.agents/rules/next-step-output.zh-CN.md +59 -0
- package/templates/.agents/rules/task-short-id.en.md +133 -0
- package/templates/.agents/rules/task-short-id.zh-CN.md +105 -0
- package/templates/.agents/scripts/platform-adapters/platform-sync.github.js +17 -0
- package/templates/.agents/scripts/task-short-id.js +556 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +13 -11
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +13 -12
- package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -1
- package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/block-task/SKILL.en.md +17 -5
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +17 -6
- package/templates/.agents/skills/block-task/config/verify.json +1 -1
- package/templates/.agents/skills/cancel-task/SKILL.en.md +17 -5
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +17 -6
- package/templates/.agents/skills/cancel-task/config/verify.json +1 -1
- package/templates/.agents/skills/check-task/SKILL.en.md +15 -9
- package/templates/.agents/skills/check-task/SKILL.zh-CN.md +15 -10
- package/templates/.agents/skills/close-codescan/SKILL.en.md +16 -5
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +16 -5
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +16 -5
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +16 -5
- package/templates/.agents/skills/code-task/SKILL.en.md +13 -5
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +14 -6
- package/templates/.agents/skills/code-task/config/verify.en.json +2 -1
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +2 -1
- package/templates/.agents/skills/code-task/reference/fix-mode.en.md +10 -5
- package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +10 -5
- package/templates/.agents/skills/code-task/reference/output-template.en.md +3 -3
- package/templates/.agents/skills/code-task/reference/output-template.zh-CN.md +3 -3
- package/templates/.agents/skills/code-task/reference/report-template.en.md +8 -0
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +8 -0
- package/templates/.agents/skills/commit/SKILL.en.md +5 -1
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/commit/reference/task-status-update.en.md +9 -9
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +9 -9
- package/templates/.agents/skills/complete-task/SKILL.en.md +17 -1
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +17 -2
- package/templates/.agents/skills/complete-task/config/verify.en.json +1 -1
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/create-pr/SKILL.en.md +9 -5
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +9 -5
- package/templates/.agents/skills/create-pr/config/verify.json +2 -1
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +1 -1
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +1 -1
- package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +3 -3
- package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +3 -3
- package/templates/.agents/skills/create-task/SKILL.en.md +29 -15
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +29 -16
- package/templates/.agents/skills/create-task/config/verify.json +1 -1
- package/templates/.agents/skills/import-codescan/SKILL.en.md +20 -6
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +20 -6
- package/templates/.agents/skills/import-codescan/config/verify.json +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +20 -6
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +20 -6
- package/templates/.agents/skills/import-dependabot/config/verify.json +1 -1
- package/templates/.agents/skills/import-issue/SKILL.en.md +19 -5
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +19 -5
- package/templates/.agents/skills/plan-task/SKILL.en.md +13 -11
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +13 -12
- package/templates/.agents/skills/plan-task/config/verify.en.json +1 -1
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/restore-task/SKILL.en.md +12 -0
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +12 -1
- package/templates/.agents/skills/review-analysis/SKILL.en.md +7 -1
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +7 -2
- package/templates/.agents/skills/review-analysis/config/verify.en.json +3 -2
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +3 -2
- package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +15 -15
- package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +15 -15
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +7 -1
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +7 -1
- package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +2 -0
- package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +2 -0
- package/templates/.agents/skills/review-code/SKILL.en.md +8 -1
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +8 -2
- package/templates/.agents/skills/review-code/config/verify.en.json +3 -2
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +3 -2
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +9 -9
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +9 -9
- package/templates/.agents/skills/review-code/reference/report-template.en.md +7 -1
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +7 -1
- package/templates/.agents/skills/review-code/reference/review-criteria.en.md +2 -0
- package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +2 -0
- package/templates/.agents/skills/review-plan/SKILL.en.md +7 -1
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +7 -2
- package/templates/.agents/skills/review-plan/config/verify.en.json +3 -2
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +3 -2
- package/templates/.agents/skills/review-plan/reference/output-templates.en.md +15 -15
- package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +15 -15
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +7 -1
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +7 -1
- package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +2 -0
- package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +2 -0
- package/templates/.agents/skills/update-agent-infra/SKILL.en.md +1 -0
- package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +1 -0
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +112 -21
- package/templates/.agents/workflows/bug-fix.en.yaml +1 -1
- package/templates/.agents/workflows/bug-fix.zh-CN.yaml +1 -1
- package/templates/.agents/workflows/feature-development.en.yaml +1 -1
- package/templates/.agents/workflows/feature-development.zh-CN.yaml +1 -1
- package/templates/.agents/workflows/refactoring.en.yaml +1 -1
- package/templates/.agents/workflows/refactoring.zh-CN.yaml +1 -1
- package/templates/.claude/settings.json +11 -0
|
@@ -2,9 +2,13 @@ const USAGE = `Usage: ai sandbox <command> [options]
|
|
|
2
2
|
|
|
3
3
|
Commands:
|
|
4
4
|
create <branch> [base] Create a sandbox (VM + image + worktree + container)
|
|
5
|
-
exec <branch | '#N'> [cmd...]
|
|
6
|
-
Enter sandbox or run a command (
|
|
7
|
-
|
|
5
|
+
exec <branch | TASK-id | N | '#N'> [cmd...]
|
|
6
|
+
Enter sandbox or run a command. N (bare) is the
|
|
7
|
+
recommended form for task short ids (e.g.
|
|
8
|
+
'ai sandbox exec 11'); '#N' is also accepted.
|
|
9
|
+
ls List sandboxes for the current project (the '#'
|
|
10
|
+
column is a display-only row number; the 'SHORT'
|
|
11
|
+
column shows the active task short id, '-' if none)
|
|
8
12
|
prune [--dry-run] Remove orphaned per-branch state dirs
|
|
9
13
|
rebuild [--quiet] [--refresh]
|
|
10
14
|
Rebuild the sandbox image (--refresh pulls base + tools)
|
|
@@ -1,7 +1,20 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
1
2
|
import fs from 'node:fs';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
const TASK_ID_RE = /^TASK-\d{8}-\d{6}$/;
|
|
5
|
+
const SHORT_ID_RE = /^#?\d+$/;
|
|
4
6
|
const WORKSPACE_DIRS = ['active', 'completed', 'blocked', 'archive'];
|
|
7
|
+
function resolveShortIdStrict(arg, repoRoot) {
|
|
8
|
+
const scriptPath = path.join(repoRoot, '.agents', 'scripts', 'task-short-id.js');
|
|
9
|
+
if (!fs.existsSync(scriptPath)) {
|
|
10
|
+
throw new Error(`Short id '${arg}' provided but task-short-id.js script is missing at ${scriptPath}`);
|
|
11
|
+
}
|
|
12
|
+
const result = spawnSync('node', [scriptPath, 'resolve', arg], { encoding: 'utf8', cwd: repoRoot });
|
|
13
|
+
if (result.status !== 0) {
|
|
14
|
+
throw new Error(`Short id '${arg}' not found in active task registry: ${(result.stderr || '').trim()}`);
|
|
15
|
+
}
|
|
16
|
+
return result.stdout.trim();
|
|
17
|
+
}
|
|
5
18
|
function stripQuotes(value) {
|
|
6
19
|
return value.replace(/^(["'])(.*)\1$/, '$2');
|
|
7
20
|
}
|
|
@@ -26,6 +39,11 @@ function resolveBranchFromTaskContent(content, taskId) {
|
|
|
26
39
|
throw new Error(`Task ${taskId} has no branch field in task.md`);
|
|
27
40
|
}
|
|
28
41
|
export function resolveTaskBranch(arg, repoRoot) {
|
|
42
|
+
if (SHORT_ID_RE.test(arg)) {
|
|
43
|
+
const taskId = resolveShortIdStrict(arg, repoRoot);
|
|
44
|
+
const content = readTaskContent(repoRoot, taskId);
|
|
45
|
+
return resolveBranchFromTaskContent(content, taskId);
|
|
46
|
+
}
|
|
29
47
|
if (!TASK_ID_RE.test(arg)) {
|
|
30
48
|
return arg;
|
|
31
49
|
}
|
|
@@ -6,7 +6,7 @@ function createBuiltinTools(home, project) {
|
|
|
6
6
|
'claude-code': {
|
|
7
7
|
id: 'claude-code',
|
|
8
8
|
name: 'Claude Code',
|
|
9
|
-
install: { type: 'npm', cmd: '@anthropic-ai/claude-code@
|
|
9
|
+
install: { type: 'npm', cmd: '@anthropic-ai/claude-code@latest' },
|
|
10
10
|
sandboxBase: hostJoin(home, '.agent-infra', 'sandboxes', 'claude-code'),
|
|
11
11
|
containerMount: '/home/devuser/.claude',
|
|
12
12
|
versionCmd: 'claude --version',
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
function formatTable(headers, rows) {
|
|
2
|
+
const columnCount = headers.length;
|
|
3
|
+
const widths = headers.map((header, i) => {
|
|
4
|
+
const headerLen = header.length;
|
|
5
|
+
let max = headerLen;
|
|
6
|
+
for (const row of rows) {
|
|
7
|
+
const cell = row[i] ?? '';
|
|
8
|
+
if (cell.length > max)
|
|
9
|
+
max = cell.length;
|
|
10
|
+
}
|
|
11
|
+
return max;
|
|
12
|
+
});
|
|
13
|
+
const renderRow = (values) => {
|
|
14
|
+
const parts = [];
|
|
15
|
+
for (let i = 0; i < columnCount; i += 1) {
|
|
16
|
+
const cell = values[i] ?? '';
|
|
17
|
+
if (i === columnCount - 1) {
|
|
18
|
+
parts.push(cell);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
parts.push(cell.padEnd(widths[i]));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return parts.join(' ').trimEnd();
|
|
25
|
+
};
|
|
26
|
+
return [renderRow(headers), ...rows.map((row) => renderRow(row))];
|
|
27
|
+
}
|
|
28
|
+
export { formatTable };
|
|
29
|
+
//# sourceMappingURL=table.js.map
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { execFileSync } from 'node:child_process';
|
|
4
|
+
import { formatTable } from "../../table.js";
|
|
5
|
+
import { parseTaskFrontmatter, extractTitle } from "../frontmatter.js";
|
|
6
|
+
import { loadShortIdByTaskId } from "../short-id.js";
|
|
7
|
+
const USAGE = `Usage: ai task ls [--all | --blocked | --completed]
|
|
8
|
+
|
|
9
|
+
Lists tasks under .agents/workspace/. Defaults to active tasks only.
|
|
10
|
+
--all Include active + blocked + completed (excludes archive)
|
|
11
|
+
--blocked Only blocked tasks
|
|
12
|
+
--completed Only completed tasks
|
|
13
|
+
|
|
14
|
+
Columns: # (display-only row number) / SHORT (task short id, usable as an argument) / type / status / current_step / branch / title
|
|
15
|
+
`;
|
|
16
|
+
const TASK_ID_RE = /^TASK-\d{8}-\d{6}$/;
|
|
17
|
+
const TABLE_HEADERS = ['#', 'SHORT', 'TYPE', 'STATUS', 'STEP', 'BRANCH', 'TITLE'];
|
|
18
|
+
function detectRepoRoot() {
|
|
19
|
+
try {
|
|
20
|
+
return execFileSync('git', ['rev-parse', '--show-toplevel'], {
|
|
21
|
+
encoding: 'utf8',
|
|
22
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
23
|
+
}).trim();
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
throw new Error('ai task: current directory is not inside a git repository');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function parseSelection(args) {
|
|
30
|
+
const positional = args.filter((a) => !a.startsWith('--'));
|
|
31
|
+
if (positional.length > 0) {
|
|
32
|
+
return {
|
|
33
|
+
ok: false,
|
|
34
|
+
message: `ai task ls: unexpected positional argument(s): ${positional.join(' ')}`
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const flags = args.filter((a) => a.startsWith('--'));
|
|
38
|
+
if (flags.length === 0)
|
|
39
|
+
return { ok: true, selection: ['active'] };
|
|
40
|
+
if (flags.length > 1) {
|
|
41
|
+
return {
|
|
42
|
+
ok: false,
|
|
43
|
+
message: 'ai task ls: pass at most one of --all / --blocked / --completed'
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
switch (flags[0]) {
|
|
47
|
+
case '--all':
|
|
48
|
+
return { ok: true, selection: ['active', 'blocked', 'completed'] };
|
|
49
|
+
case '--blocked':
|
|
50
|
+
return { ok: true, selection: ['blocked'] };
|
|
51
|
+
case '--completed':
|
|
52
|
+
return { ok: true, selection: ['completed'] };
|
|
53
|
+
default:
|
|
54
|
+
return { ok: false, message: `ai task ls: unknown flag: ${flags[0]}` };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function collectTasks(repoRoot, state) {
|
|
58
|
+
const dir = path.join(repoRoot, '.agents', 'workspace', state);
|
|
59
|
+
if (!fs.existsSync(dir))
|
|
60
|
+
return [];
|
|
61
|
+
// Short ids live only in the registry and only for active tasks; archived
|
|
62
|
+
// (blocked/completed) tasks have released their short id and render '-'.
|
|
63
|
+
const shortIdByTaskId = state === 'active' ? loadShortIdByTaskId(repoRoot) : new Map();
|
|
64
|
+
const rows = [];
|
|
65
|
+
for (const entry of fs.readdirSync(dir).sort()) {
|
|
66
|
+
if (!TASK_ID_RE.test(entry))
|
|
67
|
+
continue;
|
|
68
|
+
const taskMdPath = path.join(dir, entry, 'task.md');
|
|
69
|
+
if (!fs.existsSync(taskMdPath))
|
|
70
|
+
continue;
|
|
71
|
+
const content = fs.readFileSync(taskMdPath, 'utf8');
|
|
72
|
+
const fm = parseTaskFrontmatter(content);
|
|
73
|
+
const title = extractTitle(content);
|
|
74
|
+
const shortId = shortIdByTaskId.get(entry) ?? '-';
|
|
75
|
+
rows.push({
|
|
76
|
+
shortId,
|
|
77
|
+
type: fm.type ?? '-',
|
|
78
|
+
status: fm.status ?? state,
|
|
79
|
+
step: fm.current_step ?? '-',
|
|
80
|
+
branch: fm.branch ?? '-',
|
|
81
|
+
title: title || fm.id || entry
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return rows;
|
|
85
|
+
}
|
|
86
|
+
function ls(args = []) {
|
|
87
|
+
if (args[0] === '--help' || args[0] === '-h') {
|
|
88
|
+
process.stdout.write(USAGE);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const result = parseSelection(args);
|
|
92
|
+
if (!result.ok) {
|
|
93
|
+
process.stderr.write(`${result.message}\n`);
|
|
94
|
+
process.exitCode = 1;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const { selection } = result;
|
|
98
|
+
const repoRoot = detectRepoRoot();
|
|
99
|
+
const rows = [];
|
|
100
|
+
for (const state of selection) {
|
|
101
|
+
rows.push(...collectTasks(repoRoot, state));
|
|
102
|
+
}
|
|
103
|
+
if (rows.length === 0) {
|
|
104
|
+
process.stdout.write(`No tasks under .agents/workspace/${selection.join('|')}\n`);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const tableRows = rows.map((r, i) => [
|
|
108
|
+
String(i + 1),
|
|
109
|
+
r.shortId,
|
|
110
|
+
r.type,
|
|
111
|
+
r.status,
|
|
112
|
+
r.step,
|
|
113
|
+
r.branch,
|
|
114
|
+
r.title
|
|
115
|
+
]);
|
|
116
|
+
for (const line of formatTable(TABLE_HEADERS, tableRows)) {
|
|
117
|
+
process.stdout.write(`${line}\n`);
|
|
118
|
+
}
|
|
119
|
+
process.stdout.write(`Total: ${rows.length} tasks\n`);
|
|
120
|
+
}
|
|
121
|
+
export { ls };
|
|
122
|
+
//# sourceMappingURL=ls.js.map
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { execFileSync, spawnSync } from 'node:child_process';
|
|
4
|
+
import { normalizeShortIdInput } from "../short-id.js";
|
|
5
|
+
const USAGE = `Usage: ai task show <N | #N | TASK-id>
|
|
6
|
+
|
|
7
|
+
Prints the task.md content for the matching task.
|
|
8
|
+
N (bare numeric) Recommended; resolves the active short id via the registry.
|
|
9
|
+
'#N' Compatibility form for old commands.
|
|
10
|
+
TASK-YYYYMMDD-HHMMSS Locates a task in active / blocked / completed / archive.
|
|
11
|
+
`;
|
|
12
|
+
const TASK_ID_RE = /^TASK-\d{8}-\d{6}$/;
|
|
13
|
+
// Flat-structured workspace dirs that hold tasks under `{dir}/{taskId}/task.md`.
|
|
14
|
+
// Note: `archive` uses a three-level YYYY/MM/DD layout and is handled separately.
|
|
15
|
+
const FLAT_WORKSPACE_DIRS = ['active', 'blocked', 'completed'];
|
|
16
|
+
function detectRepoRoot() {
|
|
17
|
+
try {
|
|
18
|
+
return execFileSync('git', ['rev-parse', '--show-toplevel'], {
|
|
19
|
+
encoding: 'utf8',
|
|
20
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
21
|
+
}).trim();
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
throw new Error('ai task: current directory is not inside a git repository');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function readShortIdLength(repoRoot) {
|
|
28
|
+
try {
|
|
29
|
+
const cfg = JSON.parse(fs.readFileSync(path.join(repoRoot, '.agents', '.airc.json'), 'utf8'));
|
|
30
|
+
const v = cfg?.task?.shortIdLength;
|
|
31
|
+
if (typeof v === 'number' && Number.isFinite(v) && v >= 1)
|
|
32
|
+
return v;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// fall through to default
|
|
36
|
+
}
|
|
37
|
+
return 2;
|
|
38
|
+
}
|
|
39
|
+
function resolveShortIdToTaskId(arg, repoRoot) {
|
|
40
|
+
const scriptPath = path.join(repoRoot, '.agents', 'scripts', 'task-short-id.js');
|
|
41
|
+
if (!fs.existsSync(scriptPath)) {
|
|
42
|
+
throw new Error(`task-short-id.js not found at ${scriptPath}`);
|
|
43
|
+
}
|
|
44
|
+
const result = spawnSync('node', [scriptPath, 'resolve', arg], {
|
|
45
|
+
encoding: 'utf8',
|
|
46
|
+
cwd: repoRoot
|
|
47
|
+
});
|
|
48
|
+
if (result.status !== 0) {
|
|
49
|
+
throw new Error((result.stderr || '').trim() || `failed to resolve '${arg}'`);
|
|
50
|
+
}
|
|
51
|
+
return result.stdout.trim();
|
|
52
|
+
}
|
|
53
|
+
function listSortedNumeric(dir, width) {
|
|
54
|
+
if (!fs.existsSync(dir))
|
|
55
|
+
return [];
|
|
56
|
+
const pattern = new RegExp(`^\\d{${width}}$`);
|
|
57
|
+
return fs
|
|
58
|
+
.readdirSync(dir)
|
|
59
|
+
.filter((entry) => pattern.test(entry))
|
|
60
|
+
.sort()
|
|
61
|
+
.reverse();
|
|
62
|
+
}
|
|
63
|
+
function findInArchive(repoRoot, taskId) {
|
|
64
|
+
// archive-tasks SKILL writes to .agents/workspace/archive/YYYY/MM/DD/{taskId}/task.md
|
|
65
|
+
// where YYYY/MM/DD comes from completed_at (or updated_at fallback) — NOT from
|
|
66
|
+
// the task id's creation date. So we cannot derive the path from taskId alone;
|
|
67
|
+
// walk the bounded YYYY/MM/DD tree instead. Newest-first to favor recent archives.
|
|
68
|
+
const archiveDir = path.join(repoRoot, '.agents', 'workspace', 'archive');
|
|
69
|
+
for (const year of listSortedNumeric(archiveDir, 4)) {
|
|
70
|
+
const yearDir = path.join(archiveDir, year);
|
|
71
|
+
for (const month of listSortedNumeric(yearDir, 2)) {
|
|
72
|
+
const monthDir = path.join(yearDir, month);
|
|
73
|
+
for (const day of listSortedNumeric(monthDir, 2)) {
|
|
74
|
+
const candidate = path.join(monthDir, day, taskId, 'task.md');
|
|
75
|
+
if (fs.existsSync(candidate))
|
|
76
|
+
return candidate;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
function findTaskMd(repoRoot, taskId) {
|
|
83
|
+
for (const sub of FLAT_WORKSPACE_DIRS) {
|
|
84
|
+
const candidate = path.join(repoRoot, '.agents', 'workspace', sub, taskId, 'task.md');
|
|
85
|
+
if (fs.existsSync(candidate))
|
|
86
|
+
return candidate;
|
|
87
|
+
}
|
|
88
|
+
return findInArchive(repoRoot, taskId);
|
|
89
|
+
}
|
|
90
|
+
function show(args = []) {
|
|
91
|
+
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
92
|
+
process.stdout.write(USAGE);
|
|
93
|
+
if (args.length === 0)
|
|
94
|
+
process.exitCode = 1;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const repoRoot = detectRepoRoot();
|
|
98
|
+
const arg = args[0];
|
|
99
|
+
let taskId;
|
|
100
|
+
if (TASK_ID_RE.test(arg)) {
|
|
101
|
+
taskId = arg;
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
const shortIdLength = readShortIdLength(repoRoot);
|
|
105
|
+
const normalized = normalizeShortIdInput(arg, { shortIdLength });
|
|
106
|
+
if (normalized.kind === 'error') {
|
|
107
|
+
process.stderr.write(`ai task show: ${normalized.message}\n`);
|
|
108
|
+
process.exitCode = 1;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (normalized.kind === 'pass') {
|
|
112
|
+
process.stderr.write(`ai task show: '${arg}' is not a valid short id or TASK-id; ` +
|
|
113
|
+
`expected bare digits, '#N', or 'TASK-YYYYMMDD-HHMMSS'\n`);
|
|
114
|
+
process.exitCode = 1;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
taskId = resolveShortIdToTaskId(normalized.value, repoRoot);
|
|
119
|
+
}
|
|
120
|
+
catch (e) {
|
|
121
|
+
process.stderr.write(`ai task show: ${e.message}\n`);
|
|
122
|
+
process.exitCode = 1;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const taskMdPath = findTaskMd(repoRoot, taskId);
|
|
127
|
+
if (!taskMdPath) {
|
|
128
|
+
process.stderr.write(`ai task show: task ${taskId} not found in active / blocked / completed / archive\n`);
|
|
129
|
+
process.exitCode = 1;
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
process.stdout.write(fs.readFileSync(taskMdPath, 'utf8'));
|
|
133
|
+
}
|
|
134
|
+
export { show };
|
|
135
|
+
//# sourceMappingURL=show.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
function parseTaskFrontmatter(content) {
|
|
2
|
+
const result = {};
|
|
3
|
+
if (!content.startsWith('---'))
|
|
4
|
+
return result;
|
|
5
|
+
const end = content.indexOf('\n---', 3);
|
|
6
|
+
if (end === -1)
|
|
7
|
+
return result;
|
|
8
|
+
const body = content.slice(3, end);
|
|
9
|
+
for (const rawLine of body.split('\n')) {
|
|
10
|
+
const line = rawLine.replace(/\r$/, '');
|
|
11
|
+
if (!line.trim())
|
|
12
|
+
continue;
|
|
13
|
+
const colon = line.indexOf(':');
|
|
14
|
+
if (colon === -1)
|
|
15
|
+
continue;
|
|
16
|
+
const key = line.slice(0, colon).trim();
|
|
17
|
+
const value = line.slice(colon + 1).trim();
|
|
18
|
+
if (key)
|
|
19
|
+
result[key] = value;
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
function extractTitle(content) {
|
|
24
|
+
for (const line of content.split('\n')) {
|
|
25
|
+
const m = /^#\s+(?:任务[::]?\s*)?(.+)$/.exec(line.trim());
|
|
26
|
+
if (m && m[1])
|
|
27
|
+
return m[1].trim();
|
|
28
|
+
}
|
|
29
|
+
return '';
|
|
30
|
+
}
|
|
31
|
+
export { parseTaskFrontmatter, extractTitle };
|
|
32
|
+
//# sourceMappingURL=frontmatter.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const USAGE = `Usage: ai task <command> [options]
|
|
2
|
+
|
|
3
|
+
Commands:
|
|
4
|
+
ls [--all | --blocked | --completed] List tasks (default: active)
|
|
5
|
+
show <N | #N | TASK-id> Print a task.md
|
|
6
|
+
|
|
7
|
+
Examples:
|
|
8
|
+
ai task ls
|
|
9
|
+
ai task show 11
|
|
10
|
+
ai task show TASK-20260612-162737
|
|
11
|
+
|
|
12
|
+
Run 'ai task <command> --help' for details.`;
|
|
13
|
+
export async function runTask(args) {
|
|
14
|
+
const [subcommand, ...rest] = args;
|
|
15
|
+
if (!subcommand) {
|
|
16
|
+
process.stdout.write(`${USAGE}\n`);
|
|
17
|
+
process.exitCode = 1;
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (subcommand === '--help' || subcommand === '-h' || subcommand === 'help') {
|
|
21
|
+
process.stdout.write(`${USAGE}\n`);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
switch (subcommand) {
|
|
25
|
+
case 'ls': {
|
|
26
|
+
const { ls } = await import("./commands/ls.js");
|
|
27
|
+
ls(rest);
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
case 'show': {
|
|
31
|
+
const { show } = await import("./commands/show.js");
|
|
32
|
+
show(rest);
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
default:
|
|
36
|
+
process.stderr.write(`Unknown task command: ${subcommand}\n\n`);
|
|
37
|
+
process.stdout.write(`${USAGE}\n`);
|
|
38
|
+
process.exitCode = 1;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const REGISTRY_NAME = '.short-ids.json';
|
|
4
|
+
function normalizeShortIdInput(input, opts) {
|
|
5
|
+
const L = opts.shortIdLength;
|
|
6
|
+
const m = /^#?(\d+)$/.exec(input);
|
|
7
|
+
if (!m) {
|
|
8
|
+
return { kind: 'pass', value: input };
|
|
9
|
+
}
|
|
10
|
+
const n = Number(m[1]);
|
|
11
|
+
if (n === 0) {
|
|
12
|
+
return {
|
|
13
|
+
kind: 'error',
|
|
14
|
+
message: `short id '${input}' is invalid (#${'0'.repeat(L)} is reserved)`
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
const max = Math.pow(10, L) - 1;
|
|
18
|
+
if (n > max) {
|
|
19
|
+
return {
|
|
20
|
+
kind: 'error',
|
|
21
|
+
message: `short id ${n} exceeds shortIdLength=${L} capacity (max=${max}); archive tasks or raise task.shortIdLength in .agents/.airc.json`
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return { kind: 'shortId', value: `#${String(n).padStart(L, '0')}` };
|
|
25
|
+
}
|
|
26
|
+
function readRegistry(repoRoot) {
|
|
27
|
+
const registryPath = path.join(repoRoot, '.agents', 'workspace', 'active', REGISTRY_NAME);
|
|
28
|
+
if (!fs.existsSync(registryPath))
|
|
29
|
+
return null;
|
|
30
|
+
try {
|
|
31
|
+
const raw = fs.readFileSync(registryPath, 'utf8');
|
|
32
|
+
const data = JSON.parse(raw);
|
|
33
|
+
if (!data || typeof data !== 'object' || !data.ids)
|
|
34
|
+
return null;
|
|
35
|
+
return data;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function readBranchFromTaskMd(repoRoot, taskId) {
|
|
42
|
+
const taskMdPath = path.join(repoRoot, '.agents', 'workspace', 'active', taskId, 'task.md');
|
|
43
|
+
if (!fs.existsSync(taskMdPath))
|
|
44
|
+
return null;
|
|
45
|
+
const content = fs.readFileSync(taskMdPath, 'utf8');
|
|
46
|
+
const m = content.match(/^branch:\s*(.+)$/m);
|
|
47
|
+
if (!m || !m[1])
|
|
48
|
+
return null;
|
|
49
|
+
return m[1].trim().replace(/^(["'])(.*)\1$/, '$2');
|
|
50
|
+
}
|
|
51
|
+
function loadShortIdByTaskId(repoRoot) {
|
|
52
|
+
const registry = readRegistry(repoRoot);
|
|
53
|
+
const map = new Map();
|
|
54
|
+
if (!registry)
|
|
55
|
+
return map;
|
|
56
|
+
for (const [key, taskId] of Object.entries(registry.ids)) {
|
|
57
|
+
map.set(taskId, `#${key}`);
|
|
58
|
+
}
|
|
59
|
+
return map;
|
|
60
|
+
}
|
|
61
|
+
function lookupShortIdByBranch(branch, repoRoot, _opts) {
|
|
62
|
+
const registry = readRegistry(repoRoot);
|
|
63
|
+
if (!registry)
|
|
64
|
+
return null;
|
|
65
|
+
const matches = [];
|
|
66
|
+
for (const [key, taskId] of Object.entries(registry.ids)) {
|
|
67
|
+
const taskBranch = readBranchFromTaskMd(repoRoot, taskId);
|
|
68
|
+
if (taskBranch && taskBranch === branch) {
|
|
69
|
+
matches.push(`#${key}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (matches.length === 0)
|
|
73
|
+
return null;
|
|
74
|
+
if (matches.length > 1) {
|
|
75
|
+
process.stderr.write(`Warning: branch '${branch}' is bound to multiple active tasks: ${matches.join(', ')}; using ${matches[0]}\n`);
|
|
76
|
+
}
|
|
77
|
+
return matches[0];
|
|
78
|
+
}
|
|
79
|
+
export { normalizeShortIdInput, lookupShortIdByBranch, loadShortIdByTaskId };
|
|
80
|
+
//# sourceMappingURL=short-id.js.map
|
package/dist/lib/update.js
CHANGED
|
@@ -3,6 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import { info, ok, err } from "./log.js";
|
|
4
4
|
import { resolveTemplateDir } from "./paths.js";
|
|
5
5
|
import { renderFile, copySkillDir, KNOWN_PLATFORMS } from "./render.js";
|
|
6
|
+
import { isPathOwnedByDisabledTUI, resolveEnabledTUIs } from "./builtin-tuis.js";
|
|
6
7
|
const defaults = JSON.parse(fs.readFileSync(new URL('./defaults.json', import.meta.url), 'utf8'));
|
|
7
8
|
const CONFIG_DIR = '.agents';
|
|
8
9
|
const CONFIG_PATH = path.join(CONFIG_DIR, '.airc.json');
|
|
@@ -15,7 +16,7 @@ function isPathOwnedByOtherPlatform(relativePath, platformType) {
|
|
|
15
16
|
return false;
|
|
16
17
|
return candidate !== platformType;
|
|
17
18
|
}
|
|
18
|
-
function syncFileRegistry(config, platformType) {
|
|
19
|
+
function syncFileRegistry(config, platformType, enabledTUIs) {
|
|
19
20
|
config.files ||= {};
|
|
20
21
|
const before = JSON.stringify({
|
|
21
22
|
files: {
|
|
@@ -36,6 +37,8 @@ function syncFileRegistry(config, platformType) {
|
|
|
36
37
|
for (const entry of defaults.files.managed) {
|
|
37
38
|
if (isPathOwnedByOtherPlatform(entry, platformType))
|
|
38
39
|
continue;
|
|
40
|
+
if (isPathOwnedByDisabledTUI(entry, enabledTUIs))
|
|
41
|
+
continue;
|
|
39
42
|
if (!allExisting.includes(entry)) {
|
|
40
43
|
config.files.managed.push(entry);
|
|
41
44
|
added.managed.push(entry);
|
|
@@ -44,6 +47,8 @@ function syncFileRegistry(config, platformType) {
|
|
|
44
47
|
for (const entry of defaults.files.merged) {
|
|
45
48
|
if (isPathOwnedByOtherPlatform(entry, platformType))
|
|
46
49
|
continue;
|
|
50
|
+
if (isPathOwnedByDisabledTUI(entry, enabledTUIs))
|
|
51
|
+
continue;
|
|
47
52
|
if (!allExisting.includes(entry)) {
|
|
48
53
|
config.files.merged.push(entry);
|
|
49
54
|
added.merged.push(entry);
|
|
@@ -82,6 +87,7 @@ async function cmdUpdate() {
|
|
|
82
87
|
const config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
|
|
83
88
|
const { project, org, language } = config;
|
|
84
89
|
const platformType = config.platform?.type || defaults.platform.type;
|
|
90
|
+
const enabledTUIs = resolveEnabledTUIs(config.tuis);
|
|
85
91
|
const replacements = { project, org };
|
|
86
92
|
info(`Updating seed files for: ${project}`);
|
|
87
93
|
console.log('');
|
|
@@ -106,20 +112,27 @@ async function cmdUpdate() {
|
|
|
106
112
|
catch {
|
|
107
113
|
// Ignore missing legacy script from pre-ESM installs.
|
|
108
114
|
}
|
|
109
|
-
// update Claude command
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
// update Claude command (only if enabled)
|
|
116
|
+
if (enabledTUIs.has('claude-code')) {
|
|
117
|
+
renderFile(path.join(templateDir, '.claude', 'commands', claudeSrc), path.join('.claude', 'commands', 'update-agent-infra.md'), replacements);
|
|
118
|
+
ok('Updated .claude/commands/update-agent-infra.md');
|
|
119
|
+
}
|
|
120
|
+
// update Gemini command (only if enabled)
|
|
121
|
+
if (enabledTUIs.has('gemini-cli')) {
|
|
122
|
+
renderFile(path.join(templateDir, '.gemini', 'commands', '_project_', geminiSrc), path.join('.gemini', 'commands', project, 'update-agent-infra.toml'), replacements);
|
|
123
|
+
ok(`Updated .gemini/commands/${project}/update-agent-infra.toml`);
|
|
124
|
+
}
|
|
125
|
+
// update OpenCode command (only if enabled)
|
|
126
|
+
if (enabledTUIs.has('opencode')) {
|
|
127
|
+
renderFile(path.join(templateDir, '.opencode', 'commands', opencodeSrc), path.join('.opencode', 'commands', 'update-agent-infra.md'), replacements);
|
|
128
|
+
ok('Updated .opencode/commands/update-agent-infra.md');
|
|
129
|
+
}
|
|
118
130
|
// sync file registry
|
|
119
|
-
const { added, changed } = syncFileRegistry(config, platformType);
|
|
131
|
+
const { added, changed } = syncFileRegistry(config, platformType, enabledTUIs);
|
|
120
132
|
const hasNewEntries = added.managed.length > 0 || added.merged.length > 0;
|
|
121
133
|
const platformAdded = !config.platform;
|
|
122
134
|
const sandboxAdded = !config.sandbox;
|
|
135
|
+
const taskAdded = !config.task;
|
|
123
136
|
const labelsAdded = !config.labels;
|
|
124
137
|
const requiresPullRequestAdded = config.requiresPullRequest === undefined;
|
|
125
138
|
let configChanged = changed;
|
|
@@ -131,6 +144,10 @@ async function cmdUpdate() {
|
|
|
131
144
|
config.sandbox = structuredClone(defaults.sandbox);
|
|
132
145
|
configChanged = true;
|
|
133
146
|
}
|
|
147
|
+
if (taskAdded) {
|
|
148
|
+
config.task = structuredClone(defaults.task);
|
|
149
|
+
configChanged = true;
|
|
150
|
+
}
|
|
134
151
|
if (labelsAdded) {
|
|
135
152
|
config.labels = structuredClone(defaults.labels);
|
|
136
153
|
configChanged = true;
|
|
@@ -150,13 +167,16 @@ async function cmdUpdate() {
|
|
|
150
167
|
ok(` merged: ${entry}`);
|
|
151
168
|
}
|
|
152
169
|
}
|
|
153
|
-
else if (platformAdded || sandboxAdded || labelsAdded || requiresPullRequestAdded) {
|
|
170
|
+
else if (platformAdded || sandboxAdded || taskAdded || labelsAdded || requiresPullRequestAdded) {
|
|
154
171
|
if (platformAdded) {
|
|
155
172
|
info(`Default platform config added to ${CONFIG_PATH}.`);
|
|
156
173
|
}
|
|
157
174
|
if (sandboxAdded) {
|
|
158
175
|
info(`Default sandbox config added to ${CONFIG_PATH}.`);
|
|
159
176
|
}
|
|
177
|
+
if (taskAdded) {
|
|
178
|
+
info(`Default task.shortIdLength=${defaults.task.shortIdLength} added to ${CONFIG_PATH}.`);
|
|
179
|
+
}
|
|
160
180
|
if (labelsAdded) {
|
|
161
181
|
info(`Default labels.in config added to ${CONFIG_PATH}.`);
|
|
162
182
|
}
|
|
@@ -170,6 +190,9 @@ async function cmdUpdate() {
|
|
|
170
190
|
if (hasNewEntries && sandboxAdded) {
|
|
171
191
|
info(`Default sandbox config added to ${CONFIG_PATH}.`);
|
|
172
192
|
}
|
|
193
|
+
if (hasNewEntries && taskAdded) {
|
|
194
|
+
info(`Default task.shortIdLength=${defaults.task.shortIdLength} added to ${CONFIG_PATH}.`);
|
|
195
|
+
}
|
|
173
196
|
if (hasNewEntries && labelsAdded) {
|
|
174
197
|
info(`Default labels.in config added to ${CONFIG_PATH}.`);
|
|
175
198
|
}
|
|
@@ -186,12 +209,30 @@ async function cmdUpdate() {
|
|
|
186
209
|
console.log('');
|
|
187
210
|
ok('Seed files updated successfully!');
|
|
188
211
|
console.log('');
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
212
|
+
if (enabledTUIs.size === 0) {
|
|
213
|
+
console.log(' No built-in TUI enabled (tuis: []).');
|
|
214
|
+
console.log(` Configure "customTUIs" in ${CONFIG_PATH} if needed.`);
|
|
215
|
+
console.log('');
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
console.log(' Next step: run the full update in your AI TUI:');
|
|
219
|
+
console.log('');
|
|
220
|
+
const claudeOrOpencode = [];
|
|
221
|
+
if (enabledTUIs.has('claude-code'))
|
|
222
|
+
claudeOrOpencode.push('Claude Code');
|
|
223
|
+
if (enabledTUIs.has('opencode'))
|
|
224
|
+
claudeOrOpencode.push('OpenCode');
|
|
225
|
+
if (claudeOrOpencode.length > 0) {
|
|
226
|
+
console.log(` ${claudeOrOpencode.join(' / ')}: /update-agent-infra`);
|
|
227
|
+
}
|
|
228
|
+
if (enabledTUIs.has('gemini-cli')) {
|
|
229
|
+
console.log(` Gemini CLI: /${project}:update-agent-infra`);
|
|
230
|
+
}
|
|
231
|
+
if (enabledTUIs.has('codex')) {
|
|
232
|
+
console.log(' Codex CLI: $update-agent-infra');
|
|
233
|
+
}
|
|
234
|
+
console.log('');
|
|
235
|
+
}
|
|
195
236
|
}
|
|
196
237
|
export { cmdUpdate };
|
|
197
238
|
//# sourceMappingURL=update.js.map
|