empirical-sdd 0.32.0 → 0.33.0
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 +38 -1
- package/dist/cli.js +167 -34
- package/dist/demo-integration-repair.js +140 -30
- package/dist/demo-ticket-policy.js +140 -30
- package/dist/index.js +140 -30
- package/dist/integrations.js +132 -28
- package/dist/mcp.js +147 -33
- package/dist/mockups.d.ts +3 -1
- package/dist/protocol.d.ts +1 -1
- package/dist/protocol.js +1 -1
- package/dist/setup.d.ts +1 -1
- package/dist/types.d.ts +2 -0
- package/docs/demo.md +21 -14
- package/docs/protocol.md +15 -0
- package/docs/versioning.md +7 -6
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,42 @@ under the alpha rules in [docs/versioning.md](docs/versioning.md).
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.33.0] - 2026-09-09
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- Added a saved **Create mockups before coding?** Yes/No preference to init and
|
|
16
|
+
configuration, exposed as `mockupsBeforeCoding` through MCP. Existing
|
|
17
|
+
repositories retain enabled behavior until explicitly changed. Disabling it
|
|
18
|
+
skips mandatory UI mockups while retaining fidelity checks for approved designs.
|
|
19
|
+
- Added a terminal-only fresh-repository demo with recorded CLI, MCP, worktree,
|
|
20
|
+
verification, review, and integration scenarios.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- Setup shows proposed defaults for new repositories and actual saved values
|
|
25
|
+
for existing repositories, with one applicable menu and explicit Save.
|
|
26
|
+
- Init prefers permitted host-native selection controls and uses one text
|
|
27
|
+
prompt when they are unavailable, without duplicating the same question.
|
|
28
|
+
- Linear MCP discovery resolves actual host tools by provider and capability,
|
|
29
|
+
including lazy-loaded tools, and distinguishes configuration, tool exposure,
|
|
30
|
+
authentication, permissions, and transient failures before offering recovery.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- Fixed initialization rejecting valid Linear MCP policies after discovery and
|
|
35
|
+
preview by routing them through the existing credential-free MCP setup path.
|
|
36
|
+
- Prevented missing tool-name prefixes or unavailable future write operations
|
|
37
|
+
from triggering an automatic Linear API-key fallback.
|
|
38
|
+
- Preserved an explicit mockup preference through repeated initialization and
|
|
39
|
+
unrelated configuration updates, while rejecting invalid values before writes.
|
|
40
|
+
- Limited product test discovery to `tests/` so generated demo repositories do
|
|
41
|
+
not accidentally enter the product suite.
|
|
42
|
+
|
|
43
|
+
### Migration
|
|
44
|
+
|
|
45
|
+
No migration required.
|
|
46
|
+
|
|
11
47
|
## [0.32.0] - 2026-09-08
|
|
12
48
|
|
|
13
49
|
### Added
|
|
@@ -438,7 +474,8 @@ Published through GitHub Actions trusted publishing with npm provenance.
|
|
|
438
474
|
|
|
439
475
|
- Prepared and released package version `0.20.2`.
|
|
440
476
|
|
|
441
|
-
[Unreleased]: https://github.com/goempirical/empirical-sdd/compare/v0.
|
|
477
|
+
[Unreleased]: https://github.com/goempirical/empirical-sdd/compare/v0.33.0...HEAD
|
|
478
|
+
[0.33.0]: https://github.com/goempirical/empirical-sdd/compare/v0.32.0...v0.33.0
|
|
442
479
|
[0.32.0]: https://github.com/goempirical/empirical-sdd/compare/v0.31.0...v0.32.0
|
|
443
480
|
[0.31.0]: https://github.com/goempirical/empirical-sdd/compare/v0.30.0...v0.31.0
|
|
444
481
|
[0.30.0]: https://github.com/goempirical/empirical-sdd/compare/v0.29.0...v0.30.0
|
package/dist/cli.js
CHANGED
|
@@ -14853,7 +14853,7 @@ function verifyReceiptDigest(receipt) {
|
|
|
14853
14853
|
throw new Error(`Evidence receipt ${parsed.id} has an asserted result inconsistent with its provenance.`);
|
|
14854
14854
|
}
|
|
14855
14855
|
}
|
|
14856
|
-
var SCHEMA_VERSION = 5, POLICY_SCHEMA_VERSION = 2, MANIFEST_SCHEMA_VERSION = 2, RECEIPT_SCHEMA_VERSION = 1, PRODUCT_VERSION = "0.
|
|
14856
|
+
var SCHEMA_VERSION = 5, POLICY_SCHEMA_VERSION = 2, MANIFEST_SCHEMA_VERSION = 2, RECEIPT_SCHEMA_VERSION = 1, PRODUCT_VERSION = "0.33.0", workflowSchema, executionModeSchema, riskFloorSchema, completionLevelSchema, phaseSchema, workflowStatusSchema, criterionSchema, evidenceKindSchema, qaCheckKindSchema, qaAttemptOutcomeSchema, commandPolicySchema, evidencePolicySchema, projectPolicySchema, impactManifestSchema, authorizationSchema, COMPLETION_ORDER, receiptProvenanceSchema, receiptBaseSchema, executedReceiptSchema, artifactRecordSchema, qaCommandRecordSchema, qaResultRecordSchema, qaAttemptSchema, qaReceiptSchema, collectedReceiptSchema, evidenceReceiptSchema;
|
|
14857
14857
|
var init_protocol = __esm(() => {
|
|
14858
14858
|
init_zod();
|
|
14859
14859
|
workflowSchema = exports_external.enum(["fast", "complex"]);
|
|
@@ -25762,6 +25762,9 @@ function isRecord(value) {
|
|
|
25762
25762
|
function normalizeConfig(config2) {
|
|
25763
25763
|
assertSupportedSchema(config2);
|
|
25764
25764
|
const value = config2;
|
|
25765
|
+
if (value.mockupsBeforeCoding !== undefined && typeof value.mockupsBeforeCoding !== "boolean") {
|
|
25766
|
+
throw new EmpiricalError("INVALID_CONFIG", "mockupsBeforeCoding must be a boolean");
|
|
25767
|
+
}
|
|
25765
25768
|
const isolation = isRecord(value.isolation) ? value.isolation : {};
|
|
25766
25769
|
const decisions = isRecord(value.decisions) ? value.decisions : {};
|
|
25767
25770
|
const interaction = isRecord(value.interaction) ? value.interaction : {};
|
|
@@ -25788,6 +25791,7 @@ function normalizeConfig(config2) {
|
|
|
25788
25791
|
...config2,
|
|
25789
25792
|
schemaVersion: SCHEMA_VERSION,
|
|
25790
25793
|
profile: normalizeProfile(config2.profile),
|
|
25794
|
+
mockupsBeforeCoding: value.mockupsBeforeCoding === undefined ? true : value.mockupsBeforeCoding,
|
|
25791
25795
|
evidence: {
|
|
25792
25796
|
required: typeof evidence.required === "boolean" ? evidence.required : true,
|
|
25793
25797
|
browserForUi: typeof evidence.browserForUi === "boolean" ? evidence.browserForUi : true,
|
|
@@ -25944,6 +25948,52 @@ first and private \`empirical __internal\` fallbacks only when MCP is unavailabl
|
|
|
25944
25948
|
If the config is missing, invalid, or incomplete, do not initialize implicitly;
|
|
25945
25949
|
tell the user to invoke \`empirical-init\` explicitly.
|
|
25946
25950
|
${END}`;
|
|
25951
|
+
var LINEAR_MCP_DISCOVERY_GUIDANCE = `### Discover the host's Linear connection
|
|
25952
|
+
|
|
25953
|
+
Discover by capability, not by a guessed tool prefix. Inspect the actual host
|
|
25954
|
+
registry/tool metadata (including provider/server identity, descriptions and input
|
|
25955
|
+
schemas). Use host tool search or lazy loading when exposed; search for Linear
|
|
25956
|
+
and the needed operation, not just one namespace string. In code-mode hosts,
|
|
25957
|
+
inspect the available tool catalog (for example ALL_TOOLS) before invoking its
|
|
25958
|
+
actual callable name. Names such as mcp__linear__list_teams,
|
|
25959
|
+
mcp__plugin_linear__list_teams, or linear.list_teams are examples, not a whitelist.
|
|
25960
|
+
A failed prefix filter is not evidence that Linear is absent. Do not substitute
|
|
25961
|
+
an unrelated tool merely because its name or description contains "Linear";
|
|
25962
|
+
confirm provider provenance and a compatible input schema.
|
|
25963
|
+
|
|
25964
|
+
Keep three facts separate: configured server, exposed callable tools, and a
|
|
25965
|
+
successful authenticated request. An enabled OAuth entry in a host's MCP list
|
|
25966
|
+
proves configuration, not that this session loaded its tools or can authenticate.
|
|
25967
|
+
When the user selected Linear discovery, verify access with a bounded read-only
|
|
25968
|
+
team-list request using the smallest supported limit. Never probe with a write.
|
|
25969
|
+
Only claim authenticated access after a successful provider response. Classify
|
|
25970
|
+
401/login failures, 403/permission failures, transport/rate-limit failures, and
|
|
25971
|
+
missing tool exposure separately; none means "Linear is not installed".
|
|
25972
|
+
|
|
25973
|
+
For setup, discover only the needed read capabilities first: list teams, list
|
|
25974
|
+
projects and list issue statuses. Do not require save_issue, save_comment, or
|
|
25975
|
+
other future sync operations to begin read-only catalog discovery. Resolve later
|
|
25976
|
+
capabilities when required and report the exact missing operation. A partial
|
|
25977
|
+
capability set never authorizes changing authentication mode or pretending sync
|
|
25978
|
+
is available.
|
|
25979
|
+
|
|
25980
|
+
Treat canonical linear.* names returned by the Empirical bridge as operation
|
|
25981
|
+
identifiers, not literal host tool names. Map each to the discovered actual
|
|
25982
|
+
callable tool and its documented schema. Preserve operation semantics, target,
|
|
25983
|
+
authorized fields, bounded pagination and normalized result validation. Do not
|
|
25984
|
+
invent an argument translation, drop a required field, or replace an unavailable
|
|
25985
|
+
write with another operation; report the precise capability/schema gap instead.
|
|
25986
|
+
|
|
25987
|
+
Before reporting missing tools, exhaust the exposed registry and any available
|
|
25988
|
+
host search/lazy-load path. If the user shows an enabled OAuth server but tools
|
|
25989
|
+
remain unexposed, say "Linear is configured, but this session does not expose
|
|
25990
|
+
<needed capability>" and give host-specific exposure/reload recovery. Do not ask
|
|
25991
|
+
them to add an already configured server or log in again without an authentication
|
|
25992
|
+
failure. Do not infer a need for an API key from missing names, partial tools,
|
|
25993
|
+
permission errors or transient failures. Keep the chosen MCP/OAuth route; offer
|
|
25994
|
+
host-file credentials only after actual discovery/recovery checks and an explicit
|
|
25995
|
+
user choice to use that alternative. Never inspect private host OAuth stores.
|
|
25996
|
+
`;
|
|
25947
25997
|
var INIT_SKILL_BODY = `# Empirical Init
|
|
25948
25998
|
|
|
25949
25999
|
Use this skill only when the user explicitly asks to initialize, set up, or
|
|
@@ -25956,9 +26006,10 @@ Present setup as a wizard inside the current agent conversation. On each setup
|
|
|
25956
26006
|
turn, show \`Empirical init — Step N of 6: <name>\` and a compact progress line
|
|
25957
26007
|
using these stable stages, in order:
|
|
25958
26008
|
|
|
25959
|
-
1. **Setup** — inspect the repository
|
|
25960
|
-
|
|
25961
|
-
2. **Preferences** — verification, parallel work, decisions,
|
|
26009
|
+
1. **Setup** — inspect the repository, explain the proposed or saved settings,
|
|
26010
|
+
and offer only the actions applicable to that configuration.
|
|
26011
|
+
2. **Preferences** — verification, mockups before coding, parallel work, decisions,
|
|
26012
|
+
and question detail.
|
|
25962
26013
|
3. **Review bot** — resolve the optional bot choice once or keep its saved value.
|
|
25963
26014
|
4. **Tracking** — keep the saved choice or complete the existing tracker flow.
|
|
25964
26015
|
5. **Confirm** — show all effective settings; offer Save, Edit a section, or Cancel.
|
|
@@ -25968,13 +26019,22 @@ Mark each stage \`[done]\`, \`[current]\`, \`[pending]\`, or \`[blocked]\`.
|
|
|
25968
26019
|
For example, while choosing tracking:
|
|
25969
26020
|
\`[done] Setup > [done] Preferences > [done] Review bot > [current] Tracking > [pending] Confirm > [pending] Apply\`.
|
|
25970
26021
|
Before Apply, \`[done]\` means a decision is resolved, not that settings were
|
|
25971
|
-
saved. Keep stage numbers stable when skipping or revisiting decisions.
|
|
25972
|
-
|
|
25973
|
-
|
|
26022
|
+
saved. Keep stage numbers stable when skipping or revisiting decisions. Present each pending question exactly once. Prefer a callable host-native choice
|
|
26023
|
+
tool permitted in the current mode: Claude Code's AskUserQuestion, Codex's
|
|
26024
|
+
request_user_input when available, or the equivalent exposed by another agent.
|
|
26025
|
+
Follow that tool's schema and option limits; do not switch host mode to unlock it.
|
|
26026
|
+
Native tools supply keyboard/arrow selection where supported by the host; skill
|
|
26027
|
+
text cannot create keyboard controls. Put choices in the native tool only, with
|
|
26028
|
+
one step heading/progress summary; do not also print a numbered menu. If no
|
|
26029
|
+
permitted choice tool is available, end the turn with one numbered text question.
|
|
26030
|
+
Do not render the same step, summary or question in both commentary and final.
|
|
26031
|
+
After asking, wait for the answer without echoing the prompt. Do not invent an
|
|
26032
|
+
interactive widget or require a browser or terminal screen.
|
|
25974
26033
|
|
|
25975
26034
|
Show only the current section's detail and ask one material question at a time.
|
|
25976
|
-
|
|
25977
|
-
steps without redundant questions; they never bypass
|
|
26035
|
+
Use recommended settings and Keep current settings resolve unchanged preference
|
|
26036
|
+
steps without redundant questions; they never bypass an unresolved mockup choice,
|
|
26037
|
+
the one-time bot choice,
|
|
25978
26038
|
an unconfigured tracker choice, provider authorization, or final Save. On repair,
|
|
25979
26039
|
mark saved bot and tracker choices kept without offering them again. A user who
|
|
25980
26040
|
already answered a question in the request need not answer it again.
|
|
@@ -26010,16 +26070,48 @@ These are presentation stages, not feature workflow phases or new durable state.
|
|
|
26010
26070
|
Determine whether this is first setup or a repair. Preserve existing
|
|
26011
26071
|
configuration values and durable workflow history unless the user explicitly
|
|
26012
26072
|
changes a value.
|
|
26013
|
-
2. At Setup,
|
|
26014
|
-
|
|
26073
|
+
2. At Setup, choose the menu from inspected repository configuration, never from
|
|
26074
|
+
whether Empirical or its skills are globally installed:
|
|
26075
|
+
- Fresh repository (no saved configuration): say "No settings saved in this
|
|
26076
|
+
repository yet". Show the proposed defaults: verification required, browser
|
|
26077
|
+
and screenshot evidence for UI changes, isolated code review, ask before
|
|
26078
|
+
creating worktrees, automatic Git base, worktree path ../{repo}-{feature},
|
|
26079
|
+
branch pattern {type}/{feature}, Complex decision records required, and
|
|
26080
|
+
concise questions. Propose mockups before coding for UI changes, but resolve
|
|
26081
|
+
the explicit Yes/No choice in Preferences. Label reviewer bot and tracking
|
|
26082
|
+
as "Not chosen yet".
|
|
26083
|
+
Offer **Use recommended settings**, **Customize**, and **Cancel** only.
|
|
26084
|
+
Explain Use recommended settings as "Continue with the defaults shown;
|
|
26085
|
+
nothing is saved until Save". Never offer Keep current settings here.
|
|
26086
|
+
- Valid saved configuration: show its actual Verification, Parallel work,
|
|
26087
|
+
Mockups before coding, Decisions, Interaction, Review bot and Tracker values, labeled "Saved in
|
|
26088
|
+
this repository". Offer **Keep current settings**, **Customize**,
|
|
26089
|
+
**Configure tracker**, and **Cancel**. Explain Keep as retaining the values
|
|
26090
|
+
shown; never show recommended and current as competing primary choices.
|
|
26091
|
+
- Invalid or incomplete configuration: explain what is missing or invalid,
|
|
26092
|
+
preserve readable values in the draft, and resolve the missing choices;
|
|
26093
|
+
do not claim a complete saved setup or silently replace it with defaults.
|
|
26094
|
+
Keep this overview compact and put all action choices in the single native
|
|
26095
|
+
tool or text fallback described above. At Confirm,
|
|
26015
26096
|
before any mutation, render the complete effective Empirical setup summary for
|
|
26016
|
-
Verification, Pull-request review, Parallel work,
|
|
26017
|
-
and Tracker.
|
|
26097
|
+
Verification, Mockups before coding, Pull-request review, Parallel work,
|
|
26098
|
+
Decisions, Interaction, and Tracker. In Preferences ask **Create mockups before
|
|
26099
|
+
coding?** with **Yes (Recommended)** — approve a mockup before coding UI changes,
|
|
26100
|
+
and **No** — start UI implementation without mandatory mockups. Resolve this
|
|
26101
|
+
once on fresh setup even after Use recommended settings, unless already answered.
|
|
26102
|
+
Save the boolean as \`mockupsBeforeCoding\` through \`empirical_init\` or
|
|
26103
|
+
\`empirical_configure\` (private CLI: \`--mockups on/off\`). Show Yes/No in
|
|
26104
|
+
Confirm. Keep an existing value, including No, on repeat setup and unrelated
|
|
26105
|
+
configuration; revisit only on Customize/Edit or an explicit change request.
|
|
26106
|
+
Older configurations without the field retain Yes. This applies to UI-feature
|
|
26107
|
+
mockups, not terminal/backend work; browser/screenshot verification remains
|
|
26108
|
+
independent. Previously approved mockups still require fidelity verification.
|
|
26109
|
+
For question detail in Preferences, offer
|
|
26018
26110
|
\`concise\` questions (recommended for new setup) or \`detailed\` questions;
|
|
26019
26111
|
concise means ask only a question whose answer changes scope, architecture,
|
|
26020
26112
|
authorization, or a safety gate. When tracker setup is unconfigured, Tracker
|
|
26021
26113
|
MUST present \`Track work by type\` as the recommended default and
|
|
26022
|
-
\`No tracking\` as the explicit alternative.
|
|
26114
|
+
\`No tracking\` as the explicit alternative. Using recommended
|
|
26023
26115
|
settings or customizing MUST NOT bypass that choice. On repair with an
|
|
26024
26116
|
explicitly disabled or configured tracker, Preserve current tracker is the
|
|
26025
26117
|
default and MUST make no provider request. On Customize, visit Preferences,
|
|
@@ -26054,6 +26146,7 @@ These are presentation stages, not feature workflow phases or new durable state.
|
|
|
26054
26146
|
3. \`Track work by type\` selects Linear, GitHub Projects, or Jira and starts with
|
|
26055
26147
|
OAuth. First check for callable authenticated Linear MCP tools and prefer
|
|
26056
26148
|
the sibling MCP bridge when available, including during legacy policy repair.
|
|
26149
|
+
Follow the shared host-discovery procedure below before any unavailable claim.
|
|
26057
26150
|
Preserve target, states, ticket rules, visibility and enforcement; remove
|
|
26058
26151
|
credentialEnv only in the previewed Policy v2 MCP migration. The installed \`empirical mcp\` server supplies an in-memory client for
|
|
26059
26152
|
Linear's official remote MCP OAuth endpoint when no embedding resolver is
|
|
@@ -26076,20 +26169,21 @@ These are presentation stages, not feature workflow phases or new durable state.
|
|
|
26076
26169
|
Codex, verify that \`linear\` is enabled with OAuth, and resume tracker setup.
|
|
26077
26170
|
Explain that this enables direct Linear MCP tools but does not authorize
|
|
26078
26171
|
Empirical tracker mirroring. Do not read or reuse Codex's private OAuth
|
|
26079
|
-
credential store.
|
|
26080
|
-
|
|
26081
|
-
\`
|
|
26082
|
-
tools are available, use real Linear MCP-backed tracking: collect a bounded
|
|
26083
|
-
catalog, call \`empirical_tracker_linear_mcp_discover\`, preview and save a
|
|
26172
|
+
credential store. Resolve the actual callable names for the read capabilities
|
|
26173
|
+
using the shared host-discovery procedure. Collect a bounded catalog, call
|
|
26174
|
+
\`empirical_tracker_linear_mcp_discover\`, preview and save a
|
|
26084
26175
|
Linear Policy v2 with \`connection: "linear-mcp"\` and no \`credentialEnv\`,
|
|
26085
26176
|
then call \`empirical_tracker_linear_mcp_prepare\`. Execute only the exact
|
|
26086
|
-
returned \`linear.*\`
|
|
26177
|
+
returned \`linear.*\` operation through its discovered host tool and compatible
|
|
26178
|
+
arguments, exhaust bounded pagination when
|
|
26087
26179
|
the result shape requires \`complete: true\`, normalize only its documented safe
|
|
26088
26180
|
IDs/keys/URLs/names/state/comment fields, submit them with
|
|
26089
26181
|
\`empirical_tracker_linear_mcp_accept\`, and repeat prepare/tool/accept until
|
|
26090
26182
|
tracker health is \`synced\`. Never claim that login alone synchronized
|
|
26091
|
-
Empirical.
|
|
26092
|
-
|
|
26183
|
+
Empirical. A discovery or tool-exposure failure alone does not authorize
|
|
26184
|
+
credential fallback. Only after the shared discovery/recovery checks and the
|
|
26185
|
+
user explicitly chooses host-file credentials, present the secure alternative
|
|
26186
|
+
and say exactly
|
|
26093
26187
|
\`Never paste credentials into chat\`, show the expanded
|
|
26094
26188
|
host-only file path (\`\${XDG_CONFIG_HOME:-$HOME/.config}/empirical/secrets.env\`
|
|
26095
26189
|
on POSIX or \`%APPDATA%\\Empirical\\secrets.env\` on Windows), and name only
|
|
@@ -26134,7 +26228,9 @@ These are presentation stages, not feature workflow phases or new durable state.
|
|
|
26134
26228
|
or archive, and do not create or select feature workflow state.
|
|
26135
26229
|
|
|
26136
26230
|
Never scan other repositories, overwrite unmanaged files, follow unsafe paths,
|
|
26137
|
-
or claim automatic activation for a repository without valid completed config
|
|
26231
|
+
or claim automatic activation for a repository without valid completed config.
|
|
26232
|
+
|
|
26233
|
+
${LINEAR_MCP_DISCOVERY_GUIDANCE}`;
|
|
26138
26234
|
var LOCAL_AUTOMATIC_SKILL_BODY = `# Empirical
|
|
26139
26235
|
|
|
26140
26236
|
Automatically route, track, resume, and complete Empirical work in this
|
|
@@ -26202,7 +26298,8 @@ the user does not need to mention Empirical or choose a profile.
|
|
|
26202
26298
|
require an exact choice; Empirical never guesses.
|
|
26203
26299
|
After each local workflow mutation is durably committed, inspect the tracker
|
|
26204
26300
|
policy. Before a Linear credential operation, check authenticated sibling
|
|
26205
|
-
Linear MCP tools
|
|
26301
|
+
Linear MCP tools using the shared host-discovery procedure below. Prefer
|
|
26302
|
+
that connection even when a legacy API-key policy
|
|
26206
26303
|
exists: call the MCP prepare operation to obtain its migration candidate,
|
|
26207
26304
|
discover and preview through MCP, then configure the candidate preserving
|
|
26208
26305
|
target, states, ticket rules and enforcement. Policy v1 maps to manual
|
|
@@ -26211,7 +26308,8 @@ the user does not need to mention Empirical or choose a profile.
|
|
|
26211
26308
|
empirical_integrations; package upgrades alone do not rewrite repository files.
|
|
26212
26309
|
For Linear Policy v2 with \`connection: "linear-mcp"\`, call
|
|
26213
26310
|
\`empirical_tracker_linear_mcp_prepare\` with the exact feature id, execute
|
|
26214
|
-
only its returned \`linear.*\`
|
|
26311
|
+
only its returned \`linear.*\` operation via the discovered equivalent host
|
|
26312
|
+
tool/schema, submit the bounded normalized
|
|
26215
26313
|
result through \`empirical_tracker_linear_mcp_accept\`, and repeat until
|
|
26216
26314
|
synced. For issue results, copy attachment URLs from Linear get_issue into
|
|
26217
26315
|
attachmentUrls. For reconciliation, paginate the entire bounded team/project
|
|
@@ -26230,7 +26328,8 @@ the user does not need to mention Empirical or choose a profile.
|
|
|
26230
26328
|
Tracker operations are granular MCP tools, not additional skills or user
|
|
26231
26329
|
commands. OAuth authorization is out-of-band through negotiated URL mode.
|
|
26232
26330
|
Raw credentials are never chat text or tool arguments/results. If OAuth is
|
|
26233
|
-
unavailable
|
|
26331
|
+
unavailable, host discovery/recovery has been checked, and the user explicitly
|
|
26332
|
+
chooses host-file credentials, tell the human \`Never paste credentials into chat\` and pause
|
|
26234
26333
|
for direct host-file configuration at
|
|
26235
26334
|
\`\${XDG_CONFIG_HOME:-$HOME/.config}/empirical/secrets.env\` on POSIX or
|
|
26236
26335
|
\`%APPDATA%\\Empirical\\secrets.env\` on Windows.
|
|
@@ -26258,7 +26357,10 @@ the user does not need to mention Empirical or choose a profile.
|
|
|
26258
26357
|
isolated boundary on that exact remote base/head diff; request changes keep
|
|
26259
26358
|
the PR draft and a new head requires a new packet. Report the exact highest
|
|
26260
26359
|
completion level. Stop only at Done, Blocked, or Awaiting Human.
|
|
26261
|
-
9.
|
|
26360
|
+
9. The saved \`mockupsBeforeCoding\` preference controls new required UI mockups.
|
|
26361
|
+
Honor No without asking again; change it only on an explicit user request via
|
|
26362
|
+
\`empirical_configure\`. Existing approved designs retain fidelity checks.
|
|
26363
|
+
When a phase asks for a mockup, build the directions it names, then run
|
|
26262
26364
|
\`empirical mockups\` and give the user the address it prints. That command is
|
|
26263
26365
|
public on purpose: a person clicks through and chooses. Record their choice,
|
|
26264
26366
|
and anything the mockup revealed that the criteria do not cover, before the
|
|
@@ -26268,7 +26370,9 @@ the user does not need to mention Empirical or choose a profile.
|
|
|
26268
26370
|
another runtime requires explicit approval of its exact target, cwd, and argv.
|
|
26269
26371
|
|
|
26270
26372
|
Do not invent state, weaken acceptance criteria, expose credentials, or persist
|
|
26271
|
-
private chain-of-thought. Files under .empirical/ are the durable source of truth
|
|
26373
|
+
private chain-of-thought. Files under .empirical/ are the durable source of truth.
|
|
26374
|
+
|
|
26375
|
+
${LINEAR_MCP_DISCOVERY_GUIDANCE}`;
|
|
26272
26376
|
function skillContent(name, description, body, explicitOnly = false) {
|
|
26273
26377
|
const invocationMetadata = explicitOnly ? `disable-model-invocation: true
|
|
26274
26378
|
` : "";
|
|
@@ -42762,6 +42866,8 @@ async function evaluateMockupGate(input) {
|
|
|
42762
42866
|
if (input.phase === MOCKUP_GATE_PHASE) {
|
|
42763
42867
|
if (!interfaceSurface)
|
|
42764
42868
|
return empty(false);
|
|
42869
|
+
if (input.mockupsBeforeCoding === false)
|
|
42870
|
+
return empty(true);
|
|
42765
42871
|
const path = mockupApprovalPath(input.feature);
|
|
42766
42872
|
const entry = featureMockupEntryPath(input.feature);
|
|
42767
42873
|
const requiredPaths = [entry, path];
|
|
@@ -45742,7 +45848,7 @@ class EmpiricalProject {
|
|
|
45742
45848
|
static async initialize(root = process.cwd(), options = {}) {
|
|
45743
45849
|
const absoluteRoot = resolve16(root);
|
|
45744
45850
|
const trackerChange = options.tracker ? parseTrackerSetupChange(options.tracker) : undefined;
|
|
45745
|
-
if (trackerChange?.mode === "apply") {
|
|
45851
|
+
if (trackerChange?.mode === "apply" && !isLinearMcpPolicy(trackerChange.policy)) {
|
|
45746
45852
|
await previewTrackerPolicy(trackerChange.policy, withTrackerRepositoryRoot2(options.trackerDependencies ?? {}, absoluteRoot));
|
|
45747
45853
|
}
|
|
45748
45854
|
await mkdir9(absoluteRoot, { recursive: true });
|
|
@@ -45936,6 +46042,7 @@ class EmpiricalProject {
|
|
|
45936
46042
|
const current = await this.store.loadConfig();
|
|
45937
46043
|
const configured = await this.store.configure({
|
|
45938
46044
|
...current,
|
|
46045
|
+
mockupsBeforeCoding: input.mockupsBeforeCoding === undefined ? current.mockupsBeforeCoding : input.mockupsBeforeCoding,
|
|
45939
46046
|
evidence: { ...current.evidence, ...input.evidence },
|
|
45940
46047
|
isolation: { ...current.isolation, ...input.isolation },
|
|
45941
46048
|
decisions: { ...current.decisions, ...input.decisions },
|
|
@@ -47853,6 +47960,7 @@ class EmpiricalProject {
|
|
|
47853
47960
|
feature,
|
|
47854
47961
|
phase: state.phase,
|
|
47855
47962
|
criteria,
|
|
47963
|
+
mockupsBeforeCoding: (await store.loadConfig()).mockupsBeforeCoding,
|
|
47856
47964
|
read: async (path) => {
|
|
47857
47965
|
try {
|
|
47858
47966
|
const absolute = join20(store.root, path);
|
|
@@ -47940,6 +48048,7 @@ function defaultConfig(profile, legacySource, options = {}) {
|
|
|
47940
48048
|
schemaVersion: SCHEMA_VERSION,
|
|
47941
48049
|
profile,
|
|
47942
48050
|
maxRepairAttempts: 2,
|
|
48051
|
+
mockupsBeforeCoding: options.mockupsBeforeCoding === undefined ? true : options.mockupsBeforeCoding,
|
|
47943
48052
|
evidence: {
|
|
47944
48053
|
required: options.evidence?.required ?? true,
|
|
47945
48054
|
browserForUi: options.evidence?.browserForUi ?? true,
|
|
@@ -47972,9 +48081,10 @@ function initializationConfiguration(options) {
|
|
|
47972
48081
|
const decisions = options.decisions && Object.keys(options.decisions).length > 0 ? options.decisions : undefined;
|
|
47973
48082
|
const interaction = options.interaction && Object.keys(options.interaction).length > 0 ? options.interaction : undefined;
|
|
47974
48083
|
const review = options.review && Object.keys(options.review).length > 0 ? options.review : undefined;
|
|
47975
|
-
if (!evidence && !isolation && !decisions && !interaction && !review && options.setupComplete === undefined)
|
|
48084
|
+
if (!evidence && !isolation && !decisions && !interaction && !review && options.setupComplete === undefined && options.mockupsBeforeCoding === undefined)
|
|
47976
48085
|
return null;
|
|
47977
48086
|
return {
|
|
48087
|
+
...options.mockupsBeforeCoding !== undefined ? { mockupsBeforeCoding: options.mockupsBeforeCoding } : {},
|
|
47978
48088
|
...evidence ? { evidence } : {},
|
|
47979
48089
|
...isolation ? { isolation } : {},
|
|
47980
48090
|
...decisions ? { decisions } : {},
|
|
@@ -51255,6 +51365,7 @@ var reviewSubmissionSchema = exports_external.object({
|
|
|
51255
51365
|
reviewerInvocationId: exports_external.string().min(1).max(200)
|
|
51256
51366
|
}).strict();
|
|
51257
51367
|
var configurationSchema = {
|
|
51368
|
+
mockupsBeforeCoding: exports_external.boolean().optional(),
|
|
51258
51369
|
evidenceRequired: exports_external.boolean().optional(),
|
|
51259
51370
|
browserForUi: exports_external.boolean().optional(),
|
|
51260
51371
|
screenshotForUi: exports_external.boolean().optional(),
|
|
@@ -51361,7 +51472,7 @@ function createMcpServer(defaultRoot = mcpDefaultRoot(), options = {}) {
|
|
|
51361
51472
|
description: operationSummary("init"),
|
|
51362
51473
|
inputSchema: { root: exports_external.string().optional(), profile: profileSchema.optional(), tracker: trackerSetupSchema.optional(), ...configurationSchema },
|
|
51363
51474
|
annotations: operationAnnotations("init")
|
|
51364
|
-
}, async ({ root, profile, tracker, evidenceRequired, browserForUi, screenshotForUi, codeReview, reviewMode, reviewerTokenEnv, isolation, base, worktreePath, branchPattern, decisions, questions }) => toolResult(async () => {
|
|
51475
|
+
}, async ({ root, profile, tracker, evidenceRequired, browserForUi, screenshotForUi, codeReview, reviewMode, reviewerTokenEnv, isolation, base, worktreePath, branchPattern, decisions, questions, mockupsBeforeCoding }) => toolResult(async () => {
|
|
51365
51476
|
const initialized = await EmpiricalProject.initialize(root ?? defaultRoot, {
|
|
51366
51477
|
...profile ? { profile } : {},
|
|
51367
51478
|
evidence: {
|
|
@@ -51376,6 +51487,7 @@ function createMcpServer(defaultRoot = mcpDefaultRoot(), options = {}) {
|
|
|
51376
51487
|
...worktreePath ? { worktreePath } : {},
|
|
51377
51488
|
...branchPattern ? { branchPattern } : {}
|
|
51378
51489
|
},
|
|
51490
|
+
...mockupsBeforeCoding !== undefined ? { mockupsBeforeCoding } : {},
|
|
51379
51491
|
decisions: { ...decisions ? { complexRecords: decisions } : {} },
|
|
51380
51492
|
interaction: { ...questions ? { questions } : {} },
|
|
51381
51493
|
review: {
|
|
@@ -51417,7 +51529,7 @@ function createMcpServer(defaultRoot = mcpDefaultRoot(), options = {}) {
|
|
|
51417
51529
|
description: operationSummary("configure"),
|
|
51418
51530
|
inputSchema: { root: exports_external.string().optional(), policy: exports_external.unknown().optional(), tracker: trackerSetupSchema.optional(), ...configurationSchema },
|
|
51419
51531
|
annotations: operationAnnotations("configure")
|
|
51420
|
-
}, async ({ root, policy, tracker, evidenceRequired, browserForUi, screenshotForUi, codeReview, reviewMode, reviewerTokenEnv, isolation, base, worktreePath, branchPattern, decisions, questions }) => toolResult(async () => {
|
|
51532
|
+
}, async ({ root, policy, tracker, evidenceRequired, browserForUi, screenshotForUi, codeReview, reviewMode, reviewerTokenEnv, isolation, base, worktreePath, branchPattern, decisions, questions, mockupsBeforeCoding }) => toolResult(async () => {
|
|
51421
51533
|
const project = await EmpiricalProject.open(root ?? defaultRoot, { selection: "selected" });
|
|
51422
51534
|
const configurationSupplied = [
|
|
51423
51535
|
evidenceRequired,
|
|
@@ -51431,7 +51543,8 @@ function createMcpServer(defaultRoot = mcpDefaultRoot(), options = {}) {
|
|
|
51431
51543
|
worktreePath,
|
|
51432
51544
|
branchPattern,
|
|
51433
51545
|
decisions,
|
|
51434
|
-
questions
|
|
51546
|
+
questions,
|
|
51547
|
+
mockupsBeforeCoding
|
|
51435
51548
|
].some((value) => value !== undefined);
|
|
51436
51549
|
if (policy !== undefined && (tracker !== undefined || configurationSupplied)) {
|
|
51437
51550
|
throw new EmpiricalError("INVALID_CONFIG", "Configure project policy, project settings, and tracker setup in separate exact requests");
|
|
@@ -51453,6 +51566,7 @@ function createMcpServer(defaultRoot = mcpDefaultRoot(), options = {}) {
|
|
|
51453
51566
|
...worktreePath ? { worktreePath } : {},
|
|
51454
51567
|
...branchPattern ? { branchPattern } : {}
|
|
51455
51568
|
},
|
|
51569
|
+
...mockupsBeforeCoding !== undefined ? { mockupsBeforeCoding } : {},
|
|
51456
51570
|
decisions: { ...decisions ? { complexRecords: decisions } : {} },
|
|
51457
51571
|
interaction: { ...questions ? { questions } : {} },
|
|
51458
51572
|
review: {
|
|
@@ -52651,6 +52765,7 @@ function characterWidth(character) {
|
|
|
52651
52765
|
// src/setup.ts
|
|
52652
52766
|
function recommendedSetupSettings() {
|
|
52653
52767
|
return {
|
|
52768
|
+
mockupsBeforeCoding: true,
|
|
52654
52769
|
evidence: {
|
|
52655
52770
|
required: true,
|
|
52656
52771
|
browserForUi: true,
|
|
@@ -52673,6 +52788,7 @@ function recommendedSetupSettings() {
|
|
|
52673
52788
|
}
|
|
52674
52789
|
function setupSettingsFromConfig(config2) {
|
|
52675
52790
|
return {
|
|
52791
|
+
mockupsBeforeCoding: config2.mockupsBeforeCoding,
|
|
52676
52792
|
evidence: { ...config2.evidence },
|
|
52677
52793
|
isolation: { ...config2.isolation },
|
|
52678
52794
|
decisions: { ...config2.decisions },
|
|
@@ -52682,6 +52798,7 @@ function setupSettingsFromConfig(config2) {
|
|
|
52682
52798
|
}
|
|
52683
52799
|
function setupConfigurationInput(settings) {
|
|
52684
52800
|
return {
|
|
52801
|
+
mockupsBeforeCoding: settings.mockupsBeforeCoding,
|
|
52685
52802
|
evidence: { ...settings.evidence },
|
|
52686
52803
|
isolation: { ...settings.isolation },
|
|
52687
52804
|
decisions: { ...settings.decisions },
|
|
@@ -52691,6 +52808,9 @@ function setupConfigurationInput(settings) {
|
|
|
52691
52808
|
};
|
|
52692
52809
|
}
|
|
52693
52810
|
function validateSetupSettings(settings) {
|
|
52811
|
+
if (typeof settings.mockupsBeforeCoding !== "boolean") {
|
|
52812
|
+
throw new EmpiricalError("INVALID_CONFIG", "mockupsBeforeCoding must be a boolean");
|
|
52813
|
+
}
|
|
52694
52814
|
if (settings.isolation.mode !== "ask" && settings.isolation.mode !== "off") {
|
|
52695
52815
|
throw new EmpiricalError("INVALID_CONFIG", "Isolation must be ask or off");
|
|
52696
52816
|
}
|
|
@@ -52736,6 +52856,7 @@ function renderSetupSummary(settings, options = { current: false }) {
|
|
|
52736
52856
|
"Questions: concise · only material blockers",
|
|
52737
52857
|
`Verification: ${verification}`,
|
|
52738
52858
|
`Worktrees: ${settings.isolation.mode} · base ${base} · ${settings.isolation.branchPattern}`,
|
|
52859
|
+
`Mockups before coding: ${settings.mockupsBeforeCoding ? "Yes (UI changes)" : "No"}`,
|
|
52739
52860
|
`Decisions: ${settings.decisions.complexRecords}`,
|
|
52740
52861
|
`Review: ${settings.review.mode} · ${settings.review.mode === "bot" ? `credential name ${settings.review.reviewerTokenEnv}` : "fallback · no second credential"} · ${state}`,
|
|
52741
52862
|
reviewSetupGuidance(settings.review),
|
|
@@ -52763,6 +52884,8 @@ function renderSetupSummary(settings, options = { current: false }) {
|
|
|
52763
52884
|
`│ Path: ${settings.isolation.worktreePath}`,
|
|
52764
52885
|
`│ Branch: ${settings.isolation.branchPattern}`,
|
|
52765
52886
|
"│",
|
|
52887
|
+
`│ Mockups before coding: ${settings.mockupsBeforeCoding ? "Yes — approve UI mockups before coding" : "No — skip required mockups"}`,
|
|
52888
|
+
"│",
|
|
52766
52889
|
"│ Decisions",
|
|
52767
52890
|
`│ ${marker2(settings.decisions.complexRecords === "required")} ${settings.decisions.complexRecords === "required" ? "Require reviewable decision records for Complex work" : "Do not require Complex decision records"}`,
|
|
52768
52891
|
"│",
|
|
@@ -53615,6 +53738,9 @@ ${renderSetupSummary(settings, {
|
|
|
53615
53738
|
const firstChoice = await askEnumDefault(prompt, `Choice [${primary}]: `, primary, new Set([primary, current ? "k" : "a", "customize", "c", "tracker", "t", "cancel", "x", "q"]));
|
|
53616
53739
|
if (["cancel", "x", "q"].includes(firstChoice))
|
|
53617
53740
|
throw setupCancelled();
|
|
53741
|
+
if (!current && !["customize", "c"].includes(firstChoice)) {
|
|
53742
|
+
settings.mockupsBeforeCoding = await askMockupPreference(prompt, settings.mockupsBeforeCoding);
|
|
53743
|
+
}
|
|
53618
53744
|
if (firstChoice === primary || firstChoice === (current ? "k" : "a")) {
|
|
53619
53745
|
if (currentTrackerSetup.mode !== "unconfigured") {
|
|
53620
53746
|
return { configuration: setupConfigurationInput(settings), tracker: { mode: "preserve" } };
|
|
@@ -53929,6 +54055,7 @@ async function customizeSetup(prompt, current) {
|
|
|
53929
54055
|
} else {
|
|
53930
54056
|
console.log("Worktree base and templates are inactive and will keep their stored values.");
|
|
53931
54057
|
}
|
|
54058
|
+
const mockupsBeforeCoding = await askMockupPreference(prompt, current.mockupsBeforeCoding);
|
|
53932
54059
|
console.log(`
|
|
53933
54060
|
◆ Decisions`);
|
|
53934
54061
|
const complexRecords = await askEnumDefault(prompt, `Complex decision records [${current.decisions.complexRecords}] (required/off): `, current.decisions.complexRecords, new Set(["required", "off"]));
|
|
@@ -53938,11 +54065,15 @@ async function customizeSetup(prompt, current) {
|
|
|
53938
54065
|
return {
|
|
53939
54066
|
evidence: { required: required2, browserForUi, screenshotForUi, codeReview },
|
|
53940
54067
|
isolation: { mode, baseBranch, worktreePath, branchPattern },
|
|
54068
|
+
mockupsBeforeCoding,
|
|
53941
54069
|
decisions: { complexRecords },
|
|
53942
54070
|
interaction: { questions },
|
|
53943
54071
|
review: { mode: reviewMode, reviewerTokenEnv }
|
|
53944
54072
|
};
|
|
53945
54073
|
}
|
|
54074
|
+
async function askMockupPreference(prompt, current) {
|
|
54075
|
+
return await askEnumDefault(prompt, `Create mockups before coding? [${current ? "yes" : "no"}] (yes/no, UI changes): `, current ? "yes" : "no", new Set(["yes", "no"])) === "yes";
|
|
54076
|
+
}
|
|
53946
54077
|
async function askOnOff(prompt, label, current) {
|
|
53947
54078
|
const fallback = current ? "on" : "off";
|
|
53948
54079
|
return await askEnumDefault(prompt, `${label} [${fallback}] (on/off): `, fallback, new Set(["on", "off"])) === "on";
|
|
@@ -54318,6 +54449,7 @@ function parseGlobals(argv) {
|
|
|
54318
54449
|
return { args, root, json: json2 };
|
|
54319
54450
|
}
|
|
54320
54451
|
function readConfigurationFlags(args) {
|
|
54452
|
+
const mockupsBeforeCoding = takeOnOffOption(args, "--mockups");
|
|
54321
54453
|
const evidenceRequired = takeOnOffOption(args, "--evidence");
|
|
54322
54454
|
const browserForUi = takeOnOffOption(args, "--ui-browser");
|
|
54323
54455
|
const screenshotForUi = takeOnOffOption(args, "--ui-screenshot");
|
|
@@ -54349,10 +54481,11 @@ function readConfigurationFlags(args) {
|
|
|
54349
54481
|
const questions = takeOption(args, "--questions");
|
|
54350
54482
|
if (questions && questions !== "concise" && questions !== "detailed")
|
|
54351
54483
|
throw new EmpiricalError("INVALID_CONFIG", "--questions must be concise or detailed");
|
|
54352
|
-
const explicit = [evidenceRequired, browserForUi, screenshotForUi, codeReview].some((value) => value !== undefined) || Boolean(reviewMode || reviewerTokenEnv || mode || baseBranch || worktreePath || branchPattern || complexRecords || questions);
|
|
54484
|
+
const explicit = [mockupsBeforeCoding, evidenceRequired, browserForUi, screenshotForUi, codeReview].some((value) => value !== undefined) || Boolean(reviewMode || reviewerTokenEnv || mode || baseBranch || worktreePath || branchPattern || complexRecords || questions);
|
|
54353
54485
|
return {
|
|
54354
54486
|
explicit,
|
|
54355
54487
|
input: {
|
|
54488
|
+
...mockupsBeforeCoding !== undefined ? { mockupsBeforeCoding } : {},
|
|
54356
54489
|
...evidenceRequired !== undefined || browserForUi !== undefined || screenshotForUi !== undefined || codeReview !== undefined ? { evidence: {
|
|
54357
54490
|
...evidenceRequired !== undefined ? { required: evidenceRequired } : {},
|
|
54358
54491
|
...browserForUi !== undefined ? { browserForUi } : {},
|