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,473 @@
1
+ // THE JUST-IN-TIME INSTRUCTION SURFACE — one chapter's expanded doctrine, returned AT that chapter.
2
+ //
3
+ // WHY THIS EXISTS AS A RETURN VALUE RATHER THAN AS MORE RESIDENT TEXT.
4
+ //
5
+ // The three channels that reach a supervisor all arrive at the START of a run and never again:
6
+ // the MCP `instructions` (resident, and observed truncated at byte 2,050 — see
7
+ // `supervisorContract.ts`), the bundled skill, and `supervisor-playbook.md` on disk. That shape
8
+ // forces an unwinnable trade. Put the delivery rules in a resident channel and they compete for the
9
+ // first 2 KB against the activation rules, which the run needs an hour earlier. Put them in the
10
+ // playbook and the model reads them ninety minutes before it uses them, at the point in the run
11
+ // when its context is emptiest and its attention is on intake.
12
+ //
13
+ // A TOOL RETURN HAS NEITHER PROBLEM. It costs nothing until it is called, it arrives at the moment
14
+ // the instruction applies, and it lands in the context window at the position where the model is
15
+ // about to act on it. That is why the doctrine diet and this tool are one design and not two: the
16
+ // resident contract could only be cut to a skeleton because a just-in-time channel exists to carry
17
+ // what was cut, and this channel is only affordable because the contract is a skeleton.
18
+ //
19
+ // WHAT BELONGS HERE, AND THE RULE THAT KEEPS IT FROM GROWING BACK INTO A SECOND PLAYBOOK.
20
+ //
21
+ // Only what the supervisor must have IN HAND to do THIS chapter and could get wrong without it.
22
+ // Concretely: the order of operations no tool can see, the judgement calls no check makes, and the
23
+ // live-caught lemmas whose cost is only payable once. NOT restatements of a tool description (they
24
+ // arrive on the same connect, and truncation deletes the duplicate first), NOT restatements of a
25
+ // refusal message (it arrives at the moment it fires, which is strictly better timing than this),
26
+ // and NOT the operator-voice guide or the Configuration Item guide, both of which are files the
27
+ // text POINTS at rather than inlines.
28
+ //
29
+ // The playbook remains the deep reference and the fallback for a run that never crosses a boundary.
30
+ // Its step headings name their chapters (`supervisor-playbook.md`), so the two surfaces are
31
+ // addressable in one vocabulary and per-step detail can migrate here without either becoming
32
+ // unreadable.
33
+ import { CHAPTERS } from "./phases.js";
34
+ import { OPERATOR_VOICE_PATH, SUPERVISOR_PLAYBOOK_PATH } from "./paths.js";
35
+ /**
36
+ * Written once, read on every boundary. Each entry is prose the model acts on directly, so it is
37
+ * addressed to the model in the second person and states its reasons — an instruction whose reason
38
+ * is missing is one a model will optimise away the first time it looks expensive.
39
+ */
40
+ const BRIEFS = {
41
+ activation: {
42
+ headline: "Bind the session and the org",
43
+ progressLine: "Connecting to your Salesforce org and picking up the requirements you selected.",
44
+ instructions: [
45
+ "ACTIVATION — the session and the org become real, and nothing else happens yet.",
46
+ "",
47
+ "A pasted activation code is the whole start: `activate_session {code}` authenticates their org into",
48
+ "the sf CLI, binds it to the session, grants write authority to exactly that org, and imports the",
49
+ "requirements they picked in Campfire. Any other start is `create_session` then `import_requirements`.",
50
+ "An org that is not authenticated goes through `org_login`, a browser flow THEY complete — call it",
51
+ "again with the same alias until it reports CONNECTED.",
52
+ "",
53
+ "This batch is provider-bound: every step from here to close_batch uses the mcp__in2__ tools only,",
54
+ "whatever other Salesforce MCPs this client has connected.",
55
+ "",
56
+ "NEVER ask for a username, password or token, and never re-authenticate an org yourself when a",
57
+ "session dies. Salesforce auto-freezes an integration user on rapid retries, so a second attempt is",
58
+ "not free — stop, and tell the operator exactly what to run.",
59
+ "",
60
+ "CARRY THE sessionId, NOT AN ORG. Every org-touching tool derives its org from the session, bound and",
61
+ "verified when the session was created. `ALIAS_REPOINTED` means the alias moved to another org since",
62
+ "binding: card the operator, never work around it.",
63
+ "",
64
+ "SURFACE THE IDENTITY. `activate_session` reports which Salesforce USER the session acts as. Every",
65
+ "org change will be attributed to that user forever, so it goes to the operator in your first message,",
66
+ "not into your own notes.",
67
+ "",
68
+ "RELAY THE `Live progress:` URL exactly as `activate_session` returned it — it pins this session, and a",
69
+ "link you compose yourself would point the operator at another run. If the result carried no such line,",
70
+ "say nothing about a viewer.",
71
+ "",
72
+ "Advance to `intake` once the org is bound and the requirements are on disk."
73
+ ].join("\n")
74
+ },
75
+ intake: {
76
+ headline: "Read every requirement and form the batch model",
77
+ progressLine: "Reading through your requirements to understand what they add up to.",
78
+ instructions: [
79
+ "INTAKE — you read the whole batch yourself, before anything is delegated.",
80
+ "",
81
+ "This is codebase planning. Read ALL requirements first and form the BATCH MODEL: the shared",
82
+ "object(s), the cross-requirement dependency ladder (which requirements are an ordered chain and",
83
+ "which are independent), and any ambiguity that is only visible ACROSS requirements — three",
84
+ "requirements touching one object, two asking for contradictory sharing.",
85
+ "",
86
+ "READ INTENT ACROSS ALL THREE SURFACES of each requirement: the Solution Design Summary (the most",
87
+ "technical statement of HOW), the user story, and the acceptance criteria (what it is FOR). The",
88
+ "Summary is hand-written and sometimes asks for the impossible, or for what the other two contradict.",
89
+ "Work out what was INTENDED, propose the SMALLEST correction that achieves it, and recommend that.",
90
+ "Never refuse the requirement and never silently substitute your own reading. This is a CORRECTION",
91
+ "mechanism, not a licence to add — improving the design is the consultant's job.",
92
+ "",
93
+ "THEN GROUND ONCE. `project_org` across the scope you now know is touched. It is ground truth:",
94
+ "requirement-asserted API names are UNTRUSTED, and a component that already exists is a modify, never",
95
+ "a clobbering create. It also collects the org's traits (multi-currency, person accounts, call centre)",
96
+ "and a sample of precedent components on every run regardless of scope, which is exactly what a",
97
+ "greenfield batch needs most.",
98
+ "",
99
+ "YOU ARE THE ONLY ONE WHO CAN WIDEN THE PROJECTION. Analyzers READ it and cannot extend it, so",
100
+ "anything you fail to project is not missing to them — it is INVISIBLE, and they plan against a gap",
101
+ "they cannot see. Enumerate every metadata TYPE the batch touches, not just the objects: tabs, apps,",
102
+ "profiles, queues, groups, flows, approval processes, email templates, permission sets. Live-caught",
103
+ "2026-07-25: a batch projected as objects-plus-prefix left five types uncaptured and an analyzer had",
104
+ "to flag the blind spot itself.",
105
+ "",
106
+ "Advance to `partitioning` when you can state the batch model in a paragraph. If the batch is small",
107
+ "enough that you already hold it whole and will analyze it inline, you may advance straight past",
108
+ "`partitioning` and `parallel-analysis` to `clarification` — but read what that costs in the",
109
+ "partitioning brief before you decide."
110
+ ].join("\n")
111
+ },
112
+ partitioning: {
113
+ headline: "Write the brief and decide who analyzes what",
114
+ progressLine: "Planning how the work splits up before starting the detailed design.",
115
+ instructions: [
116
+ "PARTITIONING — the batch model becomes a session artifact, and the analyzer mapping is decided.",
117
+ "",
118
+ "WRITE THE BRIEF at `<sessionDir>/analysis/brief.md`: a shared preamble (the batch shape, the shared",
119
+ "objects, the dependency ladder, the decisions already in force) plus one delimited section per",
120
+ "requirement (its dependencies, its siblings, the trap it cannot see from its own text, and the",
121
+ "ownership of every shared component). Writing it ONCE and having N analyzers read it in parallel is",
122
+ "the speed mechanism: context that used to stream serially as output tokens into N Task prompts",
123
+ "becomes input tokens read concurrently. A measured 43-second start stagger across just four agents.",
124
+ "",
125
+ "RULES THE BRIEF LIVES BY:",
126
+ "- DECISIONS BIND; DESCRIPTIONS DO NOT. Carry decisions and POINTERS, never paraphrases of what an",
127
+ " analyzer can read itself. Live-caught: a briefing described a flow guard using the wrong technique",
128
+ " and the analyzer rightly mirrored the real artifact instead. A paraphrase is a bug vector.",
129
+ "- BINDING IS NOT UNCHALLENGEABLE. An analyzer never silently deviates from a brief decision — and",
130
+ " never silently complies with one it can show is wrong either. The disagreement arrives as a",
131
+ " BLOCKER citing evidence. That is the system working.",
132
+ "- AMENDMENTS ARE DATED APPENDS. When something changes mid-run you append rather than rewrite, so a",
133
+ " re-dispatched analyzer reads the CURRENT brief and re-dispatch needs no prompt surgery.",
134
+ "",
135
+ "PRE-ASSIGN OWNERSHIP IN THE BRIEF — dedupe is a repair, not a plan. You already know the collisions",
136
+ "from reading the batch, so name the owner of every shared component (\"REQ-B: the object is REQ-A's —",
137
+ "record dependsOn, do NOT author it\") and fold facet-level asks into the creating owner's file. A",
138
+ "parent-object facet is an edit to the OBJECT and belongs in the object's own full-definition file,",
139
+ "not as its own components[] entry. Measured: with ownership stated up front, 15 analyzers produced",
140
+ "zero collisions and the wave plan ordered 24/24 first try. Without it, a create-owner/modify-owner",
141
+ "split on one field left 7 dependent components unordered.",
142
+ "",
143
+ "THE EARLY ROUND — ONE OPTIONAL CARD, HARD-GATED. Before fan-out you MAY ask one card of 1-3",
144
+ "questions. A question qualifies only if ALL THREE hold: it is visible from the requirement texts and",
145
+ "the projection alone; its answer unlocks or reshapes MULTIPLE requirements or the batch model itself;",
146
+ "and unanswered, analyzers must guess and their guesses could diverge. EACH QUESTION NAMES THE",
147
+ "REQUIREMENTS IT UNLOCKS — writing that clause is the test, and a question you cannot qualify that way",
148
+ "is self-evidently not an early question. Everything else waits for the consolidated round.",
149
+ "",
150
+ "SKIPPING THE FAN-OUT is a legitimate call on a small batch and it is much faster. Know exactly what",
151
+ "you give up: the analyzers' only durable output is `requirements/<extId>/plan.json`, and that file is",
152
+ "what decides WHICH REQUIREMENT EACH CONFIGURATION ITEM IS FILED AGAINST at writeback. Skip the",
153
+ "fan-out and that mapping exists only in your head — carry it forward explicitly by passing",
154
+ "`ownership: [{typeName, fullName, extId}]` to the Campfire tools, which refuse an unattributed plan.",
155
+ "Skip deliberately, never by drift.",
156
+ "",
157
+ "Advance to `parallel-analysis` when the brief is written and the mapping is decided."
158
+ ].join("\n")
159
+ },
160
+ "parallel-analysis": {
161
+ headline: "Fan out one analyzer per requirement",
162
+ progressLine: "Designing each requirement in detail, all of them at once.",
163
+ instructions: [
164
+ "PARALLEL ANALYSIS — every Task in ONE message, so wall clock is the slowest analyzer rather than",
165
+ "the sum of them.",
166
+ "",
167
+ "DELEGATION DEFAULTS TO 1:1, one analyzer per requirement, dispatched as",
168
+ "`subagent_type: \"plan-requirement\"`. That agent definition ships with the install and its `tools:`",
169
+ "frontmatter is a hard ALLOWLIST — the analyzer is handed only the five IN2 tools its skill permits",
170
+ "plus the file tools, so the ~21 it may not call are never loaded. If the agent type is not found,",
171
+ "STOP before any analysis — never dispatch a generic subagent in its place: it inherits every MCP",
172
+ "connected in this client, which un-scopes the one surface this allowlist exists to scope. The fix",
173
+ "rides on the server itself: every server START re-installs `~/.claude/agents` from the package, so",
174
+ "a missing definition means this session's start predates the copy — card the operator to start a",
175
+ "new conversation and re-paste their activation prompt (a fresh server start re-syncs the files;",
176
+ "nothing is lost), then `close_batch` and stop. If a fresh conversation STILL lacks the agent type,",
177
+ "the copy step itself is failing on this machine — card the operator to run `in2 setup` in a",
178
+ "terminal, then `close_batch` and stop.",
179
+ "",
180
+ "GROUP 2-3 ONTO ONE ANALYZER ONLY ON REAL COUPLING — one builds what another modifies or deletes, a",
181
+ "shared ordered ladder, a contradiction that needs one mind. NEVER topical similarity: with the brief",
182
+ "carrying the shared context there is no dispatch-economy reason left to group, and unearned grouping",
183
+ "just un-parallelizes the batch. A grouped analyzer still writes ONE plan.json PER requirement — that",
184
+ "artifact contract is inviolable, since wave planning, Configuration Item ownership and writeback all",
185
+ "read one plan.json per requirement. Partial-group failure is survivable by construction: each",
186
+ "finished plan.json persists as it is written, so you re-dispatch only what is missing.",
187
+ "",
188
+ "EACH TASK PROMPT IS A FIXED STUB, about forty tokens: read the plan-requirement skill (the tool list",
189
+ "names its path), you own <extId>, session <sessionId>, read your section(s) of the brief FIRST. Do",
190
+ "NOT paste cross-requirement context back into the prompts — that re-serialization is the dispatch",
191
+ "streaming this design removed.",
192
+ "",
193
+ "A PINSLEY-CLASS REQUIREMENT (one requirement the size of ten) splits BY DELIVERABLE AREA into",
194
+ "disjoint component sets, each fragment writing `plan.fragment-<n>.json` plus its own authored files.",
195
+ "YOU merge them into the one canonical `requirements/<extId>/plan.json`. `plan_waves` audits the",
196
+ "fragments before ordering anything and refuses an unmerged or doubly-claimed set by name",
197
+ "(`PLAN_FRAGMENTS_UNRESOLVED`, which spells out its own fix); what it cannot verify is the judgement",
198
+ "half — your summary and the blocker/assumption dedup are yours.",
199
+ "",
200
+ "Advance to `clarification` once every plan.json is on disk (and every fragment set is merged)."
201
+ ].join("\n")
202
+ },
203
+ clarification: {
204
+ headline: "Consolidate the plans and ask everything the batch genuinely raises",
205
+ progressLine: "Bringing the designs together and working out what needs a decision from you.",
206
+ instructions: [
207
+ "CLARIFICATION — a PHASE, not one tool call, and it happens BEFORE anything is applied.",
208
+ "",
209
+ "CONSOLIDATE FIRST. Read every plan.json. Dedupe by ownership: a component appearing in more than one",
210
+ "plan is created ONCE, owned by the requirement that most naturally creates it (usually the earliest",
211
+ "in the ladder), and the others merely DEPEND on it. Then `plan_waves {sessionId}` for the deploy",
212
+ "order — it reads the dependsOn the analyzers already recorded and returns the fewest waves the batch",
213
+ "allows.",
214
+ "",
215
+ "WHAT THE WAVE PLAN WILL TELL YOU, and what each answer means:",
216
+ "- A component this batch CHANGES AFTER CREATING IT is TWO entries — the same component,",
217
+ " `intent: \"create\"` then `intent: \"update\"`, each naming its own `authoredFile`. Never one file",
218
+ " plus a wave you assemble by hand: that path skips the ownership and drop checks entirely. The",
219
+ " planner NAMES the split and never writes it; what the second state must CONTAIN is yours to author.",
220
+ "- A component the batch DELETES is an entry with `intent: \"delete\"` and no file. Planning orders it;",
221
+ " nothing deletes it. That call is yours, and `dryRunOnly` goes first.",
222
+ "- \"not verifiable\" is answered with a `project_org` pass, never by deploying past it. A projection is",
223
+ " a point-in-time read of a scope you chose, so absence from it is not evidence of absence from the org.",
224
+ "",
225
+ "THEN ASK EVERYTHING, BACK TO BACK. What is minimised is the OPERATOR'S ATTENTION WINDOW — they answer",
226
+ "in one focused stretch and then walk away while you execute — NOT your tool-call count. As many cards",
227
+ "as the batch honestly has; two readable cards beat one dense one. Never fold distinct ambiguities",
228
+ "together to hit a number: that pressure is exactly what turns a question into a guessed API name.",
229
+ "",
230
+ "A QUESTION WHOSE RECOMMENDATION YOU WOULD FOLLOW ANYWAY IS AN ASSUMPTION TO STATE, NOT A ROUND-TRIP",
231
+ "TO SPEND. Measured: 19 questions on one run, 18 answered with the recommendation, and operator wait",
232
+ "rose 9.2 minutes — cancelling out every second the parallel authoring had saved.",
233
+ "",
234
+ "THE TEST IS LIKELY DISSENT, NOT THE TEXT'S SILENCE. Ask yourself: might a reasonable operator",
235
+ "actually pick the other option? Business meaning, data risk, anything irreversible — yes, card it.",
236
+ "A recommendation any operator would confirm — display cosmetics (a formula that shows blank instead",
237
+ "of a meaningless number), a reading of a spec where both readings hold every real value, a platform",
238
+ "default the requirement does not contradict — is an assumption on the approval card. \"It deviates",
239
+ "from the literal text\" is NOT by itself a reason to ask: the approval card exists precisely so that",
240
+ "small, sensible deviations are DISCLOSED and consented to in one place. Live-caught 2026-08-05: a",
241
+ "run carded \"blank vs -46,700 days on an empty date\" and \"16 total digits vs 18\" — both answered",
242
+ "with the recommendation, both pure assumption material, two round-trips spent on questions whose",
243
+ "other option no operator would choose.",
244
+ "",
245
+ "`ask_operator` only RECORDS a card. Mirror every card through the native AskUserQuestion UI or the",
246
+ "operator never sees it and cannot answer. After answers: `record_operator_answers` FIRST, always —",
247
+ "it is the only record of what was actually chosen, and it closes the round so a resumed session can",
248
+ "tell an open card from a settled one. Then `resolve_blocker` when the answer is an edit you can make,",
249
+ "and a re-dispatch only when the reply changes WHICH components exist.",
250
+ "",
251
+ "Advance to `scope-approval` when every answer is recorded and every plan is reconciled."
252
+ ].join("\n")
253
+ },
254
+ "scope-approval": {
255
+ headline: "Show the full extent, then take one approval",
256
+ progressLine: "Putting the full plan in front of you for approval before anything changes in your org.",
257
+ instructions: [
258
+ "SCOPE AND APPROVAL — the last moment before the org changes, and the operator's only real gate.",
259
+ "",
260
+ "THE ORDERING IS FIXED: scope sheet -> approval card -> (in beta) the manual-time estimate card ->",
261
+ "first deploy. Ask the estimate card PLAINLY and NEVER EXPLAIN TO THE OPERATOR WHY IT COMES THERE —",
262
+ "the ordering answers a measurement problem that is ours, not theirs, and QA caught the tool reciting",
263
+ "that argument to the person it was measuring. The rule stays; the justification is not operator-facing.",
264
+ "",
265
+ `RENDER THE SCOPE SHEET AS ITS OWN MESSAGE, immediately before the card. Layouts and worked examples`,
266
+ `are in reference/templates.md beside ${SUPERVISOR_PLAYBOOK_PATH}. It is the full enumeration of what`,
267
+ "is about to happen in the org, grouped so the extent is visible at a glance, with every removal,",
268
+ "every deviation-from-as-written (each citing the answer that caused it) and every judgement call",
269
+ "flagged where it lands.",
270
+ "",
271
+ "THEN ONE APPROVAL CARD: the dependency-ordered plan, per-wave components, the assumptions in force",
272
+ "VERBATIM (approval is informed consent — an assumption paraphrased is an assumption not consented",
273
+ "to), the coverage routes, and the execution ask. One Recommended option: approve and execute.",
274
+ "",
275
+ "SAY WHAT VERIFICATION WILL NOT PROVE. `DIFF_VERIFIED` proves metadata SHAPE, never runtime behaviour.",
276
+ "Flows, validation rules and approval processes get a would-be-runtime-smoke note; content-file types",
277
+ "verify the meta, not the content bytes. An operator who thinks the harness proved behaviour has been",
278
+ "misled by omission.",
279
+ "",
280
+ "THE FIVE JUDGEMENT RULES THAT GOVERN WHAT YOU LET INTO THE BATCH, restated here because this is the",
281
+ "chapter where they bite:",
282
+ "- ADDITIONS: BENIGN IS FINE, OBLIGATION-CREATING IS NOT. An obvious additive detail on a brand-new",
283
+ " component is welcome judgement. Forbidden is anything that CREATES OBLIGATIONS — a reference to a",
284
+ " component that must then exist, a flag whose value implies further setup.",
285
+ "- NEVER PUT INVENTED SCOPE TO THE OPERATOR. If you added it and it is now a problem, remove it rather",
286
+ " than escalating it as though the gap were theirs.",
287
+ "- NEVER MAKE SOMETHING REQUIRED THAT WAS NOT REQUESTED. A required field nobody asked for changes",
288
+ " data entry for every user of that object forever. Absolute violation, however benign it looks.",
289
+ "- DELIVER IT, DO NOT DELEGATE IT. A Deployment Task hands work BACK to the consultant this system",
290
+ " exists to save. If a human could do it in ten seconds, that is an argument for YOU doing it.",
291
+ "- READ INTENT ACROSS ALL THREE SURFACES, and propose the smallest correction rather than refusing.",
292
+ "",
293
+ "A deletion that removes something THIS BATCH CREATES goes on the card in the operator's own terms:",
294
+ "two requirements building what a third retires is a plan they should get to reconsider.",
295
+ "",
296
+ "Advance to `delivery` only after they approve. Change nothing in the org before that."
297
+ ].join("\n")
298
+ },
299
+ delivery: {
300
+ headline: "Deploy wave by wave with read-back proof",
301
+ progressLine: "Making the approved changes in your Salesforce org, in dependency order.",
302
+ instructions: [
303
+ "DELIVERY — one `direct_apply {sessionId, wave, waveComponents}` per wave, and nothing by hand.",
304
+ "",
305
+ "Pass that wave's component list straight from `plan_waves`. Assembly is a step INSIDE the call: the",
306
+ "analyzers' authored files are collected into `<session>/authored/<wave>/`, and that is what is linted,",
307
+ "validated and deployed in the same call, so there is no window in which the assembled tree and the",
308
+ "deployed tree can differ. `direct_lint` is the same assembly without the deploy.",
309
+ "",
310
+ "THE WAVE TREE IS A BUILD ARTIFACT, REBUILT EVERY CALL. A wave-specific fix goes in the requirement's",
311
+ "own file under `requirements/<extId>/authored/`. An edit made inside the wave tree is silently",
312
+ "overwritten rather than deployed, and nothing checks this.",
313
+ "",
314
+ "AUTHOR TO FILES, NOT INLINE XML. Source-format layout, since that is what the walk expects:",
315
+ "`objects/<Obj>/<Obj>.object-meta.xml`, `objects/<Obj>/fields/<F>.field-meta.xml`,",
316
+ "`flows/<F>.flow-meta.xml`, `email/<Folder>/<T>.email-meta.xml` plus its content file, and so on. Fix",
317
+ "the ONE bad file in place and call again. Re-sending full XML inline every call is dramatically",
318
+ "slower and the tree is what git history commits. Base64 static resources are the one exception.",
319
+ "",
320
+ "PASS `requirementIds` ON EVERY APPLY. The evidence bundle proves WHAT changed; only this says what it",
321
+ "was FOR, and it rides into the org's own history — which is where \"why does this field exist?\" gets",
322
+ "answered months from now by someone who was not on this run.",
323
+ "",
324
+ "READING THE VERDICTS:",
325
+ "- `DIFF_VERIFIED` is the target.",
326
+ "- `DELIVERED_WITH_DRIFT`: read `diff.json` and classify each drifted facet. Comparator noise",
327
+ " (org-materialized `default:\"false\"`, array reorder, typed-value `{_,$}`, empty-array",
328
+ " materialization, object key-order) is benign. RECONCILE WITH EVIDENCE, NOT ASSERTION: name the",
329
+ " specific noise class AND cite the diff.json path per component. Never just say \"benign\" in chat.",
330
+ "- `REJECTED_BY_ORG`: fix from the verbatim `componentFailures` — the dry run is a direct, actionable",
331
+ " error channel. Max 4 iterations, then STOP and card.",
332
+ "- `AMBIGUOUS_DELIVERY`: the deploy LANDED but the read-back failed. Re-`project_org` the scope; if the",
333
+ " components are present and correctly shaped they are delivered, and the ambiguous origin plus the",
334
+ " confirming projection is the evidence. Only if genuinely absent do you re-apply.",
335
+ "- A CONTENT REMOVED note means the component lost content between its pre- and post-image. Read the",
336
+ " pre-image and fix the file rather than acking a drop you have not looked at.",
337
+ "",
338
+ "ORDERING TRAPS THAT COST A LIVE RUN:",
339
+ "- A facet a child component's shape DEPENDS ON goes in an earlier call or its own wave. Inside one",
340
+ " apply the metadata deploy runs BEFORE the facet updates, so fields carrying `trackHistory` land",
341
+ " while history is still off and the tracking does not take.",
342
+ "- Brownfield facet changes: a FULL `CustomObject` deploy first (it MERGES — an object deployed with",
343
+ " its validationRules directory absent kept all three rules), `objectFacetUpdates` only as fallback.",
344
+ "- `dryRunOnly` before an irreversible wave. It checks deletes too, each with its own verdict. It does",
345
+ " NOT prove a destructive package will land: those roll back WHOLE, so split the call rather than",
346
+ " shipping a VALIDATED member beside a refused one. `objectFacetUpdates` have no practice mode at all.",
347
+ "- A ListView delete is a MANUAL SETUP TASK by default. \"Nothing references it\" is not evidence.",
348
+ "",
349
+ "NEVER RE-AUTH THE ORG YOURSELF. On `ORG_READ_FAILED` / `Session expired`: card the operator with the",
350
+ "fix (one line, re-auth from Campfire), then `close_batch {sessionId}`, then stop — IN THAT ORDER.",
351
+ "`close_batch` makes no org round-trip, so it works with every token dead; a run that stops at the",
352
+ "card reads as in-progress-forever and the waves that DID land are never reported. Rapid retries trip",
353
+ "Salesforce's integration-user auto-freeze, so never touch the token endpoint yourself.",
354
+ "",
355
+ "UNDOING A WAVE is `direct_rollback {sessionId, wave}`, never by hand and never by a sha. A custom",
356
+ "field deleted under 15 days ago is NOT a deploy: relay the tool's Setup undelete card, because an",
357
+ "undelete restores the field AND ITS DATA while a metadata re-create restores the definition, reports",
358
+ "success, and destroys every value in it.",
359
+ "",
360
+ "Advance to `review-results` when the last wave has a verdict — including when it has a bad one."
361
+ ].join("\n")
362
+ },
363
+ "review-results": {
364
+ headline: "Cross-check the claims, then review with the operator",
365
+ progressLine: "Checking what actually landed in your org against what was asked for.",
366
+ instructions: [
367
+ "REVIEW — cross-check every requirement's claims against verified org state BEFORE reporting.",
368
+ "",
369
+ "Drifted prose flowing into writeback publishes guarantees the org contradicts, and the writeback is",
370
+ "read by a ClickDeploy operator who was not on this run. So the order is: verify, then report, then",
371
+ "ask about writeback.",
372
+ "",
373
+ `COMPOSE THE REVIEW IN THE OPERATOR'S LANGUAGE, per ${OPERATOR_VOICE_PATH}. Read it before writing.`,
374
+ "- LEAD with what the independent org read proves and the exact configuration work still left to a",
375
+ " person. Then a component-level table (Configuration | What happened in Salesforce). Verdicts arrive",
376
+ " as `operatorSummary` phrasing, never as internal names.",
377
+ "- DO NOT CLAIM A CAMPFIRE COUNT YET. That belongs on the end-results page, after writeback has been",
378
+ " independently read back.",
379
+ "- THEN \"Optional checks — about X minutes\" AS A CHECKBOX LIST. This section is REQUIRED. Verification",
380
+ " proves metadata shape, never runtime behaviour, so map each requirement's metadata back to the",
381
+ " human flow it implements and render concrete `- [ ]` steps: create a record of each type and compare",
382
+ " picklist choices; trigger the validation rule with and without the bypass; assign the permission set",
383
+ " (nothing in a batch assigns people); add queue/group members before expecting sharing rules to grant",
384
+ " anything; send the email template from a record. Specific to THIS batch. Flag re-entry and",
385
+ " duplicate-fire risk for record-triggered flows. This checklist is the deliverable's other half, not",
386
+ " part of the manual-configuration count.",
387
+ "- CLOSE with \"Details for your technical team\": internal verdict names, drift classifications with",
388
+ " their evidence citations, assumptions applied, coverage routes, session id and evidence locations.",
389
+ " Everything above that section must be readable without it.",
390
+ "",
391
+ "\"I COULD NOT VERIFY THAT\" IS ONLY TRUE AFTER YOU LOOKED. Not having checked is not the same as not",
392
+ "being able to check, and reporting the second when you mean the first is a false statement about the",
393
+ "org.",
394
+ "",
395
+ "The review rides ABOVE the writeback question card, so the turn still ends in a card. Do NOT write to",
396
+ "Campfire yet — end by asking whether to.",
397
+ "",
398
+ "Advance to `writeback-close` once they answer that card, whichever way they answer it."
399
+ ].join("\n")
400
+ },
401
+ "writeback-close": {
402
+ headline: "Record the configuration items, then end the batch",
403
+ progressLine: "Recording the configuration items you delivered, and closing out the batch.",
404
+ instructions: [
405
+ "WRITEBACK AND CLOSE — the consultant org is REAL and SHARED, and this chapter ends the run.",
406
+ "",
407
+ "A WRITEBACK IS THE CONFIGURATION ITEMS. Not requirement notes, not Build Status, not Org",
408
+ "Deployed To. This program automates CONFIGURATION; deploying that configuration onward to other",
409
+ "environments is a separate process it does not perform, and a run that hands back manual work",
410
+ "has not finished a build. Do not call `update_campfire_requirements` — it is operator-directed",
411
+ "and outside this loop.",
412
+ "",
413
+ "THE ORDER IS THE PART NO TOOL ENFORCES:",
414
+ "1. `campfire_config_item_plan {sessionId}` FIRST. Its rows carry every observed delivery of each",
415
+ " component and what the independent read-back actually confirmed. It returns the Configuration",
416
+ " Item guide by absolute path in `guide`; that guide is the authority on manifest shape.",
417
+ "2. Resolve `ownershipGaps` and any ownership refusal WITH THE OPERATOR, never by guessing. The",
418
+ " result reports `ownershipSource` — `plan` (computed) or `supervisor` (asserted by you) — and",
419
+ " those carry different confidence, so say which it was.",
420
+ "3. THE WRITEBACK — `campfire_write_config_items {sessionId, ownership?}`, one call, the only",
421
+ " Configuration Item writer there is. A correction is a re-derivation scoped with `waves`,",
422
+ " never a hand-keyed row.",
423
+ "4. DEPLOYMENT TASKS, a separate step under the same approval — `create_campfire_deployment_tasks`,",
424
+ " ONE call carrying every manual item, each classified with `taskKind` and `expectedMinutes`.",
425
+ " Neither is written to Campfire; they ride the telemetry event as shape. You know both at the",
426
+ " moment you decide you cannot automate the work; nobody recovers them afterwards.",
427
+ "",
428
+ "THE PLAN'S DEVIATION LIST IS FOR THE OPERATOR REVIEW, NOT FOR A CAMPFIRE FIELD. Every disclosed",
429
+ "difference is scoped to that component's final delivery, the same rule its Configuration Item",
430
+ "row's own description follows, so the two never disagree. Speak them; do not paste them anywhere.",
431
+ "",
432
+ "CONFIGURATION ITEMS ARE WHAT A REQUIREMENT IS BUILT FROM, not a log of this run's deltas — a",
433
+ "component the requirement owns that already existed still belongs on its manifest. DERIVE them,",
434
+ "never enumerate them from memory.",
435
+ "",
436
+ "A DELIVERED ROW WHOSE POST-DEPLOY TRUTH IS UNCONFIRMED IS HELD, PER ROW. Every confirmed row writes",
437
+ "normally, so one ambiguous wave never strands the manifest. Never turn an ambiguous deploy or a",
438
+ "roll-up counter into evidence that the record matches.",
439
+ "",
440
+ "AN OBSERVED DIFFERENCE ON AN ASYNC SETTING IS A CLAIM TO VERIFY, NOT A FACT TO RECORD. A sharing-model",
441
+ "change kicks off a recalculation and a read taken before it finishes reports the OLD value",
442
+ "(live-caught: an OWD-private wave read back `sharingModel=ReadWrite`). Re-read after it settles; if",
443
+ "the org now shows the approved value, do not disclose a deviation that no longer exists.",
444
+ "",
445
+ "VERIFY THE WRITEBACK AGAINST THE CONSULTANT ORG, not the deploy target:",
446
+ "`sf_read {sessionId, targetOrg: \"campfire\", args: [...]}` resolves it from the session. The",
447
+ "Configuration Item's lookup to its requirement is `Requirement__c` / `Requirement__r`. Query the",
448
+ "external ids YOU wrote; Campfire's own automation files Deployment Tasks of its own beside them",
449
+ "seconds later, and those are Campfire working, not duplicates to delete.",
450
+ "",
451
+ "THEN `close_batch {sessionId}`, AS THE LAST TOOL CALL OF THE RUN — after the final wave and any",
452
+ "writeback, and EQUALLY when the run ended badly. `advance_phase` never replaces it: this tool records",
453
+ "where the run stands, and `close_batch` is the only thing that states the batch's terminal RESULT,",
454
+ "assembles the closing evidence and ships everything waiting on the end of the run. A run you do not",
455
+ "close reads as ABANDONED on the IN2 dashboard however well it went.",
456
+ "",
457
+ `It RETURNS \`operatorPage\` — the operator's results page, ALREADY RENDERED from the persisted counts.`,
458
+ `PASTE IT VERBATIM as the top of your reply, then write only what belongs BELOW THE PASTED BLOCK —`,
459
+ `everything after the \`=== END OF BLOCK\` fence, which is the boundary. The block's own`,
460
+ `\`### Still to do\` heading appears inside it only when work remains; a fully automated run has none.`,
461
+ `Below the fence, in order: the manual items, the Campfire count (the tool cannot read Campfire),`,
462
+ `rollback, optional checks, notes, and the technical section. Do not recompose or re-count it —`,
463
+ `see ${OPERATOR_VOICE_PATH}.`
464
+ ].join("\n")
465
+ }
466
+ };
467
+ export function chapterBrief(chapter) {
468
+ return BRIEFS[chapter];
469
+ }
470
+ /** Every chapter has a brief — asserted here so a chapter added to `CHAPTERS` cannot ship empty. */
471
+ export function chaptersWithoutBrief() {
472
+ return CHAPTERS.filter((chapter) => !BRIEFS[chapter]);
473
+ }
@@ -0,0 +1,61 @@
1
+ // Register the package's skills and agent definitions into ~/.claude.
2
+ //
3
+ // Runs at every server start, and that timing is the point. The copy used to live in the payload
4
+ // installers and (after QA round 1 caught the gap) in the updater — under npm there is no updater
5
+ // hook to hang it on, and npm's own lifecycle scripts are installed with --ignore-scripts on the
6
+ // update path by design. Server start is the one moment that provably runs on every machine after
7
+ // every update, so it is where the skills stop being stale. A machine whose server got newer while
8
+ // the instructions describing how to drive it did not is a silent and particularly confusing kind
9
+ // of stale (live-caught on testers' machines during QA round 1: the analyzer agent file was
10
+ // missing, so every analyzer fanned out UNSCOPED, with every banned tool shipped into its context).
11
+ //
12
+ // Best-effort by contract. A skill that cannot be written must never fail a server start: the
13
+ // server is the thing being started, and it works without them.
14
+ import fs from "node:fs/promises";
15
+ import os from "node:os";
16
+ import path from "node:path";
17
+ import { SERVER_ROOT } from "./install.js";
18
+ export async function installClaudeAssets() {
19
+ await installSkills();
20
+ await installAgents();
21
+ }
22
+ async function installSkills() {
23
+ const source = path.join(SERVER_ROOT, "skills");
24
+ const dest = path.join(os.homedir(), ".claude", "skills");
25
+ try {
26
+ const entries = await fs.readdir(source, { withFileTypes: true });
27
+ for (const entry of entries) {
28
+ if (!entry.isDirectory())
29
+ continue;
30
+ const to = path.join(dest, entry.name);
31
+ // Replace rather than merge: a file left behind by an older version is a set of
32
+ // instructions that disagrees with the server shipping beside it.
33
+ await fs.rm(to, { recursive: true, force: true }).catch(() => { });
34
+ await fs.mkdir(dest, { recursive: true });
35
+ await fs.cp(path.join(source, entry.name), to, { recursive: true });
36
+ }
37
+ }
38
+ catch {
39
+ // No skills in the package, or an unwritable ~/.claude — neither is worth failing a start.
40
+ }
41
+ }
42
+ async function installAgents() {
43
+ const source = path.join(SERVER_ROOT, "agents");
44
+ const dest = path.join(os.homedir(), ".claude", "agents");
45
+ try {
46
+ const entries = await fs.readdir(source, { withFileTypes: true });
47
+ for (const entry of entries) {
48
+ if (!entry.isFile() || !entry.name.endsWith(".md"))
49
+ continue;
50
+ // Per-file replace, never a directory wipe: ~/.claude/agents is the user's directory and
51
+ // holds agents we never shipped. A stale copy of OUR file is overwritten — an old allowlist
52
+ // either hides a tool this build needs or re-admits one it removed — but everything else
53
+ // survives.
54
+ await fs.mkdir(dest, { recursive: true });
55
+ await fs.copyFile(path.join(source, entry.name), path.join(dest, entry.name));
56
+ }
57
+ }
58
+ catch {
59
+ // No agents in the package, or an unwritable ~/.claude — neither is worth failing a start.
60
+ }
61
+ }