in2-agent-server 0.20260821.185429

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.
Files changed (115) hide show
  1. package/README.md +369 -0
  2. package/agents/plan-requirement.md +32 -0
  3. package/dist/campfire/configItem.js +201 -0
  4. package/dist/campfire/configItemDescription.js +379 -0
  5. package/dist/campfire/deriveFromBundle.js +1013 -0
  6. package/dist/cli.js +465 -0
  7. package/dist/core/betaFeedback.js +493 -0
  8. package/dist/core/chapterInstructions.js +473 -0
  9. package/dist/core/claudeAssets.js +61 -0
  10. package/dist/core/gate.js +201 -0
  11. package/dist/core/ids.js +9 -0
  12. package/dist/core/install.js +60 -0
  13. package/dist/core/operatorQa.js +462 -0
  14. package/dist/core/orgCallMeter.js +178 -0
  15. package/dist/core/parcels.js +1235 -0
  16. package/dist/core/paths.js +105 -0
  17. package/dist/core/phases.js +225 -0
  18. package/dist/core/planFile.js +251 -0
  19. package/dist/core/planFragments.js +119 -0
  20. package/dist/core/readsLog.js +398 -0
  21. package/dist/core/registration.js +24 -0
  22. package/dist/core/result.js +38 -0
  23. package/dist/core/resume.js +233 -0
  24. package/dist/core/revisionChain.js +351 -0
  25. package/dist/core/richText.js +61 -0
  26. package/dist/core/semanticHash.js +89 -0
  27. package/dist/core/sessionOrg.js +60 -0
  28. package/dist/core/sfQuery.js +19 -0
  29. package/dist/core/spawn.js +182 -0
  30. package/dist/core/supervisorContract.js +230 -0
  31. package/dist/core/telemetry.js +1297 -0
  32. package/dist/core/telemetryContext.js +154 -0
  33. package/dist/core/telemetrySpool.js +244 -0
  34. package/dist/core/transcriptUpload.js +516 -0
  35. package/dist/core/update.js +363 -0
  36. package/dist/core/viewer.js +117 -0
  37. package/dist/core/workspace.js +92 -0
  38. package/dist/core/writeGrants.js +93 -0
  39. package/dist/core/writebackManifest.js +92 -0
  40. package/dist/direct/applyLoop.js +2516 -0
  41. package/dist/direct/batchReport.js +510 -0
  42. package/dist/direct/comparatorNoise.js +75 -0
  43. package/dist/direct/containers.js +85 -0
  44. package/dist/direct/contamination.js +221 -0
  45. package/dist/direct/crud.js +56 -0
  46. package/dist/direct/destructive.js +168 -0
  47. package/dist/direct/knownTokens.js +94 -0
  48. package/dist/direct/lint.js +382 -0
  49. package/dist/direct/metadataSchema.generated.json +1 -0
  50. package/dist/direct/metadataSchema.js +179 -0
  51. package/dist/direct/operatorPage.js +349 -0
  52. package/dist/direct/orgRepo.js +1531 -0
  53. package/dist/direct/orgRepoSpawnCount.js +21 -0
  54. package/dist/direct/plannedScope.js +119 -0
  55. package/dist/direct/preImageTargets.js +63 -0
  56. package/dist/direct/refVerify.js +191 -0
  57. package/dist/direct/registry.js +129 -0
  58. package/dist/direct/removals.js +262 -0
  59. package/dist/direct/rollback.js +1513 -0
  60. package/dist/direct/rollbackRun.js +1360 -0
  61. package/dist/direct/sessionProjection.js +126 -0
  62. package/dist/direct/snapshotComparability.js +165 -0
  63. package/dist/direct/sourceTree.js +113 -0
  64. package/dist/direct/unstatedChanges.js +106 -0
  65. package/dist/direct/waveAssembly.js +556 -0
  66. package/dist/direct/waveCounts.js +19 -0
  67. package/dist/direct/waveDerivation.js +152 -0
  68. package/dist/direct/waveGrade.js +185 -0
  69. package/dist/index.js +90 -0
  70. package/dist/orgread/customFieldSnapshot.js +48 -0
  71. package/dist/orgread/fieldMetadata.js +178 -0
  72. package/dist/orgread/genericSnapshot.js +61 -0
  73. package/dist/orgread/layoutSnapshot.js +151 -0
  74. package/dist/orgread/salesforceOrgReader.js +184 -0
  75. package/dist/orgread/snapshotTypes.js +9 -0
  76. package/dist/projection/bridge.js +26 -0
  77. package/dist/projection/diff.js +141 -0
  78. package/dist/projection/mapmd.js +213 -0
  79. package/dist/projection/nameAmbiguity.js +106 -0
  80. package/dist/projection/precedent.js +136 -0
  81. package/dist/projection/project.js +214 -0
  82. package/dist/projection/scope.js +110 -0
  83. package/dist/projection/types.js +5 -0
  84. package/dist/tools/analyze.js +322 -0
  85. package/dist/tools/auth.js +915 -0
  86. package/dist/tools/campfire.js +1742 -0
  87. package/dist/tools/closeBatch.js +154 -0
  88. package/dist/tools/closeText.js +35 -0
  89. package/dist/tools/direct.js +1613 -0
  90. package/dist/tools/feedback.js +318 -0
  91. package/dist/tools/operator.js +287 -0
  92. package/dist/tools/org.js +739 -0
  93. package/dist/tools/phase.js +249 -0
  94. package/dist/tools/projection.js +172 -0
  95. package/dist/tools/session.js +313 -0
  96. package/dist/tools/update.js +82 -0
  97. package/dist/tools/waves.js +793 -0
  98. package/package.json +48 -0
  99. package/reference/campfire-configuration-items-guide.md +710 -0
  100. package/reference/deployability-cribs.md +119 -0
  101. package/reference/operator-voice.md +141 -0
  102. package/reference/org-read-cribs.md +34 -0
  103. package/reference/scoped-dml-interim.md +68 -0
  104. package/reference/supervisor-playbook.md +313 -0
  105. package/reference/templates.md +233 -0
  106. package/skills/in2-delivery/SKILL.md +322 -0
  107. package/skills/in2-delivery/references/campfire-configuration-items-guide.md +710 -0
  108. package/skills/in2-delivery/references/deployability-cribs.md +119 -0
  109. package/skills/in2-delivery/references/operator-voice.md +141 -0
  110. package/skills/in2-delivery/references/org-read-cribs.md +34 -0
  111. package/skills/in2-delivery/references/scoped-dml-interim.md +68 -0
  112. package/skills/in2-delivery/references/templates.md +233 -0
  113. package/skills/plan-requirement/SKILL.md +188 -0
  114. package/viewer/index.html +899 -0
  115. package/viewer/server.mjs +433 -0
@@ -0,0 +1,154 @@
1
+ import { z } from "zod";
2
+ import { fail, internalError, ok } from "../core/result.js";
3
+ import { WorkspaceError } from "../core/workspace.js";
4
+ import { SessionOrgError, resolveSessionOrg } from "../core/sessionOrg.js";
5
+ import { closeBatchTelemetry } from "../core/telemetryContext.js";
6
+ import { batchReportArtifacts, composeBatchReport, renderBatchReport, writeBatchReportArtifacts } from "../direct/batchReport.js";
7
+ import { renderOperatorPage } from "../direct/operatorPage.js";
8
+ import { installPendingUpdate } from "../core/update.js";
9
+ import { loadRequirementsIndex, loadSession } from "./session.js";
10
+ import { composeCloseText } from "./closeText.js";
11
+ /**
12
+ * THE EXPLICIT END OF A BATCH.
13
+ *
14
+ * Before this tool existed, a batch had no end — five subsystems in `core/telemetry.ts` each
15
+ * guessed at one with `process.once("beforeExit", …)`, and the guess was wrong in production:
16
+ * 7 batches, 0 terminal; 0 transcripts uploaded; no session ever produced a contamination report.
17
+ *
18
+ * Measured cause (see `registerBatchCloser` in core/telemetryContext.ts): the MCP client closes
19
+ * stdin, waits 2000 ms, then SIGTERMs. `beforeExit` fires only if the event loop drains inside that
20
+ * window — one still-ref'd handle and it never fires at all — and no signal handler gets more time.
21
+ * Every step that mattered was network work that could not finish in two seconds.
22
+ *
23
+ * So finalization happens HERE instead, in a tool call, while the server is alive and unhurried,
24
+ * and the artifacts are RETURNED rather than only written — a report the supervisor cannot read is
25
+ * a report that does not reach the operator.
26
+ */
27
+ export function registerCloseBatchTools(server) {
28
+ server.registerTool("close_batch", {
29
+ description: "END THE BATCH. Call this ONCE, as the LAST tool call of a delivery run, after the final wave and any Campfire writeback — including when the run ended badly (waves rejected, blocked, or abandoned). " +
30
+ "It is the only thing that gives a batch an end: it states the batch's terminal result to the ledger, assembles and writes the closing evidence, and ships everything that was waiting on the end of the run (provenance parcels, the session transcript, any unflushed events). " +
31
+ "Nothing else does this. A run that is never closed reads as ABANDONED on the IN2 dashboard no matter how well it went, and its evidence never leaves the machine. " +
32
+ "RETURNS the technical spine for the operator's end-results page: the COMPUTED summary counts (`scope`: how many configurations were planned, how many the org read-back proved, how many still need a person, and the automation rate) plus per-wave verdicts and rollback coverage, batch-level findings, the delivery log with its drift explanations, and the contamination report. " +
33
+ "USE `scope` VERBATIM for the page's summary panel — do NOT re-count configurations from the evidence bundles. Those numbers are derived once, at Configuration Item grain, from what the approved plans asked for; a hand-derived second count is how a run reported 205 components as 94 configurations. A null `scope` means this batch never recorded what it was asked for: say the rate is unavailable rather than printing a zero. " +
34
+ "RETURNS `operatorPage`: the operator's results page, ALREADY RENDERED. Paste it verbatim as the top of your reply and write only what belongs below it — the manual steps, rollback, notes and the technical section. Do NOT recompose it, reorder it, or re-count anything in it; it is derived from the same numbers `scope` reports, and a hand-written second version is how the page came to differ on every run. " +
35
+ "Local-only evidence: the report names components, and component identity never enters the ledger. Safe to call more than once — the batch closes at most once per server process and later calls return the same result. " +
36
+ "This is the ONLY correct way to end a run; do not rely on the session simply stopping.",
37
+ inputSchema: {
38
+ sessionId: z
39
+ .string()
40
+ .describe("The session whose batch to close. The org is derived from the session, exactly as it is for every other org-touching tool — there is no org to name and none to get wrong.")
41
+ }
42
+ }, async ({ sessionId }) => {
43
+ try {
44
+ const session = await loadSession(sessionId);
45
+ const { alias, orgId } = await resolveSessionOrg(session, "target", { verify: false });
46
+ if (!orgId) {
47
+ return fail("ORG_NOT_BOUND", `Session ${sessionId} is bound to alias ${JSON.stringify(alias)} but recorded no Org ID, and both the mirror and the read-set are org-keyed. Re-bind the session (activate_session, or create_session { targetOrgAlias, targetOrgId }).`);
48
+ }
49
+ // Order matters, and it is the opposite of what it looks like.
50
+ //
51
+ // The report is composed and written FIRST, from this tool's own arguments, so the operator
52
+ // gets it even if shipping fails entirely — a local artifact is worth more than a network
53
+ // round-trip. The telemetry closer then runs the same report writer again behind its own
54
+ // once-guard, which is a no-op re-render rather than a second computation of anything sent.
55
+ const report = await composeBatchReport({
56
+ sessionId,
57
+ orgId,
58
+ ...(alias ? { orgAlias: alias } : {})
59
+ });
60
+ const rendered = renderBatchReport(report);
61
+ const written = await writeBatchReportArtifacts(report, rendered);
62
+ // FAIL-OPEN, like every other piece of closing bookkeeping. A missing requirements index
63
+ // costs the page its titles, never the close its result — `close_batch` must still close
64
+ // when everything else has gone wrong, and that guard is not negotiable.
65
+ //
66
+ // BUT NOT SILENTLY. A bare `catch { operatorPage = "" }` turned any renderer throw into an
67
+ // empty page with no note anywhere: the operator saw a close with no summary and no reason
68
+ // for its absence, and a later reader had nothing to find. The failure is now carried out
69
+ // as a closing note, which reaches both the returned text and the payload, without ever
70
+ // reaching the return value's success.
71
+ let operatorPage = "";
72
+ let pageFailure = null;
73
+ try {
74
+ operatorPage = renderOperatorPage(report, await loadRequirementsIndex(sessionId));
75
+ }
76
+ catch (error) {
77
+ operatorPage = "";
78
+ pageFailure =
79
+ `the operator's results page could NOT be rendered (${error instanceof Error ? error.message : String(error)}) — ` +
80
+ `the batch still closed and every count below is intact. State the result and the \`scope\` counts in plain language; do not reconstruct the page by hand.`;
81
+ }
82
+ // Ship. Awaited, unlike every exit hook this replaces, so what follows is a statement about
83
+ // what happened rather than a hope about what might.
84
+ const outcome = await closeBatchTelemetry();
85
+ // The update activation deferred. AFTER the evidence has shipped, deliberately: this is
86
+ // the last tool call of the run, nothing will lazily import another module, and an
87
+ // `npm install -g` that replaces dist under this process can no longer skew anything. The
88
+ // next session starts on the new version with no one asked to do anything — the reason
89
+ // activation stopped asking (QA rounds 1-2: every "update available" notice was ignored).
90
+ // Fail-open like everything else here: a failed install is a note, never a failed close.
91
+ const updateInstalled = await installPendingUpdate().catch(() => undefined);
92
+ const updateNote = !updateInstalled
93
+ ? []
94
+ : updateInstalled.ok && updateInstalled.updated
95
+ ? [
96
+ `server updated to ${updateInstalled.toVersion} (this run was on ${updateInstalled.fromVersion}) — the NEXT conversation runs the new version; this one is done either way.`
97
+ ]
98
+ : updateInstalled.ok
99
+ ? []
100
+ : [`a pending server update could not be installed (${updateInstalled.error ?? "unknown error"}) — the next activation will retry.`];
101
+ const artifacts = batchReportArtifacts(sessionId);
102
+ const shipping = [
103
+ ...(outcome
104
+ ? outcome.notes
105
+ : ["telemetry is disabled on this install (CC_MCP_TELEMETRY=0) — nothing was sent, and nothing was expected to be"]),
106
+ ...updateNote,
107
+ // FIRST-CLASS, not appended as an afterthought: this is the note that explains an empty
108
+ // `operatorPage`, and it must survive into the payload as well as the text.
109
+ ...(pageFailure ? [pageFailure] : [])
110
+ ];
111
+ const text = composeCloseText({
112
+ operatorPage,
113
+ rendered,
114
+ artifactPath: artifacts.markdown,
115
+ written: written !== null,
116
+ shipping
117
+ });
118
+ // The mirror (ok()'s `text`) carries the operator page a SECOND time here — once inside
119
+ // the paste fence, once under `operatorPage`. Deliberate, reviewed 2026-08-21: this fires
120
+ // once per run, and the fence-with-page-inside is the deliverable whose verbatim relay
121
+ // exists because hand re-derivation miscounted a results page twice (QA rounds 1 and 2).
122
+ // Slimming the mirrored text to a pointer would reopen exactly that. direct_history made
123
+ // the opposite call (text overridden to a pointer) because its duplicate is an uncapped
124
+ // git patch on a tool called many times a run.
125
+ return ok(text, {
126
+ sessionId,
127
+ orgId,
128
+ result: report.result,
129
+ // THE FOUR COUNTS, COMPUTED. The page's summary panel is composed from these rather than
130
+ // hand-derived from evidence bundles at the end of a long run — which is how QA round 1
131
+ // item 24 happened (205 components reported as 94 configurations) and QA round 2 repeated
132
+ // it. `null` means this batch never recorded what it was asked for: state no rate, never
133
+ // a zero one.
134
+ scope: report.scope,
135
+ // The finished page, for a client that would rather render than parse.
136
+ operatorPage,
137
+ deliveredWaves: report.deliveredWaves,
138
+ problemWaves: report.problemWaves,
139
+ practiceRuns: report.practiceRuns,
140
+ findings: report.findings,
141
+ artifacts: written ? artifacts : null,
142
+ closed: outcome?.finalized ?? false,
143
+ shipping
144
+ });
145
+ }
146
+ catch (error) {
147
+ if (error instanceof SessionOrgError)
148
+ return fail(error.code, error.message);
149
+ if (error instanceof WorkspaceError)
150
+ return fail(error.code, error.message);
151
+ return internalError(error);
152
+ }
153
+ });
154
+ }
@@ -0,0 +1,35 @@
1
+ // HOW A CLOSE READS, ASSEMBLED.
2
+ //
3
+ // Extracted from the `close_batch` handler so the branch that matters — whether the operator's
4
+ // finished page leads the result or is absent entirely — is reachable from a test without a
5
+ // session, an org, or a workspace on disk.
6
+ export function composeCloseText(input) {
7
+ return [
8
+ // THE OPERATOR'S PAGE, FINISHED. It leads because the supervisor reads this result top down,
9
+ // and the technical spine below it used to be the first thing found — which is how the page
10
+ // came to be re-derived by hand on every run.
11
+ ...(input.operatorPage
12
+ ? [
13
+ `=== PASTE THE BLOCK BELOW VERBATIM AS THE OPERATOR'S RESULTS PAGE ===`,
14
+ ``,
15
+ input.operatorPage,
16
+ ``,
17
+ `=== END OF BLOCK. Everything below is yours, not the operator's: write the "Still to do" items, rollback, notes and the technical section beneath the pasted block. ===`,
18
+ ``,
19
+ `---`,
20
+ ``
21
+ ]
22
+ : []),
23
+ input.rendered,
24
+ ``,
25
+ `---`,
26
+ ``,
27
+ `## Batch close`,
28
+ ``,
29
+ input.written
30
+ ? `Evidence written to ${input.artifactPath} (and batch-report.json beside it).`
31
+ : `Evidence could NOT be written to ${input.artifactPath} — the report above is the only copy.`,
32
+ ``,
33
+ ...input.shipping.map((note) => `- ${note}`)
34
+ ].join("\n");
35
+ }