Add --pipeline flag and improve log file naming

- Add --pipeline flag for explicit pipeline/non-interactive mode
- Change log file naming from base36 to YYYYMMDD-HHmmss-random format
- Update --task description to clarify it's an alternative to --issue
- Add tests for new timestamp-based session ID format

Resolves #28
This commit is contained in:
nrslib 2026-02-01 08:40:18 +09:00
parent 9ac4f374b8
commit cf393312a2
7 changed files with 27 additions and 12 deletions

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "takt",
"version": "0.3.6",
"version": "0.3.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "takt",
"version": "0.3.6",
"version": "0.3.7",
"license": "MIT",
"dependencies": {
"@anthropic-ai/claude-agent-sdk": "^0.2.19",

View File

@ -1,6 +1,6 @@
{
"name": "takt",
"version": "0.3.6",
"version": "0.3.7",
"description": "TAKT: Task Agent Koordination Tool - AI Agent Workflow Orchestration",
"main": "dist/index.js",
"types": "dist/index.d.ts",

View File

@ -208,7 +208,7 @@ steps:
permission_mode: acceptEdits
rules:
- condition: AI issues fixed
next: reviewers
next: ai_review
- condition: Cannot proceed, insufficient info
next: plan
instruction_template: |

View File

@ -204,7 +204,7 @@ steps:
permission_mode: acceptEdits
rules:
- condition: AI問題の修正完了
next: reviewers
next: ai_review
- condition: 判断できない、情報不足
next: plan
instruction_template: |

View File

@ -52,6 +52,11 @@ describe('generateSessionId', () => {
expect(typeof id).toBe('string');
expect(id.length).toBeGreaterThan(0);
});
it('should follow the new timestamp format', () => {
const id = generateSessionId();
expect(id).toMatch(/^\d{8}-\d{6}-[a-z0-9]{6}$/);
});
});
describe('createSessionLog', () => {

View File

@ -260,7 +260,8 @@ program
.option('--repo <owner/repo>', 'Repository (defaults to current)')
.option('--provider <name>', 'Override agent provider (claude|codex|mock)')
.option('--model <name>', 'Override agent model')
.option('-t, --task <string>', 'Task content (triggers pipeline/non-interactive mode)')
.option('-t, --task <string>', 'Task content (as alternative to GitHub issue)')
.option('--pipeline', 'Pipeline mode: non-interactive, no worktree, direct branch creation')
.option('--skip-git', 'Skip branch creation, commit, and push (pipeline mode)')
.option('--create-worktree <yes|no>', 'Skip the worktree prompt by explicitly specifying yes or no');
@ -268,9 +269,9 @@ program
program.hook('preAction', async () => {
resolvedCwd = resolve(process.cwd());
// Pipeline mode: triggered by --task (non-interactive)
// Pipeline mode: triggered by --pipeline flag
const rootOpts = program.opts();
pipelineMode = rootOpts.task !== undefined;
pipelineMode = rootOpts.pipeline === true;
await initGlobalDirs({ nonInteractive: pipelineMode });
initProjectDirs(resolvedCwd);
@ -390,11 +391,11 @@ program
createWorktree: createWorktreeOverride,
};
// --- Pipeline mode (non-interactive): triggered by --task ---
// --- Pipeline mode (non-interactive): triggered by --pipeline ---
if (pipelineMode) {
const exitCode = await executePipeline({
issueNumber: opts.issue as number | undefined,
task: opts.task as string,
task: opts.task as string | undefined,
workflow: (opts.workflow as string | undefined) ?? DEFAULT_WORKFLOW_NAME,
branch: opts.branch as string | undefined,
autoPr: opts.autoPr === true,
@ -413,6 +414,13 @@ program
// --- Normal (interactive) mode ---
// Resolve --task option to task text
const taskFromOption = opts.task as string | undefined;
if (taskFromOption) {
await selectAndExecuteTask(resolvedCwd, taskFromOption, selectOptions, agentOverrides);
return;
}
// Resolve --issue N to task text (same as #N)
const issueFromOption = opts.issue as number | undefined;
if (issueFromOption) {

View File

@ -195,7 +195,10 @@ export function loadNdjsonLog(filepath: string): SessionLog | null {
/** Generate a session ID */
export function generateSessionId(): string {
const timestamp = Date.now().toString(36);
const now = new Date();
const timestamp = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}-${String(
now.getHours(),
).padStart(2, '0')}${String(now.getMinutes()).padStart(2, '0')}${String(now.getSeconds()).padStart(2, '0')}`;
const random = Math.random().toString(36).slice(2, 8);
return `${timestamp}-${random}`;
}
@ -333,4 +336,3 @@ export function updateLatestPointer(
writeFileAtomic(latestPath, JSON.stringify(pointer, null, 2));
}