@fitlab-ai/agent-infra 0.9.3 → 0.9.4

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.
Files changed (175) hide show
  1. package/README.md +2 -0
  2. package/README.zh-CN.md +2 -0
  3. package/bin/cli.ts +12 -0
  4. package/dist/bin/cli.js +14 -0
  5. package/dist/bin/internal-cli.js +134 -123
  6. package/dist/lib/agent-clients/adapter.js +92 -2
  7. package/dist/lib/{sandbox/credentials.js → agent-clients/adapters/claude-code-credentials.js} +4 -14
  8. package/dist/lib/agent-clients/adapters/claude-code-refresh.js +85 -0
  9. package/dist/lib/agent-clients/adapters/claude-code-sandbox.js +247 -0
  10. package/dist/lib/agent-clients/adapters/claude-code.js +17 -3
  11. package/dist/lib/agent-clients/adapters/opencode-sandbox.js +108 -0
  12. package/dist/lib/agent-clients/adapters/opencode.js +15 -3
  13. package/dist/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
  14. package/dist/lib/agent-clients/registry.js +9 -1
  15. package/dist/lib/internal/sandbox-control.js +24 -0
  16. package/dist/lib/internal/task-activity.js +45 -13
  17. package/dist/lib/internal/task-ledger.js +12 -3
  18. package/dist/lib/internal/task-lifecycle.js +19 -1
  19. package/dist/lib/internal/task-orchestration.js +122 -18
  20. package/dist/lib/platform/github-client.js +19 -2
  21. package/dist/lib/platform/pr-checks.js +1 -1
  22. package/dist/lib/platform/pull-requests.js +47 -1
  23. package/dist/lib/platform/releases.js +13 -5
  24. package/dist/lib/process-data/index.js +239 -0
  25. package/dist/lib/process-data/normalize.js +198 -0
  26. package/dist/lib/process-data/privacy.js +33 -0
  27. package/dist/lib/process-data/reconcile.js +95 -0
  28. package/dist/lib/process-data/repair.js +58 -0
  29. package/dist/lib/process-data/sources.js +345 -0
  30. package/dist/lib/process-data/store.js +282 -0
  31. package/dist/lib/process-data/types.js +2 -0
  32. package/dist/lib/run/index.js +4 -3
  33. package/dist/lib/run/tui.js +7 -8
  34. package/dist/lib/sandbox/agent-client-reconciler.js +26 -2
  35. package/dist/lib/sandbox/capture.js +7 -2
  36. package/dist/lib/sandbox/commands/create.js +109 -228
  37. package/dist/lib/sandbox/commands/enter.js +15 -47
  38. package/dist/lib/sandbox/commands/list-running.js +16 -6
  39. package/dist/lib/sandbox/commands/ls.js +10 -6
  40. package/dist/lib/sandbox/commands/rebuild.js +4 -3
  41. package/dist/lib/sandbox/commands/refresh.js +4 -84
  42. package/dist/lib/sandbox/commands/rm.js +24 -3
  43. package/dist/lib/sandbox/commands/show.js +12 -3
  44. package/dist/lib/sandbox/commands/start.js +7 -4
  45. package/dist/lib/sandbox/config.js +2 -0
  46. package/dist/lib/sandbox/constants.js +6 -0
  47. package/dist/lib/sandbox/control/client.js +44 -0
  48. package/dist/lib/sandbox/control/protocol.js +35 -0
  49. package/dist/lib/sandbox/control/server.js +109 -0
  50. package/dist/lib/sandbox/dockerfile.js +36 -13
  51. package/dist/lib/sandbox/mounts.js +17 -4
  52. package/dist/lib/sandbox/recovery.js +128 -5
  53. package/dist/lib/sandbox/redaction.js +12 -0
  54. package/dist/lib/sandbox/runtimes/base.dockerfile +24 -74
  55. package/dist/lib/sandbox/workspace-identity.js +95 -0
  56. package/dist/lib/sandbox/workspace-view.js +103 -0
  57. package/dist/lib/task/activity-intent.js +257 -51
  58. package/dist/lib/task/commit-finalization.js +267 -0
  59. package/dist/lib/task/commit-intent.js +165 -0
  60. package/dist/lib/task/decision-intents.js +31 -17
  61. package/dist/lib/task/delegation-receipts.js +2 -2
  62. package/dist/lib/task/implementation-inputs.js +54 -7
  63. package/dist/lib/task/ledger-intents.js +35 -1
  64. package/dist/lib/task/orchestration.js +363 -28
  65. package/dist/lib/task/resolve-ref.js +41 -1
  66. package/lib/agent-clients/adapter.ts +126 -2
  67. package/lib/{sandbox/credentials.ts → agent-clients/adapters/claude-code-credentials.ts} +3 -18
  68. package/lib/agent-clients/adapters/claude-code-refresh.ts +128 -0
  69. package/lib/agent-clients/adapters/claude-code-sandbox.ts +295 -0
  70. package/lib/agent-clients/adapters/claude-code.ts +21 -3
  71. package/lib/agent-clients/adapters/opencode-sandbox.ts +136 -0
  72. package/lib/agent-clients/adapters/opencode.ts +18 -3
  73. package/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
  74. package/lib/agent-clients/registry.ts +9 -1
  75. package/lib/internal/sandbox-control.ts +24 -0
  76. package/lib/internal/task-activity.ts +50 -14
  77. package/lib/internal/task-ledger.ts +12 -3
  78. package/lib/internal/task-lifecycle.ts +22 -1
  79. package/lib/internal/task-orchestration.ts +81 -11
  80. package/lib/platform/github-client.ts +20 -2
  81. package/lib/platform/pr-checks.ts +1 -1
  82. package/lib/platform/pull-requests.ts +49 -1
  83. package/lib/platform/releases.ts +16 -4
  84. package/lib/process-data/index.ts +224 -0
  85. package/lib/process-data/normalize.ts +202 -0
  86. package/lib/process-data/privacy.ts +41 -0
  87. package/lib/process-data/reconcile.ts +110 -0
  88. package/lib/process-data/repair.ts +64 -0
  89. package/lib/process-data/sources.ts +354 -0
  90. package/lib/process-data/store.ts +315 -0
  91. package/lib/process-data/types.ts +135 -0
  92. package/lib/run/index.ts +5 -3
  93. package/lib/run/tui.ts +11 -8
  94. package/lib/sandbox/agent-client-reconciler.ts +44 -2
  95. package/lib/sandbox/capture.ts +9 -2
  96. package/lib/sandbox/commands/create.ts +126 -260
  97. package/lib/sandbox/commands/enter.ts +13 -59
  98. package/lib/sandbox/commands/list-running.ts +23 -6
  99. package/lib/sandbox/commands/ls.ts +22 -6
  100. package/lib/sandbox/commands/rebuild.ts +4 -3
  101. package/lib/sandbox/commands/refresh.ts +4 -126
  102. package/lib/sandbox/commands/rm.ts +24 -3
  103. package/lib/sandbox/commands/show.ts +29 -3
  104. package/lib/sandbox/commands/start.ts +6 -4
  105. package/lib/sandbox/config.ts +4 -0
  106. package/lib/sandbox/constants.ts +8 -0
  107. package/lib/sandbox/control/client.ts +55 -0
  108. package/lib/sandbox/control/protocol.ts +75 -0
  109. package/lib/sandbox/control/server.ts +117 -0
  110. package/lib/sandbox/dockerfile.ts +66 -13
  111. package/lib/sandbox/mounts.ts +24 -4
  112. package/lib/sandbox/recovery.ts +163 -6
  113. package/lib/sandbox/redaction.ts +14 -0
  114. package/lib/sandbox/runtimes/base.dockerfile +24 -74
  115. package/lib/sandbox/tool-types.ts +16 -0
  116. package/lib/sandbox/workspace-identity.ts +123 -0
  117. package/lib/sandbox/workspace-view.ts +143 -0
  118. package/lib/task/activity-intent.ts +350 -61
  119. package/lib/task/commit-finalization.ts +356 -0
  120. package/lib/task/commit-intent.ts +230 -0
  121. package/lib/task/decision-intents.ts +32 -12
  122. package/lib/task/delegation-receipts.ts +2 -2
  123. package/lib/task/implementation-inputs.ts +62 -8
  124. package/lib/task/ledger-intents.ts +43 -3
  125. package/lib/task/orchestration.ts +501 -33
  126. package/lib/task/resolve-ref.ts +46 -1
  127. package/package.json +1 -1
  128. package/templates/.agents/rules/README.en.md +1 -1
  129. package/templates/.agents/rules/README.zh-CN.md +1 -1
  130. package/templates/.agents/rules/human-decision-context.en.md +11 -2
  131. package/templates/.agents/rules/human-decision-context.zh-CN.md +11 -2
  132. package/templates/.agents/rules/pr-checks-commands.en.md +1 -1
  133. package/templates/.agents/rules/pr-checks-commands.github.en.md +1 -1
  134. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +2 -2
  135. package/templates/.agents/rules/pr-checks-commands.zh-CN.md +1 -1
  136. package/templates/.agents/rules/review-handshake.zh-CN.md +1 -1
  137. package/templates/.agents/rules/task-management.en.md +2 -0
  138. package/templates/.agents/rules/task-management.zh-CN.md +2 -0
  139. package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
  140. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +1 -1
  141. package/templates/.agents/skills/commit/SKILL.en.md +21 -11
  142. package/templates/.agents/skills/commit/SKILL.zh-CN.md +27 -11
  143. package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +49 -0
  144. package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +55 -0
  145. package/templates/.agents/skills/commit/reference/task-status-update.en.md +4 -4
  146. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +4 -4
  147. package/templates/.agents/skills/complete-task/SKILL.en.md +1 -1
  148. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +1 -1
  149. package/templates/.agents/skills/create-pr/SKILL.en.md +4 -4
  150. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +4 -4
  151. package/templates/.agents/skills/create-task/reference/context-capture.en.md +34 -0
  152. package/templates/.agents/skills/create-task/reference/context-capture.zh-CN.md +34 -0
  153. package/templates/.agents/skills/review-code/SKILL.en.md +2 -2
  154. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +2 -2
  155. package/templates/.agents/skills/review-code/reference/output-templates.en.md +1 -1
  156. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +1 -1
  157. package/templates/.agents/skills/review-pr/SKILL.en.md +36 -8
  158. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +36 -8
  159. package/templates/.agents/skills/review-pr/reference/report-template.en.md +1 -1
  160. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +1 -1
  161. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +67 -50
  162. package/templates/.agents/skills/watch-pr/SKILL.en.md +4 -4
  163. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +4 -4
  164. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +2 -2
  165. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +2 -2
  166. package/templates/.agents/templates/task.en.md +1 -1
  167. package/templates/.agents/templates/task.zh-CN.md +1 -1
  168. package/templates/.claude/commands/watch-pr.en.md +1 -1
  169. package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
  170. package/templates/.claude/rules/tool-preferences.en.md +20 -0
  171. package/templates/.claude/rules/tool-preferences.zh-CN.md +20 -0
  172. package/templates/.opencode/commands/watch-pr.en.md +1 -1
  173. package/templates/.opencode/commands/watch-pr.zh-CN.md +1 -1
  174. package/templates/.gemini/commands/_project_/review-pr.en.toml +0 -10
  175. package/templates/.gemini/commands/_project_/review-pr.zh-CN.toml +0 -10
@@ -8,7 +8,7 @@ const COLUMNS = [
8
8
  const TIMESTAMP_RE = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}$/;
9
9
  const ARTIFACT_RE = /^code(?:-r(?:[2-9]|[1-9]\d+))?\.md$/;
10
10
 
11
- type ImplementationInputStatus = 'pending' | 'not-required' | 'consumed';
11
+ type ImplementationInputStatus = 'declared' | 'pending' | 'not-required' | 'consumed';
12
12
  type ImplementationInput = {
13
13
  id: string;
14
14
  ledgerId: string;
@@ -25,18 +25,18 @@ type ImplementationInputDraft = {
25
25
  needsImplementation: boolean;
26
26
  decidedAt: string;
27
27
  };
28
+ type ImplementationInputDeclaration = Omit<ImplementationInputDraft, 'decidedAt'>;
28
29
 
29
30
  function validateInput(row: ImplementationInput): void {
30
31
  if (!/^II-[1-9]\d*$/.test(row.id)) throw new Error(`implementation input id '${row.id}' is invalid`);
31
32
  if (!row.ledgerId || !row.decisionEvidence || /[\r\n]/.test(row.ledgerId) || /[\r\n]/.test(row.decisionEvidence)) throw new Error(`implementation input ${row.id} has incomplete decision identity`);
32
33
  if (row.stage !== 'code') throw new Error(`implementation input ${row.id} has invalid stage`);
33
- if (!TIMESTAMP_RE.test(row.decidedAt) || !Number.isFinite(Date.parse(row.decidedAt.replace(' ', 'T')))) {
34
- throw new Error(`implementation input ${row.id} has invalid decided_at`);
35
- }
34
+ const hasValidTimestamp = TIMESTAMP_RE.test(row.decidedAt) && Number.isFinite(Date.parse(row.decidedAt.replace(' ', 'T')));
36
35
  const valid =
37
- (row.needsImplementation && row.status === 'pending' && row.consumedBy === '') ||
38
- (!row.needsImplementation && row.status === 'not-required' && row.consumedBy === '') ||
39
- (row.needsImplementation && row.status === 'consumed' && ARTIFACT_RE.test(row.consumedBy));
36
+ (row.status === 'declared' && row.decidedAt === '' && row.consumedBy === '') ||
37
+ (hasValidTimestamp && row.needsImplementation && row.status === 'pending' && row.consumedBy === '') ||
38
+ (hasValidTimestamp && !row.needsImplementation && row.status === 'not-required' && row.consumedBy === '') ||
39
+ (hasValidTimestamp && row.needsImplementation && row.status === 'consumed' && ARTIFACT_RE.test(row.consumedBy));
40
40
  if (!valid) throw new Error(`implementation input ${row.id} has an invalid state combination`);
41
41
  }
42
42
 
@@ -79,6 +79,57 @@ function createImplementationInput(rows: readonly ImplementationInput[], draft:
79
79
  return row;
80
80
  }
81
81
 
82
+ function declareImplementationInput(
83
+ rows: readonly ImplementationInput[], draft: ImplementationInputDeclaration
84
+ ): ImplementationInput {
85
+ const existing = rows.filter((row) => row.ledgerId === draft.ledgerId && row.status === 'declared');
86
+ if (existing.length > 1) throw new Error(`implementation input declaration for '${draft.ledgerId}' conflicts with existing rows`);
87
+ if (existing.length === 1) {
88
+ const row = existing[0]!;
89
+ if (row.decisionEvidence !== draft.decisionEvidence || row.needsImplementation !== draft.needsImplementation) {
90
+ throw new Error(`implementation input declaration for '${draft.ledgerId}' conflicts with the existing row`);
91
+ }
92
+ return row;
93
+ }
94
+ const row: ImplementationInput = {
95
+ id: nextId(rows), ledgerId: draft.ledgerId, decisionEvidence: draft.decisionEvidence,
96
+ stage: 'code', needsImplementation: draft.needsImplementation, decidedAt: '',
97
+ status: 'declared', consumedBy: ''
98
+ };
99
+ validateInput(row);
100
+ return row;
101
+ }
102
+
103
+ function selectDeclaredImplementationInput(
104
+ rows: readonly ImplementationInput[], ledgerId: string, decisionEvidence: string
105
+ ): ImplementationInput | null {
106
+ const forLedger = rows.filter((row) => row.ledgerId === ledgerId && row.status === 'declared');
107
+ if (forLedger.length > 1) throw new Error(`implementation input declaration for '${ledgerId}' is ambiguous`);
108
+ if (forLedger.length === 0) return null;
109
+ if (forLedger[0]!.decisionEvidence !== decisionEvidence) {
110
+ throw new Error(`implementation input declaration for '${ledgerId}' has conflicting evidence`);
111
+ }
112
+ return forLedger[0]!;
113
+ }
114
+
115
+ function finalizeImplementationInput(
116
+ rows: readonly ImplementationInput[], id: string, decisionEvidence: string, decidedAt: string
117
+ ): ImplementationInput[] {
118
+ let found = false;
119
+ const next = rows.map((row) => {
120
+ if (row.id !== id) return row;
121
+ found = true;
122
+ if (row.status !== 'declared') throw new Error(`implementation input ${id} is not declared`);
123
+ return {
124
+ ...row, decisionEvidence, decidedAt,
125
+ status: row.needsImplementation ? 'pending' as const : 'not-required' as const
126
+ };
127
+ });
128
+ if (!found) throw new Error(`implementation input ${id} was not found`);
129
+ next.forEach(validateInput);
130
+ return next;
131
+ }
132
+
82
133
  function selectPendingImplementationInput(
83
134
  rows: readonly ImplementationInput[], reviewCompletedAt: string
84
135
  ): ImplementationInput | null {
@@ -130,8 +181,11 @@ export {
130
181
  SECTION_ALIASES as IMPLEMENTATION_INPUT_ALIASES,
131
182
  createImplementationInput,
132
183
  consumeImplementationInput,
184
+ declareImplementationInput,
185
+ finalizeImplementationInput,
133
186
  parseImplementationInputs,
134
187
  renderImplementationInputs,
188
+ selectDeclaredImplementationInput,
135
189
  selectPendingImplementationInput
136
190
  };
137
- export type { ImplementationInput, ImplementationInputDraft, ImplementationInputStatus };
191
+ export type { ImplementationInput, ImplementationInputDeclaration, ImplementationInputDraft, ImplementationInputStatus };
@@ -1,6 +1,12 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
 
4
+ import {
5
+ declareImplementationInput,
6
+ IMPLEMENTATION_INPUT_ALIASES,
7
+ parseImplementationInputs,
8
+ renderImplementationInputs
9
+ } from './implementation-inputs.ts';
4
10
  import { LEDGER_COLUMNS, LEDGER_HEADINGS, nextHdId, parseLedger, validateLedgerRows } from './ledger.ts';
5
11
  import type { LedgerRow, ReviewStage } from './ledger.ts';
6
12
  import { resolveTaskRef } from './resolve-ref.ts';
@@ -13,9 +19,9 @@ type ReviewDisposition = 'confirmed' | 'closed' | 'open' | 'needs-human-decision
13
19
  type LedgerIntent =
14
20
  | { kind: 'finding-upsert'; taskRef: string; stage: ReviewStage; reviewArtifact: string; ordinal: number; severity: ReviewSeverity; evidence: string; dryRun?: boolean }
15
21
  | { kind: 'finding-respond'; taskRef: string; id: string; round: number; status: ExecutorResponse; evidence: string; dryRun?: boolean }
16
- | { kind: 'finding-review'; taskRef: string; id: string; status: ReviewDisposition; evidence: string; dryRun?: boolean }
22
+ | { kind: 'finding-review'; taskRef: string; id: string; status: ReviewDisposition; evidence: string; needsImplementation?: boolean; dryRun?: boolean }
17
23
  | { kind: 'decision-next-id'; taskRef: string }
18
- | { kind: 'decision-upsert'; taskRef: string; id: string; stage: ReviewStage; artifact: string; dryRun?: boolean };
24
+ | { kind: 'decision-upsert'; taskRef: string; id: string; stage: ReviewStage; artifact: string; needsImplementation?: boolean; dryRun?: boolean };
19
25
 
20
26
  type LedgerIntentError = { code: string; message: string };
21
27
  type LedgerIntentResult = {
@@ -97,6 +103,15 @@ function ledgerSectionMutation(content: string): TaskMutation[] {
97
103
  }];
98
104
  }
99
105
 
106
+ function implementationInputMutation(content: string, rows: Parameters<typeof renderImplementationInputs>[0]): TaskMutation {
107
+ const english = /^##\s+Activity Log\s*$/m.test(content);
108
+ return {
109
+ kind: 'section', aliases: IMPLEMENTATION_INPUT_ALIASES,
110
+ heading: english ? 'Implementation Inputs' : '实现输入',
111
+ body: renderImplementationInputs(rows)
112
+ };
113
+ }
114
+
100
115
  function mapWrite(intent: LedgerIntent, entityId: string, before: LedgerRow | null, after: LedgerRow, result: ReturnType<typeof writeTask>): LedgerIntentResult {
101
116
  if (result.status === 'failed') return failed(intent, result.error.code, result.error.message, result.taskId, entityId);
102
117
  return { status: result.status, changed: result.changed, intent: intent.kind, taskId: result.taskId, entityId, before, after, operations: result.operations, error: null };
@@ -189,9 +204,34 @@ function applyLedgerIntent(intent: LedgerIntent, options: TaskWriteOptions = {})
189
204
  }
190
205
  }
191
206
 
207
+ let implementationMutation: TaskMutation | null = null;
208
+ if (intent.kind === 'decision-upsert' || intent.kind === 'finding-review') {
209
+ const stage = intent.kind === 'decision-upsert' ? intent.stage : after.stage;
210
+ const escalates = intent.kind === 'decision-upsert' || intent.status === 'needs-human-decision';
211
+ if (stage === 'code' && escalates && intent.needsImplementation === undefined) {
212
+ return failed(intent, 'LEDGER_PAYLOAD_INVALID', 'code-stage decisions require --needs-implementation true|false', resolved.taskId, after.id);
213
+ }
214
+ if ((stage !== 'code' || !escalates) && intent.needsImplementation !== undefined) {
215
+ return failed(intent, 'LEDGER_PAYLOAD_INVALID', '--needs-implementation is only valid for code-stage escalation', resolved.taskId, after.id);
216
+ }
217
+ if (stage === 'code' && escalates) {
218
+ try {
219
+ const parsed = parseImplementationInputs(content);
220
+ const declaration = declareImplementationInput(parsed.rows, {
221
+ ledgerId: after.id, decisionEvidence: after.evidence,
222
+ needsImplementation: intent.needsImplementation!
223
+ });
224
+ const nextRows = parsed.rows.includes(declaration) ? parsed.rows : [...parsed.rows, declaration];
225
+ implementationMutation = implementationInputMutation(content, nextRows);
226
+ } catch (error) {
227
+ return failed(intent, 'LEDGER_DOCUMENT_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId, after.id);
228
+ }
229
+ }
230
+ }
231
+
192
232
  const result = writeTask({
193
233
  taskRef: intent.taskRef, expectedState: 'active',
194
- mutations: [...ledgerSectionMutation(content), rowMutation(after)],
234
+ mutations: [...ledgerSectionMutation(content), rowMutation(after), ...(implementationMutation ? [implementationMutation] : [])],
195
235
  dryRun: 'dryRun' in intent ? intent.dryRun : false
196
236
  }, { ...options, taskLocation: { repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, state: resolved.state } });
197
237
  return mapWrite(intent, after.id, before, after, result);