@bli-cockpit/cli 0.2.48 → 0.2.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/raw-evidence-attribution-gaps.js +133 -0
- package/dist/adapters/raw-evidence-claude-reader.js +108 -0
- package/dist/adapters/raw-evidence-codex-reader.js +147 -0
- package/dist/adapters/raw-evidence-collection-state.js +199 -0
- package/dist/adapters/raw-evidence-facts.js +338 -0
- package/dist/adapters/raw-evidence-git-diff-reader.js +187 -0
- package/dist/adapters/raw-evidence-image-reader.js +107 -0
- package/dist/adapters/raw-evidence-sanitize.js +56 -0
- package/dist/adapters/raw-evidence-transcript-file.js +182 -0
- package/dist/adapters/raw-evidence.js +94 -1203
- package/dist/autostart-contract.js +79 -0
- package/dist/autostart-darwin-plist.js +265 -0
- package/dist/autostart-darwin.js +171 -0
- package/dist/autostart-windows-scripts.js +310 -0
- package/dist/autostart-windows-task-xml.js +260 -0
- package/dist/autostart-windows.js +237 -0
- package/dist/autostart-xml.js +23 -0
- package/dist/autostart.js +35 -1148
- package/dist/commands/agent-rules-command.js +55 -0
- package/dist/commands/agent-session-report.js +290 -0
- package/dist/commands/analyze.js +131 -0
- package/dist/commands/autostart-command.js +105 -0
- package/dist/commands/backfill-batches.js +34 -0
- package/dist/commands/backfill-candidates.js +54 -0
- package/dist/commands/backfill-checkpoint.js +101 -0
- package/dist/commands/backfill-command-line.js +70 -0
- package/dist/commands/backfill-evidence-outcomes.js +104 -0
- package/dist/commands/backfill-issues.js +265 -0
- package/dist/commands/backfill-output.js +75 -0
- package/dist/commands/backfill-plan.js +71 -0
- package/dist/commands/backfill-reasons.js +107 -0
- package/dist/commands/backfill-report.js +298 -0
- package/dist/commands/backfill-result.js +150 -0
- package/dist/commands/backfill-scan.js +274 -0
- package/dist/commands/backfill-scope.js +114 -0
- package/dist/commands/backfill-session-report.js +145 -0
- package/dist/commands/backfill-types.js +1 -0
- package/dist/commands/backfill-upload.js +212 -0
- package/dist/commands/backfill.js +58 -1705
- package/dist/commands/cli-io.js +13 -0
- package/dist/commands/doctor.js +57 -0
- package/dist/commands/jarvis-trace.js +184 -0
- package/dist/commands/jarvis.js +323 -7
- package/dist/commands/local-arg-values.js +169 -0
- package/dist/commands/local-args-collector.js +604 -0
- package/dist/commands/local-args-tower.js +891 -0
- package/dist/commands/local-args.js +10 -1549
- package/dist/commands/local-help.js +30 -5
- package/dist/commands/local.js +21 -1786
- package/dist/commands/login.js +53 -0
- package/dist/commands/logout.js +66 -0
- package/dist/commands/memory-install-claude.js +294 -0
- package/dist/commands/memory-install-codex.js +205 -0
- package/dist/commands/memory-install-contract.js +231 -0
- package/dist/commands/memory-install-files.js +63 -0
- package/dist/commands/memory-install-skills.js +121 -0
- package/dist/commands/memory-install-toml.js +265 -0
- package/dist/commands/memory-install.js +378 -0
- package/dist/commands/onboard-receipts.js +66 -0
- package/dist/commands/onboard-report.js +274 -0
- package/dist/commands/onboard.js +449 -0
- package/dist/commands/ops-render.js +36 -0
- package/dist/commands/public-root.js +1 -1
- package/dist/commands/serve.js +13 -0
- package/dist/commands/session-sync.js +513 -534
- package/dist/commands/settings-render.js +28 -0
- package/dist/commands/settings.js +66 -2
- package/dist/commands/start.js +47 -0
- package/dist/commands/sync-followups.js +308 -0
- package/dist/commands/sync.js +387 -0
- package/dist/local-state-attributed-target.js +75 -0
- package/dist/local-state-config.js +147 -0
- package/dist/local-state-files.js +59 -0
- package/dist/local-state-identity.js +73 -0
- package/dist/local-state-pairing.js +263 -0
- package/dist/local-state-paths.js +61 -0
- package/dist/local-state-session.js +68 -0
- package/dist/local-state-status.js +163 -0
- package/dist/local-state-work-context.js +190 -0
- package/dist/local-state.js +34 -848
- package/dist/tower-client.js +3 -2
- package/dist/tower-stream.js +76 -6
- package/package.json +2 -1
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { LocalWorkContextSchema, } from "@bli-cockpit/telemetry-core";
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { ensureRuntimeDirectories, getCollectorRuntimePaths, workContextFile, } from "./local-state-paths.js";
|
|
6
|
+
import { readJsonFile, writeJsonFile } from "./local-state-files.js";
|
|
7
|
+
import { LOCAL_COLLECTOR_VERSION, readLocalCollectorConfig, } from "./local-state-config.js";
|
|
8
|
+
import { readLocalSessionReference } from "./local-state-session.js";
|
|
9
|
+
import { resolveIdentityOrFallback } from "./local-state-identity.js";
|
|
10
|
+
import { validateAttributedTargetIdentity } from "./local-state-attributed-target.js";
|
|
11
|
+
/** What `cockpit start` binds: the repo, branch and ticket this session's work belongs to. */
|
|
12
|
+
export async function startLocalWorkContext(options = {}) {
|
|
13
|
+
return writeLocalWorkContext(options);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Starts a context for a transcript-attributed sync target that does not exist
|
|
17
|
+
* in the current git inventory, such as an approved wrapper folder or a
|
|
18
|
+
* deleted repo reconstructed from transcript provenance. This internal path
|
|
19
|
+
* validates the exact target identity before writing any context state.
|
|
20
|
+
*/
|
|
21
|
+
export async function startLocalWorkContextForAttributedTarget(options, attributedIdentity) {
|
|
22
|
+
const repoRoot = path.resolve(options.repoRoot ?? process.cwd());
|
|
23
|
+
const identity = await validateAttributedTargetIdentity(repoRoot, attributedIdentity);
|
|
24
|
+
return writeLocalWorkContext(options, identity);
|
|
25
|
+
}
|
|
26
|
+
async function writeLocalWorkContext(options, attributedIdentity) {
|
|
27
|
+
if (options.activeTicketId && options.clearTicket) {
|
|
28
|
+
throw new Error("--ticket and --clear-ticket cannot be combined.");
|
|
29
|
+
}
|
|
30
|
+
const now = options.now ?? new Date();
|
|
31
|
+
const homeDir = options.homeDir ?? os.homedir();
|
|
32
|
+
const repoRoot = path.resolve(options.repoRoot ?? process.cwd());
|
|
33
|
+
const paths = getCollectorRuntimePaths(homeDir);
|
|
34
|
+
await ensureRuntimeDirectories(paths);
|
|
35
|
+
const config = await readLocalCollectorConfig(paths).catch(() => null);
|
|
36
|
+
const session = await readLocalSessionReference(paths, {
|
|
37
|
+
operatorId: options.operatorId,
|
|
38
|
+
sessionId: options.sessionId,
|
|
39
|
+
});
|
|
40
|
+
const identity = attributedIdentity ??
|
|
41
|
+
(await resolveIdentityOrFallback(repoRoot, options.branch));
|
|
42
|
+
const branch = attributedIdentity
|
|
43
|
+
? attributedIdentity.branch
|
|
44
|
+
: (options.branch ?? identity.branch);
|
|
45
|
+
const sessionId = options.sessionId ??
|
|
46
|
+
(session.session_state === "missing" ? `local-${crypto.randomUUID()}` : session.session_id);
|
|
47
|
+
const operatorId = options.operatorId ?? session.operator_id;
|
|
48
|
+
const deviceId = session.device_id ?? config?.device_id ?? "device-unknown";
|
|
49
|
+
const workContextId = stableWorkContextId({
|
|
50
|
+
operatorId,
|
|
51
|
+
deviceId,
|
|
52
|
+
repoFingerprint: identity.repo_fingerprint,
|
|
53
|
+
worktreeFingerprint: identity.worktree_fingerprint,
|
|
54
|
+
});
|
|
55
|
+
const existingContext = await readLocalWorkContextByFingerprint(paths, identity.worktree_fingerprint).catch(() => null);
|
|
56
|
+
const context = buildWorkContext({
|
|
57
|
+
options,
|
|
58
|
+
now,
|
|
59
|
+
identity,
|
|
60
|
+
branch,
|
|
61
|
+
operatorId,
|
|
62
|
+
sessionId,
|
|
63
|
+
workContextId,
|
|
64
|
+
existingContext,
|
|
65
|
+
});
|
|
66
|
+
await writeJsonFile(workContextFile(paths, identity.worktree_fingerprint), context);
|
|
67
|
+
await writeJsonFile(paths.active_work_context_file, context);
|
|
68
|
+
return context;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The context record itself, kept in one piece because it is a schema: every
|
|
72
|
+
* field an ambient envelope will later carry as provenance is decided here.
|
|
73
|
+
*/
|
|
74
|
+
function buildWorkContext(input) {
|
|
75
|
+
const { options, now, identity, branch, operatorId, sessionId, workContextId, existingContext } = input;
|
|
76
|
+
const { activeTicketId, ticketBindingCandidates } = resolveTicketBinding(options, existingContext);
|
|
77
|
+
return LocalWorkContextSchema.parse({
|
|
78
|
+
work_context_id: workContextId,
|
|
79
|
+
repo: identity.repo_root,
|
|
80
|
+
branch,
|
|
81
|
+
repo_label: identity.repo_label,
|
|
82
|
+
repo_fingerprint: identity.repo_fingerprint,
|
|
83
|
+
repo_origin_url: identity.repo_origin_url ?? undefined,
|
|
84
|
+
head_sha: identity.head_sha ?? undefined,
|
|
85
|
+
worktree_label: identity.worktree_label,
|
|
86
|
+
worktree_fingerprint: identity.worktree_fingerprint,
|
|
87
|
+
worktree_is_primary: identity.worktree_is_primary,
|
|
88
|
+
operator_id: operatorId,
|
|
89
|
+
session_id: sessionId,
|
|
90
|
+
started_at: existingContext?.started_at ?? now.toISOString(),
|
|
91
|
+
updated_at: now.toISOString(),
|
|
92
|
+
active_ticket_id: activeTicketId,
|
|
93
|
+
ticket_binding_candidates: ticketBindingCandidates,
|
|
94
|
+
topic_label: options.topicLabel,
|
|
95
|
+
topic_summary_redacted: options.topicSummaryRedacted,
|
|
96
|
+
work_intent: options.workIntent,
|
|
97
|
+
work_phase: options.workPhase,
|
|
98
|
+
intent_source: options.intentSource,
|
|
99
|
+
intent_confidence: options.intentConfidence,
|
|
100
|
+
pull_request_url: existingContext?.pull_request_url,
|
|
101
|
+
provenance: {
|
|
102
|
+
capture_source: "collector_runtime",
|
|
103
|
+
capture_adapter_version: LOCAL_COLLECTOR_VERSION,
|
|
104
|
+
collector_version: LOCAL_COLLECTOR_VERSION,
|
|
105
|
+
repo: identity.repo_root,
|
|
106
|
+
branch,
|
|
107
|
+
repo_label: identity.repo_label,
|
|
108
|
+
repo_fingerprint: identity.repo_fingerprint,
|
|
109
|
+
repo_origin_url: identity.repo_origin_url ?? undefined,
|
|
110
|
+
worktree_label: identity.worktree_label,
|
|
111
|
+
worktree_fingerprint: identity.worktree_fingerprint,
|
|
112
|
+
worktree_is_primary: identity.worktree_is_primary,
|
|
113
|
+
operator_id: operatorId,
|
|
114
|
+
session_id: sessionId,
|
|
115
|
+
work_context_id: workContextId,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Three answers, not two: a named ticket binds, `--clear-ticket` unbinds, and
|
|
121
|
+
* saying neither leaves whatever the previous `cockpit start` bound in place.
|
|
122
|
+
*/
|
|
123
|
+
// The return type is inferred deliberately: naming it would mean indexing the
|
|
124
|
+
// context schema by field name, and this module keeps its literals to the ones
|
|
125
|
+
// that reach disk.
|
|
126
|
+
function resolveTicketBinding(options, existingContext) {
|
|
127
|
+
const activeTicketId = options.clearTicket
|
|
128
|
+
? undefined
|
|
129
|
+
: (options.activeTicketId ?? existingContext?.active_ticket_id);
|
|
130
|
+
const ticketBindingCandidates = options.activeTicketId
|
|
131
|
+
? [
|
|
132
|
+
{
|
|
133
|
+
ticket_id: options.activeTicketId,
|
|
134
|
+
binding_source: "active_work_context",
|
|
135
|
+
confidence: 1,
|
|
136
|
+
evidence_labels: ["cockpit_start_ticket"],
|
|
137
|
+
},
|
|
138
|
+
]
|
|
139
|
+
: options.clearTicket
|
|
140
|
+
? []
|
|
141
|
+
: (existingContext?.ticket_binding_candidates ?? []);
|
|
142
|
+
return { activeTicketId, ticketBindingCandidates };
|
|
143
|
+
}
|
|
144
|
+
/** The active context: what the last `cockpit start` on this machine bound, whatever the folder. */
|
|
145
|
+
export async function readLocalWorkContext(paths) {
|
|
146
|
+
return LocalWorkContextSchema.parse(await readJsonFile(paths.active_work_context_file));
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* The context for ONE repo, because a machine running two checkouts at once
|
|
150
|
+
* would otherwise attribute both to whichever was started last.
|
|
151
|
+
*/
|
|
152
|
+
export async function readLocalWorkContextForRepo(paths, repoRoot) {
|
|
153
|
+
const identity = await resolveIdentityOrFallback(repoRoot);
|
|
154
|
+
const context = await readLocalWorkContextByFingerprint(paths, identity.worktree_fingerprint).catch(() => null);
|
|
155
|
+
if (context)
|
|
156
|
+
return context;
|
|
157
|
+
const active = await readLocalWorkContext(paths);
|
|
158
|
+
if (active.worktree_fingerprint === identity.worktree_fingerprint ||
|
|
159
|
+
path.resolve(active.repo) === identity.repo_root) {
|
|
160
|
+
return active;
|
|
161
|
+
}
|
|
162
|
+
throw new Error(`Active work context missing for ${identity.worktree_label}. Run \`cockpit start --workspace "${identity.repo_root}"\`.`);
|
|
163
|
+
}
|
|
164
|
+
async function readLocalWorkContextByFingerprint(paths, worktreeFingerprint) {
|
|
165
|
+
return LocalWorkContextSchema.parse(await readJsonFile(workContextFile(paths, worktreeFingerprint)));
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* The same operator, device, repo and worktree must produce the same id on
|
|
169
|
+
* every run, because the ambient envelope joins sessions on it.
|
|
170
|
+
*/
|
|
171
|
+
function stableWorkContextId(input) {
|
|
172
|
+
return `work-${sha256([
|
|
173
|
+
input.operatorId,
|
|
174
|
+
input.deviceId,
|
|
175
|
+
input.repoFingerprint,
|
|
176
|
+
input.worktreeFingerprint,
|
|
177
|
+
].join(":")).slice(0, 32)}`;
|
|
178
|
+
}
|
|
179
|
+
function sha256(value) {
|
|
180
|
+
return crypto.createHash("sha256").update(value, "utf8").digest("hex");
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* The label a person reads for a work context — repo over worktree, so two
|
|
184
|
+
* checkouts of one repo are told apart at a glance.
|
|
185
|
+
*/
|
|
186
|
+
export function workDisplayLabel(context) {
|
|
187
|
+
const repoLabel = (context.repo_label ?? path.basename(context.repo)) || "workspace";
|
|
188
|
+
const worktreeLabel = context.worktree_label ?? repoLabel;
|
|
189
|
+
return `${repoLabel}/${worktreeLabel}`;
|
|
190
|
+
}
|