Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions src/__tests__/wiki-toggle-env.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { isWikiEnabled } from '../types.js';

describe('isWikiEnabled (env var approach)', () => {
const originalEnv = process.env;

beforeEach(() => {
process.env = { ...originalEnv };
});

afterEach(() => {
process.env = originalEnv;
});

it('returns true by default', () => {
delete process.env.TEAMAI_WIKI_DISABLED;
delete process.env.TEAMAI_WIKI_ENABLED;
expect(isWikiEnabled()).toBe(true);
});

it('returns false when TEAMAI_WIKI_DISABLED=1', () => {
process.env.TEAMAI_WIKI_DISABLED = '1';
expect(isWikiEnabled()).toBe(false);
});

it('returns false when TEAMAI_WIKI_DISABLED=true', () => {
process.env.TEAMAI_WIKI_DISABLED = 'true';
expect(isWikiEnabled()).toBe(false);
});

it('returns false when TEAMAI_WIKI_ENABLED=false', () => {
process.env.TEAMAI_WIKI_ENABLED = 'false';
expect(isWikiEnabled()).toBe(false);
});

it('returns false when TEAMAI_WIKI_ENABLED=0', () => {
process.env.TEAMAI_WIKI_ENABLED = '0';
expect(isWikiEnabled()).toBe(false);
});

it('returns true when TEAMAI_WIKI_DISABLED is not 1 or true', () => {
process.env.TEAMAI_WIKI_DISABLED = '0';
expect(isWikiEnabled()).toBe(true);
});

it('returns true when TEAMAI_WIKI_ENABLED=1', () => {
process.env.TEAMAI_WIKI_ENABLED = '1';
expect(isWikiEnabled()).toBe(true);
});
});
10 changes: 8 additions & 2 deletions src/builtin-skills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const BUILTIN_SKILL_NAMES = new Set(['teamai-share-learnings', 'teamai-wi
* - Built-in skills directory doesn't exist (dev environment without build)
* - A tool's skills directory is not configured
*/
export async function deployBuiltinSkills(teamConfig: TeamaiConfig, localConfig?: LocalConfig): Promise<number> {
export async function deployBuiltinSkills(teamConfig: TeamaiConfig, localConfig?: LocalConfig, options?: { skipWiki?: boolean }): Promise<number> {
const builtinDir = getBuiltinSkillsDir();

if (!await pathExists(builtinDir)) {
Expand All @@ -76,6 +76,12 @@ export async function deployBuiltinSkills(teamConfig: TeamaiConfig, localConfig?

if (skillNames.length === 0) return 0;

// Skip teamai-wiki deployment when wiki feature is disabled
const filteredSkills = options?.skipWiki
? skillNames.filter(name => name !== 'teamai-wiki')
: skillNames;
if (filteredSkills.length === 0) return 0;

const baseDir = localConfig ? resolveBaseDir(localConfig) : (process.env.HOME ?? '');
let deployed = 0;

Expand All @@ -90,7 +96,7 @@ export async function deployBuiltinSkills(teamConfig: TeamaiConfig, localConfig?

const targetSkillsDir = path.join(baseDir, toolPath.skills);

for (const skillName of skillNames) {
for (const skillName of filteredSkills) {
const srcDir = path.join(builtinDir, skillName);
const destDir = path.join(targetSkillsDir, skillName);

Expand Down
8 changes: 6 additions & 2 deletions src/pull.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
TEAMAI_CLAUDEMD_END,
CultureFrontmatterSchema,
resolveBaseDir,
isWikiEnabled,
getTeamaiHome,
} from './types.js';
import type { CultureFrontmatter } from './types.js';
Expand Down Expand Up @@ -260,7 +261,10 @@ async function pullForScope(
const subscribedTags = localConfig.subscribedTags;

// Step 2: Sync each resource type
const resourceTypes: ResourceType[] = ['skills', 'rules', 'docs', 'env', 'wiki'];
const wikiEnabled = isWikiEnabled();
const resourceTypes: ResourceType[] = wikiEnabled
? ['skills', 'rules', 'docs', 'env', 'wiki']
: ['skills', 'rules', 'docs', 'env'];
let totalSynced = 0;
let desiredSkillNames: Set<string> | null = null;
let knownRepoSkillNames: Set<string> | null = null;
Expand Down Expand Up @@ -555,7 +559,7 @@ async function pullForScope(
if (!options.dryRun) {
try {
const { deployBuiltinSkills } = await import('./builtin-skills.js');
const deployed = await deployBuiltinSkills(freshConfig, localConfig);
const deployed = await deployBuiltinSkills(freshConfig, localConfig, { skipWiki: !wikiEnabled });
if (deployed > 0) {
log.debug(`[${scopeLabel}] Deployed ${deployed} built-in skill(s)`);
}
Expand Down
5 changes: 4 additions & 1 deletion src/push.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { log, spinner } from './utils/logger.js';
import { getHandler } from './resources/index.js';
import { scanTeamRepoNamespaces } from './resources/skills.js';
import type { GlobalOptions, ResourceItem, ResourceType } from './types.js';
import { isWikiEnabled } from './types.js';
import { loadRolesManifest, resolveRoleResourceNamespaces } from './roles.js';
import { askQuestion, askSelection } from './utils/prompt.js';
import { pathExists } from './utils/fs.js';
Expand Down Expand Up @@ -137,7 +138,9 @@ export async function push(options: GlobalOptions & { all?: boolean; role?: stri

// Scan for pushable resources first, then resolve namespace for new skills only.
// Modified skills already carry their namespace from scanLocalForPush.
const pushableTypes: ResourceType[] = ['skills', 'rules', 'env', 'wiki'];
const pushableTypes: ResourceType[] = isWikiEnabled()
? ['skills', 'rules', 'env', 'wiki']
: ['skills', 'rules', 'env'];
const allItems: ResourceItem[] = [];

for (const type of pushableTypes) {
Expand Down
7 changes: 7 additions & 0 deletions src/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
type AgentSkillsView,
} from './agent-skills.js';
import type { GlobalOptions, ResourceType } from './types.js';
import { isWikiEnabled } from './types.js';

export interface ListOptions extends GlobalOptions {
/** Where to look for resources: 'repo' (default for backwards compat),
Expand Down Expand Up @@ -100,6 +101,12 @@ export async function status(options: GlobalOptions): Promise<void> {
console.log(` ${type}: ${count}`);
}

// Wiki feature status
if (!isWikiEnabled()) {
console.log('');
log.info('ℹ Wiki: disabled (TEAMAI_WIKI_DISABLED=1) — wiki routing handled by external plugin');
}

// Local pushable items
console.log('');
log.info('Local resources not yet pushed:');
Expand Down
11 changes: 11 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -534,3 +534,14 @@ export function getStatePath(scope: Scope, projectRoot?: string): string {
export function getPushignorePath(): string {
return path.join(process.env.HOME ?? '', '.teamai', 'pushignore');
}

/**
* Check if wiki feature is enabled.
* Disable by setting TEAMAI_WIKI_DISABLED=1 or TEAMAI_WIKI_ENABLED=false.
* Defaults to enabled for backward compatibility.
*/
export function isWikiEnabled(): boolean {
if (process.env.TEAMAI_WIKI_DISABLED === '1' || process.env.TEAMAI_WIKI_DISABLED === 'true') return false;
if (process.env.TEAMAI_WIKI_ENABLED === '0' || process.env.TEAMAI_WIKI_ENABLED === 'false') return false;
return true;
}
Loading