Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions skills/worklog/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,36 @@ ingest sync files

---

## 登録済み情報の修正

タスクやトピックの内容(タイトル・重要度・ステータスなど)を後から変更したい場合は `ingest edit` を使用する。

```bash
# タスクのタイトルを変更
ingest edit task "旧タイトル" --title "新タイトル"

# タスクの重要度を変更(0〜10)
ingest edit task <task-id> --importance 8.5

# タスクのステータスを変更(active | paused | blocked | closed)
ingest edit task <task-id> --status paused

# 複数フィールドを一度に変更
ingest edit task "タスク名" --title "新タイトル" --importance 7.0

# トピックの名前を変更
ingest edit topic "旧名前" --name "新名前"

# トピックの基本重要度を変更
ingest edit topic "トピック名" --importance 6.0
```

- タスクは ID またはタイトルのどちらでも指定できる
- importance の変更は `importance_reassessed` イベントとして監査ログに記録される
- タイトル揺れを正規化したい場合は `match suggest` / `match apply` を優先する

---

## タイトル揺れへの対処

タスクタイトルの表記揺れ(例: 「機能A設計」と「機能Aの設計」)は完全一致で判定しません。
Expand Down
57 changes: 57 additions & 0 deletions skills/worklog/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,63 @@ ingest close

---

## 編集コマンド

### `ingest edit task <id|タイトル>`

登録済みタスクの情報を変更します。

```bash
# タイトルを変更
ingest edit task "旧タイトル" --title "新タイトル"

# 重要度を変更(0〜10)
ingest edit task <task-id> --importance 8.5

# ステータスを変更
ingest edit task <task-id> --status paused

# 複数フィールドを一度に変更
ingest edit task "タスク名" --title "新タイトル" --importance 7.0 --status active
```

**オプション**

| オプション | 説明 |
|---|---|
| `--title <text>` | タスクのタイトルを変更 |
| `--importance <0-10>` | 重要度スコアを変更(変更は `importance_reassessed` イベントとして記録) |
| `--status <status>` | ステータスを変更(`active` / `paused` / `blocked` / `closed`) |

- タスクは ID またはタイトルのどちらで指定しても検索されます
- 引数を何も指定しないとエラーになります

---

### `ingest edit topic <id|名前>`

登録済みトピックの情報を変更します。

```bash
# 名前を変更
ingest edit topic "旧名前" --name "新名前"

# 基本重要度を変更(0〜10)
ingest edit topic "トピック名" --importance 6.0

# 両方を一度に変更
ingest edit topic <topic-id> --name "新名前" --importance 6.0
```

**オプション**

| オプション | 説明 |
|---|---|
| `--name <text>` | トピック名を変更 |
| `--importance <0-10>` | 基本重要度スコアを変更 |

---

## ingest コマンド(外部イベントの取り込み)

### `ingest ingest calendar-start --title <title> --at <datetime>`
Expand Down
50 changes: 49 additions & 1 deletion skills/worklog/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,55 @@ ingest decision "〇〇については今週中に方針を決定する"

---

## 6. タイトル揺れを正規化する
## 6. 登録済みタスク・トピックを修正する

タスクのタイトルを入力ミスした、重要度を見直したいといったケースです。

```bash
# タスク一覧で ID とタイトルを確認
ingest tasks

# タイトルを修正(タイトルで指定)
ingest edit task "認章機能の実装" --title "認証機能の実装"
```

出力例:
```
Task updated: xK9mP2
title: 認章機能の実装 → 認証機能の実装
```

```bash
# 重要度を上げる(ID で指定)
ingest edit task xK9mP2 --importance 8.5
```

出力例:
```
Task updated: xK9mP2
importance: 5 → 8.5
```

```bash
# ステータスを一時停止に変更
ingest edit task xK9mP2 --status paused
```

```bash
# トピックの名前と重要度を一度に変更
ingest edit topic "auth" --name "認証・認可" --importance 7.0
```

出力例:
```
Topic updated: tY3pR1
name: auth → 認証・認可
base_importance: 5 → 7
```

---

## 7. タイトル揺れを正規化する

複数セッションにわたって類似タスクが別々に作られてしまった場合のケースです。

Expand Down
126 changes: 126 additions & 0 deletions src/cli/commands/edit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { Command } from 'commander';
import { getTask, findTaskByTitle, updateTask } from '../../core/taskService.js';
import { getTopic, findTopicByName, updateTopic } from '../../core/topicService.js';
import { createEvent } from '../../core/eventService.js';
import { TaskStatus } from '../../types/task.js';

const VALID_STATUSES: TaskStatus[] = ['active', 'paused', 'blocked', 'closed'];

export function registerEdit(program: Command): void {
const edit = program
.command('edit')
.description('Edit a registered task or topic');

// --- edit task ---
edit
.command('task <id-or-title>')
.description('Edit a task (title, importance, status)')
.option('--title <text>', 'New title')
.option('--importance <number>', 'New importance (0–10)', parseFloat)
.option('--status <status>', `New status (${VALID_STATUSES.join(' | ')})`)
.action(async (idOrTitle: string, options) => {
try {
const task = getTask(idOrTitle) ?? findTaskByTitle(idOrTitle);
if (!task) {
console.error(`Task not found: ${idOrTitle}`);
process.exit(1);
}

const fields: { title?: string; importance?: number; status?: TaskStatus } = {};

if (options.title !== undefined) {
fields.title = options.title;
}

if (options.importance !== undefined) {
const imp = options.importance;
if (isNaN(imp) || imp < 0 || imp > 10) {
console.error('--importance must be a number between 0 and 10');
process.exit(1);
}
fields.importance = imp;
}

if (options.status !== undefined) {
if (!VALID_STATUSES.includes(options.status as TaskStatus)) {
console.error(`--status must be one of: ${VALID_STATUSES.join(', ')}`);
process.exit(1);
}
fields.status = options.status as TaskStatus;
}

if (Object.keys(fields).length === 0) {
console.error('Nothing to update. Specify at least one of --title, --importance, --status.');
process.exit(1);
}

updateTask(task.id, fields);

// Record importance change as an auditable event
if (fields.importance !== undefined) {
createEvent({
event_type: 'importance_reassessed',
task_id: task.id,
project_id: task.project_id ?? undefined,
actor: 'human',
origin: 'manual',
summary: `Importance updated: ${task.importance} → ${fields.importance}`,
importance: fields.importance,
});
}

console.log(`Task updated: ${task.id}`);
if (fields.title) console.log(` title: ${task.title} → ${fields.title}`);
if (fields.importance !== undefined) console.log(` importance: ${task.importance} → ${fields.importance}`);
if (fields.status) console.log(` status: ${task.status} → ${fields.status}`);
} catch (err) {
console.error('Error:', err instanceof Error ? err.message : String(err));
process.exit(1);
}
});

// --- edit topic ---
edit
.command('topic <id-or-name>')
.description('Edit a topic (name, base_importance)')
.option('--name <text>', 'New name')
.option('--importance <number>', 'New base importance (0–10)', parseFloat)
.action(async (idOrName: string, options) => {
try {
const topic = getTopic(idOrName) ?? findTopicByName(idOrName);
if (!topic) {
console.error(`Topic not found: ${idOrName}`);
process.exit(1);
}

const fields: { name?: string; base_importance?: number } = {};

if (options.name !== undefined) {
fields.name = options.name;
}

if (options.importance !== undefined) {
const imp = options.importance;
if (isNaN(imp) || imp < 0 || imp > 10) {
console.error('--importance must be a number between 0 and 10');
process.exit(1);
}
fields.base_importance = imp;
}

if (Object.keys(fields).length === 0) {
console.error('Nothing to update. Specify at least one of --name, --importance.');
process.exit(1);
}

updateTopic(topic.id, fields);

console.log(`Topic updated: ${topic.id}`);
if (fields.name) console.log(` name: ${topic.name} → ${fields.name}`);
if (fields.base_importance !== undefined) console.log(` base_importance: ${topic.base_importance} → ${fields.base_importance}`);
} catch (err) {
console.error('Error:', err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
}
2 changes: 2 additions & 0 deletions src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { registerTopics } from './commands/topics.js';
import { registerTasks } from './commands/tasks.js';
import { registerShow } from './commands/show.js';
import { registerPromote } from './commands/promote.js';
import { registerEdit } from './commands/edit.js';

// Ensure ~/.worklog directory and DB exist on startup
const worklogDir = join(process.env.HOME ?? '.', '.worklog');
Expand Down Expand Up @@ -52,5 +53,6 @@ registerTopics(program);
registerTasks(program);
registerShow(program);
registerPromote(program);
registerEdit(program);

program.parse();
Loading
Loading