feed-the-machine 1.6.1 → 1.7.0
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/LICENSE +21 -21
- package/README.md +170 -170
- package/bin/brain.py +1340 -0
- package/bin/convert_claude_skills_to_codex.py +490 -0
- package/bin/generate-manifest.mjs +463 -463
- package/bin/harden_codex_skills.py +141 -0
- package/bin/install.mjs +491 -491
- package/bin/migrate-eng-buddy-data.py +875 -0
- package/bin/playbook_engine/__init__.py +1 -0
- package/bin/playbook_engine/conftest.py +8 -0
- package/bin/playbook_engine/extractor.py +33 -0
- package/bin/playbook_engine/manager.py +102 -0
- package/bin/playbook_engine/models.py +84 -0
- package/bin/playbook_engine/registry.py +35 -0
- package/bin/playbook_engine/test_extractor.py +72 -0
- package/bin/playbook_engine/test_integration.py +129 -0
- package/bin/playbook_engine/test_manager.py +85 -0
- package/bin/playbook_engine/test_models.py +166 -0
- package/bin/playbook_engine/test_registry.py +67 -0
- package/bin/playbook_engine/test_tracer.py +86 -0
- package/bin/playbook_engine/tracer.py +93 -0
- package/bin/tasks_db.py +456 -0
- package/docs/HOOKS.md +243 -243
- package/docs/INBOX.md +233 -233
- package/ftm/SKILL.md +125 -122
- package/ftm-audit/SKILL.md +623 -623
- package/ftm-audit/references/protocols/PROJECT-PATTERNS.md +91 -91
- package/ftm-audit/references/protocols/RUNTIME-WIRING.md +66 -66
- package/ftm-audit/references/protocols/WIRING-CONTRACTS.md +135 -135
- package/ftm-audit/references/strategies/AUTO-FIX-STRATEGIES.md +69 -69
- package/ftm-audit/references/templates/REPORT-FORMAT.md +96 -96
- package/ftm-audit/scripts/run-knip.sh +23 -23
- package/ftm-audit.yml +2 -2
- package/ftm-brainstorm/SKILL.md +1003 -498
- package/ftm-brainstorm/evals/evals.json +180 -100
- package/ftm-brainstorm/evals/promptfoo.yaml +109 -109
- package/ftm-brainstorm/references/agent-prompts.md +552 -224
- package/ftm-brainstorm/references/plan-template.md +209 -121
- package/ftm-brainstorm.yml +2 -2
- package/ftm-browse/SKILL.md +454 -454
- package/ftm-browse/daemon/browser-manager.ts +206 -206
- package/ftm-browse/daemon/bun.lock +30 -30
- package/ftm-browse/daemon/cli.ts +347 -347
- package/ftm-browse/daemon/commands.ts +410 -410
- package/ftm-browse/daemon/main.ts +357 -357
- package/ftm-browse/daemon/package.json +17 -17
- package/ftm-browse/daemon/server.ts +189 -189
- package/ftm-browse/daemon/snapshot.ts +519 -519
- package/ftm-browse/daemon/tsconfig.json +22 -22
- package/ftm-browse.yml +4 -4
- package/ftm-capture/SKILL.md +370 -370
- package/ftm-capture.yml +4 -4
- package/ftm-codex-gate/SKILL.md +361 -361
- package/ftm-codex-gate.yml +2 -2
- package/ftm-config/SKILL.md +422 -345
- package/ftm-config.default.yml +125 -82
- package/ftm-config.yml +44 -2
- package/ftm-council/SKILL.md +416 -416
- package/ftm-council/references/prompts/CLAUDE-INVESTIGATION.md +60 -60
- package/ftm-council/references/prompts/CODEX-INVESTIGATION.md +58 -58
- package/ftm-council/references/prompts/GEMINI-INVESTIGATION.md +58 -58
- package/ftm-council/references/prompts/REBUTTAL-TEMPLATE.md +57 -57
- package/ftm-council/references/protocols/PREREQUISITES.md +47 -47
- package/ftm-council/references/protocols/STEP-0-FRAMING.md +46 -46
- package/ftm-council.yml +2 -2
- package/ftm-dashboard/SKILL.md +163 -163
- package/ftm-dashboard.yml +4 -4
- package/ftm-debug/SKILL.md +1037 -1037
- package/ftm-debug/references/phases/PHASE-0-INTAKE.md +58 -58
- package/ftm-debug/references/phases/PHASE-1-TRIAGE.md +46 -46
- package/ftm-debug/references/phases/PHASE-2-WAR-ROOM-AGENTS.md +279 -279
- package/ftm-debug/references/phases/PHASE-3-TO-6-EXECUTION.md +436 -436
- package/ftm-debug/references/protocols/BLACKBOARD.md +86 -86
- package/ftm-debug/references/protocols/EDGE-CASES.md +103 -103
- package/ftm-debug.yml +2 -2
- package/ftm-diagram/SKILL.md +277 -277
- package/ftm-diagram.yml +2 -2
- package/ftm-executor/SKILL.md +777 -777
- package/ftm-executor/references/STYLE-TEMPLATE.md +73 -73
- package/ftm-executor/references/phases/PHASE-0-VERIFICATION.md +62 -62
- package/ftm-executor/references/phases/PHASE-2-AGENT-ASSEMBLY.md +34 -34
- package/ftm-executor/references/phases/PHASE-3-WORKTREES.md +38 -38
- package/ftm-executor/references/phases/PHASE-4-5-AUDIT.md +72 -72
- package/ftm-executor/references/phases/PHASE-4-DISPATCH.md +66 -66
- package/ftm-executor/references/phases/PHASE-5-5-CODEX-GATE.md +73 -73
- package/ftm-executor/references/protocols/DOCUMENTATION-BOOTSTRAP.md +36 -36
- package/ftm-executor/references/protocols/MODEL-PROFILE.md +59 -59
- package/ftm-executor/references/protocols/PROGRESS-TRACKING.md +66 -66
- package/ftm-executor/runtime/ftm-runtime.mjs +252 -252
- package/ftm-executor/runtime/package.json +8 -8
- package/ftm-executor.yml +2 -2
- package/ftm-git/SKILL.md +441 -441
- package/ftm-git/evals/evals.json +26 -26
- package/ftm-git/evals/promptfoo.yaml +75 -75
- package/ftm-git/hooks/post-commit-experience.sh +92 -92
- package/ftm-git/references/patterns/SECRET-PATTERNS.md +104 -104
- package/ftm-git/references/protocols/REMEDIATION.md +139 -139
- package/ftm-git/scripts/pre-commit-secrets.sh +110 -110
- package/ftm-git.yml +2 -2
- package/ftm-inbox/backend/__pycache__/main.cpython-314.pyc +0 -0
- package/ftm-inbox/backend/adapters/_retry.py +64 -64
- package/ftm-inbox/backend/adapters/base.py +230 -230
- package/ftm-inbox/backend/adapters/freshservice.py +104 -104
- package/ftm-inbox/backend/adapters/gmail.py +125 -125
- package/ftm-inbox/backend/adapters/jira.py +136 -136
- package/ftm-inbox/backend/adapters/registry.py +192 -192
- package/ftm-inbox/backend/adapters/slack.py +110 -110
- package/ftm-inbox/backend/db/connection.py +54 -54
- package/ftm-inbox/backend/db/schema.py +78 -78
- package/ftm-inbox/backend/executor/__init__.py +7 -7
- package/ftm-inbox/backend/executor/engine.py +149 -149
- package/ftm-inbox/backend/executor/step_runner.py +98 -98
- package/ftm-inbox/backend/main.py +103 -103
- package/ftm-inbox/backend/models/__init__.py +1 -1
- package/ftm-inbox/backend/models/unified_task.py +36 -36
- package/ftm-inbox/backend/planner/__init__.py +6 -6
- package/ftm-inbox/backend/planner/__pycache__/__init__.cpython-314.pyc +0 -0
- package/ftm-inbox/backend/planner/__pycache__/generator.cpython-314.pyc +0 -0
- package/ftm-inbox/backend/planner/__pycache__/schema.cpython-314.pyc +0 -0
- package/ftm-inbox/backend/planner/generator.py +127 -127
- package/ftm-inbox/backend/planner/schema.py +34 -34
- package/ftm-inbox/backend/requirements.txt +5 -5
- package/ftm-inbox/backend/routes/__pycache__/plan.cpython-314.pyc +0 -0
- package/ftm-inbox/backend/routes/execute.py +186 -186
- package/ftm-inbox/backend/routes/health.py +52 -52
- package/ftm-inbox/backend/routes/inbox.py +68 -68
- package/ftm-inbox/backend/routes/plan.py +271 -271
- package/ftm-inbox/bin/launchagent.mjs +91 -91
- package/ftm-inbox/bin/setup.mjs +188 -188
- package/ftm-inbox/bin/start.sh +10 -10
- package/ftm-inbox/bin/status.sh +17 -17
- package/ftm-inbox/bin/stop.sh +8 -8
- package/ftm-inbox/config.example.yml +55 -55
- package/ftm-inbox/package-lock.json +2898 -2898
- package/ftm-inbox/package.json +26 -26
- package/ftm-inbox/postcss.config.js +6 -6
- package/ftm-inbox/src/app.css +199 -199
- package/ftm-inbox/src/app.html +18 -18
- package/ftm-inbox/src/lib/api.ts +166 -166
- package/ftm-inbox/src/lib/components/ExecutionLog.svelte +81 -81
- package/ftm-inbox/src/lib/components/InboxFeed.svelte +143 -143
- package/ftm-inbox/src/lib/components/PlanStep.svelte +271 -271
- package/ftm-inbox/src/lib/components/PlanView.svelte +206 -206
- package/ftm-inbox/src/lib/components/StreamPanel.svelte +99 -99
- package/ftm-inbox/src/lib/components/TaskCard.svelte +190 -190
- package/ftm-inbox/src/lib/components/ui/EmptyState.svelte +63 -63
- package/ftm-inbox/src/lib/components/ui/KawaiiCard.svelte +86 -86
- package/ftm-inbox/src/lib/components/ui/PillButton.svelte +106 -106
- package/ftm-inbox/src/lib/components/ui/StatusBadge.svelte +67 -67
- package/ftm-inbox/src/lib/components/ui/StreamDrawer.svelte +149 -149
- package/ftm-inbox/src/lib/components/ui/ThemeToggle.svelte +80 -80
- package/ftm-inbox/src/lib/theme.ts +47 -47
- package/ftm-inbox/src/routes/+layout.svelte +76 -76
- package/ftm-inbox/src/routes/+page.svelte +401 -401
- package/ftm-inbox/svelte.config.js +12 -12
- package/ftm-inbox/tailwind.config.ts +63 -63
- package/ftm-inbox/tsconfig.json +13 -13
- package/ftm-inbox/vite.config.ts +6 -6
- package/ftm-intent/SKILL.md +241 -241
- package/ftm-intent.yml +2 -2
- package/ftm-manifest.json +3794 -3794
- package/ftm-map/SKILL.md +291 -291
- package/ftm-map/scripts/db.py +712 -712
- package/ftm-map/scripts/index.py +415 -415
- package/ftm-map/scripts/parser.py +224 -224
- package/ftm-map/scripts/queries/go-tags.scm +20 -20
- package/ftm-map/scripts/queries/javascript-tags.scm +35 -35
- package/ftm-map/scripts/queries/python-tags.scm +31 -31
- package/ftm-map/scripts/queries/ruby-tags.scm +19 -19
- package/ftm-map/scripts/queries/rust-tags.scm +37 -37
- package/ftm-map/scripts/queries/typescript-tags.scm +41 -41
- package/ftm-map/scripts/query.py +301 -301
- package/ftm-map/scripts/ranker.py +377 -377
- package/ftm-map/scripts/requirements.txt +5 -5
- package/ftm-map/scripts/setup-hooks.sh +27 -27
- package/ftm-map/scripts/setup.sh +56 -56
- package/ftm-map/scripts/test_db.py +364 -364
- package/ftm-map/scripts/test_parser.py +174 -174
- package/ftm-map/scripts/test_query.py +183 -183
- package/ftm-map/scripts/test_ranker.py +199 -199
- package/ftm-map/scripts/views.py +591 -591
- package/ftm-map.yml +2 -2
- package/ftm-mind/SKILL.md +201 -1943
- package/ftm-mind/evals/promptfoo.yaml +142 -142
- package/ftm-mind/references/blackboard-protocol.md +110 -0
- package/ftm-mind/references/blackboard-schema.md +328 -328
- package/ftm-mind/references/complexity-guide.md +110 -110
- package/ftm-mind/references/complexity-sizing.md +138 -0
- package/ftm-mind/references/decide-act-protocol.md +172 -0
- package/ftm-mind/references/direct-execution.md +51 -0
- package/ftm-mind/references/environment-discovery.md +77 -0
- package/ftm-mind/references/event-registry.md +319 -319
- package/ftm-mind/references/mcp-inventory.md +300 -296
- package/ftm-mind/references/ops-routing.md +47 -0
- package/ftm-mind/references/orient-protocol.md +234 -0
- package/ftm-mind/references/personality.md +40 -0
- package/ftm-mind/references/protocols/COMPLEXITY-SIZING.md +72 -72
- package/ftm-mind/references/protocols/MCP-HEURISTICS.md +32 -32
- package/ftm-mind/references/protocols/PLAN-APPROVAL.md +80 -80
- package/ftm-mind/references/reflexion-protocol.md +249 -249
- package/ftm-mind/references/routing/SCENARIOS.md +22 -22
- package/ftm-mind/references/routing-scenarios.md +35 -35
- package/ftm-mind.yml +2 -2
- package/ftm-ops.yml +4 -0
- package/ftm-pause/SKILL.md +395 -395
- package/ftm-pause/references/protocols/SKILL-RESTORE-PROTOCOLS.md +186 -186
- package/ftm-pause/references/protocols/VALIDATION.md +80 -80
- package/ftm-pause.yml +2 -2
- package/ftm-researcher/SKILL.md +275 -275
- package/ftm-researcher/evals/agent-diversity.yaml +17 -17
- package/ftm-researcher/evals/synthesis-quality.yaml +12 -12
- package/ftm-researcher/evals/trigger-accuracy.yaml +39 -39
- package/ftm-researcher/references/adaptive-search.md +116 -116
- package/ftm-researcher/references/agent-prompts.md +193 -193
- package/ftm-researcher/references/council-integration.md +193 -193
- package/ftm-researcher/references/output-format.md +203 -203
- package/ftm-researcher/references/synthesis-pipeline.md +165 -165
- package/ftm-researcher/scripts/score_credibility.py +234 -234
- package/ftm-researcher/scripts/validate_research.py +92 -92
- package/ftm-researcher.yml +2 -2
- package/ftm-resume/SKILL.md +518 -518
- package/ftm-resume/references/protocols/VALIDATION.md +172 -172
- package/ftm-resume.yml +2 -2
- package/ftm-retro/SKILL.md +380 -380
- package/ftm-retro/references/protocols/SCORING-RUBRICS.md +89 -89
- package/ftm-retro/references/templates/REPORT-FORMAT.md +109 -109
- package/ftm-retro.yml +2 -2
- package/ftm-routine/SKILL.md +170 -170
- package/ftm-routine.yml +4 -4
- package/ftm-state/blackboard/capabilities.json +5 -5
- package/ftm-state/blackboard/capabilities.schema.json +27 -27
- package/ftm-state/blackboard/context.json +37 -23
- package/ftm-state/blackboard/experiences/doom-statusline-fix.json +26 -0
- package/ftm-state/blackboard/experiences/hackathon-pages-site.json +26 -0
- package/ftm-state/blackboard/experiences/hindsight-sso-kickoff.json +42 -0
- package/ftm-state/blackboard/experiences/index.json +58 -9
- package/ftm-state/blackboard/experiences/learning-ragnarok-api-access.json +23 -0
- package/ftm-state/blackboard/experiences/nordlayer-members-auto-assign.json +26 -0
- package/ftm-state/blackboard/experiences/saml2aws-stale-session-fix.json +41 -0
- package/ftm-state/blackboard/patterns.json +6 -6
- package/ftm-state/schemas/context.schema.json +130 -130
- package/ftm-state/schemas/experience-index.schema.json +77 -77
- package/ftm-state/schemas/experience.schema.json +78 -78
- package/ftm-state/schemas/patterns.schema.json +44 -44
- package/ftm-upgrade/SKILL.md +194 -194
- package/ftm-upgrade/scripts/check-version.sh +76 -76
- package/ftm-upgrade/scripts/upgrade.sh +143 -143
- package/ftm-upgrade.yml +2 -2
- package/ftm-verify.yml +2 -2
- package/ftm.yml +2 -2
- package/hooks/ftm-auto-log.sh +137 -0
- package/hooks/ftm-blackboard-enforcer.sh +93 -93
- package/hooks/ftm-discovery-reminder.sh +90 -90
- package/hooks/ftm-drafts-gate.sh +61 -61
- package/hooks/ftm-event-logger.mjs +107 -107
- package/hooks/ftm-install-hooks.sh +240 -0
- package/hooks/ftm-learning-capture.sh +117 -0
- package/hooks/ftm-map-autodetect.sh +79 -79
- package/hooks/ftm-pending-sync-check.sh +22 -22
- package/hooks/ftm-plan-gate.sh +92 -92
- package/hooks/ftm-post-commit-trigger.sh +57 -57
- package/hooks/ftm-post-compaction.sh +138 -0
- package/hooks/ftm-pre-compaction.sh +147 -0
- package/hooks/ftm-session-end.sh +52 -0
- package/hooks/ftm-session-snapshot.sh +213 -0
- package/hooks/settings-template.json +81 -81
- package/install.sh +363 -363
- package/package.json +84 -84
- package/uninstall.sh +25 -25
package/ftm-inbox/src/lib/api.ts
CHANGED
|
@@ -1,166 +1,166 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* API client for the FTM Inbox backend.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
const API_BASE = 'http://localhost:8042';
|
|
6
|
-
|
|
7
|
-
export interface UnifiedTask {
|
|
8
|
-
id: number;
|
|
9
|
-
source: string;
|
|
10
|
-
source_id: string;
|
|
11
|
-
title: string;
|
|
12
|
-
body: string;
|
|
13
|
-
status: string;
|
|
14
|
-
priority: string;
|
|
15
|
-
assignee: string | null;
|
|
16
|
-
requester: string | null;
|
|
17
|
-
created_at: string | null;
|
|
18
|
-
updated_at: string | null;
|
|
19
|
-
tags: string[];
|
|
20
|
-
custom_fields: Record<string, unknown>;
|
|
21
|
-
source_url: string | null;
|
|
22
|
-
content_hash: string | null;
|
|
23
|
-
ingested_at: string | null;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface InboxResponse {
|
|
27
|
-
tasks: UnifiedTask[];
|
|
28
|
-
total: number;
|
|
29
|
-
page: number;
|
|
30
|
-
per_page: number;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export async function fetchInbox(source?: string, page = 1): Promise<InboxResponse> {
|
|
34
|
-
const params = new URLSearchParams({ page: String(page) });
|
|
35
|
-
if (source && source !== 'all') params.set('source', source);
|
|
36
|
-
const res = await fetch(`${API_BASE}/api/inbox?${params}`);
|
|
37
|
-
if (!res.ok) throw new Error(`API error: ${res.status}`);
|
|
38
|
-
return res.json();
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export async function fetchSources(): Promise<{ name: string; count: number }[]> {
|
|
42
|
-
const res = await fetch(`${API_BASE}/api/inbox/sources`);
|
|
43
|
-
if (!res.ok) return [];
|
|
44
|
-
const data = await res.json();
|
|
45
|
-
return data.sources ?? [];
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// ---------------------------------------------------------------------------
|
|
49
|
-
// Plan types
|
|
50
|
-
// ---------------------------------------------------------------------------
|
|
51
|
-
|
|
52
|
-
export interface PlanStep {
|
|
53
|
-
id: number;
|
|
54
|
-
title: string;
|
|
55
|
-
target_system: string;
|
|
56
|
-
method_primary: string;
|
|
57
|
-
method_fallback: string;
|
|
58
|
-
risk_level: string;
|
|
59
|
-
approval_required: boolean;
|
|
60
|
-
rollback: string;
|
|
61
|
-
status: string;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export interface Plan {
|
|
65
|
-
id: number;
|
|
66
|
-
task_id: number;
|
|
67
|
-
steps: PlanStep[];
|
|
68
|
-
status: string;
|
|
69
|
-
yaml_content: string;
|
|
70
|
-
created_at: string | null;
|
|
71
|
-
updated_at: string | null;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// ---------------------------------------------------------------------------
|
|
75
|
-
// Plan API functions
|
|
76
|
-
// ---------------------------------------------------------------------------
|
|
77
|
-
|
|
78
|
-
export async function generatePlan(taskId: number): Promise<Plan> {
|
|
79
|
-
const res = await fetch(`${API_BASE}/api/tasks/${taskId}/generate-plan`, {
|
|
80
|
-
method: 'POST'
|
|
81
|
-
});
|
|
82
|
-
if (!res.ok) {
|
|
83
|
-
const err = await res.json().catch(() => ({ detail: res.statusText }));
|
|
84
|
-
throw new Error(err.detail ?? `API error: ${res.status}`);
|
|
85
|
-
}
|
|
86
|
-
return res.json();
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export async function getPlan(taskId: number): Promise<Plan | null> {
|
|
90
|
-
const res = await fetch(`${API_BASE}/api/tasks/${taskId}/plan`);
|
|
91
|
-
if (!res.ok) return null;
|
|
92
|
-
const data = await res.json();
|
|
93
|
-
// Backend returns { plan: null } when no plan exists
|
|
94
|
-
if ('plan' in data && data.plan === null) return null;
|
|
95
|
-
return data as Plan;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export async function approveStep(taskId: number, stepId: number): Promise<Plan> {
|
|
99
|
-
const res = await fetch(`${API_BASE}/api/tasks/${taskId}/plan/steps/${stepId}/approve`, {
|
|
100
|
-
method: 'POST'
|
|
101
|
-
});
|
|
102
|
-
if (!res.ok) {
|
|
103
|
-
const err = await res.json().catch(() => ({ detail: res.statusText }));
|
|
104
|
-
throw new Error(err.detail ?? `API error: ${res.status}`);
|
|
105
|
-
}
|
|
106
|
-
return res.json();
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export async function approveAllSteps(taskId: number): Promise<Plan> {
|
|
110
|
-
const res = await fetch(`${API_BASE}/api/tasks/${taskId}/plan/approve-all`, {
|
|
111
|
-
method: 'POST'
|
|
112
|
-
});
|
|
113
|
-
if (!res.ok) {
|
|
114
|
-
const err = await res.json().catch(() => ({ detail: res.statusText }));
|
|
115
|
-
throw new Error(err.detail ?? `API error: ${res.status}`);
|
|
116
|
-
}
|
|
117
|
-
return res.json();
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// ---------------------------------------------------------------------------
|
|
121
|
-
// Execution types
|
|
122
|
-
// ---------------------------------------------------------------------------
|
|
123
|
-
|
|
124
|
-
export interface AuditEntry {
|
|
125
|
-
id: number;
|
|
126
|
-
step_id: string;
|
|
127
|
-
action_type: string;
|
|
128
|
-
target_system: string;
|
|
129
|
-
target_object: string;
|
|
130
|
-
mutation_performed: string;
|
|
131
|
-
result: Record<string, unknown>;
|
|
132
|
-
rollback_available: boolean;
|
|
133
|
-
created_at: string;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// ---------------------------------------------------------------------------
|
|
137
|
-
// Execution API functions
|
|
138
|
-
// ---------------------------------------------------------------------------
|
|
139
|
-
|
|
140
|
-
export async function startExecution(taskId: number): Promise<Record<string, unknown>> {
|
|
141
|
-
const res = await fetch(`${API_BASE}/api/tasks/${taskId}/execute`, { method: 'POST' });
|
|
142
|
-
if (!res.ok) {
|
|
143
|
-
const err = await res.json().catch(() => ({ detail: res.statusText }));
|
|
144
|
-
throw new Error(err.detail ?? `API error: ${res.status}`);
|
|
145
|
-
}
|
|
146
|
-
return res.json();
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export async function pauseExecution(taskId: number): Promise<void> {
|
|
150
|
-
await fetch(`${API_BASE}/api/tasks/${taskId}/pause`, { method: 'POST' });
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export async function resumeExecution(taskId: number): Promise<void> {
|
|
154
|
-
await fetch(`${API_BASE}/api/tasks/${taskId}/resume`, { method: 'POST' });
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export async function retryStep(taskId: number, stepId: number): Promise<void> {
|
|
158
|
-
await fetch(`${API_BASE}/api/tasks/${taskId}/steps/${stepId}/retry`, { method: 'POST' });
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
export async function getAuditLog(taskId: number): Promise<AuditEntry[]> {
|
|
162
|
-
const res = await fetch(`${API_BASE}/api/tasks/${taskId}/audit-log`);
|
|
163
|
-
if (!res.ok) return [];
|
|
164
|
-
const data = await res.json();
|
|
165
|
-
return data.entries ?? [];
|
|
166
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* API client for the FTM Inbox backend.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const API_BASE = 'http://localhost:8042';
|
|
6
|
+
|
|
7
|
+
export interface UnifiedTask {
|
|
8
|
+
id: number;
|
|
9
|
+
source: string;
|
|
10
|
+
source_id: string;
|
|
11
|
+
title: string;
|
|
12
|
+
body: string;
|
|
13
|
+
status: string;
|
|
14
|
+
priority: string;
|
|
15
|
+
assignee: string | null;
|
|
16
|
+
requester: string | null;
|
|
17
|
+
created_at: string | null;
|
|
18
|
+
updated_at: string | null;
|
|
19
|
+
tags: string[];
|
|
20
|
+
custom_fields: Record<string, unknown>;
|
|
21
|
+
source_url: string | null;
|
|
22
|
+
content_hash: string | null;
|
|
23
|
+
ingested_at: string | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface InboxResponse {
|
|
27
|
+
tasks: UnifiedTask[];
|
|
28
|
+
total: number;
|
|
29
|
+
page: number;
|
|
30
|
+
per_page: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function fetchInbox(source?: string, page = 1): Promise<InboxResponse> {
|
|
34
|
+
const params = new URLSearchParams({ page: String(page) });
|
|
35
|
+
if (source && source !== 'all') params.set('source', source);
|
|
36
|
+
const res = await fetch(`${API_BASE}/api/inbox?${params}`);
|
|
37
|
+
if (!res.ok) throw new Error(`API error: ${res.status}`);
|
|
38
|
+
return res.json();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function fetchSources(): Promise<{ name: string; count: number }[]> {
|
|
42
|
+
const res = await fetch(`${API_BASE}/api/inbox/sources`);
|
|
43
|
+
if (!res.ok) return [];
|
|
44
|
+
const data = await res.json();
|
|
45
|
+
return data.sources ?? [];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// Plan types
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
|
|
52
|
+
export interface PlanStep {
|
|
53
|
+
id: number;
|
|
54
|
+
title: string;
|
|
55
|
+
target_system: string;
|
|
56
|
+
method_primary: string;
|
|
57
|
+
method_fallback: string;
|
|
58
|
+
risk_level: string;
|
|
59
|
+
approval_required: boolean;
|
|
60
|
+
rollback: string;
|
|
61
|
+
status: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface Plan {
|
|
65
|
+
id: number;
|
|
66
|
+
task_id: number;
|
|
67
|
+
steps: PlanStep[];
|
|
68
|
+
status: string;
|
|
69
|
+
yaml_content: string;
|
|
70
|
+
created_at: string | null;
|
|
71
|
+
updated_at: string | null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
// Plan API functions
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
export async function generatePlan(taskId: number): Promise<Plan> {
|
|
79
|
+
const res = await fetch(`${API_BASE}/api/tasks/${taskId}/generate-plan`, {
|
|
80
|
+
method: 'POST'
|
|
81
|
+
});
|
|
82
|
+
if (!res.ok) {
|
|
83
|
+
const err = await res.json().catch(() => ({ detail: res.statusText }));
|
|
84
|
+
throw new Error(err.detail ?? `API error: ${res.status}`);
|
|
85
|
+
}
|
|
86
|
+
return res.json();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export async function getPlan(taskId: number): Promise<Plan | null> {
|
|
90
|
+
const res = await fetch(`${API_BASE}/api/tasks/${taskId}/plan`);
|
|
91
|
+
if (!res.ok) return null;
|
|
92
|
+
const data = await res.json();
|
|
93
|
+
// Backend returns { plan: null } when no plan exists
|
|
94
|
+
if ('plan' in data && data.plan === null) return null;
|
|
95
|
+
return data as Plan;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export async function approveStep(taskId: number, stepId: number): Promise<Plan> {
|
|
99
|
+
const res = await fetch(`${API_BASE}/api/tasks/${taskId}/plan/steps/${stepId}/approve`, {
|
|
100
|
+
method: 'POST'
|
|
101
|
+
});
|
|
102
|
+
if (!res.ok) {
|
|
103
|
+
const err = await res.json().catch(() => ({ detail: res.statusText }));
|
|
104
|
+
throw new Error(err.detail ?? `API error: ${res.status}`);
|
|
105
|
+
}
|
|
106
|
+
return res.json();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export async function approveAllSteps(taskId: number): Promise<Plan> {
|
|
110
|
+
const res = await fetch(`${API_BASE}/api/tasks/${taskId}/plan/approve-all`, {
|
|
111
|
+
method: 'POST'
|
|
112
|
+
});
|
|
113
|
+
if (!res.ok) {
|
|
114
|
+
const err = await res.json().catch(() => ({ detail: res.statusText }));
|
|
115
|
+
throw new Error(err.detail ?? `API error: ${res.status}`);
|
|
116
|
+
}
|
|
117
|
+
return res.json();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
// Execution types
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
|
|
124
|
+
export interface AuditEntry {
|
|
125
|
+
id: number;
|
|
126
|
+
step_id: string;
|
|
127
|
+
action_type: string;
|
|
128
|
+
target_system: string;
|
|
129
|
+
target_object: string;
|
|
130
|
+
mutation_performed: string;
|
|
131
|
+
result: Record<string, unknown>;
|
|
132
|
+
rollback_available: boolean;
|
|
133
|
+
created_at: string;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
// Execution API functions
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
|
|
140
|
+
export async function startExecution(taskId: number): Promise<Record<string, unknown>> {
|
|
141
|
+
const res = await fetch(`${API_BASE}/api/tasks/${taskId}/execute`, { method: 'POST' });
|
|
142
|
+
if (!res.ok) {
|
|
143
|
+
const err = await res.json().catch(() => ({ detail: res.statusText }));
|
|
144
|
+
throw new Error(err.detail ?? `API error: ${res.status}`);
|
|
145
|
+
}
|
|
146
|
+
return res.json();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export async function pauseExecution(taskId: number): Promise<void> {
|
|
150
|
+
await fetch(`${API_BASE}/api/tasks/${taskId}/pause`, { method: 'POST' });
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export async function resumeExecution(taskId: number): Promise<void> {
|
|
154
|
+
await fetch(`${API_BASE}/api/tasks/${taskId}/resume`, { method: 'POST' });
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export async function retryStep(taskId: number, stepId: number): Promise<void> {
|
|
158
|
+
await fetch(`${API_BASE}/api/tasks/${taskId}/steps/${stepId}/retry`, { method: 'POST' });
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export async function getAuditLog(taskId: number): Promise<AuditEntry[]> {
|
|
162
|
+
const res = await fetch(`${API_BASE}/api/tasks/${taskId}/audit-log`);
|
|
163
|
+
if (!res.ok) return [];
|
|
164
|
+
const data = await res.json();
|
|
165
|
+
return data.entries ?? [];
|
|
166
|
+
}
|
|
@@ -1,81 +1,81 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { AuditEntry } from '$lib/api';
|
|
3
|
-
|
|
4
|
-
export let entries: AuditEntry[] = [];
|
|
5
|
-
|
|
6
|
-
const levelColors: Record<string, string> = {
|
|
7
|
-
info: '#66bb6a',
|
|
8
|
-
warn: '#ffd54f',
|
|
9
|
-
success: '#4caf50',
|
|
10
|
-
error: '#ef5350'
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
function levelFromAction(entry: AuditEntry): string {
|
|
14
|
-
const result = entry.result as Record<string, unknown>;
|
|
15
|
-
if (result?.status === 'failed') return 'error';
|
|
16
|
-
if (result?.status === 'completed') return 'success';
|
|
17
|
-
return 'info';
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function formatTime(dateStr: string): string {
|
|
21
|
-
try {
|
|
22
|
-
return new Date(dateStr).toLocaleTimeString('en-GB', { hour12: false });
|
|
23
|
-
} catch {
|
|
24
|
-
return dateStr;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
</script>
|
|
28
|
-
|
|
29
|
-
<div class="exec-log">
|
|
30
|
-
{#each entries as entry (entry.id)}
|
|
31
|
-
{@const level = levelFromAction(entry)}
|
|
32
|
-
<div class="log-entry" style="border-left-color: {levelColors[level] ?? '#66bb6a'}">
|
|
33
|
-
<span class="log-time">{formatTime(entry.created_at)}</span>
|
|
34
|
-
<span class="log-action">{entry.action_type}</span>
|
|
35
|
-
<span class="log-target">{entry.target_object}</span>
|
|
36
|
-
</div>
|
|
37
|
-
{/each}
|
|
38
|
-
</div>
|
|
39
|
-
|
|
40
|
-
<style>
|
|
41
|
-
.exec-log {
|
|
42
|
-
display: flex;
|
|
43
|
-
flex-direction: column;
|
|
44
|
-
gap: 0.25rem;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.log-entry {
|
|
48
|
-
display: flex;
|
|
49
|
-
flex-direction: column;
|
|
50
|
-
gap: 0.1rem;
|
|
51
|
-
padding: 0.35rem 0.5rem;
|
|
52
|
-
border-radius: 8px;
|
|
53
|
-
font-size: 0.72rem;
|
|
54
|
-
border-left: 3px solid #66bb6a;
|
|
55
|
-
transition: background 0.1s;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.log-entry:hover {
|
|
59
|
-
background: rgba(76, 175, 80, 0.04);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.log-time {
|
|
63
|
-
font-family: 'Menlo', monospace;
|
|
64
|
-
font-size: 0.65rem;
|
|
65
|
-
color: var(--text-muted);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.log-action {
|
|
69
|
-
font-weight: 700;
|
|
70
|
-
color: var(--text-secondary);
|
|
71
|
-
text-transform: uppercase;
|
|
72
|
-
font-size: 0.6rem;
|
|
73
|
-
letter-spacing: 0.05em;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
.log-target {
|
|
77
|
-
color: var(--text-primary);
|
|
78
|
-
font-weight: 600;
|
|
79
|
-
line-height: 1.4;
|
|
80
|
-
}
|
|
81
|
-
</style>
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { AuditEntry } from '$lib/api';
|
|
3
|
+
|
|
4
|
+
export let entries: AuditEntry[] = [];
|
|
5
|
+
|
|
6
|
+
const levelColors: Record<string, string> = {
|
|
7
|
+
info: '#66bb6a',
|
|
8
|
+
warn: '#ffd54f',
|
|
9
|
+
success: '#4caf50',
|
|
10
|
+
error: '#ef5350'
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
function levelFromAction(entry: AuditEntry): string {
|
|
14
|
+
const result = entry.result as Record<string, unknown>;
|
|
15
|
+
if (result?.status === 'failed') return 'error';
|
|
16
|
+
if (result?.status === 'completed') return 'success';
|
|
17
|
+
return 'info';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function formatTime(dateStr: string): string {
|
|
21
|
+
try {
|
|
22
|
+
return new Date(dateStr).toLocaleTimeString('en-GB', { hour12: false });
|
|
23
|
+
} catch {
|
|
24
|
+
return dateStr;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<div class="exec-log">
|
|
30
|
+
{#each entries as entry (entry.id)}
|
|
31
|
+
{@const level = levelFromAction(entry)}
|
|
32
|
+
<div class="log-entry" style="border-left-color: {levelColors[level] ?? '#66bb6a'}">
|
|
33
|
+
<span class="log-time">{formatTime(entry.created_at)}</span>
|
|
34
|
+
<span class="log-action">{entry.action_type}</span>
|
|
35
|
+
<span class="log-target">{entry.target_object}</span>
|
|
36
|
+
</div>
|
|
37
|
+
{/each}
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<style>
|
|
41
|
+
.exec-log {
|
|
42
|
+
display: flex;
|
|
43
|
+
flex-direction: column;
|
|
44
|
+
gap: 0.25rem;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.log-entry {
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-direction: column;
|
|
50
|
+
gap: 0.1rem;
|
|
51
|
+
padding: 0.35rem 0.5rem;
|
|
52
|
+
border-radius: 8px;
|
|
53
|
+
font-size: 0.72rem;
|
|
54
|
+
border-left: 3px solid #66bb6a;
|
|
55
|
+
transition: background 0.1s;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.log-entry:hover {
|
|
59
|
+
background: rgba(76, 175, 80, 0.04);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.log-time {
|
|
63
|
+
font-family: 'Menlo', monospace;
|
|
64
|
+
font-size: 0.65rem;
|
|
65
|
+
color: var(--text-muted);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.log-action {
|
|
69
|
+
font-weight: 700;
|
|
70
|
+
color: var(--text-secondary);
|
|
71
|
+
text-transform: uppercase;
|
|
72
|
+
font-size: 0.6rem;
|
|
73
|
+
letter-spacing: 0.05em;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.log-target {
|
|
77
|
+
color: var(--text-primary);
|
|
78
|
+
font-weight: 600;
|
|
79
|
+
line-height: 1.4;
|
|
80
|
+
}
|
|
81
|
+
</style>
|