@quolu/lattice 0.38.1 → 0.39.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/README.ja.md +22 -16
- package/README.md +11 -7
- package/bin/lattice-mcp.mjs +0 -0
- package/bin/lattice.mjs +1 -1
- package/docs/schemas/lattice.phase_todo_revision.v3.schema.json +49 -1
- package/docs/schemas/lattice.plan_create_input.v4.schema.json +85 -0
- package/docs/schemas/lattice.todo_extraction.v3.schema.json +146 -0
- package/docs/schemas/lattice.todo_revision.v2.schema.json +41 -1
- package/package.json +3 -1
- package/src/cli-help.mjs +7 -7
- package/src/project-cli.mjs +32 -15
- package/src/todo-cli.mjs +360 -218
- package/src/todo-contracts.mjs +46 -8
- package/src/todo-dashboard-registry.mjs +17 -3
- package/src/todo-gantt-html-independence.mjs +14 -3
- package/src/todo-gantt-html-shared.mjs +5 -2
- package/src/todo-gantt-layout.mjs +1 -1
- package/src/todo-gantt-scope.mjs +1 -1
- package/src/todo-migration.mjs +46 -9
- package/src/todo-revision.mjs +10 -8
- package/src/todo-status.mjs +3 -3
- package/src/todo-store.mjs +74 -31
package/src/project-cli.mjs
CHANGED
|
@@ -4,8 +4,10 @@ import { lstat, open, realpath } from 'node:fs/promises';
|
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
|
+
TODO_DESIGN_MEMO_PROMPT,
|
|
7
8
|
canonicalizeTodoArtifact,
|
|
8
9
|
exactRecord,
|
|
10
|
+
isTodoDesignMemo,
|
|
9
11
|
isStrictTodoTimestamp,
|
|
10
12
|
isTodoDigest,
|
|
11
13
|
isTodoIdentifier,
|
|
@@ -42,8 +44,9 @@ const PLACEHOLDER_SHA = '0'.repeat(40);
|
|
|
42
44
|
const CREATE_INPUT_SCHEMA = 'lattice.plan_create_input.v1';
|
|
43
45
|
const PHASE_CREATE_INPUT_SCHEMA = 'lattice.plan_create_input.v2';
|
|
44
46
|
const DECOUPLED_PHASE_CREATE_INPUT_SCHEMA = 'lattice.plan_create_input.v3';
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
+
const MEMO_PHASE_CREATE_INPUT_SCHEMA = 'lattice.plan_create_input.v4';
|
|
48
|
+
const CURRENT_CREATE_INPUT_SCHEMA = MEMO_PHASE_CREATE_INPUT_SCHEMA;
|
|
49
|
+
const CURRENT_CREATE_SCHEMA_COMMAND = 'lattice plan create --schema-version 4 --json';
|
|
47
50
|
const CREATE_RESULT_SCHEMA = 'lattice.plan_create_result.v1';
|
|
48
51
|
|
|
49
52
|
function resolveRepoRoot(cwd) {
|
|
@@ -404,8 +407,10 @@ async function readCanonicalInput(repoRoot, inputRef) {
|
|
|
404
407
|
}
|
|
405
408
|
|
|
406
409
|
function validateCreateInput(value) {
|
|
407
|
-
const phaseInput = [PHASE_CREATE_INPUT_SCHEMA, DECOUPLED_PHASE_CREATE_INPUT_SCHEMA
|
|
408
|
-
|
|
410
|
+
const phaseInput = [PHASE_CREATE_INPUT_SCHEMA, DECOUPLED_PHASE_CREATE_INPUT_SCHEMA,
|
|
411
|
+
MEMO_PHASE_CREATE_INPUT_SCHEMA].includes(value?.schema);
|
|
412
|
+
const decoupledPhaseInput = [DECOUPLED_PHASE_CREATE_INPUT_SCHEMA,
|
|
413
|
+
MEMO_PHASE_CREATE_INPUT_SCHEMA].includes(value?.schema);
|
|
409
414
|
const keys = [
|
|
410
415
|
'schema', 'project_id', 'plan_key', 'plan_version', 'actor', 'recorded_at',
|
|
411
416
|
'tasks', 'hard_dependencies', 'joins', 'input_digest',
|
|
@@ -414,6 +419,7 @@ function validateCreateInput(value) {
|
|
|
414
419
|
if (decoupledPhaseInput) keys.push('phase_accept_dependencies');
|
|
415
420
|
if (!exactRecord(value, keys) || ![
|
|
416
421
|
CREATE_INPUT_SCHEMA, PHASE_CREATE_INPUT_SCHEMA, DECOUPLED_PHASE_CREATE_INPUT_SCHEMA,
|
|
422
|
+
MEMO_PHASE_CREATE_INPUT_SCHEMA,
|
|
417
423
|
].includes(value.schema)
|
|
418
424
|
|| !isTodoIdentifier(value.project_id)
|
|
419
425
|
|| !isTodoIdentifier(value.plan_key) || !isTodoIdentifier(value.plan_version)
|
|
@@ -425,7 +431,8 @@ function validateCreateInput(value) {
|
|
|
425
431
|
|| value.tasks.some((task) => task?.narrative_anchor !== null || task?.compile_binding !== null)) return false;
|
|
426
432
|
try {
|
|
427
433
|
buildTodoPlan({
|
|
428
|
-
schema:
|
|
434
|
+
schema: value.schema === MEMO_PHASE_CREATE_INPUT_SCHEMA ? 'lattice.todo_plan.v7'
|
|
435
|
+
: decoupledPhaseInput ? 'lattice.todo_plan.v5'
|
|
429
436
|
: phaseInput ? 'lattice.todo_plan.v4' : 'lattice.todo_plan.v3', project_id: value.project_id,
|
|
430
437
|
plan_key: value.plan_key, plan_version: value.plan_version,
|
|
431
438
|
predecessor_plan_digest: null, tasks: value.tasks,
|
|
@@ -441,6 +448,13 @@ export async function runPlanCreate({ cwd, inputRef, stdout, serializationReview
|
|
|
441
448
|
const repoRoot = resolveRepoRoot(cwd);
|
|
442
449
|
if (repoRoot === null) throw new TodoStoreError('REPO_UNRESOLVED', 'git_toplevel_unresolved');
|
|
443
450
|
const input = await readCanonicalInput(repoRoot, inputRef);
|
|
451
|
+
if (input?.schema !== MEMO_PHASE_CREATE_INPUT_SCHEMA
|
|
452
|
+
|| !Array.isArray(input.tasks) || input.tasks.some((task) => !isTodoDesignMemo(task?.design_memo))) {
|
|
453
|
+
throw new TodoStoreError('DESIGN_MEMO_REQUIRED', 'plan_create_design_memo_required', undefined, {
|
|
454
|
+
prompt: TODO_DESIGN_MEMO_PROMPT,
|
|
455
|
+
next_action: CURRENT_CREATE_SCHEMA_COMMAND,
|
|
456
|
+
});
|
|
457
|
+
}
|
|
444
458
|
if (!validateCreateInput(input)) throw new TodoStoreError('INPUT_INVALID', 'plan_create_schema_invalid');
|
|
445
459
|
// dispatch_shapeのgateはstore初期化より前に判定する(拒否時にstoreへ何も書かないため、
|
|
446
460
|
// 再考後の再実行がplan_key_already_existsで詰まらない)。
|
|
@@ -456,15 +470,16 @@ export async function runPlanCreate({ cwd, inputRef, stdout, serializationReview
|
|
|
456
470
|
repoRoot, writer: createTodoStoreWriter({ caller: 'g5-authoring' }),
|
|
457
471
|
projectId: input.project_id, repositories: [{ repo_id: 'self', path: '.' }],
|
|
458
472
|
plan: {
|
|
459
|
-
schema: input.schema ===
|
|
473
|
+
schema: input.schema === MEMO_PHASE_CREATE_INPUT_SCHEMA ? 'lattice.todo_plan.v7'
|
|
474
|
+
: input.schema === DECOUPLED_PHASE_CREATE_INPUT_SCHEMA ? 'lattice.todo_plan.v5'
|
|
460
475
|
: input.schema === PHASE_CREATE_INPUT_SCHEMA
|
|
461
476
|
? 'lattice.todo_plan.v4' : 'lattice.todo_plan.v3', project_id: input.project_id,
|
|
462
477
|
plan_key: input.plan_key, plan_version: input.plan_version,
|
|
463
478
|
predecessor_plan_digest: null, tasks: input.tasks,
|
|
464
479
|
hard_dependencies: input.hard_dependencies, joins: input.joins,
|
|
465
|
-
...(
|
|
466
|
-
|
|
467
|
-
...(input.schema
|
|
480
|
+
...([PHASE_CREATE_INPUT_SCHEMA, DECOUPLED_PHASE_CREATE_INPUT_SCHEMA,
|
|
481
|
+
MEMO_PHASE_CREATE_INPUT_SCHEMA].includes(input.schema) ? { phases: input.phases } : {}),
|
|
482
|
+
...([DECOUPLED_PHASE_CREATE_INPUT_SCHEMA, MEMO_PHASE_CREATE_INPUT_SCHEMA].includes(input.schema)
|
|
468
483
|
? { phase_accept_dependencies: input.phase_accept_dependencies } : {}),
|
|
469
484
|
},
|
|
470
485
|
genesis: { actor: input.actor, recorded_at: input.recorded_at, provenance: null },
|
|
@@ -493,17 +508,18 @@ export async function runPlanCreate({ cwd, inputRef, stdout, serializationReview
|
|
|
493
508
|
}
|
|
494
509
|
|
|
495
510
|
/**
|
|
496
|
-
* `--schema --json`(版指定なし)の既定はCURRENT_CREATE_INPUT_SCHEMAと同じ
|
|
511
|
+
* `--schema --json`(版指定なし)の既定はCURRENT_CREATE_INPUT_SCHEMAと同じv4にする。
|
|
497
512
|
* 既定がv1のままだと、素の`--schema`を叩いたAIが古いv1(Phaseを表現できない)を
|
|
498
513
|
* 受け取り、実運用で通らない入力を作ってしまう(実際に踏んだ)。
|
|
499
514
|
* `--schema-version 1`は互換のため引き続き取得できる(bin/lattice.mjs側で許可)。
|
|
500
515
|
*
|
|
501
|
-
* 「どの版を返したか」は返すJSON Schema自身の`title`(例: `lattice.plan_create_input.
|
|
516
|
+
* 「どの版を返したか」は返すJSON Schema自身の`title`(例: `lattice.plan_create_input.v4`)が
|
|
502
517
|
* 既に機械可読に持っている。壊さずに追加のkeyを足す理由が無いので足さない。
|
|
503
518
|
*/
|
|
504
|
-
export async function runPlanCreateSchema({ stdout, version =
|
|
505
|
-
if (![1, 2, 3].includes(version)) throw new TypeError('unsupported plan create schema version');
|
|
506
|
-
const expected = version ===
|
|
519
|
+
export async function runPlanCreateSchema({ stdout, version = 4 }) {
|
|
520
|
+
if (![1, 2, 3, 4].includes(version)) throw new TypeError('unsupported plan create schema version');
|
|
521
|
+
const expected = version === 4 ? MEMO_PHASE_CREATE_INPUT_SCHEMA
|
|
522
|
+
: version === 3 ? DECOUPLED_PHASE_CREATE_INPUT_SCHEMA
|
|
507
523
|
: version === 2 ? PHASE_CREATE_INPUT_SCHEMA : CREATE_INPUT_SCHEMA;
|
|
508
524
|
const schemaUrl = new URL(`../docs/schemas/lattice.plan_create_input.v${version}.schema.json`, import.meta.url);
|
|
509
525
|
const handle = await open(schemaUrl, fsConstants.O_RDONLY);
|
|
@@ -539,7 +555,8 @@ export async function runPlanShow({ cwd, planKey, stdout }) {
|
|
|
539
555
|
});
|
|
540
556
|
}
|
|
541
557
|
const { plan, tasks, phases } = member;
|
|
542
|
-
const phaseInput = ['lattice.todo_plan.v4', 'lattice.todo_plan.v5'
|
|
558
|
+
const phaseInput = ['lattice.todo_plan.v4', 'lattice.todo_plan.v5', 'lattice.todo_plan.v7']
|
|
559
|
+
.includes(plan.schema);
|
|
543
560
|
const stateByTaskId = new Map(tasks.map((state) => [state.task_id, state]));
|
|
544
561
|
// snapshot artifactの形式(v1にはphasesキーが無い)には縛られない導出ビューを読む
|
|
545
562
|
// (readTodoStoreが常に member.phases として埋める。ADR 0147)。
|