@kylecheng3146/agent-ops 0.1.18 → 0.1.19

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.
@@ -2,6 +2,13 @@ import { AgentOpsError } from "./paths.js";
2
2
  function escapeRegExp(value) {
3
3
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4
4
  }
5
+ export function normalizeToLF(source) {
6
+ return source.replace(/\r\n/g, "\n");
7
+ }
8
+ /** Newline sequence to use for newly rendered content, inferred from the file. */
9
+ function detectNewline(source) {
10
+ return source.includes("\r\n") ? "\r\n" : "\n";
11
+ }
5
12
  function assertBlockId(id) {
6
13
  if (!/^[a-z][a-z0-9-]{0,127}$/.test(id)) {
7
14
  throw new AgentOpsError("INVALID_BLOCK_ID", `Invalid block ID: ${id}`);
@@ -70,25 +77,30 @@ function locateMarkers(source, id, version, markerStyle = "html") {
70
77
  }
71
78
  return { start, end, startIndex, endIndex };
72
79
  }
73
- function renderBlock(options) {
80
+ function renderBlock(options, nl) {
74
81
  if (/(?:<!--|#)\s*agent-ops:/.test(options.content)) {
75
82
  throw new AgentOpsError("AMBIGUOUS_MANAGED_CONTENT", "Managed content must not contain agent-ops marker boundaries.");
76
83
  }
77
84
  const { start, end } = managedBlockMarkers(options.id, options.version, options.markerStyle);
78
- const content = options.content.replace(/\r\n/g, "\n").replace(/\n+$/g, "");
79
- return `${start}\n${content}\n${end}`;
85
+ const content = normalizeToLF(options.content)
86
+ .replace(/\n+$/g, "")
87
+ .split("\n")
88
+ .join(nl);
89
+ return `${start}${nl}${content}${nl}${end}`;
80
90
  }
81
91
  export function applyManagedBlock(source, options) {
82
- const block = renderBlock(options);
92
+ const nl = detectNewline(source);
93
+ const block = renderBlock(options, nl);
83
94
  const located = locateMarkers(source, options.id, options.version, options.markerStyle);
84
95
  if (located === null) {
85
96
  if (source.length === 0) {
86
- return `${block}\n`;
97
+ return `${block}${nl}`;
87
98
  }
88
- return `${source.replace(/\n*$/, "\n\n")}${block}\n`;
99
+ return `${source.replace(/(?:\r\n|\n)*$/, `${nl}${nl}`)}${block}${nl}`;
89
100
  }
90
101
  return `${source.slice(0, located.startIndex)}${block}${source.slice(located.endIndex + located.end.length)}`;
91
102
  }
103
+ const NEWLINE_STYLES = ["\r\n", "\n"];
92
104
  export function removeManagedBlock(source, id, markerStyle = "html") {
93
105
  const located = locateMarkers(source, id, undefined, markerStyle);
94
106
  if (located === null) {
@@ -96,12 +108,13 @@ export function removeManagedBlock(source, id, markerStyle = "html") {
96
108
  }
97
109
  let before = source.slice(0, located.startIndex);
98
110
  let after = source.slice(located.endIndex + located.end.length);
99
- if (before.length === 0 && after === "\n") {
111
+ if (before.length === 0 && NEWLINE_STYLES.some((nl) => after === nl)) {
100
112
  return "";
101
113
  }
102
- if (before.endsWith("\n\n") && after.startsWith("\n")) {
103
- before = before.slice(0, -1);
104
- after = after.slice(1);
114
+ const collapseNl = NEWLINE_STYLES.find((nl) => before.endsWith(`${nl}${nl}`) && after.startsWith(nl));
115
+ if (collapseNl !== undefined) {
116
+ before = before.slice(0, -collapseNl.length);
117
+ after = after.slice(collapseNl.length);
105
118
  }
106
119
  return `${before}${after}`;
107
120
  }
@@ -1,4 +1,4 @@
1
- import { applyManagedBlock, managedBlockMarkers } from "../fs/managed-block.js";
1
+ import { applyManagedBlock, managedBlockMarkers, normalizeToLF } from "../fs/managed-block.js";
2
2
  import { AgentOpsError } from "../fs/paths.js";
3
3
  import { harnessDescriptor, harnessHookPath, routingBlockId, selectHarnessHookSurface, rulesArtifactId } from "./harness.js";
4
4
  import { isOpencodePluginPath } from "../adapters/opencode/config.js";
@@ -211,18 +211,18 @@ export function assertExpectedManagedBlock(source, marker, expected) {
211
211
  startIndex >= endIndex) {
212
212
  throw new AgentOpsError("MANAGED_BLOCK_CHANGED", `Managed block boundaries changed after installation: ${marker.path}`);
213
213
  }
214
- const currentBlock = source.slice(startIndex, endIndex + marker.endMarker.length);
214
+ const currentBlock = normalizeToLF(source.slice(startIndex, endIndex + marker.endMarker.length));
215
215
  const candidates = [
216
216
  ["desired", expected.content],
217
217
  ...expected.legacyContent.map((content) => ["legacy", content])
218
218
  ];
219
219
  for (const [kind, content] of candidates) {
220
- const expectedBlock = applyManagedBlock("", {
220
+ const expectedBlock = normalizeToLF(applyManagedBlock("", {
221
221
  id: expected.id,
222
222
  version: 1,
223
223
  content,
224
224
  markerStyle: expected.markerStyle
225
- }).replace(/\n$/u, "");
225
+ }).replace(/\n$/u, ""));
226
226
  if (currentBlock === expectedBlock) {
227
227
  return kind;
228
228
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kylecheng3146/agent-ops",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
4
4
  "description": "Evidence-driven development loops for Codex, Claude Code, and opencode",
5
5
  "type": "module",
6
6
  "license": "MIT",