agent-sin 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 +33 -0
- package/LICENSE +21 -0
- package/README.md +81 -0
- package/assets/logo.png +0 -0
- package/builtin-skills/_shared/_models_lib.py +227 -0
- package/builtin-skills/_shared/_profile_lib.py +98 -0
- package/builtin-skills/_shared/_schedules_lib.py +313 -0
- package/builtin-skills/_shared/_skill_settings_lib.py +153 -0
- package/builtin-skills/_shared/i18n.py +26 -0
- package/builtin-skills/memo-delete/main.py +155 -0
- package/builtin-skills/memo-delete/skill.yaml +57 -0
- package/builtin-skills/memo-index/main.py +178 -0
- package/builtin-skills/memo-index/skill.yaml +53 -0
- package/builtin-skills/memo-save/README.md +5 -0
- package/builtin-skills/memo-save/main.py +74 -0
- package/builtin-skills/memo-save/skill.yaml +52 -0
- package/builtin-skills/memo-search/README.md +10 -0
- package/builtin-skills/memo-search/main.py +97 -0
- package/builtin-skills/memo-search/skill.yaml +51 -0
- package/builtin-skills/memo-vector-search/main.py +121 -0
- package/builtin-skills/memo-vector-search/skill.yaml +53 -0
- package/builtin-skills/model-add/main.py +180 -0
- package/builtin-skills/model-add/skill.yaml +112 -0
- package/builtin-skills/model-list/main.py +93 -0
- package/builtin-skills/model-list/skill.yaml +48 -0
- package/builtin-skills/model-set/main.py +123 -0
- package/builtin-skills/model-set/skill.yaml +69 -0
- package/builtin-skills/profile-delete/_profile_lib.py +98 -0
- package/builtin-skills/profile-delete/main.py +98 -0
- package/builtin-skills/profile-delete/skill.yaml +64 -0
- package/builtin-skills/profile-edit/_profile_lib.py +98 -0
- package/builtin-skills/profile-edit/main.py +97 -0
- package/builtin-skills/profile-edit/skill.yaml +72 -0
- package/builtin-skills/profile-save/main.py +52 -0
- package/builtin-skills/profile-save/skill.yaml +69 -0
- package/builtin-skills/schedule-add/_schedules_lib.py +303 -0
- package/builtin-skills/schedule-add/main.py +137 -0
- package/builtin-skills/schedule-add/skill.yaml +94 -0
- package/builtin-skills/schedule-list/_schedules_lib.py +303 -0
- package/builtin-skills/schedule-list/main.py +86 -0
- package/builtin-skills/schedule-list/skill.yaml +45 -0
- package/builtin-skills/schedule-remove/_schedules_lib.py +303 -0
- package/builtin-skills/schedule-remove/main.py +69 -0
- package/builtin-skills/schedule-remove/skill.yaml +49 -0
- package/builtin-skills/schedule-toggle/_schedules_lib.py +303 -0
- package/builtin-skills/schedule-toggle/main.py +78 -0
- package/builtin-skills/schedule-toggle/skill.yaml +61 -0
- package/builtin-skills/skills-disable/main.py +63 -0
- package/builtin-skills/skills-disable/skill.yaml +52 -0
- package/builtin-skills/skills-enable/main.py +62 -0
- package/builtin-skills/skills-enable/skill.yaml +51 -0
- package/builtin-skills/todo-add/main.py +68 -0
- package/builtin-skills/todo-add/skill.yaml +53 -0
- package/builtin-skills/todo-delete/main.py +65 -0
- package/builtin-skills/todo-delete/skill.yaml +47 -0
- package/builtin-skills/todo-done/main.py +75 -0
- package/builtin-skills/todo-done/skill.yaml +47 -0
- package/builtin-skills/todo-list/main.py +91 -0
- package/builtin-skills/todo-list/skill.yaml +48 -0
- package/builtin-skills/todo-tick/main.py +125 -0
- package/builtin-skills/todo-tick/skill.yaml +48 -0
- package/dist/builder/build-action-classifier.d.ts +18 -0
- package/dist/builder/build-action-classifier.js +142 -0
- package/dist/builder/build-commands.d.ts +19 -0
- package/dist/builder/build-commands.js +133 -0
- package/dist/builder/build-flow.d.ts +72 -0
- package/dist/builder/build-flow.js +416 -0
- package/dist/builder/builder-session.d.ts +117 -0
- package/dist/builder/builder-session.js +1129 -0
- package/dist/builder/conversation-router.d.ts +22 -0
- package/dist/builder/conversation-router.js +69 -0
- package/dist/builder/intent-runtime-store.d.ts +7 -0
- package/dist/builder/intent-runtime-store.js +60 -0
- package/dist/builder/progress-format.d.ts +7 -0
- package/dist/builder/progress-format.js +46 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +2835 -0
- package/dist/cli/spinner.d.ts +30 -0
- package/dist/cli/spinner.js +164 -0
- package/dist/core/ai-provider.d.ts +75 -0
- package/dist/core/ai-provider.js +678 -0
- package/dist/core/builtin-skills.d.ts +27 -0
- package/dist/core/builtin-skills.js +120 -0
- package/dist/core/chat-engine.d.ts +70 -0
- package/dist/core/chat-engine.js +812 -0
- package/dist/core/config.d.ts +127 -0
- package/dist/core/config.js +1379 -0
- package/dist/core/daily-memory-promotion.d.ts +21 -0
- package/dist/core/daily-memory-promotion.js +422 -0
- package/dist/core/i18n.d.ts +23 -0
- package/dist/core/i18n.js +167 -0
- package/dist/core/info-lines.d.ts +5 -0
- package/dist/core/info-lines.js +39 -0
- package/dist/core/input-schema.d.ts +2 -0
- package/dist/core/input-schema.js +156 -0
- package/dist/core/intent-router.d.ts +27 -0
- package/dist/core/intent-router.js +160 -0
- package/dist/core/logger.d.ts +60 -0
- package/dist/core/logger.js +240 -0
- package/dist/core/memory.d.ts +10 -0
- package/dist/core/memory.js +72 -0
- package/dist/core/message-utils.d.ts +13 -0
- package/dist/core/message-utils.js +104 -0
- package/dist/core/notifier.d.ts +17 -0
- package/dist/core/notifier.js +424 -0
- package/dist/core/output-writer.d.ts +13 -0
- package/dist/core/output-writer.js +100 -0
- package/dist/core/plan-decision.d.ts +16 -0
- package/dist/core/plan-decision.js +88 -0
- package/dist/core/profile-memory.d.ts +17 -0
- package/dist/core/profile-memory.js +142 -0
- package/dist/core/runtime.d.ts +50 -0
- package/dist/core/runtime.js +187 -0
- package/dist/core/scheduler.d.ts +28 -0
- package/dist/core/scheduler.js +155 -0
- package/dist/core/secrets.d.ts +31 -0
- package/dist/core/secrets.js +214 -0
- package/dist/core/service.d.ts +35 -0
- package/dist/core/service.js +479 -0
- package/dist/core/skill-planner.d.ts +24 -0
- package/dist/core/skill-planner.js +100 -0
- package/dist/core/skill-registry.d.ts +98 -0
- package/dist/core/skill-registry.js +319 -0
- package/dist/core/skill-scaffold.d.ts +33 -0
- package/dist/core/skill-scaffold.js +256 -0
- package/dist/core/skill-settings.d.ts +11 -0
- package/dist/core/skill-settings.js +63 -0
- package/dist/core/transfer.d.ts +31 -0
- package/dist/core/transfer.js +270 -0
- package/dist/core/update-notifier.d.ts +2 -0
- package/dist/core/update-notifier.js +140 -0
- package/dist/discord/bot.d.ts +96 -0
- package/dist/discord/bot.js +2424 -0
- package/dist/runtimes/codex-app-server.d.ts +53 -0
- package/dist/runtimes/codex-app-server.js +305 -0
- package/dist/runtimes/python-runner.d.ts +7 -0
- package/dist/runtimes/python-runner.js +302 -0
- package/dist/runtimes/typescript-runner.d.ts +5 -0
- package/dist/runtimes/typescript-runner.js +172 -0
- package/dist/skills-sdk/types.d.ts +38 -0
- package/dist/skills-sdk/types.js +1 -0
- package/dist/telegram/bot.d.ts +94 -0
- package/dist/telegram/bot.js +1219 -0
- package/install.ps1 +132 -0
- package/install.sh +130 -0
- package/package.json +60 -0
- package/templates/skill-python/main.py +74 -0
- package/templates/skill-python/skill.yaml +48 -0
- package/templates/skill-typescript/main.ts +87 -0
- package/templates/skill-typescript/skill.yaml +42 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Builtin: todo-add
|
|
2
|
+
|
|
3
|
+
ToDo を1件追加する。memory.todo namespace の "items" リストに append する。
|
|
4
|
+
|
|
5
|
+
入力:
|
|
6
|
+
args.text: ToDoの本文 (必須)
|
|
7
|
+
args.due: ISO8601 日時 (任意)
|
|
8
|
+
出力:
|
|
9
|
+
data.item: 追加したToDo
|
|
10
|
+
data.total: 追加後の総件数
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import secrets
|
|
16
|
+
import os
|
|
17
|
+
import sys
|
|
18
|
+
from datetime import datetime
|
|
19
|
+
|
|
20
|
+
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "_shared"))
|
|
21
|
+
from i18n import localizer # noqa: E402
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
async def run(ctx, input):
|
|
25
|
+
loc = localizer(input)
|
|
26
|
+
args = input.get("args", {})
|
|
27
|
+
text = str(args.get("text", "")).strip()
|
|
28
|
+
due = str(args.get("due", "")).strip() or None
|
|
29
|
+
|
|
30
|
+
if not text:
|
|
31
|
+
return result_skipped(loc.t("No ToDo", "ToDoなし"), loc.t("There is nothing to add.", "追加する内容がありません"))
|
|
32
|
+
|
|
33
|
+
items = list((await ctx.memory.get("items")) or [])
|
|
34
|
+
now = input.get("trigger", {}).get("time") or datetime.now().isoformat()
|
|
35
|
+
item = {
|
|
36
|
+
"id": secrets.token_hex(3),
|
|
37
|
+
"text": text,
|
|
38
|
+
"status": "open",
|
|
39
|
+
"created_at": now,
|
|
40
|
+
}
|
|
41
|
+
if due:
|
|
42
|
+
item["due"] = due
|
|
43
|
+
items.append(item)
|
|
44
|
+
await ctx.memory.set("items", items)
|
|
45
|
+
ctx.log.info(f"todo-add: id={item['id']} total={len(items)}")
|
|
46
|
+
|
|
47
|
+
summary = loc.t(f"Added: {text}", f"追加: {text}")
|
|
48
|
+
if due:
|
|
49
|
+
summary += loc.t(f" (due {due})", f" (期限 {due})")
|
|
50
|
+
return {
|
|
51
|
+
"status": "ok",
|
|
52
|
+
"title": loc.t("Added", "追加"),
|
|
53
|
+
"summary": summary,
|
|
54
|
+
"outputs": {},
|
|
55
|
+
"data": {"item": item, "total": len(items)},
|
|
56
|
+
"suggestions": [],
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def result_skipped(title, summary):
|
|
61
|
+
return {
|
|
62
|
+
"status": "skipped",
|
|
63
|
+
"title": title,
|
|
64
|
+
"summary": summary,
|
|
65
|
+
"outputs": {},
|
|
66
|
+
"data": {},
|
|
67
|
+
"suggestions": [],
|
|
68
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Builtin: todo-add
|
|
2
|
+
# ToDo を1件追加する。状態は memory.todo namespace に保存される。
|
|
3
|
+
|
|
4
|
+
id: todo-add
|
|
5
|
+
name: ToDo Add
|
|
6
|
+
name_i18n:
|
|
7
|
+
en: ToDo Add
|
|
8
|
+
ja: ToDo追加
|
|
9
|
+
description: ToDoを1件追加する
|
|
10
|
+
description_i18n:
|
|
11
|
+
en: Add one ToDo item
|
|
12
|
+
ja: ToDoを1件追加する
|
|
13
|
+
runtime: python
|
|
14
|
+
output_mode: raw # スキル結果をそのままユーザーに返し、LLM 再整形ターンを挟まない
|
|
15
|
+
side_effect: true
|
|
16
|
+
|
|
17
|
+
invocation:
|
|
18
|
+
command: todo.add
|
|
19
|
+
phrases:
|
|
20
|
+
- todo追加
|
|
21
|
+
- やることを追加
|
|
22
|
+
- タスク追加
|
|
23
|
+
phrases_i18n:
|
|
24
|
+
en:
|
|
25
|
+
- add todo
|
|
26
|
+
- add a task
|
|
27
|
+
- create todo
|
|
28
|
+
ja:
|
|
29
|
+
- todo追加
|
|
30
|
+
- やることを追加
|
|
31
|
+
- タスク追加
|
|
32
|
+
|
|
33
|
+
input:
|
|
34
|
+
schema:
|
|
35
|
+
type: object
|
|
36
|
+
additionalProperties: false
|
|
37
|
+
properties:
|
|
38
|
+
text:
|
|
39
|
+
type: string
|
|
40
|
+
minLength: 1
|
|
41
|
+
due:
|
|
42
|
+
type: string
|
|
43
|
+
description: ISO8601 日時 (任意, 例 2026-05-17T18:00:00+09:00)。日付だけでなく時刻まで指定でき、todo-tick が到達時にctx.notifyで通知する
|
|
44
|
+
description_i18n:
|
|
45
|
+
en: Optional ISO8601 date-time, e.g. 2026-05-17T18:00:00+09:00. Include a time so todo-tick can notify when it arrives
|
|
46
|
+
ja: ISO8601 日時 (任意, 例 2026-05-17T18:00:00+09:00)。日付だけでなく時刻まで指定でき、todo-tick が到達時にctx.notifyで通知する
|
|
47
|
+
required:
|
|
48
|
+
- text
|
|
49
|
+
|
|
50
|
+
memory:
|
|
51
|
+
namespace: todo
|
|
52
|
+
read: true
|
|
53
|
+
write: true
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Builtin: todo-delete
|
|
2
|
+
|
|
3
|
+
ToDoを削除する。argsで渡されたidの完全一致または先頭一致で1件特定する。
|
|
4
|
+
|
|
5
|
+
入力:
|
|
6
|
+
args.id: 対象ToDoのID (先頭一致可)
|
|
7
|
+
出力:
|
|
8
|
+
data.removed: 削除したToDo
|
|
9
|
+
data.total: 削除後の総件数
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "_shared"))
|
|
18
|
+
from i18n import localizer # noqa: E402
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
async def run(ctx, input):
|
|
22
|
+
loc = localizer(input)
|
|
23
|
+
args = input.get("args", {})
|
|
24
|
+
target_id = str(args.get("id", "")).strip()
|
|
25
|
+
|
|
26
|
+
if not target_id:
|
|
27
|
+
return error_result(loc.t("ID is missing", "IDが指定されていません"), loc.t("Specify the ToDo ID to delete.", "削除するToDoのIDを指定してください"))
|
|
28
|
+
|
|
29
|
+
items = list((await ctx.memory.get("items")) or [])
|
|
30
|
+
if not items:
|
|
31
|
+
return error_result(loc.t("No ToDos", "ToDoがありません"), loc.t("There are no registered ToDos yet.", "ToDoがまだ登録されていません"))
|
|
32
|
+
|
|
33
|
+
matches = [i for i in items if i.get("id") == target_id]
|
|
34
|
+
if not matches:
|
|
35
|
+
matches = [i for i in items if str(i.get("id", "")).startswith(target_id)]
|
|
36
|
+
if not matches:
|
|
37
|
+
return error_result(loc.t("Not found", "見つかりません"), loc.t(f"No ToDo was found for ID {target_id}.", f"ID {target_id} のToDoは見つかりませんでした"))
|
|
38
|
+
if len(matches) > 1:
|
|
39
|
+
ids = ", ".join(str(i.get("id")) for i in matches)
|
|
40
|
+
return error_result(loc.t("Ambiguous ID", "IDが曖昧です"), loc.t(f"Multiple ToDos match: {ids}", f"複数のToDoが該当します: {ids}"))
|
|
41
|
+
|
|
42
|
+
target = matches[0]
|
|
43
|
+
remaining = [i for i in items if i is not target]
|
|
44
|
+
await ctx.memory.set("items", remaining)
|
|
45
|
+
ctx.log.info(f"todo-delete: id={target.get('id')} remaining={len(remaining)}")
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
"status": "ok",
|
|
49
|
+
"title": loc.t("Deleted", "削除"),
|
|
50
|
+
"summary": loc.t(f"Deleted: {target.get('text', '')}", f"削除: {target.get('text', '')}"),
|
|
51
|
+
"outputs": {},
|
|
52
|
+
"data": {"removed": target, "total": len(remaining)},
|
|
53
|
+
"suggestions": [],
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def error_result(title, summary):
|
|
58
|
+
return {
|
|
59
|
+
"status": "error",
|
|
60
|
+
"title": title,
|
|
61
|
+
"summary": summary,
|
|
62
|
+
"outputs": {},
|
|
63
|
+
"data": {},
|
|
64
|
+
"suggestions": [],
|
|
65
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Builtin: todo-delete
|
|
2
|
+
# 指定したToDoを削除する。
|
|
3
|
+
|
|
4
|
+
id: todo-delete
|
|
5
|
+
name: ToDo Delete
|
|
6
|
+
name_i18n:
|
|
7
|
+
en: ToDo Delete
|
|
8
|
+
ja: ToDo削除
|
|
9
|
+
description: ToDoを削除する
|
|
10
|
+
description_i18n:
|
|
11
|
+
en: Delete a ToDo item
|
|
12
|
+
ja: ToDoを削除する
|
|
13
|
+
runtime: python
|
|
14
|
+
output_mode: raw # スキル結果をそのままユーザーに返し、LLM 再整形ターンを挟まない
|
|
15
|
+
side_effect: true
|
|
16
|
+
|
|
17
|
+
invocation:
|
|
18
|
+
command: todo.delete
|
|
19
|
+
phrases:
|
|
20
|
+
- todo削除
|
|
21
|
+
- 削除
|
|
22
|
+
- 消して
|
|
23
|
+
phrases_i18n:
|
|
24
|
+
en:
|
|
25
|
+
- delete todo
|
|
26
|
+
- remove task
|
|
27
|
+
- delete task
|
|
28
|
+
ja:
|
|
29
|
+
- todo削除
|
|
30
|
+
- 削除
|
|
31
|
+
- 消して
|
|
32
|
+
|
|
33
|
+
input:
|
|
34
|
+
schema:
|
|
35
|
+
type: object
|
|
36
|
+
additionalProperties: false
|
|
37
|
+
properties:
|
|
38
|
+
id:
|
|
39
|
+
type: string
|
|
40
|
+
minLength: 1
|
|
41
|
+
required:
|
|
42
|
+
- id
|
|
43
|
+
|
|
44
|
+
memory:
|
|
45
|
+
namespace: todo
|
|
46
|
+
read: true
|
|
47
|
+
write: true
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Builtin: todo-done
|
|
2
|
+
|
|
3
|
+
ToDoを完了状態に更新する。argsで渡されたidの完全一致または先頭一致で1件特定する。
|
|
4
|
+
|
|
5
|
+
入力:
|
|
6
|
+
args.id: 対象ToDoのID (先頭一致可)
|
|
7
|
+
出力:
|
|
8
|
+
data.item: 更新後のToDo
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
import sys
|
|
15
|
+
from datetime import datetime
|
|
16
|
+
|
|
17
|
+
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "_shared"))
|
|
18
|
+
from i18n import localizer # noqa: E402
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
async def run(ctx, input):
|
|
22
|
+
loc = localizer(input)
|
|
23
|
+
args = input.get("args", {})
|
|
24
|
+
target_id = str(args.get("id", "")).strip()
|
|
25
|
+
|
|
26
|
+
if not target_id:
|
|
27
|
+
return error_result(loc.t("ID is missing", "IDが指定されていません"), loc.t("Specify the ToDo ID to complete.", "完了するToDoのIDを指定してください"))
|
|
28
|
+
|
|
29
|
+
items = list((await ctx.memory.get("items")) or [])
|
|
30
|
+
if not items:
|
|
31
|
+
return error_result(loc.t("No ToDos", "ToDoがありません"), loc.t("There are no registered ToDos yet.", "ToDoがまだ登録されていません"))
|
|
32
|
+
|
|
33
|
+
matches = [i for i in items if i.get("id") == target_id]
|
|
34
|
+
if not matches:
|
|
35
|
+
matches = [i for i in items if str(i.get("id", "")).startswith(target_id)]
|
|
36
|
+
if not matches:
|
|
37
|
+
return error_result(loc.t("Not found", "見つかりません"), loc.t(f"No ToDo was found for ID {target_id}.", f"ID {target_id} のToDoは見つかりませんでした"))
|
|
38
|
+
if len(matches) > 1:
|
|
39
|
+
ids = ", ".join(str(i.get("id")) for i in matches)
|
|
40
|
+
return error_result(loc.t("Ambiguous ID", "IDが曖昧です"), loc.t(f"Multiple ToDos match: {ids}", f"複数のToDoが該当します: {ids}"))
|
|
41
|
+
|
|
42
|
+
target = matches[0]
|
|
43
|
+
text = target.get("text", "")
|
|
44
|
+
if target.get("status") == "done":
|
|
45
|
+
return result_ok(loc.t("Already done", "既に完了済み"), loc.t(f"Already done: {text}", f"既に完了済み: {text}"), target)
|
|
46
|
+
|
|
47
|
+
now = input.get("trigger", {}).get("time") or datetime.now().isoformat()
|
|
48
|
+
target["status"] = "done"
|
|
49
|
+
target["completed_at"] = now
|
|
50
|
+
await ctx.memory.set("items", items)
|
|
51
|
+
ctx.log.info(f"todo-done: id={target.get('id')}")
|
|
52
|
+
|
|
53
|
+
return result_ok(loc.t("Done", "完了"), loc.t(f"Done: {text}", f"完了: {text}"), target)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def result_ok(title, summary, item):
|
|
57
|
+
return {
|
|
58
|
+
"status": "ok",
|
|
59
|
+
"title": title,
|
|
60
|
+
"summary": summary,
|
|
61
|
+
"outputs": {},
|
|
62
|
+
"data": {"item": item},
|
|
63
|
+
"suggestions": [],
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def error_result(title, summary):
|
|
68
|
+
return {
|
|
69
|
+
"status": "error",
|
|
70
|
+
"title": title,
|
|
71
|
+
"summary": summary,
|
|
72
|
+
"outputs": {},
|
|
73
|
+
"data": {},
|
|
74
|
+
"suggestions": [],
|
|
75
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Builtin: todo-done
|
|
2
|
+
# 指定したToDoを完了状態に更新する。idの先頭一致でも対応。
|
|
3
|
+
|
|
4
|
+
id: todo-done
|
|
5
|
+
name: ToDo Done
|
|
6
|
+
name_i18n:
|
|
7
|
+
en: ToDo Done
|
|
8
|
+
ja: ToDo完了
|
|
9
|
+
description: ToDoを完了済みにする
|
|
10
|
+
description_i18n:
|
|
11
|
+
en: Mark a ToDo item as done
|
|
12
|
+
ja: ToDoを完了済みにする
|
|
13
|
+
runtime: python
|
|
14
|
+
output_mode: raw # スキル結果をそのままユーザーに返し、LLM 再整形ターンを挟まない
|
|
15
|
+
side_effect: true
|
|
16
|
+
|
|
17
|
+
invocation:
|
|
18
|
+
command: todo.done
|
|
19
|
+
phrases:
|
|
20
|
+
- todo完了
|
|
21
|
+
- 完了
|
|
22
|
+
- チェック
|
|
23
|
+
phrases_i18n:
|
|
24
|
+
en:
|
|
25
|
+
- complete todo
|
|
26
|
+
- mark todo done
|
|
27
|
+
- check off task
|
|
28
|
+
ja:
|
|
29
|
+
- todo完了
|
|
30
|
+
- 完了
|
|
31
|
+
- チェック
|
|
32
|
+
|
|
33
|
+
input:
|
|
34
|
+
schema:
|
|
35
|
+
type: object
|
|
36
|
+
additionalProperties: false
|
|
37
|
+
properties:
|
|
38
|
+
id:
|
|
39
|
+
type: string
|
|
40
|
+
minLength: 1
|
|
41
|
+
required:
|
|
42
|
+
- id
|
|
43
|
+
|
|
44
|
+
memory:
|
|
45
|
+
namespace: todo
|
|
46
|
+
read: true
|
|
47
|
+
write: true
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Builtin: todo-list
|
|
2
|
+
|
|
3
|
+
memory.todo namespace の ToDo を一覧表示する。
|
|
4
|
+
status=open(default) / done / all で絞り込める。
|
|
5
|
+
|
|
6
|
+
入力:
|
|
7
|
+
args.status: open | done | all (default: open)
|
|
8
|
+
出力:
|
|
9
|
+
data.items: 該当ToDoの配列
|
|
10
|
+
data.counts: { open, done, total }
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
import sys
|
|
17
|
+
from datetime import datetime, timezone
|
|
18
|
+
|
|
19
|
+
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "_shared"))
|
|
20
|
+
from i18n import localizer # noqa: E402
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
async def run(ctx, input):
|
|
24
|
+
loc = localizer(input)
|
|
25
|
+
args = input.get("args", {})
|
|
26
|
+
status = str(args.get("status", "open")).strip() or "open"
|
|
27
|
+
|
|
28
|
+
items = list((await ctx.memory.get("items")) or [])
|
|
29
|
+
open_items = [i for i in items if i.get("status") == "open"]
|
|
30
|
+
done_items = [i for i in items if i.get("status") == "done"]
|
|
31
|
+
if status == "open":
|
|
32
|
+
shown = open_items
|
|
33
|
+
elif status == "done":
|
|
34
|
+
shown = done_items
|
|
35
|
+
else:
|
|
36
|
+
shown = items
|
|
37
|
+
|
|
38
|
+
counts = {"open": len(open_items), "done": len(done_items), "total": len(items)}
|
|
39
|
+
|
|
40
|
+
if not shown:
|
|
41
|
+
if status == "open":
|
|
42
|
+
return result_ok(loc.t("No ToDos", "ToDoなし"), loc.t("There are no open ToDos.", "未完了のToDoはありません"), shown, counts)
|
|
43
|
+
if status == "done":
|
|
44
|
+
return result_ok(loc.t("No ToDos", "ToDoなし"), loc.t("There are no completed ToDos.", "完了済みのToDoはありません"), shown, counts)
|
|
45
|
+
return result_ok(loc.t("No ToDos", "ToDoなし"), loc.t("There are no ToDos yet.", "ToDoがまだありません"), shown, counts)
|
|
46
|
+
|
|
47
|
+
now = parse_iso(input.get("trigger", {}).get("time")) or datetime.now(timezone.utc)
|
|
48
|
+
|
|
49
|
+
lines = []
|
|
50
|
+
for item in shown:
|
|
51
|
+
mark = "x" if loc.locale != "ja" and item.get("status") == "done" else "✔" if item.get("status") == "done" else "・"
|
|
52
|
+
line = f"{mark} {item.get('text', '')}"
|
|
53
|
+
due = item.get("due")
|
|
54
|
+
if due:
|
|
55
|
+
due_dt = parse_iso(due)
|
|
56
|
+
suffix = ""
|
|
57
|
+
if item.get("status") == "open" and due_dt and due_dt <= now:
|
|
58
|
+
suffix = loc.t(" overdue", " ⚠期限切れ")
|
|
59
|
+
elif item.get("notified_at"):
|
|
60
|
+
suffix = loc.t(" notified", " 🔔通知済")
|
|
61
|
+
line += loc.t(f" (due {due}){suffix}", f" (期限 {due}){suffix}")
|
|
62
|
+
item_id = item.get("id")
|
|
63
|
+
if item_id:
|
|
64
|
+
line += f" · {item_id}"
|
|
65
|
+
lines.append(line)
|
|
66
|
+
|
|
67
|
+
title = loc.t(f"{len(shown)} ToDos", f"ToDo {len(shown)}件")
|
|
68
|
+
return result_ok(title, "\n".join(lines), shown, counts)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def parse_iso(value):
|
|
72
|
+
if not value:
|
|
73
|
+
return None
|
|
74
|
+
try:
|
|
75
|
+
parsed = datetime.fromisoformat(str(value).replace("Z", "+00:00"))
|
|
76
|
+
except ValueError:
|
|
77
|
+
return None
|
|
78
|
+
if parsed.tzinfo is None:
|
|
79
|
+
parsed = parsed.replace(tzinfo=timezone.utc)
|
|
80
|
+
return parsed
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def result_ok(title, summary, items, counts):
|
|
84
|
+
return {
|
|
85
|
+
"status": "ok",
|
|
86
|
+
"title": title,
|
|
87
|
+
"summary": summary,
|
|
88
|
+
"outputs": {},
|
|
89
|
+
"data": {"items": items, "counts": counts},
|
|
90
|
+
"suggestions": [],
|
|
91
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Builtin: todo-list
|
|
2
|
+
# memory.todo namespace に保存された ToDo を一覧表示する読み取り専用スキル。
|
|
3
|
+
|
|
4
|
+
id: todo-list
|
|
5
|
+
name: ToDo List
|
|
6
|
+
name_i18n:
|
|
7
|
+
en: ToDo List
|
|
8
|
+
ja: ToDo一覧
|
|
9
|
+
description: ToDoの一覧を表示する
|
|
10
|
+
description_i18n:
|
|
11
|
+
en: List ToDo items
|
|
12
|
+
ja: ToDoの一覧を表示する
|
|
13
|
+
runtime: python
|
|
14
|
+
output_mode: raw # スキル結果をそのままユーザーに返し、LLM 再整形ターンを挟まない
|
|
15
|
+
|
|
16
|
+
invocation:
|
|
17
|
+
command: todo.list
|
|
18
|
+
phrases:
|
|
19
|
+
- todo一覧
|
|
20
|
+
- todo
|
|
21
|
+
- やること
|
|
22
|
+
- タスク一覧
|
|
23
|
+
phrases_i18n:
|
|
24
|
+
en:
|
|
25
|
+
- list todos
|
|
26
|
+
- show todos
|
|
27
|
+
- task list
|
|
28
|
+
ja:
|
|
29
|
+
- todo一覧
|
|
30
|
+
- todo
|
|
31
|
+
- やること
|
|
32
|
+
- タスク一覧
|
|
33
|
+
|
|
34
|
+
input:
|
|
35
|
+
schema:
|
|
36
|
+
type: object
|
|
37
|
+
additionalProperties: false
|
|
38
|
+
properties:
|
|
39
|
+
status:
|
|
40
|
+
type: string
|
|
41
|
+
enum: [open, done, all]
|
|
42
|
+
default: open
|
|
43
|
+
required: []
|
|
44
|
+
|
|
45
|
+
memory:
|
|
46
|
+
namespace: todo
|
|
47
|
+
read: true
|
|
48
|
+
write: false
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""Builtin: todo-tick
|
|
2
|
+
|
|
3
|
+
memory.todo namespace の open ToDo を走査し、due が現在時刻に達したものを
|
|
4
|
+
ctx.notify で通知する。重複通知を避けるため notified_at を打つ。
|
|
5
|
+
同じ期限時刻(分単位)のToDoは1通にまとめて通知する。
|
|
6
|
+
|
|
7
|
+
入力:
|
|
8
|
+
args.channel: 通知チャネル (auto/macos/discord/telegram/slack/mail/stderr, default: auto)
|
|
9
|
+
出力:
|
|
10
|
+
data.fired: 通知したToDoの配列
|
|
11
|
+
data.pending: 未通知のopen ToDo件数(due未設定 or 未到達も含む)
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
import sys
|
|
18
|
+
from collections import OrderedDict
|
|
19
|
+
from datetime import datetime, timezone
|
|
20
|
+
|
|
21
|
+
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "_shared"))
|
|
22
|
+
from i18n import localizer # noqa: E402
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
async def run(ctx, input):
|
|
26
|
+
loc = localizer(input)
|
|
27
|
+
args = input.get("args", {})
|
|
28
|
+
channel = str(args.get("channel", "auto")).strip() or "auto"
|
|
29
|
+
|
|
30
|
+
items = list((await ctx.memory.get("items")) or [])
|
|
31
|
+
if not items:
|
|
32
|
+
return result_ok(loc.t("Nothing due", "対象なし"), loc.t("There are no ToDos.", "ToDoはありません"), [], 0)
|
|
33
|
+
|
|
34
|
+
now_str = input.get("trigger", {}).get("time")
|
|
35
|
+
now = parse_iso(now_str) or datetime.now(timezone.utc)
|
|
36
|
+
|
|
37
|
+
# 同じ期限(分単位)のToDoをまとめて1通にする
|
|
38
|
+
groups: "OrderedDict[str, list]" = OrderedDict()
|
|
39
|
+
for item in items:
|
|
40
|
+
if item.get("status") != "open":
|
|
41
|
+
continue
|
|
42
|
+
if item.get("notified_at"):
|
|
43
|
+
continue
|
|
44
|
+
due = parse_iso(item.get("due"))
|
|
45
|
+
if not due or due > now:
|
|
46
|
+
continue
|
|
47
|
+
key = due.replace(second=0, microsecond=0).isoformat()
|
|
48
|
+
groups.setdefault(key, []).append(item)
|
|
49
|
+
|
|
50
|
+
fired = []
|
|
51
|
+
failed = []
|
|
52
|
+
for group in groups.values():
|
|
53
|
+
body = "\n".join(i.get("text", "ToDo") for i in group)
|
|
54
|
+
outcome = await ctx.notify({
|
|
55
|
+
"title": loc.t("ToDo due", "ToDoの期限"),
|
|
56
|
+
"body": body,
|
|
57
|
+
"channel": channel,
|
|
58
|
+
})
|
|
59
|
+
if outcome.get("ok"):
|
|
60
|
+
stamp = now.isoformat()
|
|
61
|
+
for item in group:
|
|
62
|
+
item["notified_at"] = stamp
|
|
63
|
+
fired.append(item)
|
|
64
|
+
ctx.log.info(f"todo-tick: fired id={item.get('id')}")
|
|
65
|
+
else:
|
|
66
|
+
detail = outcome.get("detail") or "unknown"
|
|
67
|
+
for item in group:
|
|
68
|
+
failed.append({"id": item.get("id"), "error": detail})
|
|
69
|
+
ctx.log.warn(f"todo-tick: notify failed id={item.get('id')} - {detail}")
|
|
70
|
+
|
|
71
|
+
if fired:
|
|
72
|
+
await ctx.memory.set("items", items)
|
|
73
|
+
|
|
74
|
+
pending = sum(
|
|
75
|
+
1 for i in items
|
|
76
|
+
if i.get("status") == "open" and not i.get("notified_at")
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
if not fired and not failed:
|
|
80
|
+
return result_ok(loc.t("No notifications", "通知なし"), loc.t("No ToDos are due.", "期限到達のToDoはありません"), [], pending)
|
|
81
|
+
if failed and not fired:
|
|
82
|
+
return {
|
|
83
|
+
"status": "error",
|
|
84
|
+
"title": loc.t("Notification failed", "通知に失敗しました"),
|
|
85
|
+
"summary": loc.t(f"{len(failed)} notifications failed.", f"{len(failed)}件の通知に失敗しました"),
|
|
86
|
+
"outputs": {},
|
|
87
|
+
"data": {"fired": [], "failed": failed, "pending": pending},
|
|
88
|
+
"suggestions": [],
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
title = loc.t(f"Sent {len(fired)} notifications", f"{len(fired)}件を通知しました")
|
|
92
|
+
lines = [f"- {i.get('text', '')}" for i in fired]
|
|
93
|
+
if failed:
|
|
94
|
+
lines.append(loc.t(f"({len(failed)} failed)", f"(失敗 {len(failed)}件)"))
|
|
95
|
+
return {
|
|
96
|
+
"status": "ok",
|
|
97
|
+
"title": title,
|
|
98
|
+
"summary": "\n".join(lines),
|
|
99
|
+
"outputs": {},
|
|
100
|
+
"data": {"fired": fired, "failed": failed, "pending": pending},
|
|
101
|
+
"suggestions": [],
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def parse_iso(value):
|
|
106
|
+
if not value:
|
|
107
|
+
return None
|
|
108
|
+
try:
|
|
109
|
+
parsed = datetime.fromisoformat(str(value).replace("Z", "+00:00"))
|
|
110
|
+
except ValueError:
|
|
111
|
+
return None
|
|
112
|
+
if parsed.tzinfo is None:
|
|
113
|
+
parsed = parsed.replace(tzinfo=timezone.utc)
|
|
114
|
+
return parsed
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def result_ok(title, summary, fired, pending):
|
|
118
|
+
return {
|
|
119
|
+
"status": "ok",
|
|
120
|
+
"title": title,
|
|
121
|
+
"summary": summary,
|
|
122
|
+
"outputs": {},
|
|
123
|
+
"data": {"fired": fired, "pending": pending},
|
|
124
|
+
"suggestions": [],
|
|
125
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Builtin: todo-tick
|
|
2
|
+
# 期限を過ぎた open ToDo を通知して notified_at を打つ。
|
|
3
|
+
# schedules.yaml に毎分実行で登録するか、手動で `agent-sin run todo-tick` を呼ぶ。
|
|
4
|
+
|
|
5
|
+
id: todo-tick
|
|
6
|
+
name: ToDo Tick
|
|
7
|
+
name_i18n:
|
|
8
|
+
en: ToDo Tick
|
|
9
|
+
ja: ToDo期限通知
|
|
10
|
+
description: 期限が到達したToDoを通知する
|
|
11
|
+
description_i18n:
|
|
12
|
+
en: Notify when ToDo due times are reached
|
|
13
|
+
ja: 期限が到達したToDoを通知する
|
|
14
|
+
runtime: python
|
|
15
|
+
output_mode: raw
|
|
16
|
+
side_effect: true
|
|
17
|
+
|
|
18
|
+
invocation:
|
|
19
|
+
command: todo.tick
|
|
20
|
+
phrases:
|
|
21
|
+
- 期限のToDoを確認
|
|
22
|
+
- ToDo通知をチェック
|
|
23
|
+
- todoの期限チェック
|
|
24
|
+
phrases_i18n:
|
|
25
|
+
en:
|
|
26
|
+
- check due todos
|
|
27
|
+
- todo notifications
|
|
28
|
+
- check todo deadlines
|
|
29
|
+
ja:
|
|
30
|
+
- 期限のToDoを確認
|
|
31
|
+
- ToDo通知をチェック
|
|
32
|
+
- todoの期限チェック
|
|
33
|
+
|
|
34
|
+
input:
|
|
35
|
+
schema:
|
|
36
|
+
type: object
|
|
37
|
+
additionalProperties: false
|
|
38
|
+
properties:
|
|
39
|
+
channel:
|
|
40
|
+
type: string
|
|
41
|
+
enum: [auto, macos, discord, telegram, slack, mail, stderr]
|
|
42
|
+
default: auto
|
|
43
|
+
required: []
|
|
44
|
+
|
|
45
|
+
memory:
|
|
46
|
+
namespace: todo
|
|
47
|
+
read: true
|
|
48
|
+
write: true
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AppConfig } from "../core/config.js";
|
|
2
|
+
import type { ChatTurn } from "../core/chat-engine.js";
|
|
3
|
+
import type { BuildModeState, PendingHandoff } from "./build-flow.js";
|
|
4
|
+
export interface HandoffApprovalDecision {
|
|
5
|
+
decision: "approve" | "reject" | "discuss";
|
|
6
|
+
carry_over_text?: string;
|
|
7
|
+
reason?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface BuildModeActionDecision {
|
|
10
|
+
action: "exit" | "register" | "test" | "continue";
|
|
11
|
+
reason?: string;
|
|
12
|
+
}
|
|
13
|
+
interface ClassifyOptions {
|
|
14
|
+
modelId?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function classifyHandoffApproval(config: AppConfig, userText: string, history: ChatTurn[], pending: PendingHandoff, options?: ClassifyOptions): Promise<HandoffApprovalDecision>;
|
|
17
|
+
export declare function classifyBuildModeAction(config: AppConfig, userText: string, history: ChatTurn[], build: BuildModeState, options?: ClassifyOptions): Promise<BuildModeActionDecision>;
|
|
18
|
+
export {};
|