Skip to content
This repository was archived by the owner on Feb 20, 2026. It is now read-only.

Commit c5aa8d2

Browse files
committed
chore: Cleanup and bump patch version to v5.0.1
1 parent ff6d982 commit c5aa8d2

25 files changed

Lines changed: 1390 additions & 1293 deletions

.github/workflows/publish.yml

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -35,34 +35,3 @@ jobs:
3535

3636
- name: Build
3737
run: npm run build
38-
39-
publish:
40-
needs: test
41-
runs-on: ubuntu-latest
42-
43-
permissions:
44-
contents: read
45-
packages: write
46-
id-token: write
47-
48-
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
49-
steps:
50-
- uses: actions/checkout@v4
51-
52-
- uses: actions/setup-node@v4
53-
with:
54-
node-version: '20'
55-
registry-url: 'https://registry.npmjs.org'
56-
57-
- name: Install dependencies
58-
run: npm ci
59-
60-
- name: Build
61-
run: npm run build
62-
63-
- name: Publish to npm
64-
run: |
65-
echo "Publishing @frugally3683/agent-loop-plugin@$(node -p "require('./package.json').version")"
66-
npm publish --access public
67-
env:
68-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.woodpecker.yml

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -80,30 +80,3 @@ steps:
8080
- install
8181
when:
8282
- event: [push, pull_request, manual, tag]
83-
84-
# ===========================================================================
85-
# Publish to Codeberg npm Registry (on tag events only)
86-
# Codeberg is the source of truth - packages are published here
87-
# ===========================================================================
88-
89-
publish:
90-
image: node:22-alpine
91-
environment:
92-
CODEBERG_TOKEN:
93-
from_secret: CODEBERG_TOKEN
94-
commands:
95-
- apk add --no-cache git
96-
- |
97-
echo "@nope-at:registry=https://codeberg.org/api/packages/nope-at/npm/" > .npmrc
98-
echo "//codeberg.org/api/packages/nope-at/npm/:_authToken=$CODEBERG_TOKEN" >> .npmrc
99-
cat .npmrc
100-
echo "Publishing to Codeberg npm registry..."
101-
npm publish --scope=@nope-at --access public
102-
depends_on:
103-
- typecheck
104-
- build
105-
- test
106-
- lint
107-
- format
108-
when:
109-
- event: tag

__tests__/goal-completion.test.ts

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/**
2+
* Tests for goal completion functionality (completeGoal/goal_done)
3+
*/
4+
5+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"
6+
import {
7+
createMockPluginContext,
8+
createMockFileSystem,
9+
setupMockFileSystem,
10+
} from "./goal-test-setup.js"
11+
import { createGoalManagement } from "../index.js"
12+
13+
describe("GoalManagement - Goal Completion", () => {
14+
let mockFsContext: ReturnType<typeof createMockFileSystem>
15+
let mockContext: ReturnType<typeof createMockPluginContext>
16+
17+
beforeEach(() => {
18+
vi.useFakeTimers()
19+
mockFsContext = createMockFileSystem()
20+
setupMockFileSystem(mockFsContext)
21+
mockContext = createMockPluginContext()
22+
vi.restoreAllMocks()
23+
})
24+
25+
afterEach(() => {
26+
vi.useRealTimers()
27+
vi.restoreAllMocks()
28+
})
29+
30+
it("should mark a goal as completed", async () => {
31+
const goalManagement = createGoalManagement(mockContext, {
32+
goalsBasePath: mockFsContext.basePath,
33+
})
34+
35+
// First create a goal
36+
await goalManagement.createGoal(
37+
"session-123",
38+
"Complete this goal",
39+
"Goal is done"
40+
)
41+
42+
// Then complete it
43+
const completedGoal = await goalManagement.completeGoal("session-123")
44+
45+
expect(completedGoal).toBeDefined()
46+
expect(completedGoal?.status).toBe("completed")
47+
expect(completedGoal?.completed_at).toBeDefined()
48+
})
49+
50+
it("should update goal storage when completing", async () => {
51+
const goalManagement = createGoalManagement(mockContext, {
52+
goalsBasePath: mockFsContext.basePath,
53+
})
54+
55+
// Reset write call counter for this specific test
56+
mockFsContext.writeCalls = []
57+
58+
// Create and complete goal
59+
await goalManagement.createGoal("session-123", "Storage test", "Done")
60+
await goalManagement.completeGoal("session-123")
61+
62+
// Verify writeFile was called for both operations
63+
const writeCallsForSession = mockFsContext.writeCalls.filter(
64+
call => call[0].includes("session-123")
65+
)
66+
expect(writeCallsForSession.length).toBeGreaterThanOrEqual(2)
67+
})
68+
69+
it("should return null when completing non-existent goal", async () => {
70+
const goalManagement = createGoalManagement(mockContext, {
71+
goalsBasePath: mockFsContext.basePath,
72+
})
73+
74+
const result = await goalManagement.completeGoal("non-existent-session")
75+
76+
expect(result).toBeNull()
77+
})
78+
79+
it("should set completed_at timestamp", async () => {
80+
const goalManagement = createGoalManagement(mockContext, {
81+
goalsBasePath: mockFsContext.basePath,
82+
})
83+
84+
// Create a goal
85+
await goalManagement.createGoal("session-123", "Timestamp test", "Done")
86+
87+
// Get the goal before completion
88+
const beforeComplete = await goalManagement.readGoal("session-123")
89+
90+
// Complete the goal
91+
await goalManagement.completeGoal("session-123")
92+
93+
// Get the goal after completion
94+
const afterComplete = await goalManagement.readGoal("session-123")
95+
96+
expect(beforeComplete?.completed_at).toBeNull()
97+
expect(afterComplete?.completed_at).toBeDefined()
98+
expect(afterComplete?.completed_at).not.toBeNull()
99+
})
100+
})

__tests__/goal-creation.test.ts

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/**
2+
* Tests for goal creation functionality (createGoal/goal_set)
3+
*/
4+
5+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"
6+
import {
7+
createMockPluginContext,
8+
createMockFileSystem,
9+
setupMockFileSystem,
10+
} from "./goal-test-setup.js"
11+
import { createGoalManagement } from "../index.js"
12+
13+
describe("GoalManagement - Goal Creation", () => {
14+
let mockFsContext: ReturnType<typeof createMockFileSystem>
15+
let mockContext: ReturnType<typeof createMockPluginContext>
16+
17+
beforeEach(() => {
18+
vi.useFakeTimers()
19+
mockFsContext = createMockFileSystem()
20+
setupMockFileSystem(mockFsContext)
21+
mockContext = createMockPluginContext()
22+
vi.restoreAllMocks()
23+
})
24+
25+
afterEach(() => {
26+
vi.useRealTimers()
27+
vi.restoreAllMocks()
28+
})
29+
30+
it("should create a new goal with active status", async () => {
31+
const goalManagement = createGoalManagement(mockContext, {
32+
goalsBasePath: mockFsContext.basePath,
33+
})
34+
35+
const goal = await goalManagement.createGoal(
36+
"session-123",
37+
"Complete the project setup",
38+
"All setup tasks are done"
39+
)
40+
41+
expect(goal).toBeDefined()
42+
expect(goal.title).toBe("Complete the project setup")
43+
expect(goal.done_condition).toBe("All setup tasks are done")
44+
expect(goal.status).toBe("active")
45+
expect(goal.created_at).toBeDefined()
46+
expect(goal.completed_at).toBeNull()
47+
})
48+
49+
it("should create a goal with optional description", async () => {
50+
const goalManagement = createGoalManagement(mockContext, {
51+
goalsBasePath: mockFsContext.basePath,
52+
})
53+
54+
const goal = await goalManagement.createGoal(
55+
"session-123",
56+
"Build the feature",
57+
"Feature is deployed to production",
58+
"This is a detailed description of the goal"
59+
)
60+
61+
expect(goal.description).toBe("This is a detailed description of the goal")
62+
expect(goal.title).toBe("Build the feature")
63+
})
64+
65+
it("should generate goal with ISO timestamp", async () => {
66+
const goalManagement = createGoalManagement(mockContext, {
67+
goalsBasePath: mockFsContext.basePath,
68+
})
69+
70+
const goal = await goalManagement.createGoal(
71+
"session-123",
72+
"Test goal",
73+
"Test is passing"
74+
)
75+
76+
// Verify timestamp is valid ISO format
77+
const timestamp = new Date(goal.created_at)
78+
expect(timestamp.toISOString()).toBe(goal.created_at)
79+
expect(timestamp.getTime()).toBeGreaterThan(0)
80+
})
81+
82+
it("should store goal in file system", async () => {
83+
const goalManagement = createGoalManagement(mockContext, {
84+
goalsBasePath: mockFsContext.basePath,
85+
})
86+
87+
await goalManagement.createGoal(
88+
"session-123",
89+
"Store this goal",
90+
"Goal is stored"
91+
)
92+
93+
// Verify writeFile was called
94+
const fs = await import("node:fs/promises")
95+
expect(fs.writeFile).toHaveBeenCalled()
96+
expect(fs.mkdir).toHaveBeenCalled()
97+
})
98+
99+
it("should return the created goal", async () => {
100+
const goalManagement = createGoalManagement(mockContext, {
101+
goalsBasePath: mockFsContext.basePath,
102+
})
103+
104+
const goal = await goalManagement.createGoal(
105+
"session-123",
106+
"Returnable goal",
107+
"Goal can be returned"
108+
)
109+
110+
expect(goal).toHaveProperty("title")
111+
expect(goal).toHaveProperty("done_condition")
112+
expect(goal).toHaveProperty("status")
113+
expect(goal).toHaveProperty("created_at")
114+
expect(goal).toHaveProperty("completed_at")
115+
})
116+
})

__tests__/goal-edge-cases.test.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/**
2+
* Tests for edge cases in goal management
3+
*/
4+
5+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"
6+
import {
7+
createMockPluginContext,
8+
createMockFileSystem,
9+
setupMockFileSystem,
10+
} from "./goal-test-setup.js"
11+
import { createGoalManagement } from "../index.js"
12+
13+
describe("GoalManagement - Edge Cases", () => {
14+
let mockFsContext: ReturnType<typeof createMockFileSystem>
15+
let mockContext: ReturnType<typeof createMockPluginContext>
16+
17+
beforeEach(() => {
18+
vi.useFakeTimers()
19+
mockFsContext = createMockFileSystem()
20+
setupMockFileSystem(mockFsContext)
21+
mockContext = createMockPluginContext()
22+
vi.restoreAllMocks()
23+
})
24+
25+
afterEach(() => {
26+
vi.useRealTimers()
27+
vi.restoreAllMocks()
28+
})
29+
30+
it("should handle goal with special characters in title", async () => {
31+
const goalManagement = createGoalManagement(mockContext, {
32+
goalsBasePath: mockFsContext.basePath,
33+
})
34+
35+
const goal = await goalManagement.createGoal(
36+
"session-123",
37+
"Goal with \"quotes\" and 'apostrophes'",
38+
"Done"
39+
)
40+
41+
expect(goal.title).toContain("quotes")
42+
expect(goal.title).toContain("apostrophes")
43+
})
44+
45+
it("should handle goal with empty description", async () => {
46+
const goalManagement = createGoalManagement(mockContext, {
47+
goalsBasePath: mockFsContext.basePath,
48+
})
49+
50+
const goal = await goalManagement.createGoal(
51+
"session-123",
52+
"No description",
53+
"Done"
54+
)
55+
56+
expect(goal.description).toBeUndefined()
57+
})
58+
59+
it("should handle very long goal title", async () => {
60+
const goalManagement = createGoalManagement(mockContext, {
61+
goalsBasePath: mockFsContext.basePath,
62+
})
63+
64+
const longTitle = "A".repeat(1000)
65+
const goal = await goalManagement.createGoal(
66+
"session-123",
67+
longTitle,
68+
"Done"
69+
)
70+
71+
expect(goal.title.length).toBe(1000)
72+
})
73+
})

0 commit comments

Comments
 (0)