--- name: act-master description: Install and use act-master with a CLI-generated action registry and Vue 3 plugin setup. Apply when creating, calling, organizing, testing, or debugging actions in Vue 3 or other TypeScript applications. --- # Act-Master development skill Act-Master separates application use cases (actions, also called acts) from the view. Its core works without a framework; Vue integration is a separate import. This reference targets act-master 2.9.0 and act-master-cli 1.5.0 in this repository. For other versions, check the installed exports and implementation first. ## Start with the existing application - Inspect package.json, the lockfile, .act-master.yaml, the application bootstrap, and nearby actions. Follow the project's package manager and naming conventions. - Use `act-master` for the core, `act-master/vue` for Vue integration, and `act-master/test` for test helpers. Do not mix examples from the old `vue-act-master` package or the documentation's `/v1/` section into new code. - Reuse the existing initialization, registry, services, and error policy. Add only the actions needed for the requested use case. - For Vue 3, install with `app.use(VueActMaster, options)` and then call `app.mount('#app')`. Use the Vue setup below. `app.init` is not a Vue API; `act.init` returns an ActMaster instance, which has no `mount` method. - Always generate the application's `actions` registry with act-master-cli and import its exported array. Write action source files, not an inline registry or a handwritten substitute for the generated file. Small isolated unit tests may supply action instances directly to ActTest, as shown later. - `act` is an instance-access helper, not a namespace of action constructors. There is no `act.MustAddAction`, `MustAddAction`, or action factory by that name. Define real exported classes or named fn2act wrappers in matched source files. ## Required setup: install, define actions, generate, then connect Vue Complete these steps in order for a new application. For an existing application, reuse its setup and regenerate after changing action files. Commands below use npm; use the equivalent local CLI invocation for the project's package manager. ### 1. Install and configure the CLI Run from the application root containing package.json: ```sh npm install act-master ``` If there is no .act-master.yaml or .act-master.yml yet, run: ```sh npx act-master-cli init ``` The CLI is included as a dependency; it is a development tool, not an application runtime import. `init` is interactive: it creates the config and can add an `act:gen` script and `src/act/common/OnError.act.ts`. It does not generate the registry. Keep an existing config instead of running init over it. The CLI declares Node.js >=20; also respect the application's runtime requirements. If an interactive prompt cannot be answered with the available tooling, create the config below and the actual action source files yourself, then run `g`. The registry must still be produced by the CLI. Example config supporting both shared and feature-local actions: ```yaml config: src: './src' alias: '@/' actionsPatterns: - '**/act/**/*.act.ts' generate: actionsIndexFile: 'act/generated/actions.ts' prefixText: '/* This is a generated file. Do not edit manually. */' ``` The default pattern is `act/**/*.act.ts`, which only covers the top-level act folder under src. Extend it when placing acts inside features. The alias must also resolve in TypeScript and the bundler; the CLI does not configure them. Run generation from the config directory: this CLI resolves src against the working directory, even when it finds the config in a parent directory. ### 2. Create actual action source files Before generating, create the actions requested by the user. This minimal example defines a counter action and an error handler. Reuse an existing OnError action, including the CLI scaffold, rather than adding a second action with that name. ```ts // src/act/IncrementCounter.act.ts import type { ActMasterAction } from 'act-master'; export class IncrementCounter implements ActMasterAction { readonly name = 'IncrementCounter'; exec(value: number): number { return value + 1; } } ``` If no error handler exists, create this file before generation: ```ts // src/act/common/OnError.act.ts import { CancelledAct, type ActMasterAction } from 'act-master'; export class OnError implements ActMasterAction { readonly name = 'OnError'; exec(error: unknown): void { if (CancelledAct.is(error)) return; // field feedback belongs to the caller console.error('[ActMaster]', error); // replace with the app's reporting service } } ``` CLI-compatible class actions have: - One named exported action class per matched file, with a `name` property and an `exec` method declared on the class. The CLI creates `new ClassName()` with no arguments. Supply services through ActMaster DI instead of required constructor arguments so the action remains compatible with generation. - A literal event name, preferably `readonly name = 'GetUser'`. Do not widen it to `string`. Event names must be unique across the whole application; class names imported into the generated registry must also be unambiguous. - Explicit parameter types and an explicit return type on `exec`. Use precise domain types, including cancellation when applicable. Exported named fn2act wrappers are also supported; see the function example below. ### 3. Generate and inspect the registry (required) After creating or changing the action source files, run: ```sh npx act-master-cli g ``` For the config above, the CLI writes `src/act/generated/actions.ts`. Open this actual generated file and verify that its exported `actions` includes the requested acts and the handler whose event name is OnError. The scaffolded handler's class may be called OnErrorAct; its event name is still OnError. The output path is `config.src` + `generate.actionsIndexFile`. With the example alias, import it as `import { actions } from '@/act/generated/actions'`. If the project uses another output path, derive the import from its real config. Use the imported array directly as the `actions` option. Do not recreate, map, or manually construct the application's registry in main.ts, and do not copy an example array into the generated output file. If an act is missing, fix its source/export or the scan pattern and rerun the CLI. If generation fails or the CLI cannot be run, report setup as incomplete and resolve the blocker; do not replace generation with a handwritten registry or claim that generation succeeded. Installing the package and running `init` alone are not a completed setup. For repeatable local and CI use, add `"act:gen": "act-master-cli g"` to scripts. Run generation after adding, deleting, moving, renaming, or changing the signature of an act, and before the application's type check/build. Preserve existing scripts when adding generation to a build sequence. The generated file includes instances and TypeScript module augmentation for event names, arguments, results, subscriptions, and the `$act` proxy. Keep it in the TypeScript program. Do not edit generated overloads or widen the inferred actions array to `ActMasterAction[]`, which loses the concrete action types. ### 4. Connect Vue 3 with app.use, then mount the Vue app Use Vue 3.3 or newer. This is the standard Vue bootstrap; do not combine it with the non-Vue `act.init` example later in this document. ```ts // src/main.ts import { createApp } from 'vue'; import { VueActMaster, type ActMasterOptions } from 'act-master/vue'; import App from './App.vue'; import { actions } from '@/act/generated/actions'; const options: ActMasterOptions = { actions, errorHandlerEventName: 'OnError', }; const app = createApp(App); app.use(VueActMaster, options); app.mount('#app'); ``` The OnError action must already exist in the generated array before configuring it as the handler. Preserve the application's existing CSS imports and plugin calls such as `app.use(createPinia())` and `app.use(router)`. Add ActMaster to that same `app` before its existing mount call; do not create a second app or remove other plugins. Pinia and the router are not requirements of ActMaster. `app` is the Vue application; `VueActMaster` is its plugin. The plugin initializes ActMaster internally. Use `act()` in components and actions after plugin setup, but keep `act.init(...)` out of this Vue bootstrap. Only the Vue app is mounted. #### What ActMasterOptions configures These options configure ActMaster, not Vue, Pinia, or the router: | Option | Meaning | When to include it | | --- | --- | --- | | `actions` | Registers the executable actions and their event names. | Import the CLI-generated array for the application. It contains action instances, not service dependencies. | | `errorHandlerEventName` | Names the registered action that receives errors when an action has no applicable local `$onError` handler. | Include it when the application has a global error policy. `'OnError'` is an example event name, not a built-in handler; that action must exist. Without a configured handler, unhandled execution errors reject the returned Promise. | | `di` | Registers shared dependencies by key for actions to retrieve with `act().getDI(key)`. | Optional. Include only real dependencies consumed by the application's actions; omit it when none are needed. | | `autoUnsubscribeCallback` | A custom integration hook called on subscription with `{ context, listener, eventName }`. | Optional advanced integration. It does not perform cleanup on its own. For Vue 3 components, prefer the documented lifecycle hooks or useAutoUnsubscribe instead of adding this option during installation. | DI means dependency injection: the application supplies an action's collaborators from outside instead of the action constructing them itself. For example, a GetUser action contains the use case, while an existing usersApi service handles communication with the backend. main.ts connects the two by registering that service; the action retrieves it under the same key. This lets tests supply a controlled service double without changing the action's business logic. In ActMaster, DI is a simple shared key-to-value map. It does not generate an API client, implement HTTP requests, instantiate registered classes, or persist application state. Keys such as `usersApi` are chosen by the application and are not built-in dependencies. This container is accessed through ActMaster's getDI, not through Vue's inject(). Only if the actual actions need usersApi and the project has its implementation, import that service into the existing bootstrap and add it to the options: ```ts // In the existing main.ts; use the project's actual service module path. import { VueActMaster, type ActMasterOptions } from 'act-master/vue'; import { actions } from '@/act/generated/actions'; import { usersApi } from '@/services/users-api'; const options: ActMasterOptions = { actions, errorHandlerEventName: 'OnError', di: { usersApi }, }; app.use(VueActMaster, options); // app is the existing Vue application ``` Do not add usersApi, a GetUser action, or `di: {}` just to install ActMaster. Inspect the requested use case and existing service modules first. If a real service must be implemented, use the application's actual backend/client contract. If that contract is unknown, identify the missing information rather than inventing an endpoint or returning fabricated users as a working service. An implementation that returns `Promise.resolve({ id, name: 'User ' + id })` is a mock: it makes no backend request. Use such service doubles in isolated tests or explicitly requested demo/mock mode, not as an implicit installation step. Define service implementations in service modules and keep bootstrap focused on wiring their imports together. `as UsersApi` is only a TypeScript assertion; it neither implements the service nor validates its data. Prefer a `: UsersApi` annotation or `satisfies UsersApi` on the real service definition to check its shape, and validate external data at the service boundary. Do not use assertions to conceal an unfinished adapter. ### 5. Verify setup before declaring it complete Run the application's existing type check and build after generation. Confirm that the generated import resolves, requested actions and OnError appear in the registry, and Vue composables can use the installed plugin. A component can then call the example action through the public dispatcher: ```ts // Inside a component after VueActMaster has been installed import { act } from 'act-master'; const next = await act().exec('IncrementCounter', 0); // 1; number | null ``` Do not infer success solely from files being present: verify the commands ran successfully and the application's setup matches the generated output. ## Place logic according to ownership ```text src/ main.ts # composition root: services + plugin setup services/users-api.ts # transport adapter and UsersApi contract act/ common/OnError.act.ts # application-wide error handling generated/actions.ts # generated registry, no business logic features/users/ act/GetUser.act.ts # use case owned by the users feature components/UserProfile.vue # input, rendering, local UI state ``` Place feature-specific acts beside their feature or component in an act folder. Place reusable cross-feature acts in src/act. Runtime registration does not require a particular folder; the generator's configured patterns determine discovery. Preserve an established layout rather than moving unrelated files. Keep each act focused on one application operation. Put transport details in service adapters and reusable pure calculations in ordinary functions. Components call acts and render their results; they retain presentation state such as open dialogs or loading indicators. An action does not need to wrap every UI change. Use a store when persistent shared state is needed: subscriptions are events, not a replaying state store. ## Initialize once at the composition root ActMaster is a singleton per loaded module. Repeated constructor/init calls reuse the existing instance and do not reconfigure its options. Do not initialize in components, action constructors, or per operation. Add application actions through their source files and regenerate the registry; initialize with its imported `actions` array. Avoid importing the generated registry back into actions, which creates an initialization cycle. For SSR/multiple apps, do not assume a fresh ActMaster per request or mount. The module-level singleton can share services and data across requests. In a client application with SSR, initialize on the client; server-side use needs an explicit isolation design rather than repeated `new ActMaster()` calls. ## Write a typed action and supply dependencies This is an optional users-feature example, not a list of services or actions required for installation. Apply it only when implementing that use case. The application adapter implements this contract and exports its `usersApi` instance. It handles HTTP status checks, response validation, and transport errors. For the GetUser example below, import that real usersApi instance in main.ts and add `di: { usersApi }` to the existing Vue plugin options alongside `actions`. ```ts // src/services/users-api.ts (contract; supply an implementation in this module) export interface User { id: string; name: string; } export interface UsersApi { getUser(id: string): Promise; } ``` These interfaces describe the service contract only; they do not create or export a usersApi implementation. Reuse or implement the real adapter against the project's backend contract before importing usersApi in main.ts. ```ts // src/features/users/act/GetUser.act.ts import { act, CancelledAct, type ActMasterAction } from 'act-master'; import type { User, UsersApi } from '@/services/users-api'; export class GetUser implements ActMasterAction { readonly name = 'GetUser'; $validate(id: string): true | CancelledAct { return id.trim() ? true : new CancelledAct('User ID is required', { id: 'Required' }); } async exec(id: string): Promise { const api = act().getDI('usersApi'); return api.getUser(id); } } ``` Use runtime validation appropriate to the input boundary; TypeScript annotations do not validate external data. `$validate` receives the same arguments as exec and may be async. Only `true` permits execution. Return a CancelledAct for an expected validation failure, and include it in exec's declared result union: generated result types are derived from exec, not from $validate. DI stores the values you supply. Pass a service instance or object, not a class unless the action intentionally consumes the constructor/static API. Register dependencies before execution via `di` or `act().setDI(key, value)`. `getDI` is a type assertion at the boundary, not a runtime check; a missing key returns undefined. Treat setDI as registration, not a service replacement API. In projects using legacy TypeScript decorators, `@UseDI('usersApi') private api!: UsersApi` is another supported option (`UseDI` is from `act-master`). It requires a build pipeline supporting legacy decorators, with `experimentalDecorators: true`. Without decorators, the getDI example above works. In this version `$di` appears in the interface but is not injected by the runtime; declaring `$di!` alone will not work. No BaseActMasterAction class is exported. The CLI also collects exported fn2act / functionToAction calls imported from act-master, including import aliases. For example: ```ts // src/act/get-balance.act.ts import { fn2act } from 'act-master'; export const getBalance = fn2act(function GetBalance(day: string): number { return day === '2026.01.01' ? 100 : 0; }); ``` After generation and registration, act().exec('GetBalance', '2026.01.01') has type Promise; 'GetBal' or a numeric day is a type error. The event name comes from the function, not the export variable. Default exports wrapping a named function and references to functions declared in the same file also work. Keep explicit parameter/return types and one action per file; class discovery takes precedence when a file also contains an action class. The helper preserves the exec signature; the CLI supplies the literal name that TypeScript cannot infer from Function.name. Without the generated registry, its name is string. Plain object actions and bare unexported helper calls are not collected. For application actions, use an exported class or fn2act wrapper and rerun the CLI instead of bypassing generation with manual registration. Preserve function names when minifying (e.g. esbuild keepNames) because the helper rejects anonymous functions before the registry executes. ## Execute and distinguish every outcome `act().exec('GetUser', id)` always returns a Promise. The first argument is the action's `name`, not its class name or filename. `$act.GetUser(id)` is equivalent when importing `$act` from `act-master`; generated types make both forms typed. In Vue Options API, the installed plugin also exposes `this.$act.exec(...)`. Call through the dispatcher in application code. Calling `new GetUser().exec()` directly skips validation, notifications, error routing, and execution controls. | Outcome | Caller observes | Subscriptions / $watch for the original act | | --- | --- | --- | | Normal return | Returned value, including undefined for void | Notified with that value | | Return CancelledAct from exec | The cancellation object | Not notified | | $validate returns CancelledAct | The cancellation object; exec is skipped | Not notified | | Throw/reject with configured handler | null | Not notified of success | | Throw/reject without a handler | Rejected Promise | Not notified of success | | Unknown action name | Rejected Promise (NotFoundActionError) | No action runs; global handler does not handle this error | Reserve null for handled failure where possible. An act that deliberately returns null succeeds and notifies listeners, so its caller cannot distinguish that value from a handled error using null alone. A void success is undefined: avoid `if (!result)` as a generic failure check because 0, false, and empty strings can also be valid results. ```ts // Inside Vue setup; the application is already initialized. import { ref } from 'vue'; import { act, CancelledAct } from 'act-master'; import type { User } from '@/services/users-api'; const user = ref(null); const loading = ref(false); const message = ref(''); async function loadUser(id: string): Promise { if (loading.value) return; loading.value = true; message.value = ''; try { const result = await act().exec('GetUser', id); if (result === null) return; // handled by the configured error action if (result instanceof CancelledAct) { message.value = result.reason; return; } user.value = result; } catch (error: unknown) { // Covers errors without a handler, including a registration mistake. message.value = error instanceof Error ? error.message : 'Unable to load user'; } finally { loading.value = false; } } ``` `CancelledAct.is(value)` also recognizes marker-based cancellations, including those constructed from an Error. It currently returns boolean, not a TypeScript type predicate. Use a typed wrapper when you need that broader check and type narrowing together. `instanceof` above is sufficient for the plain CancelledAct instances created by the example. ## Handle errors deliberately Create the handler as an action source file and regenerate, then set global `errorHandlerEventName` or per-action `$onError = 'OnError'`. A local $onError takes precedence for thrown errors. Handlers receive the error value, not the original argument list or an automatic action-name envelope; add domain context when constructing an Error. Use the OnError source example from the required setup above, or adapt the project's existing handler. Keep its event name in the generated registry. - For expected cancellation, return CancelledAct; throwing it enters exception routing instead. Returning it from exec does not invoke error handlers. - Validation is a distinct path in this version: a non-true $validate result is returned unchanged and sent to BOTH global and local handlers when configured, even if both names are equal. Avoid duplicate reporting; normalize/ignore validation cancellations in handlers as appropriate. - Error-handler actions are started without awaiting their completion. The original call returns null, not the handler's return value. Do not use a handler as an awaited fallback/recovery function. Perform required recovery explicitly inside the action instead. - Handlers should complete reliably, contain failures of their own reporting calls, and avoid recursive error-action cycles. A missing handler is a registry bug, not a successful recovery. - Let unexpected service errors reach the chosen error policy. Catch locally when adding context or performing meaningful recovery, not to return a fake success. For fetch adapters, check response.ok: HTTP errors do not reject fetch by default. ## Compose actions, cancellation, and concurrency Call another act through `act().exec(...)` and await it when the next step requires its result. This also keeps generated types and execution controls on the public dispatch path: ```ts // src/features/users/act/GetUserName.act.ts import { act, CancelledAct, type ActMasterAction } from 'act-master'; export class GetUserName implements ActMasterAction { readonly name = 'GetUserName'; async exec(id: string): Promise { const result = await act().exec('GetUser', id); if (result === null) { return new CancelledAct('GetUser failed and its error was handled'); } if (result instanceof CancelledAct) return result; return result.name; } } ``` A cancellation does not automatically interrupt JavaScript after an awaited call. Return it (or stop explicitly) in every dependent step. Returning null from the parent would count as the parent's normal success and notify its subscribers. CancelledAct does not abort an HTTP request or roll back completed side effects; use the service's cancellation/transaction mechanism when needed. Use `$watch = ['GetUser']` for an independent reaction: after GetUser succeeds, the watching act receives its result as the sole argument. Watchers start without being awaited; awaiting GetUser does not await them. Avoid self-watching and indirect cycles. Use explicit composition when order or completion matters. `$isSingleton = true` merges overlapping calls to the same act into one in-flight execution. It is keyed only by action name: the first caller's arguments win. It is not a cache, debounce, queue, or per-ID deduplication. Do not apply it to parameter-dependent requests or writes unless ignoring later inputs is intended. The runtime also supports an injected `$emit` property, assigned before exec runs. In this version the directly injected emitter uses an internal dispatch path that bypasses exec's singleton/progress tracking. With generated types, putting EmitAction on a class in the registry can create a circular type reference through ActGenerated. Prefer the public `act().exec(...)` pattern above in generated projects rather than weakening types to any or editing generated declarations. Action instances are reused. Keep per-call data in local variables and pass it as arguments; mutable fields can mix concurrent callers. Handle stale responses in the calling feature when multiple different requests can overlap. ## Subscribe with a clear owner and cleanup `subscribe`/`on` observes future successful results, not inputs or a stored last value. Register before the event you need. With generated types, prefer `on`: in this version subscribe uses Parameters of an overloaded type and can accept only the last generated event name, while on retains all event overloads. At runtime they are aliases. `unsubscribe`/`off` needs the same callback reference; the returned unsubscribe function is often simpler. ```ts // Inside Vue setup import { onBeforeUnmount } from 'vue'; import { act } from 'act-master'; const off = act().on('GetUser', (user) => { console.log('User loaded', user); }); onBeforeUnmount(off); ``` The third argument can register cleanup directly: `act().on('GetUser', callback, onBeforeUnmount)`. For a group, pass the same unique object or Symbol as the third argument, then call `act().subsList.clear(key)` when its owner is disposed. Prefer explicit ownership over the ambient `subsList.add(key)` mode, which changes the current group for later subscriptions. In React, subscribe in an effect and return a cleanup function that calls off; do not subscribe during render. `act().once(name, callback)` returns an unsubscribe function and removes itself after the first successful event. Still dispose it if its owner disappears first. It is not a replay of an earlier result. Keep subscriber callbacks small; async callbacks are not awaited, so handle their rejected work explicitly. Vue >=3.3 also provides `useRefSubscription` from `act-master/vue`. In setup, `const user = useRefSubscription('GetUser')` gives a ref initially containing null and cleans up on unmount. It subscribes onBeforeMount, so a completed execution earlier in setup can be missed; execute onMounted or subscribe explicitly before dispatch. Its typed overloads need the CLI-generated actionList augmentation. ## Non-Vue bootstrap only (React or vanilla TypeScript) This alternative is for applications without Vue. It uses the same mandatory CLI generation workflow and the actual configured registry import: ```ts import { act } from 'act-master'; import { actions } from '@/act/generated/actions'; act.init({ actions, errorHandlerEventName: 'OnError' }); ``` Initialize before the first `act()` call. `act.init` returns an ActMaster instance, not a framework application. In Vue 3, use the app.use(VueActMaster, options) bootstrap above instead. A standalone `new ActMaster(options)` does not initialize the `act()` helper. ## Test behavior with the current test API Import ActTest from `act-master/test`, not the package root. Each `ActTest.getInstance(options)` creates a fresh test singleton and initializes act(). Use fresh action instances and service doubles per test. Tests sharing the module-level singleton should not run concurrently in the same context. The explicit arrays below intentionally isolate unit tests; do not copy them into the application bootstrap, which imports the CLI-generated actions array. ```ts import { expect, it, vi } from 'vitest'; import { CancelledAct } from 'act-master'; import { ActTest } from 'act-master/test'; import { GetUser } from '@/features/users/act/GetUser.act'; it('returns and publishes a user', async () => { const expected = { id: '42', name: 'Ada' }; const getUser = vi.fn().mockResolvedValue(expected); const dispatcher = ActTest.getInstance({ actions: [new GetUser()], di: { usersApi: { getUser } }, }); const listener = vi.fn(); const off = dispatcher.on('GetUser', listener); expect(await dispatcher.exec('GetUser', '42')).toEqual(expected); expect(getUser).toHaveBeenCalledWith('42'); expect(listener).toHaveBeenCalledWith(expected); off(); expect(dispatcher.t.entityCount('listeners')).toBe(0); }); it('skips the API and success event on validation failure', async () => { const getUser = vi.fn(); const dispatcher = ActTest.getInstance({ actions: [new GetUser()], di: { usersApi: { getUser } }, }); const listener = vi.fn(); dispatcher.on('GetUser', listener); expect(CancelledAct.is(await dispatcher.exec('GetUser', ''))).toBe(true); expect(getUser).not.toHaveBeenCalled(); expect(listener).not.toHaveBeenCalled(); }); ``` For code using error routing, also assert the null result and handler input, plus rejection when no handler is configured. For orchestration, verify cancellation prevents the next side effect. Test concurrency behavior if using $isSingleton. The helper surface is `ActTest.getInstance(...)`, then `dispatcher.t.makeActionStub(...)`, `makeAndAddActionStub(...)`, and `entityCount('actions' | 'watchers' | 'listeners' | 'di')`. Execute via the returned dispatcher and assert the returned result. There are no static ActTest.exec, getLastResult, resetAll, or removeSingleton methods in this version. ## Debugging and completion checklist - "Instance call before initialization": move initialization before the first act() call; avoid dispatch during module imports. - "Not found action": check name spelling, the scan pattern, generation output, imported registry, and bootstrap. A type declaration alone does not register it. - Duplicate action/DI registration: reuse the existing instance and registration; do not attempt to reinitialize the singleton to replace its configuration. - Missing types: keep readonly literal names, typed exec signatures, and the generated registry/module augmentation in the TypeScript program. - `$di is not a function`: use getDI or configured UseDI decorators for this version. - Duplicate/missing UI updates: check cleanup, subscription timing, validation, CancelledAct/null outcomes, $watch cycles, and overlapping requests. - Prefer current `$watch`, `$validate`, `$isSingleton`, `$onError`, and plain `$emit` to deprecated watch, validateInput, isSingleExec, action-level errorHandlerEventName, useEmit, or @Emit. Global errorHandlerEventName remains supported. Avoid deprecated inProgress/removeAction/clearActions in new code; use component loading state with try/finally and owned subscription cleanup. - For setup: verify the actual CLI output file, import its actions array, and install VueActMaster on the existing Vue app before app.mount. A fabricated action constructor or act.init(...).mount(...) is not a valid installation. - Before completing a change, run CLI generation, run the application's type check and relevant tests, and verify success, failure, cancellation, and cleanup for the behavior changed. Inspect the generated diff for unexpected acts. ## Further references - Installation: https://avil13.github.io/act-master/guide/installation - Action concepts: https://avil13.github.io/act-master/guide/act-master-action - Execution/subscriptions: https://avil13.github.io/act-master/guide/exec-and-subscribe - CLI: https://avil13.github.io/act-master/guide/cli - Vue 3: https://avil13.github.io/act-master/guide/vue - Helpers: https://avil13.github.io/act-master/guide/helpers - Source and tests: https://github.com/avil13/act-master/tree/master/packages/act-master/src Some older documentation examples use APIs absent from this version. When details differ, verify package exports, runtime code, and tests rather than copying legacy snippets.