@hasna/instructions 0.7.1 → 0.7.2

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 (59) hide show
  1. package/README.md +34 -7
  2. package/dist/chunks/{apply-c3sd4agz.js → apply-ps6jjt6k.js} +3 -3
  3. package/dist/chunks/{apply-pnn7a3y7.js → apply-wj7wh5km.js} +3 -3
  4. package/dist/chunks/{index-pdpg8a44.js → index-18j7x3xw.js} +2 -2
  5. package/dist/chunks/{index-3djthcm6.js → index-27az1qb1.js} +28 -1
  6. package/dist/chunks/{index-ypcef3a2.js → index-ape24zc0.js} +2 -2
  7. package/dist/chunks/{index-jg8ptcwh.js → index-ek15201v.js} +2 -2
  8. package/dist/chunks/{index-6jncnnw7.js → index-n6nh6f5r.js} +119 -17
  9. package/dist/chunks/{index-aj66f6xr.js → index-pq18fdbj.js} +29 -6
  10. package/dist/chunks/{index-n3fjspr0.js → index-preyvj8n.js} +28 -1
  11. package/dist/chunks/{index-r7nfef2g.js → index-y8410ve0.js} +3 -3
  12. package/dist/chunks/{local-0a9gja58.js → local-1c1qxzvx.js} +15 -4
  13. package/dist/chunks/{local-969ye538.js → local-hc67bynj.js} +15 -4
  14. package/dist/chunks/{sync-q5hvwq6e.js → sync-12m3vs6g.js} +4 -4
  15. package/dist/chunks/{sync-xtkbm5br.js → sync-azd9t4p8.js} +4 -4
  16. package/dist/chunks/{template-wgnzdn7h.js → template-e4qrxs8p.js} +1 -1
  17. package/dist/chunks/{template-fsfxpe4p.js → template-nhn124zd.js} +1 -1
  18. package/dist/cli/index.js +596 -133
  19. package/dist/data/config-store.d.ts +12 -4
  20. package/dist/data/config-store.d.ts.map +1 -1
  21. package/dist/db/configs.d.ts.map +1 -1
  22. package/dist/index.d.ts +5 -3
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +658 -98
  25. package/dist/lib/asset-plan.d.ts.map +1 -1
  26. package/dist/lib/codewith-shared-todos-storage-standard.d.ts.map +1 -1
  27. package/dist/lib/dangerous-operation-guard-standard.d.ts.map +1 -1
  28. package/dist/lib/global-agent-rules-standard.d.ts.map +1 -1
  29. package/dist/lib/global-source-coverage.d.ts +12 -7
  30. package/dist/lib/global-source-coverage.d.ts.map +1 -1
  31. package/dist/lib/instruction-graph.d.ts +1 -1
  32. package/dist/lib/instruction-graph.d.ts.map +1 -1
  33. package/dist/lib/instruction-source-policy.d.ts +6 -0
  34. package/dist/lib/instruction-source-policy.d.ts.map +1 -0
  35. package/dist/lib/platform-profiles.d.ts.map +1 -1
  36. package/dist/lib/project-dashboard-standard.d.ts.map +1 -1
  37. package/dist/lib/session-apply.d.ts +24 -0
  38. package/dist/lib/session-apply.d.ts.map +1 -1
  39. package/dist/lib/session-refresh.d.ts +30 -0
  40. package/dist/lib/session-refresh.d.ts.map +1 -0
  41. package/dist/lib/session-render.d.ts +34 -1
  42. package/dist/lib/session-render.d.ts.map +1 -1
  43. package/dist/lib/transforms.d.ts +1 -0
  44. package/dist/lib/transforms.d.ts.map +1 -1
  45. package/dist/mcp/index.js +13 -12
  46. package/dist/mcp/server.d.ts.map +1 -1
  47. package/dist/sdk/index.js +19 -0
  48. package/dist/sdk/v1-client.d.ts +7 -1
  49. package/dist/sdk/v1-client.d.ts.map +1 -1
  50. package/dist/sdk/v1.generated.d.ts +20 -0
  51. package/dist/sdk/v1.generated.d.ts.map +1 -1
  52. package/dist/server/index.js +122 -8
  53. package/dist/server/openapi.d.ts +123 -0
  54. package/dist/server/openapi.d.ts.map +1 -1
  55. package/dist/server/v1.d.ts.map +1 -1
  56. package/dist/storage/cloud-store.d.ts.map +1 -1
  57. package/dist/types/index.d.ts +16 -2
  58. package/dist/types/index.d.ts.map +1 -1
  59. package/package.json +1 -1
package/README.md CHANGED
@@ -83,6 +83,24 @@ envelope. Its top-level fields are `configs`, `profiles`, `drift`, `secrets`,
83
83
  `secrets.policy` is `redacted_on_ingest`. Run `instructions report` without
84
84
  `--json` for the human-readable report.
85
85
 
86
+ ### Conditional config updates
87
+
88
+ Read the current config version before preparing an edit, then pass that
89
+ `expected_version` to `updateConfig` (store/public SDK), `update_config` (MCP), or:
90
+
91
+ ```bash
92
+ instructions add ./rule.md --kind reference --name example-rule --update --expected-version 7
93
+ ```
94
+
95
+ Guarded clients use `POST /v1/configs/:id/conditional-update`, which requires
96
+ `expected_version`. The generated SDK also exposes `conditionalUpdateConfig` for
97
+ this operation. An older server returns 404 without mutation; clients never fall
98
+ back to an unconditional update. A version mismatch returns HTTP 409 with code
99
+ `CONFIG_VERSION_CONFLICT`, changing neither the config nor its snapshots. Refresh
100
+ and review the newer version before trying again. Calls without a precondition
101
+ retain their existing behavior. New servers also accept `expected_version` on
102
+ PATCH/PUT; use the dedicated conditional route when server capabilities are unknown.
103
+
86
104
  ## Package-Manager Secret Guard
87
105
 
88
106
  `instructions package-manager-scan` blocks package-manager credential ingress without
@@ -361,13 +379,20 @@ upgrade.
361
379
 
362
380
  `instructions session plan` and `instructions session apply` render
363
381
  OpenIdentities and instruction sources into provider-native files for Claude,
364
- Codex, Cursor, OpenCode, Codewith, Qwen, aicopilot, and Google Antigravity.
382
+ Codex, Cursor, OpenCode, Sumi, Codewith, Qwen, aicopilot, and Google Antigravity.
365
383
  The old Google agent target is removed; Antigravity is the only Google coding
366
384
  agent render target. Antigravity workspace rules are rendered to
367
385
  `.agents/rules/*.md`; its current global rules and MCP files use Google's
368
386
  legacy-named `~/.gemini/GEMINI.md` and `~/.gemini/config/mcp_config.json`
369
387
  paths but remain owned by the `antigravity` target.
370
388
 
389
+ Sumi renders one flattened `AGENTS.md`. Pass its actual config directory from
390
+ `sumi debug paths config` as `--target-home`, or use `--project-root` for
391
+ repository instructions. Global plans return `SUMI_CONFIG_DIR`; project plans
392
+ do not change the global config environment. No OpenCode config or fragment
393
+ imports are written. See [session rendering](docs/session-rendering.md) for
394
+ capability limits and examples.
395
+
371
396
  Qwen Code session rendering writes `QWEN.md` instructional context with
372
397
  `QWEN_HOME` pointing at the rendered profile home. Known config sync also
373
398
  tracks Qwen Code `QWEN.md` and `settings.json` files at `~/.qwen/...` and
@@ -536,14 +561,16 @@ and prior on-box-only evidence must be explicitly reconciled before use.
536
561
 
537
562
  ## Machine-aware Profiles
538
563
 
539
- `instructions init` seeds two platform profiles:
564
+ `instructions init` seeds two empty platform profiles:
540
565
 
541
- - `linux-arm64` for `linux-node-a` / `linux-node-b`
542
- - `macos-arm64` for `macos-node-a` / `macos-node-b`
566
+ - `linux-arm64` for Linux arm64
567
+ - `macos-arm64` for macOS arm64
543
568
 
544
- These profiles resolve machine variables like `{{WORKSPACE_ROOT}}`,
545
- `{{BUN_BIN_DIR}}`, `{{BUN_PATH}}`, and `{{PATH_PREFIX}}`, so synced configs can be
546
- portable across Linux and macOS arm64 machines.
569
+ The public presets contain no fleet hostnames or workspace paths. They resolve
570
+ portable tool variables such as `{{BUN_BIN_DIR}}`, `{{BUN_PATH}}`, and
571
+ `{{PATH_PREFIX}}`. Instruction membership is never bulk-copied from the config
572
+ registry; bind reviewed provider/project/role sources explicitly before compiling
573
+ a prompt profile.
547
574
 
548
575
  They also include the project channel variable used by agent-managed project
549
576
  workflows:
@@ -8,10 +8,10 @@ import {
8
8
  getConfigHome,
9
9
  normalizeTargetPath,
10
10
  previewConfigs
11
- } from "./index-ypcef3a2.js";
12
- import"./index-aj66f6xr.js";
11
+ } from "./index-ape24zc0.js";
12
+ import"./index-pq18fdbj.js";
13
13
  import"./index-35z65jsa.js";
14
- import"./index-3djthcm6.js";
14
+ import"./index-27az1qb1.js";
15
15
  import"./index-nnwp92tk.js";
16
16
  export {
17
17
  previewConfigs,
@@ -8,9 +8,9 @@ import {
8
8
  getConfigHome,
9
9
  normalizeTargetPath,
10
10
  previewConfigs
11
- } from "./index-r7nfef2g.js";
12
- import"./index-6jncnnw7.js";
13
- import"./index-n3fjspr0.js";
11
+ } from "./index-y8410ve0.js";
12
+ import"./index-n6nh6f5r.js";
13
+ import"./index-preyvj8n.js";
14
14
  import"./index-fpeyzn3n.js";
15
15
  import"./index-bsan4c16.js";
16
16
  export {
@@ -5,7 +5,7 @@ import {
5
5
  expandPath,
6
6
  getConfigHome,
7
7
  normalizeTargetPath
8
- } from "./index-r7nfef2g.js";
8
+ } from "./index-y8410ve0.js";
9
9
  import {
10
10
  applyTransform,
11
11
  detectMachineContext,
@@ -16,7 +16,7 @@ import {
16
16
  resolveConfigStore,
17
17
  retiredOrUnsupportedAgentReason,
18
18
  templateizeMachineContent
19
- } from "./index-6jncnnw7.js";
19
+ } from "./index-n6nh6f5r.js";
20
20
 
21
21
  // src/lib/sync.ts
22
22
  import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync2 } from "fs";
@@ -4,6 +4,7 @@ var CONFIG_AGENTS = [
4
4
  "claude",
5
5
  "codex",
6
6
  "opencode",
7
+ "sumi",
7
8
  "cursor",
8
9
  "codewith",
9
10
  "aicopilot",
@@ -28,6 +29,32 @@ var ASSET_DESTINATION_STRATEGIES = ["emit-file", "install-local", "install-marke
28
29
  var ASSET_SCOPES = ["global", "project", "session"];
29
30
  var ASSET_UNINSTALL_POLICIES = ["remove-managed", "retain"];
30
31
  var ASSET_ROLLBACK_POLICIES = ["snapshot", "installer-receipt", "none"];
32
+ class InvalidExpectedVersionError extends Error {
33
+ code = "INVALID_EXPECTED_VERSION";
34
+ constructor() {
35
+ super("expected_version must be a positive safe integer");
36
+ this.name = "InvalidExpectedVersionError";
37
+ }
38
+ }
39
+ function validateExpectedConfigVersion(value) {
40
+ if (value !== undefined && (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1)) {
41
+ throw new InvalidExpectedVersionError;
42
+ }
43
+ }
44
+
45
+ class ConfigVersionConflictError extends Error {
46
+ config_id;
47
+ expected_version;
48
+ code = "CONFIG_VERSION_CONFLICT";
49
+ status = 409;
50
+ constructor(config_id, expected_version) {
51
+ super(`Config version conflict: ${config_id} no longer has expected version ${expected_version}`);
52
+ this.config_id = config_id;
53
+ this.expected_version = expected_version;
54
+ this.name = "ConfigVersionConflictError";
55
+ }
56
+ }
57
+
31
58
  class ConfigNotFoundError extends Error {
32
59
  constructor(id) {
33
60
  super(`Config not found: ${id}`);
@@ -114,4 +141,4 @@ function isTemplate(content) {
114
141
  return VAR_PATTERN.test(content);
115
142
  }
116
143
 
117
- export { CONFIG_AGENTS, PROFILE_CONFIG_BINDING_SCHEMA, INSTRUCTION_ACTIVATION_MODES, INSTRUCTION_FALLBACKS, PROFILE_ASSET_BINDING_SCHEMA, ASSET_KINDS, ASSET_DESTINATION_STRATEGIES, ASSET_SCOPES, ASSET_UNINSTALL_POLICIES, ASSET_ROLLBACK_POLICIES, ConfigNotFoundError, ProfileNotFoundError, ConfigApplyError, parseTemplateVars, extractTemplateVars, renderTemplate, renderTemplatePreview, isTemplate };
144
+ export { CONFIG_AGENTS, PROFILE_CONFIG_BINDING_SCHEMA, INSTRUCTION_ACTIVATION_MODES, INSTRUCTION_FALLBACKS, PROFILE_ASSET_BINDING_SCHEMA, ASSET_KINDS, ASSET_DESTINATION_STRATEGIES, ASSET_SCOPES, ASSET_UNINSTALL_POLICIES, ASSET_ROLLBACK_POLICIES, validateExpectedConfigVersion, ConfigVersionConflictError, ConfigNotFoundError, ProfileNotFoundError, ConfigApplyError, parseTemplateVars, extractTemplateVars, renderTemplate, renderTemplatePreview, isTemplate };
@@ -15,7 +15,7 @@ import {
15
15
  resolveConfigStore,
16
16
  resolveProfileVariables,
17
17
  stampCursorGlobalAuthorityMarker
18
- } from "./index-aj66f6xr.js";
18
+ } from "./index-pq18fdbj.js";
19
19
  import {
20
20
  isSecretVarName,
21
21
  redactFormatForTarget,
@@ -24,7 +24,7 @@ import {
24
24
  import {
25
25
  ConfigApplyError,
26
26
  parseTemplateVars
27
- } from "./index-3djthcm6.js";
27
+ } from "./index-27az1qb1.js";
28
28
 
29
29
  // src/lib/apply.ts
30
30
  import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, realpathSync, writeFileSync } from "fs";
@@ -5,7 +5,7 @@ import {
5
5
  expandPath,
6
6
  getConfigHome,
7
7
  normalizeTargetPath
8
- } from "./index-ypcef3a2.js";
8
+ } from "./index-ape24zc0.js";
9
9
  import {
10
10
  applyTransform,
11
11
  detectMachineContext,
@@ -13,7 +13,7 @@ import {
13
13
  resolveConfigStore,
14
14
  retiredOrUnsupportedAgentReason,
15
15
  templateizeMachineContent
16
- } from "./index-aj66f6xr.js";
16
+ } from "./index-pq18fdbj.js";
17
17
  import {
18
18
  isSecretVarName,
19
19
  redactContent,
@@ -14,8 +14,9 @@ import {
14
14
  ProfileNotFoundError,
15
15
  isTemplate,
16
16
  renderTemplate,
17
- renderTemplatePreview
18
- } from "./index-n3fjspr0.js";
17
+ renderTemplatePreview,
18
+ validateExpectedConfigVersion
19
+ } from "./index-preyvj8n.js";
19
20
  import {
20
21
  INSTRUCTIONS_LOCAL_OPT_IN_ENV_KEYS,
21
22
  clientTransportEnvKeys,
@@ -77,6 +78,36 @@ function truncateMiddle(value, max = 80) {
77
78
  return `${text.slice(0, head)}...${text.slice(text.length - tail)}`;
78
79
  }
79
80
 
81
+ // src/lib/instruction-source-policy.ts
82
+ function isRetiredInstructionSource(config) {
83
+ return config.tags.some((tag) => tag === "retired-global-source" || tag === "retired-instruction-source");
84
+ }
85
+ function instructionSourceRejection(config) {
86
+ if (isRetiredInstructionSource(config) || config.tags.includes("config-only")) {
87
+ return "source is retired or explicitly configuration-only";
88
+ }
89
+ if (config.category !== "rules")
90
+ return `category ${config.category} is not an instruction source; classify reviewed prose as rules`;
91
+ if (config.format !== "markdown" && config.format !== "text")
92
+ return `format ${config.format} is not instruction prose`;
93
+ if (config.is_template)
94
+ return "unresolved templates must be rendered and reviewed before prompt injection";
95
+ if (!config.content.trim())
96
+ return "instruction source is empty";
97
+ if (config.content.includes("\x00"))
98
+ return "instruction source contains binary content";
99
+ const target = config.target_path?.split(/[\\/]/).pop() ?? "";
100
+ if (/\.(?:json|toml|yaml|yml|ini|sh|bash|zsh|fish|js|ts|py|rules)$/i.test(target)) {
101
+ return "target is an executable, provider policy, or settings file rather than a prompt";
102
+ }
103
+ return null;
104
+ }
105
+ function assertInstructionSource(config) {
106
+ const rejection = instructionSourceRejection(config);
107
+ if (rejection)
108
+ throw new Error(`Cannot inject ${config.slug}: ${rejection}.`);
109
+ }
110
+
80
111
  // src/lib/global-agent-rules-standard.ts
81
112
  import { createHash as createHash7 } from "crypto";
82
113
 
@@ -186,17 +217,18 @@ async function ensureCodewithSharedTodosStorageStandardConfig(store = resolveCon
186
217
  let config;
187
218
  try {
188
219
  const existing = await store.getConfig(CODEWITH_SHARED_TODOS_STORAGE_STANDARD_SLUG);
220
+ if (isRetiredInstructionSource(existing))
221
+ return existing;
189
222
  if (existing.content !== input.content || existing.description !== input.description || existing.category !== input.category || existing.agent !== input.agent || existing.format !== input.format || existing.kind !== input.kind || JSON.stringify(existing.tags) !== JSON.stringify(input.tags)) {
190
223
  config = await store.updateConfig(existing.id, input);
191
224
  } else {
192
225
  config = existing;
193
226
  }
194
- } catch {
227
+ } catch (error) {
228
+ if (!(error instanceof ConfigNotFoundError))
229
+ throw error;
195
230
  config = await store.createConfig(input);
196
231
  }
197
- for (const profile of await store.listProfiles()) {
198
- await store.addConfigToProfile(profile.id, config.id);
199
- }
200
232
  return config;
201
233
  }
202
234
 
@@ -7373,6 +7405,9 @@ function buildCodexAgentsMd(source, context = {}) {
7373
7405
  function buildOpenCodeAgentsMd(source, context = {}) {
7374
7406
  return flattenWithRules(source, context);
7375
7407
  }
7408
+ function buildSumiAgentsMd(source, context = {}) {
7409
+ return flattenWithRules(source, context);
7410
+ }
7376
7411
  function buildCursorMdc(source) {
7377
7412
  const stem = source.target_path ? basename2(source.target_path, extname(source.target_path)) : source.slug;
7378
7413
  const description = source.name || stem;
@@ -7401,6 +7436,8 @@ function applyTransform(source, output, context = {}) {
7401
7436
  return buildCodexAgentsMd(source, context);
7402
7437
  case "opencode-flat":
7403
7438
  return buildOpenCodeAgentsMd(source, context);
7439
+ case "sumi-flat":
7440
+ return buildSumiAgentsMd(source, context);
7404
7441
  case "cursor-mdc":
7405
7442
  return buildCursorMdc(source);
7406
7443
  case "skill-neutral":
@@ -7515,6 +7552,7 @@ var DEFAULT_ASSET_SURFACES = Object.freeze({
7515
7552
  codex: "cli",
7516
7553
  cursor: "ide",
7517
7554
  opencode: "cli",
7555
+ sumi: "cli",
7518
7556
  codewith: "cli",
7519
7557
  qwen: "cli",
7520
7558
  aicopilot: "cli",
@@ -8178,6 +8216,7 @@ var SESSION_RENDER_TOOLS = [
8178
8216
  "codex",
8179
8217
  "cursor",
8180
8218
  "opencode",
8219
+ "sumi",
8181
8220
  "codewith",
8182
8221
  "qwen",
8183
8222
  "aicopilot",
@@ -8266,6 +8305,15 @@ var SESSION_TOOL_ADAPTERS = {
8266
8305
  description: "OpenCode AGENTS.md plus opencode.json instructions pointing at managed fragments.",
8267
8306
  providerSurface: "legacy-dual"
8268
8307
  },
8308
+ sumi: {
8309
+ tool: "sumi",
8310
+ mode: "flattened-markdown",
8311
+ indexFile: "AGENTS.md",
8312
+ managedDir: SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR,
8313
+ envVar: "SUMI_CONFIG_DIR",
8314
+ nativeImports: false,
8315
+ description: "Sumi native AGENTS.md in the explicit resolved config directory or project root."
8316
+ },
8269
8317
  aicopilot: {
8270
8318
  tool: "aicopilot",
8271
8319
  mode: "flattened-markdown",
@@ -8550,9 +8598,19 @@ function skippedSource(source, reason) {
8550
8598
  };
8551
8599
  }
8552
8600
  function normalizeSources(sources, tool, allowEmptySources) {
8553
- const normalized = sources.map((source, index) => {
8601
+ const providerSkipped = [];
8602
+ const normalized = sources.flatMap((source, index) => {
8554
8603
  if (!source.id.trim())
8555
8604
  throw new Error("Session instruction source id is required.");
8605
+ if (source.targetProviders?.length && !providerTargetsTool(source.targetProviders, tool)) {
8606
+ providerSkipped.push({
8607
+ id: source.id,
8608
+ label: source.label ?? source.id,
8609
+ targetProviders: source.targetProviders,
8610
+ reason: "instruction source targets a different provider"
8611
+ });
8612
+ return [];
8613
+ }
8556
8614
  const floored = applyAgentOperatingRulesFloor(source, source.content ?? "");
8557
8615
  const content = filterProviderOnlyBlocks(floored.content, tool);
8558
8616
  const normalized2 = {
@@ -8571,7 +8629,7 @@ function normalizeSources(sources, tool, allowEmptySources) {
8571
8629
  if (!allowEmptySources && !normalized2.content.trim() && normalized2.resolvedRules.length === 0 && !hasPathReferences) {
8572
8630
  throw new Error(`Session instruction source "${source.id}" is empty. Pass --allow-empty-sources only for explicit empty renders.`);
8573
8631
  }
8574
- return normalized2;
8632
+ return [normalized2];
8575
8633
  });
8576
8634
  const originalOrder = [...normalized].sort(compareSessionInstructionSources);
8577
8635
  const deduplicated = deduplicateSemanticPolicySources(normalized);
@@ -8579,7 +8637,7 @@ function normalizeSources(sources, tool, allowEmptySources) {
8579
8637
  validateTargetedReplacementSources(originalOrder, ordered, deduplicated.skipped, tool);
8580
8638
  rejectDuplicateSourceSlugs(ordered);
8581
8639
  rejectDuplicateRulePaths(ordered);
8582
- return { sources: ordered, skipped: deduplicated.skipped };
8640
+ return { sources: ordered, skipped: [...providerSkipped, ...deduplicated.skipped] };
8583
8641
  }
8584
8642
  function compareSessionInstructionSources(a, b) {
8585
8643
  return SESSION_LAYER_RANK[a.resolvedLayer] - SESSION_LAYER_RANK[b.resolvedLayer] || a.resolvedOrder - b.resolvedOrder || a.id.localeCompare(b.id);
@@ -9185,6 +9243,11 @@ function isNativeProfileSessionTarget(input) {
9185
9243
  return (input.tool === "grok" || input.tool === "devin") && Boolean(input.targetHome?.trim()) && !input.projectRoot;
9186
9244
  }
9187
9245
  function adapterFor(input) {
9246
+ if (input.tool === "sumi" && input.projectRoot) {
9247
+ if (input.providerSurface)
9248
+ throw new Error(`Provider surface ${input.providerSurface} is not valid for Sumi.`);
9249
+ return Object.freeze({ ...SESSION_TOOL_ADAPTERS.sumi, projectScoped: true, envVar: undefined });
9250
+ }
9188
9251
  if (input.tool === "opencode" && input.providerSurface) {
9189
9252
  if (input.providerSurface !== "opencode-config-instructions" && input.providerSurface !== "opencode-agents-md") {
9190
9253
  throw new Error(`Provider surface ${input.providerSurface} is not valid for OpenCode.`);
@@ -9226,7 +9289,7 @@ function adapterFor(input) {
9226
9289
  }
9227
9290
  if (input.tool !== "codewith")
9228
9291
  return SESSION_TOOL_ADAPTERS[input.tool];
9229
- const gatedNativeImports = input.codewithNativeImports === true || process.env[CODEWITH_NATIVE_IMPORTS_ENV] === "1" || process.env[CODEWITH_NATIVE_IMPORTS_ENV] === "true";
9292
+ const gatedNativeImports = input.codewithNativeImports ?? (process.env[CODEWITH_NATIVE_IMPORTS_ENV] === "1" || process.env[CODEWITH_NATIVE_IMPORTS_ENV] === "true");
9230
9293
  return gatedNativeImports ? CODEWITH_NATIVE_ADAPTER : CODEWITH_FLATTENED_ADAPTER;
9231
9294
  }
9232
9295
  function getHomeDir() {
@@ -9277,6 +9340,13 @@ function assertSafeTargetRoot(targetHome) {
9277
9340
  return normalized;
9278
9341
  }
9279
9342
  function resolveRenderTarget(input, adapter) {
9343
+ if (input.tool === "sumi" && !input.projectRoot && !input.targetHome?.trim()) {
9344
+ return {
9345
+ targetHome: defaultTargetHome(input.tool, input.profile, input.sessionId),
9346
+ targetKind: "blocked",
9347
+ blockers: ["Sumi requires --target-home from `sumi debug paths config`, or --project-root for repository AGENTS.md."]
9348
+ };
9349
+ }
9280
9350
  if (adapter.projectScoped) {
9281
9351
  if (!input.projectRoot) {
9282
9352
  const label = input.tool === "cursor" ? "Cursor rules" : input.tool === "antigravity" ? "Antigravity rules" : `${adapter.description.split(".")[0]} files`;
@@ -9378,6 +9448,14 @@ function planSessionRender(input) {
9378
9448
  const normalized = normalizeSources(input.sources, input.tool, allowEmptySources);
9379
9449
  const composed = composeSources(normalized.sources, input.tool);
9380
9450
  const orderedSources = composed.sources;
9451
+ if (input.tool === "sumi") {
9452
+ for (const source of orderedSources) {
9453
+ const activation = source.metadata?.["activation"];
9454
+ if (source.globs?.length || source.resolvedRules.some((rule) => rule.globs?.length) || activation?.mode && activation.mode !== "always") {
9455
+ throw new Error(`Sumi AGENTS.md cannot preserve conditional activation for source ${source.id}; compile a profile with an explicit supported fallback.`);
9456
+ }
9457
+ }
9458
+ }
9381
9459
  const skippedSources = [
9382
9460
  ...input.skippedSources ?? [],
9383
9461
  ...normalized.skipped,
@@ -9421,6 +9499,7 @@ function planSessionRender(input) {
9421
9499
  adapterMode: adapter.mode,
9422
9500
  profile: input.profile,
9423
9501
  sessionId: input.sessionId ?? null,
9502
+ ...input.refreshSelector ? { refreshSelector: input.refreshSelector } : {},
9424
9503
  targetHome,
9425
9504
  targetKind,
9426
9505
  targetOwner,
@@ -9933,6 +10012,7 @@ var DEFAULT_PROVIDER_CAPABILITIES = Object.freeze({
9933
10012
  codex: capability("codex", ">=0.1.0", "flattened", "AGENTS.md", { asset_surface: "cli" }),
9934
10013
  cursor: capability("cursor", ">=1.0.0", "cursor-rule", ".cursor/rules/*.mdc", { activation_modes: ["always", "glob"], conditional_artifacts: true, asset_surface: "ide" }),
9935
10014
  opencode: capability("opencode", ">=1.0.0", "managed-fragment", "opencode.json instructions", { provider_variant: "v1-instructions", session_surface: "opencode-config-instructions" }),
10015
+ sumi: capability("sumi", ">=0.2.22 <0.3.0", "flattened", "AGENTS.md"),
9936
10016
  codewith: capability("codewith", ">=0.1.0", "flattened", "CODEWITH.md"),
9937
10017
  qwen: capability("qwen", ">=0.1.0", "flattened", "QWEN.md"),
9938
10018
  aicopilot: capability("aicopilot", ">=0.1.0", "flattened", "AICOPILOT.md"),
@@ -10155,12 +10235,22 @@ function compileInstructionGraph(input) {
10155
10235
  const selector = binding.providers?.find((entry) => entry.provider === input.context.provider || entry.provider === "global");
10156
10236
  if (binding.providers?.length && !selector)
10157
10237
  continue;
10238
+ const output = config.outputs.find((entry) => entry.agent === input.context.provider);
10239
+ if (!binding.providers?.length && config.agent !== "global" && config.agent !== input.context.provider && !output) {
10240
+ diagnostics.push({ severity: "info", code: "SOURCE_PROVIDER_NOT_SELECTED", config_id: configId, message: `${config.slug} targets ${config.agent}, not ${input.context.provider}.` });
10241
+ continue;
10242
+ }
10158
10243
  if (selector?.version_range && !providerVersionSatisfies(input.context.provider_version, selector.version_range)) {
10159
10244
  diagnostics.push({ severity: binding.required ? "error" : "warning", code: "PROVIDER_SELECTOR_VERSION_MISMATCH", config_id: configId, message: `${config.slug} requires ${input.context.provider} ${selector.version_range}; current version is ${input.context.provider_version}.` });
10160
10245
  continue;
10161
10246
  }
10162
10247
  if (!activationMatches(binding.activation, config, input.context))
10163
10248
  continue;
10249
+ const rejection = instructionSourceRejection(config);
10250
+ if (rejection) {
10251
+ diagnostics.push({ severity: !binding.required && binding.fallback === "omit" ? "warning" : "error", code: "SOURCE_NOT_INSTRUCTION", config_id: configId, message: `${config.slug}: ${rejection}.` });
10252
+ continue;
10253
+ }
10164
10254
  if (capability2.activation_modes.includes(binding.activation.mode)) {
10165
10255
  selected.add(configId);
10166
10256
  effective.set(configId, binding.activation);
@@ -10235,7 +10325,9 @@ function compileInstructionGraph(input) {
10235
10325
  assertExactOnce(units, artifacts);
10236
10326
  const sources = units.map((unit, index) => {
10237
10327
  const config = configs.get(unit.config_id);
10238
- return sourceForUnit(config, unit, index);
10328
+ const output = config.outputs.find((entry) => entry.agent === input.context.provider);
10329
+ const content = output ? applyTransform(config, output, { configs: [config] }) : config.content;
10330
+ return sourceForUnit({ ...config, content }, unit, index);
10239
10331
  });
10240
10332
  const planWithoutHash = {
10241
10333
  schema: INSTRUCTION_GRAPH_PLAN_SCHEMA,
@@ -11819,7 +11911,7 @@ function formatCliError(err, env = process.env) {
11819
11911
  var localStoreModulePromise = null;
11820
11912
  function localStoreModule() {
11821
11913
  if (!localStoreModulePromise)
11822
- localStoreModulePromise = import("./local-969ye538.js");
11914
+ localStoreModulePromise = import("./local-hc67bynj.js");
11823
11915
  return localStoreModulePromise;
11824
11916
  }
11825
11917
 
@@ -12100,7 +12192,9 @@ class CloudConfigStore {
12100
12192
  return data.config;
12101
12193
  }
12102
12194
  async updateConfig(idOrSlug, input) {
12103
- const { data } = await this.request("PATCH", `/configs/${encodeURIComponent(idOrSlug)}`, input);
12195
+ validateExpectedConfigVersion(input.expected_version);
12196
+ const conditional = input.expected_version !== undefined;
12197
+ const { data } = await this.request(conditional ? "POST" : "PATCH", `/configs/${encodeURIComponent(idOrSlug)}${conditional ? "/conditional-update" : ""}`, input);
12104
12198
  return data.config;
12105
12199
  }
12106
12200
  async deleteConfig(idOrSlug) {
@@ -12177,7 +12271,7 @@ class CloudConfigStore {
12177
12271
  throw new ProfileNotFoundError(idOrSlug);
12178
12272
  return parseBoundedOrLegacyPage(data.configs, data.profile.configs, normalized, "profile membership");
12179
12273
  }
12180
- async getProfileConfigBindings(idOrSlug) {
12274
+ async getProfileConfigBindings(idOrSlug, options = {}) {
12181
12275
  let routeMissing = false;
12182
12276
  const bindings = await aggregateBoundedCollection("profile config bindings", async (cursor) => {
12183
12277
  const normalized = normalizeBoundedReadOptions({ limit: 100, cursor });
@@ -12190,6 +12284,8 @@ class CloudConfigStore {
12190
12284
  }, (binding) => `${binding.profile_id}\x00${binding.config_id}`);
12191
12285
  if (!routeMissing)
12192
12286
  return bindings;
12287
+ if (options.requireExplicit)
12288
+ throw new Error("HOSTED_BINDINGS_REQUIRED: profile config binding route is unavailable; refusing legacy activation fallback.");
12193
12289
  const profile = await this.getProfile(idOrSlug);
12194
12290
  const configs = await this.getProfileConfigs(idOrSlug);
12195
12291
  return configs.map((config, sort_order) => ({
@@ -12254,7 +12350,7 @@ class CloudConfigStore {
12254
12350
  async removeConfigFromProfile(profileIdOrSlug, configId) {
12255
12351
  await this.request("DELETE", `/profiles/${encodeURIComponent(profileIdOrSlug)}/configs/${encodeURIComponent(configId)}`, undefined, { allow404: true });
12256
12352
  }
12257
- async getProfileAssetBindings(profileIdOrSlug) {
12353
+ async getProfileAssetBindings(profileIdOrSlug, options = {}) {
12258
12354
  let routeMissing = false;
12259
12355
  const assets = await aggregateBoundedCollection("profile asset bindings", async (cursor) => {
12260
12356
  const normalized = normalizeBoundedReadOptions({ limit: 100, cursor });
@@ -12267,6 +12363,8 @@ class CloudConfigStore {
12267
12363
  }, (asset) => `${asset.profile_id}\x00${asset.binding.assetKey}`);
12268
12364
  if (!routeMissing)
12269
12365
  return assets;
12366
+ if (options.requireExplicit)
12367
+ throw new Error("HOSTED_ASSETS_REQUIRED: profile asset binding route is unavailable; refusing an empty asset fallback.");
12270
12368
  await this.getProfile(profileIdOrSlug);
12271
12369
  return [];
12272
12370
  }
@@ -12580,9 +12678,13 @@ async function ensureGlobalAgentRulesStandardConfig(store = resolveConfigStore()
12580
12678
  let existing;
12581
12679
  try {
12582
12680
  existing = await store.getConfig(GLOBAL_AGENT_RULES_STANDARD_SLUG);
12583
- } catch {
12681
+ } catch (error) {
12682
+ if (!(error instanceof ConfigNotFoundError))
12683
+ throw error;
12584
12684
  return await store.createConfig(standardConfigInput(resolveAgentOperatingRulesPayload(null)));
12585
12685
  }
12686
+ if (isRetiredInstructionSource(existing))
12687
+ return existing;
12586
12688
  const payload = resolveAgentOperatingRulesPayload(existing.content);
12587
12689
  const input = standardConfigInput(payload);
12588
12690
  if (existing.content !== input.content || existing.description !== input.description || existing.category !== input.category || existing.agent !== input.agent || existing.format !== input.format || existing.kind !== input.kind || JSON.stringify(existing.tags) !== JSON.stringify(input.tags)) {
@@ -12688,4 +12790,4 @@ function renderMachineAwareContentPreview(content, variables) {
12688
12790
  return isTemplate(content) ? renderTemplatePreview(content, variables) : { content, unresolved: [] };
12689
12791
  }
12690
12792
 
12691
- export { DEFAULT_LIST_LIMIT, parseLimit, paginate, truncateText, truncateMiddle, normalizeBoundedReadOptions, boundedReadPage, ensureGlobalAgentRulesStandardConfig, ensureCodewithSharedTodosStorageStandardConfig, redactFormatForTarget, redactContent, scanSecrets, isSecretVarName, SESSION_RENDER_MANAGED_MARKER, SESSION_RENDER_SCHEMA, SESSION_RENDER_MANIFEST_RELATIVE_PATH, SESSION_INSTRUCTION_LAYERS, getSessionRenderSnapshotDir, sessionRenderSnapshotWorkspaceRoot, PROJECT_CONTEXT_MAX_INPUT_BYTES, SESSION_MANAGED_INPUT_MAX_BYTES, ProjectContextError, parseProjectContextBundle, planProjectContext, observeProjectContextSessionGuard, withProjectContextSessionGuard, applyProjectContext, writeProjectContextCoordinatedFile, removeProjectContextCoordinatedFile, isRetiredOrUnsupportedConfigAgent, retiredOrUnsupportedAgentReason, applyTransform, normalizeProfileAssetBinding, observeCursorGlobalAuthorityAtPath, isCursorGlobalAuthorityPath, stampCursorGlobalAuthorityMarker, detectCursorAuthorityConflicts, detectClaudeAuthorityConflicts, ANTIGRAVITY_RULE_FILE_CHAR_LIMIT, SESSION_RENDERER_OWNER_ID, SESSION_RENDER_TOOLS, SESSION_RENDER_OWNED_CONFIG_TARGETS, SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS, normalizeSessionInstructionSourceId, resolveSessionPath, planSessionRender, sourceFromFilePath, sourceFromConfig, sourcesFromIdentityExport, legacyProfileConfigBinding, normalizeProfileConfigBinding, planProfileSessionRender, normalizeOsFamily, detectMachineContext, machineContextToVariables, resolveProfileVariables, templateizeMachineContent, renderMachineAwareContentPreview, formatCliError, CloudConfigStore, resolveConfigStore };
12793
+ export { DEFAULT_LIST_LIMIT, parseLimit, paginate, truncateText, truncateMiddle, normalizeBoundedReadOptions, boundedReadPage, isRetiredInstructionSource, instructionSourceRejection, assertInstructionSource, ensureGlobalAgentRulesStandardConfig, ensureCodewithSharedTodosStorageStandardConfig, exports_external, redactFormatForTarget, redactContent, scanSecrets, isSecretVarName, CODEWITH_NATIVE_IMPORTS_ENV, SESSION_RENDER_MANAGED_MARKER, SESSION_RENDER_SCHEMA, SESSION_RENDER_MANIFEST_RELATIVE_PATH, SESSION_INSTRUCTION_LAYERS, getSessionRenderSnapshotDir, sessionRenderSnapshotWorkspaceRoot, PROJECT_CONTEXT_MAX_INPUT_BYTES, SESSION_MANAGED_INPUT_MAX_BYTES, ProjectContextError, parseProjectContextBundle, planProjectContext, observeProjectContextSessionGuard, withProjectContextSessionGuard, applyProjectContext, writeProjectContextCoordinatedFile, removeProjectContextCoordinatedFile, isRetiredOrUnsupportedConfigAgent, retiredOrUnsupportedAgentReason, applyTransform, normalizeProfileAssetBinding, observeCursorGlobalAuthorityAtPath, isCursorGlobalAuthorityPath, stampCursorGlobalAuthorityMarker, detectCursorAuthorityConflicts, detectClaudeAuthorityConflicts, ANTIGRAVITY_RULE_FILE_CHAR_LIMIT, SESSION_RENDERER_OWNER_ID, SESSION_RENDER_TOOLS, SESSION_RENDER_OWNED_CONFIG_TARGETS, SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS, normalizeSessionInstructionSourceId, resolveSessionPath, planSessionRender, sourceFromFilePath, sourceFromConfig, sourcesFromIdentityExport, legacyProfileConfigBinding, normalizeProfileConfigBinding, planProfileSessionRender, normalizeOsFamily, detectMachineContext, machineContextToVariables, resolveProfileVariables, templateizeMachineContent, renderMachineAwareContentPreview, formatCliError, CloudConfigStore, resolveConfigStore };
@@ -14,8 +14,9 @@ import {
14
14
  ProfileNotFoundError,
15
15
  isTemplate,
16
16
  renderTemplate,
17
- renderTemplatePreview
18
- } from "./index-3djthcm6.js";
17
+ renderTemplatePreview,
18
+ validateExpectedConfigVersion
19
+ } from "./index-27az1qb1.js";
19
20
  import {
20
21
  __export,
21
22
  __require
@@ -114,6 +115,9 @@ function buildCodexAgentsMd(source, context = {}) {
114
115
  function buildOpenCodeAgentsMd(source, context = {}) {
115
116
  return flattenWithRules(source, context);
116
117
  }
118
+ function buildSumiAgentsMd(source, context = {}) {
119
+ return flattenWithRules(source, context);
120
+ }
117
121
  function buildCursorMdc(source) {
118
122
  const stem = source.target_path ? basename(source.target_path, extname(source.target_path)) : source.slug;
119
123
  const description = source.name || stem;
@@ -142,6 +146,8 @@ function applyTransform(source, output, context = {}) {
142
146
  return buildCodexAgentsMd(source, context);
143
147
  case "opencode-flat":
144
148
  return buildOpenCodeAgentsMd(source, context);
149
+ case "sumi-flat":
150
+ return buildSumiAgentsMd(source, context);
145
151
  case "cursor-mdc":
146
152
  return buildCursorMdc(source);
147
153
  case "skill-neutral":
@@ -409,6 +415,7 @@ var DEFAULT_ASSET_SURFACES = Object.freeze({
409
415
  codex: "cli",
410
416
  cursor: "ide",
411
417
  opencode: "cli",
418
+ sumi: "cli",
412
419
  codewith: "cli",
413
420
  qwen: "cli",
414
421
  aicopilot: "cli",
@@ -534,6 +541,7 @@ var DEFAULT_PROVIDER_CAPABILITIES = Object.freeze({
534
541
  codex: capability("codex", ">=0.1.0", "flattened", "AGENTS.md", { asset_surface: "cli" }),
535
542
  cursor: capability("cursor", ">=1.0.0", "cursor-rule", ".cursor/rules/*.mdc", { activation_modes: ["always", "glob"], conditional_artifacts: true, asset_surface: "ide" }),
536
543
  opencode: capability("opencode", ">=1.0.0", "managed-fragment", "opencode.json instructions", { provider_variant: "v1-instructions", session_surface: "opencode-config-instructions" }),
544
+ sumi: capability("sumi", ">=0.2.22 <0.3.0", "flattened", "AGENTS.md"),
537
545
  codewith: capability("codewith", ">=0.1.0", "flattened", "CODEWITH.md"),
538
546
  qwen: capability("qwen", ">=0.1.0", "flattened", "QWEN.md"),
539
547
  aicopilot: capability("aicopilot", ">=0.1.0", "flattened", "AICOPILOT.md"),
@@ -2115,7 +2123,7 @@ function isNotFoundHttpError2(err) {
2115
2123
  var localStoreModulePromise = null;
2116
2124
  function localStoreModule() {
2117
2125
  if (!localStoreModulePromise)
2118
- localStoreModulePromise = import("./local-0a9gja58.js");
2126
+ localStoreModulePromise = import("./local-1c1qxzvx.js");
2119
2127
  return localStoreModulePromise;
2120
2128
  }
2121
2129
 
@@ -2396,7 +2404,9 @@ class CloudConfigStore {
2396
2404
  return data.config;
2397
2405
  }
2398
2406
  async updateConfig(idOrSlug, input) {
2399
- const { data } = await this.request("PATCH", `/configs/${encodeURIComponent(idOrSlug)}`, input);
2407
+ validateExpectedConfigVersion(input.expected_version);
2408
+ const conditional = input.expected_version !== undefined;
2409
+ const { data } = await this.request(conditional ? "POST" : "PATCH", `/configs/${encodeURIComponent(idOrSlug)}${conditional ? "/conditional-update" : ""}`, input);
2400
2410
  return data.config;
2401
2411
  }
2402
2412
  async deleteConfig(idOrSlug) {
@@ -2473,7 +2483,7 @@ class CloudConfigStore {
2473
2483
  throw new ProfileNotFoundError(idOrSlug);
2474
2484
  return parseBoundedOrLegacyPage(data.configs, data.profile.configs, normalized, "profile membership");
2475
2485
  }
2476
- async getProfileConfigBindings(idOrSlug) {
2486
+ async getProfileConfigBindings(idOrSlug, options = {}) {
2477
2487
  let routeMissing = false;
2478
2488
  const bindings = await aggregateBoundedCollection("profile config bindings", async (cursor) => {
2479
2489
  const normalized = normalizeBoundedReadOptions({ limit: 100, cursor });
@@ -2486,6 +2496,8 @@ class CloudConfigStore {
2486
2496
  }, (binding) => `${binding.profile_id}\x00${binding.config_id}`);
2487
2497
  if (!routeMissing)
2488
2498
  return bindings;
2499
+ if (options.requireExplicit)
2500
+ throw new Error("HOSTED_BINDINGS_REQUIRED: profile config binding route is unavailable; refusing legacy activation fallback.");
2489
2501
  const profile = await this.getProfile(idOrSlug);
2490
2502
  const configs = await this.getProfileConfigs(idOrSlug);
2491
2503
  return configs.map((config, sort_order) => ({
@@ -2550,7 +2562,7 @@ class CloudConfigStore {
2550
2562
  async removeConfigFromProfile(profileIdOrSlug, configId) {
2551
2563
  await this.request("DELETE", `/profiles/${encodeURIComponent(profileIdOrSlug)}/configs/${encodeURIComponent(configId)}`, undefined, { allow404: true });
2552
2564
  }
2553
- async getProfileAssetBindings(profileIdOrSlug) {
2565
+ async getProfileAssetBindings(profileIdOrSlug, options = {}) {
2554
2566
  let routeMissing = false;
2555
2567
  const assets = await aggregateBoundedCollection("profile asset bindings", async (cursor) => {
2556
2568
  const normalized = normalizeBoundedReadOptions({ limit: 100, cursor });
@@ -2563,6 +2575,8 @@ class CloudConfigStore {
2563
2575
  }, (asset) => `${asset.profile_id}\x00${asset.binding.assetKey}`);
2564
2576
  if (!routeMissing)
2565
2577
  return assets;
2578
+ if (options.requireExplicit)
2579
+ throw new Error("HOSTED_ASSETS_REQUIRED: profile asset binding route is unavailable; refusing an empty asset fallback.");
2566
2580
  await this.getProfile(profileIdOrSlug);
2567
2581
  return [];
2568
2582
  }
@@ -7199,6 +7213,15 @@ var SESSION_TOOL_ADAPTERS = {
7199
7213
  description: "OpenCode AGENTS.md plus opencode.json instructions pointing at managed fragments.",
7200
7214
  providerSurface: "legacy-dual"
7201
7215
  },
7216
+ sumi: {
7217
+ tool: "sumi",
7218
+ mode: "flattened-markdown",
7219
+ indexFile: "AGENTS.md",
7220
+ managedDir: SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR,
7221
+ envVar: "SUMI_CONFIG_DIR",
7222
+ nativeImports: false,
7223
+ description: "Sumi native AGENTS.md in the explicit resolved config directory or project root."
7224
+ },
7202
7225
  aicopilot: {
7203
7226
  tool: "aicopilot",
7204
7227
  mode: "flattened-markdown",