march-cli 0.1.30 → 0.1.32
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/package.json
CHANGED
|
@@ -113,9 +113,9 @@ function renderTable(token, lines, width) {
|
|
|
113
113
|
shrinkColumns(widths, Math.max(1, width - borderWidth - paddingWidth));
|
|
114
114
|
|
|
115
115
|
lines.push(formatTableBorder(widths, "┌", "┬", "┐"));
|
|
116
|
-
lines.push(formatTableRow(cells[0], widths, true));
|
|
116
|
+
lines.push(...formatTableRow(cells[0], widths, true));
|
|
117
117
|
lines.push(formatTableBorder(widths, "├", "┼", "┤"));
|
|
118
|
-
for (const row of cells.slice(1)) lines.push(formatTableRow(row, widths, false));
|
|
118
|
+
for (const row of cells.slice(1)) lines.push(...formatTableRow(row, widths, false));
|
|
119
119
|
lines.push(formatTableBorder(widths, "└", "┴", "┘"));
|
|
120
120
|
}
|
|
121
121
|
|
|
@@ -200,12 +200,18 @@ function plainInline(tokens) {
|
|
|
200
200
|
}
|
|
201
201
|
|
|
202
202
|
function formatTableRow(row, widths, header) {
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
203
|
+
const wrappedCells = widths.map((width, i) => wrapTableCell(row[i] ?? "", width));
|
|
204
|
+
const height = Math.max(...wrappedCells.map((cell) => cell.length));
|
|
205
|
+
const visualRows = [];
|
|
206
|
+
for (let lineIndex = 0; lineIndex < height; lineIndex += 1) {
|
|
207
|
+
const cells = widths.map((width, i) => {
|
|
208
|
+
const text = wrappedCells[i][lineIndex] ?? "";
|
|
209
|
+
const padded = text + " ".repeat(Math.max(0, width - visibleWidth(text)));
|
|
210
|
+
return ` ${header ? bold(padded) : padded} `;
|
|
211
|
+
});
|
|
212
|
+
visualRows.push(`${brightBlack("│")}${cells.join(brightBlack("│"))}${brightBlack("│")}`);
|
|
213
|
+
}
|
|
214
|
+
return visualRows;
|
|
209
215
|
}
|
|
210
216
|
|
|
211
217
|
function formatTableBorder(widths, left, join, right) {
|
|
@@ -218,22 +224,30 @@ function shrinkColumns(widths, maxTotal) {
|
|
|
218
224
|
widths[index] -= 1;
|
|
219
225
|
}
|
|
220
226
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
227
|
+
function wrapTableCell(text, width) {
|
|
228
|
+
const lines = [];
|
|
229
|
+
let current = "";
|
|
230
|
+
let currentWidth = 0;
|
|
231
|
+
for (const ch of String(text ?? "")) {
|
|
232
|
+
if (ch === "\n") {
|
|
233
|
+
lines.push(current);
|
|
234
|
+
current = "";
|
|
235
|
+
currentWidth = 0;
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
const charWidth = visibleWidth(ch);
|
|
239
|
+
if (currentWidth + charWidth > width && currentWidth > 0) {
|
|
240
|
+
lines.push(current.trimEnd());
|
|
241
|
+
current = "";
|
|
242
|
+
currentWidth = 0;
|
|
243
|
+
if (/\s/.test(ch)) continue;
|
|
244
|
+
}
|
|
245
|
+
if (!current && /\s/.test(ch)) continue;
|
|
246
|
+
current += ch;
|
|
247
|
+
currentWidth += charWidth;
|
|
235
248
|
}
|
|
236
|
-
|
|
249
|
+
lines.push(current);
|
|
250
|
+
return lines;
|
|
237
251
|
}
|
|
238
252
|
|
|
239
253
|
function renderPlainMarkdownFallback(markdown, width) {
|
|
@@ -5,6 +5,7 @@ The user primarily asks for software engineering work: fixing bugs, adding behav
|
|
|
5
5
|
|
|
6
6
|
<communication_contract>
|
|
7
7
|
- Be concise and direct. Match the response shape to the task; simple questions get simple answers.
|
|
8
|
+
- Keep responses honest, restrained, and professional. Do not flatter, praise performatively, exaggerate approval, or default to agreeing with the user.
|
|
8
9
|
- Assume users may not see tool calls. Before the first tool call, say in one sentence what you are about to do. While working, give brief updates when you find something important, change direction, or hit a blocker.
|
|
9
10
|
- For multi-step work, checkpoint after meaningful milestones: what changed, what was verified, and what remains.
|
|
10
11
|
- Don't narrate hidden reasoning. State decisions, results, and relevant next steps.
|
|
@@ -18,6 +19,7 @@ The user primarily asks for software engineering work: fixing bugs, adding behav
|
|
|
18
19
|
- Distinguish the proposed solution from the underlying problem; restate the problem before accepting the solution when the user brings a design or implementation idea.
|
|
19
20
|
- Surface assumptions and ambiguity before acting. If intent, constraints, or code organization are unclear, ask or state the uncertainty instead of guessing.
|
|
20
21
|
- Challenge weak, over-engineered, or mis-scoped proposals directly and offer 1-2 concrete alternatives.
|
|
22
|
+
- If the user is mistaken, the logic is unclear, or information is insufficient, say so plainly with a brief reason, then offer facts, analysis, or actionable next steps.
|
|
21
23
|
- Ask one focused question at a time; when useful, provide 2-4 distinct options rather than open-ended questionnaires.
|
|
22
24
|
- Keep context use bounded. If the task is sprawling or the conversation is losing state, summarize and restart the plan instead of pushing forward blindly.
|
|
23
25
|
- Do not force discussion when the request is already clear; summarize the decision and move toward the appropriate next step.
|
|
@@ -95,8 +97,10 @@ The user primarily asks for software engineering work: fixing bugs, adding behav
|
|
|
95
97
|
- A recall hint's description may record key operational constraints, including when the full memory must be opened; factor those constraints into relevance before acting.
|
|
96
98
|
- If a recall hint may help the current task, use memory_open(id) to read the full memory before relying on it. Ignore hints that are clearly unrelated or too low-value for the task.
|
|
97
99
|
- Use memory_search(query) for full-text search across all memories.
|
|
98
|
-
- To edit an existing memory, use memory_open(id) to get its path, then edit_file with mode="patch" for targeted edits.
|
|
99
|
-
-
|
|
100
|
+
- To edit an existing memory's body, use memory_open(id) to get its path, then edit_file with mode="patch" for targeted edits.
|
|
101
|
+
- Memory identity is the `id`; local Markdown filenames are id-based storage paths and do not carry title meaning. The user-visible recall/list title comes from frontmatter `name`, not from the filename.
|
|
102
|
+
- When renaming or re-describing an existing memory, update the memory metadata fields (`name`, `description`, `tags`) as metadata, not only the Markdown body heading. Already-injected recall hints in the current prompt may remain stale until the next recall.
|
|
103
|
+
- Use memory_save() to create memories or update whole metadata fields on an existing memory. Before creating a new memory, first search/open related memories and merge updates into an existing memory when they share the same topic, project, or decision thread; prefer modifying the existing memory file over creating a scattered new one. Tags are the primary retrieval key for future recall. Prefer lowercase-kebab-case tags like 'march-cli', 'tooling', 'permissions'.
|
|
100
104
|
- When learning multiple related external workflows or skills, maintain memory as an evolving domain library: start with the specific source name when only one item exists, then rename and rewrite the memory title/description as the scope grows; merge new related learnings into the same memory, preserving each source's unique traits while distilling reusable principles.
|
|
101
105
|
- Distinguish "migrating a Skill to memory" from "learning a Skill": migration preserves the complete Skill folder under memory_root/skills/ and creates a memory entry as its index; that memory should describe what the Skill is for and reference the copied Skill folder path so future recall knows how to use it. Learning only reads and internalizes the Skill's methods, scenarios, and principles into ordinary memory without copying source files. Infer the action from the user's wording, and ask when ambiguous.
|
|
102
106
|
- Unlike recall blocks, this system-core center is always visible in every model call. Only update the center for instructions that must always be followed; use memory for contextual, project-specific, or recall-dependent knowledge.
|
|
@@ -55,15 +55,6 @@ export function generateMemoryId() {
|
|
|
55
55
|
return `mem_${randomUUID().replace(/-/g, "").slice(0, 16)}`;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
export function slugify(value) {
|
|
59
|
-
return String(value ?? "memory")
|
|
60
|
-
.trim()
|
|
61
|
-
.toLowerCase()
|
|
62
|
-
.replace(/[^a-z0-9\u4e00-\u9fff]+/g, "-")
|
|
63
|
-
.replace(/^-+|-+$/g, "")
|
|
64
|
-
.slice(0, 80) || "memory";
|
|
65
|
-
}
|
|
66
|
-
|
|
67
58
|
export function walkMarkdownFiles(root) {
|
|
68
59
|
const out = [];
|
|
69
60
|
if (!existsSync(root)) return out;
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
normalizeText,
|
|
9
9
|
parseMemoryMarkdown,
|
|
10
10
|
quoteFtsTerm,
|
|
11
|
-
slugify,
|
|
12
11
|
walkMarkdownFiles,
|
|
13
12
|
} from "./markdown/markdown-format.mjs";
|
|
14
13
|
import { scoreEntry, toHint } from "./markdown/markdown-recall.mjs";
|
|
@@ -176,7 +175,7 @@ export class MarkdownMemoryStore {
|
|
|
176
175
|
if (!nextDescription) throw new Error("description is required");
|
|
177
176
|
if (!existing && body == null) throw new Error("body is required");
|
|
178
177
|
const nextBody = body ?? (existing ? parseMemoryMarkdown(readFileSync(existing.path, "utf8")).body : "");
|
|
179
|
-
const nextPath = existing?.path ?? this.#newMemoryPath(now,
|
|
178
|
+
const nextPath = existing?.path ?? this.#newMemoryPath(now, nextId);
|
|
180
179
|
mkdirSync(dirname(nextPath), { recursive: true });
|
|
181
180
|
const content = formatMemoryMarkdown({
|
|
182
181
|
frontmatter: {
|
|
@@ -248,11 +247,11 @@ export class MarkdownMemoryStore {
|
|
|
248
247
|
}
|
|
249
248
|
}
|
|
250
249
|
|
|
251
|
-
#newMemoryPath(isoDate,
|
|
250
|
+
#newMemoryPath(isoDate, id) {
|
|
252
251
|
const date = isoDate.slice(0, 10);
|
|
253
252
|
const [year, month, day] = date.split("-");
|
|
254
253
|
const week = `week${Math.ceil(Number(day) / 7)}`;
|
|
255
|
-
return join(this.root, year, month, week, `${date}-${
|
|
254
|
+
return join(this.root, year, month, week, `${date}-${id}.md`);
|
|
256
255
|
}
|
|
257
256
|
|
|
258
257
|
#resolveMemoryPath(raw) {
|
|
@@ -70,7 +70,7 @@ export function createMarkdownMemoryTools(store, { remoteSources = [] } = {}) {
|
|
|
70
70
|
name: "memory_save",
|
|
71
71
|
label: "Memory Save",
|
|
72
72
|
description:
|
|
73
|
-
"Create a Markdown memory or update whole fields on an existing memory. For targeted edits to an existing memory body or frontmatter, use memory_open to get the path, then edit_file. Before creating a new memory, merge related updates into an existing memory when they share the same topic or decision thread. New memories require name, description, body, and at least one tag because recall hints only use tags. When updating by id, omitted fields keep their existing values; passing tags replaces the full tag list.",
|
|
73
|
+
"Create a Markdown memory or update whole fields on an existing memory. Local memory filenames are id-based storage paths; frontmatter name is the user-visible title. For targeted edits to an existing memory body or frontmatter, use memory_open to get the path, then edit_file. Before creating a new memory, merge related updates into an existing memory when they share the same topic or decision thread. New memories require name, description, body, and at least one tag because recall hints only use tags. When updating by id, omitted fields keep their existing values; passing tags replaces the full tag list.",
|
|
74
74
|
parameters: Type.Object({
|
|
75
75
|
id: Type.Optional(Type.String({ description: "Existing memory id to update. Omit to create a new memory." })),
|
|
76
76
|
name: Type.Optional(Type.String({ description: "Memory name. Required when creating." })),
|