@fitlab-ai/agent-infra 0.12.0 → 0.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -2
- package/README.zh-CN.md +0 -2
- package/dist/bin/internal-cli.js +2 -17
- package/dist/lib/agent-clients/adapter.js +0 -13
- package/dist/lib/agent-clients/adapters/antigravity-cli.js +0 -5
- package/dist/lib/agent-clients/adapters/claude-code-credentials.js +0 -17
- package/dist/lib/agent-clients/adapters/claude-code.js +0 -9
- package/dist/lib/agent-clients/adapters/codex.js +0 -52
- package/dist/lib/agent-clients/adapters/opencode.js +0 -5
- package/dist/lib/agent-clients/adapters/traecli.js +0 -5
- package/dist/lib/agent-clients/config.js +19 -54
- package/dist/lib/agent-clients/registry.js +1 -12
- package/dist/lib/agent-clients/schema.js +0 -18
- package/dist/lib/agent-clients/tokens.js +1 -2
- package/dist/lib/agent-clients/types.js +0 -1
- package/dist/lib/decide.js +2 -0
- package/dist/lib/git/worktree-identity.js +1 -9
- package/dist/lib/internal/agent-client.js +2 -62
- package/dist/lib/internal/cli-route-inventory.js +1 -5
- package/dist/lib/internal/manual-validation.js +29 -27
- package/dist/lib/internal/platform-comment.js +56 -7
- package/dist/lib/internal/task-create.js +1 -1
- package/dist/lib/internal/task-event.js +1 -8
- package/dist/lib/internal/task-finalization.js +0 -1
- package/dist/lib/internal/task-lifecycle.js +2 -2
- package/dist/lib/internal/task-operation-registry.js +4 -20
- package/dist/lib/internal/task-review.js +4 -4
- package/dist/lib/platform/comment-safety.js +1 -7
- package/dist/lib/platform/in-label-sync.js +1 -14
- package/dist/lib/platform/issue-comments.js +373 -282
- package/dist/lib/platform/issue-summary-content.js +112 -0
- package/dist/lib/platform/issues.js +1 -1
- package/dist/lib/platform/operation-coordinator.js +4 -2
- package/dist/lib/platform/pr-change-report.js +176 -30
- package/dist/lib/platform/pr-checks.js +2 -8
- package/dist/lib/platform/pr-summary-content.js +54 -0
- package/dist/lib/platform/pr-summary.js +318 -284
- package/dist/lib/platform/provider-validation.js +0 -20
- package/dist/lib/platform/pull-requests.js +73 -84
- package/dist/lib/platform/releases.js +1 -43
- package/dist/lib/platform/summary-content-pipeline.js +18 -0
- package/dist/lib/platform/verification-required.js +0 -2
- package/dist/lib/platform/verification-sync.js +1 -79
- package/dist/lib/process-data/normalize.js +1 -185
- package/dist/lib/process-data/privacy.js +1 -16
- package/dist/lib/process-data/sources.js +2 -279
- package/dist/lib/render.js +0 -12
- package/dist/lib/run/index.js +15 -10
- package/dist/lib/run/skills.js +0 -3
- package/dist/lib/sandbox/commands/create.js +40 -53
- package/dist/lib/sandbox/commands/list-running.js +0 -18
- package/dist/lib/sandbox/commands/start.js +7 -8
- package/dist/lib/sandbox/constants.js +0 -6
- package/dist/lib/sandbox/control/client.js +0 -1
- package/dist/lib/sandbox/control/container-identity.js +1 -16
- package/dist/lib/sandbox/control/executor.js +0 -4
- package/dist/lib/sandbox/control/identity-sentinel.js +0 -7
- package/dist/lib/sandbox/control/lifecycle.js +21 -37
- package/dist/lib/sandbox/control/native-file-lock.js +0 -3
- package/dist/lib/sandbox/control/server.js +18 -38
- package/dist/lib/sandbox/control/state.js +1 -9
- package/dist/lib/sandbox/dockerfile.js +0 -6
- package/dist/lib/sandbox/engine.js +0 -14
- package/dist/lib/sandbox/engines/docker-exact-discovery.js +1 -4
- package/dist/lib/sandbox/engines/wsl2-paths.js +0 -3
- package/dist/lib/sandbox/recovery.js +24 -26
- package/dist/lib/sandbox/removal.js +67 -518
- package/dist/lib/sandbox/task-resolver.js +0 -41
- package/dist/lib/sandbox/tools.js +1 -4
- package/dist/lib/sandbox/workspace-view.js +1 -2
- package/dist/lib/server/display.js +0 -6
- package/dist/lib/task/activity-intent.js +45 -40
- package/dist/lib/task/activity-log.js +9 -16
- package/dist/lib/task/artifact-command.js +1 -1
- package/dist/lib/task/artifact-lifecycle.js +61 -63
- package/dist/lib/task/artifact-name.js +0 -6
- package/dist/lib/task/artifact-operations.js +3 -3
- package/dist/lib/task/capabilities.js +4 -5
- package/dist/lib/task/commands/log.js +0 -6
- package/dist/lib/task/commands/status.js +17 -60
- package/dist/lib/task/commit-operation.js +28 -39
- package/dist/lib/task/completion-facts.js +56 -43
- package/dist/lib/task/control-authority.js +23 -256
- package/dist/lib/task/control-recovery.js +3 -5
- package/dist/lib/task/create.js +2 -4
- package/dist/lib/task/decision-intents.js +8 -9
- package/dist/lib/task/delivery-target.js +1 -40
- package/dist/lib/task/events.js +84 -107
- package/dist/lib/task/finalization.js +60 -15
- package/dist/lib/task/ledger-intents.js +1 -1
- package/dist/lib/task/lifecycle-execution.js +38 -33
- package/dist/lib/task/lifecycle.js +49 -41
- package/dist/lib/task/local-artifact-finalization.js +1 -4
- package/dist/lib/task/manual-validation-evidence.js +1 -37
- package/dist/lib/task/platform-operation-recovery.js +151 -108
- package/dist/lib/task/pr-delivery-fact.js +2 -5
- package/dist/lib/task/qualification-confirmation.js +5 -7
- package/dist/lib/task/resolve-ref.js +1 -25
- package/dist/lib/task/review-command.js +2 -2
- package/dist/lib/task/review-finalization.js +1 -21
- package/dist/lib/task/review-fingerprint.js +0 -4
- package/dist/lib/task/secure-fs.js +0 -56
- package/dist/lib/task/short-id.js +1 -39
- package/dist/lib/task/skill-scope.js +0 -1
- package/dist/lib/task/verification-engine.js +58 -282
- package/dist/lib/task/verification.js +6 -3
- package/dist/lib/task/write.js +11 -1
- package/lib/agent-clients/adapter.ts +0 -76
- package/lib/agent-clients/adapters/antigravity-cli.ts +0 -5
- package/lib/agent-clients/adapters/claude-code-credentials.ts +0 -19
- package/lib/agent-clients/adapters/claude-code.ts +0 -9
- package/lib/agent-clients/adapters/codex.ts +0 -56
- package/lib/agent-clients/adapters/opencode.ts +0 -5
- package/lib/agent-clients/adapters/traecli.ts +0 -5
- package/lib/agent-clients/config.ts +20 -61
- package/lib/agent-clients/registry.ts +1 -34
- package/lib/agent-clients/schema.ts +0 -18
- package/lib/agent-clients/tokens.ts +1 -2
- package/lib/agent-clients/types.ts +0 -15
- package/lib/decide.ts +1 -0
- package/lib/git/worktree-identity.ts +0 -10
- package/lib/internal/agent-client.ts +2 -70
- package/lib/internal/cli-route-inventory.ts +1 -4
- package/lib/internal/manual-validation.ts +28 -27
- package/lib/internal/platform-comment.ts +46 -4
- package/lib/internal/task-create.ts +0 -1
- package/lib/internal/task-event.ts +1 -5
- package/lib/internal/task-finalization.ts +0 -1
- package/lib/internal/task-lifecycle.ts +3 -5
- package/lib/internal/task-operation-registry.ts +3 -19
- package/lib/internal/task-review.ts +4 -4
- package/lib/platform/comment-safety.ts +0 -10
- package/lib/platform/github-provider.ts +0 -2
- package/lib/platform/in-label-sync.ts +0 -16
- package/lib/platform/issue-comments.ts +478 -301
- package/lib/platform/issue-summary-content.ts +132 -0
- package/lib/platform/issues.ts +0 -2
- package/lib/platform/operation-coordinator.ts +4 -2
- package/lib/platform/pr-change-report.ts +165 -25
- package/lib/platform/pr-checks.ts +1 -10
- package/lib/platform/pr-review.ts +1 -1
- package/lib/platform/pr-summary-content.ts +60 -0
- package/lib/platform/pr-summary.ts +364 -257
- package/lib/platform/provider-bridge.ts +0 -1
- package/lib/platform/provider-loader.ts +1 -5
- package/lib/platform/provider-validation.ts +1 -49
- package/lib/platform/pull-requests.ts +64 -99
- package/lib/platform/releases.ts +1 -40
- package/lib/platform/summary-content-pipeline.ts +23 -0
- package/lib/platform/verification-required.ts +0 -2
- package/lib/platform/verification-sync.ts +0 -94
- package/lib/process-data/normalize.ts +1 -186
- package/lib/process-data/privacy.ts +2 -19
- package/lib/process-data/sources.ts +3 -283
- package/lib/render.ts +0 -15
- package/lib/run/index.ts +13 -7
- package/lib/run/skills.ts +0 -4
- package/lib/sandbox/commands/create.ts +37 -74
- package/lib/sandbox/commands/list-running.ts +0 -19
- package/lib/sandbox/commands/start.ts +7 -10
- package/lib/sandbox/constants.ts +0 -8
- package/lib/sandbox/control/client.ts +0 -1
- package/lib/sandbox/control/container-identity.ts +1 -16
- package/lib/sandbox/control/executor.ts +1 -5
- package/lib/sandbox/control/identity-sentinel.ts +0 -8
- package/lib/sandbox/control/lifecycle.ts +18 -51
- package/lib/sandbox/control/native-file-lock.ts +0 -8
- package/lib/sandbox/control/protocol.ts +0 -2
- package/lib/sandbox/control/server.ts +13 -39
- package/lib/sandbox/control/state.ts +1 -10
- package/lib/sandbox/dockerfile.ts +0 -11
- package/lib/sandbox/engine.ts +0 -17
- package/lib/sandbox/engines/docker-exact-discovery.ts +1 -5
- package/lib/sandbox/engines/wsl2-paths.ts +0 -4
- package/lib/sandbox/recovery.ts +24 -26
- package/lib/sandbox/removal.ts +58 -687
- package/lib/sandbox/shell.ts +1 -1
- package/lib/sandbox/task-resolver.ts +0 -48
- package/lib/sandbox/tools.ts +1 -5
- package/lib/sandbox/workspace-view.ts +2 -4
- package/lib/server/display.ts +0 -14
- package/lib/server/process-control.ts +1 -1
- package/lib/task/activity-intent.ts +36 -44
- package/lib/task/activity-log.ts +9 -22
- package/lib/task/artifact-command.ts +1 -1
- package/lib/task/artifact-lifecycle.ts +58 -67
- package/lib/task/artifact-name.ts +0 -7
- package/lib/task/artifact-operations.ts +3 -3
- package/lib/task/capabilities.ts +5 -6
- package/lib/task/commands/log.ts +0 -7
- package/lib/task/commands/status.ts +14 -79
- package/lib/task/commit-operation.ts +29 -51
- package/lib/task/completion-facts.ts +45 -42
- package/lib/task/control-authority.ts +27 -317
- package/lib/task/control-recovery.ts +2 -5
- package/lib/task/create.ts +2 -5
- package/lib/task/decision-intents.ts +5 -5
- package/lib/task/delivery-target.ts +0 -40
- package/lib/task/events.ts +89 -123
- package/lib/task/finalization.ts +52 -15
- package/lib/task/ledger-intents.ts +1 -1
- package/lib/task/lifecycle-execution.ts +37 -89
- package/lib/task/lifecycle.ts +48 -44
- package/lib/task/local-artifact-finalization.ts +0 -7
- package/lib/task/manual-validation-evidence.ts +1 -47
- package/lib/task/platform-operation-recovery.ts +117 -104
- package/lib/task/pr-delivery-fact.ts +2 -11
- package/lib/task/qualification-confirmation.ts +6 -6
- package/lib/task/resolve-ref.ts +0 -23
- package/lib/task/review-command.ts +2 -2
- package/lib/task/review-finalization.ts +1 -27
- package/lib/task/review-fingerprint.ts +0 -8
- package/lib/task/secure-fs.ts +0 -42
- package/lib/task/short-id.ts +0 -43
- package/lib/task/skill-scope.ts +0 -1
- package/lib/task/verification-engine.ts +56 -287
- package/lib/task/verification.ts +5 -5
- package/lib/task/write.ts +12 -1
- package/package.json +2 -2
- package/templates/.agents/README.en.md +1 -3
- package/templates/.agents/README.zh-CN.md +0 -2
- package/templates/.agents/rules/README.en.md +0 -1
- package/templates/.agents/rules/README.zh-CN.md +0 -1
- package/templates/.agents/rules/commit-and-pr.en.md +1 -1
- package/templates/.agents/rules/commit-and-pr.zh-CN.md +1 -1
- package/templates/.agents/rules/no-mid-flow-questions.en.md +0 -10
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +0 -10
- package/templates/.agents/rules/pr-sync.en.md +4 -2
- package/templates/.agents/rules/pr-sync.zh-CN.md +6 -9
- package/templates/.agents/rules/task-management.en.md +3 -3
- package/templates/.agents/rules/task-management.zh-CN.md +3 -3
- package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/cancel-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/commit/SKILL.en.md +2 -2
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +6 -6
- package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +6 -6
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +2 -2
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +2 -2
- package/templates/.agents/skills/complete-task/SKILL.en.md +10 -25
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +11 -26
- package/templates/.agents/skills/create-pr/SKILL.en.md +1 -1
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/create-pr/reference/change-report.en.md +9 -2
- package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +9 -2
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +2 -2
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +2 -2
- package/templates/.agents/skills/create-task/SKILL.en.md +0 -18
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +0 -18
- package/templates/.agents/skills/plan-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-analysis/SKILL.en.md +3 -3
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-code/SKILL.en.md +5 -5
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/review-plan/SKILL.en.md +3 -3
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-pr/SKILL.en.md +4 -4
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +3 -75
- package/templates/.agents/skills/watch-pr/SKILL.en.md +1 -1
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +3 -3
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +3 -3
- package/templates/.agents/templates/task.en.md +1 -0
- package/templates/.agents/templates/task.zh-CN.md +1 -0
- package/templates/.claude/settings.json +0 -24
- package/templates/.codex/hooks.json +0 -50
- package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +0 -582
- package/dist/lib/agent-clients/adapters/codex-lifecycle/binding.js +0 -114
- package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +0 -237
- package/dist/lib/agent-clients/adapters/codex-lifecycle/cli.js +0 -443
- package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +0 -236
- package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +0 -292
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +0 -267
- package/dist/lib/agent-clients/adapters/codex-orchestration.js +0 -466
- package/dist/lib/internal/task-orchestration.js +0 -71
- package/dist/lib/platform/verification.js +0 -6
- package/dist/lib/run/prompt.js +0 -2
- package/dist/lib/sandbox/engines/authority.js +0 -289
- package/dist/lib/task/delegation-receipts.js +0 -410
- package/dist/lib/task/orchestration.js +0 -1233
- package/dist/lib/task/verification-checks.js +0 -9
- package/dist/lib/task/workspace-snapshot.js +0 -121
- package/dist/lifecycle-build-manifest.json +0 -6
- package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +0 -688
- package/lib/agent-clients/adapters/codex-lifecycle/binding.ts +0 -147
- package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +0 -349
- package/lib/agent-clients/adapters/codex-lifecycle/cli.ts +0 -506
- package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +0 -385
- package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +0 -41
- package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +0 -418
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +0 -354
- package/lib/agent-clients/adapters/codex-orchestration.ts +0 -630
- package/lib/internal/task-orchestration.ts +0 -74
- package/lib/platform/verification.ts +0 -11
- package/lib/run/prompt.ts +0 -1
- package/lib/sandbox/engines/authority.ts +0 -365
- package/lib/task/delegation-receipts.ts +0 -547
- package/lib/task/orchestration.ts +0 -1651
- package/lib/task/verification-checks.ts +0 -10
- package/lib/task/workspace-snapshot.ts +0 -144
- package/templates/.agents/hooks/lifecycle-delegation.js +0 -140
- package/templates/.agents/rules/lifecycle-orchestration.en.md +0 -44
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +0 -44
- package/templates/.agents/skills/run-task/SKILL.en.md +0 -29
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +0 -29
- package/templates/.agents/skills/run-task/config/verify.en.json +0 -10
- package/templates/.agents/skills/run-task/config/verify.zh-CN.json +0 -10
- package/templates/.agents/skills/run-task/reference/host-validation.en.md +0 -24
- package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +0 -24
- package/templates/.claude/agents/agent-infra-lifecycle-executor.en.md +0 -6
- package/templates/.claude/agents/agent-infra-lifecycle-executor.zh-CN.md +0 -6
- package/templates/.claude/agents/agent-infra-lifecycle-reviewer.en.md +0 -6
- package/templates/.claude/agents/agent-infra-lifecycle-reviewer.zh-CN.md +0 -6
- package/templates/.claude/commands/run-task.en.md +0 -8
- package/templates/.claude/commands/run-task.zh-CN.md +0 -8
- package/templates/.codex/agents/agent-infra-lifecycle-executor.en.toml +0 -3
- package/templates/.codex/agents/agent-infra-lifecycle-executor.zh-CN.toml +0 -3
- package/templates/.codex/agents/agent-infra-lifecycle-reviewer.en.toml +0 -3
- package/templates/.codex/agents/agent-infra-lifecycle-reviewer.zh-CN.toml +0 -3
- package/templates/.opencode/commands/run-task.en.md +0 -11
- package/templates/.opencode/commands/run-task.zh-CN.md +0 -11
|
@@ -1,198 +1,13 @@
|
|
|
1
1
|
import { sha256 } from './store.ts';
|
|
2
|
-
import { normalizeAgentToken } from '../agent-clients/tokens.ts';
|
|
3
2
|
|
|
4
3
|
import type { CapturedObject, JsonValue, NormalizedKind, NormalizedRecord } from './types.ts';
|
|
5
4
|
|
|
6
5
|
const TASK_ID_RE = /TASK-\d{8}-\d{6}/;
|
|
7
|
-
const ACTIVITY_RE = /^- (\d{4}-\d{2}-\d{2} [^ ]+) — \*\*(.+?)\*\* by ([^ ]+) — (.+)$/gm;
|
|
8
|
-
const LEDGER_RE = /^\|\s*((?:AN|PL|CD)-\d+)\s*\|\s*(analysis|plan|code)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|$/gm;
|
|
9
|
-
const RULING_RE = /^###\s+(HDR-\d+)\s*$([\s\S]*?)(?=^###\s+|^##\s+|(?![\s\S]))/gm;
|
|
10
|
-
const CONFLICT_STATUSES = new Set(['open', 'accepted', 'adjusted', 'refuted', 'cannot-judge', 'needs-human-decision']);
|
|
11
6
|
|
|
12
7
|
function recordId(kind: NormalizedKind, identity: string, suffix = ''): string {
|
|
13
8
|
return `${kind}:${sha256(`${identity}\0${suffix}`).slice(0, 24)}`;
|
|
14
9
|
}
|
|
15
10
|
|
|
16
|
-
function canonicalActor(raw: string): string | null {
|
|
17
|
-
const lowered = raw.toLowerCase();
|
|
18
|
-
return normalizeAgentToken(lowered);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function nextOccurrence(occurrences: Map<string, number>, identity: string): string {
|
|
22
|
-
const occurrence = (occurrences.get(identity) ?? 0) + 1;
|
|
23
|
-
occurrences.set(identity, occurrence);
|
|
24
|
-
return occurrence === 1 ? '' : `occurrence=${occurrence}`;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function normalizePlatformPage(object: CapturedObject): NormalizedRecord[] {
|
|
28
|
-
if (!object.content) return [];
|
|
29
|
-
try {
|
|
30
|
-
const page = JSON.parse(object.content) as unknown;
|
|
31
|
-
if (!Array.isArray(page)) return [];
|
|
32
|
-
return page.map((entry, index) => {
|
|
33
|
-
const value = entry as Record<string, unknown>;
|
|
34
|
-
const identity = String(value.id ?? value.node_id ?? value.sha ?? value.number ?? `${object.sourceIdentity}:${index}`);
|
|
35
|
-
const platformIdentity = /\/issues\?/.test(object.sourceIdentity) && typeof value.number === 'number'
|
|
36
|
-
? `issue:${value.number}`
|
|
37
|
-
: /\/pulls\?/.test(object.sourceIdentity) && typeof value.number === 'number'
|
|
38
|
-
? `pr:${value.number}`
|
|
39
|
-
: /\/issues\/\d+\/comments/.test(object.sourceIdentity)
|
|
40
|
-
? `issue-comment:${identity}`
|
|
41
|
-
: /\/pulls\/\d+\/reviews/.test(object.sourceIdentity)
|
|
42
|
-
? `review:${identity}`
|
|
43
|
-
: /\/pulls\/\d+\/commits/.test(object.sourceIdentity)
|
|
44
|
-
? `commit:${identity}`
|
|
45
|
-
: `platform:${identity}`;
|
|
46
|
-
const binding = typeof value.body === 'string' ? value.body.match(TASK_ID_RE)?.[0] : undefined;
|
|
47
|
-
return {
|
|
48
|
-
recordId: recordId('platform-resource', object.sourceIdentity, identity),
|
|
49
|
-
kind: 'platform-resource',
|
|
50
|
-
sourceIdentity: platformIdentity,
|
|
51
|
-
sourceSha256: object.sha256,
|
|
52
|
-
...(binding ? { binding } : {}),
|
|
53
|
-
data: entry as JsonValue
|
|
54
|
-
};
|
|
55
|
-
});
|
|
56
|
-
} catch {
|
|
57
|
-
return [];
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function normalizeObjects(objects: CapturedObject[]): NormalizedRecord[] {
|
|
62
|
-
const records: NormalizedRecord[] = [];
|
|
63
|
-
for (const object of objects) {
|
|
64
|
-
if (object.disposition?.state && object.disposition.state !== 'included') {
|
|
65
|
-
records.push({
|
|
66
|
-
recordId: recordId('missing', object.sourceIdentity),
|
|
67
|
-
kind: 'missing',
|
|
68
|
-
sourceIdentity: object.sourceIdentity,
|
|
69
|
-
sourceSha256: object.sha256,
|
|
70
|
-
data: object.disposition.state === 'excluded-sensitive'
|
|
71
|
-
? { reason: 'privacy-excluded', ruleId: object.disposition.ruleId }
|
|
72
|
-
: { reason: object.disposition.reason }
|
|
73
|
-
});
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
if (object.sourceKind === 'github-rest') {
|
|
77
|
-
records.push(...normalizePlatformPage(object));
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
if (object.sourceKind === 'operational-report') {
|
|
81
|
-
records.push({
|
|
82
|
-
recordId: recordId('operational-report', object.sourceIdentity),
|
|
83
|
-
kind: 'operational-report',
|
|
84
|
-
sourceIdentity: object.sourceIdentity,
|
|
85
|
-
sourceSha256: object.sha256
|
|
86
|
-
});
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
if (object.sourceKind === 'structured-telemetry') {
|
|
90
|
-
let data: JsonValue = { availability: 'unknown' };
|
|
91
|
-
try {
|
|
92
|
-
data = JSON.parse(object.content ?? '{}') as JsonValue;
|
|
93
|
-
} catch {
|
|
94
|
-
data = { availability: 'unavailable', reason: 'invalid receipt JSON' };
|
|
95
|
-
}
|
|
96
|
-
records.push({
|
|
97
|
-
recordId: recordId('telemetry', object.sourceIdentity),
|
|
98
|
-
kind: 'telemetry',
|
|
99
|
-
sourceIdentity: object.sourceIdentity,
|
|
100
|
-
sourceSha256: object.sha256,
|
|
101
|
-
data
|
|
102
|
-
});
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const taskId = object.sourceIdentity.match(TASK_ID_RE)?.[0];
|
|
107
|
-
if (/\/task\.md$/.test(object.sourceIdentity) && taskId) {
|
|
108
|
-
const activityOccurrences = new Map<string, number>();
|
|
109
|
-
const findingOccurrences = new Map<string, number>();
|
|
110
|
-
const issueNumber = object.content?.match(/^issue_number:\s*(\d+)$/m)?.[1];
|
|
111
|
-
const agentInfraVersion = object.content?.match(/^agent_infra_version:\s*(\S+)$/m)?.[1];
|
|
112
|
-
records.push({
|
|
113
|
-
recordId: recordId('task', taskId),
|
|
114
|
-
kind: 'task',
|
|
115
|
-
sourceIdentity: taskId,
|
|
116
|
-
sourceSha256: object.sha256,
|
|
117
|
-
...(issueNumber ? { binding: `issue:${issueNumber}` } : {}),
|
|
118
|
-
data: {
|
|
119
|
-
agentInfraVersion: agentInfraVersion
|
|
120
|
-
? { state: 'known', value: agentInfraVersion }
|
|
121
|
-
: { state: 'unknown', reason: 'legacy-task-missing-agent-infra-version' }
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
for (const match of object.content?.matchAll(ACTIVITY_RE) ?? []) {
|
|
125
|
-
const rawActor = match[3]!;
|
|
126
|
-
const identity = `${match[1]}:${match[2]}`;
|
|
127
|
-
const occurrence = nextOccurrence(activityOccurrences, identity);
|
|
128
|
-
records.push({
|
|
129
|
-
recordId: recordId('lifecycle-event', taskId, occurrence ? `${identity}\0${occurrence}` : identity),
|
|
130
|
-
kind: 'lifecycle-event',
|
|
131
|
-
sourceIdentity: `${taskId}#activity=${match[1]}`,
|
|
132
|
-
sourceSha256: object.sha256,
|
|
133
|
-
data: {
|
|
134
|
-
timestamp: match[1]!,
|
|
135
|
-
action: match[2]!,
|
|
136
|
-
actorRaw: rawActor,
|
|
137
|
-
actorCanonical: canonicalActor(rawActor),
|
|
138
|
-
note: match[4]!
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
for (const match of object.content?.matchAll(LEDGER_RE) ?? []) {
|
|
143
|
-
const findingId = match[1]!.trim();
|
|
144
|
-
const stage = match[2]!.trim();
|
|
145
|
-
const round = match[3]!.trim();
|
|
146
|
-
const severity = match[4]!.trim();
|
|
147
|
-
const status = match[5]!.trim();
|
|
148
|
-
const evidence = match[6]!.trim();
|
|
149
|
-
const identity = `${taskId}#finding=${findingId}`;
|
|
150
|
-
const occurrence = nextOccurrence(findingOccurrences, identity);
|
|
151
|
-
const data = { findingId, stage, round, severity, status, evidence };
|
|
152
|
-
records.push({
|
|
153
|
-
recordId: recordId('review-finding', identity, occurrence),
|
|
154
|
-
kind: 'review-finding',
|
|
155
|
-
sourceIdentity: identity,
|
|
156
|
-
sourceSha256: object.sha256,
|
|
157
|
-
binding: taskId,
|
|
158
|
-
data
|
|
159
|
-
});
|
|
160
|
-
if (status && CONFLICT_STATUSES.has(status)) {
|
|
161
|
-
records.push({
|
|
162
|
-
recordId: recordId('conflict', identity, occurrence),
|
|
163
|
-
kind: 'conflict',
|
|
164
|
-
sourceIdentity: `${identity}#status=${status}`,
|
|
165
|
-
sourceSha256: object.sha256,
|
|
166
|
-
binding: taskId,
|
|
167
|
-
data
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
for (const match of object.content?.matchAll(RULING_RE) ?? []) {
|
|
172
|
-
const rulingId = match[1]!;
|
|
173
|
-
const identity = `${taskId}#ruling=${rulingId}`;
|
|
174
|
-
records.push({
|
|
175
|
-
recordId: recordId('human-ruling', identity),
|
|
176
|
-
kind: 'human-ruling',
|
|
177
|
-
sourceIdentity: identity,
|
|
178
|
-
sourceSha256: object.sha256,
|
|
179
|
-
binding: taskId,
|
|
180
|
-
data: { rulingId, evidence: match[2]!.trim() }
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
continue;
|
|
184
|
-
}
|
|
185
|
-
records.push({
|
|
186
|
-
recordId: recordId('artifact', object.sourceIdentity),
|
|
187
|
-
kind: 'artifact',
|
|
188
|
-
sourceIdentity: object.sourceIdentity,
|
|
189
|
-
sourceSha256: object.sha256,
|
|
190
|
-
...(taskId ? { binding: taskId } : {})
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
return records.sort((left, right) => left.recordId.localeCompare(right.recordId));
|
|
194
|
-
}
|
|
195
|
-
|
|
196
11
|
function normalizeResources(objects: CapturedObject[]): NormalizedRecord[] {
|
|
197
12
|
const records: NormalizedRecord[] = [];
|
|
198
13
|
for (const object of objects) {
|
|
@@ -221,4 +36,4 @@ function normalizeResources(objects: CapturedObject[]): NormalizedRecord[] {
|
|
|
221
36
|
return records.sort((left, right) => left.recordId.localeCompare(right.recordId));
|
|
222
37
|
}
|
|
223
38
|
|
|
224
|
-
export {
|
|
39
|
+
export { normalizeResources };
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import type { CapturedObject, PrivacyDisposition, SourceKind } from './types.ts';
|
|
1
|
+
import type { PrivacyDisposition } from './types.ts';
|
|
4
2
|
|
|
5
3
|
type ScannedDisposition =
|
|
6
4
|
| Extract<PrivacyDisposition, { state: 'included' }>
|
|
@@ -23,19 +21,4 @@ function inspectPrivacy(content: string): ScannedDisposition {
|
|
|
23
21
|
return { state: 'included' };
|
|
24
22
|
}
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
const bytes = Buffer.byteLength(content);
|
|
28
|
-
const digest = sha256(Buffer.from(content, 'utf8'));
|
|
29
|
-
const disposition = inspectPrivacy(content);
|
|
30
|
-
return disposition.state === 'included'
|
|
31
|
-
? { sourceKind, sourceIdentity, sha256: digest, bytes, content, disposition }
|
|
32
|
-
: { sourceKind, sourceIdentity, sha256: digest, bytes, disposition };
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function redactExcerpt(content: string, maxBytes = 4096): string | null {
|
|
36
|
-
if (inspectPrivacy(content).state !== 'included') return null;
|
|
37
|
-
const buffer = Buffer.from(content, 'utf8');
|
|
38
|
-
return buffer.subarray(0, maxBytes).toString('utf8').replace(/\b(token|password|secret)=\S+/gi, '$1=[REDACTED]');
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export { captureText, inspectPrivacy, redactExcerpt };
|
|
24
|
+
export { inspectPrivacy };
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
1
|
|
|
4
2
|
import { createGitHubClient } from '../platform/github-client.ts';
|
|
5
|
-
import {
|
|
6
|
-
import { resolveProjectTaskWorkspaceRoot } from '../task/workspace-root.ts';
|
|
7
|
-
import { captureText, inspectPrivacy, redactExcerpt } from './privacy.ts';
|
|
3
|
+
import { inspectPrivacy } from './privacy.ts';
|
|
8
4
|
import { canonicalJsonBytes, sha256 } from './store.ts';
|
|
9
5
|
|
|
10
6
|
import type { GitHubClient } from '../platform/github-client.ts';
|
|
@@ -16,23 +12,6 @@ import type {
|
|
|
16
12
|
RestPageEvidence
|
|
17
13
|
} from './types.ts';
|
|
18
14
|
|
|
19
|
-
type RestPage = { evidence: RestPageEvidence; bytes: Buffer };
|
|
20
|
-
type RestCollection<T> = { items: T[]; evidence: RestCollectionEvidence; pageObjects: CapturedObject[] };
|
|
21
|
-
|
|
22
|
-
type FetchRestCollectionOptions<T> = {
|
|
23
|
-
client: GitHubClient;
|
|
24
|
-
endpoint: string;
|
|
25
|
-
identify: (item: T) => string;
|
|
26
|
-
select?: (item: T) => T;
|
|
27
|
-
perPage?: number;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
type GitHubCapture = {
|
|
31
|
-
repository: string;
|
|
32
|
-
objects: CapturedObject[];
|
|
33
|
-
endpoints: RestCollectionEvidence[];
|
|
34
|
-
};
|
|
35
|
-
|
|
36
15
|
type GitHubBoundaryCapture = {
|
|
37
16
|
repository: string;
|
|
38
17
|
preflightDate: string;
|
|
@@ -60,209 +39,6 @@ type EndpointDescriptor = {
|
|
|
60
39
|
includeResource?: (item: unknown) => boolean;
|
|
61
40
|
};
|
|
62
41
|
|
|
63
|
-
function endpointForPage(endpoint: string, page: number, perPage: number): string {
|
|
64
|
-
const parsed = new URL(endpoint, 'https://api.github.invalid/');
|
|
65
|
-
if (parsed.searchParams.has('page') || parsed.searchParams.has('per_page')) {
|
|
66
|
-
throw new Error('endpoint must not predefine page or per_page');
|
|
67
|
-
}
|
|
68
|
-
parsed.searchParams.set('per_page', String(perPage));
|
|
69
|
-
parsed.searchParams.set('page', String(page));
|
|
70
|
-
return `${parsed.pathname.replace(/^\//, '')}${parsed.search}`;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function fetchRestCollection<T>(options: FetchRestCollectionOptions<T>): ProcessResult<RestCollection<T>> {
|
|
74
|
-
const perPage = options.perPage ?? 100;
|
|
75
|
-
if (!Number.isInteger(perPage) || perPage < 1 || perPage > 100) {
|
|
76
|
-
return { ok: false, error: { code: 'PAGINATION_INVALID', message: 'perPage must be between 1 and 100' } };
|
|
77
|
-
}
|
|
78
|
-
let pageIndex = 1;
|
|
79
|
-
let previousHash: string | null = null;
|
|
80
|
-
const identities = new Set<string>();
|
|
81
|
-
const items: T[] = [];
|
|
82
|
-
const pages: RestPage[] = [];
|
|
83
|
-
|
|
84
|
-
while (true) {
|
|
85
|
-
let url: string;
|
|
86
|
-
try {
|
|
87
|
-
url = endpointForPage(options.endpoint, pageIndex, perPage);
|
|
88
|
-
} catch (error) {
|
|
89
|
-
return { ok: false, error: { code: 'PAGINATION_INVALID', message: String(error) } };
|
|
90
|
-
}
|
|
91
|
-
const response = options.client.json<unknown>(['api', url]);
|
|
92
|
-
if (!response.ok) return { ok: false, error: response.error };
|
|
93
|
-
if (!Array.isArray(response.value) || response.value.length > perPage) {
|
|
94
|
-
return {
|
|
95
|
-
ok: false,
|
|
96
|
-
error: { code: 'INVALID_PLATFORM_RESPONSE', message: `GitHub page ${pageIndex} is not a valid array page` }
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
let selected: T[];
|
|
100
|
-
try {
|
|
101
|
-
selected = (response.value as T[]).map((entry) => options.select ? options.select(entry) : entry);
|
|
102
|
-
} catch (error) {
|
|
103
|
-
return { ok: false, error: { code: 'INVALID_PLATFORM_RESPONSE', message: String(error) } };
|
|
104
|
-
}
|
|
105
|
-
let bytes: Buffer;
|
|
106
|
-
try {
|
|
107
|
-
bytes = canonicalJsonBytes(selected);
|
|
108
|
-
} catch (error) {
|
|
109
|
-
return { ok: false, error: { code: 'INVALID_PLATFORM_RESPONSE', message: String(error) } };
|
|
110
|
-
}
|
|
111
|
-
const canonicalSha256 = sha256(bytes);
|
|
112
|
-
if (previousHash === canonicalSha256 && response.value.length > 0) {
|
|
113
|
-
return {
|
|
114
|
-
ok: false,
|
|
115
|
-
error: { code: 'PAGINATION_UNSTABLE', message: `GitHub page ${pageIndex} repeats the previous page` }
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
for (const entry of selected) {
|
|
119
|
-
const identity = options.identify(entry);
|
|
120
|
-
if (!identity || identities.has(identity)) {
|
|
121
|
-
return {
|
|
122
|
-
ok: false,
|
|
123
|
-
error: { code: 'PAGINATION_UNSTABLE', message: `duplicate or empty identity on page ${pageIndex}` }
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
identities.add(identity);
|
|
127
|
-
items.push(entry);
|
|
128
|
-
}
|
|
129
|
-
pages.push({ evidence: { index: pageIndex, itemCount: response.value.length, canonicalSha256 }, bytes });
|
|
130
|
-
previousHash = canonicalSha256;
|
|
131
|
-
if (response.value.length < perPage) break;
|
|
132
|
-
pageIndex += 1;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const evidence: RestCollectionEvidence = {
|
|
136
|
-
endpoint: options.endpoint,
|
|
137
|
-
requestCount: pages.length,
|
|
138
|
-
dataPageCount: pages.filter((page) => page.evidence.itemCount > 0).length,
|
|
139
|
-
itemCount: items.length,
|
|
140
|
-
termination: 'short-page',
|
|
141
|
-
pages: pages.map((page) => page.evidence)
|
|
142
|
-
};
|
|
143
|
-
return {
|
|
144
|
-
ok: true,
|
|
145
|
-
value: {
|
|
146
|
-
items,
|
|
147
|
-
evidence,
|
|
148
|
-
pageObjects: pages.map((page) => ({
|
|
149
|
-
sourceKind: 'github-rest',
|
|
150
|
-
sourceIdentity: `${options.endpoint}#page=${page.evidence.index}`,
|
|
151
|
-
sha256: page.evidence.canonicalSha256,
|
|
152
|
-
bytes: page.bytes.length,
|
|
153
|
-
content: page.bytes.toString('utf8'),
|
|
154
|
-
disposition: { state: 'included' }
|
|
155
|
-
}))
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function relativeIdentity(repoRoot: string, filePath: string): string {
|
|
161
|
-
const workspaceRoot = resolveProjectTaskWorkspaceRoot(repoRoot);
|
|
162
|
-
const taskRelative = path.relative(workspaceRoot, filePath);
|
|
163
|
-
if (taskRelative && !taskRelative.startsWith('..') && !path.isAbsolute(taskRelative)) {
|
|
164
|
-
return path.posix.join('task-workspace', taskRelative.split(path.sep).join('/'));
|
|
165
|
-
}
|
|
166
|
-
const relative = path.relative(repoRoot, filePath);
|
|
167
|
-
if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) throw new Error(`path escapes repository: ${filePath}`);
|
|
168
|
-
return relative.split(path.sep).join('/');
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function readStableFile(repoRoot: string, filePath: string, sourceKind: CapturedObject['sourceKind']): CapturedObject {
|
|
172
|
-
const before = fs.lstatSync(filePath);
|
|
173
|
-
if (!before.isFile() || before.isSymbolicLink()) throw new Error(`unsafe source file: ${filePath}`);
|
|
174
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
175
|
-
const after = fs.lstatSync(filePath);
|
|
176
|
-
if (before.dev !== after.dev || before.ino !== after.ino || before.size !== after.size || before.mtimeMs !== after.mtimeMs) {
|
|
177
|
-
throw new Error(`source changed while reading: ${filePath}`);
|
|
178
|
-
}
|
|
179
|
-
return captureText(sourceKind, relativeIdentity(repoRoot, filePath), content);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function listFiles(directory: string): string[] {
|
|
183
|
-
if (!fs.existsSync(directory)) return [];
|
|
184
|
-
const output: string[] = [];
|
|
185
|
-
const walk = (current: string) => {
|
|
186
|
-
for (const entry of fs.readdirSync(current, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
187
|
-
const candidate = path.join(current, entry.name);
|
|
188
|
-
if (entry.isSymbolicLink()) throw new Error(`symlink source is not allowed: ${candidate}`);
|
|
189
|
-
if (entry.isDirectory()) walk(candidate);
|
|
190
|
-
else if (entry.isFile()) output.push(candidate);
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
|
-
walk(directory);
|
|
194
|
-
return output;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
function structuredReceipt(repoRoot: string, filePath: string): CapturedObject {
|
|
198
|
-
const raw = readStableFile(repoRoot, filePath, 'structured-telemetry');
|
|
199
|
-
if (!raw.content) return raw;
|
|
200
|
-
try {
|
|
201
|
-
const parsed = JSON.parse(raw.content) as Record<string, unknown>;
|
|
202
|
-
const fields = ['client', 'model', 'reasoning', 'stage', 'toolCategory', 'time', 'status', 'retry', 'error', 'fallback'];
|
|
203
|
-
const selected = Object.fromEntries(
|
|
204
|
-
fields.filter((field) => parsed[field] !== undefined).map((field) => [field, jsonClone(parsed[field])])
|
|
205
|
-
);
|
|
206
|
-
selected.sourceSha256 = raw.sha256;
|
|
207
|
-
return captureText('structured-telemetry', raw.sourceIdentity, canonicalJsonBytes(selected).toString('utf8'));
|
|
208
|
-
} catch {
|
|
209
|
-
return { ...raw, content: undefined, disposition: { state: 'unavailable', reason: 'invalid receipt JSON' } };
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function unavailableLog(repoRoot: string, filePath: string, includeExcerpts: boolean): CapturedObject {
|
|
214
|
-
const raw = readStableFile(repoRoot, filePath, 'local-file');
|
|
215
|
-
if (raw.disposition?.state === 'excluded-sensitive') return raw;
|
|
216
|
-
const recognizedBody = /\/(?:sessions?|tools?)(?:\/|[-_])/i.test(raw.sourceIdentity);
|
|
217
|
-
if (includeExcerpts && recognizedBody && raw.content) {
|
|
218
|
-
const excerpt = redactExcerpt(raw.content);
|
|
219
|
-
if (excerpt !== null) return captureText('local-file', `${raw.sourceIdentity}#excerpt`, excerpt);
|
|
220
|
-
}
|
|
221
|
-
return {
|
|
222
|
-
sourceKind: 'local-file',
|
|
223
|
-
sourceIdentity: raw.sourceIdentity,
|
|
224
|
-
sha256: raw.sha256,
|
|
225
|
-
bytes: raw.bytes,
|
|
226
|
-
disposition: { state: 'unavailable', reason: recognizedBody ? 'body-excerpts-disabled' : 'unknown-log-format' }
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function collectLocalObjects(repoRoot: string, options: { includeExcerpts?: boolean } = {}): ProcessResult<CapturedObject[]> {
|
|
231
|
-
try {
|
|
232
|
-
const objects: CapturedObject[] = [];
|
|
233
|
-
for (const task of enumerateAllTaskDirs(repoRoot)) {
|
|
234
|
-
for (const filePath of listFiles(task.taskDir)) {
|
|
235
|
-
if (!/\.(?:md|json)$/i.test(filePath)) continue;
|
|
236
|
-
objects.push(readStableFile(repoRoot, filePath, 'local-file'));
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
const logsRoot = path.join(repoRoot, '.agents', 'workspace', 'logs');
|
|
240
|
-
for (const filePath of listFiles(logsRoot)) {
|
|
241
|
-
if (!/\.(?:md|json)$/i.test(filePath)) continue;
|
|
242
|
-
const identity = relativeIdentity(repoRoot, filePath);
|
|
243
|
-
if (/\/entropy-check\/.*\.md$/i.test(identity)) {
|
|
244
|
-
objects.push(readStableFile(repoRoot, filePath, 'operational-report'));
|
|
245
|
-
} else if (/\/(?:delegation|orchestration)(?:\/|[-_]).*\.json$/i.test(identity)) {
|
|
246
|
-
objects.push(structuredReceipt(repoRoot, filePath));
|
|
247
|
-
} else {
|
|
248
|
-
objects.push(unavailableLog(repoRoot, filePath, options.includeExcerpts === true));
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
return { ok: true, value: objects.sort((a, b) => a.sourceIdentity.localeCompare(b.sourceIdentity)) };
|
|
252
|
-
} catch (error) {
|
|
253
|
-
return { ok: false, error: { code: 'LOCAL_SOURCE_UNSTABLE', message: error instanceof Error ? error.message : String(error) } };
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
function githubIdentity(item: unknown): string {
|
|
258
|
-
if (!item || typeof item !== 'object') return '';
|
|
259
|
-
const record = item as Record<string, unknown>;
|
|
260
|
-
for (const key of ['id', 'node_id', 'sha', 'number']) {
|
|
261
|
-
if (typeof record[key] === 'string' || typeof record[key] === 'number') return `${key}:${String(record[key])}`;
|
|
262
|
-
}
|
|
263
|
-
return '';
|
|
264
|
-
}
|
|
265
|
-
|
|
266
42
|
function jsonClone(value: unknown): unknown {
|
|
267
43
|
return JSON.parse(JSON.stringify(value)) as unknown;
|
|
268
44
|
}
|
|
@@ -360,62 +136,6 @@ function projectGitHubTimelineItem(item: unknown): unknown {
|
|
|
360
136
|
return output;
|
|
361
137
|
}
|
|
362
138
|
|
|
363
|
-
function collectGitHubObjects(repoRoot: string, client: GitHubClient = createGitHubClient()): ProcessResult<GitHubCapture> {
|
|
364
|
-
const repoResult = client.json<{ nameWithOwner?: string }>(['repo', 'view', '--json', 'nameWithOwner'], { cwd: repoRoot });
|
|
365
|
-
if (!repoResult.ok) return { ok: false, error: repoResult.error };
|
|
366
|
-
const repository = repoResult.value.nameWithOwner;
|
|
367
|
-
if (!repository || !/^[^/]+\/[^/]+$/.test(repository)) {
|
|
368
|
-
return { ok: false, error: { code: 'INVALID_PLATFORM_RESPONSE', message: 'GitHub repository identity is missing' } };
|
|
369
|
-
}
|
|
370
|
-
const objects: CapturedObject[] = [];
|
|
371
|
-
const evidence: RestCollectionEvidence[] = [];
|
|
372
|
-
const captureEndpoint = (endpoint: string) => {
|
|
373
|
-
const result = fetchRestCollection({
|
|
374
|
-
client,
|
|
375
|
-
endpoint,
|
|
376
|
-
identify: githubIdentity,
|
|
377
|
-
select: (item) => projectGitHubItem(item) as unknown
|
|
378
|
-
});
|
|
379
|
-
if (!result.ok) return result;
|
|
380
|
-
objects.push(...result.value.pageObjects);
|
|
381
|
-
evidence.push(result.value.evidence);
|
|
382
|
-
return result;
|
|
383
|
-
};
|
|
384
|
-
|
|
385
|
-
const issues = captureEndpoint(`repos/${repository}/issues?state=all&sort=created&direction=asc`);
|
|
386
|
-
if (!issues.ok) return issues;
|
|
387
|
-
const pulls = captureEndpoint(`repos/${repository}/pulls?state=all&sort=created&direction=asc`);
|
|
388
|
-
if (!pulls.ok) return pulls;
|
|
389
|
-
|
|
390
|
-
for (const issue of issues.value.items) {
|
|
391
|
-
const number = (issue as Record<string, unknown>).number;
|
|
392
|
-
if (typeof number !== 'number') return { ok: false, error: { code: 'INVALID_PLATFORM_RESPONSE', message: 'Issue number is missing' } };
|
|
393
|
-
const comments = captureEndpoint(`repos/${repository}/issues/${number}/comments`);
|
|
394
|
-
if (!comments.ok) return comments;
|
|
395
|
-
}
|
|
396
|
-
for (const pull of pulls.value.items) {
|
|
397
|
-
const record = pull as Record<string, unknown>;
|
|
398
|
-
const number = record.number;
|
|
399
|
-
const head = record.head as Record<string, unknown> | undefined;
|
|
400
|
-
const headSha = head?.sha;
|
|
401
|
-
if (typeof number !== 'number' || typeof headSha !== 'string') {
|
|
402
|
-
return { ok: false, error: { code: 'INVALID_PLATFORM_RESPONSE', message: 'Pull request identity or head SHA is missing' } };
|
|
403
|
-
}
|
|
404
|
-
for (const suffix of ['comments', 'reviews', 'commits']) {
|
|
405
|
-
const nested = captureEndpoint(`repos/${repository}/pulls/${number}/${suffix}`);
|
|
406
|
-
if (!nested.ok) return nested;
|
|
407
|
-
}
|
|
408
|
-
const current = client.json<unknown>(['api', `repos/${repository}/pulls/${number}`]);
|
|
409
|
-
if (!current.ok) return { ok: false, error: current.error };
|
|
410
|
-
const projected = projectGitHubItem(current.value) as Record<string, unknown>;
|
|
411
|
-
const currentHead = projected.head as Record<string, unknown> | undefined;
|
|
412
|
-
if (currentHead?.sha !== headSha) {
|
|
413
|
-
return { ok: false, error: { code: 'SOURCE_DRIFT', message: `Pull request ${number} head changed during capture` } };
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
return { ok: true, value: { repository, objects, endpoints: evidence } };
|
|
417
|
-
}
|
|
418
|
-
|
|
419
139
|
function resolveGitHubRepository(repoRoot: string, client: GitHubClient = createGitHubClient()): ProcessResult<string> {
|
|
420
140
|
const result = client.json<{ nameWithOwner?: string }>(['repo', 'view', '--json', 'nameWithOwner'], { cwd: repoRoot });
|
|
421
141
|
if (!result.ok) return { ok: false, error: result.error };
|
|
@@ -803,5 +523,5 @@ function collectGitHubBoundary(repoRoot: string, options: BoundaryCaptureOptions
|
|
|
803
523
|
};
|
|
804
524
|
}
|
|
805
525
|
|
|
806
|
-
export { collectGitHubBoundary,
|
|
807
|
-
export type { BoundaryCaptureOptions,
|
|
526
|
+
export { collectGitHubBoundary, projectGitHubItem, projectGitHubTimelineItem, resolveGitHubRepository };
|
|
527
|
+
export type { BoundaryCaptureOptions, GitHubBoundaryCapture };
|
package/lib/render.ts
CHANGED
|
@@ -62,21 +62,6 @@ function containsPlaceholders(src: string): boolean {
|
|
|
62
62
|
return content.includes('{{project}}') || content.includes('{{org}}');
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
function variantExt(relativePath: string): string {
|
|
66
|
-
return path.extname(relativePath);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function variantBase(relativePath: string): string {
|
|
70
|
-
const ext = variantExt(relativePath);
|
|
71
|
-
return relativePath.slice(0, -ext.length);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function withVariant(relativePath: string, variant: string): string {
|
|
75
|
-
const ext = variantExt(relativePath);
|
|
76
|
-
const base = variantBase(relativePath);
|
|
77
|
-
return `${base}.${variant}${ext}`;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
65
|
function stripVariant(relativePath: string, variant: string): string {
|
|
81
66
|
return relativePath.replace(new RegExp(`\\.${variant.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\.`), '.');
|
|
82
67
|
}
|
package/lib/run/index.ts
CHANGED
|
@@ -3,7 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import { loadServerConfig } from '../server/config.ts';
|
|
4
4
|
import { resolveSandboxTarget, type SandboxWorkspaceIdentity } from '../sandbox/workspace-identity.ts';
|
|
5
5
|
import { createRunId, runInSandbox, type SandboxRunMetadata } from '../sandbox/capture.ts';
|
|
6
|
-
import {
|
|
6
|
+
import { normalizeShortIdInput } from '../task/short-id.ts';
|
|
7
7
|
import { resolveProjectTaskWorkspaceRoot } from '../task/workspace-root.ts';
|
|
8
8
|
import { buildTuiCommand, renderPrompt, selectTui } from './tui.ts';
|
|
9
9
|
import { getSkillRunSpec } from './skills.ts';
|
|
@@ -101,11 +101,21 @@ function extractHostOptions(args: string[]): {
|
|
|
101
101
|
return { positionals, forwarded, skill, taskRef, tui, recreate };
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
function parseCreateTaskArgs(skill: string, options: ReturnType<typeof extractHostOptions>): ParsedRunArgs {
|
|
105
|
+
const { taskRef, recreate, positionals, forwarded, tui } = options;
|
|
106
|
+
if (taskRef !== null) throw new Error("create-task does not accept '--task'");
|
|
107
|
+
if (recreate) throw new Error('--recreate is only valid for sandbox task runs');
|
|
108
|
+
const createArgs = [...positionals, ...forwarded];
|
|
109
|
+
if (createArgs.length === 0) throw new Error('create-task requires a description');
|
|
110
|
+
return { skill, taskRef: null, args: createArgs, tui };
|
|
111
|
+
}
|
|
112
|
+
|
|
104
113
|
export function parseRunArgs(args: string[]): ParsedRunArgs {
|
|
105
114
|
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
106
115
|
throw new Error(USAGE);
|
|
107
116
|
}
|
|
108
|
-
const
|
|
117
|
+
const options = extractHostOptions(args);
|
|
118
|
+
const { positionals, forwarded, skill, taskRef, tui, recreate } = options;
|
|
109
119
|
if (!skill) throw new Error("option '--skill' is required");
|
|
110
120
|
const spec = getSkillRunSpec(skill);
|
|
111
121
|
if (!spec) throw new Error(`Unknown skill '${skill}'`);
|
|
@@ -114,11 +124,7 @@ export function parseRunArgs(args: string[]): ParsedRunArgs {
|
|
|
114
124
|
throw new Error(`Unsupported run route '${routeSelector}'`);
|
|
115
125
|
}
|
|
116
126
|
if (spec.kind === 'create') {
|
|
117
|
-
|
|
118
|
-
if (recreate) throw new Error('--recreate is only valid for sandbox task runs');
|
|
119
|
-
const createArgs = [...positionals, ...forwarded];
|
|
120
|
-
if (createArgs.length === 0) throw new Error('create-task requires a description');
|
|
121
|
-
return { skill, taskRef: null, args: createArgs, tui };
|
|
127
|
+
return parseCreateTaskArgs(skill, options);
|
|
122
128
|
}
|
|
123
129
|
if (positionals.length > 0) {
|
|
124
130
|
throw new Error('ai run requires --skill and --task; positional host arguments are not supported');
|