@indigoai-us/hq-cli 5.108.1 → 5.108.3
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/CHANGELOG.md +79 -0
- package/assets/mesh-daemon/README.md +23 -0
- package/assets/mesh-daemon/launchd.plist.template +33 -0
- package/assets/mesh-daemon/systemd.system.service.template +27 -0
- package/assets/mesh-daemon/systemd.user.service.template +18 -0
- package/assets/scaffold/core/scripts/lib/work-mesh-enqueue.sh +267 -0
- package/dist/commands/core.js +5 -4
- package/dist/commands/index-cmd.js +13 -0
- package/dist/commands/mesh.d.ts +15 -0
- package/dist/commands/mesh.js +732 -4
- package/dist/commands/search.d.ts +23 -0
- package/dist/commands/search.js +42 -1
- package/dist/lib/doctor/checks/work-context.d.ts +23 -0
- package/dist/lib/doctor/checks/work-context.js +195 -0
- package/dist/lib/doctor/registry.js +4 -0
- package/dist/lib/mesh/api.d.ts +18 -0
- package/dist/lib/mesh/api.js +55 -0
- package/dist/lib/mesh/cache.js +35 -4
- package/dist/lib/mesh/client.d.ts +118 -0
- package/dist/lib/mesh/client.js +268 -0
- package/dist/lib/mesh/live/backoff.d.ts +16 -0
- package/dist/lib/mesh/live/backoff.js +20 -0
- package/dist/lib/mesh/live/daemon/board-refresh.d.ts +49 -0
- package/dist/lib/mesh/live/daemon/board-refresh.js +185 -0
- package/dist/lib/mesh/live/daemon/credentials.d.ts +71 -0
- package/dist/lib/mesh/live/daemon/credentials.js +227 -0
- package/dist/lib/mesh/live/daemon/doctor.d.ts +37 -0
- package/dist/lib/mesh/live/daemon/doctor.js +139 -0
- package/dist/lib/mesh/live/daemon/index.d.ts +24 -0
- package/dist/lib/mesh/live/daemon/index.js +14 -0
- package/dist/lib/mesh/live/daemon/install.d.ts +83 -0
- package/dist/lib/mesh/live/daemon/install.js +330 -0
- package/dist/lib/mesh/live/daemon/log.d.ts +11 -0
- package/dist/lib/mesh/live/daemon/log.js +79 -0
- package/dist/lib/mesh/live/daemon/paths.d.ts +18 -0
- package/dist/lib/mesh/live/daemon/paths.js +31 -0
- package/dist/lib/mesh/live/daemon/pid-lock.d.ts +48 -0
- package/dist/lib/mesh/live/daemon/pid-lock.js +134 -0
- package/dist/lib/mesh/live/daemon/presence.d.ts +101 -0
- package/dist/lib/mesh/live/daemon/presence.js +250 -0
- package/dist/lib/mesh/live/daemon/presign.d.ts +18 -0
- package/dist/lib/mesh/live/daemon/presign.js +65 -0
- package/dist/lib/mesh/live/daemon/run.d.ts +74 -0
- package/dist/lib/mesh/live/daemon/run.js +400 -0
- package/dist/lib/mesh/live/daemon/state.d.ts +24 -0
- package/dist/lib/mesh/live/daemon/state.js +57 -0
- package/dist/lib/mesh/live/daemon/transcript-watch.d.ts +170 -0
- package/dist/lib/mesh/live/daemon/transcript-watch.js +520 -0
- package/dist/lib/mesh/live/enqueue.d.ts +48 -0
- package/dist/lib/mesh/live/enqueue.js +100 -0
- package/dist/lib/mesh/live/flush.d.ts +56 -0
- package/dist/lib/mesh/live/flush.js +360 -0
- package/dist/lib/mesh/live/format-spool-line.d.ts +42 -0
- package/dist/lib/mesh/live/format-spool-line.js +106 -0
- package/dist/lib/mesh/live/index.d.ts +22 -0
- package/dist/lib/mesh/live/index.js +16 -0
- package/dist/lib/mesh/live/paths.d.ts +13 -0
- package/dist/lib/mesh/live/paths.js +30 -0
- package/dist/lib/mesh/live/session-events-client.d.ts +58 -0
- package/dist/lib/mesh/live/session-events-client.js +120 -0
- package/dist/lib/mesh/live/session-identity.d.ts +39 -0
- package/dist/lib/mesh/live/session-identity.js +91 -0
- package/dist/lib/mesh/live/spool.d.ts +52 -0
- package/dist/lib/mesh/live/spool.js +193 -0
- package/dist/lib/mesh/live/ulid.d.ts +12 -0
- package/dist/lib/mesh/live/ulid.js +39 -0
- package/dist/lib/mesh/live/validate-session-event.d.ts +39 -0
- package/dist/lib/mesh/live/validate-session-event.js +128 -0
- package/dist/lib/search-index/index.d.ts +98 -0
- package/dist/lib/search-index/index.js +174 -2
- package/dist/lib/work-context/atomic.d.ts +18 -0
- package/dist/lib/work-context/atomic.js +132 -0
- package/dist/lib/work-context/company.d.ts +103 -0
- package/dist/lib/work-context/company.js +274 -0
- package/dist/lib/work-context/config.d.ts +59 -0
- package/dist/lib/work-context/config.js +172 -0
- package/dist/lib/work-context/contract.d.ts +81 -0
- package/dist/lib/work-context/contract.js +65 -0
- package/dist/lib/work-context/errors.d.ts +27 -0
- package/dist/lib/work-context/errors.js +46 -0
- package/dist/lib/work-context/index.d.ts +23 -0
- package/dist/lib/work-context/index.js +20 -0
- package/dist/lib/work-context/migrate.d.ts +84 -0
- package/dist/lib/work-context/migrate.js +287 -0
- package/dist/lib/work-context/organize.d.ts +130 -0
- package/dist/lib/work-context/organize.js +471 -0
- package/dist/lib/work-context/outbox.d.ts +97 -0
- package/dist/lib/work-context/outbox.js +357 -0
- package/dist/lib/work-context/paths.d.ts +14 -0
- package/dist/lib/work-context/paths.js +39 -0
- package/dist/lib/work-context/project.d.ts +78 -0
- package/dist/lib/work-context/project.js +247 -0
- package/dist/lib/work-context/reconcile.d.ts +85 -0
- package/dist/lib/work-context/reconcile.js +651 -0
- package/dist/lib/work-context/repo-remote.d.ts +43 -0
- package/dist/lib/work-context/repo-remote.js +200 -0
- package/dist/lib/work-context/state.d.ts +112 -0
- package/dist/lib/work-context/state.js +162 -0
- package/dist/main.js +93 -4
- package/dist/utils/cognito-session.d.ts +85 -9
- package/dist/utils/cognito-session.js +216 -9
- package/dist/utils/qmd-model-download-error.d.ts +27 -0
- package/dist/utils/qmd-model-download-error.js +114 -0
- package/dist/utils/qmd-query-document-error.d.ts +23 -0
- package/dist/utils/qmd-query-document-error.js +117 -0
- package/dist/utils/qmd-workdir-missing-error.d.ts +18 -0
- package/dist/utils/qmd-workdir-missing-error.js +78 -0
- package/dist/utils/sentry-fingerprint.js +7 -0
- package/package.json +5 -1
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project/task resolution for work-context (US-007B).
|
|
3
|
+
*
|
|
4
|
+
* Order:
|
|
5
|
+
* 1. existing active binding (state bound / needs_task with projectId)
|
|
6
|
+
* 2. trusted explicit (HQ_SPAWN_PROJECT/HQ_SPAWN_TASK, observation, meta.yaml)
|
|
7
|
+
* 3. exactly one deterministic mapping (cwd under companies/{slug}/projects/{project}/
|
|
8
|
+
* or a registry resource that names exactly one project for the repo)
|
|
9
|
+
* Soft evidence never auto-binds — candidates are server-owned (GET .../candidates).
|
|
10
|
+
*/
|
|
11
|
+
import * as fs from "node:fs";
|
|
12
|
+
import * as path from "node:path";
|
|
13
|
+
import { projectIdFromCwd } from "./company.js";
|
|
14
|
+
import { normalizeTaskId } from "./contract.js";
|
|
15
|
+
import { findEnclosingGitDir, normalizeRemoteOwnerName, readOriginRemoteUrl, } from "./repo-remote.js";
|
|
16
|
+
const SLUG_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
17
|
+
function normalizeSlug(value) {
|
|
18
|
+
if (!value)
|
|
19
|
+
return undefined;
|
|
20
|
+
const s = value.trim();
|
|
21
|
+
if (!s || !SLUG_RE.test(s))
|
|
22
|
+
return undefined;
|
|
23
|
+
return s;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Read project / task from workspace/sessions/<sid>/meta.yaml (best-effort).
|
|
27
|
+
* Keys written by startwork, execute-task, run-project, plan, brainstorm:
|
|
28
|
+
* project | project_id | projectId
|
|
29
|
+
* task | task_id | taskId | story_id | storyId
|
|
30
|
+
*/
|
|
31
|
+
export function readMetaProjectTask(sessionId, hqRoot) {
|
|
32
|
+
if (!hqRoot || !sessionId)
|
|
33
|
+
return {};
|
|
34
|
+
const metaPath = path.join(hqRoot, "workspace", "sessions", sessionId, "meta.yaml");
|
|
35
|
+
if (!fs.existsSync(metaPath))
|
|
36
|
+
return {};
|
|
37
|
+
try {
|
|
38
|
+
const text = fs.readFileSync(metaPath, "utf8");
|
|
39
|
+
let projectId;
|
|
40
|
+
let taskId;
|
|
41
|
+
for (const line of text.split(/\r?\n/)) {
|
|
42
|
+
const proj = /^\s*(?:project|project_id|projectId)\s*:\s*["']?([A-Za-z0-9._-]+)["']?\s*$/.exec(line);
|
|
43
|
+
if (proj?.[1] && !projectId)
|
|
44
|
+
projectId = normalizeSlug(proj[1]);
|
|
45
|
+
const task = /^\s*(?:task|task_id|taskId|story_id|storyId)\s*:\s*["']?([A-Za-z0-9._-]+)["']?\s*$/.exec(line);
|
|
46
|
+
if (task?.[1] && !taskId)
|
|
47
|
+
taskId = normalizeSlug(task[1]);
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
...(projectId ? { projectId } : {}),
|
|
51
|
+
...(taskId ? { taskId } : {}),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return {};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Look up a company registry resource that names exactly one project for the
|
|
60
|
+
* enclosing git remote. Scans companies/{slug}/registry/resources/*.yaml for
|
|
61
|
+
* type: repo entries whose repo_url matches and that carry a `project:` field.
|
|
62
|
+
* Zero or multiple distinct projects → null (never guess).
|
|
63
|
+
*/
|
|
64
|
+
export function projectIdFromRepoRegistry(input) {
|
|
65
|
+
const hqRoot = input.hqRoot?.trim()
|
|
66
|
+
? path.resolve(input.hqRoot)
|
|
67
|
+
: undefined;
|
|
68
|
+
const companySlug = normalizeSlug(input.companySlug);
|
|
69
|
+
if (!hqRoot || !companySlug || !input.cwd)
|
|
70
|
+
return null;
|
|
71
|
+
const gitDir = findEnclosingGitDir(path.resolve(input.cwd));
|
|
72
|
+
if (!gitDir)
|
|
73
|
+
return null;
|
|
74
|
+
const origin = readOriginRemoteUrl(gitDir);
|
|
75
|
+
if (!origin)
|
|
76
|
+
return null;
|
|
77
|
+
const ownerName = normalizeRemoteOwnerName(origin);
|
|
78
|
+
if (!ownerName)
|
|
79
|
+
return null;
|
|
80
|
+
const target = ownerName.toLowerCase();
|
|
81
|
+
const resourcesDir = path.join(hqRoot, "companies", companySlug, "registry", "resources");
|
|
82
|
+
if (!fs.existsSync(resourcesDir))
|
|
83
|
+
return null;
|
|
84
|
+
const matches = new Set();
|
|
85
|
+
let entries;
|
|
86
|
+
try {
|
|
87
|
+
entries = fs.readdirSync(resourcesDir);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
for (const name of entries) {
|
|
93
|
+
if (!name.endsWith(".yaml") && !name.endsWith(".yml"))
|
|
94
|
+
continue;
|
|
95
|
+
let text;
|
|
96
|
+
try {
|
|
97
|
+
text = fs.readFileSync(path.join(resourcesDir, name), "utf8");
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
// Must be a repo resource.
|
|
103
|
+
if (!/^\s*type:\s*repo\s*$/m.test(text))
|
|
104
|
+
continue;
|
|
105
|
+
// Extract repo_url / url and compare.
|
|
106
|
+
const urlMatch = /^\s*(?:repo_url|url)\s*:\s*["']?([^"'\s]+)["']?\s*$/m.exec(text);
|
|
107
|
+
if (!urlMatch?.[1])
|
|
108
|
+
continue;
|
|
109
|
+
const candidate = normalizeRemoteOwnerName(urlMatch[1]);
|
|
110
|
+
if (!candidate || candidate.toLowerCase() !== target)
|
|
111
|
+
continue;
|
|
112
|
+
const projMatch = /^\s*project\s*:\s*["']?([A-Za-z0-9._-]+)["']?\s*$/m.exec(text);
|
|
113
|
+
if (projMatch?.[1]) {
|
|
114
|
+
const p = normalizeSlug(projMatch[1]);
|
|
115
|
+
if (p)
|
|
116
|
+
matches.add(p);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (matches.size === 1)
|
|
120
|
+
return [...matches][0];
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Resolve project and task. Never invents an adhoc target. Soft evidence is
|
|
125
|
+
* out of scope here (server candidates only).
|
|
126
|
+
*/
|
|
127
|
+
export function resolveProjectTask(input) {
|
|
128
|
+
const env = input.env ?? process.env;
|
|
129
|
+
const state = input.existingState ?? null;
|
|
130
|
+
// 1. Existing active binding.
|
|
131
|
+
if (state) {
|
|
132
|
+
const boundStatuses = new Set(["bound", "needs_task", "needs_project"]);
|
|
133
|
+
if (boundStatuses.has(state.contextStatus) &&
|
|
134
|
+
state.projectId &&
|
|
135
|
+
state.contextStatus === "bound") {
|
|
136
|
+
return {
|
|
137
|
+
projectId: state.projectId,
|
|
138
|
+
taskId: state.taskId,
|
|
139
|
+
source: "existing_binding",
|
|
140
|
+
complete: Boolean(state.projectId && state.taskId),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
// needs_task with project already accepted — keep project, fill task from
|
|
144
|
+
// higher-precedence sources below only when absent.
|
|
145
|
+
if ((state.contextStatus === "needs_task" ||
|
|
146
|
+
state.contextStatus === "bound") &&
|
|
147
|
+
state.projectId &&
|
|
148
|
+
state.taskId) {
|
|
149
|
+
return {
|
|
150
|
+
projectId: state.projectId,
|
|
151
|
+
taskId: state.taskId,
|
|
152
|
+
source: "existing_binding",
|
|
153
|
+
complete: true,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// 2. Trusted explicit: env + observation + meta.yaml.
|
|
158
|
+
const spawnProject = normalizeSlug(env.HQ_SPAWN_PROJECT);
|
|
159
|
+
const spawnTask = normalizeSlug(env.HQ_SPAWN_TASK);
|
|
160
|
+
const trustedProject = normalizeSlug(input.trusted?.projectId ?? spawnProject);
|
|
161
|
+
let trustedTask = spawnTask;
|
|
162
|
+
if (input.trusted?.taskId || input.trusted?.storyId) {
|
|
163
|
+
const norm = normalizeTaskId({
|
|
164
|
+
taskId: input.trusted.taskId,
|
|
165
|
+
storyId: input.trusted.storyId,
|
|
166
|
+
});
|
|
167
|
+
if (norm.ok)
|
|
168
|
+
trustedTask = norm.taskId;
|
|
169
|
+
}
|
|
170
|
+
else if (spawnTask) {
|
|
171
|
+
trustedTask = spawnTask;
|
|
172
|
+
}
|
|
173
|
+
const meta = input.metaProjectId !== undefined || input.metaTaskId !== undefined
|
|
174
|
+
? {
|
|
175
|
+
projectId: normalizeSlug(input.metaProjectId) ?? undefined,
|
|
176
|
+
taskId: normalizeSlug(input.metaTaskId) ?? undefined,
|
|
177
|
+
}
|
|
178
|
+
: readMetaProjectTask(input.sessionId, input.hqRoot);
|
|
179
|
+
const explicitProject = trustedProject ?? meta.projectId;
|
|
180
|
+
const explicitTask = trustedTask ?? meta.taskId;
|
|
181
|
+
if (explicitProject || explicitTask) {
|
|
182
|
+
// Prefer spawn/trusted over meta; already merged above.
|
|
183
|
+
if (explicitProject) {
|
|
184
|
+
return {
|
|
185
|
+
projectId: explicitProject,
|
|
186
|
+
taskId: explicitTask,
|
|
187
|
+
source: "trusted_explicit",
|
|
188
|
+
complete: Boolean(explicitProject && explicitTask),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// Preserve existing project from needs_task without task (not a full bind).
|
|
193
|
+
if (state?.projectId && state.contextStatus === "needs_task") {
|
|
194
|
+
return {
|
|
195
|
+
projectId: state.projectId,
|
|
196
|
+
taskId: state.taskId,
|
|
197
|
+
source: "existing_binding",
|
|
198
|
+
complete: Boolean(state.taskId),
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
// 3. Exactly one deterministic mapping.
|
|
202
|
+
const fromCwd = projectIdFromCwd(input.cwd, input.hqRoot);
|
|
203
|
+
if (fromCwd) {
|
|
204
|
+
return {
|
|
205
|
+
projectId: fromCwd,
|
|
206
|
+
source: "deterministic_cwd",
|
|
207
|
+
complete: false,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
const fromRegistry = input.registryProjectId !== undefined
|
|
211
|
+
? normalizeSlug(input.registryProjectId) ?? null
|
|
212
|
+
: projectIdFromRepoRegistry({
|
|
213
|
+
cwd: input.cwd,
|
|
214
|
+
hqRoot: input.hqRoot,
|
|
215
|
+
companySlug: state?.companySlug ??
|
|
216
|
+
input.trusted?.companySlug ??
|
|
217
|
+
normalizeSlug(env.HQ_SPAWN_COMPANY),
|
|
218
|
+
});
|
|
219
|
+
if (fromRegistry) {
|
|
220
|
+
return {
|
|
221
|
+
projectId: fromRegistry,
|
|
222
|
+
source: "deterministic_registry",
|
|
223
|
+
complete: false,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
/** Work-signal thresholds for one-time clarification (US-007B). */
|
|
229
|
+
export const TOOL_WRITES_ASK_THRESHOLD = 3;
|
|
230
|
+
export const SESSION_AGE_ASK_MS = 10 * 60 * 1000;
|
|
231
|
+
/**
|
|
232
|
+
* Whether the session has crossed the work-signal threshold that unlocks a
|
|
233
|
+
* one-time clarification. Soft — never auto-binds.
|
|
234
|
+
*/
|
|
235
|
+
export function shouldAskAfter(input) {
|
|
236
|
+
const writes = input.toolWrites ?? 0;
|
|
237
|
+
if (writes >= TOOL_WRITES_ASK_THRESHOLD)
|
|
238
|
+
return true;
|
|
239
|
+
if (!input.hasTurn || !input.startedAt)
|
|
240
|
+
return false;
|
|
241
|
+
const startMs = Date.parse(input.startedAt);
|
|
242
|
+
if (!Number.isFinite(startMs))
|
|
243
|
+
return false;
|
|
244
|
+
const now = input.now ?? new Date();
|
|
245
|
+
return now.getTime() - startMs >= SESSION_AGE_ASK_MS;
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hq mesh context reconcile — sole runtime-to-control-plane entrypoint
|
|
3
|
+
* (US-007A company gate + US-007B project/task organization).
|
|
4
|
+
*/
|
|
5
|
+
import type { MembershipValidationResult } from "./config.js";
|
|
6
|
+
import { type ContextResult, type TrustedExplicitContext } from "./contract.js";
|
|
7
|
+
import { type FetchCandidatesFn } from "./organize.js";
|
|
8
|
+
import { replayOutbox, type DeliverFn } from "./outbox.js";
|
|
9
|
+
export interface ReconcileObservation {
|
|
10
|
+
contractVersion: number;
|
|
11
|
+
identity: {
|
|
12
|
+
sessionId?: string;
|
|
13
|
+
providerSessionId?: string;
|
|
14
|
+
harness?: string;
|
|
15
|
+
adapterVersion?: string;
|
|
16
|
+
runtimeVersion?: string;
|
|
17
|
+
};
|
|
18
|
+
clientOperationId: string;
|
|
19
|
+
explicit?: TrustedExplicitContext & {
|
|
20
|
+
companySlug?: string;
|
|
21
|
+
};
|
|
22
|
+
/** Alias for explicit (dispatch envelope). */
|
|
23
|
+
trustedContext?: TrustedExplicitContext & {
|
|
24
|
+
companySlug?: string;
|
|
25
|
+
};
|
|
26
|
+
untrackedOrigin?: "user";
|
|
27
|
+
/** Structured untracked choice; only origin "user" is accepted. */
|
|
28
|
+
untracked?: {
|
|
29
|
+
origin: string;
|
|
30
|
+
};
|
|
31
|
+
/** Local-only evidence — never written to outbox/state beyond structured ids. */
|
|
32
|
+
cwd?: string;
|
|
33
|
+
hqRoot?: string;
|
|
34
|
+
remoteOwnerSlug?: string;
|
|
35
|
+
/**
|
|
36
|
+
* How the observation was produced. Transcript-watch sets "transcript"
|
|
37
|
+
* so durable state carries source + transcriptMarker (US-018).
|
|
38
|
+
*/
|
|
39
|
+
source?: "hooks" | "transcript";
|
|
40
|
+
/** Optional turn signal for the 10-minute ask threshold (US-007B). */
|
|
41
|
+
hasTurn?: boolean;
|
|
42
|
+
toolWrites?: number;
|
|
43
|
+
/** Prohibited content may appear on the wire-in observation; must be stripped. */
|
|
44
|
+
prompt?: unknown;
|
|
45
|
+
transcript?: unknown;
|
|
46
|
+
message?: unknown;
|
|
47
|
+
token?: unknown;
|
|
48
|
+
credentials?: unknown;
|
|
49
|
+
[key: string]: unknown;
|
|
50
|
+
}
|
|
51
|
+
export interface ReconcileDeps {
|
|
52
|
+
root: string;
|
|
53
|
+
env?: NodeJS.ProcessEnv;
|
|
54
|
+
now?: () => Date;
|
|
55
|
+
/** Network deliverer; only called after outbox write. */
|
|
56
|
+
deliver?: DeliverFn;
|
|
57
|
+
/** Skip network even when company is resolved (local unit tests). */
|
|
58
|
+
offline?: boolean;
|
|
59
|
+
/** Server candidates fetcher (US-007B); ranking is server-owned. */
|
|
60
|
+
fetchCandidates?: FetchCandidatesFn;
|
|
61
|
+
/** Observation may mark that a turn occurred (for 10-minute ask threshold). */
|
|
62
|
+
markTurn?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Membership-validated slug→uid (GET /membership/me). Required to attach a
|
|
65
|
+
* companyUid when local resolution only yielded a slug. Injectable for tests.
|
|
66
|
+
*/
|
|
67
|
+
validateMembership?: (slug: string) => Promise<MembershipValidationResult> | MembershipValidationResult;
|
|
68
|
+
}
|
|
69
|
+
export interface ReconcileOutcome {
|
|
70
|
+
result: ContextResult;
|
|
71
|
+
exitCode: number;
|
|
72
|
+
/** Diagnostics for stderr (no secrets). */
|
|
73
|
+
diagnostics: string[];
|
|
74
|
+
statePath?: string;
|
|
75
|
+
outboxOperationId?: string;
|
|
76
|
+
}
|
|
77
|
+
export declare function parseObservationJson(raw: string): ReconcileObservation;
|
|
78
|
+
export declare function loadObservationFromFile(filePath: string): ReconcileObservation;
|
|
79
|
+
/**
|
|
80
|
+
* Mark a session untracked (user origin only). Local receipt; no server write.
|
|
81
|
+
*/
|
|
82
|
+
export declare function markUntracked(sessionId: string, deps: Pick<ReconcileDeps, "root" | "now">, clientOperationId?: string): ReconcileOutcome;
|
|
83
|
+
export declare function reconcileObservation(obs: ReconcileObservation, deps: ReconcileDeps): Promise<ReconcileOutcome>;
|
|
84
|
+
export { replayOutbox };
|
|
85
|
+
//# sourceMappingURL=reconcile.d.ts.map
|