@fifine/aim-studio 0.0.2 → 0.0.3
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/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +123 -101
- package/dist/commands/init.js.map +1 -1
- package/dist/configurators/workflow.d.ts.map +1 -1
- package/dist/configurators/workflow.js +91 -65
- package/dist/configurators/workflow.js.map +1 -1
- package/dist/templates/aim/scripts/common/paths.py +3 -2
- package/dist/templates/aim/scripts/export.py +427 -0
- package/dist/templates/claude/commands/aim/export.md +89 -115
- package/dist/templates/claude/commands/aim/onboard.md +10 -8
- package/dist/templates/claude/commands/aim/start.md +104 -37
- package/dist/templates/claude/hooks/inject-subagent-context.py +6 -10
- package/dist/templates/claude/hooks/session-start.py +134 -24
- package/dist/templates/markdown/index.d.ts +5 -0
- package/dist/templates/markdown/index.d.ts.map +1 -1
- package/dist/templates/markdown/index.js +6 -0
- package/dist/templates/markdown/index.js.map +1 -1
- package/dist/templates/markdown/spec/cli/directory-structure.md.txt +71 -0
- package/dist/templates/markdown/spec/cli/error-handling.md.txt +91 -0
- package/dist/templates/markdown/spec/cli/index.md.txt +37 -0
- package/dist/templates/markdown/spec/cli/options-flags.md.txt +71 -0
- package/dist/templates/markdown/spec/cli/output-formatting.md.txt +93 -0
- package/dist/utils/project-detector.d.ts +1 -1
- package/dist/utils/project-detector.d.ts.map +1 -1
- package/dist/utils/project-detector.js +20 -0
- package/dist/utils/project-detector.js.map +1 -1
- package/package.json +1 -1
- package/dist/templates/claude/commands/trellis/before-backend-dev.md +0 -13
- package/dist/templates/claude/commands/trellis/before-frontend-dev.md +0 -13
- package/dist/templates/claude/commands/trellis/break-loop.md +0 -125
- package/dist/templates/claude/commands/trellis/check-backend.md +0 -13
- package/dist/templates/claude/commands/trellis/check-cross-layer.md +0 -153
- package/dist/templates/claude/commands/trellis/check-frontend.md +0 -13
- package/dist/templates/claude/commands/trellis/create-command.md +0 -154
- package/dist/templates/claude/commands/trellis/finish-work.md +0 -129
- package/dist/templates/claude/commands/trellis/integrate-skill.md +0 -219
- package/dist/templates/claude/commands/trellis/onboard.md +0 -358
- package/dist/templates/claude/commands/trellis/parallel.md +0 -193
- package/dist/templates/claude/commands/trellis/record-session.md +0 -62
- package/dist/templates/claude/commands/trellis/start.md +0 -280
- package/dist/templates/claude/commands/trellis/update-spec.md +0 -285
- package/dist/templates/trellis/gitignore.txt +0 -29
- package/dist/templates/trellis/index.d.ts +0 -49
- package/dist/templates/trellis/index.d.ts.map +0 -1
- package/dist/templates/trellis/index.js +0 -92
- package/dist/templates/trellis/index.js.map +0 -1
- package/dist/templates/trellis/scripts/__init__.py +0 -5
- package/dist/templates/trellis/scripts/add_session.py +0 -392
- package/dist/templates/trellis/scripts/common/__init__.py +0 -80
- package/dist/templates/trellis/scripts/common/cli_adapter.py +0 -435
- package/dist/templates/trellis/scripts/common/developer.py +0 -190
- package/dist/templates/trellis/scripts/common/git_context.py +0 -383
- package/dist/templates/trellis/scripts/common/paths.py +0 -347
- package/dist/templates/trellis/scripts/common/phase.py +0 -253
- package/dist/templates/trellis/scripts/common/registry.py +0 -366
- package/dist/templates/trellis/scripts/common/task_queue.py +0 -255
- package/dist/templates/trellis/scripts/common/task_utils.py +0 -178
- package/dist/templates/trellis/scripts/common/worktree.py +0 -219
- package/dist/templates/trellis/scripts/create_bootstrap.py +0 -290
- package/dist/templates/trellis/scripts/get_context.py +0 -16
- package/dist/templates/trellis/scripts/get_developer.py +0 -26
- package/dist/templates/trellis/scripts/init_developer.py +0 -51
- package/dist/templates/trellis/scripts/multi_agent/__init__.py +0 -5
- package/dist/templates/trellis/scripts/multi_agent/cleanup.py +0 -403
- package/dist/templates/trellis/scripts/multi_agent/create_pr.py +0 -329
- package/dist/templates/trellis/scripts/multi_agent/plan.py +0 -233
- package/dist/templates/trellis/scripts/multi_agent/start.py +0 -461
- package/dist/templates/trellis/scripts/multi_agent/status.py +0 -817
- package/dist/templates/trellis/scripts/task.py +0 -1056
- package/dist/templates/trellis/scripts-shell-archive/add-session.sh +0 -384
- package/dist/templates/trellis/scripts-shell-archive/common/developer.sh +0 -129
- package/dist/templates/trellis/scripts-shell-archive/common/git-context.sh +0 -263
- package/dist/templates/trellis/scripts-shell-archive/common/paths.sh +0 -208
- package/dist/templates/trellis/scripts-shell-archive/common/phase.sh +0 -150
- package/dist/templates/trellis/scripts-shell-archive/common/registry.sh +0 -247
- package/dist/templates/trellis/scripts-shell-archive/common/task-queue.sh +0 -142
- package/dist/templates/trellis/scripts-shell-archive/common/task-utils.sh +0 -151
- package/dist/templates/trellis/scripts-shell-archive/common/worktree.sh +0 -128
- package/dist/templates/trellis/scripts-shell-archive/create-bootstrap.sh +0 -299
- package/dist/templates/trellis/scripts-shell-archive/get-context.sh +0 -7
- package/dist/templates/trellis/scripts-shell-archive/get-developer.sh +0 -15
- package/dist/templates/trellis/scripts-shell-archive/init-developer.sh +0 -34
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/cleanup.sh +0 -396
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/create-pr.sh +0 -241
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/plan.sh +0 -207
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/start.sh +0 -317
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/status.sh +0 -828
- package/dist/templates/trellis/scripts-shell-archive/task.sh +0 -1204
- package/dist/templates/trellis/tasks/.gitkeep +0 -0
- package/dist/templates/trellis/workflow.md +0 -416
- package/dist/templates/trellis/worktree.yaml +0 -47
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Trellis workflow templates
|
|
3
|
-
*
|
|
4
|
-
* These are GENERIC templates for user projects.
|
|
5
|
-
* Do NOT use Trellis project's own .trellis/ directory (which may be customized).
|
|
6
|
-
*
|
|
7
|
-
* Directory structure:
|
|
8
|
-
* trellis/
|
|
9
|
-
* ├── scripts/
|
|
10
|
-
* │ ├── __init__.py
|
|
11
|
-
* │ ├── common/ # Shared utilities (Python)
|
|
12
|
-
* │ ├── multi_agent/ # Multi-agent pipeline scripts (Python)
|
|
13
|
-
* │ └── *.py # Main scripts (Python)
|
|
14
|
-
* ├── scripts-shell-archive/ # Archived shell scripts (for reference)
|
|
15
|
-
* ├── workflow.md # Workflow guide
|
|
16
|
-
* ├── worktree.yaml # Worktree configuration
|
|
17
|
-
* └── gitignore.txt # .gitignore content
|
|
18
|
-
*/
|
|
19
|
-
import { readFileSync } from "node:fs";
|
|
20
|
-
import { dirname, join } from "node:path";
|
|
21
|
-
import { fileURLToPath } from "node:url";
|
|
22
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
23
|
-
const __dirname = dirname(__filename);
|
|
24
|
-
function readTemplate(relativePath) {
|
|
25
|
-
return readFileSync(join(__dirname, relativePath), "utf-8");
|
|
26
|
-
}
|
|
27
|
-
// Python scripts - package init
|
|
28
|
-
export const scriptsInit = readTemplate("scripts/__init__.py");
|
|
29
|
-
// Python scripts - common
|
|
30
|
-
export const commonInit = readTemplate("scripts/common/__init__.py");
|
|
31
|
-
export const commonPaths = readTemplate("scripts/common/paths.py");
|
|
32
|
-
export const commonDeveloper = readTemplate("scripts/common/developer.py");
|
|
33
|
-
export const commonGitContext = readTemplate("scripts/common/git_context.py");
|
|
34
|
-
export const commonWorktree = readTemplate("scripts/common/worktree.py");
|
|
35
|
-
export const commonTaskQueue = readTemplate("scripts/common/task_queue.py");
|
|
36
|
-
export const commonTaskUtils = readTemplate("scripts/common/task_utils.py");
|
|
37
|
-
export const commonPhase = readTemplate("scripts/common/phase.py");
|
|
38
|
-
export const commonRegistry = readTemplate("scripts/common/registry.py");
|
|
39
|
-
export const commonCliAdapter = readTemplate("scripts/common/cli_adapter.py");
|
|
40
|
-
// Python scripts - multi_agent
|
|
41
|
-
export const multiAgentInit = readTemplate("scripts/multi_agent/__init__.py");
|
|
42
|
-
export const multiAgentStart = readTemplate("scripts/multi_agent/start.py");
|
|
43
|
-
export const multiAgentCleanup = readTemplate("scripts/multi_agent/cleanup.py");
|
|
44
|
-
export const multiAgentStatus = readTemplate("scripts/multi_agent/status.py");
|
|
45
|
-
export const multiAgentCreatePr = readTemplate("scripts/multi_agent/create_pr.py");
|
|
46
|
-
export const multiAgentPlan = readTemplate("scripts/multi_agent/plan.py");
|
|
47
|
-
// Python scripts - main
|
|
48
|
-
export const getDeveloperScript = readTemplate("scripts/get_developer.py");
|
|
49
|
-
export const initDeveloperScript = readTemplate("scripts/init_developer.py");
|
|
50
|
-
export const taskScript = readTemplate("scripts/task.py");
|
|
51
|
-
export const getContextScript = readTemplate("scripts/get_context.py");
|
|
52
|
-
export const addSessionScript = readTemplate("scripts/add_session.py");
|
|
53
|
-
export const createBootstrapScript = readTemplate("scripts/create_bootstrap.py");
|
|
54
|
-
// Configuration files
|
|
55
|
-
export const workflowMdTemplate = readTemplate("workflow.md");
|
|
56
|
-
export const worktreeYamlTemplate = readTemplate("worktree.yaml");
|
|
57
|
-
export const gitignoreTemplate = readTemplate("gitignore.txt");
|
|
58
|
-
/**
|
|
59
|
-
* Get all script templates as a map of relative path to content
|
|
60
|
-
*/
|
|
61
|
-
export function getAllScripts() {
|
|
62
|
-
const scripts = new Map();
|
|
63
|
-
// Package init
|
|
64
|
-
scripts.set("__init__.py", scriptsInit);
|
|
65
|
-
// Common
|
|
66
|
-
scripts.set("common/__init__.py", commonInit);
|
|
67
|
-
scripts.set("common/paths.py", commonPaths);
|
|
68
|
-
scripts.set("common/developer.py", commonDeveloper);
|
|
69
|
-
scripts.set("common/git_context.py", commonGitContext);
|
|
70
|
-
scripts.set("common/worktree.py", commonWorktree);
|
|
71
|
-
scripts.set("common/task_queue.py", commonTaskQueue);
|
|
72
|
-
scripts.set("common/task_utils.py", commonTaskUtils);
|
|
73
|
-
scripts.set("common/phase.py", commonPhase);
|
|
74
|
-
scripts.set("common/registry.py", commonRegistry);
|
|
75
|
-
scripts.set("common/cli_adapter.py", commonCliAdapter);
|
|
76
|
-
// Multi-agent
|
|
77
|
-
scripts.set("multi_agent/__init__.py", multiAgentInit);
|
|
78
|
-
scripts.set("multi_agent/start.py", multiAgentStart);
|
|
79
|
-
scripts.set("multi_agent/cleanup.py", multiAgentCleanup);
|
|
80
|
-
scripts.set("multi_agent/status.py", multiAgentStatus);
|
|
81
|
-
scripts.set("multi_agent/create_pr.py", multiAgentCreatePr);
|
|
82
|
-
scripts.set("multi_agent/plan.py", multiAgentPlan);
|
|
83
|
-
// Main
|
|
84
|
-
scripts.set("get_developer.py", getDeveloperScript);
|
|
85
|
-
scripts.set("init_developer.py", initDeveloperScript);
|
|
86
|
-
scripts.set("task.py", taskScript);
|
|
87
|
-
scripts.set("get_context.py", getContextScript);
|
|
88
|
-
scripts.set("add_session.py", addSessionScript);
|
|
89
|
-
scripts.set("create_bootstrap.py", createBootstrapScript);
|
|
90
|
-
return scripts;
|
|
91
|
-
}
|
|
92
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/trellis/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,392 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
"""
|
|
4
|
-
Add a new session to journal file and update index.md.
|
|
5
|
-
|
|
6
|
-
Usage:
|
|
7
|
-
python3 add_session.py --title "Title" --commit "hash" --summary "Summary"
|
|
8
|
-
echo "content" | python3 add_session.py --title "Title" --commit "hash"
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
from __future__ import annotations
|
|
12
|
-
|
|
13
|
-
import sys
|
|
14
|
-
|
|
15
|
-
# IMPORTANT: Force stdout to use UTF-8 on Windows
|
|
16
|
-
# This fixes UnicodeEncodeError when outputting non-ASCII characters
|
|
17
|
-
if sys.platform == "win32":
|
|
18
|
-
import io as _io
|
|
19
|
-
if hasattr(sys.stdout, "reconfigure"):
|
|
20
|
-
sys.stdout.reconfigure(encoding="utf-8", errors="replace") # type: ignore[union-attr]
|
|
21
|
-
elif hasattr(sys.stdout, "detach"):
|
|
22
|
-
sys.stdout = _io.TextIOWrapper(sys.stdout.detach(), encoding="utf-8", errors="replace") # type: ignore[union-attr]
|
|
23
|
-
|
|
24
|
-
import argparse
|
|
25
|
-
import re
|
|
26
|
-
import sys
|
|
27
|
-
from datetime import datetime
|
|
28
|
-
from pathlib import Path
|
|
29
|
-
|
|
30
|
-
from common.paths import (
|
|
31
|
-
FILE_JOURNAL_PREFIX,
|
|
32
|
-
get_repo_root,
|
|
33
|
-
get_developer,
|
|
34
|
-
get_workspace_dir,
|
|
35
|
-
)
|
|
36
|
-
from common.developer import ensure_developer
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
MAX_LINES = 2000
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
# =============================================================================
|
|
43
|
-
# Helper Functions
|
|
44
|
-
# =============================================================================
|
|
45
|
-
|
|
46
|
-
def get_latest_journal_info(dev_dir: Path) -> tuple[Path | None, int, int]:
|
|
47
|
-
"""Get latest journal file info.
|
|
48
|
-
|
|
49
|
-
Returns:
|
|
50
|
-
Tuple of (file_path, file_number, line_count).
|
|
51
|
-
"""
|
|
52
|
-
latest_file: Path | None = None
|
|
53
|
-
latest_num = -1
|
|
54
|
-
|
|
55
|
-
for f in dev_dir.glob(f"{FILE_JOURNAL_PREFIX}*.md"):
|
|
56
|
-
if not f.is_file():
|
|
57
|
-
continue
|
|
58
|
-
|
|
59
|
-
match = re.search(r"(\d+)$", f.stem)
|
|
60
|
-
if match:
|
|
61
|
-
num = int(match.group(1))
|
|
62
|
-
if num > latest_num:
|
|
63
|
-
latest_num = num
|
|
64
|
-
latest_file = f
|
|
65
|
-
|
|
66
|
-
if latest_file:
|
|
67
|
-
lines = len(latest_file.read_text(encoding="utf-8").splitlines())
|
|
68
|
-
return latest_file, latest_num, lines
|
|
69
|
-
|
|
70
|
-
return None, 0, 0
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def get_current_session(index_file: Path) -> int:
|
|
74
|
-
"""Get current session number from index.md."""
|
|
75
|
-
if not index_file.is_file():
|
|
76
|
-
return 0
|
|
77
|
-
|
|
78
|
-
content = index_file.read_text(encoding="utf-8")
|
|
79
|
-
for line in content.splitlines():
|
|
80
|
-
if "Total Sessions" in line:
|
|
81
|
-
match = re.search(r":\s*(\d+)", line)
|
|
82
|
-
if match:
|
|
83
|
-
return int(match.group(1))
|
|
84
|
-
return 0
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def _extract_journal_num(filename: str) -> int:
|
|
88
|
-
"""Extract journal number from filename for sorting."""
|
|
89
|
-
match = re.search(r"(\d+)", filename)
|
|
90
|
-
return int(match.group(1)) if match else 0
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def count_journal_files(dev_dir: Path, active_num: int) -> str:
|
|
94
|
-
"""Count journal files and return table rows."""
|
|
95
|
-
active_file = f"{FILE_JOURNAL_PREFIX}{active_num}.md"
|
|
96
|
-
result_lines = []
|
|
97
|
-
|
|
98
|
-
files = sorted(
|
|
99
|
-
[f for f in dev_dir.glob(f"{FILE_JOURNAL_PREFIX}*.md") if f.is_file()],
|
|
100
|
-
key=lambda f: _extract_journal_num(f.stem),
|
|
101
|
-
reverse=True
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
for f in files:
|
|
105
|
-
filename = f.name
|
|
106
|
-
lines = len(f.read_text(encoding="utf-8").splitlines())
|
|
107
|
-
status = "Active" if filename == active_file else "Archived"
|
|
108
|
-
result_lines.append(f"| `{filename}` | ~{lines} | {status} |")
|
|
109
|
-
|
|
110
|
-
return "\n".join(result_lines)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
def create_new_journal_file(dev_dir: Path, num: int, developer: str, today: str) -> Path:
|
|
114
|
-
"""Create a new journal file."""
|
|
115
|
-
prev_num = num - 1
|
|
116
|
-
new_file = dev_dir / f"{FILE_JOURNAL_PREFIX}{num}.md"
|
|
117
|
-
|
|
118
|
-
content = f"""# Journal - {developer} (Part {num})
|
|
119
|
-
|
|
120
|
-
> Continuation from `{FILE_JOURNAL_PREFIX}{prev_num}.md` (archived at ~{MAX_LINES} lines)
|
|
121
|
-
> Started: {today}
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
|
-
"""
|
|
126
|
-
new_file.write_text(content, encoding="utf-8")
|
|
127
|
-
return new_file
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
def generate_session_content(
|
|
131
|
-
session_num: int,
|
|
132
|
-
title: str,
|
|
133
|
-
commit: str,
|
|
134
|
-
summary: str,
|
|
135
|
-
extra_content: str,
|
|
136
|
-
today: str
|
|
137
|
-
) -> str:
|
|
138
|
-
"""Generate session content."""
|
|
139
|
-
if commit and commit != "-":
|
|
140
|
-
commit_table = """| Hash | Message |
|
|
141
|
-
|------|---------|"""
|
|
142
|
-
for c in commit.split(","):
|
|
143
|
-
c = c.strip()
|
|
144
|
-
commit_table += f"\n| `{c}` | (see git log) |"
|
|
145
|
-
else:
|
|
146
|
-
commit_table = "(No commits - planning session)"
|
|
147
|
-
|
|
148
|
-
return f"""
|
|
149
|
-
|
|
150
|
-
## Session {session_num}: {title}
|
|
151
|
-
|
|
152
|
-
**Date**: {today}
|
|
153
|
-
**Task**: {title}
|
|
154
|
-
|
|
155
|
-
### Summary
|
|
156
|
-
|
|
157
|
-
{summary}
|
|
158
|
-
|
|
159
|
-
### Main Changes
|
|
160
|
-
|
|
161
|
-
{extra_content}
|
|
162
|
-
|
|
163
|
-
### Git Commits
|
|
164
|
-
|
|
165
|
-
{commit_table}
|
|
166
|
-
|
|
167
|
-
### Testing
|
|
168
|
-
|
|
169
|
-
- [OK] (Add test results)
|
|
170
|
-
|
|
171
|
-
### Status
|
|
172
|
-
|
|
173
|
-
[OK] **Completed**
|
|
174
|
-
|
|
175
|
-
### Next Steps
|
|
176
|
-
|
|
177
|
-
- None - task complete
|
|
178
|
-
"""
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
def update_index(
|
|
182
|
-
index_file: Path,
|
|
183
|
-
dev_dir: Path,
|
|
184
|
-
title: str,
|
|
185
|
-
commit: str,
|
|
186
|
-
new_session: int,
|
|
187
|
-
active_file: str,
|
|
188
|
-
today: str
|
|
189
|
-
) -> bool:
|
|
190
|
-
"""Update index.md with new session info."""
|
|
191
|
-
# Format commit for display
|
|
192
|
-
commit_display = "-"
|
|
193
|
-
if commit and commit != "-":
|
|
194
|
-
commit_display = re.sub(r"([a-f0-9]{7,})", r"`\1`", commit.replace(",", ", "))
|
|
195
|
-
|
|
196
|
-
# Get file number from active_file name
|
|
197
|
-
match = re.search(r"(\d+)", active_file)
|
|
198
|
-
active_num = int(match.group(1)) if match else 0
|
|
199
|
-
files_table = count_journal_files(dev_dir, active_num)
|
|
200
|
-
|
|
201
|
-
print(f"Updating index.md for session {new_session}...")
|
|
202
|
-
print(f" Title: {title}")
|
|
203
|
-
print(f" Commit: {commit_display}")
|
|
204
|
-
print(f" Active File: {active_file}")
|
|
205
|
-
print()
|
|
206
|
-
|
|
207
|
-
content = index_file.read_text(encoding="utf-8")
|
|
208
|
-
|
|
209
|
-
if "@@@auto:current-status" not in content:
|
|
210
|
-
print("Error: Markers not found in index.md. Please ensure markers exist.", file=sys.stderr)
|
|
211
|
-
return False
|
|
212
|
-
|
|
213
|
-
# Process sections
|
|
214
|
-
lines = content.splitlines()
|
|
215
|
-
new_lines = []
|
|
216
|
-
|
|
217
|
-
in_current_status = False
|
|
218
|
-
in_active_documents = False
|
|
219
|
-
in_session_history = False
|
|
220
|
-
header_written = False
|
|
221
|
-
|
|
222
|
-
for line in lines:
|
|
223
|
-
if "@@@auto:current-status" in line:
|
|
224
|
-
new_lines.append(line)
|
|
225
|
-
in_current_status = True
|
|
226
|
-
new_lines.append(f"- **Active File**: `{active_file}`")
|
|
227
|
-
new_lines.append(f"- **Total Sessions**: {new_session}")
|
|
228
|
-
new_lines.append(f"- **Last Active**: {today}")
|
|
229
|
-
continue
|
|
230
|
-
|
|
231
|
-
if "@@@/auto:current-status" in line:
|
|
232
|
-
in_current_status = False
|
|
233
|
-
new_lines.append(line)
|
|
234
|
-
continue
|
|
235
|
-
|
|
236
|
-
if "@@@auto:active-documents" in line:
|
|
237
|
-
new_lines.append(line)
|
|
238
|
-
in_active_documents = True
|
|
239
|
-
new_lines.append("| File | Lines | Status |")
|
|
240
|
-
new_lines.append("|------|-------|--------|")
|
|
241
|
-
new_lines.append(files_table)
|
|
242
|
-
continue
|
|
243
|
-
|
|
244
|
-
if "@@@/auto:active-documents" in line:
|
|
245
|
-
in_active_documents = False
|
|
246
|
-
new_lines.append(line)
|
|
247
|
-
continue
|
|
248
|
-
|
|
249
|
-
if "@@@auto:session-history" in line:
|
|
250
|
-
new_lines.append(line)
|
|
251
|
-
in_session_history = True
|
|
252
|
-
header_written = False
|
|
253
|
-
continue
|
|
254
|
-
|
|
255
|
-
if "@@@/auto:session-history" in line:
|
|
256
|
-
in_session_history = False
|
|
257
|
-
new_lines.append(line)
|
|
258
|
-
continue
|
|
259
|
-
|
|
260
|
-
if in_current_status:
|
|
261
|
-
continue
|
|
262
|
-
|
|
263
|
-
if in_active_documents:
|
|
264
|
-
continue
|
|
265
|
-
|
|
266
|
-
if in_session_history:
|
|
267
|
-
new_lines.append(line)
|
|
268
|
-
if line.startswith("|---") and not header_written:
|
|
269
|
-
new_lines.append(f"| {new_session} | {today} | {title} | {commit_display} |")
|
|
270
|
-
header_written = True
|
|
271
|
-
continue
|
|
272
|
-
|
|
273
|
-
new_lines.append(line)
|
|
274
|
-
|
|
275
|
-
index_file.write_text("\n".join(new_lines), encoding="utf-8")
|
|
276
|
-
print("[OK] Updated index.md successfully!")
|
|
277
|
-
return True
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
# =============================================================================
|
|
281
|
-
# Main Function
|
|
282
|
-
# =============================================================================
|
|
283
|
-
|
|
284
|
-
def add_session(
|
|
285
|
-
title: str,
|
|
286
|
-
commit: str = "-",
|
|
287
|
-
summary: str = "(Add summary)",
|
|
288
|
-
extra_content: str = "(Add details)"
|
|
289
|
-
) -> int:
|
|
290
|
-
"""Add a new session."""
|
|
291
|
-
repo_root = get_repo_root()
|
|
292
|
-
ensure_developer(repo_root)
|
|
293
|
-
|
|
294
|
-
developer = get_developer(repo_root)
|
|
295
|
-
if not developer:
|
|
296
|
-
print("Error: Developer not initialized", file=sys.stderr)
|
|
297
|
-
return 1
|
|
298
|
-
|
|
299
|
-
dev_dir = get_workspace_dir(repo_root)
|
|
300
|
-
if not dev_dir:
|
|
301
|
-
print("Error: Workspace directory not found", file=sys.stderr)
|
|
302
|
-
return 1
|
|
303
|
-
|
|
304
|
-
index_file = dev_dir / "index.md"
|
|
305
|
-
today = datetime.now().strftime("%Y-%m-%d")
|
|
306
|
-
|
|
307
|
-
journal_file, current_num, current_lines = get_latest_journal_info(dev_dir)
|
|
308
|
-
current_session = get_current_session(index_file)
|
|
309
|
-
new_session = current_session + 1
|
|
310
|
-
|
|
311
|
-
session_content = generate_session_content(
|
|
312
|
-
new_session, title, commit, summary, extra_content, today
|
|
313
|
-
)
|
|
314
|
-
content_lines = len(session_content.splitlines())
|
|
315
|
-
|
|
316
|
-
print("========================================", file=sys.stderr)
|
|
317
|
-
print("ADD SESSION", file=sys.stderr)
|
|
318
|
-
print("========================================", file=sys.stderr)
|
|
319
|
-
print("", file=sys.stderr)
|
|
320
|
-
print(f"Session: {new_session}", file=sys.stderr)
|
|
321
|
-
print(f"Title: {title}", file=sys.stderr)
|
|
322
|
-
print(f"Commit: {commit}", file=sys.stderr)
|
|
323
|
-
print("", file=sys.stderr)
|
|
324
|
-
print(f"Current journal file: {FILE_JOURNAL_PREFIX}{current_num}.md", file=sys.stderr)
|
|
325
|
-
print(f"Current lines: {current_lines}", file=sys.stderr)
|
|
326
|
-
print(f"New content lines: {content_lines}", file=sys.stderr)
|
|
327
|
-
print(f"Total after append: {current_lines + content_lines}", file=sys.stderr)
|
|
328
|
-
print("", file=sys.stderr)
|
|
329
|
-
|
|
330
|
-
target_file = journal_file
|
|
331
|
-
target_num = current_num
|
|
332
|
-
|
|
333
|
-
if current_lines + content_lines > MAX_LINES:
|
|
334
|
-
target_num = current_num + 1
|
|
335
|
-
print(f"[!] Exceeds {MAX_LINES} lines, creating {FILE_JOURNAL_PREFIX}{target_num}.md", file=sys.stderr)
|
|
336
|
-
target_file = create_new_journal_file(dev_dir, target_num, developer, today)
|
|
337
|
-
print(f"Created: {target_file}", file=sys.stderr)
|
|
338
|
-
|
|
339
|
-
# Append session content
|
|
340
|
-
if target_file:
|
|
341
|
-
with target_file.open("a", encoding="utf-8") as f:
|
|
342
|
-
f.write(session_content)
|
|
343
|
-
print(f"[OK] Appended session to {target_file.name}", file=sys.stderr)
|
|
344
|
-
|
|
345
|
-
print("", file=sys.stderr)
|
|
346
|
-
|
|
347
|
-
# Update index.md
|
|
348
|
-
active_file = f"{FILE_JOURNAL_PREFIX}{target_num}.md"
|
|
349
|
-
if not update_index(index_file, dev_dir, title, commit, new_session, active_file, today):
|
|
350
|
-
return 1
|
|
351
|
-
|
|
352
|
-
print("", file=sys.stderr)
|
|
353
|
-
print("========================================", file=sys.stderr)
|
|
354
|
-
print(f"[OK] Session {new_session} added successfully!", file=sys.stderr)
|
|
355
|
-
print("========================================", file=sys.stderr)
|
|
356
|
-
print("", file=sys.stderr)
|
|
357
|
-
print("Files updated:", file=sys.stderr)
|
|
358
|
-
print(f" - {target_file.name if target_file else 'journal'}", file=sys.stderr)
|
|
359
|
-
print(" - index.md", file=sys.stderr)
|
|
360
|
-
|
|
361
|
-
return 0
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
# =============================================================================
|
|
365
|
-
# Main Entry
|
|
366
|
-
# =============================================================================
|
|
367
|
-
|
|
368
|
-
def main() -> int:
|
|
369
|
-
"""CLI entry point."""
|
|
370
|
-
parser = argparse.ArgumentParser(
|
|
371
|
-
description="Add a new session to journal file and update index.md"
|
|
372
|
-
)
|
|
373
|
-
parser.add_argument("--title", required=True, help="Session title")
|
|
374
|
-
parser.add_argument("--commit", default="-", help="Comma-separated commit hashes")
|
|
375
|
-
parser.add_argument("--summary", default="(Add summary)", help="Brief summary")
|
|
376
|
-
parser.add_argument("--content-file", help="Path to file with detailed content")
|
|
377
|
-
|
|
378
|
-
args = parser.parse_args()
|
|
379
|
-
|
|
380
|
-
extra_content = "(Add details)"
|
|
381
|
-
if args.content_file:
|
|
382
|
-
content_path = Path(args.content_file)
|
|
383
|
-
if content_path.is_file():
|
|
384
|
-
extra_content = content_path.read_text(encoding="utf-8")
|
|
385
|
-
elif not sys.stdin.isatty():
|
|
386
|
-
extra_content = sys.stdin.read()
|
|
387
|
-
|
|
388
|
-
return add_session(args.title, args.commit, args.summary, extra_content)
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
if __name__ == "__main__":
|
|
392
|
-
sys.exit(main())
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Common utilities for Trellis workflow scripts.
|
|
3
|
-
|
|
4
|
-
This module provides shared functionality used by other Trellis scripts.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import io
|
|
8
|
-
import sys
|
|
9
|
-
|
|
10
|
-
# =============================================================================
|
|
11
|
-
# Windows Encoding Fix (MUST be at top, before any other output)
|
|
12
|
-
# =============================================================================
|
|
13
|
-
# On Windows, stdout defaults to the system code page (often GBK/CP936).
|
|
14
|
-
# This causes UnicodeEncodeError when printing non-ASCII characters.
|
|
15
|
-
#
|
|
16
|
-
# Any script that imports from common will automatically get this fix.
|
|
17
|
-
# =============================================================================
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def _configure_stream(stream: object) -> object:
|
|
21
|
-
"""Configure a stream for UTF-8 encoding on Windows."""
|
|
22
|
-
# Try reconfigure() first (Python 3.7+, more reliable)
|
|
23
|
-
if hasattr(stream, "reconfigure"):
|
|
24
|
-
stream.reconfigure(encoding="utf-8", errors="replace") # type: ignore[union-attr]
|
|
25
|
-
return stream
|
|
26
|
-
# Fallback: detach and rewrap with TextIOWrapper
|
|
27
|
-
elif hasattr(stream, "detach"):
|
|
28
|
-
return io.TextIOWrapper(
|
|
29
|
-
stream.detach(), # type: ignore[union-attr]
|
|
30
|
-
encoding="utf-8",
|
|
31
|
-
errors="replace",
|
|
32
|
-
)
|
|
33
|
-
return stream
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if sys.platform == "win32":
|
|
37
|
-
sys.stdout = _configure_stream(sys.stdout) # type: ignore[assignment]
|
|
38
|
-
sys.stderr = _configure_stream(sys.stderr) # type: ignore[assignment]
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def configure_encoding() -> None:
|
|
42
|
-
"""
|
|
43
|
-
Configure stdout/stderr for UTF-8 encoding on Windows.
|
|
44
|
-
|
|
45
|
-
This is automatically called when importing from common,
|
|
46
|
-
but can be called manually for scripts that don't import common.
|
|
47
|
-
|
|
48
|
-
Safe to call multiple times.
|
|
49
|
-
"""
|
|
50
|
-
global sys
|
|
51
|
-
if sys.platform == "win32":
|
|
52
|
-
sys.stdout = _configure_stream(sys.stdout) # type: ignore[assignment]
|
|
53
|
-
sys.stderr = _configure_stream(sys.stderr) # type: ignore[assignment]
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
from .paths import (
|
|
57
|
-
DIR_WORKFLOW,
|
|
58
|
-
DIR_WORKSPACE,
|
|
59
|
-
DIR_TASKS,
|
|
60
|
-
DIR_ARCHIVE,
|
|
61
|
-
DIR_SPEC,
|
|
62
|
-
DIR_SCRIPTS,
|
|
63
|
-
FILE_DEVELOPER,
|
|
64
|
-
FILE_CURRENT_TASK,
|
|
65
|
-
FILE_TASK_JSON,
|
|
66
|
-
FILE_JOURNAL_PREFIX,
|
|
67
|
-
get_repo_root,
|
|
68
|
-
get_developer,
|
|
69
|
-
check_developer,
|
|
70
|
-
get_tasks_dir,
|
|
71
|
-
get_workspace_dir,
|
|
72
|
-
get_active_journal_file,
|
|
73
|
-
count_lines,
|
|
74
|
-
get_current_task,
|
|
75
|
-
get_current_task_abs,
|
|
76
|
-
set_current_task,
|
|
77
|
-
clear_current_task,
|
|
78
|
-
has_current_task,
|
|
79
|
-
generate_task_date_prefix,
|
|
80
|
-
)
|