markform 0.1.22 → 0.1.24
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/README.md +53 -16
- package/dist/ai-sdk.d.mts +1 -1
- package/dist/ai-sdk.mjs +48 -6
- package/dist/ai-sdk.mjs.map +1 -1
- package/dist/bin.mjs +1 -1
- package/dist/{cli-C8F9yDsv.mjs → cli-B1DhFYBS.mjs} +642 -96
- package/dist/cli-B1DhFYBS.mjs.map +1 -0
- package/dist/cli.d.mts +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/{coreTypes-CTLr-NGd.mjs → coreTypes-CctFK6uE.mjs} +38 -2
- package/dist/coreTypes-CctFK6uE.mjs.map +1 -0
- package/dist/{coreTypes-BlsJkU1w.d.mts → coreTypes-GxzWNXap.d.mts} +137 -3
- package/dist/{fillRecord-DTl5lnK0.d.mts → fillRecord-DeqI2pQ5.d.mts} +25 -1
- package/dist/{fillRecordRenderer-CruJrLkj.mjs → fillRecordRenderer-VBQ2vwPV.mjs} +2 -5
- package/dist/fillRecordRenderer-VBQ2vwPV.mjs.map +1 -0
- package/dist/index.d.mts +52 -29
- package/dist/index.mjs +5 -5
- package/dist/{apply-C7mO7VkZ.mjs → prompts-BCnYaH4_.mjs} +969 -8
- package/dist/prompts-BCnYaH4_.mjs.map +1 -0
- package/dist/render.d.mts +2 -2
- package/dist/render.mjs +1 -1
- package/dist/{session-BCcltrLA.mjs → session-BLjN3BkJ.mjs} +2 -2
- package/dist/{session-BCcltrLA.mjs.map → session-BLjN3BkJ.mjs.map} +1 -1
- package/dist/{session-VeSkVrck.mjs → session-D7C7IlEv.mjs} +1 -1
- package/dist/{shared-CsdT2T7k.mjs → shared-CuSRYcIB.mjs} +3 -3
- package/dist/shared-CuSRYcIB.mjs.map +1 -0
- package/dist/{shared-fb0nkzQi.mjs → shared-DtorFV21.mjs} +1 -1
- package/dist/{src-CbRnGzMK.mjs → src-C5OWf1dL.mjs} +114 -826
- package/dist/src-C5OWf1dL.mjs.map +1 -0
- package/docs/markform-apis.md +6 -0
- package/docs/markform-reference.md +26 -1
- package/docs/markform-spec.md +11 -3
- package/docs/skill/SKILL.md +119 -0
- package/examples/rejection-test/rejection-test.session.yaml +52 -0
- package/examples/simple/simple-with-skips.session.yaml +78 -0
- package/examples/simple/simple.session.yaml +78 -0
- package/package.json +2 -2
- package/dist/apply-C7mO7VkZ.mjs.map +0 -1
- package/dist/cli-C8F9yDsv.mjs.map +0 -1
- package/dist/coreTypes-CTLr-NGd.mjs.map +0 -1
- package/dist/fillRecordRenderer-CruJrLkj.mjs.map +0 -1
- package/dist/shared-CsdT2T7k.mjs.map +0 -1
- package/dist/src-CbRnGzMK.mjs.map +0 -1
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
|
|
2
|
-
import { R as PatchSchema } from "./coreTypes-
|
|
3
|
-
import { $ as
|
|
4
|
-
import { C as
|
|
5
|
-
import { n as serializeSession } from "./session-
|
|
6
|
-
import { _ as writeFile, a as formatPath, c as logError, d as logTiming, f as logVerbose, g as stripHtmlComments, h as shouldUseColors, i as formatOutput, l as logInfo, m as readFile$1, n as createSpinner, o as getCommandContext, p as logWarn, r as ensureFormsDir, s as logDryRun, t as OUTPUT_FORMATS, u as logSuccess } from "./shared-
|
|
7
|
-
import { a as renderJsonContent, c as renderViewContent, i as highlightYamlValue, l as renderYamlContent, o as renderMarkdownContent, r as renderFillRecordContent, s as renderSourceContent, u as escapeHtml } from "./fillRecordRenderer-
|
|
2
|
+
import { R as PatchSchema } from "./coreTypes-CctFK6uE.mjs";
|
|
3
|
+
import { $ as DEFAULT_RESEARCH_MAX_PATCHES_PER_TURN, E as serializeReport, H as AGENT_ROLE, K as DEFAULT_MAX_PATCHES_PER_TURN, Q as DEFAULT_RESEARCH_MAX_ISSUES_PER_TURN, S as computeStructureSummary, T as serializeRawMarkdown, U as DEFAULT_FORMS_DIR, W as DEFAULT_MAX_ISSUES_PER_TURN, X as DEFAULT_PORT, Y as DEFAULT_MAX_TURNS, _ as inspect, _t as parseModelIdForDisplay, at as deriveExportPath, c as filterIssuesByOrder, ct as deriveSchemaPath, d as coerceInputContext, f as coerceToFieldPatch, ft as SUGGESTED_LLMS, gt as hasWebSearchSupport, h as getAllFields, it as USER_ROLE, k as validateSyntaxConsistency, l as filterIssuesByScope, lt as detectFileType, m as applyPatches, mt as formatSuggestedLlms, nt as MAX_FORMS_IN_MENU, ot as deriveFillRecordPath, p as findFieldById, pt as WEB_SEARCH_CONFIG, rt as REPORT_EXTENSION, st as deriveReportPath, u as getFieldIdFromRef, ut as parseRolesFlag, w as serializeForm, x as computeProgressSummary } from "./prompts-BCnYaH4_.mjs";
|
|
4
|
+
import { C as getProviderInfo, D as createLiveAgent, E as buildMockWireFormat, H as parseForm, N as createHarness, O as FillRecordCollector, T as resolveModel, V as formToJsonSchema, _ as resolveHarnessConfig, g as formatFillRecordSummary, h as stripUnstableFillRecordFields, i as runResearch, j as createMockAgent, k as computeExecutionPlan, m as isEmptyFillRecord, n as isResearchForm, t as VERSION, v as fillForm, w as getProviderNames } from "./src-C5OWf1dL.mjs";
|
|
5
|
+
import { n as serializeSession } from "./session-BLjN3BkJ.mjs";
|
|
6
|
+
import { _ as writeFile$1, a as formatPath, c as logError, d as logTiming, f as logVerbose, g as stripHtmlComments, h as shouldUseColors, i as formatOutput, l as logInfo, m as readFile$1, n as createSpinner, o as getCommandContext, p as logWarn, r as ensureFormsDir, s as logDryRun, t as OUTPUT_FORMATS, u as logSuccess } from "./shared-CuSRYcIB.mjs";
|
|
7
|
+
import { a as renderJsonContent, c as renderViewContent, i as highlightYamlValue, l as renderYamlContent, o as renderMarkdownContent, r as renderFillRecordContent, s as renderSourceContent, u as escapeHtml } from "./fillRecordRenderer-VBQ2vwPV.mjs";
|
|
8
8
|
import Markdoc from "@markdoc/markdoc";
|
|
9
9
|
import YAML from "yaml";
|
|
10
10
|
import { Command } from "commander";
|
|
11
11
|
import pc from "picocolors";
|
|
12
12
|
import { exec, execSync, spawn } from "node:child_process";
|
|
13
13
|
import { basename, dirname, join, resolve } from "node:path";
|
|
14
|
-
import { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
15
14
|
import { fileURLToPath } from "node:url";
|
|
16
|
-
import {
|
|
15
|
+
import { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
16
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
17
17
|
import * as p from "@clack/prompts";
|
|
18
18
|
import { createServer } from "node:http";
|
|
19
19
|
|
|
@@ -72,6 +72,21 @@ const CLI_VERSION = VERSION === "development" ? getGitVersion() : VERSION;
|
|
|
72
72
|
* library to remain Node.js-free.
|
|
73
73
|
*/
|
|
74
74
|
/**
|
|
75
|
+
* Resolve a path relative to the package root, handling both dev and dist modes.
|
|
76
|
+
*
|
|
77
|
+
* In dist mode, commands run from `<pkg>/dist/` (1 level below root).
|
|
78
|
+
* In dev mode, commands run from `<pkg>/src/cli/commands/` or `<pkg>/src/cli/examples/`
|
|
79
|
+
* (3 levels below root).
|
|
80
|
+
*
|
|
81
|
+
* @param callerMetaUrl - The `import.meta.url` of the calling module
|
|
82
|
+
* @param relativePath - Path relative to the package root (e.g. 'docs/markform-reference.md')
|
|
83
|
+
*/
|
|
84
|
+
function resolvePackagePath(callerMetaUrl, relativePath) {
|
|
85
|
+
const thisDir = dirname(fileURLToPath(callerMetaUrl));
|
|
86
|
+
if (thisDir.split(/[/\\]/).pop() === "dist") return join(dirname(thisDir), relativePath);
|
|
87
|
+
return join(dirname(dirname(dirname(thisDir))), relativePath);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
75
90
|
* Resolve the forms directory path to an absolute path.
|
|
76
91
|
* Uses the provided override or falls back to DEFAULT_FORMS_DIR.
|
|
77
92
|
*
|
|
@@ -86,19 +101,10 @@ function getFormsDir(override, cwd = process.cwd()) {
|
|
|
86
101
|
//#endregion
|
|
87
102
|
//#region src/cli/commands/apis.ts
|
|
88
103
|
/**
|
|
89
|
-
* Get the path to the markform-apis.md file.
|
|
90
|
-
* Works both during development and when installed as a package.
|
|
91
|
-
*/
|
|
92
|
-
function getApisPath() {
|
|
93
|
-
const thisDir = dirname(fileURLToPath(import.meta.url));
|
|
94
|
-
if (thisDir.split(/[/\\]/).pop() === "dist") return join(dirname(thisDir), "docs", "markform-apis.md");
|
|
95
|
-
return join(dirname(dirname(dirname(thisDir))), "docs", "markform-apis.md");
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
104
|
* Load the APIs documentation content.
|
|
99
105
|
*/
|
|
100
106
|
function loadApis() {
|
|
101
|
-
const apisPath =
|
|
107
|
+
const apisPath = resolvePackagePath(import.meta.url, "docs/markform-apis.md");
|
|
102
108
|
try {
|
|
103
109
|
return readFileSync(apisPath, "utf-8");
|
|
104
110
|
} catch (error) {
|
|
@@ -178,7 +184,7 @@ function registerApisCommand(program) {
|
|
|
178
184
|
}
|
|
179
185
|
|
|
180
186
|
//#endregion
|
|
181
|
-
//#region src/cli/commands/
|
|
187
|
+
//#region src/cli/commands/patch.ts
|
|
182
188
|
/**
|
|
183
189
|
* Format state badge for console output.
|
|
184
190
|
*/
|
|
@@ -192,16 +198,16 @@ function formatState$2(state, useColors) {
|
|
|
192
198
|
return useColors ? colorFn(text) : text;
|
|
193
199
|
}
|
|
194
200
|
/**
|
|
195
|
-
* Format
|
|
201
|
+
* Format patch report for console output.
|
|
196
202
|
*/
|
|
197
|
-
function formatConsoleReport$
|
|
203
|
+
function formatConsoleReport$5(report, useColors) {
|
|
198
204
|
const lines = [];
|
|
199
205
|
const bold = useColors ? pc.bold : (s) => s;
|
|
200
206
|
const dim = useColors ? pc.dim : (s) => s;
|
|
201
207
|
const cyan = useColors ? pc.cyan : (s) => s;
|
|
202
208
|
const green = useColors ? pc.green : (s) => s;
|
|
203
209
|
const red = useColors ? pc.red : (s) => s;
|
|
204
|
-
lines.push(bold(cyan("
|
|
210
|
+
lines.push(bold(cyan("Patch Result")));
|
|
205
211
|
lines.push("");
|
|
206
212
|
const statusColor = report.apply_status === "applied" ? green : red;
|
|
207
213
|
lines.push(`${bold("Status:")} ${statusColor(report.apply_status)}`);
|
|
@@ -225,16 +231,12 @@ function formatConsoleReport$3(report, useColors) {
|
|
|
225
231
|
return lines.join("\n");
|
|
226
232
|
}
|
|
227
233
|
/**
|
|
228
|
-
* Register the
|
|
234
|
+
* Register the patch command.
|
|
229
235
|
*/
|
|
230
|
-
function
|
|
231
|
-
program.command("
|
|
236
|
+
function registerPatchCommand(program) {
|
|
237
|
+
program.command("patch <file> <json>").description("Apply raw typed patches to a form").option("-o, --output <file>", "Output file (defaults to stdout)").option("--report", "Output patch result report instead of modified form").option("--normalize", "Regenerate form without preserving external content").action(async (file, json, options, cmd) => {
|
|
232
238
|
const ctx = getCommandContext(cmd);
|
|
233
239
|
try {
|
|
234
|
-
if (!options.patch) {
|
|
235
|
-
logError("--patch option is required");
|
|
236
|
-
process.exit(1);
|
|
237
|
-
}
|
|
238
240
|
logVerbose(ctx, `Reading file: ${file}`);
|
|
239
241
|
const content = await readFile$1(file);
|
|
240
242
|
logVerbose(ctx, "Parsing form...");
|
|
@@ -242,13 +244,13 @@ function registerApplyCommand(program) {
|
|
|
242
244
|
logVerbose(ctx, "Parsing patches...");
|
|
243
245
|
let parsedJson;
|
|
244
246
|
try {
|
|
245
|
-
parsedJson = JSON.parse(
|
|
247
|
+
parsedJson = JSON.parse(json);
|
|
246
248
|
} catch {
|
|
247
|
-
logError("Invalid JSON in
|
|
249
|
+
logError("Invalid JSON in patch argument");
|
|
248
250
|
process.exit(1);
|
|
249
251
|
}
|
|
250
252
|
if (!Array.isArray(parsedJson)) {
|
|
251
|
-
logError("
|
|
253
|
+
logError("Patch argument must be a JSON array");
|
|
252
254
|
process.exit(1);
|
|
253
255
|
}
|
|
254
256
|
const patches = parsedJson;
|
|
@@ -276,7 +278,7 @@ function registerApplyCommand(program) {
|
|
|
276
278
|
structure: result.structureSummary,
|
|
277
279
|
progress: result.progressSummary,
|
|
278
280
|
issues: result.issues
|
|
279
|
-
}, (data, useColors) => formatConsoleReport$
|
|
281
|
+
}, (data, useColors) => formatConsoleReport$5(data, useColors));
|
|
280
282
|
console.error(output);
|
|
281
283
|
process.exit(1);
|
|
282
284
|
}
|
|
@@ -288,15 +290,15 @@ function registerApplyCommand(program) {
|
|
|
288
290
|
structure: result.structureSummary,
|
|
289
291
|
progress: result.progressSummary,
|
|
290
292
|
issues: result.issues
|
|
291
|
-
}, (data, useColors) => formatConsoleReport$
|
|
293
|
+
}, (data, useColors) => formatConsoleReport$5(data, useColors));
|
|
292
294
|
if (options.output) {
|
|
293
|
-
await writeFile(options.output, output);
|
|
295
|
+
await writeFile$1(options.output, output);
|
|
294
296
|
logSuccess(ctx, `Report written to ${options.output}`);
|
|
295
297
|
} else console.log(output);
|
|
296
298
|
} else {
|
|
297
299
|
const output = serializeForm(form, { preserveContent: !options.normalize });
|
|
298
300
|
if (options.output) {
|
|
299
|
-
await writeFile(options.output, output);
|
|
301
|
+
await writeFile$1(options.output, output);
|
|
300
302
|
logSuccess(ctx, `Modified form written to ${options.output}`);
|
|
301
303
|
} else console.log(output);
|
|
302
304
|
}
|
|
@@ -670,19 +672,10 @@ function registerBrowseCommand(program) {
|
|
|
670
672
|
//#endregion
|
|
671
673
|
//#region src/cli/commands/docs.ts
|
|
672
674
|
/**
|
|
673
|
-
* Get the path to the markform-reference.md file.
|
|
674
|
-
* Works both during development and when installed as a package.
|
|
675
|
-
*/
|
|
676
|
-
function getDocsPath() {
|
|
677
|
-
const thisDir = dirname(fileURLToPath(import.meta.url));
|
|
678
|
-
if (thisDir.split(/[/\\]/).pop() === "dist") return join(dirname(thisDir), "docs", "markform-reference.md");
|
|
679
|
-
return join(dirname(dirname(dirname(thisDir))), "docs", "markform-reference.md");
|
|
680
|
-
}
|
|
681
|
-
/**
|
|
682
675
|
* Load the docs content.
|
|
683
676
|
*/
|
|
684
677
|
function loadDocs() {
|
|
685
|
-
const docsPath =
|
|
678
|
+
const docsPath = resolvePackagePath(import.meta.url, "docs/markform-reference.md");
|
|
686
679
|
try {
|
|
687
680
|
return readFileSync(docsPath, "utf-8");
|
|
688
681
|
} catch (error) {
|
|
@@ -909,7 +902,7 @@ function deriveExportPaths(basePath) {
|
|
|
909
902
|
async function exportMultiFormat(form, basePath) {
|
|
910
903
|
const paths = deriveExportPaths(basePath);
|
|
911
904
|
const reportContent = serializeReport(form);
|
|
912
|
-
await writeFile(paths.reportPath, reportContent);
|
|
905
|
+
await writeFile$1(paths.reportPath, reportContent);
|
|
913
906
|
const values = toStructuredValues(form);
|
|
914
907
|
const notes = toNotesArray(form);
|
|
915
908
|
const exportData = {
|
|
@@ -917,12 +910,12 @@ async function exportMultiFormat(form, basePath) {
|
|
|
917
910
|
...notes.length > 0 && { notes }
|
|
918
911
|
};
|
|
919
912
|
const yamlContent = YAML.stringify(exportData);
|
|
920
|
-
await writeFile(paths.yamlPath, yamlContent);
|
|
913
|
+
await writeFile$1(paths.yamlPath, yamlContent);
|
|
921
914
|
const formContent = serializeForm(form);
|
|
922
|
-
await writeFile(paths.formPath, formContent);
|
|
915
|
+
await writeFile$1(paths.formPath, formContent);
|
|
923
916
|
const schemaResult = formToJsonSchema(form);
|
|
924
917
|
const schemaContent = JSON.stringify(schemaResult.schema, null, 2) + "\n";
|
|
925
|
-
await writeFile(paths.schemaPath, schemaContent);
|
|
918
|
+
await writeFile$1(paths.schemaPath, schemaContent);
|
|
926
919
|
return paths;
|
|
927
920
|
}
|
|
928
921
|
|
|
@@ -1061,9 +1054,7 @@ function getExampleOrder(filename) {
|
|
|
1061
1054
|
* Works both during development and when installed as a package.
|
|
1062
1055
|
*/
|
|
1063
1056
|
function getExamplesDir() {
|
|
1064
|
-
|
|
1065
|
-
if (thisDir.split(/[/\\]/).pop() === "dist") return join(dirname(thisDir), "examples");
|
|
1066
|
-
return join(dirname(dirname(dirname(thisDir))), "examples");
|
|
1057
|
+
return resolvePackagePath(import.meta.url, "examples");
|
|
1067
1058
|
}
|
|
1068
1059
|
/**
|
|
1069
1060
|
* Load the content of an example form.
|
|
@@ -1967,6 +1958,12 @@ function formatPatchValue(patch) {
|
|
|
1967
1958
|
const rowCount = patch.value?.length ?? 0;
|
|
1968
1959
|
return rowCount > 0 ? truncate(`[${rowCount} rows]`) : "(empty)";
|
|
1969
1960
|
}
|
|
1961
|
+
case "append_table": return truncate(`+[${patch.value?.length ?? 0} rows]`);
|
|
1962
|
+
case "delete_table": return `(delete row ${patch.value})`;
|
|
1963
|
+
case "append_string_list": return truncate(`+[${patch.value.join(", ")}]`);
|
|
1964
|
+
case "delete_string_list": return `(delete item ${patch.value})`;
|
|
1965
|
+
case "append_url_list": return truncate(`+[${patch.value.join(", ")}]`);
|
|
1966
|
+
case "delete_url_list": return `(delete item ${patch.value})`;
|
|
1970
1967
|
case "add_note": return truncate(`note: ${patch.text}`);
|
|
1971
1968
|
case "remove_note": return `(remove note ${patch.noteId})`;
|
|
1972
1969
|
}
|
|
@@ -1990,6 +1987,12 @@ function formatPatchType(patch) {
|
|
|
1990
1987
|
case "set_date": return "date";
|
|
1991
1988
|
case "set_year": return "year";
|
|
1992
1989
|
case "set_table": return "table";
|
|
1990
|
+
case "append_table": return "append_table";
|
|
1991
|
+
case "delete_table": return "delete_table";
|
|
1992
|
+
case "append_string_list": return "append_string_list";
|
|
1993
|
+
case "delete_string_list": return "delete_string_list";
|
|
1994
|
+
case "append_url_list": return "append_url_list";
|
|
1995
|
+
case "delete_url_list": return "delete_url_list";
|
|
1993
1996
|
case "add_note": return "note";
|
|
1994
1997
|
case "remove_note": return "remove_note";
|
|
1995
1998
|
}
|
|
@@ -2462,7 +2465,7 @@ async function copyExample(exampleId, formsDir, overwrite, _quiet) {
|
|
|
2462
2465
|
path: outputPath
|
|
2463
2466
|
};
|
|
2464
2467
|
}
|
|
2465
|
-
await writeFile(outputPath, loadExampleContent(exampleId));
|
|
2468
|
+
await writeFile$1(outputPath, loadExampleContent(exampleId));
|
|
2466
2469
|
return {
|
|
2467
2470
|
copied: true,
|
|
2468
2471
|
skipped: false,
|
|
@@ -2920,7 +2923,7 @@ function registerFillCommand(program) {
|
|
|
2920
2923
|
logTiming(ctx, "Fill time", durationMs);
|
|
2921
2924
|
if (ctx.dryRun) logInfo(ctx, `[DRY RUN] Would write form to: ${outputPath}`);
|
|
2922
2925
|
else {
|
|
2923
|
-
await writeFile(outputPath, result.markdown);
|
|
2926
|
+
await writeFile$1(outputPath, result.markdown);
|
|
2924
2927
|
logSuccess(ctx, `Form written to: ${outputPath}`);
|
|
2925
2928
|
}
|
|
2926
2929
|
if (result.record && !ctx.quiet) {
|
|
@@ -2928,7 +2931,8 @@ function registerFillCommand(program) {
|
|
|
2928
2931
|
const summary = formatFillRecordSummary(result.record, { verbose: ctx.verbose });
|
|
2929
2932
|
console.error(summary);
|
|
2930
2933
|
}
|
|
2931
|
-
if ((options.recordFill || options.recordFillStable) && result.record)
|
|
2934
|
+
if ((options.recordFill || options.recordFillStable) && result.record) if (isEmptyFillRecord(result.record)) logVerbose(ctx, "Skipping fill record: no turns were executed");
|
|
2935
|
+
else {
|
|
2932
2936
|
const sidecarPath = deriveFillRecordPath(outputPath);
|
|
2933
2937
|
const recordToWrite = options.recordFillStable ? stripUnstableFillRecordFields(result.record) : result.record;
|
|
2934
2938
|
if (ctx.dryRun) logInfo(ctx, `[DRY RUN] Would write fill record to: ${sidecarPath}`);
|
|
@@ -3142,6 +3146,7 @@ function registerFillCommand(program) {
|
|
|
3142
3146
|
requiredIssuesRemaining: stepResult.issues.filter((i) => i.severity === "required").length,
|
|
3143
3147
|
isComplete: stepResult.isComplete,
|
|
3144
3148
|
rejectedPatches,
|
|
3149
|
+
coercionWarnings: stepResult.coercionWarnings,
|
|
3145
3150
|
issues: stepResult.issues,
|
|
3146
3151
|
patches
|
|
3147
3152
|
});
|
|
@@ -3172,7 +3177,7 @@ function registerFillCommand(program) {
|
|
|
3172
3177
|
const formMarkdown = serializeForm(harness.getForm(), { preserveContent: !options.normalize });
|
|
3173
3178
|
if (ctx.dryRun) logInfo(ctx, `[DRY RUN] Would write form to: ${outputPath}`);
|
|
3174
3179
|
else {
|
|
3175
|
-
await writeFile(outputPath, formMarkdown);
|
|
3180
|
+
await writeFile$1(outputPath, formMarkdown);
|
|
3176
3181
|
logSuccess(ctx, `Form written to: ${outputPath}`);
|
|
3177
3182
|
}
|
|
3178
3183
|
const finalInspect = inspect(harness.getForm(), { targetRoles });
|
|
@@ -3184,7 +3189,8 @@ function registerFillCommand(program) {
|
|
|
3184
3189
|
const summary = formatFillRecordSummary(fillRecord, { verbose: ctx.verbose });
|
|
3185
3190
|
console.error(summary);
|
|
3186
3191
|
}
|
|
3187
|
-
if (options.recordFill || options.recordFillStable)
|
|
3192
|
+
if (options.recordFill || options.recordFillStable) if (isEmptyFillRecord(fillRecord)) logVerbose(ctx, "Skipping fill record: no turns were executed");
|
|
3193
|
+
else {
|
|
3188
3194
|
const sidecarPath = deriveFillRecordPath(outputPath);
|
|
3189
3195
|
const recordToWrite = options.recordFillStable ? stripUnstableFillRecordFields(fillRecord) : fillRecord;
|
|
3190
3196
|
if (ctx.dryRun) logInfo(ctx, `[DRY RUN] Would write fill record to: ${sidecarPath}`);
|
|
@@ -3201,7 +3207,7 @@ function registerFillCommand(program) {
|
|
|
3201
3207
|
logInfo(ctx, `[DRY RUN] Would write session to: ${recordPath}`);
|
|
3202
3208
|
console.log(yaml);
|
|
3203
3209
|
} else {
|
|
3204
|
-
await writeFile(recordPath, yaml);
|
|
3210
|
+
await writeFile$1(recordPath, yaml);
|
|
3205
3211
|
logSuccess(ctx, `Session recorded to: ${recordPath}`);
|
|
3206
3212
|
}
|
|
3207
3213
|
} else if (!ctx.quiet) {
|
|
@@ -3218,10 +3224,12 @@ function registerFillCommand(program) {
|
|
|
3218
3224
|
const progressSummary = computeProgressSummary(form.schema, currentForm.responsesByFieldId, currentForm.notes, finalInspect.issues);
|
|
3219
3225
|
collector.setStatus("failed", message);
|
|
3220
3226
|
const fillRecord = collector.getRecord(progressSummary.counts);
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3227
|
+
if (!isEmptyFillRecord(fillRecord)) {
|
|
3228
|
+
const sidecarPath = deriveFillRecordPath(resolve(options.output));
|
|
3229
|
+
const recordToWrite = options.recordFillStable ? stripUnstableFillRecordFields(fillRecord) : fillRecord;
|
|
3230
|
+
writeFileSync(sidecarPath, JSON.stringify(recordToWrite, null, 2));
|
|
3231
|
+
logWarn(ctx, `Partial fill record written to: ${sidecarPath}`);
|
|
3232
|
+
}
|
|
3225
3233
|
} catch {}
|
|
3226
3234
|
process.exit(1);
|
|
3227
3235
|
}
|
|
@@ -3336,7 +3344,7 @@ function formatFieldValue(value, useColors) {
|
|
|
3336
3344
|
/**
|
|
3337
3345
|
* Format inspect report for console output.
|
|
3338
3346
|
*/
|
|
3339
|
-
function formatConsoleReport$
|
|
3347
|
+
function formatConsoleReport$4(report, useColors) {
|
|
3340
3348
|
const lines = [];
|
|
3341
3349
|
const bold = useColors ? pc.bold : (s) => s;
|
|
3342
3350
|
const dim = useColors ? pc.dim : (s) => s;
|
|
@@ -3449,7 +3457,7 @@ function registerInspectCommand(program) {
|
|
|
3449
3457
|
severity: issue.severity,
|
|
3450
3458
|
blockedBy: issue.blockedBy
|
|
3451
3459
|
}))
|
|
3452
|
-
}, (data, useColors) => formatConsoleReport$
|
|
3460
|
+
}, (data, useColors) => formatConsoleReport$4(data, useColors));
|
|
3453
3461
|
console.log(output);
|
|
3454
3462
|
} catch (error) {
|
|
3455
3463
|
logError(error instanceof Error ? error.message : String(error));
|
|
@@ -3461,19 +3469,10 @@ function registerInspectCommand(program) {
|
|
|
3461
3469
|
//#endregion
|
|
3462
3470
|
//#region src/cli/commands/readme.ts
|
|
3463
3471
|
/**
|
|
3464
|
-
* Get the path to the README.md file.
|
|
3465
|
-
* Works both during development and when installed as a package.
|
|
3466
|
-
*/
|
|
3467
|
-
function getReadmePath() {
|
|
3468
|
-
const thisDir = dirname(fileURLToPath(import.meta.url));
|
|
3469
|
-
if (thisDir.split(/[/\\]/).pop() === "dist") return join(dirname(thisDir), "README.md");
|
|
3470
|
-
return join(dirname(dirname(dirname(thisDir))), "README.md");
|
|
3471
|
-
}
|
|
3472
|
-
/**
|
|
3473
3472
|
* Load the README content.
|
|
3474
3473
|
*/
|
|
3475
3474
|
function loadReadme() {
|
|
3476
|
-
const readmePath =
|
|
3475
|
+
const readmePath = resolvePackagePath(import.meta.url, "README.md");
|
|
3477
3476
|
try {
|
|
3478
3477
|
return readFileSync(readmePath, "utf-8");
|
|
3479
3478
|
} catch (error) {
|
|
@@ -3570,7 +3569,7 @@ function registerReportCommand(program) {
|
|
|
3570
3569
|
if (options.output) {
|
|
3571
3570
|
let outputPath = options.output;
|
|
3572
3571
|
if (!outputPath.endsWith(REPORT_EXTENSION) && !outputPath.endsWith(".md")) outputPath = outputPath + REPORT_EXTENSION;
|
|
3573
|
-
await writeFile(outputPath, reportContent);
|
|
3572
|
+
await writeFile$1(outputPath, reportContent);
|
|
3574
3573
|
logVerbose(ctx, `Report written to: ${outputPath}`);
|
|
3575
3574
|
} else console.log(reportContent);
|
|
3576
3575
|
} catch (error) {
|
|
@@ -3583,19 +3582,10 @@ function registerReportCommand(program) {
|
|
|
3583
3582
|
//#endregion
|
|
3584
3583
|
//#region src/cli/commands/spec.ts
|
|
3585
3584
|
/**
|
|
3586
|
-
* Get the path to the markform-spec.md file.
|
|
3587
|
-
* Works both during development and when installed as a package.
|
|
3588
|
-
*/
|
|
3589
|
-
function getSpecPath() {
|
|
3590
|
-
const thisDir = dirname(fileURLToPath(import.meta.url));
|
|
3591
|
-
if (thisDir.split(/[/\\]/).pop() === "dist") return join(dirname(thisDir), "docs", "markform-spec.md");
|
|
3592
|
-
return join(dirname(dirname(dirname(thisDir))), "docs", "markform-spec.md");
|
|
3593
|
-
}
|
|
3594
|
-
/**
|
|
3595
3585
|
* Load the spec content.
|
|
3596
3586
|
*/
|
|
3597
3587
|
function loadSpec() {
|
|
3598
|
-
const specPath =
|
|
3588
|
+
const specPath = resolvePackagePath(import.meta.url, "docs/markform-spec.md");
|
|
3599
3589
|
try {
|
|
3600
3590
|
return readFileSync(specPath, "utf-8");
|
|
3601
3591
|
} catch (error) {
|
|
@@ -3727,6 +3717,201 @@ function registerModelsCommand(program) {
|
|
|
3727
3717
|
});
|
|
3728
3718
|
}
|
|
3729
3719
|
|
|
3720
|
+
//#endregion
|
|
3721
|
+
//#region src/cli/commands/next.ts
|
|
3722
|
+
/**
|
|
3723
|
+
* Build field metadata for an issue's field.
|
|
3724
|
+
*/
|
|
3725
|
+
function buildFieldMeta(field) {
|
|
3726
|
+
const meta = {
|
|
3727
|
+
kind: field.kind,
|
|
3728
|
+
label: field.label,
|
|
3729
|
+
required: field.required
|
|
3730
|
+
};
|
|
3731
|
+
if (field.kind === "single_select" || field.kind === "multi_select") meta.options = field.options.map((o) => o.id);
|
|
3732
|
+
else if (field.kind === "checkboxes") {
|
|
3733
|
+
meta.options = field.options.map((o) => o.id);
|
|
3734
|
+
meta.checkbox_mode = field.checkboxMode;
|
|
3735
|
+
} else if (field.kind === "table") {
|
|
3736
|
+
meta.columns = field.columns.map((c) => ({
|
|
3737
|
+
id: c.id,
|
|
3738
|
+
type: c.type,
|
|
3739
|
+
required: c.required
|
|
3740
|
+
}));
|
|
3741
|
+
if (field.minRows !== void 0) meta.min_rows = field.minRows;
|
|
3742
|
+
if (field.maxRows !== void 0) meta.max_rows = field.maxRows;
|
|
3743
|
+
}
|
|
3744
|
+
return meta;
|
|
3745
|
+
}
|
|
3746
|
+
/**
|
|
3747
|
+
* Generate a concrete `markform set` example for a field.
|
|
3748
|
+
*/
|
|
3749
|
+
function generateSetExample(file, field) {
|
|
3750
|
+
const base = `markform set ${file} ${field.id}`;
|
|
3751
|
+
switch (field.kind) {
|
|
3752
|
+
case "string": return `${base} "example text"`;
|
|
3753
|
+
case "number": return `${base} 42`;
|
|
3754
|
+
case "string_list": return `${base} '["item1", "item2"]'`;
|
|
3755
|
+
case "single_select": return field.options.length > 0 ? `${base} ${field.options[0].id}` : `${base} option_id`;
|
|
3756
|
+
case "multi_select": return field.options.length > 0 ? `${base} '["${field.options.map((o) => o.id).join("\", \"")}"]'` : `${base} '["option1"]'`;
|
|
3757
|
+
case "checkboxes":
|
|
3758
|
+
if (field.checkboxMode === "simple") return `${base} '${JSON.stringify(Object.fromEntries(field.options.map((o) => [o.id, true])))}'`;
|
|
3759
|
+
return `${base} '${JSON.stringify(Object.fromEntries(field.options.map((o) => [o.id, "done"])))}'`;
|
|
3760
|
+
case "url": return `${base} "https://example.com"`;
|
|
3761
|
+
case "url_list": return `${base} '["https://example.com"]'`;
|
|
3762
|
+
case "date": return `${base} "2024-01-15"`;
|
|
3763
|
+
case "year": return `${base} 2024`;
|
|
3764
|
+
case "table":
|
|
3765
|
+
if (field.columns.length > 0) {
|
|
3766
|
+
const example = Object.fromEntries(field.columns.map((c) => [c.id, `example_${c.type}`]));
|
|
3767
|
+
return `${base} --append '${JSON.stringify(example)}'`;
|
|
3768
|
+
}
|
|
3769
|
+
return `${base} --append '{}'`;
|
|
3770
|
+
}
|
|
3771
|
+
}
|
|
3772
|
+
/**
|
|
3773
|
+
* Generate a skip example for optional fields, or null for required fields.
|
|
3774
|
+
*/
|
|
3775
|
+
function generateSkipExample(file, fieldId, required) {
|
|
3776
|
+
if (required) return null;
|
|
3777
|
+
return `markform set ${file} ${fieldId} --skip --reason "Not applicable"`;
|
|
3778
|
+
}
|
|
3779
|
+
/**
|
|
3780
|
+
* Convert a FieldValue to a serializable current_value for the report.
|
|
3781
|
+
*/
|
|
3782
|
+
function serializeCurrentValue(value) {
|
|
3783
|
+
switch (value.kind) {
|
|
3784
|
+
case "string":
|
|
3785
|
+
case "url":
|
|
3786
|
+
case "date": return value.value;
|
|
3787
|
+
case "number":
|
|
3788
|
+
case "year": return value.value;
|
|
3789
|
+
case "string_list":
|
|
3790
|
+
case "url_list": return value.items;
|
|
3791
|
+
case "single_select": return value.selected;
|
|
3792
|
+
case "multi_select": return value.selected;
|
|
3793
|
+
case "checkboxes": return value.values;
|
|
3794
|
+
case "table": return value.rows;
|
|
3795
|
+
}
|
|
3796
|
+
}
|
|
3797
|
+
/**
|
|
3798
|
+
* Enrich an InspectIssue into a NextIssue with field metadata and examples.
|
|
3799
|
+
*/
|
|
3800
|
+
function enrichIssue(issue, form, file) {
|
|
3801
|
+
const fieldId = getFieldIdFromRef(issue.ref, issue.scope);
|
|
3802
|
+
const field = fieldId ? findFieldById(form, fieldId) : void 0;
|
|
3803
|
+
const enriched = {
|
|
3804
|
+
ref: issue.ref,
|
|
3805
|
+
scope: issue.scope,
|
|
3806
|
+
reason: issue.reason,
|
|
3807
|
+
message: issue.message,
|
|
3808
|
+
severity: issue.severity,
|
|
3809
|
+
priority: issue.priority,
|
|
3810
|
+
set_example: field ? generateSetExample(file, field) : `markform set ${file} ${issue.ref} "value"`,
|
|
3811
|
+
skip_example: field ? generateSkipExample(file, field.id, field.required) : null
|
|
3812
|
+
};
|
|
3813
|
+
if (field) {
|
|
3814
|
+
enriched.field = buildFieldMeta(field);
|
|
3815
|
+
const response = form.responsesByFieldId[field.id];
|
|
3816
|
+
if (response?.state === "answered" && response.value) enriched.current_value = serializeCurrentValue(response.value);
|
|
3817
|
+
}
|
|
3818
|
+
return enriched;
|
|
3819
|
+
}
|
|
3820
|
+
/**
|
|
3821
|
+
* Format next report for console output.
|
|
3822
|
+
*/
|
|
3823
|
+
function formatConsoleReport$3(report, useColors) {
|
|
3824
|
+
const lines = [];
|
|
3825
|
+
const bold = useColors ? pc.bold : (s) => s;
|
|
3826
|
+
const dim = useColors ? pc.dim : (s) => s;
|
|
3827
|
+
const cyan = useColors ? pc.cyan : (s) => s;
|
|
3828
|
+
const green = useColors ? pc.green : (s) => s;
|
|
3829
|
+
const yellow = useColors ? pc.yellow : (s) => s;
|
|
3830
|
+
const red = useColors ? pc.red : (s) => s;
|
|
3831
|
+
const stateColor = report.form_state === "complete" ? green : report.form_state === "invalid" ? red : yellow;
|
|
3832
|
+
const progressStr = `${report.progress.filled_fields}/${report.progress.total_fields} fields filled, ${report.progress.empty_required_fields} required remaining`;
|
|
3833
|
+
lines.push(`${bold("State:")} ${stateColor(report.form_state)} ${dim(`(${progressStr})`)}`);
|
|
3834
|
+
if (report.is_complete) {
|
|
3835
|
+
lines.push("");
|
|
3836
|
+
lines.push(green(bold("Form is complete!")));
|
|
3837
|
+
return lines.join("\n");
|
|
3838
|
+
}
|
|
3839
|
+
lines.push("");
|
|
3840
|
+
lines.push(bold(`Next fields to fill (${report.issues.length} issues, budget: ${report.step_budget}):`));
|
|
3841
|
+
lines.push("");
|
|
3842
|
+
for (const issue of report.issues) {
|
|
3843
|
+
const prioLabel = `P${issue.priority}`;
|
|
3844
|
+
const prioColor = issue.priority <= 1 ? red : issue.priority <= 2 ? yellow : cyan;
|
|
3845
|
+
const sevLabel = issue.severity === "required" ? "required" : "recommended";
|
|
3846
|
+
const kindStr = issue.field ? ` ${dim(`(${issue.field.kind})`)}` : "";
|
|
3847
|
+
let optionsStr = "";
|
|
3848
|
+
if (issue.field?.options && issue.field.options.length > 0) optionsStr = ` ${dim(`[${issue.field.options.join(", ")}]`)}`;
|
|
3849
|
+
lines.push(` ${prioColor(prioLabel)} ${dim(`[${sevLabel}]`)} ${bold(issue.ref)}${kindStr}${optionsStr}`);
|
|
3850
|
+
lines.push(` ${issue.message}`);
|
|
3851
|
+
lines.push(` ${dim("->")} ${cyan(issue.set_example)}`);
|
|
3852
|
+
if (issue.skip_example) lines.push(` ${dim("->")} ${dim(issue.skip_example)}`);
|
|
3853
|
+
lines.push("");
|
|
3854
|
+
}
|
|
3855
|
+
return lines.join("\n").trimEnd();
|
|
3856
|
+
}
|
|
3857
|
+
const DEFAULT_MAX_ISSUES = 10;
|
|
3858
|
+
/**
|
|
3859
|
+
* Register the next command.
|
|
3860
|
+
*/
|
|
3861
|
+
function registerNextCommand(program) {
|
|
3862
|
+
program.command("next <file>").description("Show prioritized next fields to fill (field advisor for CLI form filling)").option("--roles <roles>", "Target roles (comma-separated, or '*' for all; default: all)").option("--max-fields <n>", "Max distinct fields per batch").option("--max-groups <n>", "Max distinct groups per batch").option("--max-issues <n>", `Max issues to return (default: ${DEFAULT_MAX_ISSUES})`).action(async (file, options, cmd) => {
|
|
3863
|
+
const ctx = getCommandContext(cmd);
|
|
3864
|
+
try {
|
|
3865
|
+
let targetRoles;
|
|
3866
|
+
if (options.roles) try {
|
|
3867
|
+
targetRoles = parseRolesFlag(options.roles);
|
|
3868
|
+
if (targetRoles.includes("*")) targetRoles = void 0;
|
|
3869
|
+
} catch (error) {
|
|
3870
|
+
logError(`Invalid --roles: ${error instanceof Error ? error.message : String(error)}`);
|
|
3871
|
+
process.exit(1);
|
|
3872
|
+
}
|
|
3873
|
+
const maxFields = options.maxFields ? parseInt(options.maxFields, 10) : void 0;
|
|
3874
|
+
const maxGroups = options.maxGroups ? parseInt(options.maxGroups, 10) : void 0;
|
|
3875
|
+
const maxIssuesParsed = options.maxIssues ? parseInt(options.maxIssues, 10) : void 0;
|
|
3876
|
+
if (maxFields !== void 0 && isNaN(maxFields) || maxGroups !== void 0 && isNaN(maxGroups) || maxIssuesParsed !== void 0 && isNaN(maxIssuesParsed)) {
|
|
3877
|
+
logError("--max-fields, --max-groups, and --max-issues must be numeric");
|
|
3878
|
+
process.exit(1);
|
|
3879
|
+
}
|
|
3880
|
+
logVerbose(ctx, `Reading file: ${file}`);
|
|
3881
|
+
const content = await readFile$1(file);
|
|
3882
|
+
logVerbose(ctx, "Parsing form...");
|
|
3883
|
+
const form = parseForm(content);
|
|
3884
|
+
const harnessConfig = form.metadata?.harnessConfig;
|
|
3885
|
+
const effectiveMaxIssues = maxIssuesParsed ?? harnessConfig?.maxIssuesPerTurn ?? DEFAULT_MAX_ISSUES;
|
|
3886
|
+
const effectiveMaxFields = maxFields ?? void 0;
|
|
3887
|
+
const effectiveMaxGroups = maxGroups ?? void 0;
|
|
3888
|
+
logVerbose(ctx, "Running inspection...");
|
|
3889
|
+
const result = inspect(form, { targetRoles });
|
|
3890
|
+
const limitedIssues = filterIssuesByScope(filterIssuesByOrder(result.issues, form), form, effectiveMaxFields, effectiveMaxGroups).slice(0, effectiveMaxIssues);
|
|
3891
|
+
const maxPatches = harnessConfig?.maxPatchesPerTurn ?? limitedIssues.length;
|
|
3892
|
+
const stepBudget = Math.min(maxPatches, limitedIssues.length);
|
|
3893
|
+
const enrichedIssues = limitedIssues.map((issue) => enrichIssue(issue, form, file));
|
|
3894
|
+
const counts = result.progressSummary.counts;
|
|
3895
|
+
const output = formatOutput(ctx, {
|
|
3896
|
+
is_complete: result.isComplete,
|
|
3897
|
+
form_state: result.formState,
|
|
3898
|
+
step_budget: stepBudget,
|
|
3899
|
+
progress: {
|
|
3900
|
+
total_fields: counts.totalFields,
|
|
3901
|
+
required_fields: counts.requiredFields,
|
|
3902
|
+
filled_fields: counts.filledFields,
|
|
3903
|
+
empty_required_fields: counts.emptyRequiredFields
|
|
3904
|
+
},
|
|
3905
|
+
issues: enrichedIssues
|
|
3906
|
+
}, (data, useColors) => formatConsoleReport$3(data, useColors));
|
|
3907
|
+
console.log(output);
|
|
3908
|
+
} catch (error) {
|
|
3909
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
3910
|
+
process.exit(1);
|
|
3911
|
+
}
|
|
3912
|
+
});
|
|
3913
|
+
}
|
|
3914
|
+
|
|
3730
3915
|
//#endregion
|
|
3731
3916
|
//#region src/cli/commands/plan.ts
|
|
3732
3917
|
/**
|
|
@@ -4326,7 +4511,7 @@ async function handleSave(req, res, form, filePath, ctx, updateForm) {
|
|
|
4326
4511
|
}));
|
|
4327
4512
|
return;
|
|
4328
4513
|
}
|
|
4329
|
-
await writeFile(newPath, content);
|
|
4514
|
+
await writeFile$1(newPath, content);
|
|
4330
4515
|
logInfo(ctx, pc.green(`Saved to: ${newPath}`));
|
|
4331
4516
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
4332
4517
|
res.end(JSON.stringify({
|
|
@@ -4677,6 +4862,12 @@ function renderFormHtml(form, tabs) {
|
|
|
4677
4862
|
border-radius: 3px;
|
|
4678
4863
|
margin-left: 0.5rem;
|
|
4679
4864
|
}
|
|
4865
|
+
.skip-reason {
|
|
4866
|
+
font-size: 0.85rem;
|
|
4867
|
+
color: #6c757d;
|
|
4868
|
+
font-style: italic;
|
|
4869
|
+
margin-top: 0.25rem;
|
|
4870
|
+
}
|
|
4680
4871
|
.table-container {
|
|
4681
4872
|
overflow-x: auto;
|
|
4682
4873
|
}
|
|
@@ -5052,8 +5243,8 @@ function renderFieldHtml(field, value, isSkipped, skipReason) {
|
|
|
5052
5243
|
const skipped = isSkipped === true;
|
|
5053
5244
|
const requiredMark = field.required ? "<span class=\"required\">*</span>" : "";
|
|
5054
5245
|
const typeLabel = `<span class="type-badge">${field.kind}</span>`;
|
|
5055
|
-
const
|
|
5056
|
-
const
|
|
5246
|
+
const skippedBadge = skipped ? `<span class="skipped-badge">Skipped</span>` : "";
|
|
5247
|
+
const skipReasonHtml = skipped && skipReason ? `<div class="skip-reason">(skipped: ${escapeHtml(skipReason)})</div>` : "";
|
|
5057
5248
|
const fieldClass = skipped ? "field field-skipped" : "field";
|
|
5058
5249
|
const disabledAttr = skipped ? " disabled" : "";
|
|
5059
5250
|
let inputHtml;
|
|
@@ -5105,6 +5296,7 @@ function renderFieldHtml(field, value, isSkipped, skipReason) {
|
|
|
5105
5296
|
${escapeHtml(field.label)} ${requiredMark} ${typeLabel} ${skippedBadge}
|
|
5106
5297
|
</label>
|
|
5107
5298
|
${inputHtml}
|
|
5299
|
+
${skipReasonHtml}
|
|
5108
5300
|
${skipButton}
|
|
5109
5301
|
</div>`;
|
|
5110
5302
|
}
|
|
@@ -5516,7 +5708,7 @@ function registerRenderCommand(program) {
|
|
|
5516
5708
|
logDryRun(`Would write HTML to: ${outputPath}`);
|
|
5517
5709
|
return;
|
|
5518
5710
|
}
|
|
5519
|
-
await writeFile(outputPath, html);
|
|
5711
|
+
await writeFile$1(outputPath, html);
|
|
5520
5712
|
logSuccess(ctx, pc.green(`✓ Rendered to ${outputPath}`));
|
|
5521
5713
|
} catch (error) {
|
|
5522
5714
|
logError(error instanceof Error ? error.message : String(error));
|
|
@@ -5678,9 +5870,9 @@ function registerResearchCommand(program) {
|
|
|
5678
5870
|
console.log(` ${formPath} ${pc.dim("(filled markform source)")}`);
|
|
5679
5871
|
console.log(` ${schemaPath} ${pc.dim("(JSON Schema)")}`);
|
|
5680
5872
|
if (options.transcript && result.transcript) {
|
|
5681
|
-
const { serializeSession } = await import("./session-
|
|
5873
|
+
const { serializeSession } = await import("./session-D7C7IlEv.mjs");
|
|
5682
5874
|
const transcriptPath = outputPath.replace(/\.form\.md$/, ".session.yaml");
|
|
5683
|
-
const { writeFile } = await import("./shared-
|
|
5875
|
+
const { writeFile } = await import("./shared-DtorFV21.mjs");
|
|
5684
5876
|
await writeFile(transcriptPath, serializeSession(result.transcript));
|
|
5685
5877
|
logInfo(ctx, `Transcript: ${transcriptPath}`);
|
|
5686
5878
|
}
|
|
@@ -5727,6 +5919,349 @@ function registerSchemaCommand(program) {
|
|
|
5727
5919
|
});
|
|
5728
5920
|
}
|
|
5729
5921
|
|
|
5922
|
+
//#endregion
|
|
5923
|
+
//#region src/cli/commands/set.ts
|
|
5924
|
+
/**
|
|
5925
|
+
* Parse a CLI value string into a RawFieldValue.
|
|
5926
|
+
*
|
|
5927
|
+
* Only detects JSON arrays/objects ([ or { prefix). Everything else
|
|
5928
|
+
* is passed through as a string — the coercion layer handles
|
|
5929
|
+
* type conversion based on the field's kind.
|
|
5930
|
+
*/
|
|
5931
|
+
function parseCliValue(raw) {
|
|
5932
|
+
if (raw.startsWith("[") || raw.startsWith("{")) try {
|
|
5933
|
+
return JSON.parse(raw);
|
|
5934
|
+
} catch {
|
|
5935
|
+
return raw;
|
|
5936
|
+
}
|
|
5937
|
+
return raw;
|
|
5938
|
+
}
|
|
5939
|
+
/**
|
|
5940
|
+
* Format set report for console output.
|
|
5941
|
+
*/
|
|
5942
|
+
function formatConsoleReport$2(report, useColors) {
|
|
5943
|
+
const lines = [];
|
|
5944
|
+
const bold = useColors ? pc.bold : (s) => s;
|
|
5945
|
+
const dim = useColors ? pc.dim : (s) => s;
|
|
5946
|
+
const cyan = useColors ? pc.cyan : (s) => s;
|
|
5947
|
+
const green = useColors ? pc.green : (s) => s;
|
|
5948
|
+
const red = useColors ? pc.red : (s) => s;
|
|
5949
|
+
lines.push(bold(cyan("Set Result")));
|
|
5950
|
+
lines.push("");
|
|
5951
|
+
const statusColor = report.apply_status === "applied" ? green : red;
|
|
5952
|
+
lines.push(`${bold("Status:")} ${statusColor(report.apply_status)}`);
|
|
5953
|
+
lines.push(`${bold("Form State:")} ${report.form_state}`);
|
|
5954
|
+
lines.push(`${bold("Complete:")} ${report.is_complete ? green("yes") : dim("no")}`);
|
|
5955
|
+
lines.push("");
|
|
5956
|
+
const counts = report.progress.counts;
|
|
5957
|
+
lines.push(bold("Progress:"));
|
|
5958
|
+
lines.push(` Total fields: ${counts.totalFields}`);
|
|
5959
|
+
lines.push(` Filled: ${counts.filledFields}, Empty: ${counts.emptyFields}`);
|
|
5960
|
+
lines.push(` Empty required: ${counts.emptyRequiredFields}`);
|
|
5961
|
+
lines.push("");
|
|
5962
|
+
if (report.issues.length > 0) {
|
|
5963
|
+
lines.push(bold(`Issues (${report.issues.length}):`));
|
|
5964
|
+
for (const issue of report.issues) lines.push(` P${issue.priority} ${dim(issue.ref)}: ${issue.message}`);
|
|
5965
|
+
} else lines.push(dim("No issues."));
|
|
5966
|
+
return lines.join("\n");
|
|
5967
|
+
}
|
|
5968
|
+
/**
|
|
5969
|
+
* Register the set command.
|
|
5970
|
+
*/
|
|
5971
|
+
function registerSetCommand(program) {
|
|
5972
|
+
program.command("set <file> [fieldId] [value]").description("Set field values with auto-coercion").option("--values <json>", "Batch set: JSON object of {fieldId: rawValue} pairs").option("--append <value>", "Append item/row to a collection field").option("--delete <n>", "Delete item/row at index (0-based) from a collection field").option("--clear", "Clear the field value").option("--skip", "Skip the field (marks as skipped)").option("--abort", "Abort the field (marks as unable to complete)").option("--role <role>", "Role for skip/abort (default: \"user\")", "user").option("--reason <text>", "Reason for skip/abort").option("-o, --output <file>", "Output file (default: modify in place)").option("--report", "Output JSON report after applying (issues, progress)").option("--normalize", "Regenerate form without preserving external content").action(async (file, fieldId, value, options, cmd) => {
|
|
5973
|
+
const ctx = getCommandContext(cmd);
|
|
5974
|
+
try {
|
|
5975
|
+
logVerbose(ctx, `Reading file: ${file}`);
|
|
5976
|
+
const content = await readFile$1(file);
|
|
5977
|
+
logVerbose(ctx, "Parsing form...");
|
|
5978
|
+
const form = parseForm(content);
|
|
5979
|
+
let patches;
|
|
5980
|
+
if (options.values) {
|
|
5981
|
+
if (fieldId) {
|
|
5982
|
+
logError("Cannot use --values with positional fieldId/value arguments");
|
|
5983
|
+
process.exit(1);
|
|
5984
|
+
}
|
|
5985
|
+
if (options.clear || options.skip || options.abort || options.append !== void 0 || options.delete !== void 0) {
|
|
5986
|
+
logError("Cannot use --values with --clear, --skip, --abort, --append, or --delete");
|
|
5987
|
+
process.exit(1);
|
|
5988
|
+
}
|
|
5989
|
+
let inputContext;
|
|
5990
|
+
try {
|
|
5991
|
+
inputContext = JSON.parse(options.values);
|
|
5992
|
+
} catch {
|
|
5993
|
+
logError("Invalid JSON in --values option");
|
|
5994
|
+
process.exit(1);
|
|
5995
|
+
}
|
|
5996
|
+
if (typeof inputContext !== "object" || Array.isArray(inputContext)) {
|
|
5997
|
+
logError("--values must be a JSON object");
|
|
5998
|
+
process.exit(1);
|
|
5999
|
+
}
|
|
6000
|
+
const result = coerceInputContext(form, inputContext);
|
|
6001
|
+
for (const w of result.warnings) logVerbose(ctx, `Warning: ${w}`);
|
|
6002
|
+
if (result.errors.length > 0) {
|
|
6003
|
+
for (const e of result.errors) logError(e);
|
|
6004
|
+
process.exit(1);
|
|
6005
|
+
}
|
|
6006
|
+
patches = result.patches;
|
|
6007
|
+
} else if (!fieldId) {
|
|
6008
|
+
logError("Either <fieldId> or --values is required");
|
|
6009
|
+
process.exit(1);
|
|
6010
|
+
} else if (options.clear) {
|
|
6011
|
+
if (!findFieldById(form, fieldId)) {
|
|
6012
|
+
logError(`Field "${fieldId}" not found in form`);
|
|
6013
|
+
process.exit(1);
|
|
6014
|
+
}
|
|
6015
|
+
patches = [{
|
|
6016
|
+
op: "clear_field",
|
|
6017
|
+
fieldId
|
|
6018
|
+
}];
|
|
6019
|
+
} else if (options.skip) {
|
|
6020
|
+
if (!findFieldById(form, fieldId)) {
|
|
6021
|
+
logError(`Field "${fieldId}" not found in form`);
|
|
6022
|
+
process.exit(1);
|
|
6023
|
+
}
|
|
6024
|
+
patches = [{
|
|
6025
|
+
op: "skip_field",
|
|
6026
|
+
fieldId,
|
|
6027
|
+
role: options.role,
|
|
6028
|
+
...options.reason && { reason: options.reason }
|
|
6029
|
+
}];
|
|
6030
|
+
} else if (options.abort) {
|
|
6031
|
+
if (!findFieldById(form, fieldId)) {
|
|
6032
|
+
logError(`Field "${fieldId}" not found in form`);
|
|
6033
|
+
process.exit(1);
|
|
6034
|
+
}
|
|
6035
|
+
patches = [{
|
|
6036
|
+
op: "abort_field",
|
|
6037
|
+
fieldId,
|
|
6038
|
+
role: options.role,
|
|
6039
|
+
...options.reason && { reason: options.reason }
|
|
6040
|
+
}];
|
|
6041
|
+
} else if (options.append !== void 0) {
|
|
6042
|
+
const field = findFieldById(form, fieldId);
|
|
6043
|
+
if (!field) {
|
|
6044
|
+
logError(`Field "${fieldId}" not found in form`);
|
|
6045
|
+
process.exit(1);
|
|
6046
|
+
}
|
|
6047
|
+
const rawValue = parseCliValue(options.append);
|
|
6048
|
+
if (field.kind === "table") {
|
|
6049
|
+
const rows = Array.isArray(rawValue) ? rawValue : typeof rawValue === "object" && rawValue !== null ? [rawValue] : null;
|
|
6050
|
+
if (!rows) {
|
|
6051
|
+
logError(`--append for table field "${fieldId}" requires a JSON object or array of row objects`);
|
|
6052
|
+
process.exit(1);
|
|
6053
|
+
}
|
|
6054
|
+
patches = [{
|
|
6055
|
+
op: "append_table",
|
|
6056
|
+
fieldId,
|
|
6057
|
+
value: rows
|
|
6058
|
+
}];
|
|
6059
|
+
} else if (field.kind === "string_list") patches = [{
|
|
6060
|
+
op: "append_string_list",
|
|
6061
|
+
fieldId,
|
|
6062
|
+
value: Array.isArray(rawValue) ? rawValue : [typeof rawValue === "string" ? rawValue : JSON.stringify(rawValue)]
|
|
6063
|
+
}];
|
|
6064
|
+
else if (field.kind === "url_list") patches = [{
|
|
6065
|
+
op: "append_url_list",
|
|
6066
|
+
fieldId,
|
|
6067
|
+
value: Array.isArray(rawValue) ? rawValue : [typeof rawValue === "string" ? rawValue : JSON.stringify(rawValue)]
|
|
6068
|
+
}];
|
|
6069
|
+
else {
|
|
6070
|
+
logError(`--append is not supported for ${field.kind} fields (only table, string_list, url_list)`);
|
|
6071
|
+
process.exit(1);
|
|
6072
|
+
}
|
|
6073
|
+
} else if (options.delete !== void 0) {
|
|
6074
|
+
const field = findFieldById(form, fieldId);
|
|
6075
|
+
if (!field) {
|
|
6076
|
+
logError(`Field "${fieldId}" not found in form`);
|
|
6077
|
+
process.exit(1);
|
|
6078
|
+
}
|
|
6079
|
+
const index = parseInt(options.delete, 10);
|
|
6080
|
+
if (isNaN(index) || index < 0) {
|
|
6081
|
+
logError(`--delete requires a non-negative integer index, got "${options.delete}"`);
|
|
6082
|
+
process.exit(1);
|
|
6083
|
+
}
|
|
6084
|
+
if (field.kind === "table") patches = [{
|
|
6085
|
+
op: "delete_table",
|
|
6086
|
+
fieldId,
|
|
6087
|
+
value: index
|
|
6088
|
+
}];
|
|
6089
|
+
else if (field.kind === "string_list") patches = [{
|
|
6090
|
+
op: "delete_string_list",
|
|
6091
|
+
fieldId,
|
|
6092
|
+
value: index
|
|
6093
|
+
}];
|
|
6094
|
+
else if (field.kind === "url_list") patches = [{
|
|
6095
|
+
op: "delete_url_list",
|
|
6096
|
+
fieldId,
|
|
6097
|
+
value: index
|
|
6098
|
+
}];
|
|
6099
|
+
else {
|
|
6100
|
+
logError(`--delete is not supported for ${field.kind} fields (only table, string_list, url_list)`);
|
|
6101
|
+
process.exit(1);
|
|
6102
|
+
}
|
|
6103
|
+
} else if (value !== void 0) {
|
|
6104
|
+
const result = coerceToFieldPatch(form, fieldId, parseCliValue(value));
|
|
6105
|
+
if (!result.ok) {
|
|
6106
|
+
logError(result.error);
|
|
6107
|
+
process.exit(1);
|
|
6108
|
+
}
|
|
6109
|
+
if ("warning" in result && result.warning) logVerbose(ctx, `Warning: ${result.warning}`);
|
|
6110
|
+
patches = [result.patch];
|
|
6111
|
+
} else {
|
|
6112
|
+
logError("No value provided. Use <value>, --clear, --skip, --abort, --append, or --delete");
|
|
6113
|
+
process.exit(1);
|
|
6114
|
+
}
|
|
6115
|
+
if (ctx.dryRun) {
|
|
6116
|
+
logDryRun(`Would apply ${patches.length} patches to ${file}`, { patches });
|
|
6117
|
+
return;
|
|
6118
|
+
}
|
|
6119
|
+
logVerbose(ctx, `Applying ${patches.length} patches...`);
|
|
6120
|
+
const applyResult = applyPatches(form, patches);
|
|
6121
|
+
if (applyResult.applyStatus === "rejected") {
|
|
6122
|
+
logError("Patches rejected");
|
|
6123
|
+
for (const rp of applyResult.rejectedPatches) logError(` ${rp.message}`);
|
|
6124
|
+
process.exit(1);
|
|
6125
|
+
}
|
|
6126
|
+
if (options.report) {
|
|
6127
|
+
const output = formatOutput(ctx, {
|
|
6128
|
+
apply_status: applyResult.applyStatus,
|
|
6129
|
+
form_state: applyResult.formState,
|
|
6130
|
+
is_complete: applyResult.isComplete,
|
|
6131
|
+
structure: applyResult.structureSummary,
|
|
6132
|
+
progress: applyResult.progressSummary,
|
|
6133
|
+
issues: applyResult.issues
|
|
6134
|
+
}, (data, useColors) => formatConsoleReport$2(data, useColors));
|
|
6135
|
+
if (options.output) {
|
|
6136
|
+
await writeFile$1(options.output, output);
|
|
6137
|
+
logSuccess(ctx, `Report written to ${options.output}`);
|
|
6138
|
+
} else console.log(output);
|
|
6139
|
+
} else {
|
|
6140
|
+
const output = serializeForm(form, { preserveContent: !options.normalize });
|
|
6141
|
+
const target = options.output ?? file;
|
|
6142
|
+
await writeFile$1(target, output);
|
|
6143
|
+
logSuccess(ctx, `Form updated: ${target}`);
|
|
6144
|
+
}
|
|
6145
|
+
} catch (error) {
|
|
6146
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
6147
|
+
process.exit(1);
|
|
6148
|
+
}
|
|
6149
|
+
});
|
|
6150
|
+
}
|
|
6151
|
+
|
|
6152
|
+
//#endregion
|
|
6153
|
+
//#region src/cli/commands/setup.ts
|
|
6154
|
+
const DO_NOT_EDIT_MARKER = `<!-- DO NOT EDIT: Generated by markform setup.
|
|
6155
|
+
Run 'markform setup' to update.
|
|
6156
|
+
-->`;
|
|
6157
|
+
/**
|
|
6158
|
+
* Load SKILL.md content and insert the DO NOT EDIT marker after frontmatter.
|
|
6159
|
+
*/
|
|
6160
|
+
function loadSkillWithMarker() {
|
|
6161
|
+
const lines = readFileSync(resolvePackagePath(import.meta.url, "docs/skill/SKILL.md"), "utf-8").split("\n");
|
|
6162
|
+
let endOfFrontmatter = -1;
|
|
6163
|
+
if (lines[0] === "---") {
|
|
6164
|
+
for (let i = 1; i < lines.length; i++) if (lines[i] === "---") {
|
|
6165
|
+
endOfFrontmatter = i;
|
|
6166
|
+
break;
|
|
6167
|
+
}
|
|
6168
|
+
}
|
|
6169
|
+
if (endOfFrontmatter >= 0) lines.splice(endOfFrontmatter + 1, 0, "", DO_NOT_EDIT_MARKER);
|
|
6170
|
+
return lines.join("\n");
|
|
6171
|
+
}
|
|
6172
|
+
/**
|
|
6173
|
+
* Install the skill file to .claude/skills/markform/SKILL.md.
|
|
6174
|
+
*/
|
|
6175
|
+
async function installSkill(projectDir, ctx) {
|
|
6176
|
+
const skillDir = join(projectDir, ".claude", "skills", "markform");
|
|
6177
|
+
const skillPath = join(skillDir, "SKILL.md");
|
|
6178
|
+
const isUpdate = existsSync(skillPath);
|
|
6179
|
+
const content = loadSkillWithMarker();
|
|
6180
|
+
await mkdir(skillDir, { recursive: true });
|
|
6181
|
+
await writeFile(skillPath, content, "utf-8");
|
|
6182
|
+
logSuccess(ctx, `${isUpdate ? "Updated" : "Installed"} ${pc.bold(".claude/skills/markform/SKILL.md")}`);
|
|
6183
|
+
}
|
|
6184
|
+
/**
|
|
6185
|
+
* Run setup in auto mode (non-interactive, for agents).
|
|
6186
|
+
*/
|
|
6187
|
+
async function setupAuto(ctx) {
|
|
6188
|
+
logInfo(ctx, "Installing Markform skill for Claude Code...");
|
|
6189
|
+
await installSkill(process.cwd(), ctx);
|
|
6190
|
+
logInfo(ctx, `Run ${pc.cyan("markform skill")} to view the installed skill content.`);
|
|
6191
|
+
}
|
|
6192
|
+
/**
|
|
6193
|
+
* Run setup in interactive mode (guided, for humans).
|
|
6194
|
+
*/
|
|
6195
|
+
async function setupInteractive(ctx) {
|
|
6196
|
+
p.intro(pc.bgCyan(pc.black(" markform setup ")));
|
|
6197
|
+
p.log.info([
|
|
6198
|
+
"This will install Markform as a Claude Code skill in your project.",
|
|
6199
|
+
"",
|
|
6200
|
+
` ${pc.dim("Creates:")} .claude/skills/markform/SKILL.md`,
|
|
6201
|
+
"",
|
|
6202
|
+
"This teaches Claude Code how to use markform commands when working",
|
|
6203
|
+
"with .form.md files in this project."
|
|
6204
|
+
].join("\n"));
|
|
6205
|
+
const shouldContinue = await p.confirm({
|
|
6206
|
+
message: "Install the Markform skill?",
|
|
6207
|
+
initialValue: true
|
|
6208
|
+
});
|
|
6209
|
+
if (p.isCancel(shouldContinue) || !shouldContinue) {
|
|
6210
|
+
p.outro("Setup cancelled.");
|
|
6211
|
+
return;
|
|
6212
|
+
}
|
|
6213
|
+
await installSkill(process.cwd(), ctx);
|
|
6214
|
+
p.outro("Markform skill installed! Claude Code will now know how to use markform.");
|
|
6215
|
+
}
|
|
6216
|
+
/**
|
|
6217
|
+
* Register the setup command.
|
|
6218
|
+
*/
|
|
6219
|
+
function registerSetupCommand(program) {
|
|
6220
|
+
const cmd = program.command("setup").description("Install Markform as a Claude Code skill in the current project").option("--auto", "Non-interactive setup (for agents and scripts)").option("--interactive", "Guided setup with prompts (for humans)").action(async (options, command) => {
|
|
6221
|
+
const ctx = getCommandContext(command);
|
|
6222
|
+
try {
|
|
6223
|
+
if (!options.auto && !options.interactive) {
|
|
6224
|
+
cmd.help();
|
|
6225
|
+
return;
|
|
6226
|
+
}
|
|
6227
|
+
if (options.auto) await setupAuto(ctx);
|
|
6228
|
+
else await setupInteractive(ctx);
|
|
6229
|
+
} catch (error) {
|
|
6230
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
6231
|
+
process.exit(1);
|
|
6232
|
+
}
|
|
6233
|
+
});
|
|
6234
|
+
}
|
|
6235
|
+
|
|
6236
|
+
//#endregion
|
|
6237
|
+
//#region src/cli/commands/skill.ts
|
|
6238
|
+
/**
|
|
6239
|
+
* Load the SKILL.md content.
|
|
6240
|
+
*/
|
|
6241
|
+
function loadSkillContent() {
|
|
6242
|
+
const skillPath = resolvePackagePath(import.meta.url, "docs/skill/SKILL.md");
|
|
6243
|
+
try {
|
|
6244
|
+
return readFileSync(skillPath, "utf-8");
|
|
6245
|
+
} catch (error) {
|
|
6246
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6247
|
+
throw new Error(`Failed to load SKILL.md from ${skillPath}: ${message}`);
|
|
6248
|
+
}
|
|
6249
|
+
}
|
|
6250
|
+
/**
|
|
6251
|
+
* Register the skill command.
|
|
6252
|
+
*/
|
|
6253
|
+
function registerSkillCommand(program) {
|
|
6254
|
+
program.command("skill").description("Output SKILL.md content for Claude Code integration").action(() => {
|
|
6255
|
+
try {
|
|
6256
|
+
const content = loadSkillContent();
|
|
6257
|
+
process.stdout.write(content);
|
|
6258
|
+
} catch (error) {
|
|
6259
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
6260
|
+
process.exit(1);
|
|
6261
|
+
}
|
|
6262
|
+
});
|
|
6263
|
+
}
|
|
6264
|
+
|
|
5730
6265
|
//#endregion
|
|
5731
6266
|
//#region src/cli/commands/status.ts
|
|
5732
6267
|
/**
|
|
@@ -6032,7 +6567,7 @@ function registerValidateCommand(program) {
|
|
|
6032
6567
|
/**
|
|
6033
6568
|
* CLI implementation for markform.
|
|
6034
6569
|
*
|
|
6035
|
-
* Provides commands for inspecting,
|
|
6570
|
+
* Provides commands for inspecting, patching, exporting,
|
|
6036
6571
|
* serving, and running harness loops on .form.md files.
|
|
6037
6572
|
*/
|
|
6038
6573
|
/**
|
|
@@ -6040,6 +6575,7 @@ function registerValidateCommand(program) {
|
|
|
6040
6575
|
*/
|
|
6041
6576
|
function withColoredHelp(cmd) {
|
|
6042
6577
|
cmd.configureHelp({
|
|
6578
|
+
helpWidth: 88,
|
|
6043
6579
|
styleTitle: (str) => pc.bold(pc.cyan(str)),
|
|
6044
6580
|
styleCommandText: (str) => pc.green(str),
|
|
6045
6581
|
styleOptionText: (str) => pc.yellow(str),
|
|
@@ -6052,12 +6588,18 @@ function withColoredHelp(cmd) {
|
|
|
6052
6588
|
*/
|
|
6053
6589
|
function createProgram() {
|
|
6054
6590
|
const program = withColoredHelp(new Command());
|
|
6055
|
-
program.name("markform").description("Agent-friendly, human-readable, editable forms").version(CLI_VERSION, "--version", "output the version number").showHelpAfterError().option("--verbose", "Enable verbose output").option("--quiet", "Suppress non-essential output").option("--dry-run", "Show what would be done without making changes").option("--format <format>", `Output format: ${OUTPUT_FORMATS.join(", ")}`, "console").option("--forms-dir <dir>", `Directory for form output (default: ${DEFAULT_FORMS_DIR})`).option("--overwrite", "Overwrite existing field values (default: continue/skip filled)")
|
|
6591
|
+
program.name("markform").description("Agent-friendly, human-readable, editable forms").version(CLI_VERSION, "--version", "output the version number").showHelpAfterError().option("--verbose", "Enable verbose output").option("--quiet", "Suppress non-essential output").option("--dry-run", "Show what would be done without making changes").option("--format <format>", `Output format: ${OUTPUT_FORMATS.join(", ")}`, "console").option("--forms-dir <dir>", `Directory for form output (default: ${DEFAULT_FORMS_DIR})`).option("--overwrite", "Overwrite existing field values (default: continue/skip filled)").addHelpText("after", `
|
|
6592
|
+
Skill Setup:
|
|
6593
|
+
To use Markform as a Claude Code skill, run: markform setup --auto
|
|
6594
|
+
To view the skill content: markform skill
|
|
6595
|
+
|
|
6596
|
+
Getting Started:
|
|
6597
|
+
npm install -g markform && markform setup --auto`);
|
|
6056
6598
|
registerReadmeCommand(program);
|
|
6057
6599
|
registerDocsCommand(program);
|
|
6058
6600
|
registerSpecCommand(program);
|
|
6059
6601
|
registerApisCommand(program);
|
|
6060
|
-
|
|
6602
|
+
registerPatchCommand(program);
|
|
6061
6603
|
registerBrowseCommand(program);
|
|
6062
6604
|
registerDumpCommand(program);
|
|
6063
6605
|
registerExamplesCommand(program);
|
|
@@ -6065,6 +6607,7 @@ function createProgram() {
|
|
|
6065
6607
|
registerFillCommand(program);
|
|
6066
6608
|
registerInspectCommand(program);
|
|
6067
6609
|
registerModelsCommand(program);
|
|
6610
|
+
registerNextCommand(program);
|
|
6068
6611
|
registerPlanCommand(program);
|
|
6069
6612
|
registerRenderCommand(program);
|
|
6070
6613
|
registerReportCommand(program);
|
|
@@ -6072,6 +6615,9 @@ function createProgram() {
|
|
|
6072
6615
|
registerRunCommand(program);
|
|
6073
6616
|
registerSchemaCommand(program);
|
|
6074
6617
|
registerServeCommand(program);
|
|
6618
|
+
registerSetCommand(program);
|
|
6619
|
+
registerSetupCommand(program);
|
|
6620
|
+
registerSkillCommand(program);
|
|
6075
6621
|
registerStatusCommand(program);
|
|
6076
6622
|
registerValidateCommand(program);
|
|
6077
6623
|
return program;
|
|
@@ -6085,4 +6631,4 @@ async function runCli() {
|
|
|
6085
6631
|
|
|
6086
6632
|
//#endregion
|
|
6087
6633
|
export { runCli as t };
|
|
6088
|
-
//# sourceMappingURL=cli-
|
|
6634
|
+
//# sourceMappingURL=cli-B1DhFYBS.mjs.map
|