@fitlab-ai/agent-infra 0.8.2 → 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/dist/bin/cli.js +1 -1
- package/dist/lib/cp.js +1 -1
- package/dist/lib/decide.js +2 -2
- package/dist/lib/defaults.json +1 -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 +67 -65
- 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 +10 -4
- 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/tools.js +2 -2
- package/dist/lib/server/adapters/feishu/index.js +10 -3
- package/dist/lib/server/adapters/feishu/renderer.js +88 -0
- package/dist/lib/server/adapters/feishu/transport.js +2 -13
- 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 +2 -2
- 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 +4 -4
- package/lib/defaults.json +1 -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 +84 -64
- package/lib/sandbox/commands/rebuild.ts +42 -54
- package/lib/sandbox/config.ts +13 -1
- package/lib/sandbox/constants.ts +4 -0
- package/lib/sandbox/image-build.ts +134 -0
- package/lib/server/adapters/_contract.ts +3 -0
- package/lib/server/adapters/feishu/index.ts +11 -3
- package/lib/server/adapters/feishu/renderer.ts +99 -0
- package/lib/server/adapters/feishu/transport.ts +5 -18
- package/lib/server/daemon.ts +74 -38
- package/lib/server/display.ts +136 -0
- 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/package.json +2 -2
- 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 +7 -0
- 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
package/lib/task/commands/log.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { formatTable } from '../../table.ts';
|
|
3
3
|
import { resolveTaskRef } from '../resolve-ref.ts';
|
|
4
|
-
import { parseLedger,
|
|
4
|
+
import { parseLedger, type LedgerRow } from '../ledger.ts';
|
|
5
5
|
|
|
6
6
|
const USAGE = `Usage: ai task log <N | #N | TASK-id>
|
|
7
7
|
|
|
@@ -14,7 +14,7 @@ Columns: # (row) / STEP / AGENT / STARTED / DONE / NOTE
|
|
|
14
14
|
A human-executed step shows AGENT as 'human' and, when it has no start marker,
|
|
15
15
|
a '-' STARTED placeholder. Review-step NOTE also carries two human counts in
|
|
16
16
|
the verdict list, right after blockers/major/minor: manual-validation
|
|
17
|
-
and human-decision (current ledger stage total).
|
|
17
|
+
and human-decision (current pending ledger stage total).
|
|
18
18
|
`;
|
|
19
19
|
|
|
20
20
|
const TABLE_HEADERS = ['#', 'STEP', 'AGENT', 'STARTED', 'DONE', 'NOTE'] as const;
|
|
@@ -108,7 +108,7 @@ function pairEntries(entries: LogEntry[]): StepRow[] {
|
|
|
108
108
|
function countHumanDecisionsByStage(rows: LedgerRow[]): Map<ReviewStage, number> {
|
|
109
109
|
const counts = new Map<ReviewStage, number>();
|
|
110
110
|
for (const row of rows) {
|
|
111
|
-
if (!isReviewStage(row.stage) ||
|
|
111
|
+
if (!isReviewStage(row.stage) || row.status !== 'needs-human-decision') continue;
|
|
112
112
|
counts.set(row.stage, (counts.get(row.stage) ?? 0) + 1);
|
|
113
113
|
}
|
|
114
114
|
return counts;
|
|
@@ -6,7 +6,9 @@ import { resolveTaskRef } from '../resolve-ref.ts';
|
|
|
6
6
|
import { enumerateArtifacts, type Artifact } from '../artifacts.ts';
|
|
7
7
|
import { parseTaskFrontmatter, extractTitle, type Frontmatter } from '../frontmatter.ts';
|
|
8
8
|
import { loadShortIdByTaskId } from '../short-id.ts';
|
|
9
|
+
import { getOpenWorkflowWarnings, formatWorkflowWarningSummary, type WorkflowWarning } from '../workflow-warnings.ts';
|
|
9
10
|
import { parseActivityLog, pairEntries } from './log.ts';
|
|
11
|
+
import { statusCard, type DisplayMessage } from '../../server/display.ts';
|
|
10
12
|
|
|
11
13
|
const USAGE = `Usage: ai task status <N | #N | TASK-id>
|
|
12
14
|
|
|
@@ -322,12 +324,28 @@ type StatusModel = {
|
|
|
322
324
|
shortId: string;
|
|
323
325
|
title: string;
|
|
324
326
|
metadata: [string, string][];
|
|
327
|
+
workflowWarnings: WorkflowWarning[];
|
|
325
328
|
artifacts: { count: number; groups: { stage: string; files: string[] }[] };
|
|
326
329
|
workflow: WorkflowInfo;
|
|
327
330
|
runtime: RuntimeInfo;
|
|
328
331
|
git: GitInfo;
|
|
329
332
|
};
|
|
330
333
|
|
|
334
|
+
type BuildStatusModelInput = {
|
|
335
|
+
taskId: string;
|
|
336
|
+
taskDir: string;
|
|
337
|
+
taskMdPath: string;
|
|
338
|
+
repoRoot: string;
|
|
339
|
+
shortId?: string;
|
|
340
|
+
run?: Runner;
|
|
341
|
+
now?: Date;
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
type BuildStatusModelOptions = {
|
|
345
|
+
run?: Runner;
|
|
346
|
+
now?: Date;
|
|
347
|
+
};
|
|
348
|
+
|
|
331
349
|
// Indent each label/value pair by two spaces and pad labels to a common width so
|
|
332
350
|
// every section reads as an aligned "key value" block.
|
|
333
351
|
function renderPairs(rows: [string, string][]): string[] {
|
|
@@ -343,6 +361,14 @@ function renderStatus(model: StatusModel): string[] {
|
|
|
343
361
|
|
|
344
362
|
lines.push('', 'Metadata', ...renderPairs(model.metadata));
|
|
345
363
|
|
|
364
|
+
if (model.workflowWarnings.length > 0) {
|
|
365
|
+
lines.push(
|
|
366
|
+
'',
|
|
367
|
+
`Workflow Warnings (${model.workflowWarnings.length} open)`,
|
|
368
|
+
...formatWorkflowWarningSummary(model.workflowWarnings).map((line) => ` ${line}`)
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
|
|
346
372
|
lines.push('', `Artifacts (${model.artifacts.count})`);
|
|
347
373
|
if (model.artifacts.groups.length === 0) {
|
|
348
374
|
lines.push(' (none)');
|
|
@@ -394,36 +420,89 @@ function renderStatus(model: StatusModel): string[] {
|
|
|
394
420
|
return lines;
|
|
395
421
|
}
|
|
396
422
|
|
|
397
|
-
function
|
|
398
|
-
if (
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
return;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
const resolved = resolveTaskRef(args[0]!);
|
|
405
|
-
if (!resolved.ok) {
|
|
406
|
-
process.stderr.write(`ai task status: ${resolved.message}\n`);
|
|
407
|
-
process.exitCode = 1;
|
|
408
|
-
return;
|
|
423
|
+
function modelTone(model: StatusModel): 'info' | 'success' | 'warning' | 'danger' | 'running' {
|
|
424
|
+
if (model.workflow.state === 'in-progress') return model.workflow.stale === 'yes' ? 'warning' : 'running';
|
|
425
|
+
if (model.metadata.some(([key, value]) => key === 'status' && value === 'completed')) return 'success';
|
|
426
|
+
if (model.metadata.some(([key, value]) => key === 'status' && (value === 'blocked' || value === 'cancelled'))) {
|
|
427
|
+
return 'danger';
|
|
409
428
|
}
|
|
429
|
+
return 'info';
|
|
430
|
+
}
|
|
410
431
|
|
|
411
|
-
|
|
432
|
+
function buildFromResolved(input: BuildStatusModelInput): StatusModel {
|
|
433
|
+
const content = fs.readFileSync(input.taskMdPath, 'utf8');
|
|
412
434
|
const fm = parseTaskFrontmatter(content);
|
|
413
|
-
const run = makeRunner(
|
|
414
|
-
const artifacts = enumerateArtifacts(
|
|
415
|
-
const workflow = collectWorkflow(content);
|
|
435
|
+
const run = input.run ?? makeRunner(input.repoRoot);
|
|
436
|
+
const artifacts = enumerateArtifacts(input.taskDir);
|
|
437
|
+
const workflow = collectWorkflow(content, input.now);
|
|
416
438
|
|
|
417
|
-
|
|
418
|
-
taskId:
|
|
419
|
-
shortId: loadShortIdByTaskId(
|
|
439
|
+
return {
|
|
440
|
+
taskId: input.taskId,
|
|
441
|
+
shortId: input.shortId ?? loadShortIdByTaskId(input.repoRoot).get(input.taskId) ?? DASH,
|
|
420
442
|
title: extractTitle(content),
|
|
421
443
|
metadata: collectMetadata(fm),
|
|
444
|
+
workflowWarnings: getOpenWorkflowWarnings(content),
|
|
422
445
|
artifacts: { count: artifacts.length, groups: groupArtifacts(artifacts) },
|
|
423
446
|
workflow,
|
|
424
|
-
runtime: collectRuntime(
|
|
447
|
+
runtime: collectRuntime(input.taskDir, workflow, run),
|
|
425
448
|
git: collectGit(fm.branch ?? '', run)
|
|
426
449
|
};
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function buildStatusModel(ref: string, options?: BuildStatusModelOptions): StatusModel;
|
|
453
|
+
function buildStatusModel(input: BuildStatusModelInput): StatusModel;
|
|
454
|
+
function buildStatusModel(
|
|
455
|
+
refOrInput: string | BuildStatusModelInput,
|
|
456
|
+
options: BuildStatusModelOptions = {}
|
|
457
|
+
): StatusModel {
|
|
458
|
+
if (typeof refOrInput !== 'string') {
|
|
459
|
+
return buildFromResolved(refOrInput);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const resolved = resolveTaskRef(refOrInput);
|
|
463
|
+
if (!resolved.ok) {
|
|
464
|
+
throw new Error(resolved.message);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
return buildFromResolved({
|
|
468
|
+
taskId: resolved.taskId,
|
|
469
|
+
taskDir: resolved.taskDir,
|
|
470
|
+
taskMdPath: resolved.taskMdPath,
|
|
471
|
+
repoRoot: resolved.repoRoot,
|
|
472
|
+
run: options.run,
|
|
473
|
+
now: options.now
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function statusModelToDisplay(model: StatusModel): DisplayMessage {
|
|
478
|
+
return statusCard(
|
|
479
|
+
`Task ${model.taskId} (${model.shortId})`,
|
|
480
|
+
modelTone(model),
|
|
481
|
+
[
|
|
482
|
+
['workflow', model.workflow.state],
|
|
483
|
+
['step', model.workflow.step],
|
|
484
|
+
['runtime', model.runtime.status],
|
|
485
|
+
['git', model.git.uncommitted]
|
|
486
|
+
],
|
|
487
|
+
renderStatus(model).join('\n')
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function status(args: string[] = []): void {
|
|
492
|
+
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
493
|
+
process.stdout.write(USAGE);
|
|
494
|
+
if (args.length === 0) process.exitCode = 1;
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
let model: StatusModel;
|
|
499
|
+
try {
|
|
500
|
+
model = buildStatusModel(args[0]!);
|
|
501
|
+
} catch (error) {
|
|
502
|
+
process.stderr.write(`ai task status: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
503
|
+
process.exitCode = 1;
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
427
506
|
|
|
428
507
|
for (const line of renderStatus(model)) {
|
|
429
508
|
process.stdout.write(`${line}\n`);
|
|
@@ -433,12 +512,14 @@ function status(args: string[] = []): void {
|
|
|
433
512
|
export {
|
|
434
513
|
status,
|
|
435
514
|
makeRunner,
|
|
515
|
+
buildStatusModel,
|
|
436
516
|
collectMetadata,
|
|
437
517
|
groupArtifacts,
|
|
438
518
|
collectGit,
|
|
439
519
|
collectWorkflow,
|
|
440
520
|
collectRuntime,
|
|
441
521
|
renderStatus,
|
|
522
|
+
statusModelToDisplay,
|
|
442
523
|
METADATA_KEYS
|
|
443
524
|
};
|
|
444
|
-
export type { Runner, GitInfo, WorkflowInfo, RuntimeInfo, StatusModel };
|
|
525
|
+
export type { Runner, GitInfo, WorkflowInfo, RuntimeInfo, StatusModel, BuildStatusModelInput };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { extractSection } from './sections.ts';
|
|
2
|
+
|
|
3
|
+
const WORKFLOW_WARNING_HEADINGS = ['工作流告警', 'Workflow Warnings'];
|
|
4
|
+
const WORKFLOW_WARNING_STATUSES = new Set(['open', 'resolved', 'ignored']);
|
|
5
|
+
const WORKFLOW_WARNING_SEVERITIES = new Set(['IMPORTANT', 'ACTION_REQUIRED']);
|
|
6
|
+
|
|
7
|
+
type WorkflowWarning = {
|
|
8
|
+
id: string;
|
|
9
|
+
time: string;
|
|
10
|
+
step: string;
|
|
11
|
+
severity: string;
|
|
12
|
+
code: string;
|
|
13
|
+
status: string;
|
|
14
|
+
target: string;
|
|
15
|
+
message: string;
|
|
16
|
+
action: string;
|
|
17
|
+
resolvedAt: string;
|
|
18
|
+
resolution: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function splitTableRow(line: string): string[] {
|
|
22
|
+
let value = line.trim();
|
|
23
|
+
if (!value.startsWith('|')) return [];
|
|
24
|
+
value = value.replace(/^\|/, '').replace(/\|$/, '');
|
|
25
|
+
|
|
26
|
+
const cells: string[] = [];
|
|
27
|
+
let cell = '';
|
|
28
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
29
|
+
const char = value[index]!;
|
|
30
|
+
if (char === '|' && !isEscapedAt(value, index)) {
|
|
31
|
+
cells.push(unescapeTableCell(cell.trim()));
|
|
32
|
+
cell = '';
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
cell += char;
|
|
36
|
+
}
|
|
37
|
+
cells.push(unescapeTableCell(cell.trim()));
|
|
38
|
+
return cells;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function unescapeTableCell(value: string): string {
|
|
42
|
+
let output = '';
|
|
43
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
44
|
+
const char = value[index]!;
|
|
45
|
+
const next = value[index + 1];
|
|
46
|
+
if (char === '\\' && (next === '\\' || next === '|')) {
|
|
47
|
+
output += next;
|
|
48
|
+
index += 1;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
output += char;
|
|
52
|
+
}
|
|
53
|
+
return output;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function isEscapedAt(value: string, index: number): boolean {
|
|
57
|
+
let backslashes = 0;
|
|
58
|
+
for (let cursor = index - 1; cursor >= 0 && value[cursor] === '\\'; cursor -= 1) {
|
|
59
|
+
backslashes += 1;
|
|
60
|
+
}
|
|
61
|
+
return backslashes % 2 === 1;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function isSeparatorRow(cells: string[]): boolean {
|
|
65
|
+
return cells.length > 0 && cells.every((cell) => /^:?-{3,}:?$/.test(cell));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Parses well-formed workflow warning rows. Malformed rows are intentionally
|
|
70
|
+
* ignored here; validate-artifact is responsible for reporting structure errors.
|
|
71
|
+
*/
|
|
72
|
+
function parseWorkflowWarnings(content: string): WorkflowWarning[] {
|
|
73
|
+
const section = extractSection(content, WORKFLOW_WARNING_HEADINGS);
|
|
74
|
+
if (!section) return [];
|
|
75
|
+
|
|
76
|
+
const rows: WorkflowWarning[] = [];
|
|
77
|
+
for (const rawLine of section.split(/\r?\n/)) {
|
|
78
|
+
const cells = splitTableRow(rawLine);
|
|
79
|
+
if (cells.length === 0) continue;
|
|
80
|
+
if ((cells[0] ?? '').toLowerCase() === 'id') continue;
|
|
81
|
+
if (isSeparatorRow(cells)) continue;
|
|
82
|
+
if (cells.length < 11) continue;
|
|
83
|
+
|
|
84
|
+
rows.push({
|
|
85
|
+
id: cells[0] ?? '',
|
|
86
|
+
time: cells[1] ?? '',
|
|
87
|
+
step: cells[2] ?? '',
|
|
88
|
+
severity: cells[3] ?? '',
|
|
89
|
+
code: cells[4] ?? '',
|
|
90
|
+
status: cells[5] ?? '',
|
|
91
|
+
target: cells[6] ?? '',
|
|
92
|
+
message: cells[7] ?? '',
|
|
93
|
+
action: cells[8] ?? '',
|
|
94
|
+
resolvedAt: cells[9] ?? '',
|
|
95
|
+
resolution: cells[10] ?? ''
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return rows;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function getOpenWorkflowWarnings(content: string): WorkflowWarning[] {
|
|
102
|
+
return parseWorkflowWarnings(content).filter((warning) => warning.status === 'open');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function formatWorkflowWarningSummary(warnings: readonly WorkflowWarning[]): string[] {
|
|
106
|
+
return warnings.map((warning) => {
|
|
107
|
+
const target = warning.target ? ` ${warning.target}` : '';
|
|
108
|
+
const action = warning.action ? ` - ${warning.action}` : '';
|
|
109
|
+
return `${warning.id} [${warning.severity}] ${warning.code}${target}${action}`;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export {
|
|
114
|
+
WORKFLOW_WARNING_HEADINGS,
|
|
115
|
+
WORKFLOW_WARNING_STATUSES,
|
|
116
|
+
WORKFLOW_WARNING_SEVERITIES,
|
|
117
|
+
parseWorkflowWarnings,
|
|
118
|
+
getOpenWorkflowWarnings,
|
|
119
|
+
formatWorkflowWarningSummary
|
|
120
|
+
};
|
|
121
|
+
export type { WorkflowWarning };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fitlab-ai/agent-infra",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "Bootstrap tool for AI multi-tool collaboration infrastructure — works with Claude Code, Codex, Gemini CLI, and OpenCode",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"@types/cross-spawn": "^6.0.6",
|
|
68
68
|
"@types/node": "^22.20.0",
|
|
69
69
|
"@types/semver": "^7.7.1",
|
|
70
|
-
"typescript": "~
|
|
70
|
+
"typescript": "~7.0"
|
|
71
71
|
},
|
|
72
72
|
"optionalDependencies": {
|
|
73
73
|
"@lydell/node-pty": "^1.2.0-beta.12"
|
|
@@ -101,7 +101,7 @@ If the final label set is empty, omit the `--label` argument.
|
|
|
101
101
|
| `feature`, `enhancement` | `Feature` |
|
|
102
102
|
| `task`, `documentation`, `dependency-upgrade`, `chore`, `docs`, `refactor`, `refactoring`, others | `Task` |
|
|
103
103
|
|
|
104
|
-
When applying the Issue Type, follow the "Set Issue Type" command in `.agents/rules/issue-pr-commands.md`; first call `gh api orgs/{owner}/issue-types` to list the org's actually available Types, and only set the inferred value when it is present in that list.
|
|
104
|
+
When applying the Issue Type, follow the "Set Issue Type" command in `.agents/rules/issue-pr-commands.md`; only when the owner type is `Organization`, first call `gh api orgs/{owner}/issue-types` to list the org's actually available Types, and only set the inferred value when it is present in that list. User repositories, failed owner type probes, and failed writes are non-blocking.
|
|
105
105
|
|
|
106
106
|
#### milestone
|
|
107
107
|
|
|
@@ -149,7 +149,7 @@ After success, parse the Issue number from the output (match only the `https://.
|
|
|
149
149
|
|
|
150
150
|
### 6. Set Issue Type (Optional)
|
|
151
151
|
|
|
152
|
-
Execute only when `has_push=true` and the Issue Type inferred in §4 is in the org's actually available list:
|
|
152
|
+
Execute only when `has_push=true`, the owner type is `Organization`, and the Issue Type inferred in §4 is in the org's actually available list:
|
|
153
153
|
|
|
154
154
|
```bash
|
|
155
155
|
gh api "repos/$upstream_repo/issues/{issue-number}" -X PATCH \
|
|
@@ -188,4 +188,4 @@ Hand the following back to the caller `create-task`:
|
|
|
188
188
|
- Auth failure / command unavailable: return a structured `{code: "AUTH_FAILED", message}` to `create-task`; do not modify task.md
|
|
189
189
|
- Network timeout / DNS failure: `{code: "NETWORK", message}`
|
|
190
190
|
- Template parsing failure, Issue number parsing failure, other anomalies: `{code: "VALIDATION", message}`
|
|
191
|
-
- All failures keep task.md untouched; `create-task`
|
|
191
|
+
- All failures keep task.md untouched; `create-task` must record the structured error in `## Workflow Warnings` (`severity=ACTION_REQUIRED`, `code=ISSUE_CREATE_FAILED`, `target=issue`) before taking the "Scenario C: failure fallback" output branch and prompting the user to retry manually or fill `issue_number` later
|
|
@@ -101,7 +101,7 @@ ai task issue-body {task-id} > "{body-file}"
|
|
|
101
101
|
| `feature`, `enhancement` | `Feature` |
|
|
102
102
|
| `task`, `documentation`, `dependency-upgrade`, `chore`, `docs`, `refactor`, `refactoring` 及其它 | `Task` |
|
|
103
103
|
|
|
104
|
-
实际设置时按 `.agents/rules/issue-pr-commands.md` 的 "设置 Issue Type"
|
|
104
|
+
实际设置时按 `.agents/rules/issue-pr-commands.md` 的 "设置 Issue Type" 命令;仅当 owner type 为 `Organization` 时,先调 `gh api orgs/{owner}/issue-types` 列出 org 实际可用的 Type,并且仅当推断值在列表中时才设置;个人仓库、owner type 探测失败或设置失败都不阻断流程。
|
|
105
105
|
|
|
106
106
|
#### milestone
|
|
107
107
|
|
|
@@ -149,7 +149,7 @@ gh issue create -R "$upstream_repo" \
|
|
|
149
149
|
|
|
150
150
|
### 6. 设置 Issue Type(可选)
|
|
151
151
|
|
|
152
|
-
仅当 `has_push=true`
|
|
152
|
+
仅当 `has_push=true`、owner type 为 `Organization`,且 §4 推断的 Issue Type 在 org 实际可用列表中时执行:
|
|
153
153
|
|
|
154
154
|
```bash
|
|
155
155
|
gh api "repos/$upstream_repo/issues/{issue-number}" -X PATCH \
|
|
@@ -188,4 +188,4 @@ gh api "repos/$upstream_repo/issues/{issue-number}" -X PATCH \
|
|
|
188
188
|
- 认证失败 / 命令不可用:返回结构化错误 `{code: "AUTH_FAILED", message}` 给 `create-task`,不修改 task.md
|
|
189
189
|
- 网络超时 / DNS 失败:`{code: "NETWORK", message}`
|
|
190
190
|
- 模板解析失败、Issue 编号解析失败、其它异常:`{code: "VALIDATION", message}`
|
|
191
|
-
- 任意失败均不回滚 task.md;`create-task`
|
|
191
|
+
- 任意失败均不回滚 task.md;`create-task` 必须把结构化错误写入 `## 工作流告警`(`severity=ACTION_REQUIRED`,`code=ISSUE_CREATE_FAILED`,`target=issue`),再走"场景 C 失败兜底"输出,提示用户手动重试或在事后写入 `issue_number`
|
|
@@ -83,11 +83,16 @@ gh issue create -R "$upstream_repo" --title "{title}" --body "{body}" --assignee
|
|
|
83
83
|
Set the Issue Type:
|
|
84
84
|
|
|
85
85
|
```bash
|
|
86
|
-
gh api "
|
|
87
|
-
|
|
86
|
+
owner_type=$(gh api "repos/$upstream_repo" --jq '.owner.type // empty' 2>/dev/null || true)
|
|
87
|
+
if [ "$owner_type" = "Organization" ]; then
|
|
88
|
+
owner=${upstream_repo%%/*}
|
|
89
|
+
gh api "orgs/$owner/issue-types" --jq '.[].name'
|
|
90
|
+
gh api "repos/$upstream_repo/issues/{issue-number}" -X PATCH -f type="{issue-type}" --silent
|
|
91
|
+
fi
|
|
88
92
|
```
|
|
89
93
|
|
|
90
94
|
- set the Issue Type only when `has_push=true`; otherwise skip and continue
|
|
95
|
+
- query and set Issue Type only when the owner type is `Organization`; skip and continue for user repositories or failed owner type probes
|
|
91
96
|
- when changing an existing Issue Type, read `.agents/rules/issue-fields.md` and use Flow B so same-name pinned fields are migrated and fields absent from the new type are cleared
|
|
92
97
|
|
|
93
98
|
## Update Issues
|
|
@@ -83,11 +83,16 @@ gh issue create -R "$upstream_repo" --title "{title}" --body "{body}" --assignee
|
|
|
83
83
|
设置 Issue Type:
|
|
84
84
|
|
|
85
85
|
```bash
|
|
86
|
-
gh api "
|
|
87
|
-
|
|
86
|
+
owner_type=$(gh api "repos/$upstream_repo" --jq '.owner.type // empty' 2>/dev/null || true)
|
|
87
|
+
if [ "$owner_type" = "Organization" ]; then
|
|
88
|
+
owner=${upstream_repo%%/*}
|
|
89
|
+
gh api "orgs/$owner/issue-types" --jq '.[].name'
|
|
90
|
+
gh api "repos/$upstream_repo/issues/{issue-number}" -X PATCH -f type="{issue-type}" --silent
|
|
91
|
+
fi
|
|
88
92
|
```
|
|
89
93
|
|
|
90
94
|
- 仅当 `has_push=true` 时执行 Issue Type 设置;否则跳过并继续
|
|
95
|
+
- 仅当 owner type 为 `Organization` 时查询和设置 Issue Type;个人仓库或 owner type 探测失败时跳过并继续
|
|
91
96
|
- 变更现有 Issue Type 时,先读取 `.agents/rules/issue-fields.md` 并使用流程 B,确保同名 pinned fields 迁移,且新 type 不包含的字段被清空
|
|
92
97
|
|
|
93
98
|
## Issue 更新
|
|
@@ -66,6 +66,17 @@ Key rules:
|
|
|
66
66
|
- insufficient permission only affects direct Issue metadata writes and must not stop the skill
|
|
67
67
|
- keep the existing `2>/dev/null || true` error-tolerance pattern
|
|
68
68
|
|
|
69
|
+
When the caller has a `{task-id}` / task directory, permission degradation or critical sync failure must be recorded in `## Workflow Warnings`:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
node .agents/scripts/workflow-warnings.js add .agents/workspace/active/{task-id} \
|
|
73
|
+
--step issue-sync --severity IMPORTANT --code PERMISSION_DEGRADED \
|
|
74
|
+
--target "{operation}" --message "{reason}" \
|
|
75
|
+
--action "Wait for the bot/maintainer to backfill, or rerun the workflow step after permissions are available"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Comment create/update failures and exhausted network retries that affect reviewer visibility use `severity=ACTION_REQUIRED` with `code=COMMENT_SYNC_FAILED` or `NETWORK_RETRY_EXHAUSTED`.
|
|
79
|
+
|
|
69
80
|
## External Contributor Locking
|
|
70
81
|
|
|
71
82
|
Maintainers (`has_triage=true`) are never blocked. External contributors (`has_triage=false`) must check whether the current task already has a `task` comment author on the Issue before they start.
|
|
@@ -210,6 +221,8 @@ EOF
|
|
|
210
221
|
|
|
211
222
|
Comment publishing is not gated by `has_triage` or `has_push`.
|
|
212
223
|
|
|
224
|
+
If comment lookup, creation, or update fails and the caller has a task directory, record a Workflow Warning (`step=issue-sync`, `severity=ACTION_REQUIRED`, `code=COMMENT_SYNC_FAILED`, `target={file-stem}`) and surface it in the final Workflow Warnings output block.
|
|
225
|
+
|
|
213
226
|
## task.md Comment Sync
|
|
214
227
|
|
|
215
228
|
Hidden marker:
|
|
@@ -66,6 +66,17 @@ has_push=$(printf '%s' "$repo_perms" | grep -q '"push":true' 2>/dev/null && echo
|
|
|
66
66
|
- 权限不足只影响直接写 Issue 元数据的步骤,不中断整个技能
|
|
67
67
|
- 现有 `2>/dev/null || true` 容错模式保持不变
|
|
68
68
|
|
|
69
|
+
当调用方存在 `{task-id}` / task 目录时,权限降级或关键同步失败必须写入 `## 工作流告警`:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
node .agents/scripts/workflow-warnings.js add .agents/workspace/active/{task-id} \
|
|
73
|
+
--step issue-sync --severity IMPORTANT --code PERMISSION_DEGRADED \
|
|
74
|
+
--target "{operation}" --message "{reason}" \
|
|
75
|
+
--action "等待 bot/维护者补位,或在具备权限后重跑对应 workflow 步骤"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
评论创建 / 更新失败、网络重试耗尽等影响后续 reviewer 可见性的失败使用 `severity=ACTION_REQUIRED` 和 `code=COMMENT_SYNC_FAILED` 或 `NETWORK_RETRY_EXHAUSTED`。
|
|
79
|
+
|
|
69
80
|
## 外部开发者锁定机制
|
|
70
81
|
|
|
71
82
|
维护者(`has_triage=true`)不受限制。外部开发者(`has_triage=false`)在开始任务前,必须先检查 Issue 上是否已有当前任务的 `task` 留言作者。
|
|
@@ -210,6 +221,8 @@ EOF
|
|
|
210
221
|
|
|
211
222
|
评论发布不受 `has_triage` / `has_push` 限制,认证用户可正常执行。
|
|
212
223
|
|
|
224
|
+
若评论查询、创建或更新失败且调用方有关联任务目录,记录 Workflow Warning(`step=issue-sync`、`severity=ACTION_REQUIRED`、`code=COMMENT_SYNC_FAILED`、`target={file-stem}`),并在最终输出的 Workflow Warnings 块提示人工处理。
|
|
225
|
+
|
|
213
226
|
## task.md 评论同步
|
|
214
227
|
|
|
215
228
|
隐藏标记:
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# Next-Step Output Rule
|
|
2
2
|
|
|
3
|
-
This file defines
|
|
3
|
+
This file defines four **independent** rules for a skill's "notify-user / Next steps" output (the 3rd applies to review-* only); read this file before rendering the final output and apply whichever rules apply:
|
|
4
4
|
|
|
5
5
|
1. **Next-step output structure**: how "Next steps" commands and the "Task info" block present the task ID (placeholders / short-id lookup / fallback).
|
|
6
6
|
2. **Agent output trailing line (Completed at)**: the **very last line** of user-facing output, **independent of the "Next steps" block**, applying to normal / error / early-return paths alike.
|
|
7
7
|
3. **Pending human-decision pre-block**: applies only to `review-analysis` / `review-plan` / `review-code` when this stage has pending rulings (`{h} > 0`) — expand the pending items before the "Next steps" commands and prompt to resolve them first.
|
|
8
|
+
4. **Workflow Warnings output block**: applies when task.md has `status=open` rows in `## Workflow Warnings` — print the warning summary after all normal information and "Next steps" commands, and before `Completed at`.
|
|
8
9
|
|
|
9
10
|
## Placeholder semantics
|
|
10
11
|
|
|
@@ -62,6 +63,19 @@ Completed at: YYYY-MM-DD HH:mm:ss
|
|
|
62
63
|
- Position: it must be the last line of the entire user-facing output, after all "Next steps" commands. If a scenario has a conditional reminder line after the commands (e.g. the manual-validation reminder), the completion line goes after that reminder.
|
|
63
64
|
- This line is for terminal scanning only; it is never written to any artifact file or Issue/PR comment. The single source of truth for completion time remains the Activity Log in task.md.
|
|
64
65
|
|
|
66
|
+
## Workflow Warnings Output Block
|
|
67
|
+
|
|
68
|
+
If the current task's `## Workflow Warnings` / `## 工作流告警` table has any `status=open` row, the skill's final user output must append a summary block after all normal information and "Next steps" commands, and before `Completed at`. When no open warning exists, do not render this block.
|
|
69
|
+
|
|
70
|
+
Format:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
[ACTION REQUIRED] Workflow warnings are open:
|
|
74
|
+
- WW-N {code} ({target}): {action}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Use `[ACTION REQUIRED]` when any open row has `severity=ACTION_REQUIRED`; otherwise use `[IMPORTANT]`. `{code}`, `{target}`, and `{action}` come directly from the warning table columns.
|
|
78
|
+
|
|
65
79
|
## Pending human-decision pre-block (review-* only, when {h} > 0)
|
|
66
80
|
|
|
67
81
|
This section is a **third standalone rule, co-equal with the two above**, used only by the "notify-user / report conclusion" step of `review-analysis` / `review-plan` / `review-code`.
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# 下一步输出规则
|
|
2
2
|
|
|
3
|
-
本文件定义 skill「告知用户 /
|
|
3
|
+
本文件定义 skill「告知用户 / 下一步」输出的四类**相互独立**的规则(第 3 类仅 review-* 适用);渲染最终输出前先读取本文件并落实其中适用的规则:
|
|
4
4
|
|
|
5
5
|
1. **下一步输出结构**:「下一步」命令与「任务信息」段如何呈现任务 ID 形态(占位符 / 取短号 / 回退)。
|
|
6
6
|
2. **Agent 输出收尾行(Completed at)**:面向用户输出的**绝对最后一行**,**独立于「下一步」块**,正常 / 错误 / 早退路径都适用。
|
|
7
7
|
3. **人工裁决待办前置块**:仅 `review-analysis` / `review-plan` / `review-code`,且本阶段存在待裁决项(`{h} > 0`)时适用——在「下一步」命令前展开待裁决项并提示先完成裁决。
|
|
8
|
+
4. **Workflow Warnings 输出块**:当前 task.md 存在 `status=open` 的 `## 工作流告警` 行时适用——在所有常规信息和「下一步」命令之后、`Completed at` 之前输出告警摘要。
|
|
8
9
|
|
|
9
10
|
## 占位符语义
|
|
10
11
|
|
|
@@ -62,6 +63,19 @@ Completed at: YYYY-MM-DD HH:mm:ss
|
|
|
62
63
|
- 位置:必须是整段面向用户输出的最后一行,排在所有「下一步」命令之后。若某场景在命令之后还有条件性提醒行(如 manual-validation 提醒),收尾行排在该提醒行之后。
|
|
63
64
|
- 该行只用于终端扫视,不写入任何产物文件或 Issue/PR 评论;完成时刻的单一事实源仍是 task.md 的 Activity Log。
|
|
64
65
|
|
|
66
|
+
## Workflow Warnings 输出块
|
|
67
|
+
|
|
68
|
+
若当前任务的 `## 工作流告警` / `## Workflow Warnings` 表中存在 `status=open` 行,skill 最终输出必须在所有常规信息和「下一步」命令之后、`Completed at` 之前追加摘要块;无 open 告警时不输出本块。
|
|
69
|
+
|
|
70
|
+
格式:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
[ACTION REQUIRED] Workflow warnings are open:
|
|
74
|
+
- WW-N {code} ({target}): {action}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`severity=ACTION_REQUIRED` 的行使用 `[ACTION REQUIRED]`;只有 `IMPORTANT` 行时使用 `[IMPORTANT]`。`{code}`、`{target}`、`{action}` 直接来自告警表对应列。
|
|
78
|
+
|
|
65
79
|
## 人工裁决待办前置块(review-* 专用,{h} > 0 时)
|
|
66
80
|
|
|
67
81
|
本节是与上面两类规则**并列的第三类独立规则**,仅 `review-analysis` / `review-plan` / `review-code` 的「向用户汇报结论」步骤使用。
|
|
@@ -7,6 +7,7 @@ Read this file before syncing the single reviewer-facing PR summary comment.
|
|
|
7
7
|
Current callers:
|
|
8
8
|
- `create-pr`: create or update the summary comment when the PR is opened
|
|
9
9
|
- `commit`: refresh the summary comment on an existing PR when needed
|
|
10
|
+
- `complete-manual-validation`: update the summary comment in place after manual validation passes, and write a validation artifact that later aggregation can reuse
|
|
10
11
|
|
|
11
12
|
If another skill needs to refresh the PR summary later, point that skill's reference file at this rule first, then document only the skill-specific trigger and failure behavior there.
|
|
12
13
|
|
|
@@ -26,17 +27,22 @@ Aggregate the latest artifacts in the task directory:
|
|
|
26
27
|
- `plan.md` or the latest `plan-r{N}.md`
|
|
27
28
|
- `code.md` or the latest `code-r{N}.md`
|
|
28
29
|
- `review-code.md` or the latest `review-code-r{N}.md`
|
|
30
|
+
- `manual-validation.md` or the latest `manual-validation-r{N}.md`
|
|
29
31
|
|
|
30
32
|
Aggregation rules:
|
|
31
33
|
- extract 2-4 self-contained technical decisions from `plan*`
|
|
32
34
|
- build the review-history table from `review-code*` and `code*`
|
|
33
35
|
- extract the test summary from `code*`
|
|
36
|
+
- if the latest `manual-validation*` artifact has a passed verdict, render the manual-validation section first as `### ✅ Manual Validation Passed`, with a concise validation time, scope, and notes summary
|
|
34
37
|
- if one artifact class is missing, treat it as "no data for this stage" and continue
|
|
35
38
|
- Manual verification section: include only post-code-stage checks that still require a human to execute or judge and that the AI cannot close on its own.
|
|
36
39
|
- **Admission boundary**: the verification result depends on a real environment, permissions, account, external system, or human judgment, and cannot be closed by an agent rerunning tests, adding checks, or continuing the fix loop.
|
|
37
40
|
- **Sources**: `review-code*` "Manual Validation Items", plus `code*` items that satisfy the boundary above.
|
|
38
41
|
- **Wording**: each retained item must state at least "what to verify + location (file/change/scope) + why only a human can verify it".
|
|
39
|
-
- **
|
|
42
|
+
- **Rendering priority**:
|
|
43
|
+
1. the latest `manual-validation*` artifact has a passed verdict -> heading `### ✅ Manual Validation Passed` + validation summary.
|
|
44
|
+
2. no passed artifact and retained items exist -> heading `### ⚠️ Manual Verification Required` + item list.
|
|
45
|
+
3. no passed artifact and no retained items -> heading `### ✅ No Manual Verification Needed` and a single line `No items in this change require manual confirmation.`, with no item list.
|
|
40
46
|
|
|
41
47
|
## Comment Body Template
|
|
42
48
|
|
|
@@ -72,7 +78,7 @@ Use this canonical comment body template:
|
|
|
72
78
|
*Generated by {agent} · Internal tracking: {task-id}*
|
|
73
79
|
```
|
|
74
80
|
|
|
75
|
-
> Render `{manual-validation-section}` per the "manual verification section" aggregation rule above:
|
|
81
|
+
> Render `{manual-validation-section}` per the "manual verification section" aggregation rule above: passed artifact → `### ✅ Manual Validation Passed` heading + validation summary; retained items → `### ⚠️ Manual Verification Required` heading + quote + item list; none → `### ✅ No Manual Verification Needed` heading + a single line `No items in this change require manual confirmation.` (no ⚠️, no list).
|
|
76
82
|
|
|
77
83
|
## Comment Lookup And Update
|
|
78
84
|
|
|
@@ -111,6 +117,15 @@ EOF
|
|
|
111
117
|
| `gh api` GET/PATCH/POST fails | warn and continue; whether the current skill should block is decided by the caller |
|
|
112
118
|
| `pr_number` points to a missing PR | warn with `PR #{pr-number} not found` and continue |
|
|
113
119
|
|
|
120
|
+
When the caller has a `{task-id}` / task directory and GET/PATCH/POST fails, record a Workflow Warning:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
node .agents/scripts/workflow-warnings.js add .agents/workspace/active/{task-id} \
|
|
124
|
+
--step pr-sync --severity ACTION_REQUIRED --code COMMENT_SYNC_FAILED \
|
|
125
|
+
--target "pr-summary" --message "{reason}" \
|
|
126
|
+
--action "Fix GitHub API / network issues and rerun the workflow step that triggers PR summary sync"
|
|
127
|
+
```
|
|
128
|
+
|
|
114
129
|
## Result Reporting
|
|
115
130
|
|
|
116
131
|
Return one of these normalized results so callers can reuse it in Activity Log entries or user output:
|