@intutic/sync-daemon 1.10.0 → 1.10.1
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 +2 -2
- package/dist/agentReporter.d.ts +205 -0
- package/dist/agentReporter.d.ts.map +1 -0
- package/dist/agentReporter.js +394 -0
- package/dist/agentReporter.js.map +1 -0
- package/dist/configReader.d.ts +39 -2
- package/dist/configReader.d.ts.map +1 -1
- package/dist/configReader.js +56 -2
- package/dist/configReader.js.map +1 -1
- package/dist/configWriter.d.ts +51 -1
- package/dist/configWriter.d.ts.map +1 -1
- package/dist/configWriter.js +490 -63
- package/dist/configWriter.js.map +1 -1
- package/dist/harness/antigravityHooks.d.ts.map +1 -1
- package/dist/harness/antigravityHooks.js +33 -55
- package/dist/harness/antigravityHooks.js.map +1 -1
- package/dist/harness/claudeCodeHooks.d.ts +47 -13
- package/dist/harness/claudeCodeHooks.d.ts.map +1 -1
- package/dist/harness/claudeCodeHooks.js +316 -54
- package/dist/harness/claudeCodeHooks.js.map +1 -1
- package/dist/harness/claudeDesktopHooks.d.ts.map +1 -1
- package/dist/harness/claudeDesktopHooks.js +35 -48
- package/dist/harness/claudeDesktopHooks.js.map +1 -1
- package/dist/harness/clineHooks.d.ts.map +1 -1
- package/dist/harness/clineHooks.js +42 -34
- package/dist/harness/clineHooks.js.map +1 -1
- package/dist/harness/codexHooks.d.ts +36 -0
- package/dist/harness/codexHooks.d.ts.map +1 -0
- package/dist/harness/codexHooks.js +227 -0
- package/dist/harness/codexHooks.js.map +1 -0
- package/dist/harness/continueHooks.d.ts +45 -5
- package/dist/harness/continueHooks.d.ts.map +1 -1
- package/dist/harness/continueHooks.js +225 -5
- package/dist/harness/continueHooks.js.map +1 -1
- package/dist/harness/cursorHooks.d.ts +31 -0
- package/dist/harness/cursorHooks.d.ts.map +1 -1
- package/dist/harness/cursorHooks.js +78 -49
- package/dist/harness/cursorHooks.js.map +1 -1
- package/dist/harness/dshHooks.d.ts +198 -0
- package/dist/harness/dshHooks.d.ts.map +1 -0
- package/dist/harness/dshHooks.js +569 -0
- package/dist/harness/dshHooks.js.map +1 -0
- package/dist/harness/gateBody.d.ts +422 -0
- package/dist/harness/gateBody.d.ts.map +1 -0
- package/dist/harness/gateBody.js +1816 -0
- package/dist/harness/gateBody.js.map +1 -0
- package/dist/harness/gateKind.d.ts +164 -0
- package/dist/harness/gateKind.d.ts.map +1 -0
- package/dist/harness/gateKind.js +143 -0
- package/dist/harness/gateKind.js.map +1 -0
- package/dist/harness/githubCopilotHooks.d.ts +54 -0
- package/dist/harness/githubCopilotHooks.d.ts.map +1 -0
- package/dist/harness/githubCopilotHooks.js +218 -0
- package/dist/harness/githubCopilotHooks.js.map +1 -0
- package/dist/harness/gooseHooks.d.ts.map +1 -1
- package/dist/harness/gooseHooks.js +67 -37
- package/dist/harness/gooseHooks.js.map +1 -1
- package/dist/harness/grokHooks.d.ts +77 -0
- package/dist/harness/grokHooks.d.ts.map +1 -0
- package/dist/harness/grokHooks.js +350 -0
- package/dist/harness/grokHooks.js.map +1 -0
- package/dist/harness/hermesHooks.d.ts.map +1 -1
- package/dist/harness/hermesHooks.js +26 -55
- package/dist/harness/hermesHooks.js.map +1 -1
- package/dist/harness/holdRedaction.d.ts +69 -0
- package/dist/harness/holdRedaction.d.ts.map +1 -0
- package/dist/harness/holdRedaction.js +211 -0
- package/dist/harness/holdRedaction.js.map +1 -0
- package/dist/harness/jetbrainsXmlConfig.d.ts +51 -0
- package/dist/harness/jetbrainsXmlConfig.d.ts.map +1 -0
- package/dist/harness/jetbrainsXmlConfig.js +151 -0
- package/dist/harness/jetbrainsXmlConfig.js.map +1 -0
- package/dist/harness/mcpAutoWrite.d.ts +100 -3
- package/dist/harness/mcpAutoWrite.d.ts.map +1 -1
- package/dist/harness/mcpAutoWrite.js +712 -90
- package/dist/harness/mcpAutoWrite.js.map +1 -1
- package/dist/harness/museHooks.d.ts +53 -0
- package/dist/harness/museHooks.d.ts.map +1 -0
- package/dist/harness/museHooks.js +273 -0
- package/dist/harness/museHooks.js.map +1 -0
- package/dist/harness/n8nHooks.d.ts +25 -9
- package/dist/harness/n8nHooks.d.ts.map +1 -1
- package/dist/harness/n8nHooks.js +174 -9
- package/dist/harness/n8nHooks.js.map +1 -1
- package/dist/harness/openCodeHooks.d.ts +93 -0
- package/dist/harness/openCodeHooks.d.ts.map +1 -0
- package/dist/harness/openCodeHooks.js +248 -0
- package/dist/harness/openCodeHooks.js.map +1 -0
- package/dist/harness/openWebuiHooks.d.ts.map +1 -1
- package/dist/harness/openWebuiHooks.js +56 -11
- package/dist/harness/openWebuiHooks.js.map +1 -1
- package/dist/harness/openclawHooks.d.ts.map +1 -1
- package/dist/harness/openclawHooks.js +30 -54
- package/dist/harness/openclawHooks.js.map +1 -1
- package/dist/harness/openhandsHooks.d.ts.map +1 -1
- package/dist/harness/openhandsHooks.js +35 -41
- package/dist/harness/openhandsHooks.js.map +1 -1
- package/dist/harness/piHooks.d.ts.map +1 -1
- package/dist/harness/piHooks.js +31 -58
- package/dist/harness/piHooks.js.map +1 -1
- package/dist/harness/protectedPaths.d.ts +353 -0
- package/dist/harness/protectedPaths.d.ts.map +1 -0
- package/dist/harness/protectedPaths.js +805 -0
- package/dist/harness/protectedPaths.js.map +1 -0
- package/dist/harness/rooCodeHooks.d.ts.map +1 -1
- package/dist/harness/rooCodeHooks.js +34 -48
- package/dist/harness/rooCodeHooks.js.map +1 -1
- package/dist/harness/windsurfHooks.d.ts +72 -0
- package/dist/harness/windsurfHooks.d.ts.map +1 -1
- package/dist/harness/windsurfHooks.js +172 -58
- package/dist/harness/windsurfHooks.js.map +1 -1
- package/dist/harness/windsurfJetBrainsProxy.d.ts +78 -0
- package/dist/harness/windsurfJetBrainsProxy.d.ts.map +1 -0
- package/dist/harness/windsurfJetBrainsProxy.js +159 -0
- package/dist/harness/windsurfJetBrainsProxy.js.map +1 -0
- package/dist/hashReporter.js +1 -1
- package/dist/hashReporter.js.map +1 -1
- package/dist/index.d.ts +12 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -6
- package/dist/index.js.map +1 -1
- package/dist/integrityStore.d.ts +0 -8
- package/dist/integrityStore.d.ts.map +1 -1
- package/dist/integrityStore.js +6 -29
- package/dist/integrityStore.js.map +1 -1
- package/dist/lib/approvedBypasses.d.ts +76 -0
- package/dist/lib/approvedBypasses.d.ts.map +1 -0
- package/dist/lib/approvedBypasses.js +140 -0
- package/dist/lib/approvedBypasses.js.map +1 -0
- package/dist/lib/complianceProbes.d.ts.map +1 -1
- package/dist/lib/complianceProbes.js +5 -0
- package/dist/lib/complianceProbes.js.map +1 -1
- package/dist/lib/decisionsDigest.d.ts +99 -0
- package/dist/lib/decisionsDigest.d.ts.map +1 -0
- package/dist/lib/decisionsDigest.js +199 -0
- package/dist/lib/decisionsDigest.js.map +1 -0
- package/dist/lib/egressPolicy.d.ts +69 -0
- package/dist/lib/egressPolicy.d.ts.map +1 -0
- package/dist/lib/egressPolicy.js +126 -0
- package/dist/lib/egressPolicy.js.map +1 -0
- package/dist/lib/gitWorktrees.d.ts +140 -0
- package/dist/lib/gitWorktrees.d.ts.map +1 -0
- package/dist/lib/gitWorktrees.js +191 -0
- package/dist/lib/gitWorktrees.js.map +1 -0
- package/dist/lib/policySnapshot.d.ts +224 -0
- package/dist/lib/policySnapshot.d.ts.map +1 -0
- package/dist/lib/policySnapshot.js +637 -0
- package/dist/lib/policySnapshot.js.map +1 -0
- package/dist/lib/processPoller.d.ts +44 -0
- package/dist/lib/processPoller.d.ts.map +1 -1
- package/dist/lib/processPoller.js +176 -1
- package/dist/lib/processPoller.js.map +1 -1
- package/dist/lib/runtimeEnv.d.ts +8 -0
- package/dist/lib/runtimeEnv.d.ts.map +1 -1
- package/dist/lib/runtimeEnv.js +3 -0
- package/dist/lib/runtimeEnv.js.map +1 -1
- package/dist/localTrajectoryHeuristics.d.ts +51 -0
- package/dist/localTrajectoryHeuristics.d.ts.map +1 -0
- package/dist/localTrajectoryHeuristics.js +90 -0
- package/dist/localTrajectoryHeuristics.js.map +1 -0
- package/dist/sessionReporter.d.ts +70 -0
- package/dist/sessionReporter.d.ts.map +1 -0
- package/dist/sessionReporter.js +140 -0
- package/dist/sessionReporter.js.map +1 -0
- package/dist/skillWriter.d.ts +1 -1
- package/dist/skillWriter.d.ts.map +1 -1
- package/dist/skillWriter.js +5 -2
- package/dist/skillWriter.js.map +1 -1
- package/dist/syncLoop.d.ts +105 -3
- package/dist/syncLoop.d.ts.map +1 -1
- package/dist/syncLoop.js +397 -65
- package/dist/syncLoop.js.map +1 -1
- package/dist/trajectoryMonitor.d.ts +2 -0
- package/dist/trajectoryMonitor.d.ts.map +1 -1
- package/dist/trajectoryMonitor.js +57 -0
- package/dist/trajectoryMonitor.js.map +1 -1
- package/dist/watcher/driftWatcher.d.ts.map +1 -1
- package/dist/watcher/driftWatcher.js +12 -3
- package/dist/watcher/driftWatcher.js.map +1 -1
- package/dist/watcher/settingsGuard.d.ts +23 -0
- package/dist/watcher/settingsGuard.d.ts.map +1 -1
- package/dist/watcher/settingsGuard.js +202 -17
- package/dist/watcher/settingsGuard.js.map +1 -1
- package/package.json +37 -6
- package/dist/brainIndexer.d.ts +0 -51
- package/dist/brainIndexer.d.ts.map +0 -1
- package/dist/brainIndexer.js +0 -148
- package/dist/brainIndexer.js.map +0 -1
- package/dist/harness/cursorHooksJson.d.ts +0 -29
- package/dist/harness/cursorHooksJson.d.ts.map +0 -1
- package/dist/harness/cursorHooksJson.js +0 -130
- package/dist/harness/cursorHooksJson.js.map +0 -1
- package/dist/harness/gooseHooksWriter.d.ts +0 -27
- package/dist/harness/gooseHooksWriter.d.ts.map +0 -1
- package/dist/harness/gooseHooksWriter.js +0 -147
- package/dist/harness/gooseHooksWriter.js.map +0 -1
- package/dist/harness/openhandsHooksWriter.d.ts +0 -23
- package/dist/harness/openhandsHooksWriter.d.ts.map +0 -1
- package/dist/harness/openhandsHooksWriter.js +0 -146
- package/dist/harness/openhandsHooksWriter.js.map +0 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ fetch config → write harness files → compute hashes → report drift
|
|
|
15
15
|
On each sync cycle the daemon:
|
|
16
16
|
|
|
17
17
|
1. **Fetches** the latest SOP configuration from the control plane
|
|
18
|
-
2. **Writes** harness-specific config files using
|
|
18
|
+
2. **Writes** harness-specific config files using 19 format-aware config writers
|
|
19
19
|
3. **Computes** content hashes for drift detection
|
|
20
20
|
4. **Reports** any detected drift back to the control plane
|
|
21
21
|
|
|
@@ -23,7 +23,7 @@ On each sync cycle the daemon:
|
|
|
23
23
|
|
|
24
24
|
### Config Writers
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Harness-specific config writers (one module per harness under `src/harness/`) that translate governance SOPs into native configuration formats (YAML, JSON, TOML, Markdown, environment variables); most of them emit blocking pre-tool gates. The authoritative list of which harness gets which gate shape is `src/harness/gateKind.ts`, and `__tests__/harness/gateRegistry.ts` exercises every generated gate — counts are not repeated here because they drifted every time a harness was added.
|
|
27
27
|
|
|
28
28
|
### Atomic Writes
|
|
29
29
|
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agentReporter.ts — register the workspace's agents with the control plane.
|
|
3
|
+
*
|
|
4
|
+
* Each detected harness is a durable agent identity. On the sync loop, the
|
|
5
|
+
* daemon collects the facets it can see locally — the configured guardrails,
|
|
6
|
+
* the role SOPs on disk, the skills bundled into the workspace, the MCP servers
|
|
7
|
+
* declared in the harness config, and the budget tier — and reports them to
|
|
8
|
+
* `POST /api/v1/agents/report`. The control plane rescores posture on each
|
|
9
|
+
* report, so the dashboard ring stays live.
|
|
10
|
+
*
|
|
11
|
+
* The daemon only reports what is locally observable; the control plane owns
|
|
12
|
+
* anything requiring cross-session state (agent-to-agent links from session
|
|
13
|
+
* parentage, spend actuals).
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
import { type HarnessType } from '@intutic/shared-types';
|
|
18
|
+
/** Live egress-enforcement status read from the proxy's own diagnostic endpoint. */
|
|
19
|
+
export interface EgressFacet {
|
|
20
|
+
mode: string;
|
|
21
|
+
denied: number;
|
|
22
|
+
would_deny: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Summary of the proxy's last scheduled guard-liveness probe run
|
|
26
|
+
* (`GET /intutic/probes`, Wave 6.1 audit-remediation). `ranAt` is the Unix
|
|
27
|
+
* timestamp the *scheduled loop* recorded, not when this fetch ran — a dead
|
|
28
|
+
* loop shows up here as a timestamp that stops advancing, not a fresh
|
|
29
|
+
* "just ran" answer every cycle.
|
|
30
|
+
*/
|
|
31
|
+
export interface GuardProbesFacet {
|
|
32
|
+
total: number;
|
|
33
|
+
failed: number;
|
|
34
|
+
ranAt: number;
|
|
35
|
+
/** probe_id of every failing probe, capped at 10 — enough to act on
|
|
36
|
+
* without turning this into an unbounded transcript. */
|
|
37
|
+
failing: string[];
|
|
38
|
+
}
|
|
39
|
+
interface AgentFacets {
|
|
40
|
+
guardrails: {
|
|
41
|
+
dlp: boolean;
|
|
42
|
+
wasm_rules: number;
|
|
43
|
+
/**
|
|
44
|
+
* True only when this harness's gate mechanism is `'hook'` (an on-disk
|
|
45
|
+
* file the daemon writes and verified existence of) — kept for older
|
|
46
|
+
* control-plane deployments that read this boolean directly. `false` for
|
|
47
|
+
* `gateKind: 'sdk'` is NOT "this harness is unprotected"; see
|
|
48
|
+
* `gate_kind` below and `harness/gateKind.ts`'s module doc. Previously
|
|
49
|
+
* hardcoded `true` for every harness regardless of mechanism.
|
|
50
|
+
*/
|
|
51
|
+
hook_gate: boolean;
|
|
52
|
+
/** How this harness's tool calls get gated — see `harness/gateKind.ts`. */
|
|
53
|
+
gate_kind: import('./harness/gateKind.js').GateKind;
|
|
54
|
+
pcas: boolean;
|
|
55
|
+
/** Present when the local proxy answered GET /intutic/egress (LLD #63 §4). */
|
|
56
|
+
egress?: EgressFacet;
|
|
57
|
+
};
|
|
58
|
+
sops: Array<{
|
|
59
|
+
sop_id: string;
|
|
60
|
+
name: string;
|
|
61
|
+
enforced: boolean;
|
|
62
|
+
}>;
|
|
63
|
+
budgets: {
|
|
64
|
+
tier?: string;
|
|
65
|
+
};
|
|
66
|
+
mcp_tools: Array<{
|
|
67
|
+
server: string;
|
|
68
|
+
harness: string;
|
|
69
|
+
transport: string;
|
|
70
|
+
wrapped: boolean;
|
|
71
|
+
}>;
|
|
72
|
+
skills: Array<{
|
|
73
|
+
name: string;
|
|
74
|
+
source: string;
|
|
75
|
+
/** Whether `scanSkillContent` actually ran against this skill's
|
|
76
|
+
* `SKILL.md`. `false` on a read failure — never omitted, and never
|
|
77
|
+
* paired with `clean: true`; see `collectSkills` below. */
|
|
78
|
+
scanned: boolean;
|
|
79
|
+
/** Only meaningful when `scanned` is `true`. `false` means the content
|
|
80
|
+
* scan found at least one pattern match (report-only — see
|
|
81
|
+
* `packages/shared-types/src/skillScan.ts`'s doc comment; nothing here
|
|
82
|
+
* blocks or modifies the skill). */
|
|
83
|
+
clean: boolean;
|
|
84
|
+
/** Count of findings when scanned and not clean; `0` when scanned+clean
|
|
85
|
+
* or when unscanned (there is nothing to count). */
|
|
86
|
+
findingsCount: number;
|
|
87
|
+
/**
|
|
88
|
+
* Bundled-script enumeration for this skill (TD-356, Phase S2) — files
|
|
89
|
+
* alongside `SKILL.md` inside the same skill directory, discovered by
|
|
90
|
+
* the same bounded, symlink-skipping walk `discoverSkillBundledFiles`
|
|
91
|
+
* (`tools/cli/src/commands/skill.ts`) uses, and content-scanned via
|
|
92
|
+
* `scanScriptContent` when a recognized language and within
|
|
93
|
+
* `MAX_SCRIPT_SCAN_BYTES`. Omitted (not `{total: 0, ...}`) when the
|
|
94
|
+
* skill has no bundled files at all — `agentPosture.ts`'s `skills`
|
|
95
|
+
* scorer treats an absent facet as "nothing to say," not as a finding.
|
|
96
|
+
*/
|
|
97
|
+
scripts?: {
|
|
98
|
+
/** Every bundled file the walk found, scanned or not. */
|
|
99
|
+
total: number;
|
|
100
|
+
/** How many of `total` were actually content-scanned — excludes
|
|
101
|
+
* unreadable files, files over the byte cap (refused, not skipped),
|
|
102
|
+
* and files whose language `detectScriptLanguage` could not
|
|
103
|
+
* determine. */
|
|
104
|
+
scanned: number;
|
|
105
|
+
/** How many of `scanned` came back with at least one finding. */
|
|
106
|
+
flagged: number;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* sha256 of the `SKILL.md` content this row describes (Phase S5,
|
|
110
|
+
* TD-357) — lets `services/control-plane/src/routes/agents.ts` look up
|
|
111
|
+
* a previously-judged semantic verdict
|
|
112
|
+
* (`services/semanticSkillAnalysisService.ts`'s `skills:semantic:*`
|
|
113
|
+
* Valkey entry) keyed by the exact content this cycle read, without this
|
|
114
|
+
* daemon ever transmitting the content itself over `/api/v1/agents/report`
|
|
115
|
+
* — only the CLI's `/skills/report` path (opt-in,
|
|
116
|
+
* `semanticSkillAnalysisEnabled`) does that. Absent when `SKILL.md`
|
|
117
|
+
* could not be read.
|
|
118
|
+
*/
|
|
119
|
+
sha256?: string;
|
|
120
|
+
}>;
|
|
121
|
+
loops: {
|
|
122
|
+
configured: boolean;
|
|
123
|
+
};
|
|
124
|
+
harness: {
|
|
125
|
+
type: string;
|
|
126
|
+
config_synced: boolean;
|
|
127
|
+
};
|
|
128
|
+
memory: Array<{
|
|
129
|
+
provider: string;
|
|
130
|
+
configured: boolean;
|
|
131
|
+
}>;
|
|
132
|
+
/**
|
|
133
|
+
* Present only when the local proxy answered `GET /intutic/probes`. A
|
|
134
|
+
* sibling of `guardrails`, not a member of it — `guardrails` already names
|
|
135
|
+
* one boolean/count per guard mechanism (dlp, wasm_rules, hook_gate, pcas,
|
|
136
|
+
* egress); guard-liveness is a different axis (did the loaded guards prove
|
|
137
|
+
* themselves against a live probe, on a schedule) and collapsing it into
|
|
138
|
+
* `guardrails` would make `hasOwnProperty` checks there ambiguous between
|
|
139
|
+
* "this guard exists" and "this guard is alive". Absence here (vs. a
|
|
140
|
+
* present-but-empty facet) is itself meaningful to `agentPosture.ts`: no
|
|
141
|
+
* report means `not_enforced`, never a silent pass.
|
|
142
|
+
*/
|
|
143
|
+
guardProbes?: GuardProbesFacet;
|
|
144
|
+
}
|
|
145
|
+
export interface AgentReport {
|
|
146
|
+
agentKey: string;
|
|
147
|
+
displayName: string;
|
|
148
|
+
harnessType: string;
|
|
149
|
+
agentRole: string;
|
|
150
|
+
facets: AgentFacets;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Read the local proxy's egress-enforcement status (LLD #63 §4). The proxy
|
|
154
|
+
* exposes `{mode, denied, would_deny}` at `GET /intutic/egress`, but nothing
|
|
155
|
+
* plumbed those counters off the machine — this is the wiring that carries them
|
|
156
|
+
* up so an egress denial is visible in the dashboard, not just the proxy log.
|
|
157
|
+
* Best-effort: an unreachable or non-managed proxy simply omits the facet.
|
|
158
|
+
*/
|
|
159
|
+
export declare function fetchEgressStatus(): Promise<EgressFacet | null>;
|
|
160
|
+
/**
|
|
161
|
+
* Read the local proxy's last scheduled guard-liveness probe run
|
|
162
|
+
* (`GET /intutic/probes`, loopback-only — this must run on the same machine
|
|
163
|
+
* as the proxy, exactly like `fetchEgressStatus` above). Best-effort: an
|
|
164
|
+
* unreachable proxy, a 403 (non-loopback — should not happen here), or a 503
|
|
165
|
+
* (suite hasn't run yet, the narrow window right after proxy start) all
|
|
166
|
+
* simply omit the facet rather than reporting a false pass.
|
|
167
|
+
*/
|
|
168
|
+
export declare function fetchGuardProbes(): Promise<GuardProbesFacet | null>;
|
|
169
|
+
/**
|
|
170
|
+
* Read the local proxy's process-lifetime instance id (`GET /intutic/instance`,
|
|
171
|
+
* loopback-only like the two probes above; TD-231, Wave 5.6). The control
|
|
172
|
+
* plane derives one `agent_sessions` row per (workspace, harness, instance)
|
|
173
|
+
* for the traces that proxy publishes; knowing the id lets the daemon register
|
|
174
|
+
* that same row with the workspace's git/task context instead of opening a
|
|
175
|
+
* separate `ses_` session the traces never join.
|
|
176
|
+
*
|
|
177
|
+
* Returns `null` — and the caller falls back to a `ses_` session — for an
|
|
178
|
+
* unreachable or non-managed proxy, a non-OK answer, a malformed body, and for
|
|
179
|
+
* a SHARED GATEWAY (`shared_gateway: true`, or an id that does not carry the
|
|
180
|
+
* local `proxy_` prefix): a gateway pod's row aggregates every developer
|
|
181
|
+
* behind it, so one developer's branch must never be written onto it.
|
|
182
|
+
*/
|
|
183
|
+
export declare function fetchLocalProxyInstanceId(): Promise<string | null>;
|
|
184
|
+
/**
|
|
185
|
+
* Build a facet report for one harness in the workspace.
|
|
186
|
+
*
|
|
187
|
+
* `dlpEnabled` / `policyEnforced` come from the daemon's known proxy config;
|
|
188
|
+
* the daemon spawns and configures the proxy, so it knows these without a
|
|
189
|
+
* round-trip.
|
|
190
|
+
*/
|
|
191
|
+
export declare function collectAgentReport(opts: {
|
|
192
|
+
workspaceRoot: string;
|
|
193
|
+
harnessType: HarnessType;
|
|
194
|
+
agentRole?: string;
|
|
195
|
+
configSynced: boolean;
|
|
196
|
+
dlpEnabled: boolean;
|
|
197
|
+
policyEnforced: boolean;
|
|
198
|
+
budgetTier?: string;
|
|
199
|
+
/** Workspace policy: may local vaults feed /fix? Defaults to allowed. */
|
|
200
|
+
allowLocalVaults?: boolean;
|
|
201
|
+
}): Promise<AgentReport>;
|
|
202
|
+
/** POST a report to the control plane. Non-fatal on failure (mirrors reportStatus). */
|
|
203
|
+
export declare function reportAgent(controlPlaneUrl: string, apiKey: string, workspaceId: string, report: AgentReport): Promise<void>;
|
|
204
|
+
export {};
|
|
205
|
+
//# sourceMappingURL=agentReporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentReporter.d.ts","sourceRoot":"","sources":["../src/agentReporter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agentReporter.ts — register the workspace's agents with the control plane.
|
|
3
|
+
*
|
|
4
|
+
* Each detected harness is a durable agent identity. On the sync loop, the
|
|
5
|
+
* daemon collects the facets it can see locally — the configured guardrails,
|
|
6
|
+
* the role SOPs on disk, the skills bundled into the workspace, the MCP servers
|
|
7
|
+
* declared in the harness config, and the budget tier — and reports them to
|
|
8
|
+
* `POST /api/v1/agents/report`. The control plane rescores posture on each
|
|
9
|
+
* report, so the dashboard ring stays live.
|
|
10
|
+
*
|
|
11
|
+
* The daemon only reports what is locally observable; the control plane owns
|
|
12
|
+
* anything requiring cross-session state (agent-to-agent links from session
|
|
13
|
+
* parentage, spend actuals).
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
import { readFile, readdir, access } from 'node:fs/promises';
|
|
18
|
+
import { join } from 'node:path';
|
|
19
|
+
import { createHash } from 'node:crypto';
|
|
20
|
+
import { newIso } from '@intutic/id';
|
|
21
|
+
import { scanSkillContent, scanScriptContent, detectScriptLanguage, MAX_SKILL_DIR_DEPTH, MAX_FILES_PER_SKILL, MAX_SCRIPT_SCAN_BYTES, } from '@intutic/shared-types';
|
|
22
|
+
import { discoverMcpServers } from './harness/mcpAutoWrite.js';
|
|
23
|
+
import { gateKindForHarness } from './harness/gateKind.js';
|
|
24
|
+
async function exists(p) {
|
|
25
|
+
try {
|
|
26
|
+
await access(p);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Read the local proxy's egress-enforcement status (LLD #63 §4). The proxy
|
|
35
|
+
* exposes `{mode, denied, would_deny}` at `GET /intutic/egress`, but nothing
|
|
36
|
+
* plumbed those counters off the machine — this is the wiring that carries them
|
|
37
|
+
* up so an egress denial is visible in the dashboard, not just the proxy log.
|
|
38
|
+
* Best-effort: an unreachable or non-managed proxy simply omits the facet.
|
|
39
|
+
*/
|
|
40
|
+
export async function fetchEgressStatus() {
|
|
41
|
+
// Regex-free trailing-slash trim — CodeQL flags `/\/+$/` as a polynomial
|
|
42
|
+
// pattern even on operator-env input; a loop sidesteps the category.
|
|
43
|
+
let base = process.env.INTUTIC_PROXY_URL ?? 'http://localhost:4000';
|
|
44
|
+
while (base.endsWith('/'))
|
|
45
|
+
base = base.slice(0, -1);
|
|
46
|
+
try {
|
|
47
|
+
const res = await fetch(`${base}/intutic/egress`, { signal: AbortSignal.timeout(2000) });
|
|
48
|
+
if (!res.ok)
|
|
49
|
+
return null;
|
|
50
|
+
const body = (await res.json());
|
|
51
|
+
if (typeof body.mode !== 'string')
|
|
52
|
+
return null;
|
|
53
|
+
return {
|
|
54
|
+
mode: body.mode,
|
|
55
|
+
denied: typeof body.denied === 'number' ? body.denied : 0,
|
|
56
|
+
would_deny: typeof body.would_deny === 'number' ? body.would_deny : 0,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Read the local proxy's last scheduled guard-liveness probe run
|
|
65
|
+
* (`GET /intutic/probes`, loopback-only — this must run on the same machine
|
|
66
|
+
* as the proxy, exactly like `fetchEgressStatus` above). Best-effort: an
|
|
67
|
+
* unreachable proxy, a 403 (non-loopback — should not happen here), or a 503
|
|
68
|
+
* (suite hasn't run yet, the narrow window right after proxy start) all
|
|
69
|
+
* simply omit the facet rather than reporting a false pass.
|
|
70
|
+
*/
|
|
71
|
+
export async function fetchGuardProbes() {
|
|
72
|
+
let base = process.env.INTUTIC_PROXY_URL ?? 'http://localhost:4000';
|
|
73
|
+
while (base.endsWith('/'))
|
|
74
|
+
base = base.slice(0, -1);
|
|
75
|
+
try {
|
|
76
|
+
const res = await fetch(`${base}/intutic/probes`, { signal: AbortSignal.timeout(2000) });
|
|
77
|
+
if (!res.ok)
|
|
78
|
+
return null;
|
|
79
|
+
const body = (await res.json());
|
|
80
|
+
if (typeof body.total !== 'number' || typeof body.failed !== 'number' || typeof body.ran_at !== 'number') {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const probes = Array.isArray(body.probes) ? body.probes : [];
|
|
84
|
+
const failing = probes
|
|
85
|
+
.filter((p) => typeof p === 'object' && p !== null)
|
|
86
|
+
.filter((p) => p.passed === false && typeof p.probe_id === 'string')
|
|
87
|
+
.map((p) => p.probe_id)
|
|
88
|
+
.slice(0, 10);
|
|
89
|
+
return { total: body.total, failed: body.failed, ranAt: body.ran_at, failing };
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Read the local proxy's process-lifetime instance id (`GET /intutic/instance`,
|
|
97
|
+
* loopback-only like the two probes above; TD-231, Wave 5.6). The control
|
|
98
|
+
* plane derives one `agent_sessions` row per (workspace, harness, instance)
|
|
99
|
+
* for the traces that proxy publishes; knowing the id lets the daemon register
|
|
100
|
+
* that same row with the workspace's git/task context instead of opening a
|
|
101
|
+
* separate `ses_` session the traces never join.
|
|
102
|
+
*
|
|
103
|
+
* Returns `null` — and the caller falls back to a `ses_` session — for an
|
|
104
|
+
* unreachable or non-managed proxy, a non-OK answer, a malformed body, and for
|
|
105
|
+
* a SHARED GATEWAY (`shared_gateway: true`, or an id that does not carry the
|
|
106
|
+
* local `proxy_` prefix): a gateway pod's row aggregates every developer
|
|
107
|
+
* behind it, so one developer's branch must never be written onto it.
|
|
108
|
+
*/
|
|
109
|
+
export async function fetchLocalProxyInstanceId() {
|
|
110
|
+
let base = process.env.INTUTIC_PROXY_URL ?? 'http://localhost:4000';
|
|
111
|
+
while (base.endsWith('/'))
|
|
112
|
+
base = base.slice(0, -1);
|
|
113
|
+
try {
|
|
114
|
+
const res = await fetch(`${base}/intutic/instance`, { signal: AbortSignal.timeout(2000) });
|
|
115
|
+
if (!res.ok)
|
|
116
|
+
return null;
|
|
117
|
+
const body = (await res.json());
|
|
118
|
+
if (typeof body.proxy_instance_id !== 'string' || body.shared_gateway === true)
|
|
119
|
+
return null;
|
|
120
|
+
return body.proxy_instance_id.startsWith('proxy_') ? body.proxy_instance_id : null;
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/** Count `.wasm` rules under `~/.intutic/wasm` (best-effort). */
|
|
127
|
+
async function countWasmRules() {
|
|
128
|
+
const dir = join(process.env.HOME ?? '', '.intutic', 'wasm');
|
|
129
|
+
try {
|
|
130
|
+
const entries = await readdir(dir);
|
|
131
|
+
return entries.filter((e) => e.endsWith('.wasm')).length;
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return 0;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** Role SOPs on disk under `<root>/.intutic/sops`. */
|
|
138
|
+
async function collectSops(workspaceRoot) {
|
|
139
|
+
const dir = join(workspaceRoot, '.intutic', 'sops');
|
|
140
|
+
try {
|
|
141
|
+
const entries = await readdir(dir);
|
|
142
|
+
const out = [];
|
|
143
|
+
for (const file of entries.filter((e) => e.endsWith('.md'))) {
|
|
144
|
+
const body = await readFile(join(dir, file), 'utf8').catch(() => '');
|
|
145
|
+
// An SOP is "enforced" if it declares deny_tools or allow_harnesses.
|
|
146
|
+
const enforced = /deny_tools|allow_harnesses/.test(body);
|
|
147
|
+
out.push({ sop_id: file.replace(/\.md$/, ''), name: file, enforced });
|
|
148
|
+
}
|
|
149
|
+
return out;
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return [];
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Bounded, symlink-skipping walk of one skill directory's bundled files
|
|
157
|
+
* (siblings of `SKILL.md`), content-scanning each one via `scanScriptContent`
|
|
158
|
+
* when its language is recognized and it is within `MAX_SCRIPT_SCAN_BYTES`.
|
|
159
|
+
*
|
|
160
|
+
* TD-356, Phase S2: mirrors `discoverSkillBundledFiles`
|
|
161
|
+
* (`tools/cli/src/commands/skill.ts`) closely — the exact same caps
|
|
162
|
+
* (`MAX_SKILL_DIR_DEPTH`, `MAX_FILES_PER_SKILL`) and symlink-skip discipline
|
|
163
|
+
* (`Dirent.isSymbolicLink()` checked and skipped outright during `readdir`,
|
|
164
|
+
* never stat-ed or resolved — a symlink inside a skill directory could point
|
|
165
|
+
* outside it, or outside the workspace entirely, turning a bounded walk
|
|
166
|
+
* unbounded) — but is its own implementation, not a shared import. This
|
|
167
|
+
* module has no dependency on `tools/cli`; `collectSkills` already
|
|
168
|
+
* re-implements skill-directory discovery independently of the CLI's
|
|
169
|
+
* `discoverSkillFiles` for the same reason, and this walk follows that same
|
|
170
|
+
* precedent rather than introducing a new cross-package dependency for it.
|
|
171
|
+
*
|
|
172
|
+
* Returns `undefined` (not `{total: 0, scanned: 0, flagged: 0}`) when the
|
|
173
|
+
* skill has no bundled files at all, so `collectSkills` can omit `scripts`
|
|
174
|
+
* entirely for the common case of a skill that is only a `SKILL.md` — see
|
|
175
|
+
* that field's own doc comment on the `AgentFacets['skills']` item type.
|
|
176
|
+
*/
|
|
177
|
+
async function collectSkillScripts(skillDir) {
|
|
178
|
+
const files = [];
|
|
179
|
+
async function walk(dir, depth) {
|
|
180
|
+
if (depth > MAX_SKILL_DIR_DEPTH || files.length >= MAX_FILES_PER_SKILL)
|
|
181
|
+
return;
|
|
182
|
+
let entries;
|
|
183
|
+
try {
|
|
184
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
for (const entry of entries) {
|
|
190
|
+
if (files.length >= MAX_FILES_PER_SKILL)
|
|
191
|
+
return;
|
|
192
|
+
if (entry.isSymbolicLink())
|
|
193
|
+
continue; // never follow — see this function's doc comment
|
|
194
|
+
const full = join(dir, entry.name);
|
|
195
|
+
if (entry.isDirectory()) {
|
|
196
|
+
await walk(full, depth + 1);
|
|
197
|
+
}
|
|
198
|
+
else if (entry.isFile()) {
|
|
199
|
+
if (depth === 0 && entry.name === 'SKILL.md')
|
|
200
|
+
continue;
|
|
201
|
+
files.push(full);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
await walk(skillDir, 0);
|
|
206
|
+
if (files.length === 0)
|
|
207
|
+
return undefined;
|
|
208
|
+
let scanned = 0;
|
|
209
|
+
let flagged = 0;
|
|
210
|
+
for (const filePath of files) {
|
|
211
|
+
let buffer;
|
|
212
|
+
try {
|
|
213
|
+
buffer = await readFile(filePath);
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
continue; // unreadable — counted in `total`, not `scanned`
|
|
217
|
+
}
|
|
218
|
+
if (buffer.length > MAX_SCRIPT_SCAN_BYTES)
|
|
219
|
+
continue; // refused, not silently skipped or scanned
|
|
220
|
+
const firstLine = buffer.toString('utf8', 0, Math.min(buffer.length, 200)).split('\n')[0];
|
|
221
|
+
const language = detectScriptLanguage(filePath, firstLine);
|
|
222
|
+
if (language === 'unknown')
|
|
223
|
+
continue; // not a script language this scanner understands
|
|
224
|
+
const result = scanScriptContent(buffer.toString('utf8'), language);
|
|
225
|
+
scanned++;
|
|
226
|
+
if (!result.clean)
|
|
227
|
+
flagged++;
|
|
228
|
+
}
|
|
229
|
+
return { total: files.length, scanned, flagged };
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Bundled skills under `<root>/.agents/skills/<name>/SKILL.md`, content-
|
|
233
|
+
* scanned via `scanSkillContent` (`@intutic/shared-types`) on every cycle,
|
|
234
|
+
* plus (TD-356, Phase S2) a bounded enumeration of each skill's bundled
|
|
235
|
+
* scripts via `collectSkillScripts`, attached as the `scripts` facet.
|
|
236
|
+
*
|
|
237
|
+
* Report-only, matching `scanSkillContent`'s own doc comment: this function
|
|
238
|
+
* never modifies, blocks, or removes anything — it reads and attaches a
|
|
239
|
+
* verdict for `agentPosture.ts`'s content-aware `skills` scoring to consume.
|
|
240
|
+
*
|
|
241
|
+
* Refusal-not-pass: a `SKILL.md` that cannot be read (permissions, vanished
|
|
242
|
+
* between `readdir` and `readFile`, not a regular file, …) is reported
|
|
243
|
+
* `scanned: false, clean: false` — never `clean: true`, and never silently
|
|
244
|
+
* dropped from the list. An unreadable skill is not a skill the daemon can
|
|
245
|
+
* vouch for, and dropping it would make a workspace's posture score look
|
|
246
|
+
* better than what is actually known. The `scripts` enumeration runs
|
|
247
|
+
* regardless of whether `SKILL.md` itself was readable — a script bundled
|
|
248
|
+
* next to an unreadable `SKILL.md` is still on disk and still a surface to
|
|
249
|
+
* report on.
|
|
250
|
+
*/
|
|
251
|
+
async function collectSkills(workspaceRoot) {
|
|
252
|
+
const dir = join(workspaceRoot, '.agents', 'skills');
|
|
253
|
+
let entries;
|
|
254
|
+
try {
|
|
255
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
return [];
|
|
259
|
+
}
|
|
260
|
+
const dirs = entries.filter((e) => e.isDirectory());
|
|
261
|
+
const out = [];
|
|
262
|
+
for (const e of dirs) {
|
|
263
|
+
const skillDir = join(dir, e.name);
|
|
264
|
+
const skillMdPath = join(skillDir, 'SKILL.md');
|
|
265
|
+
const scripts = await collectSkillScripts(skillDir);
|
|
266
|
+
try {
|
|
267
|
+
const content = await readFile(skillMdPath, 'utf8');
|
|
268
|
+
const result = scanSkillContent(content);
|
|
269
|
+
const sha256 = createHash('sha256').update(content, 'utf8').digest('hex');
|
|
270
|
+
out.push({
|
|
271
|
+
name: e.name,
|
|
272
|
+
source: '.agents/skills',
|
|
273
|
+
scanned: true,
|
|
274
|
+
clean: result.clean,
|
|
275
|
+
findingsCount: result.findings.length,
|
|
276
|
+
sha256,
|
|
277
|
+
...(scripts ? { scripts } : {}),
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
catch {
|
|
281
|
+
out.push({
|
|
282
|
+
name: e.name,
|
|
283
|
+
source: '.agents/skills',
|
|
284
|
+
scanned: false,
|
|
285
|
+
clean: false,
|
|
286
|
+
findingsCount: 0,
|
|
287
|
+
...(scripts ? { scripts } : {}),
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return out;
|
|
292
|
+
}
|
|
293
|
+
/** Local notes vaults (Obsidian/Logseq/Foam) at or above the workspace root. */
|
|
294
|
+
async function detectLocalVaults(workspaceRoot) {
|
|
295
|
+
const markers = ['.obsidian', '.logseq', '.foam'];
|
|
296
|
+
const found = [];
|
|
297
|
+
let dir = workspaceRoot;
|
|
298
|
+
for (let depth = 0; depth < 8; depth++) {
|
|
299
|
+
for (const marker of markers) {
|
|
300
|
+
if (await exists(join(dir, marker))) {
|
|
301
|
+
found.push(marker.slice(1));
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
const parent = join(dir, '..');
|
|
305
|
+
if (parent === dir)
|
|
306
|
+
break;
|
|
307
|
+
dir = parent;
|
|
308
|
+
}
|
|
309
|
+
return [...new Set(found)];
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* MCP servers declared across every harness config format this daemon knows
|
|
313
|
+
* how to parse (see `mcpAutoWrite.ts`'s `discoverMcpServers` — 11 config paths
|
|
314
|
+
* across 9 harnesses), with each server's proxy-wrapped status. Previously
|
|
315
|
+
* this only read 3 hardcoded paths (`.mcp.json`, `.cursor/mcp.json`,
|
|
316
|
+
* `~/.claude.json`) and flattened per declared tool; `discoverMcpServers` is
|
|
317
|
+
* the shared, read-only extraction of the same format knowledge
|
|
318
|
+
* `injectMcpServer` uses to wrap servers, so this reporter's coverage can
|
|
319
|
+
* never silently lag behind what actually gets wrapped.
|
|
320
|
+
*/
|
|
321
|
+
async function collectMcpTools(workspaceRoot) {
|
|
322
|
+
return discoverMcpServers(workspaceRoot);
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Build a facet report for one harness in the workspace.
|
|
326
|
+
*
|
|
327
|
+
* `dlpEnabled` / `policyEnforced` come from the daemon's known proxy config;
|
|
328
|
+
* the daemon spawns and configures the proxy, so it knows these without a
|
|
329
|
+
* round-trip.
|
|
330
|
+
*/
|
|
331
|
+
export async function collectAgentReport(opts) {
|
|
332
|
+
const [wasmRules, sops, skills, mcpTools, vaults, egress, guardProbes] = await Promise.all([
|
|
333
|
+
countWasmRules(),
|
|
334
|
+
collectSops(opts.workspaceRoot),
|
|
335
|
+
collectSkills(opts.workspaceRoot),
|
|
336
|
+
collectMcpTools(opts.workspaceRoot),
|
|
337
|
+
detectLocalVaults(opts.workspaceRoot),
|
|
338
|
+
fetchEgressStatus(),
|
|
339
|
+
fetchGuardProbes(),
|
|
340
|
+
]);
|
|
341
|
+
const role = opts.agentRole ?? '';
|
|
342
|
+
return {
|
|
343
|
+
agentKey: `${opts.harnessType}:${role || 'default'}`,
|
|
344
|
+
displayName: role ? `${opts.harnessType} (${role})` : opts.harnessType,
|
|
345
|
+
harnessType: opts.harnessType,
|
|
346
|
+
agentRole: role,
|
|
347
|
+
facets: {
|
|
348
|
+
guardrails: {
|
|
349
|
+
dlp: opts.dlpEnabled,
|
|
350
|
+
wasm_rules: wasmRules,
|
|
351
|
+
// Computed per-harness rather than hardcoded true — see gateKind.ts's
|
|
352
|
+
// module doc for why "the daemon writes the hook gate for every
|
|
353
|
+
// harness it supports" was never actually true (langgraph, aider).
|
|
354
|
+
hook_gate: gateKindForHarness(opts.harnessType) === 'hook',
|
|
355
|
+
gate_kind: gateKindForHarness(opts.harnessType),
|
|
356
|
+
pcas: opts.policyEnforced,
|
|
357
|
+
// Present only when the local proxy answered; an egress denial thus
|
|
358
|
+
// becomes visible in the dashboard, not just the proxy's own log.
|
|
359
|
+
...(egress ? { egress } : {}),
|
|
360
|
+
},
|
|
361
|
+
sops,
|
|
362
|
+
budgets: { tier: opts.budgetTier },
|
|
363
|
+
mcp_tools: mcpTools,
|
|
364
|
+
skills,
|
|
365
|
+
loops: { configured: false }, // set by the loops feature when a run is active
|
|
366
|
+
harness: { type: opts.harnessType, config_synced: opts.configSynced },
|
|
367
|
+
// Visibility, not content: which vault kinds exist near the workspace,
|
|
368
|
+
// and whether workspace policy lets them feed /fix. Note names/content
|
|
369
|
+
// never leave the machine.
|
|
370
|
+
memory: opts.allowLocalVaults === false
|
|
371
|
+
? []
|
|
372
|
+
: vaults.map((kind) => ({ provider: `local-vault:${kind}`, configured: true })),
|
|
373
|
+
...(guardProbes ? { guardProbes } : {}),
|
|
374
|
+
},
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
/** POST a report to the control plane. Non-fatal on failure (mirrors reportStatus). */
|
|
378
|
+
export async function reportAgent(controlPlaneUrl, apiKey, workspaceId, report) {
|
|
379
|
+
try {
|
|
380
|
+
const res = await fetch(`${controlPlaneUrl}/api/v1/agents/report`, {
|
|
381
|
+
method: 'POST',
|
|
382
|
+
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}` },
|
|
383
|
+
body: JSON.stringify({ ...report, reportedAt: newIso() }),
|
|
384
|
+
signal: AbortSignal.timeout(15_000),
|
|
385
|
+
});
|
|
386
|
+
if (!res.ok) {
|
|
387
|
+
console.warn(`[sync-daemon] reportAgent failed for ${report.agentKey}: ${res.status}`);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
catch (err) {
|
|
391
|
+
console.warn(`[sync-daemon] reportAgent error for ${report.agentKey}:`, err instanceof Error ? err.message : err);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
//# sourceMappingURL=agentReporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentReporter.js","sourceRoot":"","sources":["../src/agentReporter.ts"],"names":[],"mappings":"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"}
|