@markjaquith/agency 2.43.1 → 2.44.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markjaquith/agency",
3
- "version": "2.43.1",
3
+ "version": "2.44.0",
4
4
  "description": "Manage agentic work across repositories with durable workbases",
5
5
  "keywords": [
6
6
  "agents",
@@ -59,6 +59,29 @@ describe("integration command", () => {
59
59
  expect(logs.join("\n")).toContain("global config")
60
60
  })
61
61
 
62
+ test("formats integration status for people", async () => {
63
+ const logs = await captureLogs(() =>
64
+ runTestEffect(integration({ subcommand: "status", cwd: root })),
65
+ )
66
+
67
+ expect(logs.join("\n")).toBe(`Integration status: ${root}
68
+
69
+ Agent instructions: missing
70
+ Path: .agency/AGENTS.md
71
+ Managed workbase instructions need synchronization.
72
+ Action: Run 'agency integration sync' to restore managed instructions.
73
+
74
+ OpenCode config: missing
75
+ Path: .opencode/opencode.jsonc
76
+ Agency OpenCode launches cannot load current Agency instructions or whole-workbase access.
77
+ Action: Run 'agency integration sync' to install Agency instructions and whole-workbase OpenCode access.
78
+
79
+ OpenCode /agency command: missing
80
+ Path: .opencode/command/agency.md
81
+ The managed OpenCode /agency command needs synchronization.
82
+ Action: Run 'agency integration sync' to install the managed /agency command.`)
83
+ })
84
+
62
85
  test("explicitly synchronizes integration files", async () => {
63
86
  const logs = await captureLogs(() =>
64
87
  runTestEffect(integration({ subcommand: "sync", cwd: root, json: true })),
@@ -78,4 +101,24 @@ describe("integration command", () => {
78
101
  await Bun.file(join(root, ".opencode/command/agency.md")).exists(),
79
102
  ).toBe(true)
80
103
  })
104
+
105
+ test("formats integration sync results for people", async () => {
106
+ const logs = await captureLogs(() =>
107
+ runTestEffect(integration({ subcommand: "sync", cwd: root })),
108
+ )
109
+
110
+ expect(logs.join("\n")).toBe(`Integration sync: ${root}
111
+
112
+ Agent instructions: synced
113
+ Path: .agency/AGENTS.md
114
+ Managed workbase instructions are current.
115
+
116
+ OpenCode config: synced
117
+ Path: .opencode/opencode.jsonc
118
+ Agency's managed OpenCode launch config is ready to load Agency instructions and provide whole-workbase read access.
119
+
120
+ OpenCode /agency command: synced
121
+ Path: .opencode/command/agency.md
122
+ Agency's managed OpenCode /agency command is current.`)
123
+ })
81
124
  })
@@ -1,4 +1,5 @@
1
1
  import { Effect } from "effect"
2
+ import { relative } from "node:path"
2
3
  import type { BaseCommandOptions } from "../utils/command"
3
4
  import { IntegrationService } from "../services/IntegrationService"
4
5
  import { createLoggers } from "../utils/effect"
@@ -8,6 +9,41 @@ interface IntegrationOptions extends BaseCommandOptions {
8
9
  readonly json?: boolean
9
10
  }
10
11
 
12
+ interface IntegrationResult {
13
+ readonly root: string
14
+ readonly files: readonly {
15
+ readonly name: "agents" | "opencode" | "opencode-command"
16
+ readonly path: string
17
+ readonly state: string
18
+ readonly diagnostic: string
19
+ readonly remediation: string | null
20
+ readonly changed?: boolean
21
+ }[]
22
+ }
23
+
24
+ const integrationNames = {
25
+ agents: "Agent instructions",
26
+ opencode: "OpenCode config",
27
+ "opencode-command": "OpenCode /agency command",
28
+ } as const
29
+
30
+ const logHumanResult = (
31
+ log: (message: string) => void,
32
+ subcommand: "status" | "sync",
33
+ result: IntegrationResult,
34
+ ) => {
35
+ log(`Integration ${subcommand}: ${result.root}`)
36
+ for (const file of result.files) {
37
+ log("")
38
+ log(
39
+ `${integrationNames[file.name]}: ${file.changed ? "synced" : file.state}`,
40
+ )
41
+ log(` Path: ${relative(result.root, file.path)}`)
42
+ log(` ${file.diagnostic}`)
43
+ if (file.remediation) log(` Action: ${file.remediation}`)
44
+ }
45
+ }
46
+
11
47
  export const integration = (options: IntegrationOptions) =>
12
48
  Effect.gen(function* () {
13
49
  const service = yield* IntegrationService
@@ -21,10 +57,7 @@ export const integration = (options: IntegrationOptions) =>
21
57
  log(JSON.stringify(result, null, 2))
22
58
  return
23
59
  }
24
- for (const file of result.files) {
25
- log(`${file.name}\t${file.state}\t${file.path}\t${file.diagnostic}`)
26
- if (file.remediation) log(` Remediation: ${file.remediation}`)
27
- }
60
+ logHumanResult(log, "status", result)
28
61
  return
29
62
  }
30
63
 
@@ -34,12 +67,7 @@ export const integration = (options: IntegrationOptions) =>
34
67
  log(JSON.stringify(result, null, 2))
35
68
  return
36
69
  }
37
- for (const file of result.files) {
38
- log(
39
- `${file.name}\t${file.changed ? "synced" : file.state}\t${file.path}\t${file.diagnostic}`,
40
- )
41
- if (file.remediation) log(` Remediation: ${file.remediation}`)
42
- }
70
+ logHumanResult(log, "sync", result)
43
71
  return
44
72
  }
45
73