perttool 0.1.0-alpha.2 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -1
- package/README.md +23 -7
- package/dist/application/agent-help.d.ts +3 -0
- package/dist/application/agent-help.d.ts.map +1 -0
- package/dist/application/agent-help.js +5 -0
- package/dist/application/agent-help.js.map +1 -0
- package/dist/application/mutate.d.ts.map +1 -1
- package/dist/application/mutate.js +16 -7
- package/dist/application/mutate.js.map +1 -1
- package/dist/application/project.d.ts +25 -0
- package/dist/application/project.d.ts.map +1 -0
- package/dist/application/project.js +54 -0
- package/dist/application/project.js.map +1 -0
- package/dist/cli.js +223 -8
- package/dist/cli.js.map +1 -1
- package/dist/guidance/profile.d.ts +6 -0
- package/dist/guidance/profile.d.ts.map +1 -0
- package/dist/guidance/profile.js +1158 -0
- package/dist/guidance/profile.js.map +1 -0
- package/dist/guidance/projection.d.ts +16 -0
- package/dist/guidance/projection.d.ts.map +1 -0
- package/dist/guidance/projection.js +276 -0
- package/dist/guidance/projection.js.map +1 -0
- package/dist/guidance/query.d.ts +4 -0
- package/dist/guidance/query.d.ts.map +1 -0
- package/dist/guidance/query.js +178 -0
- package/dist/guidance/query.js.map +1 -0
- package/dist/guidance/text.d.ts +4 -0
- package/dist/guidance/text.d.ts.map +1 -0
- package/dist/guidance/text.js +118 -0
- package/dist/guidance/text.js.map +1 -0
- package/dist/guidance/types.d.ts +227 -0
- package/dist/guidance/types.d.ts.map +1 -0
- package/dist/guidance/types.js +54 -0
- package/dist/guidance/types.js.map +1 -0
- package/dist/guidance/validator.d.ts +8 -0
- package/dist/guidance/validator.d.ts.map +1 -0
- package/dist/guidance/validator.js +383 -0
- package/dist/guidance/validator.js.map +1 -0
- package/dist/help/registry.d.ts +6 -0
- package/dist/help/registry.d.ts.map +1 -1
- package/dist/help/registry.js +21 -1
- package/dist/help/registry.js.map +1 -1
- package/dist/index.d.ts +12 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/mutation/project.d.ts +5 -0
- package/dist/mutation/project.d.ts.map +1 -0
- package/dist/mutation/project.js +148 -0
- package/dist/mutation/project.js.map +1 -0
- package/dist/mutation/types.d.ts +21 -1
- package/dist/mutation/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -7,9 +7,13 @@ import { checkDocument } from "./application/check.js";
|
|
|
7
7
|
import { planFormat } from "./application/format.js";
|
|
8
8
|
import { planBatchMutation, planMutation } from "./application/mutate.js";
|
|
9
9
|
import { selectNextTasks } from "./application/next.js";
|
|
10
|
+
import { getProjectMetadata, } from "./application/project.js";
|
|
11
|
+
import { getAgentHelp } from "./application/agent-help.js";
|
|
10
12
|
import { exportMermaid, } from "./conversion/mermaid.js";
|
|
11
13
|
import { importMermaid } from "./conversion/mermaid-import.js";
|
|
12
|
-
import { getHelp } from "./help/registry.js";
|
|
14
|
+
import { getAgentHelpCommandHelp, getHelp, } from "./help/registry.js";
|
|
15
|
+
import { serializeAgentGuidanceResult } from "./guidance/projection.js";
|
|
16
|
+
import { agentGuidanceExitCode, renderAgentGuidanceText, } from "./guidance/text.js";
|
|
13
17
|
import { documentContentFromBytes, readDocumentFile, } from "./io/document-file.js";
|
|
14
18
|
import { createArtifactFile, createDocumentFile, replaceDocumentFile, SafeWriteConflictError, SafeWriteVerificationError, } from "./io/safe-write.js";
|
|
15
19
|
import { formatDecimal } from "./model/rational.js";
|
|
@@ -31,6 +35,9 @@ function topLevelHelp() {
|
|
|
31
35
|
" perttool dsl check <file> [--format text|json]",
|
|
32
36
|
" perttool dsl format <file> [--check] [--diff] [--format text|json]",
|
|
33
37
|
" perttool dsl help [topic [subtopic]] [--level index|quick|detail] [--format text|json]",
|
|
38
|
+
" perttool agent help [provider [surface]] [--level index|quick|detail] [--format text|json]",
|
|
39
|
+
" perttool project show <file> [--format text|json]",
|
|
40
|
+
" perttool project set <file> [field options] [--diff] [--write | --out <path>]",
|
|
34
41
|
" perttool dag analyze <file> [--schedule precedence|resource|both] [--format text|json]",
|
|
35
42
|
" perttool dag next <file> [--capacity <resource-id>=<integer>] [--format text|json]",
|
|
36
43
|
" perttool dag advance <file> [--diff] [--write | --out <path>] [--format text|json]",
|
|
@@ -45,6 +52,9 @@ function topLevelHelp() {
|
|
|
45
52
|
].join("\n");
|
|
46
53
|
}
|
|
47
54
|
function commandHelp(resource, action) {
|
|
55
|
+
if (resource === "agent" && action === "help") {
|
|
56
|
+
return getAgentHelpCommandHelp().syntax.join("\n");
|
|
57
|
+
}
|
|
48
58
|
if (resource === "dsl" && action === "check") {
|
|
49
59
|
return [
|
|
50
60
|
"Usage: perttool dsl check <file>",
|
|
@@ -69,6 +79,24 @@ function commandHelp(resource, action) {
|
|
|
69
79
|
" [--format text|json]",
|
|
70
80
|
" [--color auto|always|never]",
|
|
71
81
|
].join("\n");
|
|
82
|
+
if (resource === "project" && action === "show")
|
|
83
|
+
return [
|
|
84
|
+
"Usage: perttool project show <file>",
|
|
85
|
+
" [--max-diagnostics <integer>] [--warnings-as-errors]",
|
|
86
|
+
" [--format text|json] [--color auto|always|never]",
|
|
87
|
+
].join("\n");
|
|
88
|
+
if (resource === "project" && action === "set")
|
|
89
|
+
return [
|
|
90
|
+
"Usage: perttool project set <file> [field options]",
|
|
91
|
+
" [--id <id>] [--version <integer>] [--title <text>] [--description <text>]",
|
|
92
|
+
" [--as-of <date-or-date-time>] [--duration-unit day|hour|point]",
|
|
93
|
+
" [--velocity <velocity>] [--finish <milestone-id>]",
|
|
94
|
+
" [--critical-epsilon <duration>] [--target-duration <duration>]",
|
|
95
|
+
" [--clear description|as_of|velocity|critical_epsilon|target_duration]...",
|
|
96
|
+
" [--diff] [--write [--expect-digest <digest>] | --out <path>]",
|
|
97
|
+
" [--max-diagnostics <integer>] [--warnings-as-errors]",
|
|
98
|
+
" [--format text|json] [--color auto|always|never]",
|
|
99
|
+
].join("\n");
|
|
72
100
|
if (resource === "dag" && action === "analyze")
|
|
73
101
|
return [
|
|
74
102
|
"Usage: perttool dag analyze <file>",
|
|
@@ -401,6 +429,86 @@ async function runCheck(args) {
|
|
|
401
429
|
}
|
|
402
430
|
return ok ? 0 : 1;
|
|
403
431
|
}
|
|
432
|
+
function projectJson(project) {
|
|
433
|
+
return {
|
|
434
|
+
id: project.id,
|
|
435
|
+
version: project.version,
|
|
436
|
+
title: project.title,
|
|
437
|
+
description: project.description,
|
|
438
|
+
as_of: project.asOf,
|
|
439
|
+
duration_unit: project.durationUnit,
|
|
440
|
+
velocity: project.velocity,
|
|
441
|
+
finish: project.finish,
|
|
442
|
+
critical_epsilon: project.criticalEpsilon,
|
|
443
|
+
target_duration: project.targetDuration,
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
function renderProjectText(project) {
|
|
447
|
+
const optional = (value) => value ?? "-";
|
|
448
|
+
return [
|
|
449
|
+
`PROJECT ${project.id}`,
|
|
450
|
+
`VERSION ${project.version}`,
|
|
451
|
+
`TITLE ${JSON.stringify(project.title)}`,
|
|
452
|
+
`DESCRIPTION ${project.description === null ? "-" : JSON.stringify(project.description)}`,
|
|
453
|
+
`AS_OF ${optional(project.asOf)}`,
|
|
454
|
+
`DURATION_UNIT ${project.durationUnit}`,
|
|
455
|
+
`VELOCITY ${optional(project.velocity)}`,
|
|
456
|
+
`FINISH ${project.finish}`,
|
|
457
|
+
`CRITICAL_EPSILON ${optional(project.criticalEpsilon)}`,
|
|
458
|
+
`TARGET_DURATION ${optional(project.targetDuration)}`,
|
|
459
|
+
"",
|
|
460
|
+
].join("\n");
|
|
461
|
+
}
|
|
462
|
+
async function runProjectShow(args) {
|
|
463
|
+
const parsed = parseOptions(args, new Set(["format", "color", "max-diagnostics"]), new Set(["warnings-as-errors"]));
|
|
464
|
+
if (parsed.positionals.length !== 1) {
|
|
465
|
+
throw new UsageError("project show requires exactly one <file>");
|
|
466
|
+
}
|
|
467
|
+
const format = outputFormat(parsed.values.get("format"));
|
|
468
|
+
const color = colorMode(parsed.values.get("color"), format);
|
|
469
|
+
const maxDiagnostics = boundedInteger(parsed.values.get("max-diagnostics"), "max-diagnostics", 100, 1, 1000);
|
|
470
|
+
const sourceOperand = parsed.positionals[0];
|
|
471
|
+
const source = sourceOperand === "-" ? "<stdin>" : sourceOperand;
|
|
472
|
+
let input;
|
|
473
|
+
try {
|
|
474
|
+
input = await readDocument(sourceOperand);
|
|
475
|
+
}
|
|
476
|
+
catch (error) {
|
|
477
|
+
return cliError(error instanceof Error ? error : new Error(String(error)), 3, "project.show", format === "json");
|
|
478
|
+
}
|
|
479
|
+
const result = getProjectMetadata(input.text, { maxDiagnostics });
|
|
480
|
+
const warningFailure = parsed.flags.has("warnings-as-errors") &&
|
|
481
|
+
(result.diagnosticsTruncated ||
|
|
482
|
+
result.diagnostics.some((diagnostic) => diagnostic.severity === "warning"));
|
|
483
|
+
const ok = result.ok && !warningFailure;
|
|
484
|
+
if (format === "json") {
|
|
485
|
+
writeJson({
|
|
486
|
+
schema_version: "Perttool.ProjectResult.v1",
|
|
487
|
+
tool_version: TOOL_VERSION,
|
|
488
|
+
operation: "project.show",
|
|
489
|
+
ok,
|
|
490
|
+
document_id: result.documentId,
|
|
491
|
+
source,
|
|
492
|
+
source_digest: input.digest,
|
|
493
|
+
diagnostics: result.diagnostics.map(jsonDiagnostic),
|
|
494
|
+
diagnostics_truncated: result.diagnosticsTruncated,
|
|
495
|
+
grammar_version: result.grammarVersion,
|
|
496
|
+
project: result.project === null ? null : projectJson(result.project),
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
else {
|
|
500
|
+
if (ok && result.project !== null) {
|
|
501
|
+
process.stdout.write(renderProjectText(result.project));
|
|
502
|
+
}
|
|
503
|
+
for (const diagnostic of result.diagnostics) {
|
|
504
|
+
process.stderr.write(`${renderDiagnostic(diagnostic, source, color)}\n`);
|
|
505
|
+
}
|
|
506
|
+
if (result.diagnosticsTruncated) {
|
|
507
|
+
process.stderr.write(`DIAGNOSTICS_TRUNCATED true limit=${maxDiagnostics}\n`);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
return ok ? 0 : 1;
|
|
511
|
+
}
|
|
404
512
|
function boundedInteger(raw, option, defaultValue, minimum, maximum) {
|
|
405
513
|
if (raw === undefined)
|
|
406
514
|
return defaultValue;
|
|
@@ -606,7 +714,11 @@ function mutationOptionSets(resource, action) {
|
|
|
606
714
|
for (const name of names)
|
|
607
715
|
repeatable.add(name);
|
|
608
716
|
};
|
|
609
|
-
if (resource === "
|
|
717
|
+
if (resource === "project" && action === "set") {
|
|
718
|
+
addValues("id", "version", "title", "description", "as-of", "duration-unit", "velocity", "finish", "critical-epsilon", "target-duration");
|
|
719
|
+
addRepeatable("clear");
|
|
720
|
+
}
|
|
721
|
+
else if (resource === "task" && action === "add") {
|
|
610
722
|
addValues("title", "description", "duration", "optimistic", "most-likely", "pessimistic", "status", "priority", "owner", "blocked-reason", "source");
|
|
611
723
|
addRepeatable("tag", "require");
|
|
612
724
|
}
|
|
@@ -824,6 +936,62 @@ function taskMutationFromOptions(action, parsed) {
|
|
|
824
936
|
...(removeRequirements.length === 0 ? {} : { removeRequirements }),
|
|
825
937
|
};
|
|
826
938
|
}
|
|
939
|
+
function projectMutationFromOptions(parsed) {
|
|
940
|
+
if (parsed.positionals.length !== 1) {
|
|
941
|
+
throw new UsageError("project set requires exactly one <file>");
|
|
942
|
+
}
|
|
943
|
+
const version = optionalInteger(parsed, "version", 0, 2_147_483_647);
|
|
944
|
+
const durationUnit = enumOption(parsed.values.get("duration-unit"), "duration-unit", new Set(["day", "hour", "point"]));
|
|
945
|
+
const clear = enumRepeated(parsed, "clear", new Set([
|
|
946
|
+
"description",
|
|
947
|
+
"as_of",
|
|
948
|
+
"velocity",
|
|
949
|
+
"critical_epsilon",
|
|
950
|
+
"target_duration",
|
|
951
|
+
]));
|
|
952
|
+
const conflicts = new Map([
|
|
953
|
+
["description", parsed.values.has("description")],
|
|
954
|
+
["as_of", parsed.values.has("as-of")],
|
|
955
|
+
["velocity", parsed.values.has("velocity")],
|
|
956
|
+
["critical_epsilon", parsed.values.has("critical-epsilon")],
|
|
957
|
+
["target_duration", parsed.values.has("target-duration")],
|
|
958
|
+
]);
|
|
959
|
+
const conflict = clear.find((field) => conflicts.get(field) === true);
|
|
960
|
+
if (conflict !== undefined) {
|
|
961
|
+
throw new UsageError(`--clear ${conflict} conflicts with another project field option`);
|
|
962
|
+
}
|
|
963
|
+
const set = {
|
|
964
|
+
...(parsed.values.get("id") === undefined ? {} : { id: parsed.values.get("id") }),
|
|
965
|
+
...(version === undefined ? {} : { version }),
|
|
966
|
+
...(parsed.values.get("title") === undefined
|
|
967
|
+
? {}
|
|
968
|
+
: { title: parsed.values.get("title") }),
|
|
969
|
+
...(parsed.values.get("description") === undefined
|
|
970
|
+
? {}
|
|
971
|
+
: { description: parsed.values.get("description") }),
|
|
972
|
+
...(parsed.values.get("as-of") === undefined
|
|
973
|
+
? {}
|
|
974
|
+
: { asOf: parsed.values.get("as-of") }),
|
|
975
|
+
...(durationUnit === undefined ? {} : { durationUnit }),
|
|
976
|
+
...(parsed.values.get("velocity") === undefined
|
|
977
|
+
? {}
|
|
978
|
+
: { velocity: parsed.values.get("velocity") }),
|
|
979
|
+
...(parsed.values.get("finish") === undefined
|
|
980
|
+
? {}
|
|
981
|
+
: { finish: parsed.values.get("finish") }),
|
|
982
|
+
...(parsed.values.get("critical-epsilon") === undefined
|
|
983
|
+
? {}
|
|
984
|
+
: { criticalEpsilon: parsed.values.get("critical-epsilon") }),
|
|
985
|
+
...(parsed.values.get("target-duration") === undefined
|
|
986
|
+
? {}
|
|
987
|
+
: { targetDuration: parsed.values.get("target-duration") }),
|
|
988
|
+
};
|
|
989
|
+
return {
|
|
990
|
+
kind: "project.set",
|
|
991
|
+
...(Object.keys(set).length === 0 ? {} : { set }),
|
|
992
|
+
...(clear.length === 0 ? {} : { clear }),
|
|
993
|
+
};
|
|
994
|
+
}
|
|
827
995
|
function milestoneMutationFromOptions(action, parsed) {
|
|
828
996
|
if (parsed.positionals.length !== 2) {
|
|
829
997
|
throw new UsageError(`milestone ${action} requires <file> <id>`);
|
|
@@ -980,11 +1148,13 @@ async function runMutation(resource, action, args) {
|
|
|
980
1148
|
}
|
|
981
1149
|
else {
|
|
982
1150
|
mutation =
|
|
983
|
-
resource === "
|
|
984
|
-
?
|
|
985
|
-
: resource === "
|
|
986
|
-
?
|
|
987
|
-
:
|
|
1151
|
+
resource === "project"
|
|
1152
|
+
? projectMutationFromOptions(parsed)
|
|
1153
|
+
: resource === "task"
|
|
1154
|
+
? taskMutationFromOptions(action, parsed)
|
|
1155
|
+
: resource === "milestone"
|
|
1156
|
+
? milestoneMutationFromOptions(action, parsed)
|
|
1157
|
+
: resourceMutationFromOptions(action, parsed);
|
|
988
1158
|
sourceOperand = parsed.positionals[0];
|
|
989
1159
|
writeRequest = editingWriteRequest(parsed, sourceOperand);
|
|
990
1160
|
}
|
|
@@ -2039,6 +2209,42 @@ function runHelp(args) {
|
|
|
2039
2209
|
}
|
|
2040
2210
|
return result.ok ? 0 : 1;
|
|
2041
2211
|
}
|
|
2212
|
+
function runAgentHelp(args) {
|
|
2213
|
+
const parsed = parseOptions(args, new Set(["level", "format", "color"]), new Set());
|
|
2214
|
+
if (parsed.positionals.length > 2) {
|
|
2215
|
+
throw new UsageError("agent help accepts at most <provider> <surface>");
|
|
2216
|
+
}
|
|
2217
|
+
const format = outputFormat(parsed.values.get("format"));
|
|
2218
|
+
const color = colorMode(parsed.values.get("color"), format);
|
|
2219
|
+
const providerId = parsed.positionals[0] ?? null;
|
|
2220
|
+
const surfaceId = parsed.positionals[1] ?? null;
|
|
2221
|
+
const level = helpLevel(parsed.values.get("level"), providerId !== null);
|
|
2222
|
+
const result = getAgentHelp({
|
|
2223
|
+
providerId,
|
|
2224
|
+
surfaceId,
|
|
2225
|
+
level,
|
|
2226
|
+
});
|
|
2227
|
+
if (format === "json") {
|
|
2228
|
+
process.stdout.write(serializeAgentGuidanceResult(result));
|
|
2229
|
+
}
|
|
2230
|
+
else {
|
|
2231
|
+
if (result.ok) {
|
|
2232
|
+
process.stdout.write(renderAgentGuidanceText(result));
|
|
2233
|
+
}
|
|
2234
|
+
for (const diagnostic of result.diagnostics) {
|
|
2235
|
+
process.stderr.write(`${renderDiagnostic({
|
|
2236
|
+
code: diagnostic.code,
|
|
2237
|
+
severity: diagnostic.severity,
|
|
2238
|
+
message: diagnostic.message,
|
|
2239
|
+
data: {
|
|
2240
|
+
provider_id: diagnostic.providerId,
|
|
2241
|
+
surface_id: diagnostic.surfaceId,
|
|
2242
|
+
},
|
|
2243
|
+
}, "<agent-guidance>", color)}\n`);
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
return agentGuidanceExitCode(result.diagnostics);
|
|
2247
|
+
}
|
|
2042
2248
|
async function main(argv) {
|
|
2043
2249
|
if (argv.length === 1 && argv[0] === "--version") {
|
|
2044
2250
|
process.stdout.write(`perttool ${TOOL_VERSION}\n`);
|
|
@@ -2053,6 +2259,7 @@ async function main(argv) {
|
|
|
2053
2259
|
const resource = argv[0];
|
|
2054
2260
|
const action = argv[1];
|
|
2055
2261
|
const entityActions = new Map([
|
|
2262
|
+
["project", new Set(["set"])],
|
|
2056
2263
|
["task", new Set(["add", "set", "remove", "finish"])],
|
|
2057
2264
|
["milestone", new Set(["add", "set", "remove"])],
|
|
2058
2265
|
["resource", new Set(["add", "set", "remove"])],
|
|
@@ -2061,7 +2268,9 @@ async function main(argv) {
|
|
|
2061
2268
|
const isMutationCommand = entityActions.get(resource)?.has(action) === true;
|
|
2062
2269
|
if (argv.length === 3 &&
|
|
2063
2270
|
argv[2] === "--help" &&
|
|
2064
|
-
((resource === "
|
|
2271
|
+
((resource === "agent" && action === "help") ||
|
|
2272
|
+
(resource === "dsl" && ["check", "format", "help"].includes(action)) ||
|
|
2273
|
+
(resource === "project" && action === "show") ||
|
|
2065
2274
|
(resource === "dag" && ["analyze", "next", "advance", "render", "import"].includes(action)) ||
|
|
2066
2275
|
isMutationCommand)) {
|
|
2067
2276
|
process.stdout.write(`${commandHelp(resource, action)}\n`);
|
|
@@ -2082,6 +2291,12 @@ async function main(argv) {
|
|
|
2082
2291
|
if (resource === "dag" && action === "import") {
|
|
2083
2292
|
return runImport(argv.slice(2));
|
|
2084
2293
|
}
|
|
2294
|
+
if (resource === "agent" && action === "help") {
|
|
2295
|
+
return runAgentHelp(argv.slice(2));
|
|
2296
|
+
}
|
|
2297
|
+
if (resource === "project" && action === "show") {
|
|
2298
|
+
return runProjectShow(argv.slice(2));
|
|
2299
|
+
}
|
|
2085
2300
|
if (resource === "dsl" && action === "format") {
|
|
2086
2301
|
return runFormat(argv.slice(2));
|
|
2087
2302
|
}
|