@fitlab-ai/agent-infra 0.8.1 → 0.8.3
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/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/bin/cli.ts +3 -3
- package/dist/bin/cli.js +4 -4
- package/dist/lib/cp.js +1 -1
- package/dist/lib/decide.js +2 -2
- package/dist/lib/defaults.json +2 -0
- package/dist/lib/init.js +7 -7
- package/dist/lib/merge.js +1 -1
- package/dist/lib/prompt.js +1 -1
- package/dist/lib/run/index.js +7 -7
- package/dist/lib/run/prompt.js +1 -1
- package/dist/lib/sandbox/capture.js +5 -5
- package/dist/lib/sandbox/clipboard/bridge.js +48 -13
- package/dist/lib/sandbox/clipboard/index.js +5 -6
- package/dist/lib/sandbox/clipboard/linux.js +91 -0
- package/dist/lib/sandbox/clipboard/paths.js +1 -1
- package/dist/lib/sandbox/clipboard/win32.js +144 -0
- package/dist/lib/sandbox/commands/create.js +101 -66
- package/dist/lib/sandbox/commands/enter.js +9 -9
- package/dist/lib/sandbox/commands/list-running.js +2 -2
- package/dist/lib/sandbox/commands/ls.js +7 -7
- package/dist/lib/sandbox/commands/prune.js +8 -8
- package/dist/lib/sandbox/commands/rebuild.js +38 -50
- package/dist/lib/sandbox/commands/refresh.js +2 -2
- package/dist/lib/sandbox/commands/rm.js +11 -11
- package/dist/lib/sandbox/commands/show.js +4 -4
- package/dist/lib/sandbox/commands/start.js +4 -4
- package/dist/lib/sandbox/commands/vm.js +4 -4
- package/dist/lib/sandbox/config.js +11 -5
- package/dist/lib/sandbox/constants.js +4 -1
- package/dist/lib/sandbox/credentials.js +1 -1
- package/dist/lib/sandbox/dotfiles.js +1 -1
- package/dist/lib/sandbox/engine.js +3 -3
- package/dist/lib/sandbox/engines/index.js +5 -5
- package/dist/lib/sandbox/engines/wsl2-paths.js +1 -1
- package/dist/lib/sandbox/image-build.js +80 -0
- package/dist/lib/sandbox/image-prune.js +2 -2
- package/dist/lib/sandbox/index.js +10 -10
- package/dist/lib/sandbox/managed-fs.js +1 -1
- package/dist/lib/sandbox/readme-scaffold.js +1 -1
- package/dist/lib/sandbox/runtimes/node20.dockerfile +1 -1
- package/dist/lib/sandbox/runtimes/node22.dockerfile +1 -1
- package/dist/lib/sandbox/tools.js +11 -2
- package/dist/lib/server/adapters/feishu/index.js +12 -3
- package/dist/lib/server/adapters/feishu/renderer.js +88 -0
- package/dist/lib/server/adapters/feishu/transport.js +9 -2
- package/dist/lib/server/daemon.js +64 -43
- package/dist/lib/server/display.js +83 -0
- package/dist/lib/server/index.js +2 -2
- package/dist/lib/server/process-control.js +2 -2
- package/dist/lib/server/protocol.js +22 -6
- package/dist/lib/server/streamer.js +5 -4
- package/dist/lib/task/commands/cat.js +2 -2
- package/dist/lib/task/commands/decisions.js +4 -4
- package/dist/lib/task/commands/files.js +3 -3
- package/dist/lib/task/commands/grep.js +3 -3
- package/dist/lib/task/commands/issue-body.js +4 -4
- package/dist/lib/task/commands/log.js +5 -5
- package/dist/lib/task/commands/ls.js +3 -3
- package/dist/lib/task/commands/show.js +1 -1
- package/dist/lib/task/commands/status.js +71 -25
- package/dist/lib/task/index.js +9 -9
- package/dist/lib/task/resolve-ref.js +1 -1
- package/dist/lib/task/workflow-warnings.js +94 -0
- package/dist/lib/update.js +35 -4
- package/lib/defaults.json +2 -0
- package/lib/sandbox/clipboard/bridge.ts +50 -8
- package/lib/sandbox/clipboard/index.ts +5 -6
- package/lib/sandbox/clipboard/linux.ts +124 -0
- package/lib/sandbox/clipboard/win32.ts +173 -0
- package/lib/sandbox/commands/create.ts +123 -65
- package/lib/sandbox/commands/rebuild.ts +42 -54
- package/lib/sandbox/config.ts +14 -2
- package/lib/sandbox/constants.ts +4 -0
- package/lib/sandbox/image-build.ts +134 -0
- package/lib/sandbox/runtimes/node20.dockerfile +1 -1
- package/lib/sandbox/runtimes/node22.dockerfile +1 -1
- package/lib/sandbox/tools.ts +9 -0
- package/lib/server/adapters/_contract.ts +3 -0
- package/lib/server/adapters/feishu/index.ts +12 -2
- package/lib/server/adapters/feishu/renderer.ts +99 -0
- package/lib/server/adapters/feishu/transport.ts +19 -3
- package/lib/server/daemon.ts +74 -38
- package/lib/server/display.ts +136 -0
- package/lib/server/protocol.ts +20 -4
- package/lib/server/streamer.ts +5 -4
- package/lib/task/commands/log.ts +3 -3
- package/lib/task/commands/status.ts +102 -21
- package/lib/task/workflow-warnings.ts +121 -0
- package/lib/update.ts +34 -0
- package/package.json +3 -3
- package/templates/.agents/README.en.md +3 -3
- package/templates/.agents/README.zh-CN.md +3 -3
- package/templates/.agents/rules/create-issue.github.en.md +3 -3
- package/templates/.agents/rules/create-issue.github.zh-CN.md +3 -3
- package/templates/.agents/rules/issue-pr-commands.github.en.md +7 -2
- package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +7 -2
- package/templates/.agents/rules/issue-sync.github.en.md +13 -0
- package/templates/.agents/rules/issue-sync.github.zh-CN.md +13 -0
- package/templates/.agents/rules/next-step-output.en.md +15 -1
- package/templates/.agents/rules/next-step-output.zh-CN.md +15 -1
- package/templates/.agents/rules/pr-sync.github.en.md +17 -2
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +17 -2
- package/templates/.agents/rules/task-management.en.md +1 -1
- package/templates/.agents/rules/task-management.zh-CN.md +1 -1
- package/templates/.agents/scripts/platform-adapters/platform-sync.github.js +57 -0
- package/templates/.agents/scripts/validate-artifact.js +120 -0
- package/templates/.agents/scripts/workflow-warnings.js +290 -0
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +118 -0
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +118 -0
- package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +49 -0
- package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +49 -0
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +48 -0
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +48 -0
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +60 -0
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +87 -0
- package/templates/.agents/skills/create-pr/SKILL.en.md +2 -0
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +2 -0
- package/templates/.agents/skills/create-task/SKILL.en.md +4 -1
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +4 -1
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +33 -1
- package/templates/.agents/templates/task.en.md +7 -0
- package/templates/.agents/templates/task.zh-CN.md +7 -0
- package/templates/.claude/commands/complete-manual-validation.en.md +9 -0
- package/templates/.claude/commands/complete-manual-validation.zh-CN.md +9 -0
- package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +8 -0
- package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +8 -0
- package/templates/.github/workflows/metadata-sync.yml +5 -0
- package/templates/.opencode/commands/complete-manual-validation.en.md +11 -0
- package/templates/.opencode/commands/complete-manual-validation.zh-CN.md +11 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { VERSION } from
|
|
2
|
-
import { getSkillRunSpec } from
|
|
1
|
+
import { VERSION } from '../version.js';
|
|
2
|
+
import { getSkillRunSpec } from '../run/skills.js';
|
|
3
3
|
const TASK_READ = new Set(['ls', 'list', 'status', 'show', 'log', 'decisions']);
|
|
4
4
|
const SANDBOX_READ = new Set(['ls', 'list', 'show']);
|
|
5
5
|
const SANDBOX_WRITE = new Set(['create', 'start']);
|
|
@@ -12,10 +12,26 @@ function taskSubcommand(subcommand) {
|
|
|
12
12
|
export function commandHelp() {
|
|
13
13
|
return [
|
|
14
14
|
`agent-infra ${VERSION}`,
|
|
15
|
-
'Built-ins:
|
|
16
|
-
'
|
|
17
|
-
'
|
|
18
|
-
'
|
|
15
|
+
'Built-ins:',
|
|
16
|
+
'/help',
|
|
17
|
+
'/ping',
|
|
18
|
+
'/version',
|
|
19
|
+
'Read:',
|
|
20
|
+
'/sandbox ls',
|
|
21
|
+
'/sandbox show {ref}',
|
|
22
|
+
'/sandbox vm status',
|
|
23
|
+
'/task decisions {ref}',
|
|
24
|
+
'/task log {ref}',
|
|
25
|
+
'/task ls',
|
|
26
|
+
'/task show {ref}',
|
|
27
|
+
'/task status {ref}',
|
|
28
|
+
'Write:',
|
|
29
|
+
'/sandbox create {ref}',
|
|
30
|
+
'/sandbox start {ref}',
|
|
31
|
+
'Exec:',
|
|
32
|
+
'/decide {task-ref} {HD-id} {decision}',
|
|
33
|
+
'/run create-task {description}',
|
|
34
|
+
'/run {skill} {task-ref}'
|
|
19
35
|
].join('\n');
|
|
20
36
|
}
|
|
21
37
|
export function parseCommand(text) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { streamEvent } from './display.js';
|
|
2
|
+
import { redactSecrets } from './redact.js';
|
|
2
3
|
function chunks(text, size) {
|
|
3
4
|
if (text.length === 0)
|
|
4
5
|
return [];
|
|
@@ -9,7 +10,7 @@ function chunks(text, size) {
|
|
|
9
10
|
return out;
|
|
10
11
|
}
|
|
11
12
|
export async function streamCommand(options, run, send) {
|
|
12
|
-
await send(
|
|
13
|
+
await send(streamEvent(options.title, 'started'));
|
|
13
14
|
const size = options.chunkChars ?? 4000;
|
|
14
15
|
const throttleMs = options.throttleMs ?? 0;
|
|
15
16
|
let streamed = false;
|
|
@@ -22,7 +23,7 @@ export async function streamCommand(options, run, send) {
|
|
|
22
23
|
buffer = '';
|
|
23
24
|
lastFlush = Date.now();
|
|
24
25
|
for (const chunk of chunks(text, size)) {
|
|
25
|
-
await send(chunk);
|
|
26
|
+
await send(streamEvent(options.title, 'chunk', chunk));
|
|
26
27
|
}
|
|
27
28
|
};
|
|
28
29
|
const emit = async (chunk) => {
|
|
@@ -38,7 +39,7 @@ export async function streamCommand(options, run, send) {
|
|
|
38
39
|
buffer += [result.stdout, result.stderr].filter(Boolean).join('\n');
|
|
39
40
|
}
|
|
40
41
|
await flush();
|
|
41
|
-
await send(
|
|
42
|
+
await send(streamEvent(options.title, 'finished', undefined, result.exitCode, result.signal));
|
|
42
43
|
return result;
|
|
43
44
|
}
|
|
44
45
|
//# sourceMappingURL=streamer.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import { resolveTaskRef } from
|
|
3
|
-
import { resolveArtifact } from
|
|
2
|
+
import { resolveTaskRef } from '../resolve-ref.js';
|
|
3
|
+
import { resolveArtifact } from '../artifacts.js';
|
|
4
4
|
const USAGE = `Usage: ai task cat <N | #N | TASK-id> <artifact | N>
|
|
5
5
|
|
|
6
6
|
Prints a task artifact's raw content to stdout.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { formatTable } from
|
|
4
|
-
import { resolveTaskRef } from
|
|
5
|
-
import { parseLedger, HUMAN_DECISION_STATUSES } from
|
|
6
|
-
import { extractSubSection } from
|
|
3
|
+
import { formatTable } from '../../table.js';
|
|
4
|
+
import { resolveTaskRef } from '../resolve-ref.js';
|
|
5
|
+
import { parseLedger, HUMAN_DECISION_STATUSES } from '../ledger.js';
|
|
6
|
+
import { extractSubSection } from '../sections.js';
|
|
7
7
|
const USAGE = `Usage: ai task decisions <N | #N | TASK-id> [selector] [options]
|
|
8
8
|
|
|
9
9
|
Lists the human-decision (HD-) items recorded in a task's review disagreement
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { formatTable } from
|
|
2
|
-
import { resolveTaskRef } from
|
|
3
|
-
import { enumerateArtifacts } from
|
|
1
|
+
import { formatTable } from '../../table.js';
|
|
2
|
+
import { resolveTaskRef } from '../resolve-ref.js';
|
|
3
|
+
import { enumerateArtifacts } from '../artifacts.js';
|
|
4
4
|
const USAGE = `Usage: ai task files <N | #N | TASK-id>
|
|
5
5
|
|
|
6
6
|
Lists the artifacts in a task directory with stable numbers.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { resolveTaskRef, detectRepoRoot, enumerateTaskDirs } from
|
|
4
|
-
import { enumerateArtifacts, resolveArtifact } from
|
|
5
|
-
import { loadShortIdByTaskId } from
|
|
3
|
+
import { resolveTaskRef, detectRepoRoot, enumerateTaskDirs } from '../resolve-ref.js';
|
|
4
|
+
import { enumerateArtifacts, resolveArtifact } from '../artifacts.js';
|
|
5
|
+
import { loadShortIdByTaskId } from '../short-id.js';
|
|
6
6
|
const USAGE = `Usage: ai task grep <pattern> [ref] [artifact | N]
|
|
7
7
|
|
|
8
8
|
Literal (non-regex) line search across task artifacts.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import { resolveTaskRef } from
|
|
3
|
-
import { extractTitle } from
|
|
4
|
-
import { extractSection, findSectionHeading } from
|
|
5
|
-
import { renderTemplateBody, PLACEHOLDER } from
|
|
2
|
+
import { resolveTaskRef } from '../resolve-ref.js';
|
|
3
|
+
import { extractTitle } from '../frontmatter.js';
|
|
4
|
+
import { extractSection, findSectionHeading } from '../sections.js';
|
|
5
|
+
import { renderTemplateBody, PLACEHOLDER } from '../issue-form.js';
|
|
6
6
|
const USAGE = `Usage: ai task issue-body <N | #N | TASK-id> [--template <path>]
|
|
7
7
|
|
|
8
8
|
Print a deterministic Issue body extracted from a task's task.md.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import { formatTable } from
|
|
3
|
-
import { resolveTaskRef } from
|
|
4
|
-
import { parseLedger
|
|
2
|
+
import { formatTable } from '../../table.js';
|
|
3
|
+
import { resolveTaskRef } from '../resolve-ref.js';
|
|
4
|
+
import { parseLedger } from '../ledger.js';
|
|
5
5
|
const USAGE = `Usage: ai task log <N | #N | TASK-id>
|
|
6
6
|
|
|
7
7
|
Renders a task's activity log as a per-step status table. A step's start and
|
|
@@ -13,7 +13,7 @@ Columns: # (row) / STEP / AGENT / STARTED / DONE / NOTE
|
|
|
13
13
|
A human-executed step shows AGENT as 'human' and, when it has no start marker,
|
|
14
14
|
a '-' STARTED placeholder. Review-step NOTE also carries two human counts in
|
|
15
15
|
the verdict list, right after blockers/major/minor: manual-validation
|
|
16
|
-
and human-decision (current ledger stage total).
|
|
16
|
+
and human-decision (current pending ledger stage total).
|
|
17
17
|
`;
|
|
18
18
|
const TABLE_HEADERS = ['#', 'STEP', 'AGENT', 'STARTED', 'DONE', 'NOTE'];
|
|
19
19
|
// The activity-log H2 heading is language-dependent (zh template / en template).
|
|
@@ -100,7 +100,7 @@ function pairEntries(entries) {
|
|
|
100
100
|
function countHumanDecisionsByStage(rows) {
|
|
101
101
|
const counts = new Map();
|
|
102
102
|
for (const row of rows) {
|
|
103
|
-
if (!isReviewStage(row.stage) ||
|
|
103
|
+
if (!isReviewStage(row.stage) || row.status !== 'needs-human-decision')
|
|
104
104
|
continue;
|
|
105
105
|
counts.set(row.stage, (counts.get(row.stage) ?? 0) + 1);
|
|
106
106
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { execFileSync } from 'node:child_process';
|
|
4
|
-
import { formatTable } from
|
|
5
|
-
import { parseTaskFrontmatter, extractTitle } from
|
|
6
|
-
import { loadShortIdByTaskId } from
|
|
4
|
+
import { formatTable } from '../../table.js';
|
|
5
|
+
import { parseTaskFrontmatter, extractTitle } from '../frontmatter.js';
|
|
6
|
+
import { loadShortIdByTaskId } from '../short-id.js';
|
|
7
7
|
const USAGE = `Usage: ai task ls [--all | --blocked | --completed]
|
|
8
8
|
|
|
9
9
|
Lists tasks under .agents/workspace/. Defaults to active tasks only.
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { execFileSync } from 'node:child_process';
|
|
4
|
-
import { commandForEngine } from
|
|
5
|
-
import { resolveTaskRef } from
|
|
6
|
-
import { enumerateArtifacts } from
|
|
7
|
-
import { parseTaskFrontmatter, extractTitle } from
|
|
8
|
-
import { loadShortIdByTaskId } from
|
|
9
|
-
import {
|
|
4
|
+
import { commandForEngine } from '../../sandbox/shell.js';
|
|
5
|
+
import { resolveTaskRef } from '../resolve-ref.js';
|
|
6
|
+
import { enumerateArtifacts } from '../artifacts.js';
|
|
7
|
+
import { parseTaskFrontmatter, extractTitle } from '../frontmatter.js';
|
|
8
|
+
import { loadShortIdByTaskId } from '../short-id.js';
|
|
9
|
+
import { getOpenWorkflowWarnings, formatWorkflowWarningSummary } from '../workflow-warnings.js';
|
|
10
|
+
import { parseActivityLog, pairEntries } from './log.js';
|
|
11
|
+
import { statusCard } from '../../server/display.js';
|
|
10
12
|
const USAGE = `Usage: ai task status <N | #N | TASK-id>
|
|
11
13
|
|
|
12
14
|
Prints an aggregated "health check" view for a task: header, metadata,
|
|
@@ -267,6 +269,9 @@ function renderStatus(model) {
|
|
|
267
269
|
if (model.title)
|
|
268
270
|
lines.push(model.title);
|
|
269
271
|
lines.push('', 'Metadata', ...renderPairs(model.metadata));
|
|
272
|
+
if (model.workflowWarnings.length > 0) {
|
|
273
|
+
lines.push('', `Workflow Warnings (${model.workflowWarnings.length} open)`, ...formatWorkflowWarningSummary(model.workflowWarnings).map((line) => ` ${line}`));
|
|
274
|
+
}
|
|
270
275
|
lines.push('', `Artifacts (${model.artifacts.count})`);
|
|
271
276
|
if (model.artifacts.groups.length === 0) {
|
|
272
277
|
lines.push(' (none)');
|
|
@@ -302,6 +307,59 @@ function renderStatus(model) {
|
|
|
302
307
|
]));
|
|
303
308
|
return lines;
|
|
304
309
|
}
|
|
310
|
+
function modelTone(model) {
|
|
311
|
+
if (model.workflow.state === 'in-progress')
|
|
312
|
+
return model.workflow.stale === 'yes' ? 'warning' : 'running';
|
|
313
|
+
if (model.metadata.some(([key, value]) => key === 'status' && value === 'completed'))
|
|
314
|
+
return 'success';
|
|
315
|
+
if (model.metadata.some(([key, value]) => key === 'status' && (value === 'blocked' || value === 'cancelled'))) {
|
|
316
|
+
return 'danger';
|
|
317
|
+
}
|
|
318
|
+
return 'info';
|
|
319
|
+
}
|
|
320
|
+
function buildFromResolved(input) {
|
|
321
|
+
const content = fs.readFileSync(input.taskMdPath, 'utf8');
|
|
322
|
+
const fm = parseTaskFrontmatter(content);
|
|
323
|
+
const run = input.run ?? makeRunner(input.repoRoot);
|
|
324
|
+
const artifacts = enumerateArtifacts(input.taskDir);
|
|
325
|
+
const workflow = collectWorkflow(content, input.now);
|
|
326
|
+
return {
|
|
327
|
+
taskId: input.taskId,
|
|
328
|
+
shortId: input.shortId ?? loadShortIdByTaskId(input.repoRoot).get(input.taskId) ?? DASH,
|
|
329
|
+
title: extractTitle(content),
|
|
330
|
+
metadata: collectMetadata(fm),
|
|
331
|
+
workflowWarnings: getOpenWorkflowWarnings(content),
|
|
332
|
+
artifacts: { count: artifacts.length, groups: groupArtifacts(artifacts) },
|
|
333
|
+
workflow,
|
|
334
|
+
runtime: collectRuntime(input.taskDir, workflow, run),
|
|
335
|
+
git: collectGit(fm.branch ?? '', run)
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
function buildStatusModel(refOrInput, options = {}) {
|
|
339
|
+
if (typeof refOrInput !== 'string') {
|
|
340
|
+
return buildFromResolved(refOrInput);
|
|
341
|
+
}
|
|
342
|
+
const resolved = resolveTaskRef(refOrInput);
|
|
343
|
+
if (!resolved.ok) {
|
|
344
|
+
throw new Error(resolved.message);
|
|
345
|
+
}
|
|
346
|
+
return buildFromResolved({
|
|
347
|
+
taskId: resolved.taskId,
|
|
348
|
+
taskDir: resolved.taskDir,
|
|
349
|
+
taskMdPath: resolved.taskMdPath,
|
|
350
|
+
repoRoot: resolved.repoRoot,
|
|
351
|
+
run: options.run,
|
|
352
|
+
now: options.now
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
function statusModelToDisplay(model) {
|
|
356
|
+
return statusCard(`Task ${model.taskId} (${model.shortId})`, modelTone(model), [
|
|
357
|
+
['workflow', model.workflow.state],
|
|
358
|
+
['step', model.workflow.step],
|
|
359
|
+
['runtime', model.runtime.status],
|
|
360
|
+
['git', model.git.uncommitted]
|
|
361
|
+
], renderStatus(model).join('\n'));
|
|
362
|
+
}
|
|
305
363
|
function status(args = []) {
|
|
306
364
|
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
307
365
|
process.stdout.write(USAGE);
|
|
@@ -309,30 +367,18 @@ function status(args = []) {
|
|
|
309
367
|
process.exitCode = 1;
|
|
310
368
|
return;
|
|
311
369
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
370
|
+
let model;
|
|
371
|
+
try {
|
|
372
|
+
model = buildStatusModel(args[0]);
|
|
373
|
+
}
|
|
374
|
+
catch (error) {
|
|
375
|
+
process.stderr.write(`ai task status: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
315
376
|
process.exitCode = 1;
|
|
316
377
|
return;
|
|
317
378
|
}
|
|
318
|
-
const content = fs.readFileSync(resolved.taskMdPath, 'utf8');
|
|
319
|
-
const fm = parseTaskFrontmatter(content);
|
|
320
|
-
const run = makeRunner(resolved.repoRoot);
|
|
321
|
-
const artifacts = enumerateArtifacts(resolved.taskDir);
|
|
322
|
-
const workflow = collectWorkflow(content);
|
|
323
|
-
const model = {
|
|
324
|
-
taskId: resolved.taskId,
|
|
325
|
-
shortId: loadShortIdByTaskId(resolved.repoRoot).get(resolved.taskId) ?? DASH,
|
|
326
|
-
title: extractTitle(content),
|
|
327
|
-
metadata: collectMetadata(fm),
|
|
328
|
-
artifacts: { count: artifacts.length, groups: groupArtifacts(artifacts) },
|
|
329
|
-
workflow,
|
|
330
|
-
runtime: collectRuntime(resolved.taskDir, workflow, run),
|
|
331
|
-
git: collectGit(fm.branch ?? '', run)
|
|
332
|
-
};
|
|
333
379
|
for (const line of renderStatus(model)) {
|
|
334
380
|
process.stdout.write(`${line}\n`);
|
|
335
381
|
}
|
|
336
382
|
}
|
|
337
|
-
export { status, makeRunner, collectMetadata, groupArtifacts, collectGit, collectWorkflow, collectRuntime, renderStatus, METADATA_KEYS };
|
|
383
|
+
export { status, makeRunner, buildStatusModel, collectMetadata, groupArtifacts, collectGit, collectWorkflow, collectRuntime, renderStatus, statusModelToDisplay, METADATA_KEYS };
|
|
338
384
|
//# sourceMappingURL=status.js.map
|
package/dist/lib/task/index.js
CHANGED
|
@@ -41,48 +41,48 @@ export async function runTask(args) {
|
|
|
41
41
|
}
|
|
42
42
|
switch (subcommand) {
|
|
43
43
|
case 'cat': {
|
|
44
|
-
const { cat } = await import(
|
|
44
|
+
const { cat } = await import('./commands/cat.js');
|
|
45
45
|
cat(rest);
|
|
46
46
|
break;
|
|
47
47
|
}
|
|
48
48
|
case 'decisions':
|
|
49
49
|
case 'd': {
|
|
50
|
-
const { decisions } = await import(
|
|
50
|
+
const { decisions } = await import('./commands/decisions.js');
|
|
51
51
|
decisions(rest);
|
|
52
52
|
break;
|
|
53
53
|
}
|
|
54
54
|
case 'files': {
|
|
55
|
-
const { files } = await import(
|
|
55
|
+
const { files } = await import('./commands/files.js');
|
|
56
56
|
files(rest);
|
|
57
57
|
break;
|
|
58
58
|
}
|
|
59
59
|
case 'grep': {
|
|
60
|
-
const { grep } = await import(
|
|
60
|
+
const { grep } = await import('./commands/grep.js');
|
|
61
61
|
grep(rest);
|
|
62
62
|
break;
|
|
63
63
|
}
|
|
64
64
|
case 'issue-body': {
|
|
65
|
-
const { issueBody } = await import(
|
|
65
|
+
const { issueBody } = await import('./commands/issue-body.js');
|
|
66
66
|
issueBody(rest);
|
|
67
67
|
break;
|
|
68
68
|
}
|
|
69
69
|
case 'log': {
|
|
70
|
-
const { log } = await import(
|
|
70
|
+
const { log } = await import('./commands/log.js');
|
|
71
71
|
log(rest);
|
|
72
72
|
break;
|
|
73
73
|
}
|
|
74
74
|
case 'ls': {
|
|
75
|
-
const { ls } = await import(
|
|
75
|
+
const { ls } = await import('./commands/ls.js');
|
|
76
76
|
ls(rest);
|
|
77
77
|
break;
|
|
78
78
|
}
|
|
79
79
|
case 'show': {
|
|
80
|
-
const { show } = await import(
|
|
80
|
+
const { show } = await import('./commands/show.js');
|
|
81
81
|
show(rest);
|
|
82
82
|
break;
|
|
83
83
|
}
|
|
84
84
|
case 'status': {
|
|
85
|
-
const { status } = await import(
|
|
85
|
+
const { status } = await import('./commands/status.js');
|
|
86
86
|
status(rest);
|
|
87
87
|
break;
|
|
88
88
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { execFileSync, spawnSync } from 'node:child_process';
|
|
4
|
-
import { normalizeShortIdInput } from
|
|
4
|
+
import { normalizeShortIdInput } from './short-id.js';
|
|
5
5
|
const TASK_ID_RE = /^TASK-\d{8}-\d{6}$/;
|
|
6
6
|
// Flat-structured workspace dirs that hold tasks under `{dir}/{taskId}/task.md`.
|
|
7
7
|
// Note: `archive` uses a three-level YYYY/MM/DD layout and is handled separately.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { extractSection } from './sections.js';
|
|
2
|
+
const WORKFLOW_WARNING_HEADINGS = ['工作流告警', 'Workflow Warnings'];
|
|
3
|
+
const WORKFLOW_WARNING_STATUSES = new Set(['open', 'resolved', 'ignored']);
|
|
4
|
+
const WORKFLOW_WARNING_SEVERITIES = new Set(['IMPORTANT', 'ACTION_REQUIRED']);
|
|
5
|
+
function splitTableRow(line) {
|
|
6
|
+
let value = line.trim();
|
|
7
|
+
if (!value.startsWith('|'))
|
|
8
|
+
return [];
|
|
9
|
+
value = value.replace(/^\|/, '').replace(/\|$/, '');
|
|
10
|
+
const cells = [];
|
|
11
|
+
let cell = '';
|
|
12
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
13
|
+
const char = value[index];
|
|
14
|
+
if (char === '|' && !isEscapedAt(value, index)) {
|
|
15
|
+
cells.push(unescapeTableCell(cell.trim()));
|
|
16
|
+
cell = '';
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
cell += char;
|
|
20
|
+
}
|
|
21
|
+
cells.push(unescapeTableCell(cell.trim()));
|
|
22
|
+
return cells;
|
|
23
|
+
}
|
|
24
|
+
function unescapeTableCell(value) {
|
|
25
|
+
let output = '';
|
|
26
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
27
|
+
const char = value[index];
|
|
28
|
+
const next = value[index + 1];
|
|
29
|
+
if (char === '\\' && (next === '\\' || next === '|')) {
|
|
30
|
+
output += next;
|
|
31
|
+
index += 1;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
output += char;
|
|
35
|
+
}
|
|
36
|
+
return output;
|
|
37
|
+
}
|
|
38
|
+
function isEscapedAt(value, index) {
|
|
39
|
+
let backslashes = 0;
|
|
40
|
+
for (let cursor = index - 1; cursor >= 0 && value[cursor] === '\\'; cursor -= 1) {
|
|
41
|
+
backslashes += 1;
|
|
42
|
+
}
|
|
43
|
+
return backslashes % 2 === 1;
|
|
44
|
+
}
|
|
45
|
+
function isSeparatorRow(cells) {
|
|
46
|
+
return cells.length > 0 && cells.every((cell) => /^:?-{3,}:?$/.test(cell));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Parses well-formed workflow warning rows. Malformed rows are intentionally
|
|
50
|
+
* ignored here; validate-artifact is responsible for reporting structure errors.
|
|
51
|
+
*/
|
|
52
|
+
function parseWorkflowWarnings(content) {
|
|
53
|
+
const section = extractSection(content, WORKFLOW_WARNING_HEADINGS);
|
|
54
|
+
if (!section)
|
|
55
|
+
return [];
|
|
56
|
+
const rows = [];
|
|
57
|
+
for (const rawLine of section.split(/\r?\n/)) {
|
|
58
|
+
const cells = splitTableRow(rawLine);
|
|
59
|
+
if (cells.length === 0)
|
|
60
|
+
continue;
|
|
61
|
+
if ((cells[0] ?? '').toLowerCase() === 'id')
|
|
62
|
+
continue;
|
|
63
|
+
if (isSeparatorRow(cells))
|
|
64
|
+
continue;
|
|
65
|
+
if (cells.length < 11)
|
|
66
|
+
continue;
|
|
67
|
+
rows.push({
|
|
68
|
+
id: cells[0] ?? '',
|
|
69
|
+
time: cells[1] ?? '',
|
|
70
|
+
step: cells[2] ?? '',
|
|
71
|
+
severity: cells[3] ?? '',
|
|
72
|
+
code: cells[4] ?? '',
|
|
73
|
+
status: cells[5] ?? '',
|
|
74
|
+
target: cells[6] ?? '',
|
|
75
|
+
message: cells[7] ?? '',
|
|
76
|
+
action: cells[8] ?? '',
|
|
77
|
+
resolvedAt: cells[9] ?? '',
|
|
78
|
+
resolution: cells[10] ?? ''
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return rows;
|
|
82
|
+
}
|
|
83
|
+
function getOpenWorkflowWarnings(content) {
|
|
84
|
+
return parseWorkflowWarnings(content).filter((warning) => warning.status === 'open');
|
|
85
|
+
}
|
|
86
|
+
function formatWorkflowWarningSummary(warnings) {
|
|
87
|
+
return warnings.map((warning) => {
|
|
88
|
+
const target = warning.target ? ` ${warning.target}` : '';
|
|
89
|
+
const action = warning.action ? ` - ${warning.action}` : '';
|
|
90
|
+
return `${warning.id} [${warning.severity}] ${warning.code}${target}${action}`;
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
export { WORKFLOW_WARNING_HEADINGS, WORKFLOW_WARNING_STATUSES, WORKFLOW_WARNING_SEVERITIES, parseWorkflowWarnings, getOpenWorkflowWarnings, formatWorkflowWarningSummary };
|
|
94
|
+
//# sourceMappingURL=workflow-warnings.js.map
|
package/dist/lib/update.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { info, ok, err } from
|
|
4
|
-
import { resolveTemplateDir } from
|
|
5
|
-
import { renderFile, copySkillDir, KNOWN_PLATFORMS } from
|
|
6
|
-
import { isPathOwnedByDisabledTUI, resolveEnabledTUIs } from
|
|
3
|
+
import { info, ok, err } from './log.js';
|
|
4
|
+
import { resolveTemplateDir } from './paths.js';
|
|
5
|
+
import { renderFile, copySkillDir, KNOWN_PLATFORMS } from './render.js';
|
|
6
|
+
import { isPathOwnedByDisabledTUI, resolveEnabledTUIs } from './builtin-tuis.js';
|
|
7
7
|
const defaults = JSON.parse(fs.readFileSync(new URL('./defaults.json', import.meta.url), 'utf8'));
|
|
8
8
|
const CONFIG_DIR = '.agents';
|
|
9
9
|
const CONFIG_PATH = path.join(CONFIG_DIR, '.airc.json');
|
|
10
|
+
const AGENT_INFRA_SANDBOX_TOOL = 'agent-infra';
|
|
11
|
+
const LEGACY_DEFAULT_SANDBOX_TOOLS = ['claude-code', 'codex', 'gemini-cli', 'opencode'];
|
|
12
|
+
const DEFAULT_SANDBOX_TOOLS = [AGENT_INFRA_SANDBOX_TOOL, ...LEGACY_DEFAULT_SANDBOX_TOOLS];
|
|
10
13
|
// One-time migration of the legacy project-level PR switch to the three-state
|
|
11
14
|
// `prFlow` preference. `true` (the old default / "PR flow on") maps to the
|
|
12
15
|
// strong constraint `required`; `false` maps to `disabled`. A missing or
|
|
@@ -25,6 +28,24 @@ function migratePrFlow(config) {
|
|
|
25
28
|
}
|
|
26
29
|
return null;
|
|
27
30
|
}
|
|
31
|
+
function isLegacyDefaultSandboxTools(value) {
|
|
32
|
+
if (!Array.isArray(value) || value.length !== LEGACY_DEFAULT_SANDBOX_TOOLS.length) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
const tools = new Set(value);
|
|
36
|
+
return LEGACY_DEFAULT_SANDBOX_TOOLS.every((tool) => tools.has(tool));
|
|
37
|
+
}
|
|
38
|
+
function migrateSandboxTools(config) {
|
|
39
|
+
const tools = config.sandbox?.tools;
|
|
40
|
+
if (!isLegacyDefaultSandboxTools(tools)) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
config.sandbox = {
|
|
44
|
+
...config.sandbox,
|
|
45
|
+
tools: [...DEFAULT_SANDBOX_TOOLS]
|
|
46
|
+
};
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
28
49
|
function isPathOwnedByOtherPlatform(relativePath, platformType) {
|
|
29
50
|
const top = String(relativePath || '').replace(/\\/g, '/').replace(/^\.\//, '').split('/')[0] ?? '';
|
|
30
51
|
if (!top.startsWith('.'))
|
|
@@ -153,6 +174,7 @@ async function cmdUpdate() {
|
|
|
153
174
|
const taskAdded = !config.task;
|
|
154
175
|
const labelsAdded = !config.labels;
|
|
155
176
|
const prFlowMigrated = migratePrFlow(config);
|
|
177
|
+
const sandboxToolsMigrated = !sandboxAdded && migrateSandboxTools(config);
|
|
156
178
|
let configChanged = changed;
|
|
157
179
|
if (platformAdded) {
|
|
158
180
|
config.platform = structuredClone(defaults.platform);
|
|
@@ -173,6 +195,9 @@ async function cmdUpdate() {
|
|
|
173
195
|
if (prFlowMigrated) {
|
|
174
196
|
configChanged = true;
|
|
175
197
|
}
|
|
198
|
+
if (sandboxToolsMigrated) {
|
|
199
|
+
configChanged = true;
|
|
200
|
+
}
|
|
176
201
|
if (configChanged) {
|
|
177
202
|
console.log('');
|
|
178
203
|
if (hasNewEntries) {
|
|
@@ -200,6 +225,9 @@ async function cmdUpdate() {
|
|
|
200
225
|
if (prFlowMigrated) {
|
|
201
226
|
info(`Migrated legacy requiresPullRequest to prFlow="${prFlowMigrated}" in ${CONFIG_PATH}.`);
|
|
202
227
|
}
|
|
228
|
+
if (sandboxToolsMigrated) {
|
|
229
|
+
info(`Migrated default sandbox.tools to include ${AGENT_INFRA_SANDBOX_TOOL} in ${CONFIG_PATH}.`);
|
|
230
|
+
}
|
|
203
231
|
}
|
|
204
232
|
else {
|
|
205
233
|
info(`File registry changed in ${CONFIG_PATH}.`);
|
|
@@ -219,6 +247,9 @@ async function cmdUpdate() {
|
|
|
219
247
|
if (hasNewEntries && prFlowMigrated) {
|
|
220
248
|
info(`Migrated legacy requiresPullRequest to prFlow="${prFlowMigrated}" in ${CONFIG_PATH}.`);
|
|
221
249
|
}
|
|
250
|
+
if (hasNewEntries && sandboxToolsMigrated) {
|
|
251
|
+
info(`Migrated default sandbox.tools to include ${AGENT_INFRA_SANDBOX_TOOL} in ${CONFIG_PATH}.`);
|
|
252
|
+
}
|
|
222
253
|
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
223
254
|
ok(`Updated ${CONFIG_PATH}`);
|
|
224
255
|
}
|